Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

claimThrone() can still be called after grace period expires

Root + Impact

Description

  • After the game ends and is reset, a grace period begins. During this grace period, players are allowed to claim the throne. Once the grace period ends, the last player to claim the throne during that window becomes the winner and can withdraw the pot.


  • The claimThrone() function does not verify whether the grace period has ended. As a result, a user can still call claimThrone() even after the grace period expires, unfairly claiming the throne and restarting the game, thus preventing the rightful winner from withdrawing.

// Root cause: missing grace period expiry check
@> // No require to check block.timestamp <= gameStartTime + gracePeriod

Risk

Likelihood:

  • Happens every time someone claims the throne after the grace period.

  • There’s no protection against late claims.

Impact:

  • A user can front-run the intended winner after timeout.

  • The grace period becomes meaningless.

Proof of Concept

The PoC shows how someone can claim the throne even after the game should’ve ended. Since the contract doesn’t properly check if the grace period is over.

// Added this getter function in Game.sol contract to get the current king
function getCurrentKing() public view returns(address) {
return currentKing;
}
// Main test function
function test_CannotClaimThroneAfterGracePeriodEnds() public {
// Simulate a new round
vm.prank(owner);
game.resetGame(); // Starts the grace period
// Player 1 claims throne during valid window
vm.prank(player1);
game.claimThrone{value: 1 ether}();
// Time passes beyond grace period
vm.warp(block.timestamp + GRACE_PERIOD + 1 days);
// Player 2 claims after expiry – should not be allowed but succeeds
vm.prank(player2);
game.claimThrone{value: 2 ether}();
// The current king becomes Player 2 wrongly
assertEq(game.getCurrentKing(), player2);
}

Recommended Mitigation

Add a check to claimThrone() that reverts if the current time exceeds the grace period window:

// Add this state variable to keep track of the time a round has started
+ uint256 public gameStartTime;
// Add this require statement for grace period checks
+ require(block.timestamp <= gameStartTime + gracePeriod, "Game: grace period ended");
Updates

Appeal created

inallhonesty Lead Judge 9 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Game::claimThrone can still be called regardless of the grace period

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.