Last Man Standing

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

[H-1] Game::claimThrone() Permanently Locks Throne Due to Faulty Require Check

Root

A faulty require check in the Game::claimThrone() function that prevents anyone including non-kings from claiming the throne.

Impact

No one can become the king the core functionality of the game is blocked permanently.

Description

Normal Behavior:
Any user should be able to claim the throne by sending the required claimFee() and become the currentKing. Only the currentKing should be restricted from calling claimThrone() again to avoid redundant updates.

Bug:
In the current implementation, even the first user to call claimThrone() gets blocked by the require condition because the contract incorrectly assumes currentKing == msg.sender before the first successful claim. As a result, no one can claim the throne, making the game unplayable.

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.");
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

Likelihood: HIGH

  • This bug always occurs on the first claim, preventing anyone from participating.

  • The game becomes immediately unusable on deployment.

Impact: HIGH

  • No player can ever become the currentKing.

  • Game flow is completely broken; users are blocked from interacting even if the fee is correct.

Proof of Concept

function testAnyoneExceptCurrentKingCannotClaim_BugProof() public {
vm.prank(player1);
game.claimThrone{value: game.claimFee()}();
assertEq(game.currentKing(), player1); // Fails here due to require reverting as address(0) is the current king.
}
// So the whole game just breaks down just after deploying because as currentKing will be address(0) so no one can claim the throne.

Recommended Mitigation

- require(msg.sender == currentKing, "You are already the king. No need to re-claim.");
+ require(currentKing == address(0) || msg.sender != currentKing, "You are already the king. No need to re-claim.");
// Just correcting the require logic will do it.
Updates

Appeal created

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

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

eeseohen Auditor
7 days ago
inallhonesty Lead Judge 5 days 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.