Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Inconsistent day-tracking and reset logic leads to incorrect dailyClaimCount behavior

Root + Impact

Description

In the claimFaucetTokens() function, the daily claim counter reset logic relies on an absolute timestamp comparison instead of a normalized day index.
This condition fails to reset dailyClaimCount when a new claim occurs exactly 24 hours (86400 seconds) after the previous claim — because the comparison is strictly > instead of >=.

As a result, the daily claim limit may persist into the next day for one extra claim cycle, violating the intended 24-hour reset rule.

// @> absolute timestamp comparison instead of a normalized day index
if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}

Risk: Medium

Likelihood: Medium

Factor Observation Likelihood Influence
Frequency Happens whenever claims are made near 24-hour boundaries High
Severity Moderate (logical inconsistency, not loss of funds) Medium
Complexity Simple deterministic bug High
Detection Hard to notice without time-based fuzzing Medium

Impact: Medium

Impact Area Description
Functionality Daily reset logic may fail, causing users to be blocked from claiming for up to 24h past the intended limit.
Fairness Users who claim slightly later might be unfairly restricted due to boundary conditions.
Usability Faucet becomes unreliable around daily reset times.
Consistency The daily claim limit enforcement becomes unpredictable.

Proof of Concept

  1. Claim once at time t0.

  2. Advance block.timestamp to t0 + 1 days (exactly +86400 seconds) and call claimFaucetTokens() again.

  3. Observe whether dailyClaimCount was reset or not.

If the contract uses if (block.timestamp > lastFaucetDripDay + 1 days) with lastFaucetDripDay = t0, then at t0 + 1 days the condition is false (not >), so reset will not occur, and dailyClaimCount may not be reset as intended.

function testDailyClaimNotResetAtBoundary() public {
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// Move forward exactly 24h
vm.warp(block.timestamp + 1 days);
// Claim at the boundary
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
// dailyClaimCount should have reset to 1, but remains incremented
assertEq(
raiseBoxFaucet.dailyClaimCount(),
1,
"Count did not reset at +1 days boundary"
);
}

Recommended Mitigation

Instead of comparing absolute timestamps, normalize to day indices by using integer division for deterministic day calculation

- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
- dailyClaimCount = 0;
- }
+ uint256 currentDay = block.timestamp / 1 days;
+ if (currentDay > lastFaucetDripDay) {
+ lastFaucetDripDay = currentDay;
+ dailyClaimCount = 0;
+ }
Updates

Lead Judging Commences

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

Inconsistent day calculation methods cause desynchronization between ETH and token daily resets.

Support

FAQs

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