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 12 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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