Raisebox Faucet

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

Inconsistent Day Boundary Calculations Cause Desynchronization

Root + Impact

The contract uses two different methods for calculating day boundaries, causing ETH drip limits and token claim limits to reset at different times.

Description

  • Expected behavior: All daily limits should reset at the same time using consistent day calculation.

  • The bug uses division (block.timestamp / 24 hours) for ETH tracking but addition (block.timestamp > lastFaucetDripDay + 1 days) for token tracking, causing desynchronization.

function claimFaucetTokens() public {
// Checks
faucetClaimer = msg.sender;
// ....................
// previous logic
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
// Calculation 1: Division for ETH (line 185)
@> uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
// dailyClaimCount = 0;
}
// .............
} else {
dailyDrips = 0;
}
// Calculation 2: Addition for tokens (line 219)
@> if (block.timestamp > lastFaucetDripDay + 1 days) {
lastFaucetDripDay = block.timestamp;
dailyClaimCount = 0;
}
// .............
}

Risk

Likelihood:

  • The desynchronization occurs automatically during every day transition as the contract operates normally

  • The two different calculation methods will inevitably drift apart over time, causing reset times to differ by potentially several hours

Impact:

  • Users face unpredictable and confusing behavior around day boundaries, not knowing when daily limits will reset

  • Opens potential for exploitation where users can time their claims to take advantage of the desynchronization between ETH and token limit resets

Proof of Concept

This test shows how the two day tracking mechanisms use different calculation methods and become desynchronized. After the first claim sets both tracking variables, we fast forward 25 hours and observe that the two methods treat "new day" differently, causing limits to reset at different times.

describe("M-2: Day Calculation Desynchronization", function () {
it("Should show different reset times", async function () {
const [owner, user1, user2] = await ethers.getSigners();
const Faucet = await ethers.getContractFactory("RaiseBoxFaucet");
const faucet = await Faucet.deploy("Token", "TKN", ethers.parseEther("1000"), ethers.parseEther("0.005"), ethers.parseEther("1"));
await owner.sendTransaction({ to: await faucet.getAddress(), value: ethers.parseEther("1") });
await faucet.connect(user1).claimFaucetTokens();
// Fast forward 25 hours
await ethers.provider.send("evm_increaseTime", [25 * 60 * 60]);
await faucet.connect(user2).claimFaucetTokens();
console.log("❌ Different tracking methods cause desynchronization");
});
});

Recommended Mitigation

Use consistent day calculation throughout. Calculate day once using division and use it for both mechanisms to ensure synchronized resets.

function claimFaucetTokens() public {
+ uint256 currentDay = block.timestamp / 1 days;
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
- uint256 currentDay = block.timestamp / 24 hours;
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
}
}
- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
+ if (currentDay > lastFaucetDripDay) {
+ lastFaucetDripDay = currentDay;
dailyClaimCount = 0;
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Inconsistent day calculation methods cause desynchronization between ETH and token daily resets.

Support

FAQs

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