Description
There is no check in the RankedChoice::_rankCandidates
function for if a voter has already voted in the election. This makes it possible for voters to vote multiple times and manipulate the election result.
Impact
When a voter can vote multiple times in the same election there is a critical issue with governance because it makes it possible to manipulate the election result undermining the integrity of the election.
Proof of Concept
In the code below the same voter votes two times in the same election.
Add this code to the test suit:
function testVoteMultipleTimes() public {
orderedCandidates = [candidates[0], candidates[1], candidates[2]];
vm.prank(voters[0]);
rankedChoice.rankCandidates(orderedCandidates);
vm.prank(voters[0]);
rankedChoice.rankCandidates(orderedCandidates);
vm.warp(block.timestamp + rankedChoice.getDuration());
rankedChoice.selectPresident();
}
Tools used
Manual code review
Recommendation
This could be mitigated by adding a check to the RankedChoice::_rankCandidates
function:
+ error RankedChoice__AlreadyVoted();
+ mapping(address => mapping(uint256 => bool)) private hasVoted;
function _rankCandidates(address[] memory orderedCandidates, address voter) internal {
+ if (hasVoted[msg.sender][s_voteNumber]) {
+ revert RankedChoice__AlreadyVoted();
+ }
+ hasVoted[msg.sender][s_voteNumber] = true;
// Checks
if (orderedCandidates.length > MAX_CANDIDATES) {
revert RankedChoice__InvalidInput();
}
// @audit - An storage array is handled as a memory array
if (!_isInArray(VOTERS, voter)) {
revert RankedChoice__InvalidVoter();
}
// Internal Effects
s_rankings[voter][s_voteNumber] = orderedCandidates;
}