Wrong value for prizeAmount in GameEnded event
Description
-
The GameEnded event is emitted with the values of the currentKing, pot/prize, timestamp and gameRound
-
However, the value of pot/prize will always be 0 as the value is reset before the event is emitted.
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: High
Impact: Low
-
The game is still valid, and the winner actually does receive the correct amount as price
-
Any scanners, apps/front-end or indexing based on the events will not work as expected as the prize amount will always be 0
Proof of Concept
To validate the issue, we can run the following test (with the default setup as per Game.t.sol)
function testIssueShouldEventGameEndedEvent() public {
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.warp(block.timestamp + GRACE_PERIOD + 1);
vm.prank(deployer);
console2.log("game.pot()", game.pot());
vm.expectEmit(true, true, true, true);
emit GameEnded(player1, game.pot(), block.timestamp, 1);
game.declareWinner();
assertEq(game.gameEnded(), true);
}
logs
├─ emit GameEnded(winner: player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84], prizeAmount: 95000000000000000 [9.5e16], timestamp: 86402 [8.64e4], round: 1)
├─ [50689] Game::declareWinner()
│ ├─ emit GameEnded(winner: player1: [0x7026B763CBE7d4E72049EA67E89326432a50ef84], prizeAmount: 0, timestamp: 86402 [8.64e4], round: 1)
│ └─ ← [Stop]
└─ ← [Revert] log != expected log
As can be seen in the last lines, we emit the wrong value, where we expect 9.5e16 but we emit 0:
Recommended Mitigation
This issue can be fixed by removing the pot = 0. Note that this will work because:
-
pot will be set to 0 when resetGame is called
-
Any functionality to the pot (claimThrone and declareWinner) cannot be called when gameEnded is true
-
gameEnded is set to true only in resetGame
Meaning that we can safely remove the pot = 0 line in declareWinner()
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);
}