Raisebox Faucet

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

Off-by-one balance check prevents valid claims at exact faucetDrip balance leads to unnecessary reverts (edge-case DoS)

Off-by-one balance check prevents valid claims at exact faucetDrip balance leads to unnecessary reverts (edge-case DoS)

Description

  • When the faucet contract holds exactly faucetDrip tokens, one claimant should be able to claim those tokens successfully.

  • The balance guard uses <= instead of <. When balanceOf(address(this)) == faucetDrip, the function reverts, blocking a legitimate final claim.

function claimFaucetTokens() public {
// Checks
faucetClaimer = msg.sender;
.
.
.
@> if (balanceOf(address(this)) <= faucetDrip) {
revert RaiseBoxFaucet_InsufficientContractBalance();
}

Risk

Likelihood:

  • Occurs whenever the faucet balance is driven to exactly faucetDrip (e.g., after burns/refills or steady usage).

  • Common during tests or operational refills where exact amounts are minted or left over.

Impact:

  • Edge-case DoS: prevents the final valid claim, leaving tokens stranded until balance changes.

  • Poor UX/operability: contradicts expected behavior and complicates automated tests/refills.

    Proof of Concept

    The test sets the faucet’s balance to exactly faucetDrip and then attempts a claim. Because the contract uses <= instead of <, the claim incorrectly reverts at this edge case, proving the off-by-one bug.

function testBalanceEqualToFaucetDripShouldWork() public {
// First burn all tokens
vm.startPrank(owner);
raiseBoxFaucet.burnFaucetTokens(raiseBoxFaucet.getFaucetTotalSupply());
// Now mint exactly faucetDrip amount
raiseBoxFaucet.mintFaucetTokens(address(raiseBoxFaucet), raiseBoxFaucet.faucetDrip());
vm.stopPrank();
// Verify balance is exactly faucetDrip
assertEq(raiseBoxFaucet.getFaucetTotalSupply(), raiseBoxFaucet.faucetDrip(), "Balance should equal faucetDrip");
// Try to claim - this should work but currently fails due to <= check instead of <
vm.startPrank(user1);
vm.expectRevert(); // The <= check causes this revert when balance equals faucetDrip
raiseBoxFaucet.claimFaucetTokens();
vm.stopPrank();
}

Recommended Mitigation

Remove the <=and use <instead to solve the problem.

- if (balanceOf(address(this)) <= faucetDrip) {
+ if (balanceOf(address(this)) < faucetDrip) {
revert RaiseBoxFaucet_InsufficientContractBalance();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 15 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Off-by-one error in `claimFaucetTokens` prevents claiming when the balance is exactly equal to faucetDrip

Support

FAQs

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