Last Man Standing

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

`GameEnded` event emits the wrong `prizeAmount`

Precondition: Reachable once this Critical [Unreachable gameplay: wrong equality check bricks claimThrone()] (https://codehawks.cyfrin.io/c/2025-07-last-man-standing/s/cmdwlle4k0003l404vznah12s) is fixed (==!=).
PoC method: Tests use a minimal harness (GamePatched.sol) with only that one-line fix to reach the intended game state.

Root + Impact

Description

  • Expected: GameEnded should log the amount the winner just earned.

  • Actual: the contract sets pot = 0 before emitting the event, so
    prizeAmount is always logged as 0.

function declareWinner() external gameNotEnded {
...
pendingWinnings[currentKing] += pot;
pot = 0; // @> pot cleared first
emit GameEnded(currentKing, pot, block.timestamp, gameRound); // @> logs 0
}

Risk

Likelihood:

  • Always: every time a winner is declared.

Impact:

  • Off-chain Events integrations receive wrong data.

Proof of Concept

What this shows: prizeAmount is logged as 0 in declareWinner()

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Test} from "forge-std/Test.sol";
import {Vm} from "forge-std/Vm.sol";
import {Game} from "../src/GamePatched.sol";
import {console2} from "forge-std/console2.sol";
contract GameEndedLogsZeroTest is Test {
Game g;
address p1 = address(0xb00b);
function setUp() public {
g = new Game(0.1 ether, 1 days, 10, 5);
vm.deal(p1, 1 ether);
vm.prank(p1);
g.claimThrone{value: 0.1 ether}();
vm.warp(block.timestamp + 2 days);
}
function test_EventLogsZero() public {
vm.recordLogs();
g.declareWinner();
Vm.Log[] memory logs = vm.getRecordedLogs();
bytes memory data = logs[0].data;
(uint256 prizeAmount, , ) = abi.decode(
data,
(uint256, uint256, uint256)
);
console2.log("prizeAmount", prizeAmount);
assertEq(prizeAmount, 0, "should be >0 but is 0");
}
}

Recommended Mitigation

Clear the state variable pot after emitting the event GameEnded, for coherence.

- pendingWinnings[currentKing] += pot;
- pot = 0;
- emit GameEnded(currentKing, pot, block.timestamp, gameRound);
+ pendingWinnings[currentKing] += pot;
+ emit GameEnded(currentKing, pot, block.timestamp, gameRound);
+ pot = 0;
Updates

Appeal created

inallhonesty Lead Judge 17 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Game::declareWinner emits GameEnded event with pot = 0 always

Support

FAQs

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