Raisebox Faucet

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

State Variables Should Be Immutable/Constant

State Variables Should Be Immutable/Constant

Description

State variables that are only set during contract deployment should be declared as immutable to reduce gas costs and improve code clarity about their unchangeable nature.

Variables faucetDrip, sepEthAmountToDrip, dailySepEthCap, and blockTime are only set in the constructor or are constant values, but are not marked as immutable or constant, causing unnecessary storage costs for every read operation throughout the contract's lifetime.

@> uint256 public faucetDrip; // Only set in constructor - should be immutable
@> uint256 public sepEthAmountToDrip; // Only set in constructor - should be immutable
@> uint256 public dailySepEthCap; // Only set in constructor - should be immutable
@> uint256 public blockTime = block.timestamp; // Never changes after deployment - should be immutable

Risk

Likelihood: High

  • Every storage read operation (SLOAD) costs additional gas for these variables in every function call

  • Gas costs accumulate across all function calls that access these variables throughout contract lifetime

  • Storage slots are unnecessarily allocated and maintained in contract state

Impact: Low

  • Significantly increased gas costs for contract deployment and every function call that reads these values

  • Reduced gas efficiency affects user experience and increases operational costs

  • Code clarity is reduced regarding which values are truly constant versus changeable

  • Higher cumulative operational costs for frequent faucet usage over time

Proof of Concept

// Demonstrate gas cost impact
contract GasImpactAnalysis {
// Current implementation (expensive)
uint256 public faucetDrip;
uint256 public sepEthAmountToDrip;
uint256 public dailySepEthCap;
uint256 public blockTime = block.timestamp;
// Optimized implementation (cheap)
uint256 public immutable faucetDripImmutable;
uint256 public immutable sepEthAmountToDripImmutable;
uint256 public immutable dailySepEthCapImmutable;
uint256 public immutable deploymentTime;
constructor() {
faucetDrip = 1000 * 10**18;
sepEthAmountToDrip = 0.005 ether;
dailySepEthCap = 1 ether;
faucetDripImmutable = 1000 * 10**18;
sepEthAmountToDripImmutable = 0.005 ether;
dailySepEthCapImmutable = 1 ether;
deploymentTime = block.timestamp;
}
// Gas cost comparison for reading values
function compareGasCosts() external view returns (
uint256 storageReadCost,
uint256 immutableReadCost,
uint256 savingsPerRead,
uint256 projectedSavings
) {
storageReadCost = 2100; // SLOAD opcode cost
immutableReadCost = 3; // Direct value insertion cost
savingsPerRead = storageReadCost - immutableReadCost; // 2,097 gas saved per read
// Project savings over 10,000 function calls
projectedSavings = savingsPerRead * 4 * 10000; // 4 variables * 10k calls = 83,880,000 gas saved
return (storageReadCost, immutableReadCost, savingsPerRead, projectedSavings);
}
// Demonstrate cumulative impact over contract lifetime
function calculateLifetimeSavings() external pure returns (
uint256 dailyUsers,
uint256 yearlyGasSavings,
uint256 etherSavingsAt50Gwei
) {
dailyUsers = 1000; // Assume 1000 users per day
uint256 dailySavings = dailyUsers * 4 * 2097; // 4 reads per claim * gas savings
yearlyGasSavings = dailySavings * 365; // Annual gas savings
// Convert to ETH cost savings at 50 gwei gas price
etherSavingsAt50Gwei = (yearlyGasSavings * 50e9) / 1e18;
return (dailyUsers, yearlyGasSavings, etherSavingsAt50Gwei);
}
// Show storage slot waste
function showStorageWaste() external pure returns (
uint256 wastedSlots,
uint256 slotsStorageCost,
string memory optimization
) {
wastedSlots = 4; // 4 variables using storage unnecessarily
slotsStorageCost = wastedSlots * 20000; // SSTORE cost per slot
optimization = "Move to immutable to eliminate storage costs";
return (wastedSlots, slotsStorageCost, optimization);
}
}

Real gas impact calculation:
Current: 4 variables * 2,100 gas per read = 8,400 gas per claim
Optimized: 4 variables * 3 gas per read = 12 gas per claim
Savings: 8,388 gas per claim
With 1000 daily users: 8,388,000 gas saved per day
Annual savings: ~3 billion gas (worth ~$150-300 at typical gas prices)

Recommended Mitigation

The mitigation converts constructor-set variables to immutable and constant values to constant, dramatically reducing gas costs while improving code clarity about which values can never change.

// Convert constructor-set variables to immutable
- uint256 public faucetDrip;
+ uint256 public immutable faucetDrip;
- uint256 public sepEthAmountToDrip;
+ uint256 public immutable sepEthAmountToDrip;
- uint256 public dailySepEthCap;
+ uint256 public immutable dailySepEthCap;
- uint256 public blockTime = block.timestamp;
+ uint256 public immutable deploymentTime;
// Keep truly constant values as constants
uint256 public constant CLAIM_COOLDOWN = 3 days;
uint256 public constant INITIAL_SUPPLY = 1e27;
+ uint256 public constant DECIMALS = 18;
constructor(
string memory name_,
string memory symbol_,
uint256 faucetDrip_,
uint256 sepEthDrip_,
uint256 dailySepEthCap_
) ERC20(name_, symbol_) Ownable(msg.sender) {
+ // Set immutable values in constructor
faucetDrip = faucetDrip_;
sepEthAmountToDrip = sepEthDrip_;
dailySepEthCap = dailySepEthCap_;
+ deploymentTime = block.timestamp;
_mint(address(this), INITIAL_SUPPLY);
}
// Update functions to use immutable values (no code changes needed - compiler handles)
// Gas savings are automatic when reading these values
// Add getter functions for consistency (optional - immutable variables are already public)
+ function getDeploymentTime() external view returns (uint256) {
+ return deploymentTime;
+ }
+
+ function getFaucetParameters() external view returns (
+ uint256 drip,
+ uint256 ethAmount,
+ uint256 dailyEthCap,
+ uint256 deployed
+ ) {
+ return (faucetDrip, sepEthAmountToDrip, dailySepEthCap, deploymentTime);
+ }
// Document the optimization in comments
+ /**
+ * @dev Gas Optimization Notes:
+ * - faucetDrip, sepEthAmountToDrip, dailySepEthCap: immutable (set in constructor)
+ * - deploymentTime: immutable (deployment timestamp)
+ * - CLAIM_COOLDOWN, INITIAL_SUPPLY: constant (compile-time values)
+ * - Total gas savings: ~8,388 gas per claim transaction
+ */
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 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.