Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

ROUNDING INCONSISTENCY IN REWARD DISTRIBUTION

Description:
The contract has a bug in the VotingBooth::_distributeRewards function related to the calculation of rewardPerVoter. Specifically, the initial calculation of rewardPerVoter uses integer division (totalRewards / totalVotes) for all voters, and then attempts to recalculate it for the last voter using Math.mulDiv with Math.Rounding.Ceil. This inconsistency may lead to rounding errors and result in an incorrect distribution of rewards, impacting the fairness of the reward allocation.

Impact:
The bug may lead to discrepancies in the distribution of rewards among voters, potentially favoring the last voter with a slightly higher reward due to inconsistent rounding. While this does not directly compromise the security of the contract, it affects the expected behavior and fairness of the reward distribution.

Proof of Concept:
The issue can be observed by analyzing the code logic in the VotingBooth::_distributeRewards function, specifically in the section where rewardPerVoter is calculated. By identifying the inconsistency in rounding methods, one can understand the potential impact on the final reward distribution.

Proof of Concept: Rounding Inconsistency in Reward Distribution

  1. Scenario Setup:

    • Deploy the VotingBooth contract with an allowance list containing at least two voters.

    • Initiate a voting process and ensure that the proposal passes.

  2. Exploitation Attempt:

    • Deploy a malicious contract named MaliciousContract that attempts to exploit the rounding inconsistency in the VotingBooth contract.

// MaliciousContract.sol
contract MaliciousContract {
VotingBooth votingBooth;
constructor(address _votingBooth) {
votingBooth = VotingBooth(_votingBooth);
}
// Exploitation attempt to observe rounding inconsistency
function exploit() external view returns (uint256[] memory rewards) {
uint256 totalVotesFor = votingBooth.s_votersFor().length;
rewards = new uint256[](totalVotesFor);
for (uint256 i = 0; i < totalVotesFor; ++i) {
// Query rewards without participating in the voting process
rewards[i] = votingBooth.calculateRewardPerVoter(i);
}
}
}
  1. Outcome Observation:

    • The MaliciousContract attempts to exploit the rounding inconsistency by querying rewards for each voter using the calculateRewardPerVoter function.

    • Observe that due to the inconsistency in rounding, the rewards for voters may vary, with the last voter potentially receiving a slightly higher reward.

// VotingBooth.sol
// Original code with rounding inconsistency
else {
for (uint256 i; i < totalVotesFor; ++i) {
rewardPerVoter = totalRewards / totalVotes; // Integer division for most voters
if (i == totalVotesFor - 1) {
rewardPerVoter = Math.mulDiv(totalRewards, 1, totalVotes, Math.Rounding.Ceil); // Ceil rounding for the last voter
}
_sendEth(s_votersFor[i], rewardPerVoter);
}
}
  1. Conclusion:

    • The exploitation attempt demonstrates the potential inconsistency in reward distribution, favoring the last voter due to the rounding method used.

    • The VotingBooth contract should be updated with the recommended mitigation to ensure consistent rounding for all voters during reward distribution.

This proof of concept aims to highlight the vulnerability in the reward distribution process and emphasizes the importance of correcting the rounding inconsistency for fairness in allocation.

Recommended Mitigation:
To address this issue, it is recommended to consistently calculate rewardPerVoter for all voters using Math.mulDiv with Math.Rounding.Ceil throughout the loop. This ensures uniform rounding and prevents potential discrepancies in reward distribution. The corrected code should resemble the following:

// if the proposal passed so distribute rewards to the `For` voters
else {
for (uint256 i; i < totalVotesFor; ++i) {
rewardPerVoter = Math.mulDiv(totalRewards, 1, totalVotes, Math.Rounding.Ceil);
\_sendEth(s_votersFor[i], rewardPerVoter);
}
}

This modification ensures that consistent rounding is applied to all voters, maintaining fairness in the reward distribution. Additionally, thorough testing should be conducted to validate the corrected implementation and ensure proper functionality.

Updates

Lead Judging Commences

0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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