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

Add ERC721Votes for NFT-based governance #2944

Merged
merged 329 commits into from
Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
329 commits
Select commit Hold shift + click to select a range
abeaf5c
Fixing checkpoints count
JulissaDantes Oct 31, 2021
798baa0
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
4f5a44d
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
13d4a91
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
6ae58d3
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
c8abe20
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
a5d52d9
Governance adocs update
JulissaDantes Nov 2, 2021
a2ec66b
Updating contracts listing order
JulissaDantes Nov 3, 2021
d8147d4
Following lint suggestions
JulissaDantes Nov 3, 2021
2b03bf9
Delete of test contract
JulissaDantes Nov 3, 2021
c987124
Merge branch 'master' of https://github.com/JulissaDantes/openzeppeli…
JulissaDantes Nov 24, 2021
69c6bb1
Delete unused test file
JulissaDantes Nov 24, 2021
339aa31
Update changelog
JulissaDantes Nov 25, 2021
1cabd29
Create Checkpoints and Voting libraries
JulissaDantes Nov 25, 2021
ec5ea0e
Update ERC721Votes contract to use library
JulissaDantes Nov 25, 2021
5f15d46
Add function to Voting library
JulissaDantes Nov 26, 2021
82b1565
Update ERC721Governance contracts
JulissaDantes Nov 26, 2021
8e3feae
Documentation for Checkpoints library
JulissaDantes Nov 26, 2021
d3f3502
Add documentation for Voting library
JulissaDantes Nov 26, 2021
1b95cc8
Add Mock contracts for Voting and checkpoints test
JulissaDantes Nov 26, 2021
9335d04
Add Voting library tests
JulissaDantes Nov 26, 2021
c88fd74
Add Checkpoints library tests
JulissaDantes Nov 26, 2021
b2c0568
Add more documentation for voting library
JulissaDantes Nov 26, 2021
f0dc612
Merge pull request #12 from JulissaDantes/VotingLibrary
JulissaDantes Nov 26, 2021
88edb90
Merge branch 'master' into ERC721Governance
JulissaDantes Nov 26, 2021
a0a26ce
Initial contracts creation
JulissaDantes Oct 31, 2021
0991757
creating permit tests
JulissaDantes Oct 31, 2021
9c3f9fd
Fixing checkpoints count
JulissaDantes Oct 31, 2021
0b0406e
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
4d3ca3a
Updating ERC721Vote tests descriptions
JulissaDantes Oct 31, 2021
d71fb49
Updating ERC721Vote contract and tests
JulissaDantes Oct 31, 2021
dd4a695
Finished tests
JulissaDantes Nov 1, 2021
2d834df
Adding _afterTokenTransfer to base ERC271 contract
JulissaDantes Nov 1, 2021
a207eb5
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
052d4a1
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
adbbbfb
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
4899be8
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
1f85057
Implementing override test
JulissaDantes Nov 2, 2021
3d0f1e4
Removing .only from tests
JulissaDantes Nov 2, 2021
9a3f2a1
Updating contracts READMEs
JulissaDantes Nov 2, 2021
f3d8453
Governance adocs update
JulissaDantes Nov 2, 2021
ec047ac
Removing test contract
JulissaDantes Nov 3, 2021
1179e90
Initial contracts creation
JulissaDantes Oct 31, 2021
913946b
creating permit tests
JulissaDantes Oct 31, 2021
e999d78
Fixing checkpoints count
JulissaDantes Oct 31, 2021
3c63a1d
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
b42d0ab
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
dc0ec55
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
9d0f7fe
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
9efd8c1
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
87cf640
Governance adocs update
JulissaDantes Nov 2, 2021
b135af5
Updating contracts listing order
JulissaDantes Nov 3, 2021
510c373
Following lint suggestions
JulissaDantes Nov 3, 2021
f58c91e
Delete of test contract
JulissaDantes Nov 3, 2021
8663d84
Initial contracts creation
JulissaDantes Oct 31, 2021
6d69091
creating permit tests
JulissaDantes Oct 31, 2021
72c887d
Fixing checkpoints count
JulissaDantes Oct 31, 2021
b94e475
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
a7397ba
Updating ERC721Vote tests descriptions
JulissaDantes Oct 31, 2021
6ed1ccd
Adding _afterTokenTransfer to base ERC271 contract
JulissaDantes Nov 1, 2021
718274a
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
e341b83
Governance adocs update
JulissaDantes Nov 2, 2021
130664e
Removing test contract
JulissaDantes Nov 3, 2021
5c9e993
Initial contracts creation
JulissaDantes Oct 31, 2021
1ad617a
creating permit tests
JulissaDantes Oct 31, 2021
13d3b7c
Fixing checkpoints count
JulissaDantes Oct 31, 2021
f9fa57a
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
af0d1a5
Updating ERC721Vote contract and tests
JulissaDantes Oct 31, 2021
3ccfdd9
Adding _afterTokenTransfer to base ERC271 contract
JulissaDantes Nov 1, 2021
05e8cee
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
b9c8e7b
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
068da60
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
e350d15
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
c5f44f7
Implementing override test
JulissaDantes Nov 2, 2021
7a9228f
Governance adocs update
JulissaDantes Nov 2, 2021
49a378f
Updating contracts listing order
JulissaDantes Nov 3, 2021
22c672e
Delete of test contract
JulissaDantes Nov 3, 2021
514e0aa
Updating comment and documentation
JulissaDantes Nov 3, 2021
074430d
Update docs/modules/ROOT/pages/governance.adoc
JulissaDantes Nov 4, 2021
a9d6cff
Improving documentation, adding spaces, renaming variables
JulissaDantes Nov 4, 2021
05ed326
Update contracts/token/ERC721/extensions/ERC721Votes.sol
JulissaDantes Nov 4, 2021
3eb6d74
Update contracts/token/ERC721/extensions/ERC721Votes.sol
JulissaDantes Nov 4, 2021
d8ff5cc
Update docs/modules/ROOT/pages/governance.adoc
JulissaDantes Nov 4, 2021
367f9bb
Adding constructor
JulissaDantes Nov 4, 2021
cca8ff2
Updating tests setting more NFT voting power to single voter
JulissaDantes Nov 4, 2021
1e0f543
Update erc721.adoc
JulissaDantes Nov 4, 2021
84d97db
Adding method to return token voting power
JulissaDantes Nov 4, 2021
8147461
Delete local file
JulissaDantes Nov 4, 2021
c914c84
Update contracts/token/ERC721/extensions/draft-ERC721Votes.sol
JulissaDantes Nov 5, 2021
2a45f36
Including getVotingPower
JulissaDantes Nov 5, 2021
deb2b1e
After prettier run, updating format
JulissaDantes Nov 5, 2021
6fe31e9
Renaming totalSupply to totalVotingPower for the code to be cleaner
JulissaDantes Nov 5, 2021
51ade3f
Update changelog
JulissaDantes Nov 25, 2021
3aec0a7
Create Checkpoints and Voting libraries
JulissaDantes Nov 25, 2021
41aa303
Update ERC721Votes contract to use library
JulissaDantes Nov 25, 2021
4d1912b
Add function to Voting library
JulissaDantes Nov 26, 2021
2524a87
Update ERC721Governance contracts
JulissaDantes Nov 26, 2021
1e46d25
Documentation for Checkpoints library
JulissaDantes Nov 26, 2021
7d4c5fe
Add documentation for Voting library
JulissaDantes Nov 26, 2021
44df89d
Add Mock contracts for Voting and checkpoints test
JulissaDantes Nov 26, 2021
55213f5
Add Voting library tests
JulissaDantes Nov 26, 2021
054c78f
Add Checkpoints library tests
JulissaDantes Nov 26, 2021
92936c8
Add more documentation for voting library
JulissaDantes Nov 26, 2021
c7c9b29
Lint run
JulissaDantes Nov 26, 2021
d05cb0a
change after rebase
JulissaDantes Nov 26, 2021
8582932
Merge branch 'master' into ERC721Governance
JulissaDantes Nov 26, 2021
b57a3dc
Remove empty spaces
JulissaDantes Nov 26, 2021
02115ae
Run prettier
JulissaDantes Nov 26, 2021
abc90f9
Merge pull request #13 from JulissaDantes/ERC721Governance
JulissaDantes Nov 26, 2021
51002f9
Remove whitespaces
JulissaDantes Nov 29, 2021
54d80db
Remove whitespaces
JulissaDantes Nov 29, 2021
acd9a00
Update changelog after merge
JulissaDantes Nov 29, 2021
7f5a8f4
Merge pull request #14 from JulissaDantes/ERC721Governance
JulissaDantes Nov 29, 2021
c919980
Initial contracts creation
JulissaDantes Oct 31, 2021
5a10153
creating permit tests
JulissaDantes Oct 31, 2021
792ce18
Fixing checkpoints count
JulissaDantes Oct 31, 2021
71301aa
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
9c39e32
Updating ERC721Vote tests descriptions
JulissaDantes Oct 31, 2021
a3396c5
Updating ERC721Vote contract and tests
JulissaDantes Oct 31, 2021
3aef1f9
Finished tests
JulissaDantes Nov 1, 2021
9784e04
Adding _afterTokenTransfer to base ERC271 contract
JulissaDantes Nov 1, 2021
1a3dc28
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
e37f4bf
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
f275406
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
6a9caf0
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
5a58fc2
Implementing override test
JulissaDantes Nov 2, 2021
e07dfa6
Removing .only from tests
JulissaDantes Nov 2, 2021
0bc0ab5
Updating contracts READMEs
JulissaDantes Nov 2, 2021
61523ed
Governance adocs update
JulissaDantes Nov 2, 2021
f82873e
Removing test contract
JulissaDantes Nov 3, 2021
4f0f39e
Initial contracts creation
JulissaDantes Oct 31, 2021
acc4aa7
creating permit tests
JulissaDantes Oct 31, 2021
82e313b
Fixing checkpoints count
JulissaDantes Oct 31, 2021
e55511a
Updating ERC721Vote tests
JulissaDantes Oct 31, 2021
9eaa01d
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
29b0e16
Updating tests based on new contract changes
JulissaDantes Nov 1, 2021
3c49d6c
Updating execution order inside of mint
JulissaDantes Nov 2, 2021
d344647
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
d687e09
Governance adocs update
JulissaDantes Nov 2, 2021
101a82c
Updating contracts listing order
JulissaDantes Nov 3, 2021
5201c96
Following lint suggestions
JulissaDantes Nov 3, 2021
4f9cc0a
Delete of test contract
JulissaDantes Nov 3, 2021
4175ade
Updating comment and documentation
JulissaDantes Nov 3, 2021
c8e1c94
Update docs/modules/ROOT/pages/governance.adoc
JulissaDantes Nov 4, 2021
de45b91
Update contracts/token/ERC721/extensions/ERC721Votes.sol
JulissaDantes Nov 4, 2021
6af56a9
Update docs/modules/ROOT/pages/governance.adoc
JulissaDantes Nov 4, 2021
9079397
Update erc721.adoc
JulissaDantes Nov 4, 2021
6eb60da
Delete unused test file
JulissaDantes Nov 24, 2021
29e7a02
Create Checkpoints and Voting libraries
JulissaDantes Nov 25, 2021
9a26c4d
Add function to Voting library
JulissaDantes Nov 26, 2021
af23b86
Documentation for Checkpoints library
JulissaDantes Nov 26, 2021
9b4d4cf
Add Mock contracts for Voting and checkpoints test
JulissaDantes Nov 26, 2021
aa3c0db
Governance adocs update
JulissaDantes Nov 2, 2021
2a3e090
Removing test contract
JulissaDantes Nov 3, 2021
e3730e1
Initial contracts creation
JulissaDantes Oct 31, 2021
731586f
Renaming supplied tokenId on tests
JulissaDantes Nov 1, 2021
9dad235
Updating contracts listing order
JulissaDantes Nov 3, 2021
ae4d235
Fixing checkpoints count
JulissaDantes Oct 31, 2021
897938f
Adding _afterTokenTransfer to base ERC271 contract
JulissaDantes Nov 1, 2021
c0cab85
Governance adocs update
JulissaDantes Nov 2, 2021
3b031da
Removing test contract
JulissaDantes Nov 3, 2021
9829c08
creating permit tests
JulissaDantes Oct 31, 2021
ada5c98
Adding Mocks for testing and integrating nft minting to current workf…
JulissaDantes Nov 2, 2021
c730f4d
Implementing override test
JulissaDantes Nov 2, 2021
98a6618
Updating contracts listing order
JulissaDantes Nov 3, 2021
ef43fb2
Update erc721.adoc
JulissaDantes Nov 4, 2021
ec7e892
Update changelog
JulissaDantes Nov 25, 2021
b813f9c
Run prettier
JulissaDantes Nov 26, 2021
09da50d
Update changelog after merge
JulissaDantes Nov 29, 2021
e0e8d74
Update after rebase
JulissaDantes Nov 29, 2021
fb2bd07
Merge branch 'master' of https://github.com/JulissaDantes/openzeppeli…
JulissaDantes Nov 29, 2021
d7f1dda
Remove unused library
JulissaDantes Nov 29, 2021
5506617
Prevent version mismatch
JulissaDantes Nov 29, 2021
25eadd0
Merge pull request #15 from JulissaDantes/ERC721Governance
JulissaDantes Nov 30, 2021
424af50
Remove minting restriction
JulissaDantes Nov 30, 2021
b2b7f5b
Remove afterToken transfer and Add _transfer function
JulissaDantes Nov 30, 2021
ef252c9
Remove checkpoints methods
JulissaDantes Nov 30, 2021
83eeac5
Update contract structure
JulissaDantes Dec 1, 2021
176d166
Add _getDelegatorVotes function for ERC721Votes
JulissaDantes Dec 1, 2021
bb32fba
Update Voting test and Mock
JulissaDantes Dec 1, 2021
1d0c1ea
Update Votes mock and tests
JulissaDantes Dec 2, 2021
3e14830
Fix functions visibility on Votes contract
JulissaDantes Dec 2, 2021
f7a7b51
Run lint
JulissaDantes Dec 2, 2021
5740f3c
Merge pull request #16 from JulissaDantes/ERC721Governance
JulissaDantes Dec 2, 2021
5704b3b
Fix delegation, add test coverage, fix moveVotingPower
JulissaDantes Dec 2, 2021
be216d0
Merge pull request #17 from JulissaDantes/ERC721Governance
JulissaDantes Dec 2, 2021
c37502f
Change inheritance order
JulissaDantes Dec 2, 2021
a28a4b2
Merge pull request #18 from JulissaDantes/ERC721Governance
JulissaDantes Dec 2, 2021
9ea08be
Update documentation contract
JulissaDantes Dec 2, 2021
6bcff2b
Update CHANGELOG.md
JulissaDantes Dec 3, 2021
73bb657
Update checkpoints storage variable names
JulissaDantes Dec 3, 2021
3ffdb76
Update docs/modules/ROOT/pages/governance.adoc
JulissaDantes Dec 3, 2021
b6cbe1d
Update variable names, Remove index based functions, update documenta…
JulissaDantes Dec 3, 2021
099fa20
Merge branch 'ERC721Governance' of https://github.com/JulissaDantes/o…
JulissaDantes Dec 3, 2021
f054441
Update delegate arguments, rename variables, add function call on bas…
JulissaDantes Dec 3, 2021
0c8b601
Update _moveVotingPower
JulissaDantes Dec 3, 2021
7de147c
Update tests
JulissaDantes Dec 3, 2021
d852c08
Run lint
JulissaDantes Dec 3, 2021
5efd9a2
Add IVote interface an update tests
JulissaDantes Dec 3, 2021
052f064
Remove .only from test
JulissaDantes Dec 3, 2021
76d47c7
Merge pull request #19 from JulissaDantes/ERC721Governance
JulissaDantes Dec 3, 2021
499559a
Merge branch 'master' of https://github.com/OpenZeppelin/openzeppelin…
JulissaDantes Dec 3, 2021
eb6304b
Update contract inheriting from GovernorVotes
JulissaDantes Dec 3, 2021
e5fecaf
Indentitation/format consistency
Amxx Dec 3, 2021
9addc4f
Improve format
JulissaDantes Dec 3, 2021
f536b1b
Merge branch 'ERC721Governance' of https://github.com/JulissaDantes/o…
JulissaDantes Dec 3, 2021
b8639e7
Update contracts/utils/Votes.sol
JulissaDantes Dec 3, 2021
f5f6aab
Update contracts/token/ERC20/extensions/ERC20Votes.sol
JulissaDantes Dec 3, 2021
87bd7b2
Update contracts/utils/Checkpoints.sol
JulissaDantes Dec 3, 2021
93a2079
Update IVotes and Votes directory
JulissaDantes Dec 3, 2021
829f074
Remove .only from test files
JulissaDantes Dec 3, 2021
8fdb1e0
Update storage variables names
JulissaDantes Dec 3, 2021
dfe225c
Change inheritance order
JulissaDantes Dec 3, 2021
ee10185
Merge pull request #20 from JulissaDantes/ERC721Governance
JulissaDantes Dec 3, 2021
1cca7be
Add function to handle mint and burn before moving voting power
JulissaDantes Dec 6, 2021
c173749
Update README.adoc
frangio Dec 6, 2021
f2cccc3
rename files to new names
frangio Dec 6, 2021
2f8cf7b
Rename function getTotalSupply
JulissaDantes Dec 6, 2021
628567c
Merge branch 'ERC721Governance' of https://github.com/JulissaDantes/o…
JulissaDantes Dec 6, 2021
edf795b
Change test function name
JulissaDantes Dec 6, 2021
7f90b88
Fix documentation after function rename
JulissaDantes Dec 6, 2021
7cda9a3
improve documentation
frangio Dec 6, 2021
a82fc9c
Update Votes.sol documentation
JulissaDantes Dec 6, 2021
b171720
Add Chekpoints.sol documentation
JulissaDantes Dec 6, 2021
7e134d8
Improve ERc721 documentation
JulissaDantes Dec 6, 2021
1197d84
Erc721 governance documentation improvement (#21)
JulissaDantes Dec 6, 2021
c60d9b5
add Checkpoints: prefix to revert reason
frangio Dec 6, 2021
81972f7
fix revert reason
frangio Dec 6, 2021
4773334
remove revert reason prefix from test
frangio Dec 6, 2021
7ead55f
Update CHANGELOG.md
JulissaDantes Dec 7, 2021
f099426
Add checkpoints tests
JulissaDantes Dec 7, 2021
c4d3dfd
Improve format
JulissaDantes Dec 7, 2021
43abcee
revert back to previous error message
frangio Dec 8, 2021
cd3ab17
restructure Checkpoints tests
frangio Dec 8, 2021
c349618
lint
frangio Dec 8, 2021
ebd3082
improve Checkpoints docs
frangio Dec 8, 2021
ce1df1f
Update revert message
JulissaDantes Dec 8, 2021
5cb991b
Add VotesWorklfow to aid testing
JulissaDantes Dec 8, 2021
37c9e73
Add mint before delegate on votes tests
JulissaDantes Dec 8, 2021
d556b27
Merge branch 'ERC721Governance' of https://github.com/JulissaDantes/o…
JulissaDantes Dec 8, 2021
94d63e0
Update token specific test for ERC721Votes
JulissaDantes Dec 8, 2021
547cba4
Merge branch 'master' into ERC721Governance
JulissaDantes Dec 8, 2021
90ca1e2
remove added whitespace
frangio Dec 10, 2021
9d705ce
further improve docs and rename for new concept of vote units
frangio Dec 10, 2021
8e74446
rename VotesWorkflow to Votes behavior
frangio Dec 10, 2021
d6ae076
remove unused helpers
frangio Dec 10, 2021
92537f3
Rename tests variables based on contract renamed variable
JulissaDantes Dec 10, 2021
b306e61
fix missing name variable
frangio Dec 10, 2021
53847b4
revert event argument change
frangio Dec 10, 2021
bd6ec00
Merge branch 'master' into ERC721Governance
frangio Dec 10, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions contracts/governance/extensions/GovernorVotesERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,26 @@
pragma solidity ^0.8.0;

import "../Governor.sol";
import "../../token/ERC721/extensions/ERC721Votes.sol";
import "../../token/ERC721/extensions/draft-ERC721Votes.sol";
import "../../utils/math/Math.sol";
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved

/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC721Votes} token.
*
* _Available since v4.3._
* _Available since v4.5._
*/
abstract contract GovernorVotesERC721 is Governor {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, this module produces the exact same result as GovernorVotesERC20, because the getPastVotes method is shared. Maybe we should not have 2 identical modules

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldnt it serve as a guide for users trying to implment Governance with ERCVotes? Or should we include some documentation somewhere instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't realized before that this module was exactly the same as GovernorVotes.

It's better to avoid the duplication. As a guide for users, we should change GovernorVotes so that it's clear that it is used with both:

  • Decouple the implementation from ERC20Votes so that it's clear that it can be used with ERC721Votes as well. We should introduce an IVotes interface that is implemented by both ERC20Votes and ERC721Votes, and use it in GovernorVotes in place of ERC20Votes.
  • Update the documentation to talk about ERC721 as well as ERC20.

ERC721Votes public immutable token;

/**
* @dev Need the ERC721Votes address to be initialized
*/
constructor(ERC721Votes tokenAddress) {
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved
token = tokenAddress;
}

/**
* Read the voting weight from the token's built in snapshot mechanism (see {IGovernor-getVotes}).
* @dev Read the voting weight from the token's built in snapshot mechanism (see {IGovernor-getVotes}).
*/
function getVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
return token.getPastVotes(account, blockNumber);
Expand Down
8 changes: 4 additions & 4 deletions contracts/mocks/ERC721VotesMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

pragma solidity ^0.8.0;

import "../token/ERC721/extensions/ERC721Votes.sol";
import "../token/ERC721/extensions/draft-ERC721Votes.sol";

contract ERC721VotesMock is ERC721Votes {
constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, "1") {}
constructor(string memory name, string memory symbol) ERC721Votes(name, symbol) {}

function mint(address account, uint256 tokenId) public {
_mint(account, tokenId);
Expand All @@ -19,7 +19,7 @@ contract ERC721VotesMock is ERC721Votes {
return block.chainid;
}

function _maxSupply() internal pure override returns(uint224){
return uint224(4);
function _maxSupply() internal pure override returns (uint224) {
return uint224(5);
}
}
17 changes: 5 additions & 12 deletions contracts/token/ERC721/ERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {

emit Transfer(from, to, tokenId);

_afterTokenTransfer(from, to, tokenId);
_afterTokenTransfer(from, to);
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -423,24 +423,17 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
address to,
uint256 tokenId
) internal virtual {}
/**

/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `tokenId` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `tokenId` tokens have been minted for `to`.
* - when `to` is zero, `tokenId` of ``from``'s tokens have been burned.
* - when `from` and `to` are both non-zero.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
function _afterTokenTransfer(address from, address to) internal virtual {}
}
1 change: 1 addition & 0 deletions contracts/token/ERC721/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Additionally there are multiple custom extensions, including:

* designation of addresses that can pause token transfers for all users ({ERC721Pausable}).
* destruction of own tokens ({ERC721Burnable}).
* support for voting and vote delegation ({ERC721Votes})

NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC721 (such as <<ERC721-_mint-address-uint256-,`_mint`>>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc721.adoc#Presets[ERC721 Presets] (such as {ERC721PresetMinterPauserAutoId}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.3.2 (token/ERC721/extensions/ERC721Votes.sol)
// OpenZeppelin Contracts v4.3.2 (token/ERC721/extensions/draft-ERC721Votes.sol)

pragma solidity ^0.8.0;

Expand All @@ -9,6 +9,7 @@ import "../../../utils/math/Math.sol";
import "../../../utils/math/SafeCast.sol";
import "../../../utils/cryptography/ECDSA.sol";
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved
import "../../../utils/cryptography/draft-EIP712.sol";

/**
* @dev Extension of ERC721 to support Compound-like voting and delegation. This version is more generic than Compound's,
* and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
Expand All @@ -22,7 +23,7 @@ import "../../../utils/cryptography/draft-EIP712.sol";
* Enabling self-delegation can easily be done by overriding the {delegates} function. Keep in mind however that this
* will significantly increase the base gas cost of transfers.
*
* _Available since v4.2._
* _Available since v4.5._
*/
abstract contract ERC721Votes is ERC721, EIP712 {
using Counters for Counters.Counter;
Expand All @@ -44,7 +45,8 @@ abstract contract ERC721Votes is ERC721, EIP712 {
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC721 token name.
*/
*/
constructor(string memory name, string memory symbol) ERC721(name, symbol) EIP712(name, "1") {}
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved

/**
* @dev Emitted when an account changes their delegate.
Expand Down Expand Up @@ -179,11 +181,11 @@ abstract contract ERC721Votes is ERC721, EIP712 {
* @dev Snapshots the totalSupply after it has been increased.
*/
function _mint(address account, uint256 tokenId) internal virtual override {
require(_totalSupply+1 <= _maxSupply(), "ERC721Votes: total supply risks overflowing votes");
require(_totalSupply + 1 <= _maxSupply(), "ERC721Votes: total supply risks overflowing votes");

super._mint(account, tokenId);
_totalSupply += 1;

_writeCheckpoint(_totalSupplyCheckpoints, _add, 1);
}

Expand All @@ -201,11 +203,9 @@ abstract contract ERC721Votes is ERC721, EIP712 {
*
* Emits a {DelegateVotesChanged} event.
*/
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override{
function _afterTokenTransfer(address from, address to) internal virtual override {
super._afterTokenTransfer(from, to);

_moveVotingPower(delegates(from), delegates(to), 1);
}

Expand Down Expand Up @@ -284,6 +284,11 @@ abstract contract ERC721Votes is ERC721, EIP712 {
return _domainSeparatorV4();
}

/**
* @dev Returns token voting power
*/
function _getVotingPower(uint tokenId) internal virtual returns(uint256) {}
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved

function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
}
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/erc721.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
= ERC721

We've discussed how you can make a _fungible_ token using xref:erc20.adoc[ERC20], but what if not all tokens are alike? This comes up in situations like *real estate*, *voting rights*, or *collectibles*, where some items are valued more than others, due to their usefulness, rarity, etc. ERC721 is a standard for representing ownership of xref:tokens.adoc#different-kinds-of-tokens[_non-fungible_ tokens], that is, where each token is unique.
We've discussed how you can make a _fungible_ token using xref:erc20.adoc[ERC20], but what if not all tokens are alike? This comes up in situations like *real estate* or *collectibles*, where some items are valued more than others, due to their usefulness, rarity, etc. ERC721 is a standard for representing ownership of xref:tokens.adoc#different-kinds-of-tokens[_non-fungible_ tokens], that is, where each token is unique.

ERC721 is a more complex standard than ERC20, with multiple optional extensions, and is split across a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the xref:api:token/ERC721.adoc[API Reference] to learn more about these.

Expand Down
21 changes: 10 additions & 11 deletions docs/modules/ROOT/pages/governance.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -130,26 +130,25 @@ If your project requires The voting power of each account in our governance setu
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol";

contract MyToken is ERC721, EIP712, ERC721Votes {
constructor() ERC721("MyToken", "MTK") EIP712("MyToken", "1") {}
contract MyToken is ERC721Votes {
constructor() ERC721Votes("MyToken", "MTK"){}

// The functions below are overrides required by Solidity.

function _afterTokenTransfer(
JulissaDantes marked this conversation as resolved.
Show resolved Hide resolved
address from,
address to,
uint256 tokenId
) internal override(ERC721, ERC721Votes) {
super._afterTokenTransfer(from, to, tokenId);
address to
) internal override(ERC721Votes) {
super._afterTokenTransfer(from, to);
}

function _mint(address to, uint256 tokenId) internal override(ERC721, ERC721Votes) {
function _mint(address to, uint256 tokenId) internal override(ERC721Votes) {
super._mint(to, tokenId);
}

function _burn(uint256 tokenId) internal override(ERC721, ERC721Votes) {
function _burn(uint256 tokenId) internal override(ERC721Votes) {
super._burn(tokenId);
}
}
Expand All @@ -159,15 +158,15 @@ NOTE: Voting power could be determined in different ways: multiple ERC20 tokens,

=== Governor

Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, but we still need to choose: 1) how voting power is determined, 2) how many votes are needed for quorum, 3) what options people have when casting a vote and how those votes are counted, and 4)what type of token should be use to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts.
Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, but we still need to choose: 1) how voting power is determined, 2) how many votes are needed for quorum, 3) what options people have when casting a vote and how those votes are counted, and 4) what type of token should be used to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts.

