Raisebox Faucet

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

Incorrect daily reset logic allows bypassing global ETH cap

[H-3] Incorrect daily reset logic allows bypassing global ETH cap

Description

The claimFaucetTokens() function resets dailyDrips to 0 inside the else branch that runs when a user has already claimed ETH before or when Sepolia drips are paused.
This means any returning user can trigger a full reset of the daily distribution counter, effectively turning what should be a global daily ETH cap into a per-user cap.

As a result, multiple users (or one attacker using multiple addresses) can each reset the counter and drain more ETH per day than intended.

function claimFaucetTokens() public {
...
// @audit Logical vulnerability here.
// This else runs whenever the user has already claimed ETH before, or ETH drips are paused.
// That means any returning user (who’s claimed before) resets dailyDrips back to 0.
// The dailyDrips variable is supposed to track how much Sepolia ETH has been distributed in a given day, enforcing the daily cap.
// But since dailyDrips gets reset to zero on any returning user’s claim, the cap can be bypassed.
} else {
dailyDrips = 0;
}
...
}

Risk

Likelihood:

  • The vulnerable else branch executes for every returning claimer or when drips are paused.

  • No date check (currentDay != lastDripDay) is performed before resetting.

Impact:

  • Bypasses the intended global daily ETH cap (dailySepEthCap).

  • Multiple users can drain more ETH than the system’s intended daily limit.

  • Faucet accounting and emission limits become meaningless.

Proof of Concept

  • When the faucet contract is vulnerable (resets per user or pause), the test will fail — because dailyDrips was reset to 0 improperly.

function test_dailyCapBypass() public {
vm.deal(address(raiseBoxFaucet), 1 ether);
// User 1 triggers a drip — dailyDrips increases
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// User 2 triggers a claim (already claimed before / paused)
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
// dailyDrips resets to 0 → cap bypassed
assertEq(raiseBoxFaucet.dailyDrips(), 0, "dailyDrips reset incorrectly");
}
forge test --match-test test_dailyCapBypass -vvv
  • This output means:

  1. Actual: dailyDrips = 1e16 (not reset)

  2. Expected: dailyDrips = 0

  3. So the faucet incorrectly reset (or didn’t behave as intended).

Recommended Mitigation

  • Ensure dailyDrips is reset only once per new day, not when a returning user claims or when drips are paused.

  • Use a day-based comparison (block.timestamp / 1 days) to detect when a new day begins.

- else {
- dailyDrips = 0;
- }
- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
- dailyDrips = 0;
- }
+ uint256 currentDay = block.timestamp / 1 days;
+ if (currentDay != lastDripDay) {
+ lastDripDay = currentDay;
+ dailyDrips = 0;
+ }
  • This ensures the daily ETH cap is enforced globally, preventing each user from resetting the counter and bypassing the limit.

Updates

Lead Judging Commences

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

dailyDrips Reset Bug

Support

FAQs

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

Give us feedback!