Immunefi Audit Competitions
Firelight

59115 sc low periodattimestamp function is incorrectly implemented and always returns period at current timestamp

Submitted on Nov 8th 2025 at 21:28:28 UTC by @Tadev for Audit Comp | Firelight

Description

Brief/Intro

As per the documentation, the periodAtTimestamp function is supposed to return the period number for the timestamp given. This function is defined as follows:

    function periodAtTimestamp(uint48 timestamp) public view returns (uint256) {
        PeriodConfiguration memory periodConfiguration = periodConfigurationAtTimestamp(timestamp);
        // solhint-disable-next-line max-line-length
        return periodConfiguration.startingPeriod + _sinceEpoch(periodConfiguration.epoch) / periodConfiguration.duration;
    }

The problem is that the current implementation is incorrect, always returning the period at the current timestamp.

Vulnerability Details

The periodAtTimestamp function fetches the periodConfiguration of the provided timestamp. After that, it computes:

periodConfiguration.startingPeriod + _sinceEpoch(periodConfiguration.epoch) / periodConfiguration.duration

The problem lies in _sinceEpoch internal function, which doesn't use the provided timestamp but block.timestamp instead:

    function _sinceEpoch(uint48 epoch) private view returns (uint48) {
        return Time.timestamp() - epoch;
    }

This means the periodAtTimestamp function will return current period instead of period at given timestamp.

Impact Details

The impact of this issue is low as it consists of a logical error in periodAtTimestamp function. Anyone querying this function to know the period of a given timestamp will get a wrong result.

The impact is limited in the protocol itself because periodAtTimestamp function is used internally only in currentPeriod function, and the timestamp provided is the current block timestamp.

Proof of Concept

Proof of Concept

Please create a poc.js file in the test folder and copy paste the following code:

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

describe('POC LOW', function() {
  const DECIMALS = 18,
        INITIAL_DEPOSIT_LIMIT = ethers.parseUnits('100000', DECIMALS)

  before(async () => {
    ({ firelight_vault, config } = await loadFixture(
      deployVault.bind(null, { decimals: DECIMALS, initial_deposit_limit: INITIAL_DEPOSIT_LIMIT })
    ))
  })

  it('demonstrates periodAtTimestamp ignores the timestamp parameter', async () => {
    const currentTime = await time.latest()
    const periodDuration = config.period_configuration_duration
    
    console.log(`\n  Current block timestamp: ${currentTime}`)
    console.log(`  Period duration: ${periodDuration} seconds`)
    
    // Get current period
    const currentPeriod = await firelight_vault.currentPeriod()
    console.log(`  Current period: ${currentPeriod}`)
    
    // Try to query period at current timestamp
    const periodAtNow = await firelight_vault.periodAtTimestamp(currentTime)
    console.log(`\n  periodAtTimestamp(${currentTime}) = ${periodAtNow}`)
    console.log(`  ✓ Correct: matches current period`)
    
    // Try to query period 3 periods in the future
    const futureTimestamp = currentTime + (periodDuration * 3)
    const periodAtFuture = await firelight_vault.periodAtTimestamp(futureTimestamp)
    const expectedPeriod = currentPeriod + 3n
    
    console.log(`\n  Query period at future timestamp:`)
    console.log(`  Future timestamp: ${futureTimestamp} (3 periods ahead)`)
    console.log(`  Expected period: ${expectedPeriod}`)
    console.log(`  periodAtTimestamp(${futureTimestamp}) = ${periodAtFuture}`)
    console.log(`  ✗ BUG: Returns ${periodAtFuture} instead of ${expectedPeriod}`)
  })
})

The output of this test is:

POC LOW

  Current block timestamp: 1766690171
  Period duration: 172800 seconds
  Current period: 0

  periodAtTimestamp(1766690171) = 0
  ✓ Correct: matches current period

  Query period at future timestamp:
  Future timestamp: 1767208571 (3 periods ahead)
  Expected period: 3
  periodAtTimestamp(1767208571) = 0
  ✗ BUG: Returns 0 instead of 3

This tests highlights that when querying the period at a given timestamp in the future, the function doesn't return the correct result. This issue is the same when querying with a timestamp that is in the past.