Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

Game stalls indefinitely if `declareWinner()` is never called

Liveness risk leads to locked funds

Description

The game relies entirely on an external caller to invoke declareWinner after the grace period expires.

  • If no one ever calls this function, the game remains in a "pending" state indefinitely, the prize pot is locked, the current King never receives winnings, and the contract cannot progress to the next round.

  • This introduces a liveness issue, where funds are inaccessible and the game becomes unusable.

@> function declareWinner() external gameNotEnded {
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:

  • This will happen in inactive rounds or when players are unaware of the need to finalize the game.

Impact:

  • The prize pot remains trapped in the contract.

  • The owner is blocked from resetting the game, halting future rounds.

Proof of Concept

  • A player claims the throne and no other player joins.

  • Time passes and grace period expires.

  • No one calls declareWinner.

  • The pot remains locked, gameEnded = false, and resetGame() cannot be called.

Recommended Mitigation

Use an automated mechanism like Chainlink Automation to ensure the game concludes reliably

Updates

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!