59296 sc low periodattimestamp uint48 timestamp ignores its parameter and always returns the current period
Submitted on Nov 10th 2025 at 20:19:08 UTC by @edantes for Audit Comp | Firelight
Report ID: #59296
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/firelight-protocol/firelight-core/blob/main/contracts/FirelightVault.sol
Impacts:
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Theft of gas
Description
Brief/Intro
The read-only helper periodAtTimestamp(uint48 timestamp) is supposed to return the period number for an arbitrary timestamp. Instead, it uses “now” via _sinceEpoch(Time.timestamp()), so it returns the current period regardless of the argument. Integrators relying on it to schedule or visualize claim windows will compute the wrong period for historical timestamps.
Vulnerability Details
Component: FirelightVault.sol
Functions:
periodAtTimestamp(uint48 timestamp)
_sinceEpoch(uint48 epoch)
Root cause
In FirelightVault.sol, periodAtTimestamp(uint48 timestamp) delegates to _sinceEpoch(periodConfiguration.epoch) when forming the period number, but _sinceEpoch is defined as Time.timestamp() - epoch. That means the function completely discards the timestamp parameter and computes the period for the present (“now”), not for the caller-provided time.
periodAtTimestamp(uint48 timestamp) returns startingPeriod + _sinceEpoch(uint48 epoch) / duration. It uses “now” instead of (timestamp - epoch) / duration.
_sinceEpoch(uint48 epoch) returns Time.timestamp() - epoch.
dApps that query a past/future period get the current period number instead. When users act on that misinformation and call claimWithdraw(uint256 period) too early, the contract reverts (if (period >= currentPeriod()) revert InvalidPeriod();). Funds remain safe, but UX is broken and automations fail.
Impact Details
Incorrect Scheduling: Any integrator using periodAtTimestamp() to map timestamps and period numbers will display/schedule the wrong claim period for historical timestamps. Users attempting to claim based on those schedules will encounter InvalidPeriod / NoWithdrawalAmount until the real period arrives.
Automation Churn: Off-chain bots may repeatedly trigger failed transactions (gas waste & alert noise).
Risk Breakdown
Low: Incorrect read causing disrupted UX without financial impact. This is a low-impact, high-likelihood issue.
Recommendation
Use the provided timestamp when computing the period offset from the configuration epoch:
No changes to currentPeriod*() functions are needed since they correctly use Time.timestamp() for “now.”
Proof of Concept
Proof of Concept
A deterministic Hardhat test shows periodAtTimestamp(tsPast) returns the current period rather than the past period because the implementation ignores its timestamp parameter.
Test Details:
Setup: Deploy the vault (initialize with a valid period configuration).
Choose a historical timestamp: historicalTs = epoch + duration + 10.
Advance time: Move forward several periods so currentPeriod() > expectedPast.
Observe:
periodAtTimestamp(historicalTs) equals currentPeriod() (bug).
The correct past period is starting + (historicalTs - epoch) / duration.
How to run:
Hardhat Test File: test/PoC_FirelightVault.periodAtTimestamp.spec.js
Was this helpful?