Raisebox Faucet

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

Faucet Locked by dailyClaimLimit Restriction

Root + Impact

Description

  • The claimFaucetTokens() function enforces a daily claim limit through dailyClaimCount and resets this counter when a new day starts.

  • However, the limit check occurs before the reset condition.

  • Once dailyClaimCount reaches dailyClaimLimit, all subsequent claims revert permanently—even after a full day has passed—because the reset logic is executed too late in the function.

  • This causes a logical deadlock, where the faucet becomes indefinitely locked until owner manually adjusts the daily claim limit.

function claimFaucetTokens() public {
...
@> // limit is checked first, and claimer will be blocked at this location once limit is reached
if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
// drip sepolia eth to first time claimers if supply hasn't ran out or sepolia drip not paused**
// still checks
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
...
} else {
dailyDrips = 0;
}
/**
*
* @param lastFaucetDripDay tracks the last day a claim was made
* @notice resets the @param dailyClaimCount every 24 hours
*/
@> // too late to reset
if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}
// Effects
lastClaimTime[faucetClaimer] = block.timestamp;
dailyClaimCount++;
// Interactions
_transfer(address(this), faucetClaimer, faucetDrip);
emit Claimed(msg.sender, faucetDrip);
}

Risk

Likelihood: High

  • The bug occurs deterministically once the limit is reached

  • Any user can trigger the lock by exhausting the daily claim quota

Impact: High

  • faucet lockout: no user can claim again even after 24 hours

  • Operational disruption: owner intervention (redeploy/reset) is required to restore service

Proof of Concept

Add the following test, then run this command: forge test --match-test testLockedByDailyClaimCount

function testLockedByDailyClaimCount() public {
vm.prank(owner);
raiseBoxFaucet.adjustDailyClaimLimit(99, false); // set daily claim limit to 1
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
advanceBlockTime(block.timestamp + 3 days);
vm.prank(user2);
vm.expectRevert(RaiseBoxFaucet.RaiseBoxFaucet_DailyClaimLimitReached.selector);
raiseBoxFaucet.claimFaucetTokens();
}

Recommended Mitigation

Move the reset logic before the claim limit check to ensure the counter refreshes correctly at each new day

function claimFaucetTokens() public {
...
- if (dailyClaimCount >= dailyClaimLimit) {
- revert RaiseBoxFaucet_DailyClaimLimitReached();
- }
- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
- dailyClaimCount = 0;
- }
+ // Reset before checking limit
+ if (block.timestamp > lastFaucetDripDay + 1 days) {
+ lastFaucetDripDay = block.timestamp;
+ dailyClaimCount = 0;
+ }
+ // Check limit after reset
+ if (dailyClaimCount >= dailyClaimLimit) {
+ revert RaiseBoxFaucet_DailyClaimLimitReached();
+ }
...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 days ago
Submission Judgement Published
Validated
Assigned finding tags:

dailyClaimCount Reset Bug

Support

FAQs

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