Last Man Standing

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

[H-3] Winner Can Never Be Declared Due to Incorrect require Grace Period Logic

Root + Impact

[H-3] Winner Can Never Be Declared Due to Incorrect require Grace Period Logic

Description

The declareWinner() function cannot be called unless block.timestamp > lastClaimTime + gracePeriod.
This logic creates a flawed dependency on lastClaimTime, which results in the grace period constantly extending if users keep calling claimThrone() close to the grace period boundary. This directly
contradicts the documentation and comments which state:

"Can call declareWinner() once the gracePeriod has expired."

However, by resetting lastClaimTime every time someone calls claimThrone(), the grace period effectively never expires unless no one calls claimThrone() for gracePeriod seconds straight.

Impact:

1.High severity: The protocol fails to finalize and declare a winner.

2.Breaks the core functionality of the contract (declaring winner).

3.Misleading documentation: only mentions gracePeriod, but lastClaimTime dependency makes logic behavior differ from expectations.

4.Funds or rewards tied to declaring the winner may become permanently locked.

5.Opens potential griefing vector where malicious users can block the game from ending indefinitely with minimal gas.

Proof of Concept

// Setup: gracePeriod = 24 hours
// Assume current time is 0
1. User A calls claimThrone() at time = 0
=> lastClaimTime = 0
2. User B calls claimThrone() at time = 10 hours
=> lastClaimTime = 10 hours
3. User C calls claimThrone() at time = 23 hours
=> lastClaimTime = 23 hours
// At every new claimThrone call, lastClaimTime gets updated.
// So block.timestamp is never greater than (lastClaimTime + 24 hours)
// Result: declareWinner() can never be called.
The require Statement of Declarewinner will check :block.timestamp>47
function declareWinner() external gameNotEnded {
require(
currentKing != address(0),
"Game: No one has claimed the throne yet."
);
@audit require(
block.timestamp > lastClaimTime + gracePeriod,
"Game: Grace period has not expired yet."
);
gameEnded = true;
pendingWinnings[currentKing] = pendingWinnings[currentKing] + pot;
pot = 0;
}

Recommended Mitigation

Update the condition for declaring a winner to compare block.timestamp with Only gracePeriod or
Updated Graceperiod By Owner:

-require(block.timestamp > lastClaimTime + gracePeriod, "Grace period not over");
+require(block.timestamp > gracePeriod, "Grace period not over");
Updates

Appeal created

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

declareWinner time check is not properly done

Support

FAQs

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

Give us feedback!