Calculation of rewards after a proposal has passed may result in funds getting permanently stuck in the voting booth.
After a proposal has passed the contract calculates how much reward each For voter has earned and runs a loop to reward those voters.
The problem with how rewardPerVoter
is calculated is that totalVotes
is assumed to represent all the For voters when in fact it accounts for all the cast votes (For and Against). In a situation in which a passed proposal contains a mix of votes, rewardPerVoter
is calculated but only the For voters are rewarded and this results in an amount of rewards getting stuck in the contract.
Let's assume 7 voters were allowed to cast their vote in a proposal and the reward to distribute is 1 ETH. Quorum is reached (55%) after the first 4 voters cast their votes in the following way: true, true, true, false
, this means there are 3 For voters and 1 Against voter. The reward per voter is calculated as such:
Then the loop runs to reward the For voters and this will result in 0.25 ETH getting stuck in the contract forever, because 1 of the voters voted against the proposal but was taken into consideration to calculate the reward.
We can leverage Foundry's fuzzing tests capabilities to extend the example from above and prove that there is a wide range of votes combinations that will result in the same outcome.
Copy and paste the following test case in VotingBoothTest.t.sol
to see the effect of this bug.
Rewards permanently stuck in the contract.
Manual verification and Foundry's fuzz test.
Update VotingBooth::_distributRewards
to only use the For voters to calculate the distribute the rewads.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.