Last Man Standing

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

Previous King Never Receives Payout When Throne Changes

Previous King Never Receives Payout When Throne Changes

Description

  • Expected behaviour: When a new player claims the throne, a portion of their claimFee should be transferred to the previous king as a reward for holding the throne (per README lines 37-40).

  • Actual issue: previousKingPayout is hard-coded to 0 and never updated or transferred. Consequently the previous king’s balance remains unchanged when they are dethroned.

// Game.sol — claimThrone()
uint256 previousKingPayout = 0; // ← always zero
...
currentPlatformFee = (sentAmount * platformFeePercentage) / 100;
...
// No line updates previousKingPayout or pays it out

Risk

Likelihood:

  • Happens on every throne claim beyond the first round once the critical logic-reversal bug is fixed.

  • Players actively monitor rewards; once discovered they will perceive the game as unfair.

Impact:

  • Economic incentives break down; previous kings earn nothing, discouraging participation.

  • Reputation loss / potential fraud accusations because README promises a payout that is never delivered.

Proof of Concept

The Foundry test below simulates two players. After player 2 claims, player 1’s balance is exactly the same as before the claim, proving no payout occurred.

// Run with: forge test --match-contract PoCMissingPrevKingPayout -vvv
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {Game} from "../src/Game.sol";
/// @title PoC for Missing Previous King Payout
contract PoCMissingPrevKingPayout is Test {
Game internal game;
address internal player1 = address(0x1111);
address internal player2 = address(0x2222);
uint256 internal constant INITIAL_CLAIM_FEE = 0.1 ether;
uint256 internal constant GRACE_PERIOD = 1 days;
uint256 internal constant FEE_INCREASE_PERCENTAGE = 10;
uint256 internal constant PLATFORM_FEE_PERCENTAGE = 5;
function setUp() public {
vm.deal(player1, 10 ether);
vm.deal(player2, 10 ether);
game = new Game(
INITIAL_CLAIM_FEE,
GRACE_PERIOD,
FEE_INCREASE_PERCENTAGE,
PLATFORM_FEE_PERCENTAGE
);
// player1 becomes the initial king
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}();
}
function test_PreviousKingGetsZero() public {
// Snapshot player1 balance before second claim
uint256 balanceBefore = player1.balance;
// player2 claims with the updated claim fee
uint256 nextClaimFee = game.claimFee();
vm.prank(player2);
game.claimThrone{value: nextClaimFee}();
// player1 balance should be unchanged (no payout)
uint256 balanceAfter = player1.balance;
assertEq(balanceAfter, balanceBefore, "Previous king did not receive expected payout");
}
}

Recommended Mitigation

Either:

  1. Implement payout logic – decide on a percentage (e.g. 50 %) and credit the previous king before updating currentKing.

- uint256 previousKingPayout = 0;
+ uint256 previousKingPayout = (sentAmount * prevKingRewardPct) / 100;
+ pendingWinnings[currentKing] += previousKingPayout; // pull-based pattern
  1. Update documentation – if no payout is intended, remove the claim from the README and delete the dead previousKingPayout variable to avoid confusion.

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.