Raisebox Faucet

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

Off-by-One Error Prevents Final Claim in `claimFaucetTokens()`

Summary

An off-by-one error in the balance check prevents users from claiming tokens when the faucet balance exactly equals faucetDrip, even though sufficient tokens exist for one more claim.

Description

Normal Behavior

  • The faucet should reject claims when it has insufficient tokens for one claim.

  • Users should be able to claim when the faucet has exactly enough tokens for one claim.

Issue

The balance validation uses<= operator instead of <, incorrectly rejecting valid claims when the balance exactly matches the drip amount.

Line: 175 - 177

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

Risk

Impact

Low

  • Users cannot claim the final faucetDrip from the faucet

  • One potential first-time claimer loses the opportunity to receive ETH rewards

  • Minimal financial impact relative to the total token supply

Likelihood

Medium

  • The faucet will naturally reach this state during normal operation.

  • No external contract or special conditions required.

Proof of Concept

Textual PoC

  1. Users claim tokens normally until the faucet balance decreases.

  2. When balanceOf(address(this)) == faucetDrip, the next claim reverts.

  3. The final faucetDrip amount of tokens remains locked in the contract.

Coded PoC

function testPreventFinalClaim() public {
//Directly set balance to faucet drip amount
//In real scenario, this would be done by multiple users claiming until the balance is low enough
vm.store(
raiseBoxFaucetContractAddress,
keccak256(abi.encode(raiseBoxFaucetContractAddress, uint256(0))),
bytes32(raiseBoxFaucet.faucetDrip())
);
vm.prank(makeAddr("lastUser"));
vm.expectRevert();
raiseBoxFaucet.claimFaucetTokens();
}

PreventFinalClaim.t.sol: https://github.com/Luu-Duc-Toan/2025-10-raisebox-faucet/blob/master/test/PreventFinalClaim.t.sol

Result:

Ran 1 test for test/PreventFinalClaim.t.sol:TestPreventFinalClaim
[PASS] testPreventFinalClaim() (gas: 45280)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.99ms (505.60µs CPU time)

Recommended Mitigation

Change the balance check to use strictly less-than (<) instead of less-than-or-equal-to (<=):

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

This allows users to claim when the faucet balance exactly equals faucetDrip, ensuring all available tokens can be distributed.

Updates

Lead Judging Commences

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

Give us feedback!