Last Man Standing

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

Game Cannot Be Started Due to Flawed Logic in `claimThrone`

Root + Impact

The claimThrone() function is intended to allow a player to become the currentKing by sending a fee. However, the function incorrectly requires that the caller (msg.sender) must already be the currentKing. When the game starts, currentKing is initialized to address(0). Since no user can have this address, this check will always fail for the first player attempting to start the game.

Description

  • A player should be able to claim the throne by sending the required claimFee.

  • However, the access control in claimThrone() is implemented incorrectly, preventing anyone from starting the game.

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.");
// @audit should be msg.sender != currentKing
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
// ...rest of code
}

Risk

Likelihood:

  • The faulty require statement is evaluated on every initial call to claimThrone().

  • This condition will always fail for the first player, making it a certainty that the game cannot be started.

Impact:

  • The core gameplay mechanic is fundamentally broken.

  • The contract's primary function is unusable, rendering the entire game unplayable.

Proof of Concept

The following test demonstrates that a player cannot claim the throne when the game starts.

function test_claimThroneFail() public {
vm.startPrank(player1);
game.claimThrone{value: game.claimFee()}();
vm.stopPrank();
}

The test will revert because currentKing is address(0) by default, and msg.sender (player1) is not address(0). The require(msg.sender == currentKing) check fails, but with a misleading error message.

Failing tests:
Encountered 1 failing test in test/Game.t.sol:GameTest
[FAIL: Game: You are already the king. No need to re-claim.] test_claimThroneFail() (gas: 47516)

Recommended Mitigation

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.");
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
// ...rest of code
}
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.