-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
Governor: Sequential Proposal Ids #5290
base: master
Are you sure you want to change the base?
Governor: Sequential Proposal Ids #5290
Conversation
Co-authored-by: Hadrien Croubois <[email protected]>
🦋 Changeset detectedLatest commit: a04b47f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
contracts/governance/extensions/GovernorSequentialProposalId.sol
Outdated
Show resolved
Hide resolved
contracts/governance/extensions/GovernorSequentialProposalId.sol
Outdated
Show resolved
Hide resolved
contracts/governance/extensions/GovernorSequentialProposalId.sol
Outdated
Show resolved
Hide resolved
contracts/governance/extensions/GovernorSequentialProposalId.sol
Outdated
Show resolved
Hide resolved
contracts/governance/extensions/GovernorSequentialProposalId.sol
Outdated
Show resolved
Hide resolved
} | ||
|
||
/** | ||
* @dev Internal function to set the sequential proposal ID for the next proposal. This is helpful for transitioning from another governing system. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a big caveat about decreasing the proposal count. I'd consider enforcing it in a require statement too, not sure if there are significant downsides to that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use-case that @arr00 metionned that someone may set the count to type(uint256).max to (temporarily) disable proposing until the correct number is set.
IMO that usecase (prevent any proposal from being submitted could be more cleanly done using the proposal threshold).
This is the require I proposed: #5290 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would like to get @wildmolasses thoughts here. I'm leaning towards pushing the above approach of just using the proposal threshold.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'd keep that use case separate. But I do think it's a concern if setting the count to the max uint permanently blocks the governor from functioning... So this is why I'm not all in on enforcing that the update is an increase. A safer thing would be to allow increases of some reasonable size (like uint32), it seems arbitrary but I think it works.
@@ -212,6 +212,16 @@ interface IGovernor is IERC165, IERC6372 { | |||
bytes32 descriptionHash | |||
) external pure returns (uint256); | |||
|
|||
/** | |||
* @dev Function used to get the proposal id from the proposal details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @dev Function used to get the proposal id from the proposal details | |
* @dev Function used to get the proposal id from the proposal details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're missing another check to mention the new getProposalId
function
_proposalCount = newProposalCount; | ||
} | ||
|
||
function proposalCount() public view virtual returns (uint256) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to document this getter. Also, I'd put it up before the _propose
function
} | ||
|
||
/** | ||
* @dev Internal function to set the current proposal count--the next proposal id will be `newProposalCount` + 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this sentence.
* @dev Internal function to set the current proposal count--the next proposal id will be `newProposalCount` + 1. | |
* @dev Internal function to set the current proposal count--the next proposal id will be `newProposalCount` + 1. |
* | ||
* May only call this function if the current proposal count is 0. | ||
*/ | ||
function _setProposalCount(uint256 newProposalCount) internal virtual { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the purpose of including this function is to allow DAOs that are upgrading to set an initial proposal count in their initializers. If this is the case, I think this should be documented somewhere
|
||
import {Governor} from "../Governor.sol"; | ||
|
||
abstract contract GovernorSequentialProposalId is Governor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're missing NatSpec here
return storedProposalId; | ||
} | ||
|
||
function _propose( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing NatSpec here too
/** | ||
* @dev The proposal count may only be set if the current proposal count is 0 in {_setProposalCount}. | ||
*/ | ||
error GovernorCanNotSetProposalCount(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename it "uninitialized" since it better indicates what's wrong. Also, it goes well with the change I'm proposing to rename {_setProposalCount} to {_initializeProposalCount}. I think that instead of explaining the error literally, we should give a hint to solve it.
/** | |
* @dev The proposal count may only be set if the current proposal count is 0 in {_setProposalCount}. | |
*/ | |
error GovernorCanNotSetProposalCount(); | |
/** | |
* @dev The proposal count may only be set if the current proposal count is uninitialized. | |
*/ | |
error GovernorUninitializedProposalCount(); |
* | ||
* May only call this function if the current proposal count is 0. | ||
*/ | ||
function _setProposalCount(uint256 newProposalCount) internal virtual { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be in favor of changing this function's name to indicate better what to do with it. In this case, it suggests developers that it should be used within an initializer.
function _setProposalCount(uint256 newProposalCount) internal virtual { | |
function _initializeProposalCount(uint256 newProposalCount) internal virtual { |
Governor_5_3: [ | ||
'name()', | ||
'version()', | ||
'COUNTING_MODE()', | ||
'hashProposal(address[],uint256[],bytes[],bytes32)', | ||
'getProposalId(address[],uint256[],bytes[],bytes32)', | ||
'state(uint256)', | ||
'proposalThreshold()', | ||
'proposalSnapshot(uint256)', | ||
'proposalDeadline(uint256)', | ||
'proposalProposer(uint256)', | ||
'proposalEta(uint256)', | ||
'proposalNeedsQueuing(uint256)', | ||
'votingDelay()', | ||
'votingPeriod()', | ||
'quorum(uint256)', | ||
'getVotes(address,uint256)', | ||
'getVotesWithParams(address,uint256,bytes)', | ||
'hasVoted(uint256,address)', | ||
'propose(address[],uint256[],bytes[],string)', | ||
'queue(address[],uint256[],bytes[],bytes32)', | ||
'execute(address[],uint256[],bytes[],bytes32)', | ||
'cancel(address[],uint256[],bytes[],bytes32)', | ||
'castVote(uint256,uint8)', | ||
'castVoteWithReason(uint256,uint8,string)', | ||
'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', | ||
'castVoteBySig(uint256,uint8,address,bytes)', | ||
'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,bytes)', | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of repeating all this interface, I'd look for a way to reuse it easily
Alternative solution to #5280
PR Checklist
npx changeset add
)