#59605 [SC-Low] logic error in periodattimestamp returns incorrect periods

Submitted on Nov 14th 2025 at 00:37:09 UTC by @zcai for Audit Comp | Firelight

  • Report ID: #59605

  • 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() function ignores its input timestamp parameter and instead uses the current block time for period calculations. This causes incorrect period results for any non-current timestamp and potential underflow reverts when querying future timestamps under scheduled future configurations. The vulnerability compromises data integrity and may cause denial-of-service for certain timestamp queries.

NOTE: This bug in periodAtTimestamp() erroneously uses block.timestamp instead of the passed in timestamp. However, the critical currentPeriod() function which relies on this function luckily passes in the block.timestamp as the argument so it is not affected. However, integrators relying on the return value of periodAtTimestamp() are directly affected, hence the severity is reduced to medium.

Vulnerability Details

The periodAtTimestamp(uint48 timestamp) function is designed to compute the period number for an arbitrary timestamp, but contains a critical implementation flaw. Instead of using the provided timestamp parameter in its calculations, the function relies on _sinceEpoch(periodConfiguration.epoch), which internally uses Time.timestamp() (the current block time) rather than the input timestamp.

The function currently computes:

When it should compute:

This implementation error manifests in two critical ways. First, the function returns the period for the current time under the configuration selected for the provided timestamp, not the period for the provided timestamp itself. Second, when a future timestamp falls under a scheduled future configuration with an epoch greater than the current time, the calculation Time.timestamp() - epoch results in an unsigned integer underflow in Solidity 0.8, causing the transaction to revert.

Impact Details

The function compromises data integrity by returning incorrect period numbers for any timestamp that differs from the current block time. When future timestamps fall under scheduled future configurations, the function reverts due to underflow, creating a denial-of-service condition for such queries. While core protocol flows using currentPeriod() remain functional since they pass the current timestamp, any integrations or extensions relying on periodAtTimestamp() for historical or future period mapping will behave incorrectly.

References

contracts/FirelightVault.sol:246-250

contracts/FirelightVault.sol:795-797

https://gist.github.com/i-am-zcai/9c0fb1b144d706e764522d95c5cd7cf9

Proof of Concept

Proof of Concept

const { loadFixture, time } = require('@nomicfoundation/hardhat-network-helpers') const { deployVault } = require('../setup/fixtures.js') const { expect } = require('chai')

/**

  • PoC: periodAtTimestamp ignores its input timestamp parameter

  • Demonstrates two bugs in periodAtTimestamp():

    1. Returns wrong period values because it uses Time.timestamp() instead of the input

    1. Reverts on future timestamps under scheduled future configs due to underflow */ describe('PoC - periodAtTimestamp ignores input timestamp', function () { const DECIMALS = 6 const DEPOSIT_LIMIT = 100000n * 10n ** BigInt(DECIMALS) const PERIOD_DURATION = 172800 // 2 days

let firelight_vault, period_configuration_updater

before(async () => { ({ firelight_vault, period_configuration_updater } = await loadFixture( deployVault.bind(null, { initial_deposit_limit: DEPOSIT_LIMIT, period_configuration_duration: PERIOD_DURATION }) )) })

it('demonstrates periodAtTimestamp returns wrong period for past timestamps', async () => { const currentPeriod = await firelight_vault.currentPeriod() const currentTime = await time.latest()

})

it('demonstrates periodAtTimestamp reverts on future timestamp with future config', async () => { // Schedule a future period configuration const currentPeriodEnd = await firelight_vault.currentPeriodEnd() const futureEpoch = Number(currentPeriodEnd) + PERIOD_DURATION const futureDuration = 604800 // 1 week

}) })

Was this helpful?