In the claimFaucetTokens function of the RaiseBoxFaucet contract, the daily reset logic for the dailyClaimCount state variable is incomplete. Specifically, in the ETH drip section, the check for a new day (if (currentDay > lastDripDay)) resets lastDripDay and dailyDrips but has a commented-out line (// dailyClaimCount = 0;), which prevents the dailyClaimCount from resetting.
The dailyClaimCount tracks the number of token claims per day and enforces the dailyClaimLimit (e.g., 100 claims). Without resetting dailyClaimCount alongside the ETH drip counters, token claims may be blocked on new days when a first-time claimer triggers the ETH drip logic. This happens because dailyClaimCount retains its previous day's value, potentially exceeding dailyClaimLimit, causing the function to revert with RaiseBoxFaucet_DailyClaimLimitReached.
Additionally, the token claim counter reset relies on a separate check (if (block.timestamp > lastFaucetDripDay + 1 days)), which uses a different time calculation than the ETH drip's block.timestamp / 24 hours. This misalignment can further exacerbate the issue, as the two reset mechanisms may not trigger simultaneously, leading to inconsistent state updates.
This logic error violates the intended behavior of the faucet, which should allow dailyClaimLimit token claims every 24 hours, as implied by the protocol documentation. The result is a denial of service (DoS) for users attempting to claim tokens on subsequent days.
Medium
The bug introduces a denial of service (DoS) risk where legitimate users are unable to claim faucet tokens on new days if dailyClaimCount is not reset, even though ETH drips for first-time claimers are allowed (due to the reset of dailyDrips). In a testnet faucet context, this degrades usability and frustrates users. In a production environment, such a logic error could lead to temporary or permanent lockouts of critical functionality.
Users (claimers) are prevented from claiming faucet tokens on new days, even if the 3-day cooldown period (CLAIM_COOLDOWN) has passed and the contract has sufficient token balance.
The dailyClaimLimit effectively becomes a permanent limit across days, rendering the faucet unusable for token claims after the first day's limit is reached.
Reduced adoption of the testnet protocol, as faucet tokens are essential for testing interactions.
No direct fund loss occurs, but the protocol's usability is significantly impacted, affecting the user experience and ecosystem.
Manual code review using VS Code with Solidity extensions.
Foundry for Proof of Concept testing (simulating time warps and claim scenarios).
To fix the issue, uncomment the dailyClaimCount = 0; line in the ETH drip reset block to ensure synchronized resetting of all daily counters:
For a more robust solution, consolidate the daily reset logic for both ETH and token claims into a single internal function to avoid duplication and ensure consistency. For example:
Call _resetDailyCounters at the start of claimFaucetTokens and remove the separate lastFaucetDripDay check to prevent misalignment. This ensures that both dailyDrips and dailyClaimCount reset consistently on new days.
The following Foundry test demonstrates the bug by simulating a scenario where the daily claim limit is reached on Day 1, and on Day 2, a new user is unable to claim tokens due to the unre reset dailyClaimCount. The test sets dailyClaimLimit to 1 for simplicity, ensuring the limit is reached after one claim.
Test Explanation:
The test sets dailyClaimLimit to 1 and funds the contract with ETH.
vm.warp(3 days + 1) bypasses the initial 3-day cooldown for the first claim.
On Day 1, user1 claims tokens and ETH, setting dailyClaimCount to 1 (limit reached).
On Day 2, user2 (a first-time claimer) attempts to claim. The ETH drip reset logic (currentDay > lastDripDay) is triggered, resetting dailyDrips, but dailyClaimCount remains 1 due to the commented-out line.
The claim reverts with RaiseBoxFaucet_DailyClaimLimitReached, proving the DoS bug.
Assertions confirm that dailyClaimCount is not reset and lastDripDay remains unchanged (since the revert prevents further execution).
Run the test with: forge test --mt test_DailyClaimCountNotResetOnNewDay -vvv.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.