For 1) we will use the GovernorVotes module, which hooks to an ERC20Votes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token.

For 2) we will use GovernorVotesQuorumFraction which works together with ERC20Votes to define quorum as a percentage of the total supply at the block a proposal’s voting power is retrieved. This requires a constructor parameter to set the percentage. Most Governors nowadays use 4%, so we will initialize the module with parameter 4 (this indicates the percentage, resulting in 4%).

For 3) we will use GovernorCountingSimple, a module that offers 3 options to voters: For, Against, and Abstain, and where only For and Abstain votes are counted towards quorum.

For 4) we will use the GovernorVotesERC721 module, which hooks to an ERC721Votes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token.
For 4) we will use the GovernorVotesERC721 module, which hooks to an ERC721Votes instance to determine the voting power of an account based on the NFTs they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token.

Besides these modules, Governor itself has some parameters we must set.

Expand Down
8 changes: 5 additions & 3 deletions test/governance/GovernorWorkflow.behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ function runGovernorWorkflow () {
for (const voter of this.settings.voters) {
if (voter.weight) {
await this.token.transfer(voter.voter, voter.weight, { from: this.settings.tokenHolder });
} else if (voter.nftWeight) {
await this.token.transferFrom(this.settings.tokenHolder, voter.voter, voter.nftWeight,
{ from: this.settings.tokenHolder });
} else if (voter.nfts) {
for (const nft of voter.nfts) {
await this.token.transferFrom(this.settings.tokenHolder, voter.voter, nft,
{ from: this.settings.tokenHolder });
}
}
}
}
Expand Down
40 changes: 32 additions & 8 deletions test/governance/extensions/GovernorERC721.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { expectEvent } = require('@openzeppelin/test-helpers');
const { BN } = require('bn.js');
const Enums = require('../../helpers/enums');

