Raisebox Faucet

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

dailyDrips reset mid-day allows Sepolia ETH cap bypass

Root + Impact

Description

dailyDrips is reset to 0 in the else branch of the ETH-drip logic (executed when caller already claimed ETH before or drips are paused), independent of day rollover. This wipes daily accounting mid-day, allowing additional first-time claimers to receive ETH beyond the cap.

Attack Path:

  1. A first-time user claims, consuming part of the daily cap (dailyDrips += sepEthAmountToDrip).

  2. A returning user (or any claim while drips are paused) calls claimFaucetTokens, resetting dailyDrips = 0 mid-day.

  3. Additional first-time users claim and receive ETH again, allowing the total for that day to exceed dailySepEthCap.

// ...existing code...
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
}
if (
dailyDrips + sepEthAmountToDrip <= dailySepEthCap &&
address(this).balance >= sepEthAmountToDrip
) {
hasClaimedEth[faucetClaimer] = true;
dailyDrips += sepEthAmountToDrip;
(bool success, ) = faucetClaimer.call{ value: sepEthAmountToDrip }("");
if (success) {
emit SepEthDripped(faucetClaimer, sepEthAmountToDrip);
} else { revert RaiseBoxFaucet_EthTransferFailed(); }
} else {
emit SepEthDripSkipped(...);
}
} else {
@> dailyDrips = 0;
}
// ...existing code..

Risk

Likelihood:

  • This issue will occur whenever a returning user who has previously claimed ETH calls claimFaucetTokens on the same day that other new users are claiming. The else branch is executed for such users, resetting dailyDrips to 0 mid-day and reopening the faucet cap unintentionally.

  • This will also occur whenever sepEthDripsPaused is toggled on and a claim attempt is made during the same day, since the else branch executes again and zeroes out dailyDrips. Once the pause is lifted, new claimers can exceed the intended daily ETH distribution cap.

Impact:

  • Daily ETH distribution invariant can be broken: total ETH dripped in a single day can exceed dailySepEthCap.

  • Faucet ETH can be drained faster than intended.

  • Daily telemetry/accounting becomes unreliable.

Proof of Concept

  • Parameters: sepEthAmountToDrip = 0.01 ETH, dailySepEthCap = 0.02 ETH.

  • userA claims (first-time) --> dailyDrips = 0.01.

  • returningUser claims (already claimed on a previous day) --> BUG: dailyDrips reset to 0.

  • userB and userC claim (first-time), pushing total dripped today to 0.03 ETH > 0.02 ETH cap.

function test_DailyDrips_ResetMidDay_AllowsCapBypass() public {
// Arrange: small cap (2 drips/day) and 0.01 ether per first-time drip
RaiseBoxFaucet faucet = new RaiseBoxFaucet(
"RaiseBoxToken",
"RBT",
1000 * 10 ** 18, // faucetDrip (tokens per claim)
0.01 ether, // sepEthAmountToDrip
0.02 ether // dailySepEthCap
);
vm.deal(address(faucet), 1 ether);
address returningUser = makeAddr("returningUser");
address userA = makeAddr("userA");
address userB = makeAddr("userB");
address userC = makeAddr("userC");
// Day 0: returningUser becomes non–first-time going forward
vm.prank(returningUser);
faucet.claimFaucetTokens();
// Move forward to a fresh day and beyond cooldown (3+ days)
vm.warp(block.timestamp + 4 days);
// Day N: First-time userA claims -> dailyDrips = 0.01
vm.prank(userA);
faucet.claimFaucetTokens();
assertEq(userA.balance, 0.01 ether, "userA should receive ETH drip");
// Same day: returningUser claims -> BUG resets dailyDrips to 0 mid-day
vm.prank(returningUser);
faucet.claimFaucetTokens();
// Same day: two more first-time users now exceed the 0.02 cap
vm.prank(userB);
faucet.claimFaucetTokens();
vm.prank(userC);
faucet.claimFaucetTokens();
uint256 totalDrippedToday = userA.balance + userB.balance + userC.balance;
assertGt(totalDrippedToday, 0.02 ether, "daily cap must not be exceedable in one day");
}
  • Expected: Total ETH dripped per day must never exceed dailySepEthCap (userC should not receive ETH in the scenario above).

  • Actual: Total dripped today equals 0.03 ETH, exceeding the 0.02 ETH cap due to dailyDrips being reset mid-day.

Recommended Mitigation

  • Remove the mid-day reset by removing the else statement block, as shown below:

- } else {
- dailyDrips = 0;
- }
+ }
Updates

Lead Judging Commences

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