Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Incorrect Daily Claim Reset Logic

Description:

The daily claim counter reset mechanism is fundamentally flawed in its execution order. The reset occurs in the middle of the claim processing, after initial checks but before state updates and token transfers. This creates a window where the daily limit can be bypassed, especially when multiple claims occur near the daily boundary.

Impact:

  • Daily Limit Bypass: Users can exceed daily claim limits by timing transactions around reset boundaries

  • Economic Exploitation: More tokens than intended can be distributed daily

  • Unfair Distribution: Early claimers near reset boundaries get preferential access

  • Contract Drainage: Accelerated token distribution beyond designed limits

Proof of Concept:

function claimFaucetTokens() public {
// Initial check: dailyClaimCount >= dailyClaimLimit would revert
if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
// ... other checks ...
// RESET IN MID-PROCESS: This is the vulnerability
if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0; // Reset happens here
}
// Claim continues processing with reset counter
dailyClaimCount++; // Now this is 1, regardless of previous claims
_transfer(address(this), faucetClaimer, faucetDrip);
}
// Attack scenario:
// Time: 23:59 - dailyClaimCount = 99 (limit is 100)
// User submits transaction that gets executed at 00:01 next day
// Transaction flow:
// - Check: dailyClaimCount (99) < dailyClaimLimit (100) ✅
// - Reset: dailyClaimCount = 0 (because new day) 🔄
// - Process: dailyClaimCount becomes 1 ✅
// Result: Claim processes when it should have been blocked

Recommended Mitigation:

function claimFaucetTokens() public {
address claimer = msg.sender;
// RESET FIRST: Check and reset at the very beginning
uint256 currentDay = block.timestamp / 1 days;
if (currentDay != lastFaucetDripDay) {
lastFaucetDripDay = currentDay;
dailyClaimCount = 0;
}
// CHECKS: All validations after reset
require(dailyClaimCount < dailyClaimLimit, "Daily claim limit reached");
require(block.timestamp >= lastClaimTime[claimer] + CLAIM_COOLDOWN, "Cooldown active");
require(claimer != address(0) && claimer != address(this) && claimer != owner(), "Invalid claimer");
require(balanceOf(address(this)) >= faucetDrip, "Insufficient token balance");
// EFFECTS: Update state
lastClaimTime[claimer] = block.timestamp;
dailyClaimCount++;
// ... rest of function ...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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