Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add LSP7Votes and LSP8Votes extension to support LSP-based Governance #980

Merged
merged 17 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 50 additions & 43 deletions packages/lsp7-contracts/contracts/LSP7DigitalAssetCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -441,19 +441,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

_beforeTokenTransfer(address(0), to, amount, data);

// tokens being minted
_existingTokens += amount;

_tokenOwnerBalances[to] += amount;

emit Transfer({
operator: msg.sender,
from: address(0),
to: to,
amount: amount,
force: force,
data: data
});
_update(address(0), to, amount, force, data);
CJ42 marked this conversation as resolved.
Show resolved Hide resolved

_afterTokenTransfer(address(0), to, amount, data);

Expand Down Expand Up @@ -503,23 +491,7 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

_beforeTokenTransfer(from, address(0), amount, data);

uint256 balance = _tokenOwnerBalances[from];
if (amount > balance) {
revert LSP7AmountExceedsBalance(balance, from, amount);
}
// tokens being burnt
_existingTokens -= amount;

_tokenOwnerBalances[from] -= amount;

emit Transfer({
operator: msg.sender,
from: from,
to: address(0),
amount: amount,
force: false,
data: data
});
_update(from, address(0), amount, false, data);

_afterTokenTransfer(from, address(0), amount, data);

Expand Down Expand Up @@ -614,29 +586,64 @@ abstract contract LSP7DigitalAssetCore is ILSP7DigitalAsset {

_beforeTokenTransfer(from, to, amount, data);

uint256 balance = _tokenOwnerBalances[from];
if (amount > balance) {
revert LSP7AmountExceedsBalance(balance, from, amount);
_update(from, to, amount, force, data);

_afterTokenTransfer(from, to, amount, data);

bytes memory lsp1Data = abi.encode(msg.sender, from, to, amount, data);

_notifyTokenSender(from, lsp1Data);
_notifyTokenReceiver(to, force, lsp1Data);
}

/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(
address from,
address to,
uint256 value,
bool force,
bytes memory data
) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_existingTokens += value;
} else {
uint256 fromBalance = _tokenOwnerBalances[from];
if (fromBalance < value) {
revert LSP7AmountExceedsBalance(fromBalance, from, value);
}
unchecked {
CJ42 marked this conversation as resolved.
Show resolved Hide resolved
// Overflow not possible: value <= fromBalance <= totalSupply.
_tokenOwnerBalances[from] = fromBalance - value;
}
}

_tokenOwnerBalances[from] -= amount;
_tokenOwnerBalances[to] += amount;
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_existingTokens -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_tokenOwnerBalances[to] += value;
}
}

emit Transfer({
operator: msg.sender,
from: from,
to: to,
amount: amount,
amount: value,
force: force,
data: data
});

_afterTokenTransfer(from, to, amount, data);

bytes memory lsp1Data = abi.encode(msg.sender, from, to, amount, data);

_notifyTokenSender(from, lsp1Data);
_notifyTokenReceiver(to, force, lsp1Data);
}

/**
Expand Down
65 changes: 65 additions & 0 deletions packages/lsp7-contracts/contracts/Mocks/MyGovernor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";

contract MyGovernor is
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction
{
constructor(
IVotes _token
)
Governor("MyGovernor")
GovernorSettings(7200 /* 1 day */, 7200 /* 1 day */, 1e18)
GovernorVotes(_token)
GovernorVotesQuorumFraction(1)
{}

// The following functions are overrides required by Solidity.

function votingDelay()
public
view
override(IGovernor, GovernorSettings)
returns (uint256)
{
return super.votingDelay();
}

function votingPeriod()
public
view
override(IGovernor, GovernorSettings)
returns (uint256)
{
return super.votingPeriod();
}

function quorum(
uint256 blockNumber
)
public
view
override(IGovernor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}

function proposalThreshold()
public
view
override(Governor, GovernorSettings)
returns (uint256)
{
return super.proposalThreshold();
}
}
19 changes: 19 additions & 0 deletions packages/lsp7-contracts/contracts/Mocks/MyVotingToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../extensions/LSP7Votes.sol";

/**
* @dev Mock of an LSP7Votes token
skimaharvey marked this conversation as resolved.
Show resolved Hide resolved
*/
contract MyVotingToken is LSP7Votes {
constructor()
LSP7DigitalAsset("MyVotingToken", "MYVTKN", msg.sender, 0, false)
EIP712("MyVotingToken", "1")
{}

function mint(address rec, uint256 amount) public {
_mint(rec, amount, true, "");
}
}
Loading
Loading