Last Man Standing

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

Missing Previous King Payout in claimThrone() Function

Root + Impact

Description

  • The expected behavior is that the game rewards the previous king with a payout when a new player claims the throne, before updating the current king. This ensures fairness and proper fund distribution.


  • The actual implementation introduces a variable previousKingPayout but sets it to 0 every time without updating it or transferring any funds to the previous king. This makes the payout logic non-functional and misleading in the code. Additionally, the conditional check using previousKingPayout is dead code, creating a false sense of security.

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; // Always zero, no real payout logic implemented
uint256 currentPlatformFee = 0;
uint256 amountToPot = 0;
// Calculate platform fee
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
);
}

Risk

Likelihood:

  • Every time a player calls claimThrone(), the logic for paying the previous king is skipped because previousKingPayout is always zero.

  • The payout code path is dead, so the bug consistently occurs for all transactions.

Impact:

  • Previous king never receives a payout, breaking core game mechanics and fairness.

  • Users may lose trust in the platform, potentially causing financial and reputational damage.

Proof of Concept

  • The claimThrone() function initializes previousKingPayout to 0 every time and never updates it with a real payout amount.

  • There is no logic to transfer any funds to the previous king, even though the defensive check suggests such a mechanism exists.

// Scenario:
// 1. Player A becomes king by sending 1 ETH.
// 2. Player B claims the throne by sending 2 ETH.
// Expected: Player A should receive some payout (e.g., 50% of Player B's amount).
// Actual: Player A receives nothing.
function testClaimThrone_NoPayoutToPreviousKing() public {
// Player A claims the throne
vm.deal(playerA, 1 ether);
vm.prank(playerA);
game.claimThrone{value: 1 ether}();
// Player B claims the throne
vm.deal(playerB, 2 ether);
vm.prank(playerB);
game.claimThrone{value: 2 ether}();
// Assert Player A balance remains unchanged (no payout received)
assertEq(playerA.balance, 0 ether);
}

Recommended Mitigation

- uint256 previousKingPayout = 0; // Remove hardcoded zero
- if (currentPlatformFee > (sentAmount - previousKingPayout)) {
- currentPlatformFee = sentAmount - previousKingPayout;
- }
+ // Calculate payout for previous king before updating the state
+ uint256 previousKingPayout = (sentAmount * previousKingSharePercentage) / 100;
+ address payable oldKing = payable(currentKing);
+ if (previousKingPayout > 0 && oldKing != address(0)) {
+ (bool success, ) = oldKing.call{value: previousKingPayout}("");
+ require(success, "Game: Previous king payout failed");
+ }
+ // Ensure platform fee does not exceed remaining amount after previousKingPayout
+ currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
+ if (currentPlatformFee > (sentAmount - previousKingPayout)) {
+ currentPlatformFee = sentAmount - previousKingPayout;
+ }
Updates

Appeal created

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

Missing Previous King Payout Functionality

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.