Raisebox Faucet

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

Uninitialized Day Tracking Variables Cause Incorrect First Day Behavior

Root + Impact

The lastDripDay and lastFaucetDripDay variables default to 0, causing incorrect reset logic on the first day of operation.

Description

  • Expected behavior: Day tracking variables should be initialized to current day in constructor.

  • The bug leaves variables at 0 (lines 26, 28), causing unnecessary resets on first claim.

@>uint256 public lastDripDay; // Defaults to 0!
@>uint256 public lastFaucetDripDay; // Defaults to 0!
constructor(...) {
// BUG: Variables not initialized
}

Risk

Likelihood:

  • This issue occurs on every single deployment of the contract without exception

  • The first user to interact with the faucet will trigger the incorrect reset logic immediately

Impact:

  • Inconsistent behavior between the first day of operation and all subsequent days, potentially causing confusion in tracking and analytics

  • Could allow the possibility of more claims or ETH drips than intended on the deployment day due to unnecessary resets

Proof of Concept

This test verifies that day tracking variables are not initialized properly. It deploys the contract, checks the initial values, and demonstrates how the first claim unnecessarily triggers a reset because the comparison currentDay > 0 will always be true.

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("M-4: Uninitialized Day Tracking Variables", function () {
it("Should show variables default to 0 and cause incorrect first-day behavior", async function () {
const [owner, user] = 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") });
// Check uninitialized values
const lastDripDayBefore = await faucet.lastDripDay();
const lastFaucetDripDayBefore = await faucet.lastFaucetDripDay();
// Calculate what they should be
const currentBlock = await ethers.provider.getBlock('latest');
const expectedDay = BigInt(currentBlock.timestamp) / 86400n;
console.log("\n=== After Deployment ===");
console.log(`lastDripDay: ${lastDripDayBefore} (expected: ${expectedDay})`);
console.log(`lastFaucetDripDay: ${lastFaucetDripDayBefore} (expected: ${expectedDay})`);
console.log("❌ Variables are 0 instead of current day!");
// First user claims
await faucet.connect(user).claimFaucetTokens();
const lastDripDayAfter = await faucet.lastDripDay();
const lastFaucetDripDayAfter = await faucet.lastFaucetDripDay();
console.log("\n=== After First Claim ===");
console.log(`lastDripDay: ${lastDripDayAfter}`);
console.log(`lastFaucetDripDay: ${lastFaucetDayAfter}`);
console.log("⚠️ First claim triggered unnecessary reset (currentDay > 0 = always true)");
expect(lastDripDayBefore).to.equal(0);
expect(lastFaucetDripDayBefore).to.equal(0);
});
});

Recommended Mitigation

Initialize variables in constructor. Setting variables to current day at deployment ensures consistent behavior from the start.

constructor(
string memory name_,
string memory symbol_,
uint256 faucetDrip_,
uint256 sepEthDrip_,
uint256 dailySepEthCap_
) ERC20(name_, symbol_) Ownable(msg.sender) {
faucetDrip = faucetDrip_;
sepEthAmountToDrip = sepEthDrip_;
dailySepEthCap = dailySepEthCap_;
+ lastDripDay = block.timestamp / 1 days;
+ lastFaucetDripDay = block.timestamp / 1 days;
_mint(address(this), INITIAL_SUPPLY);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!