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

Delegate override vote #5160

Closed
wants to merge 9 commits into from

Conversation

Amxx
Copy link
Collaborator

@Amxx Amxx commented Aug 22, 2024

No description provided.

Copy link

changeset-bot bot commented Aug 22, 2024

⚠️ No Changeset found

Latest commit: 45cb330

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

* @dev Extension of {Governor} which enables delegatees to override the vote of their delegates. This module requires a
* token token that inherits `VotesOverridable`.
*/
abstract contract GovernorOverrideDelegateVote is GovernorVotes {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This appears to be a voting module. Should be named accordingly?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, usually counting module does not inherit from GovernorVotes. Could we avoid that in heritance?

Copy link

Choose a reason for hiding this comment

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

It is both a voting module and a counting module. Maybe it could be something like GovernorCountingAndVotesOverrideDelegate?

Copy link

Choose a reason for hiding this comment

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

Yes it can be removed. The reason to inherit GovernorVotes is that this is strictly additional functionality to it and it makes inheriting GovernorVotesQuorumFraction simpler since it also inherits GovernorVotes.

Copy link
Member

Choose a reason for hiding this comment

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

I agree it's not necessary to inherit from GovernorVotes, a developer building on Governor would pick a votes module and a counting module, while the quorum fraction is optional.

In such case, I would name it GovernorCountingOverride

Copy link

Choose a reason for hiding this comment

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

I agree it's not necessary to inherit from GovernorVotes, a developer building on Governor would pick a votes module and a counting module, while the quorum fraction is optional.

In such case, I would name it GovernorCountingOverride

We could theoretically isolate this to be just a counting module and have a different voting module which implements _getPastDelegate and _getPastBalanceOf. This module would then be dependent on the usage of that voting module. Since they would be so intertwined and relatively useless on their own, I chose this approach which is a voting and counting module in one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think inheriting from GovernorVotes to get acces to token() is fine.

For the name I think it should be succinct yet explicit about what it achieves. I think the current name may be a bit too long.

This is just a proposition:

Suggested change
abstract contract GovernorOverrideDelegateVote is GovernorVotes {
abstract contract GovernorCountOverridable is GovernorVotes {

Comment on lines 153 to 155
if (proposalVote.overrideVoteReceipt[account].hasVoted) {
revert GovernorAlreadyCastVoteOverride(account);
}
Copy link

Choose a reason for hiding this comment

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

This is a check to ensure that the delegatee does not override vote twice. An override vote can come at any time when voting is allowed.

uint256 forVotes;
uint256 abstainVotes;
mapping(address voter => VoteReceipt) voteReceipt;
mapping(address voter => VoteReceipt) overrideVoteReceipt;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nobody is going to override the override ... so we should not need to track the support of the override, do we?
Feels to me that the override part of the Receipt only needs to be a boolean.

Also, could we use a single mapping for receipt, with the receipt structure being

  • bool hasVoted
  • uint8 voteSupport
  • bool hasOverriden
  • uint256 (or smaller?) overrideWeight

That would give better datalocality when we move to verkle.

Note, you could even merge hasVoted + support by storing support + 1 (here we control that support is never going to be 255, so overflow are not an issue)

Copy link

Choose a reason for hiding this comment

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

Nobody is going to override the override ... so we should not need to track the support of the override, do we? Feels to me that the override part of the Receipt only needs to be a boolean.

Yes this is correct. Also, given that snapshots within Votes are stored as uint208, we only need to allocate that to overrideWeight. So we could fit it all into one slot.

@Amxx
Copy link
Collaborator Author

Amxx commented Aug 22, 2024

I'd like to discuss the use of vote with params, versus using dedicated functions caseOverrideVote, caseOverrideVoteBySig

error GovernorAlreadyCastVoteOverride(address account);

mapping(uint256 proposalId => ProposalVote) private _proposalVotes;
mapping(address account => mapping(uint256 proposalId => uint256 votes)) private _overrideVoteWeight;
Copy link
Member

Choose a reason for hiding this comment

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

I think we can use the same ProposalVote structure to include this. In the end, a voter that overrides its delegate is emitting a vote too. That also brings better data locality for Verkle as @Amxx pointed out.

contracts/governance/utils/VotesOverridable.sol Outdated Show resolved Hide resolved
mapping(address voter => VoteReceipt) voteReceipt;
}

error GovernorAlreadyCastVoteOverride(address account);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

IMO that would be more "natural" to read, what do you think ?

Suggested change
error GovernorAlreadyCastVoteOverride(address account);
error GovernorVoteAlreadyOverriden(address account);

@Amxx Amxx closed this Sep 9, 2024
@Amxx Amxx mentioned this pull request Sep 9, 2024
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants