Raisebox Faucet

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

Combining the token claim and Sepolia ETH drip in the same function `claimFaucetTokens`

Combining the token claim and Sepolia ETH drip in the same function claimFaucetTokens

Description:

Combining the token claim and Sepolia ETH drip in the same function claimFaucetTokens is
a design flow that can cause a lot of issues to developer , protocol and users

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact:

1-increase attack surface

2-state management become complex

3.incentive for abuse

Proof of Concept:

in claimFaucetTokens function Combining the token claim and Sepolia ETH drip increase the gas cost ,make the code hard to read and increaste the benefit from the attack to hacker

​
function claimFaucetTokens() public {
// Checks
faucetClaimer = msg.sender;
​
// (lastClaimTime[faucetClaimer] == 0);
​
if (block.timestamp < (lastClaimTime[faucetClaimer] + CLAIM_COOLDOWN)) { //check drip time
revert RaiseBoxFaucet_ClaimCooldownOn();
}
​
if (faucetClaimer == address(0) || faucetClaimer == address(this) || faucetClaimer == Ownable.owner()) {
revert RaiseBoxFaucet_OwnerOrZeroOrContractAddressCannotCallClaim();
}
​
if (balanceOf(address(this)) <= faucetDrip) {
revert RaiseBoxFaucet_InsufficientContractBalance();
}
​
if (dailyClaimCount >= dailyClaimLimit) {
revert RaiseBoxFaucet_DailyClaimLimitReached();
}
​
// drip sepolia eth to first time claimers if supply hasn't ran out or sepolia drip not paused**
// still checks
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
uint256 currentDay = block.timestamp / 24 hours;
​
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
// dailyClaimCount = 0;
}
​
if (dailyDrips + sepEthAmountToDrip <= dailySepEthCap && address(this).balance >= sepEthAmountToDrip) {
hasClaimedEth[faucetClaimer] = true;
dailyDrips += sepEthAmountToDrip;
​
(bool success,) = faucetClaimer.call{value: sepEthAmountToDrip}("");
​
if (success) {
emit SepEthDripped(faucetClaimer, sepEthAmountToDrip);
} else {
revert RaiseBoxFaucet_EthTransferFailed();
}
} else {
emit SepEthDripSkipped(
faucetClaimer,
address(this).balance < sepEthAmountToDrip ? "Faucet out of ETH" : "Daily ETH cap reached"
);
}
} else {
dailyDrips = 0;
}
​
/**
*
* @param lastFaucetDripDay tracks the last day a claim was made
* @notice resets the @param dailyClaimCount every 24 hours
*/
if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}
​
// Effects
​
lastClaimTime[faucetClaimer] = block.timestamp;
dailyClaimCount++;
​
// Interactions
_transfer(address(this), faucetClaimer, faucetDrip);
​
emit Claimed(msg.sender, faucetDrip);
}

Recommended Mitigation:

Split claimFaucetTokens into two functions: claimTokens and claimSepoliaEth.

This isolates the attack surface and allows independent control over each resource

// Claim tokens
function claimTokens() external {
require(!tokenClaimsPaused, "Token claims paused");
require(msg.sender != address(0) && msg.sender != address(this) && msg.sender != owner(), "Invalid caller");
require(block.timestamp >= lastClaimTime[msg.sender] + CLAIM_COOLDOWN, "Cooldown active");
require(balanceOf(address(this)) >= faucetDrip, "Insufficient tokens");
require(dailyClaimCount < dailyClaimLimit, "Daily limit reached");
​
if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}
​
lastClaimTime[msg.sender] = block.timestamp;
dailyClaimCount++;
faucetClaimer = msg.sender;
_transfer(address(this), msg.sender, faucetDrip);
emit Claimed(msg.sender, faucetDrip);
}
​
// Claim Sepolia ETH
function claimSepoliaEth() external {
require(!sepEthDripsPaused, "ETH drips paused");
require(!hasClaimedEth[msg.sender], "Already claimed ETH");
require(address(this).balance >= sepEthAmountToDrip, "Insufficient ETH");
require(dailyDrips + sepEthAmountToDrip <= dailySepEthCap, "Daily ETH cap reached");
​
uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
}
​
hasClaimedEth[msg.sender] = true;
dailyDrips += sepEthAmountToDrip;
(bool success, ) = msg.sender.call{value: sepEthAmountToDrip}("");
require(success, "ETH transfer failed");
emit SepEthDripped(msg.sender, sepEthAmountToDrip);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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

Give us feedback!