Raisebox Faucet

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

Daily Drips Counter Reset

Root + Impact

Description

  • The dailyDrips variable is intended to maintain an accurate cumulative total of all Sepolia ETH distributed by the faucet within a 24-hour period, ensuring the contract does not exceed the defined dailySepEthCap per day.​

  • A logic flaw in the else block of the claimFaucetTokens() function resets the dailyDrips counter to 0 whenever a user who has already claimed ETH or when the drip system is paused, triggering the function. This erroneous reset makes the faucet forget previously distributed amounts, allowing it to distribute far more ETH than the daily limit.

if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
// ...
} else {
@> dailyDrips = 0;
}

Risk

Likelihood:

  • Occurs anytime an ineligible user (already claimed or paused) calls claimFaucetTokens(). Something frequent in active faucet systems.​

  • Attackers or normal users can deliberately alternate between first-time claimers and previous claimers to continuously reset dailyDrips and exceed the dailySepEthCap limit.​

Impact:

  • The contract can exceed the daily ETH limit and drain the faucet early.

  • This undermines the entire cap mechanism, leading to uncontrolled fund distribution and system insolvency risks.

Proof of Concept

  1. Assuming a dailySepEthCap = 0.005 ETH.

  2. User A (first-time claimer) calls claimFaucetTokens(): Receives 0.005 ETH -> dailyDrips = 0.005 ETH.

  3. User A calls again: hasClaimedEth\[UserA] == true -> triggers else block -> resets dailyDrips = 0.

  4. User B (first-time claimer) calls: dailyDrips appears as 0 again -> passes cap check -> distributes 0.005 ETH.

Code:

vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// Check that dailyDrips now reflects 0.005 ether
uint256 dripsAfterUserAFirstClaim = raiseBoxFaucet.dailyDrips();
assertEq(dripsAfterUserAFirstClaim, 0.005 ether);
// warp to avoid cooldown for user1
vm.warp(block.timestamp + 4 days);
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
// Check that dailyDrips now reflects 0.005 ether
uint256 dripsAfterUserBClaim = raiseBoxFaucet.dailyDrips();
assertEq(dripsAfterUserBClaim, 0.005 ether);
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// UserA second call resets dailyDrips to 0
uint256 dripsAfterUserASecondClaim = raiseBoxFaucet.dailyDrips();
assertEq(dripsAfterUserASecondClaim, 0);

By alternating such calls, users can drain well beyond the intended cap without triggering limits.

Recommended Mitigation

  • Remove the else block that resets dailyDrips.

  • For non-eligible users (already claimed or paused), simply skip distribution instead of modifying dailyDrips.

+ }
- } else {
- dailyDrips = 0;
- }
  • Reset dailyDrips only when a new day begins using timestamp-based checks:

uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
}
Updates

Lead Judging Commences

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