Medium Risk
https://github.com/Cyfrin/2024-04-Baba-Marta/blob/main/src/MartenitsaVoting.sol#L57-L74
The announceWinner
function in the MartenitsaVoting.sol
contract does not handle tie scenarios properly. In cases where multiple tokens receive the same maximum number of votes, only the first token encountered is announced as the winner, neglecting other tokens with the same vote count.
The vulnerability lies in the logic of the announceWinner
function, which does not handle tie scenarios properly. In cases where multiple tokens receive the same maximum number of votes, only the first token encountered is announced as the winner, neglecting other tokens with the same vote count.
Proof of Concept (POC) to be added to MartenitsaVoting.t.sol:
function testVoteForMartenitsaTwice() public listMartenitsa {
vm.startPrank(chasy);
martenitsaToken.createMartenitsa("bracelet2");
marketplace.listMartenitsaForSale(1, 1 wei);
vm.stopPrank();
vm.prank(address(uint160(1)));
voting.voteForMartenitsa(0);
vm.prank(address(uint160(2)));
voting.voteForMartenitsa(1);
assert(voting.voteCounts(0) == 1);
assert(voting.voteCounts(1) == 1);
}
function testAnnounceWinnerWrongly() public {
testVoteForMartenitsaTwice();
vm.warp(block.timestamp + 1 days + 1);
vm.recordLogs();
voting.announceWinner();
Vm.Log[] memory entries = vm.getRecordedLogs();
address winner = address(uint160(uint256(entries[0].topics[2])));
assert(winner == chasy);
}
This vulnerability can lead to incorrect determination of winners in tie scenarios, resulting in unfair outcomes and potentially undermining the integrity and credibility of the voting process. It may also impact user trust in the platform and the reliability of voting results.
manual code review.
To address this vulnerability and ensure fair determination of winners in tie scenarios, it is recommended to modify the announceWinner
function to handle tie situations appropriately. Consider implementing logic to identify and announce all tied tokens as winners if they share the maximum vote count.
Example:
function announceWinner() external onlyOwner {
require(block.timestamp >= startVoteTime + duration, "The voting is active");
uint256 maxVotes = 0;
address[] memory winners;
// Find the maximum number of votes
for (uint256 i = 0; i < _tokenIds.length; i++) {
if (voteCounts[_tokenIds[i]] > maxVotes) {
maxVotes = voteCounts[_tokenIds[i]];
}
}
// Identify all tokens with the maximum vote count as winners
for (uint256 i = 0; i < _tokenIds.length; i++) {
if (voteCounts[_tokenIds[i]] == maxVotes) {
winners.push(_tokenIds[i]);
}
}
// Distribute rewards to all winners
for (uint256 i = 0; i < winners.length; i++) {
list = _martenitsaMarketplace.getListing(winners[i]);
_healthToken.distributeHealthToken(list.seller, 1);
emit WinnerAnnounced(winners[i], list.seller);
}
}