-
Notifications
You must be signed in to change notification settings - Fork 0
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 minimal approval configuration #28
Conversation
… to the majority vote base init function
…tinue supporting old version
…rly set when updating or installing
… min approval is not reached
…tialize function reverts
@@ -266,17 +273,25 @@ abstract contract MajorityVotingBase is | |||
uint256 minProposerVotingPower | |||
); | |||
|
|||
/// @notice Emitted when the min approval value is updated. | |||
/// @param minApproval The minimum amount of yes votes needed for a proposal succeed. | |||
event VotingMinApprovalUpdated(uint32 minApproval); |
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.
Is it possible to have this event defined in the interface?
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 entirely certain about the approach we're taking with this, but I noticed that VotingMinApprovalUpdated](
token-voting-plugin/packages/contracts/src/MajorityVotingBase.sol
Lines 262 to 274 in 65198a0
/// @notice Emitted when the voting settings are updated. | |
/// @param votingMode A parameter to select the vote mode. | |
/// @param supportThreshold The support threshold value. | |
/// @param minParticipation The minimum participation value. | |
/// @param minDuration The minimum duration of the proposal vote in seconds. | |
/// @param minProposerVotingPower The minimum voting power required to create a proposal. | |
event VotingSettingsUpdated( | |
VotingMode votingMode, | |
uint32 supportThreshold, | |
uint32 minParticipation, | |
uint64 minDuration, | |
uint256 minProposerVotingPower | |
); |
Given that events are not part of the interface ID, I believe it’s reasonable to define them in the interface. However, for the sake of consistency, I lean to keep it here unless you have a strong reason to move it to the interface.
// todo TBD define if permission should be the same one as update settings | ||
/// @notice Updates the minimal approval value. | ||
/// @param _minApproval The new minimal approval value. | ||
function updateMinApproval( |
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.
Are we always doing breaks for function arguments or not? I see a small inconsistency here :-)
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.
It will depend on the line length (100 - 120).
If there are too many arguments will break into lines, if not it should be on the same one.
In this case, there is a single argument but the modifier name on the auth function increases the line length and breaks in lines
revert RatioOutOfBounds({limit: RATIO_BASE, actual: _minApproval}); | ||
} | ||
|
||
minApprovals = _minApproval; |
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.
small incosistency. name them the same.
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.
done f7e0f97
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.
you still use _minApproval
instead of _minApprovals
. hahaha
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.
and rename the function as well to _updateMinApprovals
.
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.
@@ -224,6 +227,10 @@ abstract contract MajorityVotingBase is | |||
/// @notice The struct storing the voting settings. | |||
VotingSettings private votingSettings; | |||
|
|||
/// @notice The minimal ratio of yes votes needed for a proposal succeed. | |||
/// @dev is not on the VotingSettings for compatibility reasons. | |||
uint32 private minApprovals; // added in v1.3 |
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.
What's the reason for going with uint32
instead of uint256
? I wonder the reason in your mind was that in the future, if we add more state variable, they would be tightly packed ? If that's the reason, I think it's a wrong reason.
packing only makes good and efficient sense if state variables are stored in the same tx. I highly doubt that whatever new state variable we add, that value and minApprovals
value would be updated in the same tx. From the solidity docs:
If you are not reading or writing all the values in a slot at the same time, this can have the opposite effect, though: When one value is written to a multi-value storage slot, the storage slot has to be read first and then combined with the new value such that other data in the same slot is not destroyed.
Up to you as I haven't thought this very deep, but from first impression, that's the impression I got.
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.
Also, can you remind me of why we can not put this state variable inside VotingSettings
struct ?
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 went with uint32
mainly because minParticipation
and supportThreshold
the other ratios we already store are defined as uint32
.
At some point questioned it because an extra operation is needed for casting the value every single time, however just continued with uint32
for consistency among the ratios.
Didn't store it inside VotingSettings
because it is being received as a parameter for several functions:
__MajorityVotingBase_init
: is not important because is not on any interface id.initialize
: that is inTOKEN_VOTING_INTERFACE_ID
but we are already overriding it so we can manage it.updateVotingSettings
: that is inIMajorityVoting
interface, adding a new entry to the struct will change the function selector, and even if we implement erc165 with both IDs, we still need to "support" the old function which has a no longer existent struct.
A new struct could be created to add this parameter and deprecate the old one, but to be honest, I don't have a strong opinion on this, neither option is clean.
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 went with uint32 mainly because minParticipation and supportThreshold the other ratios we already store are defined as uint32.
This was because of packing, but for new minApproval, no packing needed. I'd go with uint256
.
As for other question, I missed this detail and yes, I think we don't have any better way. Have to think this through
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 also agree to go with uint256
done in 4ce4388
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.
1st ROUND.
@@ -211,6 +213,7 @@ abstract contract MajorityVotingBase is | |||
this.totalVotingPower.selector ^ | |||
this.getProposal.selector ^ | |||
this.updateVotingSettings.selector ^ | |||
this.updateMinApprovals.selector ^ | |||
this.createProposal.selector; | |||
|
|||
/// @notice The ID of the permission required to call the `updateVotingSettings` function. |
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.
/// @notice The ID of the permission required to call the `updateVotingSettings` function. | |
/// @notice The ID of the permission required to call the `updateVotingSettings` and `updateMinApprovals` functions. |
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.
@clauBv23 - sorry for the long delay in getting to this review. Functionally this looks like it works as specified in the requirements.
The only thing that really makes me uncomfortable is not including minApprovals in the voting setting struct. It is a governance setting just like the others, so having it separate, and with its own permission doesn't make any practical sense.
Will this always be a problem when we want to extend the functionality of existing plugins? Are there any other product inputs that can help inform how to improve this decision?
Closing this as the same changes have already been applied by another PR. |
Task ID: OD-1451
TBD:
updateMinApproval
permission id should beUPDATE_VOTING_SETTINGS_PERMISSION_ID
or a new one should be created?initialize
function on Token voting should revert or continue allowing initialize the plugin withoutminApproval
value?