Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Flawed Calculation in `VotingBooth::_distributeRewards` leads to Incorrect Distribution for 'For' Voters, Resulting in Fund Loss

Description:

The _distributeRewards function is designed to incentivize voters who support a proposal by rewarding only the for voters. However, there is an issue in the implementation where the rewardPerVoter is calculated using the totalVotes variable instead of totalVotesFor. Consequently, the average rewardPerVoter is computed considering all votes, but the rewards are distributed exclusively to the for voters, leaving an unallocated remainder for the against voters.

Impact:

For every against voter the rewards will be stuck in the protocol forever.

Proof of Concept:

  1. Setup:

    • Create a Voting Booth with 5 addresses.

    • Set the ETH_REWARD to 10 ETH.

  2. Voting:

    • 3 addresses participate in the vote (2 votes for, 1 vote against).

  3. Distribution Calculation:

    • As the quorum is reached, rewards are set to be distributed.

    • Calculate rewardPerVoter: ETH_REWARD / totalVotes = 10 ETH / 3 = 3.333.. ETH.

  4. Incorrect Distribution:

    • The 2 addresses that voted for the proposal receive a total of 6.666.. ETH.

    • However, 3.333.. ETH remains undistributed, causing funds to be stuck in the protocol.

Proof of Code

Using testVotePassesAndMoneyIsSent in VotingBooth.t.sol we set one of the booth.vote() to false.

The test will not pass, because address(booth).balance != 0.

function testVotePassesAndMoneyIsSent() public {
vm.prank(address(0x1));
booth.vote(true);
vm.prank(address(0x2));
booth.vote(false);
vm.prank(address(0x3));
booth.vote(true);
assert(!booth.isActive() && address(booth).balance == 0);
}

Tools Used:

Manual Review and Foundry

Recommended Mitigation:

In order to distribute the whole ETH_REWARD to the for voters, we should use totalVotesFor instead of totalVotes to calculate the rewardPerVoter.

function _distributeRewards() private {
- uint256 totalVotes = totalVotesFor + totalVotesAgainst;
.
.
.
else {
- uint256 rewardPerVoter = totalRewards / totalVotes;
+ uint256 rewardPerVoter = totalRewards / totalVotesFor;
for (uint256 i; i < totalVotesFor; ++i) {
if (i == totalVotesFor - 1) {
- rewardPerVoter = Math.mulDiv(totalRewards, 1, totalVotes, Math.Rounding.Ceil);
+ rewardPerVoter = Math.mulDiv(totalRewards, 1, totalVotesFor, Math.Rounding.Ceil);
}
_sendEth(s_votersFor[i], rewardPerVoter);
}
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

VotingBooth._distributeRewards(): Incorrect computation of rewardPerVoter

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.