Root + Impact
Description
-
Normal behavior:
When the owner updates the grace period, the new value should persist for all future rounds, not just the current one.
Specific issue:
The contract only updates gracePeriod for the current round. When resetGame is called, gracePeriod is set back to initialGracePeriod, ignoring any updates made during previous rounds. This means the admin’s changes are lost after each 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:
Impact:
Proof of Concept
The following test demonstrates the bug. The owner updates the grace period, ends the game, and resets it. The grace period reverts to its original value, not the updated one.
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {Game} from "../src/Game.sol";
contract GameGracePeriodTest is Test {
Game public game;
address public deployer;
address public player;
uint256 public constant INITIAL_CLAIM_FEE = 0.1 ether;
uint256 public constant INITIAL_GRACE_PERIOD = 1 days;
uint256 public constant FEE_INCREASE_PERCENTAGE = 10;
uint256 public constant PLATFORM_FEE_PERCENTAGE = 5;
function setUp() public {
deployer = makeAddr("deployer");
player = makeAddr("player");
vm.deal(deployer, 10 ether);
vm.deal(player, 10 ether);
vm.startPrank(deployer);
game = new Game(
INITIAL_CLAIM_FEE,
INITIAL_GRACE_PERIOD,
FEE_INCREASE_PERCENTAGE,
PLATFORM_FEE_PERCENTAGE
);
vm.stopPrank();
}
function testGracePeriodNotPersistent() public {
vm.startPrank(deployer);
game.updateGracePeriod(3 days);
assertEq(game.gracePeriod(), 3 days, "Grace period should be updated to 3 days");
vm.stopPrank();
vm.startPrank(player);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.stopPrank();
vm.warp(block.timestamp + 3 days + 1);
game.declareWinner();
vm.startPrank(deployer);
game.resetGame();
vm.stopPrank();
assertEq(game.gracePeriod(), INITIAL_GRACE_PERIOD, "Grace period should revert to initial value after reset");
}
}
Recommended Mitigation
Update both gracePeriod and initialGracePeriod together when changing the grace period:
function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
require(_newGracePeriod > 0, "Game: New grace period must be greater than zero.");
- gracePeriod = _newGracePeriod;
+ gracePeriod = _newGracePeriod;
+ initialGracePeriod = _newGracePeriod;
emit GracePeriodUpdated(_newGracePeriod);
}