Raisebox Faucet

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

Off-by-One Error in Balance Check Prevents Last Valid Claim

Root + Impact

Description

  • The contract should allow users to claim tokens as long as the contract balance is sufficient to fulfill the claim (balance >= faucetDrip).

  • The balance check uses <= instead of <, which incorrectly reverts when the contract balance exactly equals faucetDrip, preventing the last valid claim even though sufficient tokens are available.

// @> if (balanceOf(address(this)) <= faucetDrip) {
// @> revert RaiseBoxFaucet_InsufficientContractBalance();
// @> }

Risk

Likelihood:

  • This occurs when the contract has exactly faucetDrip amount of tokens remaining

  • Happens naturally as the contract approaches depletion

  • Will occur at least once in the contract's lifetime when approaching empty state

Impact:

  • One claim's worth of tokens becomes permanently locked in the contract

  • Users are denied access to tokens that should be claimable

  • Contradicts the error name "InsufficientContractBalance" when balance is actually sufficient

  • Reduces total tokens distributed by one full claim amount (e.g., 1000 tokens)

Proof of Concept

function testCannotClaimWhenBalanceExactlyEqualsDrip() public {
// Setup: Reduce contract balance to exactly 1 faucetDrip
vm.startPrank(owner);
uint256 currentBalance = raiseBoxFaucet.balanceOf(address(raiseBoxFaucet));
uint256 excessAmount = currentBalance - raiseBoxFaucet.faucetDrip();
raiseBoxFaucet.burnFaucetTokens(excessAmount);
vm.stopPrank();
// Contract now has exactly faucetDrip amount
assertEq(
raiseBoxFaucet.balanceOf(address(raiseBoxFaucet)),
raiseBoxFaucet.faucetDrip()
);
// User tries to claim - should succeed but reverts
vm.prank(user1);
vm.expectRevert(RaiseBoxFaucet.RaiseBoxFaucet_InsufficientContractBalance.selector);
raiseBoxFaucet.claimFaucetTokens();
// BUG: These 1000 tokens are now permanently locked!
}

Recommended Mitigation

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

Lead Judging Commences

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