Blocked Sepolia ETH Claims Due to Low Token Balance Check
Description
claimFaucetTokens reverts on low token balance (<= faucetDrip) before ETH drip logic, preventing first-timers from receiving ETH despite availability, and blocking returns for potential retry.
if (balanceOf(address(this)) <= faucetDrip) {
revert RaiseBoxFaucet_InsufficientContractBalance();
}
Risk
Likelihood:
Impact:
-
First-timers denied ETH, must cooldown retry (risking depletion).
-
Prioritizes tokens over ETH, unfair to early callers.
Proof of Concept
function testEthClaimBlockedByLowTokenBalance() public {
uint256 drip = raiseBoxFaucet.faucetDrip();
uint256 initialTokens = raiseBoxFaucet.getFaucetTotalSupply();
uint256 initialEth = raiseBoxFaucet.getContractSepEthBalance();
vm.startPrank(owner);
raiseBoxFaucet.burnFaucetTokens(initialTokens);
raiseBoxFaucet.mintFaucetTokens(address(raiseBoxFaucet), drip);
vm.stopPrank();
assertEq(raiseBoxFaucet.balanceOf(address(raiseBoxFaucet)), drip);
assertEq(raiseBoxFaucet.getContractSepEthBalance(), initialEth);
vm.prank(user1);
vm.expectRevert(RaiseBoxFaucet.RaiseBoxFaucet_InsufficientContractBalance.selector);
raiseBoxFaucet.claimFaucetTokens();
assertEq(user1.balance, 0);
assertFalse(raiseBoxFaucet.getHasClaimedEth(user1));
}
POC Explanation: Burns tokens to exact faucetDrip. User1 (first-timer) claim reverts on token check, despite ETH available, denying ETH and starting no cooldown, proving blocked access.
Recommended Mitigation
if (balanceOf(address(this)) < faucetDrip) { // Change <= to <
revert RaiseBoxFaucet_InsufficientContractBalance();
}
// For first-timers, separate token check if needed, but allow ETH if tokens low but ETH ok
// Or move token transfer after ETH, with separate low-token handling
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused && balanceOf(address(this)) >= faucetDrip) {
// ETH drip logic (allow even if tokens marginal, but revert tokens later if needed)
}
Mitigation Key Points: Use < for token check. Decouple ETH from token balance; allow ETH drip pre-transfer. Ensures first-timers get ETH if available, tokens only if sufficient.