59288 sc insight repeated array access in rescuewithdrawfromblocklisted loop causes unnecessary gas consumption
Submitted on Nov 10th 2025 at 17:43:20 UTC by @hunterKing for Audit Comp | Firelight
Report ID: #59288
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 rescueWithdrawFromBlocklisted function accesses periods[i] multiple times in the loop without caching it in a local variable. While calldata reads are relatively cheap (~3 gas per byte), caching the value in a local variable would still save gas, especially when processing multiple periods. This is a simple optimization that reduces gas costs for this function.
Vulnerability Details
The gas optimization issue exists in the rescueWithdrawFromBlocklisted function at lines 678-690 of FirelightVault.sol:
for (uint256 i = 0; i < len; i++) {
uint256 _withdrawOf = withdrawSharesOf[periods[i]][from]; // periods[i] accessed
if (isWithdrawClaimed[periods[i]][from]) revert AlreadyClaimedPeriod(periods[i]); // periods[i] accessed twice
if (isWithdrawClaimed[periods[i]][to]) revert AlreadyClaimedPeriod(periods[i]); // periods[i] accessed twice
if (_withdrawOf == 0) revert NoWithdrawalAmount(periods[i]); // periods[i] accessed
withdrawSharesOf[periods[i]][to] += _withdrawOf; // periods[i] accessed
withdrawSharesOf[periods[i]][from] = 0; // periods[i] accessed
isWithdrawClaimed[periods[i]][from] = true; // periods[i] accessed
rescuedShares[i] = _withdrawOf;
}The Problem:
Repeated calldata access:
periods[i]is accessed 6 times in each loop iterationCalldata reads cost gas: Each calldata read costs ~3 gas per byte (plus base costs)
Simple optimization: Caching
periods[i]in a local variable would save gas on repeated accesses
Gas Cost Analysis:
Current approach: Each
periods[i]access reads from calldata (~3 gas per byte for uint256 = ~96 gas per access)Optimized approach: Cache
periods[i]in a local variable once, then use the local variable (saves ~6 * 96 = ~576 gas per iteration, though actual savings measured are ~458 gas per period due to other factors)
Impact Details
This gas optimization issue causes unnecessary gas consumption when rescuing withdrawals from blocklisted addresses. While individual calldata reads are relatively cheap, the repeated accesses add up, especially when processing multiple periods. Caching periods[i] in a local variable is a simple optimization that reduces gas costs without changing functionality.
References
contracts/FirelightVault.sol
Recommendation
Cache periods[i] in a local variable at the start of each loop iteration to avoid repeated calldata reads.
Fix:
Proof of Concept
Proof of Concept
A runnable PoC test demonstrates the gas inefficiency from repeated array access in rescueWithdrawFromBlocklisted.
PoC Test Code:
The PoC uses a test contract (contracts/GasOptimizationTest.sol) that implements both the current (repeated array access) and optimized (cached local variable) versions to directly compare gas consumption.
Test Contract (contracts/GasOptimizationTest.sol):
Test File (test/gas_optimization_repeated_array_access_poc.js):
Test Results:
Running npx hardhat test test/gas_optimization_repeated_array_access_poc.js:
Was this helpful?