Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Uncontrolled Mid-Game Fee Parameter Updates Lead to Unfair, Exponential Claim Fees

Root + Impact

Root Cause: updateClaimFeeParameters allows modifying feeIncreasePercentage at any time -> Impact: Owner can immediately set the multiplier to 100%, causing claim fees to double or more each round, gouging subsequent players.

WHY WOULD ANYONE TRUST THE OWNER: It's a Game something similar to a gamble. So we can't expect the owner to be fair. The owner can change the rules at any time, so we can't expect the game to be fair.

Description

  • The updateClaimFeeParameters(uint256 _newInitialClaimFee, uint256 _newFeeIncreasePercentage) function permits the owner to change both the base claim fee and the fee increase percentage during an active round. Because each call to claimThrone() updates the next round’s fee as:

@> claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
function updateClaimFeeParameters(
uint256 _newInitialClaimFee,
uint256 _newFeeIncreasePercentage
) external onlyOwner isValidPercentage(_newFeeIncreasePercentage) {
require(_newInitialClaimFee > 0, "Game: New initial claim fee must be greater than zero.");
initialClaimFee = _newInitialClaimFee;
@> // ❌ Updates feeIncreasePercentage during an active round
feeIncreasePercentage = _newFeeIncreasePercentage;
emit ClaimFeeParametersUpdated(_newInitialClaimFee, _newFeeIncreasePercentage);
}

Risk

Likelihood: Medium

  • an owner can, mid-game, set feeIncreasePercentage = 100. On the very next claim, claimFee doubles (100% increase). This allows the owner to arbitrarily and immediately inflate fees, forcing latecomers to pay exponentially more-without any warning or recourse.

  • Unrestricted Timing: No check preventing parameter updates while players are mid-round.

  • Immediate Effect: The next call to claimThrone() uses the new feeIncreasePercentage, causing an unexpected spike in required fee.

Impact: Medium

  • Fee Gouging: Participants can be forced to pay 2×, 3×, or more the expected fee, if the fee increase percentage is set to 100% each time a new player claims.

  • Rapid Exponential Growth: A malicious owner could set percentage to 100%, causing fees to jump by 200%, 500%, etc., bankrupting unsuspecting players.

  • Trust Erosion: Users lose confidence in predictable game economics when fees can be manipulated mid-round.

  • Real-World Parallel: In 2020, bZx’s oracle manipulation exploited mid-transaction price updates to leverage loans, illustrating the danger of allowing admins to change critical parameters on-the-fly.

Tools Used:

  • Foundry Test Suite

  • Chat-GPT AI Assistance (Report Grammar Check & Improvements)

  • Manual Review

Proof of Concept

function test_claimFeeCanBeChargedUnfairlyFromsubsquentParticipants() public {
vm.startPrank(deployer);
game.updateClaimFeeParameters(INITIAL_CLAIM_FEE, 100);
vm.stopPrank();
uint256 claimFeeForPlayer1 = game.claimFee();
vm.startPrank(player1);
game.claimThrone{value: claimFeeForPlayer1}();
vm.stopPrank();
uint256 claimFeeForSubsequentParticipants = game.claimFee();
assertEq(claimFeeForPlayer1 * 2, claimFeeForSubsequentParticipants);
}

step 1: go to test/Game.t.sol file

step 2: paste the above code ⬆️

step 3: run the test suite

forge test --mt test_claimFeeCanBeChargedUnfairlyFromsubsquentParticipants

step 4: See the Output

Scenario:

  1. Owner Raises Multiplier
    The owner calls:

    game.updateClaimFeeParameters(game.initialClaimFee(), 100);

    meaning each new claim will now increase the fee by 100%.

  2. First Participant Pays Normal Fee
    Player1 calls:

    game.claimThrone{value: game.claimFee()}();

    and becomes king; the next fee doubles.

  3. Subsequent Participant Gouged
    Player2 sees claimFee has doubled. If original was 1 ETH, now it’s 2 ETH. Player2 must pay 2 ETH (rather than an expected e.g. 1.05 ETH).

Recommended Mitigation

Restrict feeIncreasePercentage Parameter Updates to Round Boundaries in updateClaimFeeParameters

+ if(gameEnded) {
+ feeIncreasePercentage = _newFeeIncreasePercentage;
+ }
-ensures changes only apply before a new round starts.

Immutable Fee Increase Percentage During a Round

- Keep `feeIncreasePercentage` constant until after `declareWinner()` and `resetGame()` complete.
Updates

Appeal created

inallhonesty Lead Judge 30 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
theirrationalone Submitter
30 days ago
theirrationalone Submitter
30 days ago
inallhonesty Lead Judge
29 days ago
inallhonesty Lead Judge 26 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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