Incorrect denominator used when determining the rewards per voter will lock ETH in the contract, unless all voters vote "For".
The logic used to determine the reward amount to send to each "For" voter is flawed. The contract is dividing by all voters, rather than the number of "For" voters, as intended. This results in some ETH value (in proportion to the "Against" voters) being locked in the contract.
rewardPerVoter
should not be divided by the total votes, as it is here:
and here:
Rather, they should be divded by totalVotesFor
. This also aligns with the comments and README.
The only way the balance is spent from the VotingBooth
contract is via _distributeRewards()
. After _distributeRewards()
is called, if there is any ETH remaining in the contract balance, it's locked. Depending on the reward level, this could be a large loss of value to the creator, and be extension, to those that voted "For".
Initially I created an invariant fuzz test, like so:
Not shown is the setup function which used targetSender()
to constrain the voter msg.sender
to the list of voters. This test showed that the balance of the contract was not 0 when voting was complete, as was intended, when the vote passed, but some portion of the quorum voted against.
I then moved to a unit test / PoC to show that the remaining balance was the portion of "Against" votes. For example, in a quorum of 5, if two voted "Against", the amount of reward left in the contract was 40%. (2/5 = 0.4). The following test passes, but it's exhibiting a flaw, and showing the specifics of the flawed results.
Write fuzz tests for all invariants to catch logic issues. Consider expanding on unit tests for more edge cases (current tests had all true or all false). Finding issues with fuzz tests can help direct better unit tests.
Change the logic for calculating rewardPerVoter
to divide by totalVotesFor
. Further, consider changing the name of the variable to align with the intention, e.g. rewardPerForVoter
. In this instance, the name of the variable aligned with the flawed logic and not the intent. If the logic is changed, the variable name should be considered for update.
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.