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

Risk of loss of funds due to incorrect reward distribution

Summary

The smart contract manages a voting mechanism where a reward in ETH is distributed among voters based on the majority vote. When the majority votes "for," but there are individuals who voted against, the reward distribution is flawed. There's a miscalculation in the reward distribution logic that incorrectly divides the reward by the total number of votes instead of only among the voters who voted "for" the proposal.

Vulnerability Details

The contract tracks voters who cast their votes "for" and "against" a proposal. Upon tallying the votes, it computes the total number of votes for and against the proposal, respectively. The issue arises during the distribution of rewards where it incorrectly divides the reward among all voters, but it only distributes the reward to the voters who voted "for." The flawed reward calculation and distribution logic are as follows:

uint256 totalVotesFor = s_votersFor.length;
uint256 totalVotesAgainst = s_votersAgainst.length;
uint256 totalVotes = totalVotesFor + totalVotesAgainst;
uint256 totalRewards = address(this).balance;
uint256 rewardPerVoter = totalRewards / totalVotes;
for (uint256 i; i < totalVotesFor; ++i) {
if (i == totalVotesFor - 1) {
rewardPerVoter = Math.mulDiv(totalRewards, 1, totalVotes, Math.Rounding.Ceil);
}
_sendEth(s_votersFor[i], rewardPerVoter);
}

The contract computes rewardPerVoter based on the total number of votes (both "for" and "against"), yet it only sends rewards to the voters who voted "for." Consequently, it incorrectly divides the reward among all voters, leading to an incorrect distribution and loss of funds.

Impact

The flaw in the reward distribution logic results in an incorrect division of rewards among voters. Although the intention is to distribute rewards only among the voters who voted "for," the contract divides the reward among all voters, leading to an incorrect distribution of ETH rewards. This incorrect distribution causes an imbalance, leaving ETH locked in the contract indefinitely.

PoC

Add the test in the file: test/VotingBoothTest.t.sol

Run the test:

forge test --mt testIncorrectRewardDistribution
function testIncorrectRewardDistribution() public {
vm.prank(address(0x1));
booth.vote(false);
vm.prank(address(0x2));
booth.vote(true);
vm.prank(address(0x3));
booth.vote(true);
assert(address(booth).balance > 0);
}

Tools Used

Foundry

Recommendations

Update the reward calculation logic

- uint256 rewardPerVoter = totalRewards / totalVotes;
+ uint256 rewardPerVoter = totalRewards / totalVotesFor;
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.