Description
When a user calls claimFaucetTokens, the dailyClaimCount will increment. Every 24 hours, the dailyClaimCount is reset. If the dailyClaimCount reaches the dailyClaimLimit, the function will revert.
However, if the dailyClaimCount does reach the dailyClaimLimit within the 24 hour reset window, the function will never be able to reset. This is because the function checks to see if the dailyClaimLimit has been reached and reverts before it can update the dailyClaimCount.
function claimFaucetTokens() public {
faucetClaimer = msg.sender;
if (block.timestamp < (lastClaimTime[faucetClaimer] + CLAIM_COOLDOWN)) {
revert RaiseBoxFaucet_ClaimCooldownOn();
}
if (faucetClaimer == address(0) || faucetClaimer == address(this) || faucetClaimer == Ownable.owner()) {
revert RaiseBoxFaucet_OwnerOrZeroOrContractAddressCannotCallClaim();
}
if (balanceOf(address(this)) <= faucetDrip) {
revert RaiseBoxFaucet_InsufficientContractBalance();
}
@> if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
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
*/
@> if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}
lastClaimTime[faucetClaimer] = block.timestamp;
dailyClaimCount++;
_transfer(address(this), faucetClaimer, faucetDrip);
emit Claimed(msg.sender, faucetDrip);
}
Risk
Likelihood:
This happens whenever the amount of claimers from the faucet within 24 hours surpasses the limit set by the owner.
Impact:
This will tempirarily lock the protocol every time the limit is reached. The owner can always use adjustDailyClaimLimit to increase the daily limit and unlock the protocol.
Proof of Concept
function testReachingClaimCountInADayLocksFaucet() public {
uint256 dailyClaimLimit = raiseBoxFaucet.dailyClaimLimit();
for(uint256 i = 0; i < dailyClaimLimit; i++) {
vm.prank(address(uint160(i + 100)));
raiseBoxFaucet.claimFaucetTokens();
}
vm.warp(block.timestamp + 3 days);
vm.prank(user);
vm.expectRevert(RaiseBoxFaucet.RaiseBoxFaucet_DailyClaimLimitReached.selector);
raiseBoxFaucet.claimFaucetTokens();
assert(raiseBoxFaucet.dailyClaimCount() == dailyClaimLimit);
}
The test shows that once the daily claim limit has been reached, the claim count will not reset after 24 hours.
Recommended Mitigation
Reset the count before checking if the limit has been reached.
function claimFaucetTokens() public {
...
+ /**
+ *
+ * @param lastFaucetDripDay tracks the last day a claim was made
+ * @notice resets the @param dailyClaimCount every 24 hours
+ */
+ if (block.timestamp > lastFaucetDripDay + 1 days) {
+ lastFaucetDripDay = block.timestamp;
+ dailyClaimCount = 0;
+ }
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
- */
- 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);
}