Last Man Standing

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

GracePeriod reset unexpectedly after game reset, causing inconsistency between updated and initial values

Root + Impact

Description

  • The gracePeriod parameter controls how long the current King can hold their throne before another player can claim it. It can be updated by the owner via updateGracePeriod() and is expected to persist for the duration of the game round.

  • While updateGracePeriod() correctly updates the current gracePeriod, calling resetGame() resets the gracePeriod silently back to the original initial value set at contract deployment (initialGracePeriod). This causes a mismatch between the player's expectations (based on the updated gracePeriod) and the actual game behavior after reset.

function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
require(_newGracePeriod > 0, "Game: New grace period must be greater than zero.");
@> gracePeriod = _newGracePeriod;
emit GracePeriodUpdated(_newGracePeriod);
}
function resetGame() external onlyOwner gameEndedOnly {
...
@> gracePeriod = initialGracePeriod;
...
}

Risk

Likelihood:

  • Occurs whenever the owner updates the grace period during an active round, then ends the round and resets the game.

Impact:

  • Players relying on the updated grace period might be misled, affecting their strategies.

  • Gameplay fairness and predictability are compromised.

  • Could result in users missing winning conditions or unexpected game resets.

Proof of Concept

After updating the grace period, it works as expected during the round. But when the game is reset, the grace period silently reverts to the original value. This mismatch can confuse users and affect gameplay.

function testGracePeriodResetsUnexpectedly() public {
// Update the grace period to a new value (2 days)
vm.startPrank(deployer);
uint256 newGracePeriod = 2 days;
game.updateGracePeriod(newGracePeriod);
vm.stopPrank();
// Verify the grace period was updated correctly
assertEq(game.getCurrentGracePeriod(), newGracePeriod);
// Player1 claims the throne, and ends the current game round
vm.startPrank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.warp(block.timestamp + newGracePeriod + 1);
game.declareWinner();
// Owner resets the game for a new round. Verify that the grace period has been reset to the initial default value
vm.startPrank(deployer);
game.resetGame();
assertEq(game.getCurrentGracePeriod(), GRACE_PERIOD, "back to the old period");
}

Recommended Mitigation

Synchronize updates to initialGracePeriod inside updateGracePeriod() so that resetting the game preserves the updated value:

function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
require(_newGracePeriod > 0, "Game: New grace period must be greater than zero.");
- gracePeriod = _newGracePeriod;
+ initialGracePeriod = _newGracePeriod; // Keep initial value in sync
emit GracePeriodUpdated(_newGracePeriod);
}
Updates

Appeal created

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

Grace period upgrade is not persistent after reset.

Support

FAQs

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