Last Man Standing

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

Incorrect Access Check in `Game::claimThrone()` Permanently Blocks All Players From Claiming the Throne

Incorrect Access Check in Game::claimThrone() Permanently Blocks All Players From Claiming the Throne

Description

  • Normally, the Last Man Standing game allows any player (except the current king) to pay a fee and claim the throne, becoming the new king and resetting the grace period.

  • However, the following line in the Game::claimThrone() function introduces a critical logic error: it incorrectly restricts the ability to claim the throne only to the current king, instead of excluding them. As a result, no player can ever claim the throne, not even the first one — since currentKing is initialized to address(0), and msg.sender will never match it. This breaks the game entirely and renders the protocol unusable.

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 always occurs from the first interaction: the condition immediately reverts for any address since no one matches the initial value of currentKing (which is address(0)).

  • It prevents every single user from interacting with the core function of the game — including the first player who should normally be able to start the round.

Impact:

  • The game is entirely locked and no progression is possible. No one can claim the throne or win the pot.

  • All funds sent to the contract are essentially trapped, and the game state never advances past initialization.

  • The economic incentives and escalation logic of the game are fully broken.

Proof of Concept

Add the following test to Game.t.sol. This reverts on the first ever throne claim, showing the game is broken at its core.

function testNobodyCanClaimThrone() public {
vm.startPrank(player1);
vm.expectRevert();
game.claimThrone{value: 0.2 ether}();
vm.stopPrank();
}

Recommended Mitigation

The condition should be inverted in order to prevents the king from reclaming their own throne while allowing others to compete.

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