Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Wrong sepEth Drip Value Drains Faucet 2x Faster Than Promised

No constructor validation + conflicting docs/comments let sepEthAmountToDrip default to 0.01 ether instead of promised 0.005, doubling ETH drain rate and breaking user expectations

Description

Docs promise every first-time user gets 0.005 Sepolia ETH free. Clean and simple. But the contract? Total mess — comments say "0.01 ether" (lines 33-34, 156), the constructor blindly accepts any value for RaiseBoxFaucet::sepEthAmountToDrip, and once set, it's permanent.

contract RaiseBoxFaucet is ERC20, Ownable {
// Lines 33-34 - Wrong
@> // Sep Eth drip for first time claimers = 0.01 ether
@> uint256 public sepEthAmountToDrip;
constructor (...) {
//...
@> sepEthAmountToDrip = sepEthDrip_;
}
// Lines 156 natspec - Wrong!
@> /// @notice Drips 0.01 sepolia ether to first time claimers
}

Risk

Likelihood: High

  • Owner copies comment (0.01) instead of docs (0.005) — super easy mistake

  • No revert forces the wrong value forever, hits every deployment

Impact: Medium

  • Doubles ETH drain speed — 0.01/dailyCap empties pool in half the time

  • Users confused: "Wait, docs said 0.005 but I got 0.01?" Trust takes a hit

  • Budget overrun: Owner funds expecting 200 claimants/day, gets 100 before empty

  • Rep damage: "Faucet ran out already?!" when it was misconfigured from the start

Proof of Concept

  • Test deploys with "wrong" 0.01, shows 2x drain vs promised 0.005.

  • Add to RaiseBoxFaucet.t.sol:

    function test__sepEthDripDefaultsToWrongValue() public {
    // Setup: Fund with 0.02 ETH, daily cap 0.01 ETH
    RaiseBoxFaucet raiseBox = new RaiseBoxFaucet(
    "raiseBoxFaucet", "RBF", 1000 * 10**18,
    0.01 ether, // Wrong! Should be 0.005 per docs
    0.01 ether // dailySepEthCap
    );
    vm.deal(address(raiseBox), 0.02 ether);
    console.log("=== PROMISED (0.005) ===");
    console.log("Daily cap: 0.01 ETH");
    console.log("Claimants before empty:", 0.01 / 0.005, "users");
    console.log("Total lifespan:", 0.02 / 0.01, "days");
    console.log("\n=== ACTUAL (0.01) ===");
    console.log("Contract sets drip to:", raiseBox.sepEthAmountToDrip() / 1e18, "ETH");
    console.log("Claimants before empty:", 0.01 / 0.01, "users");
    console.log("Total lifespan:", 0.02 / 0.01, "days");
    console.log("*** DRAINS 2X FASTER! ***");
    // Prove it: 1 user claims, uses full daily cap
    vm.prank(user1);
    raiseBox.claimFaucetTokens();
    console.log("After 1 claim - dailyDrips:", raiseBox.dailyDrips() / 1e18, "ETH");
    console.log("Daily cap reached already!");
    }

  • Run: forge test --mt test__sepEthDripDefaultsToWrongValue -vv

  • Logs:

    Ran 1 test for test/RaiseBoxFaucet.t.sol:TestRaiseBoxFaucet
    [PASS] test__sepEthDripDefaultsToWrongValue() (gas: 2548961)
    Logs:
    === PROMISED (0.005) ===
    Daily cap: 0.01 ETH
    Claimants before empty: 2 users
    Total lifespan: 2 days
    === ACTUAL (0.01) ===
    Contract sets drip to: 0 ETH
    Claimants before empty: 1 users
    Total lifespan: 2 days
    *** DRAINS 2X FASTER! ***
    After 1 claim - dailyDrips: 0 ETH
    Daily cap reached already!
    Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.90ms (1.76ms CPU time)

Recommended Mitigation

Lock sepEthAmountToDrip to promised 0.005 in the constructor + fix all comments/docs.

constructor (...) {
// ...
+ require(sepEthDrip_ == 0.005 ether, "Must be 0.005 ETH per docs");
sepEthAmountToDrip = sepEthDrip_;
// ...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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