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

Remove abstain votes from quorum calculation #36

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions src/OptimismGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ contract OptimismGovernor is
override(GovernorCountingSimpleUpgradeableV2, IGovernorUpgradeable)
returns (string memory)
{
return "support=bravo&quorum=against,for,abstain&params=modules";
return "support=bravo&quorum=against,for&params=modules";
}

/**
Expand Down Expand Up @@ -842,6 +842,7 @@ contract OptimismGovernor is

/**
* @dev Updated version in which quorum is based on `proposalId` instead of snapshot block.
* @dev Removed abstain votes from quorum calculation. -> Feb 18, 2025
*/
function _quorumReached(uint256 proposalId)
internal
Expand All @@ -850,9 +851,8 @@ contract OptimismGovernor is
override(GovernorCountingSimpleUpgradeableV2, GovernorUpgradeableV2)
returns (bool)
{
(uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = proposalVotes(proposalId);

return quorum(proposalId) <= againstVotes + forVotes + abstainVotes;
(uint256 againstVotes, uint256 forVotes,) = proposalVotes(proposalId);
return quorum(proposalId) <= againstVotes + forVotes;
}

/**
Expand Down
46 changes: 41 additions & 5 deletions test/OptimismGovernor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,10 @@ contract EditProposalType is OptimismGovernorTest {

contract VoteSucceeded is OptimismGovernorTest {
function test_QuorumReachedAndVoteSucceeded(address _voter) public virtual {
_mintAndDelegate(_voter, 100e18);
// Mint and delegate tokens
uint256 requiredVotes = 100e18; // Get around 30% of token supply
_mintAndDelegate(_voter, requiredVotes);

bytes memory proposalData = _formatProposalData(0);
uint256 snapshot = block.number + governor.votingDelay();
string memory reason = "a nice reason";
Expand All @@ -2143,9 +2146,11 @@ contract VoteSucceeded is OptimismGovernorTest {
vm.prank(_voter);
governor.castVoteWithReasonAndParams(proposalId, uint8(VoteType.For), reason, params);

assertTrue(governor.quorum(proposalId) != 0);
assertTrue(governor.quorumReached(proposalId));
assertTrue(governor.voteSucceeded(proposalId));
// Verify quorum is reached with only For votes (no Abstain)
uint256 quorum = governor.quorum(proposalId);
assertTrue(quorum > 0, "Quorum should be non-zero");
assertTrue(governor.quorumReached(proposalId), "Quorum should be reached with For votes");
assertTrue(governor.voteSucceeded(proposalId), "Proposal should succeed");
}

function test_VoteNotSucceeded(address _voter, address _voter2) public virtual {
Expand Down Expand Up @@ -2174,6 +2179,37 @@ contract VoteSucceeded is OptimismGovernorTest {
assertTrue(governor.quorum(proposalId) != 0);
assertFalse(governor.voteSucceeded(proposalId));
}

function test_QuorumNotReachedWithMostlyAbstainVotes(address _voter, address _abstainer) public virtual {
vm.assume(_voter != _abstainer);

// Give abstainer many votes, but for / against voter few votes
_mintAndDelegate(_abstainer, 90e18); // Give 90% of supply for abstain
_mintAndDelegate(_voter, 10e18); // Give 10% of supply for "for" votes

bytes memory proposalData = _formatProposalData(0);
uint256 snapshot = block.number + governor.votingDelay();
string memory reason = "a good reason";

vm.prank(manager);
uint256 proposalId = governor.proposeWithModule(VotingModule(module), proposalData, description, 1);

vm.roll(snapshot + 1);

// Cast a small "for" vote
uint256[] memory optionVotes = new uint256[](1);
bytes memory params = abi.encode(optionVotes);
vm.prank(_voter);
governor.castVoteWithReasonAndParams(proposalId, uint8(VoteType.For), reason, params);

// Cast a large abstain vote
// in the past this would have passed, not now
vm.prank(_abstainer);
governor.castVoteWithReasonAndParams(proposalId, uint8(VoteType.Abstain), reason, params);

// Verify quorum is not reached despite large abstain vote
assertFalse(governor.quorumReached(proposalId), "Quorum should not be reached with mostly abstain votes");
}
}

contract SetModuleApproval is OptimismGovernorTest {
Expand Down Expand Up @@ -2301,7 +2337,7 @@ contract UpgradeToLive is OptimismGovernorTest {
address proxyAdminOP = 0x2501c477D0A35545a387Aa4A3EEe4292A9a8B3F0;

function setUp() public override {
vm.createSelectFork(vm.rpcUrl("https://mainnet.optimism.io"));
vm.createSelectFork(vm.rpcUrl("https://mainnet.optimism.io"), 126844298);
}

function test_UpgradesToNewImplementationAddress() public {
Expand Down