Last Man Standing

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

Incorrect require condition prevents throne claim by any player, making the game unplayable.

Root + Impact

Description

  • Any contender who is not a current King and pays an amount that is above or equal to the claimFee should be able to claim the Throne.

  • The claimThrone() function contains a critical logic error where the condition is inverted. The current implementation requires the msg.sender to be the current King which prevents anyone except the current King from claiming the throne. However, since the default value of current King is address(0), this condition completely disables the claiming throne functionality, 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.");
...
}

Risk

Likelihood:

  • The bug is triggered every time any player attempts to claim the throne

  • This occurs immediately upon the first claim attempt by any player

  • The game becomes completely non-functional from the first interaction

Impact:

  • It completely breaks the core game functionality

  • No players can claim the throne, making the game unplayable

Proof of Concept

This test:

  • verifies that current King is address(0)

  • verifies that claimThrone reverts on any user with address not equal to address(0)

  • verifies that claimThrone allows only address(0) to claim the throne.

function testOnlyAddressZeoCanClaimThrone() public {
// check if currentKing is address(0)
address currentKing = game.currentKing();
assertEq(currentKing, address(0));
// check no one can claim the throne except address(0)
vm.prank(player1);
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value: INITIAL_CLAIM_FEE}();
// check if address(0) can claim the throne
vm.deal(address(0), INITIAL_CLAIM_FEE);
vm.prank(address(0));
game.claimThrone{value: INITIAL_CLAIM_FEE}();
address newCurrentKing = game.currentKing();
assertEq(newCurrentKing, address(0));
}

Recommended Mitigation

This mitigation allows any user to claim the throne and prevents the current King from reclaiming the throne.

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

Appeal created

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

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

alexscherbatyuk Submitter
9 days ago
inallhonesty Lead Judge
6 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.