Last Man Standing

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

Game-Stopping Flaw: Incorrect require Condition in claimThrone() Prevents New Kings

Root + Impact

Description

  • Normal Behavior: The claimThrone() function allows any player (other than the current king) to claim the throne by paying the current claimFee. Once claimed, the new king becomes currentKing, and the fee increases for the next player.

  • Issue: The contract contains a faulty require condition that only allows the current king to claim the throne, which is opposite of the intended functionality. As a result, after the first player claims the throne, no other player can ever dethrone them, causing the game to get stuck indefinitely.

// Root cause in the codebase with @> marks to highlight the relevant section
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.");
// ...
}

Risk

Likelihood:

  • This occurs every time a player (who is not the current king) tries to call claimThrone().

  • Deployers or malicious actors can exploit this immediately after deployment, locking the throne forever.

Impact:

  • Game becomes unwinnable after the first claim.

  • ETH funds in pot and platformFeesBalance become permanently locked.

  • Users will lose trust in the contract's fairness and correctness.

  • Admin functions like declareWinner() will never trigger since the game cannot progress.

Proof of Concept

// Simulation Scenario
address PLAYER1 = address(0xABC);
address PLAYER2 = address(0xDEF);
// PLAYER1 claims the throne
vm.prank(PLAYER1);
game.claimThrone{value: initialClaimFee}(); // Passes as expected
// PLAYER2 tries to claim the throne
vm.prank(PLAYER2);
game.claimThrone{value: nextClaimFee}(); // <-- This call will revert!

Recommended Mitigation

- 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 2 months 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.