59931 sc insight useless check
Submitted on Nov 17th 2025 at 02:39:48 UTC by @Le_Rems for Audit Comp | Firelight
Report ID: #59931
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/firelight-protocol/firelight-core/blob/main/contracts/FirelightVault.sol
Impacts:
Description
Brief/Intro
The periodConfigurationAtNumber() function in FirelightVault contains a redundant validation check that will never execute. The function checks if periodConfiguration.epoch == 0 and reverts, but this condition is impossible to reach given the function's loop logic and how period configurations are initialized. While this redundant check doesn't cause functional issues or fund loss, it wastes gas on every call.
Vulnerability Details
The FirelightVault contract manages a dynamic array of PeriodConfiguration structures that define period boundaries over time. Each configuration contains an epoch , duration , and startingPeriod . These configurations are added during initialization and can be updated over time by users with the PERIOD_CONFIGURATION_UPDATE_ROLE.
The periodConfigurationAtNumber() function retrieves the appropriate period configuration for a given period number by iterating through the periodConfigurations array:
function periodConfigurationAtNumber(uint256 periodNumber) external view returns (PeriodConfiguration memory) {
uint256 length = periodConfigurations.length;
if (length == 0) revert InvalidPeriod();
PeriodConfiguration memory periodConfiguration;
for (uint256 i = 0; i < length; i++) {
if (periodNumber < periodConfigurations[i].startingPeriod)
break;
periodConfiguration = periodConfigurations[i];
}
@> if (periodConfiguration.epoch == 0) revert InvalidPeriod();
return periodConfiguration;
}The issue lies in the validation check. To understand why this check is unreachable, we must trace through the function's execution:
Initial state:
periodConfigurationis declared as a memory struct. In Solidity, uninitialized structs have all fields set to zero values, so initiallyperiodConfiguration.epoch = 0.First configuration guarantee: The contract ensures
periodConfigurations.length >= 1after initialization. Duringinitialize(), the contract always calls_addPeriodConfiguration(Time.timestamp(), initParams.periodConfigurationDuration), which adds the first configuration. This first configuration always hasstartingPeriod = 0as set in_addPeriodConfiguration().Loop execution: The loop starts at
i = 0. For the first iteration:The condition checks:
periodNumber < periodConfigurations[0].startingPeriodSince
periodConfigurations[0].startingPeriod = 0andperiodNumberis auint256(always>= 0), the conditionperiodNumber < 0is always falseTherefore, the loop body executes:
periodConfiguration = periodConfigurations[0]This assignment sets
periodConfiguration.epochtoperiodConfigurations[0].epoch, which isTime.timestamp()from initialization (guaranteed to be non-zero as it's a real block timestamp)
Epoch validation: The epoch values are further protected by validation in
_addPeriodConfiguration():For the first configuration:
if (newEpoch < Time.timestamp()) revert InvalidPeriodConfigurationEpoch();ensures the epoch is at least the current timestamp (non-zero)For subsequent configurations:
if (newEpoch < nextPeriodEnd() || ...)ensures the epoch is always a valid future timestamp
Unreachable check: Since the loop is guaranteed to assign at least
periodConfigurations[0](which has a non-zero epoch),periodConfiguration.epochcan never be 0.
Impact Details
The impact of this finding is primarily informational, affecting code quality rather than functionality:
1. Gas Waste (Low Impact - Operational):
Every call to
periodConfigurationAtNumber()performs an unnecessarysloadoperation to readperiodConfiguration.epochand a comparison checkWhile minimal per call (~100-200 gas), this accumulates over time and is wasteful
References
periodConfigurationAtNumber()implementation_addPeriodConfiguration()function showing epoch validationinitialize()function showing first configuration is always addedperiodConfigurationAtTimestamp()showing identical redundant check pattern
Proof of Concept
Proof of Concept
Was this helpful?