Raisebox Faucet

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

Mismatched day calculations desynchronize limits

Root + Impact

Two different “day” calculations desynchronize ETH and token resets, letting savvy users claim more often than intended.

Description

  • The ETH drip logic treats a day as block.timestamp / 24 hours, resetting counters when the integer day value changes.

  • The token claim limit uses block.timestamp > lastFaucetDripDay + 1 days, resetting exactly 24 hours after the prior reset; the mismatch lets users straddle the boundary and receive multiple resets within a single calendar day.

uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
@> lastDripDay = currentDay;
@> dailyDrips = 0;
}
...
if (block.timestamp > lastFaucetDripDay + 1 days) {
@> lastFaucetDripDay = block.timestamp;
@> dailyClaimCount = 0;
}

Risk

Likelihood:

  • The condition triggers every day boundary because the integer division resets hours before the + 1 days comparison flips.

  • Power users notice that claiming right before midnight UTC and again minutes later yields two ETH resets but only one claim reset, or vice versa.

Impact:

  • Attackers can chain claims around the seam to exceed either ETH or token limits, draining more resources than budgeted.

  • Honest users experience unexplained reverts or inconsistent allowances, damaging trust in the faucet.

Proof of Concept

Making claims right around the UTC day boundary in the PoC reveals that ETH and token counters reset at different times.

// Claim just before UTC midnight (currentDay increments)
faucet.claimFaucetTokens();
// A few minutes later, claim again; dailyDrips reset but dailyClaimCount has not yet, or vice versa.
faucet.claimFaucetTokens();

Recommended Mitigation

Unifying on the integer-day counter via this patch synchronizes the resets, removing the timing gap attackers can exploit.

- /**
- *
- * @param lastFaucetDripDay tracks the last day a claim was made
- * @notice resets the @param dailyClaimCount every 24 hours
- */
- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
+ // Use consistent day tracking mechanism for both counters
+ uint256 currentDay = block.timestamp / 24 hours;
+
+ if (currentDay > lastDripDay) {
+ lastDripDay = currentDay;
dailyClaimCount = 0;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 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.