Last Man Standing

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

H01. Incorrect Logic in Reclaim Prevention

Root + Impact

Description

Normal behavior:
In the game, players compete to become the King by paying an ETH claim fee. Once someone becomes the King, they are expected to hold the throne for a certain duration (gracePeriod) to win. The claimThrone() function is supposed to prevent the current King from reclaiming the throne unnecessarily, as they already control it.

Issue:
The logic intended to block the current king from reclaiming is flawed. Instead, it currently only allows the current king to call claimThrone(), and rejects all others, making the game unplayable once someone becomes King.

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

  • The intention (based on the error message) was to block msg.sender == currentKing.

  • Instead, the condition does the opposite, allowing only the current king to claim, and rejecting everyone else.


Risk

Likelihood:

  • Always occurs after the first player claims the throne.

  • The contract will then reject all future throne claims from other users.

Impact:

  • Effectively bricks the game after the first claim.

  • No one else can participate.

  • The pot stops growing.

  • The game ends only after the grace period, with zero competition.

  • Severely damages gameplay, engagement, and trust.


Proof of Concept

// Setup
game.claimThrone{value: 1 ether}(); // Alice becomes king
// Bob tries to claim the throne
vm.prank(bob);
game.claimThrone{value: game.claimFee()}();
// Reverts with: "Game: You are already the king" (but Bob is not the king)


Recommended Mitigation

Correct the logic to block the current king from reclaiming, but allow all others:

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.");
+ require(msg.sender != currentKing, "Game: You are already the king. No need to re-claim.");

This change ensures that only non-kings can claim the throne, as originally intended.

Alternatively, if you want to allow the king to reclaim (to reset their timer strategically), you could remove the line entirely.

Updates

Appeal created

inallhonesty Lead Judge 9 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.