The game's integrity relies on a stable and predictable set of rules for the duration of an active round. Players commit funds and strategize based on the currently defined gracePeriod
and fee structure.
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {console2} from "forge-std/console2.sol";
import {Game} from "../src/Game.sol";
* @title OwnerManipulationVerificationTest
* @dev Verify the accuracy of "Owner Can Manipulate Game Parameters" report
* @dev Tests whether owner can actually change game parameters during active round
*/
contract OwnerManipulationVerificationTest is Test {
Game public game;
address public owner;
address public player1;
address public player2;
function setUp() public {
owner = makeAddr("owner");
player1 = makeAddr("player1");
player2 = makeAddr("player2");
vm.deal(owner, 10 ether);
vm.deal(player1, 10 ether);
vm.deal(player2, 10 ether);
vm.startPrank(owner);
game = new Game(0.1 ether, 1 days, 10, 5);
vm.stopPrank();
}
* @dev Test verifying that owner can change gracePeriod during active game
* @dev This simulates the scenario described in the report
*/
function test_OwnerCanManipulateGracePeriodDuringActiveGame() public {
console2.log("=== Testing Owner Manipulation of Grace Period During Active Game ===");
bytes32 kingSlot = bytes32(uint256(1));
bytes32 lastClaimTimeSlot = bytes32(uint256(2));
bytes32 potSlot = bytes32(uint256(4));
vm.store(address(game), kingSlot, bytes32(uint256(uint160(player1))));
vm.store(address(game), lastClaimTimeSlot, bytes32(block.timestamp));
vm.store(address(game), potSlot, bytes32(uint256(1 ether)));
assertEq(game.currentKing(), player1, "Setup failed: King was not set correctly");
assertEq(game.pot(), 1 ether, "Setup failed: Pot was not set correctly");
uint256 originalGracePeriod = game.gracePeriod();
console2.log("Original grace period:", originalGracePeriod, "seconds");
assertEq(originalGracePeriod, 1 days, "Original grace period should be one day");
vm.warp(block.timestamp + originalGracePeriod - 30 minutes);
console2.log("Current time:", block.timestamp);
console2.log("Original grace period expiry time:", game.lastClaimTime() + originalGracePeriod);
vm.expectRevert("Game: Grace period has not expired yet.");
game.declareWinner();
console2.log("Confirmed: Cannot declare winner before grace period expires");
vm.startPrank(owner);
uint256 newGracePeriod = 1;
game.updateGracePeriod(newGracePeriod);
vm.stopPrank();
console2.log("New grace period:", game.gracePeriod(), "seconds");
assertEq(game.gracePeriod(), newGracePeriod, "Failed to update grace period");
uint256 timeElapsed = block.timestamp - game.lastClaimTime();
console2.log("Time elapsed since last claim:", timeElapsed, "seconds");
console2.log("New grace period:", newGracePeriod, "seconds");
assertTrue(timeElapsed > newGracePeriod, "Time elapsed should be greater than new grace period");
game.declareWinner();
assertTrue(game.gameEnded(), "VULNERABILITY CONFIRMED: Owner was able to force early game end");
console2.log("VULNERABILITY CONFIRMED: Owner was able to change game rules during active round");
}
* @dev Test verifying that owner can change platform fees during active game
*/
function test_OwnerCanManipulatePlatformFeesDuringActiveGame() public {
console2.log("=== Testing Owner Manipulation of Platform Fees During Active Game ===");
bytes32 kingSlot = bytes32(uint256(1));
vm.store(address(game), kingSlot, bytes32(uint256(uint160(player1))));
uint256 originalPlatformFee = game.platformFeePercentage();
console2.log("Original platform fee:", originalPlatformFee, "%");
vm.startPrank(owner);
uint256 newPlatformFee = 50;
game.updatePlatformFeePercentage(newPlatformFee);
vm.stopPrank();
assertEq(game.platformFeePercentage(), newPlatformFee, "Failed to update platform fee");
console2.log("New platform fee:", game.platformFeePercentage(), "%");
console2.log("VULNERABILITY CONFIRMED: Owner was able to change platform fees during active game");
}
* @dev Test verifying that owner can change claim fee parameters during active game
*/
function test_OwnerCanManipulateClaimFeeParametersDuringActiveGame() public {
console2.log("=== Testing Owner Manipulation of Claim Fee Parameters During Active Game ===");
bytes32 kingSlot = bytes32(uint256(1));
vm.store(address(game), kingSlot, bytes32(uint256(uint160(player1))));
uint256 originalInitialClaimFee = game.initialClaimFee();
uint256 originalFeeIncreasePercentage = game.feeIncreasePercentage();
console2.log("Original initial claim fee:", originalInitialClaimFee);
console2.log("Original fee increase percentage:", originalFeeIncreasePercentage, "%");
vm.startPrank(owner);
uint256 newInitialClaimFee = 10 ether;
uint256 newFeeIncreasePercentage = 100;
game.updateClaimFeeParameters(newInitialClaimFee, newFeeIncreasePercentage);
vm.stopPrank();
assertEq(game.initialClaimFee(), newInitialClaimFee, "Failed to update initial claim fee");
assertEq(game.feeIncreasePercentage(), newFeeIncreasePercentage, "Failed to update fee increase percentage");
console2.log("New initial claim fee:", game.initialClaimFee());
console2.log("New fee increase percentage:", game.feeIncreasePercentage(), "%");
console2.log("VULNERABILITY CONFIRMED: Owner was able to change fee parameters during active game");
}
* @dev Test to verify no protection mechanisms exist
*/
function test_NoProtectionMechanismsExist() public {
console2.log("=== Testing Absence of Protection Mechanisms ===");
bytes32 kingSlot = bytes32(uint256(1));
vm.store(address(game), kingSlot, bytes32(uint256(uint160(player1))));
assertFalse(game.gameEnded(), "Game should be active");
vm.startPrank(owner);
game.updateGracePeriod(2 days);
game.updatePlatformFeePercentage(20);
game.updateClaimFeeParameters(0.2 ether, 15);
vm.stopPrank();
console2.log("Confirmed: All admin functions work during active game");
console2.log("NO PROTECTION MECHANISMS exist to prevent parameter changes during active game");
}
}
$ forge test --match-path test/OwnerManipulationVerification.t.sol -vv
Ran 4 tests for test/OwnerManipulationVerification.t.sol:OwnerManipulationVerificationTest
[PASS] test_NoProtectionMechanismsExist() (gas: 51036)
Logs:
=== Testing Absence of Protection Mechanisms ===
Confirmed: All admin functions work during active game
NO PROTECTION MECHANISMS exist to prevent parameter changes during active game
[PASS] test_OwnerCanManipulateClaimFeeParametersDuringActiveGame() (gas: 43859)
Logs:
=== Testing Owner Manipulation of Claim Fee Parameters During Active Game ===
Original initial claim fee: 100000000000000000
Original fee increase percentage: 10 %
New initial claim fee: 10000000000000000000
New fee increase percentage: 100 %
VULNERABILITY CONFIRMED: Owner was able to change fee parameters during active game
[PASS] test_OwnerCanManipulateGracePeriodDuringActiveGame() (gas: 87518)
Logs:
=== Testing Owner Manipulation of Grace Period During Active Game ===
Original grace period: 86400 seconds
Current time: 84601
Original grace period expiry time: 86401
Confirmed: Cannot declare winner before grace period expires
New grace period: 1 seconds
Time elapsed since last claim: 84600 seconds
New grace period: 1 seconds
VULNERABILITY CONFIRMED: Owner was able to change game rules during active round
[PASS] test_OwnerCanManipulatePlatformFeesDuringActiveGame() (gas: 31952)
Logs:
=== Testing Owner Manipulation of Platform Fees During Active Game ===
Original platform fee: 5 %
New platform fee: 50 %
VULNERABILITY CONFIRMED: Owner was able to change platform fees during active game
Suite result: ok. 4 passed; 0 failed; 0 skipped
The successful execution of the entire test suite confirms that all administrative parameter-setting functions lack the necessary safeguards and can be called during an active game, validating the vulnerability.
To preserve the integrity and fairness of the game, all administrative functions that alter core game mechanics should be disabled while a game round is active. These parameters should only be configurable between rounds.
This change ensures that the rules of the game are locked in once a round begins, providing a fair and predictable environment for all players.