Last Man Standing

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

currentKing will always be address(0) due to require statment

Root + Impact

The require(msg.sender == currentKing) in Game::claimThrone function will always revert because variable currentKing is setted as address(0) ,causing there is no one can call claimThrone but the currentKing starts as address(0) should until first claim.And the Game::declareWinner function will always revert due to require(currentKing != address(0), "Game: No one has claimed the throne yet.");So the two function can not be called because currentKing always is address(0)

Description

When the game start, the currentKing is setted as address(0)
,but the currentKing = msg.sender; is the only way to change the currentKing,no one can call claimThrone succssfully.

function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
//When the game start, the currentKing is setted as address(0)
//but the currentKing = msg.sender; is the only way to change the currentKing,no one can call claimThrone succssfully.
@> 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 platform fee
// @audit-info division
// @audit-info platformFee is 3
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
// Defensive check to ensure platformFee doesn't exceed available amount after previousKingPayout
if (currentPlatformFee > (sentAmount - previousKingPayout)) {
currentPlatformFee = sentAmount - previousKingPayout;
}
platformFeesBalance = platformFeesBalance + currentPlatformFee;
// Remaining amount goes to the pot
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
);
}
function declareWinner() external gameNotEnded {
// always revert becasue currentKing = address(0)
@> require(currentKing != address(0), "Game: No one has claimed the throne yet.");
require(
block.timestamp > lastClaimTime + gracePeriod,
"Game: Grace period has not expired yet."
);
gameEnded = true;
pendingWinnings[currentKing] = pendingWinnings[currentKing] + pot;
pot = 0; // Reset pot after assigning to winner's pending winnings
emit GameEnded(currentKing, pot, block.timestamp, gameRound);
}

Risk

Likelihood:

  • Always

Impact:

  • no one can call claimThrone and declareWinner function


claimThroneProof of Concept

paste the test in Game.t.sol

function testnoonecancall () public {
vm.prank(player1);
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value:0.1 ether}();
vm.prank(player1);
vm.expectRevert("Game: No one has claimed the throne yet.");
game.declareWinner();
}

Recommended Mitigation

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.