const {
Expand All @@ -15,20 +16,34 @@ contract('GovernorERC721Mock', function (accounts) {
const name = 'OZ-Governor';
const tokenName = 'MockNFToken';
const tokenSymbol = 'MTKN';
const initalTokenId = web3.utils.toWei('100');
const NFT0 = web3.utils.toWei('100');
const NFT1 = web3.utils.toWei('10');
const NFT2 = web3.utils.toWei('20');
const NFT3 = web3.utils.toWei('30');
const NFT4 = web3.utils.toWei('40');

// Must be the same as in contract
const ProposalState = {
Pending: new BN('0'),
Active: new BN('1'),
Canceled: new BN('2'),
Defeated: new BN('3'),
Succeeded: new BN('4'),
Queued: new BN('5'),
Expired: new BN('6'),
Executed: new BN('7'),
};

beforeEach(async function () {
this.owner = owner;
this.token = await Token.new(tokenName, tokenSymbol);
this.mock = await Governor.new(name, this.token.address);
this.receiver = await CallReceiver.new();
await this.token.mint(owner, initalTokenId);
await this.token.mint(owner, NFT0);
await this.token.mint(owner, NFT1);
await this.token.mint(owner, NFT2);
await this.token.mint(owner, NFT3);
await this.token.mint(owner, NFT4);

await this.token.delegate(voter1, { from: voter1 });
await this.token.delegate(voter2, { from: voter2 });
Expand All @@ -55,10 +70,10 @@ contract('GovernorERC721Mock', function (accounts) {
],
tokenHolder: owner,
voters: [
{ voter: voter1, nftWeight: initalTokenId, support: Enums.VoteType.For },
{ voter: voter2, nftWeight: NFT1, support: Enums.VoteType.For },
{ voter: voter3, nftWeight: NFT2, support: Enums.VoteType.Against },
{ voter: voter4, nftWeight: NFT3, support: Enums.VoteType.Abstain },
{ voter: voter1, nfts: [NFT0], support: Enums.VoteType.For },
{ voter: voter2, nfts: [NFT1, NFT2], support: Enums.VoteType.For },
{ voter: voter3, nfts: [NFT3], support: Enums.VoteType.Against },
{ voter: voter4, nfts: [NFT4], support: Enums.VoteType.Abstain },
],
};
});
Expand All @@ -77,16 +92,25 @@ contract('GovernorERC721Mock', function (accounts) {
this.settings.voters.find(({ address }) => address === voter),
);

expect(await this.token.getVotes(voter, vote.blockNumber)).to.be.bignumber.equal('1');
if (voter === voter2) {
expect(await this.token.getVotes(voter, vote.blockNumber)).to.be.bignumber.equal('2');
} else {
expect(await this.token.getVotes(voter, vote.blockNumber)).to.be.bignumber.equal('1');
}
}

await this.mock.proposalVotes(this.id).then(result => {
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(result[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).length.toString(),
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { nfts }) => acc.add(new BN(nfts.length)),
new BN('0'),
),
);
}
});

expect(await this.mock.state(this.id)).to.be.bignumber.equal(ProposalState.Executed);
});

runGovernorWorkflow();
Expand Down