Raisebox Faucet

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

dailyDrips resets on repeat claims, making dailySepEthCap ineffective

Root + Impact

Description

  • The function should provide Sepolia ETH to first-time callers, up to a daily total cap. Once reached, it stops sending ETH and distributes only tokens. The cap resets daily to resume ETH distribution.

  • If an account has not yet received ETH, it receives it as expected. However, when an account that has already received ETH requests additional tokens, it unintentionally resets the daily ETH cap, effectively bypassing the limit and allowing more ETH to be distributed than intended.

function claimFaucetTokens() public nonReentrant {
...
}
if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
}
if (dailyDrips + sepEthAmountToDrip <= dailySepEthCap && address(this).balance >= sepEthAmountToDrip) {
hasClaimedEth[faucetClaimer] = true;
dailyDrips += sepEthAmountToDrip;
(bool success,) = faucetClaimer.call{value: sepEthAmountToDrip}("");
if (success) {
emit SepEthDripped(faucetClaimer, sepEthAmountToDrip);
} else {
revert RaiseBoxFaucet_EthTransferFailed();
}
} else {
emit SepEthDripSkipped(
faucetClaimer,
address(this).balance < sepEthAmountToDrip ? "Faucet out of ETH" : "Daily ETH cap reached"
);
}
} else {
@> dailyDrips = 0;
}
...
}

Risk

Likelihood:

  • This issue occurs whenever an account that has already received ETH calls the claimFaucetTokens() function to claim additional tokens.

Impact:

  • Under the current contract parameters, the impact is low: each account receives 0.005 ETH, the dailySepEthCap is 1 ETH, and the maximum number of claims is 100. Even if all 100 claims are made, the total distributed would only amount to 0.5 ETH

  • The risk could increase if the owner raises the maximum daily claims via the adjustDailyClaimLimit() function. Setting the limit above 200 (0.005 * 201 > 1) would make this vulnerability more severe.

Proof of Concept

This test verifies the incorrect reset of dailyDrips when an account that has already received ETH calls the function, triggering the else block at line 216 of the contract, causing the bug.

  • Called the faucet to set hasClaimedEth to true for user1.

  • Advanced 4 days to allow user1 to call the function again.

  • Called the function with user2; with dailyDrips equal to ethSentToEachAccount * 1, verified that after 3 days dailyDrips is correctly reset.

  • Called claimFaucetTokens with user1 and expected dailyDrips to remain unchanged (correct behavior).

  • Test shows dailyDrips is reset to 0 instead, triggering the bug.

function testDailyDripsIsResetInAWrongWay() public {
uint256 ethSentToEachAccount = raiseBoxFaucet.sepEthAmountToDrip(); //0.005 ether
assertEq(raiseBoxFaucet.dailyDrips(), 0);
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
//today only 1 account call faucet and receive ether
assertEq(raiseBoxFaucet.dailyDrips(), ethSentToEachAccount * 1);
vm.roll(block.timestamp + 4 days);
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
//after 1 day dailyDrips reset the amount added from user1
assertEq(raiseBoxFaucet.dailyDrips(), ethSentToEachAccount * 1);
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
assertEq(raiseBoxFaucet.dailyDrips(), ethSentToEachAccount * 1,
"dailyDrips has been set to zero even even when it should not be");
vm.prank(user3);
raiseBoxFaucet.claimFaucetTokens();
assertEq(raiseBoxFaucet.dailyDrips(), ethSentToEachAccount * 2);
}

The tests show that the contract should keep the dailyDrips value unchanged, but it is instead reset by a call from an account that has already received ETH.

RaiseBoxFaucet Test Failure Report

Test Summary

Test File: test/RaiseBoxFaucet.t.sol

Test Suite: TestRaiseBoxFaucet

Total Tests Run: 1

Tests Passed: 0

Tests Failed: 1

Tests Skipped: 0

Execution Time: 4.96ms (CPU time: 291.74µs)

Failing Tests

Test Name: testDailyDripsIsResetInAWrongWay

Failure Message:

dailyDrips has been set to zero even if should not: 0 != 5000000000000000

Gas Used: 433362


Recommended Mitigation

To mitigate this issue, it is sufficient to remove the line inside the else block that resets dailyDrips when hasClaimedEth is true.

function claimFaucetTokens() public nonReentrant {
...
if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
...
} else {
- dailyDrips = 0;
}
...
}
Updates

Lead Judging Commences

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