Logical error in the declareWinner() function + Critical Impact
Description
-
The function should be emitting how much the winner (the last king) gets at the GameEnded condition
-
The issue is that the amount shown will always be 0 since, the pot variable was reset to 0 by the declareWinner function
function declareWinner() external gameNotEnded {
require(currentKing != address(0), "Game: No one has claimed the throne yet.");
require(
block.timestamp > lastClaimTime + gracePeriod,
"Game: Grace period has not expired yet."
);
gameEnded = true;
pendingWinnings[currentKing] = pendingWinnings[currentKing] + pot;
pot = 0;
@> emit GameEnded(currentKing, pot, block.timestamp, gameRound);
}
Risk
Likelihood:
Impact:
Proof of Concept
function testDeclareWinnerEvent() public {
game.currentKing = alice;
game.pot = 10 ether;
vm.expectEmit(true, false, false, true);
emit GameEnded(alice, 10 ether, block.timestamp, game.gameRound());
game.declareWinner();
}
Explanation: Sample Scenario
Alice is currentKing and pot is 10 ether.
declareWinner() is called.
GameEnded event emits prizeAmount = 0 instead of 10 ether.
Recommended Mitigation
function declareWinner() external gameNotEnded {
require(currentKing != address(0), "Game: No one has claimed the throne yet.");
require(
block.timestamp > lastClaimTime + gracePeriod,
"Game: Grace period has not expired yet."
);
gameEnded = true;
pendingWinnings[currentKing] = pendingWinnings[currentKing] + pot;
- pot = 0; // Reset pot after assigning to winner's pending winnings
- emit GameEnded(currentKing, pot, block.timestamp, gameRound);
+ emit GameEnded(currentKing, pot, block.timestamp, gameRound);
+ pot = 0; // Reset pot after assigning to winner's pending winnings
}
Explanation : emitting the event first then resetting the variable fixes our error