Last Man Standing

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

Wrong require in claimThrone.

Wrong requirement in claimThrone function through which no one able to claim the throne.

Description

  1. require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim."); . This statement is wrong because through which no one able to claim the throne because this line reverts due to msg.sender == currentKing.

function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim."); @audit wrong require
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
// Calculate platform fee
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
// Defensive check to ensure platformFee doesn't exceed available amount after previousKingPayout
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance = platformFeesBalance + currentPlatformFee;
// Remaining amount goes to the pot
amountToPot = sentAmount - currentPlatformFee;
pot = pot + amountToPot;
// Update game state
currentKing = msg.sender;
lastClaimTime = block.timestamp;
playerClaimCount[msg.sender] = playerClaimCount[msg.sender] + 1;
totalClaims = totalClaims + 1;
// Increase the claim fee for the next player
claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
emit ThroneClaimed(msg.sender, sentAmount, claimFee, pot, block.timestamp);
}

Risk : High because it completely blocks expected progression and would likely be caught only after deployment by users failing to claim, causing trust/retention loss or requiring a contract patch/reset.I

Likelihood:

  • Likelihood: Very High for the conditional bug being triggered in any real usage after first king is set—every challenger will fail. The issue is deterministic and guaranteed as soon as someone tries to dethrone.

  • Risk: High because it completely blocks expected progression and would likely be caught only after deployment by users failing to claim, causing trust/retention loss or requiring a contract patch/reset.


  • Impact:

  • After the first throne claim, no new player can become king because challengers fail the require check—game stalls.

  • Users trying to claim after the initial king will see a revert with message that conflicts with condition semantics, making debugging/support harder.

Proof of Concept


Here is the ouput of the code.

Ran 1 test for test/Game.t.sol:GameTest
[FAIL: Game: You are already the king. No need to re-claim.] test_claimThrone() (gas: 46334)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 900.58µs (36.88µs CPU time)

function test_claimThrone() public {
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
assertEq(game.currentKing(), player1);
}

Recommended Mitigation

Change the require statement (msg.sender == currentKing) to (msg.sender != currentKing).

- require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim.");
+ require(msg.sender != currentKing, "Game: You are already the king. No need to re-claim.");
Updates

Appeal created

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

Game::claimThrone `msg.sender == currentKing` check is busted

Support

FAQs

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