Last Man Standing

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

Missing Previous King Payout Logic in claimThrone()

Root + Impact

Although the contract's documentation suggests that a portion of the new claim fee should be paid to the dethroned king, the logic to perform this payout is completely absent. Additionally, variables like previousKingPayout are defined but unused, reinforcing the appearance of incomplete implementation.

Description

The claimThrone() function documentation states that a portion of the new claim fee should be paid to the previous king. However, this logic is entirely missing from the implementation.

The variable previousKingPayout is initialized to zero and never updated. As a result, no funds are transferred to the previous king, despite the comment suggesting otherwise.

This breaks the economic incentive model and may mislead users expecting a partial rebate when dethroned.

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;

Risk

Likelihood:

  • The issue occurs during normal contract usage. Any player claiming the throne will trigger it, making exploitation trivial and highly likely.

Impact:

  • Misleading documentation / broken incentive mechanism.

  • Players may expect to receive compensation after being dethroned but will not.

Proof of Concept

function testNoPreviousKingPayout() public {
uint256 player1BalanceBeforeClaim = address(player1).balance;
vm.startPrank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
vm.stopPrank();
uint256 player1BalanceAfterClaim = address(player1).balance;
console2.log("player1 balance before claim:", player1BalanceBeforeClaim);
console2.log("player1 balance after claim:", player1BalanceAfterClaim);
vm.startPrank(player2);
game.claimThrone{value: 1 ether}();
vm.stopPrank();
uint256 player1BalanceAfterSecondClaim = address(player1).balance;
console2.log("player1 balance after second claim:", player1BalanceAfterSecondClaim);
// player1 balance before claim: 10000000000000000000 10
// player1 balance after claim: 9900000000000000000 9.9
// player1 balance after second claim: 9900000000000000000 9.9
}

Recommended Mitigation

Implement the payout logic to the previous king as described, e.g.:

Or alternatively, update the documentation and remove unused variables (e.g. previousKingPayout) if this behavior is not intended.

if (currentKing != address(0)) {
uint256 payout = (sentAmount * previousKingPercentage) / 100;
(bool success, ) = payable(currentKing).call{value: payout}("");
require(success, "Game: Failed to pay previous king");
previousKingPayout = payout;
}
Updates

Appeal created

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