diff --git a/packages/protocol/contracts/governance/Governance.sol b/packages/protocol/contracts/governance/Governance.sol index 633b7d2d23c..f14744c462b 100644 --- a/packages/protocol/contracts/governance/Governance.sol +++ b/packages/protocol/contracts/governance/Governance.sol @@ -1471,7 +1471,8 @@ contract Governance is uint256 maxUsed = 0; for (uint256 index = 0; index < dequeued.length; index = index.add(1)) { - Proposals.Proposal storage proposal = proposals[dequeued[index]]; + uint256 proposalId = dequeued[index]; + Proposals.Proposal storage proposal = proposals[proposalId]; bool isVotingReferendum = (getProposalDequeuedStage(proposal) == Proposals.Stage.Referendum); if (!isVotingReferendum) { @@ -1479,6 +1480,11 @@ contract Governance is } VoteRecord storage voteRecord = voter.referendumVotes[index]; + // skip if vote record is not for this proposal + if (voteRecord.proposalId != proposalId) { + continue; + } + uint256 votesCast = voteRecord.yesVotes.add(voteRecord.noVotes).add(voteRecord.abstainVotes); maxUsed = Math.max( maxUsed, @@ -1514,7 +1520,8 @@ contract Governance is Voter storage voter = voters[account]; for (uint256 index = 0; index < dequeued.length; index = index.add(1)) { - Proposals.Proposal storage proposal = proposals[dequeued[index]]; + uint256 proposalId = dequeued[index]; + Proposals.Proposal storage proposal = proposals[proposalId]; bool isVotingReferendum = (getProposalDequeuedStage(proposal) == Proposals.Stage.Referendum); if (!isVotingReferendum) { @@ -1522,6 +1529,13 @@ contract Governance is } VoteRecord storage voteRecord = voter.referendumVotes[index]; + + // skip if vote record is not for this proposal + if (voteRecord.proposalId != proposalId) { + delete voter.referendumVotes[index]; + continue; + } + uint256 sumOfVotes = voteRecord.yesVotes.add(voteRecord.noVotes).add(voteRecord.abstainVotes); if (sumOfVotes > newVotingPower) { diff --git a/packages/protocol/test-sol/governance/network/Governance.t.sol b/packages/protocol/test-sol/governance/network/Governance.t.sol index 5cfd1db5286..22c56524212 100644 --- a/packages/protocol/test-sol/governance/network/Governance.t.sol +++ b/packages/protocol/test-sol/governance/network/Governance.t.sol @@ -43,12 +43,16 @@ contract GovernanceForTest is Governance(true) { _removeVotesWhenRevokingDelegatedVotes(account, maxAmountAllowed); } - function setDeprecatedWeight(address voterAddress, uint256 proposalIndex, uint256 weight) - external - { + function setDeprecatedWeight( + address voterAddress, + uint256 proposalIndex, + uint256 weight, + uint256 proposalId + ) external { Voter storage voter = voters[voterAddress]; VoteRecord storage voteRecord = voter.referendumVotes[proposalIndex]; voteRecord.deprecated_weight = weight; + voteRecord.proposalId = proposalId; } } @@ -3477,7 +3481,7 @@ contract GovernanceGetAmountOfGoldUsedForVoting is GovernanceBaseTest { vm.warp(block.timestamp + governance.dequeueFrequency()); vm.prank(accApprover); governance.approve(proposalId, 0); - governance.setDeprecatedWeight(accVoter, 0, 100); + governance.setDeprecatedWeight(accVoter, 0, 100, 1); assertEq(governance.getAmountOfGoldUsedForVoting(accVoter), 100); } @@ -3506,6 +3510,27 @@ contract GovernanceGetAmountOfGoldUsedForVoting is GovernanceBaseTest { assertEq(governance.getAmountOfGoldUsedForVoting(accVoter), 0); } + function test_return0Votes_WhenIndexOfProposalGetsReused() public { + uint256 proposalId = makeValidProposal(); + vm.warp(block.timestamp + governance.dequeueFrequency()); + vm.prank(accApprover); + governance.approve(proposalId, 0); + vm.prank(accVoter); + governance.votePartially(proposalId, 0, 10, 30, 0); + vm.warp(block.timestamp + REFERENDUM_STAGE_DURATION); + governance.execute(proposalId, 0); + vm.warp(block.timestamp + governance.getExecutionStageDuration() + 1); + assertEq(governance.getAmountOfGoldUsedForVoting(accVoter), 0); + + governance.dequeueProposalsIfReady(); + proposalId = makeValidProposal(); + + vm.warp(block.timestamp + governance.dequeueFrequency() + 1); + vm.prank(accApprover); + governance.approve(proposalId, 0); + assertEq(governance.getAmountOfGoldUsedForVoting(accVoter), 0); + } + function test_returnFullWeightWhenUpvoting_WhenProposalInQueue() public { vm.prank(accOwner); governance.setConcurrentProposals(3);