Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
Submission Details
Impact: medium
Likelihood: medium

Off‑by‑one blocks the last available token drip

Author Revealed upon completion

Description:
The contract reverts when balanceOf(address(this)) <= faucetDrip. When the faucet holds exactly one drip left, claims revert, permanently trapping tokens.

Impact:

  • Users cannot claim the final drip; UX break and stranded tokens in the contract.

Proof of Concept:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import {Test, console2} from "../lib/lib/forge-std/src/Test.sol";
import {RaiseBoxFaucet} from "../src/RaiseBoxFaucet.sol";
contract RaiseBoxFaucetVulnerabilityTest is Test {
RaiseBoxFaucet public faucet;
address public owner;
address public user1;
address public user2;
function advanceBlockTime(uint256 duration_) internal {
vm.warp(duration_);
}
function setUp() public {
owner = makeAddr("owner");
user1 = makeAddr("user1");
user2 = makeAddr("user2");
vm.prank(owner);
faucet = new RaiseBoxFaucet(
"RaiseBoxToken",
"RBT",
1000 * 10**18, // 1000 tokens per claim
0.005 ether, // 0.005 ETH per first claim
1 ether // 1 ETH daily cap
);
vm.deal(address(faucet), 10 ether);
advanceBlockTime(3 days);
}
function test_LastDripBlocked() public {
uint256 initialContractBalance = faucet.balanceOf(address(faucet));
vm.startPrank(owner);
// Drain faucet balance to owner via burn function, then mint exactly one drip back to the contract
faucet.burnFaucetTokens(initialContractBalance); // moves all to owner, burns all
faucet.mintFaucetTokens(address(faucet), faucet.faucetDrip());
vm.stopPrank();
vm.prank(user1);
vm.expectRevert(RaiseBoxFaucet.RaiseBoxFaucet_InsufficientContractBalance.selector);
faucet.claimFaucetTokens(); // reverts even though exactly one drip is available
}
}

Mitigation:

Change condition to < faucetDrip.

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

Support

FAQs

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