#59967 [SC-Low] broken historical period calculation

Submitted on Nov 17th 2025 at 08:46:37 UTC by @dice for Audit Comp | Firelight

  • Report ID: #59967

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/firelight-protocol/firelight-core/blob/main/contracts/FirelightVault.sol

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Brief/Intro

The periodAtTimestamp(uint48 timestamp) function is designed to return the period number for any given timestamp parameter. However, it incorrectly uses block.timestamp instead of the provided timestamp parameter in its internal calculation via _sinceEpoch() at line 798-800. This causes the function to always return the current period number regardless of what historical timestamp is passed in, completely breaking historical period lookups and violating the function's documented behaviour.

  function _sinceEpoch(uint48 epoch) private view returns (uint48) {
      return Time.timestamp() - epoch;  // Always uses current time
  }


  // Line 246-250: periodAtTimestamp ignores its parameter
  function periodAtTimestamp(uint48 timestamp) public view returns (uint256) {
      PeriodConfiguration memory periodConfiguration = periodConfigurationAtTimestamp(timestamp);
      return periodConfiguration.startingPeriod + _sinceEpoch(periodConfiguration.epoch) / periodConfiguration.duration;
      //                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      //                                          Uses block.timestamp, NOT the timestamp parameter!
  }

Vulnerability Details

The root cause is in _sinceEpoch() which computes Time.timestamp() - epoch instead of timestamp - epoch. When periodAtTimestamp() calls this helper function at line 249, it passes the correct epoch but the calculation uses current block.timestamp, making periodAtTimestamp(50 days) and periodAtTimestamp(99 days) return identical results. While periodConfigurationAtTimestamp(timestamp) correctly finds the right configuration for the input timestamp, the subsequent period number calculation is done using current time, rendering the timestamp parameter completely useless.

Example

Impact Details

This bug completely breaks any historical period queries, causing all external systems, governance mechanisms to determine which period a past event occurred in to receive incorrect data showing the current period instead.

The function violates its NatSpec documentation which promises to return "the period number corresponding to the given timestamp", creating a critical trust and integration issue. While not directly exploitable for fund theft in the current implementation, it poses systemic risk for any future upgrades or external integrations that rely on historical period calculations for time-weighted logic, snapshot-based voting, or accounting systems. Additionally, it makes the withdrawal queue system's historical state unreconstructable, preventing accurate audits of past withdrawal requests and their corresponding periods.

function _sinceEpoch(uint48 epoch, uint48 timestamp) private pure returns (uint48) { return timestamp - epoch; // Use the timestamp parameter }

References

https://github.com/firelight-protocol/firelight-core/blob/db36312f1fb24efc88c3fde15a760defbc3e6370/contracts/FirelightVault.sol#L249

https://github.com/firelight-protocol/firelight-core/blob/db36312f1fb24efc88c3fde15a760defbc3e6370/contracts/FirelightVault.sol#L795

Proof of Concept

Proof of Concept

Was this helpful?