Root + Impact
Description
* @dev Emitted when the game ends and a winner is declared.
* @param winner The address of the declared winner.
* @param prizeAmount The total prize amount won.
* @param timestamp The block timestamp when the winner was declared.
* @param round The game round that just ended.
*/
event GameEnded(
address indexed winner,
uint256 prizeAmount,
uint256 timestamp,
uint256 round
);
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: Medium
Proof of Concept
The following test code fails due to the logs being different
function testDeclareWinner() public {
vm.startPrank(player1);
vm.expectRevert("Game: No one has claimed the throne yet.");
game.declareWinner();
game.claimThrone{value: 1 ether}();
vm.expectRevert("Game: Grace period has not expired yet.");
game.declareWinner();
vm.warp(block.timestamp + GRACE_PERIOD + 1 days);
vm.expectEmit(true, true, false, true);
emit GameEnded(player1, game.pot(), block.timestamp, 1);
game.declareWinner();
vm.stopPrank();
uint256 winnings = game.pendingWinnings(player1);
assertEq(winnings, 0.95 ether);
assertEq(game.gameEnded(), true);
}
Recommended Mitigation
The value of the current prize amount should be saved before resetting the pot to 0, and this value should then be used instead.
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;
+ uint256 prizeAmount = pot; // Store pot value before resetting
pendingWinnings[currentKing] = pendingWinnings[currentKing] + prizeAmount;
pot = 0; // Reset pot after assigning to winner's pending winnings
- emit GameEnded(currentKing, pot, block.timestamp, gameRound);
+ emit GameEnded(currentKing, prizeAmount, block.timestamp, gameRound);
}