Last Man Standing

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

`Game::claimThrone` has a require that blocks all players from participating

Game::claimThrone has a require that blocks all players from participating

Description

The claimThrone() function should allow any player to claim the throne if they pay the claimFee and are not the current king. This is essential to start and continue the game.

Currently, there is a misformulated require that prevents any player from participating, even in the first round. The initial currentKing is address(0), so no player can pass the require, leaving the game completely 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.");
uint256 sentAmount = msg.value;
uint256 previousKingPayout = 0;
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
// Calculate 5% of msg.value
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
// add the 10% to the fee balance
platformFeesBalance = platformFeesBalance + currentPlatformFee;
// amountToPot is msg.value - 5%
amountToPot = sentAmount - currentPlatformFee;
pot = pot + amountToPot;
// Update game state
currentKing = msg.sender;
lastClaimTime = block.timestamp;
playerClaimCount[msg.sender] = playerClaimCount[msg.sender] + 1;
totalClaims = totalClaims + 1;
// Increase the claim fee for the next player
claimFee = claimFee + (claimFee * feeIncreasePercentage) / 100;
emit ThroneClaimed(
msg.sender,
sentAmount,
claimFee,
pot,
block.timestamp
);
}

Risk

Likelihood: High

  • This situation always occurs; any player trying to claim the throne will be rejected by the condition msg.sender == currentKing, which is only true if msg.sender is address(0).

Impact: High

  • No player can start the game.

  • The contract becomes unusable, completely blocking the main functionality.

Proof of Concept

Reverts whenever anyone tries to claim the throne due to the misformulated require that blocks all participation.

function test_AnyPlayerCanClaimThrone() public {
vm.startPrank(player1);
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value: INITIAL_CLAIM_FEE}();
}
Ran 1 test for test/Game.t.sol:GameTest
[PASS] test_AnyPlayerCanClaimThrone() (gas: 46937)

Recommended Mitigation

Fix the condition so that only the current king cannot claim, but any other player can start or participate in 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.");
+ 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;
....
Updates

Appeal created

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