The periodConfigurationAtTimestamp function iterates through the periodConfigurations array from the beginning (index 0) to find the matching period configuration. Since period configurations are added in chronological order and most queries are for the current or recent periods (via currentPeriodConfiguration(), currentPeriod(), currentPeriodStart(), currentPeriodEnd(), and nextPeriodEnd()), iterating from the end backwards would be significantly more gas-efficient. While periodAtTimestamp() can be called with historical timestamps, these queries for historical periods are less common than queries for the current period. For arrays with many period configurations, this causes unnecessary gas consumption when querying recent periods, as the function must iterate through all older configurations first.
Vulnerability Details
The vulnerability exists in the periodConfigurationAtTimestamp function (lines 205-217):
Period configurations are added in chronological order: The _addPeriodConfiguration function (lines 799-825) ensures that new configurations are only added after the last one, confirming they are stored chronologically.
Most queries are for recent periods: Functions like currentPeriod(), currentPeriodConfiguration(), currentPeriodStart(), currentPeriodEnd(), and nextPeriodEnd() all query the current or near-future period, which will be the most recent configuration. While periodAtTimestamp() can accept historical timestamps, these queries for historical periods are less common than queries for the current period.
Inefficient iteration: When querying recent periods, the function must iterate through all older configurations first, causing unnecessary gas consumption.
Gas Cost Analysis:
Current approach: For an array with N configurations, querying the last configuration requires N storage reads (SLOAD operations at ~2100 gas each).
Optimized approach: Iterating from the end backwards would require only 1 storage read for the most common case (current period).
Example Scenario:
If there are 10 period configurations:
Querying the current period (the last configuration at index 9) requires 10 iterations and 10 storage reads
With reverse iteration, it would require only 1 iteration and 1 storage read
Impact Details
This gas optimization issue causes unnecessary gas consumption when querying recent period configurations. Since most queries are for the current period (which is the most recent configuration), iterating from the beginning of the array wastes gas by reading through all older configurations. As the vault operates over time and more period configurations are added, this inefficiency compounds, making period-related queries increasingly expensive. The impact is particularly significant for frequently called functions like currentPeriod(), currentPeriodConfiguration(), currentPeriodStart(), and currentPeriodEnd(), all of which call periodConfigurationAtTimestamp internally.
References
contracts/FirelightVault.sol
Recommendation
Optimize the loop to iterate from the end backwards, as period configurations are stored in chronological order and most queries are for recent periods.
Fix for periodConfigurationAtTimestamp:
Proof of Concept
Proof of Concept
A runnable PoC test demonstrates the gas inefficiency by measuring gas costs for querying recent periods with varying numbers of period configurations.
PoC Test Code:
The test file test/gas_optimization_period_configuration_loops_poc.js:
Test Results:
Running npx hardhat test test/gas_optimization_period_configuration_loops_poc.js:
Gas Cost Analysis:
1 configuration: ~34,280 gas
5 configurations: ~51,494 gas (+17,214 gas, +50% increase)
10 configurations: ~76,549 gas (+42,269 gas, +123% increase)
function periodConfigurationAtTimestamp(uint48 timestamp) public view returns (PeriodConfiguration memory) {
uint256 length = periodConfigurations.length;
if (length == 0) revert InvalidPeriod();
// Iterate from the end backwards for better gas efficiency
for (uint256 i = length; i > 0; ) {
unchecked {
--i;
}
PeriodConfiguration memory pc = periodConfigurations[i];
if (timestamp >= pc.epoch) {
return pc;
}
}
revert InvalidPeriod();
}
$ npx hardhat test test/gas_optimization_period_configuration_loops_poc.js
Gas Optimization: Period Configuration Loops PoC
Gas Optimization Demonstration:
With 1 configuration: 34280 gas
With 10 configurations: 76549 gas
Savings: 42269 gas per query
✓ demonstrates gas inefficiency when querying recent periods with many configurations (2539ms)
Gas Cost Growth:
1 configuration: 34280 gas
5 configurations: 51494 gas (+17214)
10 configurations: 76549 gas (+42269)
✓ demonstrates gas cost increases with more configurations (339ms)
2 passing (3s)