Skip to main content

Snapshots Periods

Overview

The SnapshotPeriods contract provides a mechanism for tracking token balances over time periods, enabling historical balance lookups and time-weighted ownership calculations.

Key Features

  • Historical balance tracking for any RestrictedLockupToken-compatible token
  • Time-weighted ownership calculation across custom periods
  • Past balance lookup for both individual accounts and total supply
  • Automatic period management for token transfers, mints, and burns

Usage

How It Works

The contract maintains a historical record of token balances and calculates ownership based on time periods:

  1. When token transfers, mints, or burns occur, the RestrictedLockupToken contract calls the onUpdate function in SnapshotPeriods.
  2. SnapshotPeriods creates and maintains periods that record the token balances and timestamps for both individual accounts and the total supply.
  3. For time-weighted operations, the contract calculates ownership as the product of token amount and time period length.

Time-Weighted Ownership

A key feature of SnapshotPeriods is the ability to calculate time-weighted ownership, which is essential for applications like interest distribution based on token holding duration:

The time-weighted ownership is calculated by:

  • Tracking when token balances change for each account
  • Creating period entries that record the balance, start time, and end time
  • Calculating the ownership as amount × (endTime - startTime)
  • Summing these values to determine the total ownership over specific time ranges

Primary Functions

The SnapshotPeriods contract provides these primary functions:

  • getPastBalanceOf(token, account, timestamp): Retrieves the balance an account had at a specific past moment
  • getPastTotalSupply(token, timestamp): Retrieves the total token supply at a specific past moment
  • ownershipForPeriod(token, account, startTimestamp, endTimestamp): Calculates time-weighted ownership for an account over a given period
  • totalOwnershipForPeriod(token, startTimestamp, endTimestamp): Calculates the total time-weighted ownership over a given period
  • calculateOwnershipForPeriod(amount, periodStart, periodEnd): Helper function to calculate ownership weight as amount × (periodEnd - periodStart)

Integration with Interest Payment

SnapshotPeriods is a critical component for the Interest Payment system, as it provides the historical data needed to calculate interest distributions based on token ownership over specific time periods:

  1. Interest Payment periods are created with specific start and end timestamps
  2. When tokens are claimed, the SnapshotPeriods contract calculates each account's proportional ownership during that period
  3. Interest is distributed according to the proportion of time-weighted ownership

API Reference

Constructor

constructor()

Initializes the SnapshotPeriods contract and sets the interface ID for ERC-165 support.

Requirements:

  • None (parameterless constructor)

Core Functions

onUpdate(address tokenAddress, address from, address to, uint256 amount)

Called by token contracts to update period tracking when transfers, mints, or burns occur.

Parameters:

  • tokenAddress (address): The token contract address making the call
  • from (address): Source address (zero address for mints)
  • to (address): Destination address (zero address for burns)
  • amount (uint256): Amount being transferred

Requirements:

  • Caller must be the token contract (msg.sender == tokenAddress)
  • Amount must be greater than zero to trigger updates

Emits: No events (internal state updates only)


Historical Balance Functions

getPastBalanceOf(address token, address account, uint256 timestamp) → uint256

Returns the balance an account had at a specific past timestamp.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • timestamp (uint256): Past timestamp to query (must be < block.timestamp)

Returns:

  • uint256: Account balance at the specified timestamp

Requirements:

  • Timestamp must be in the past (< block.timestamp)

getPastTotalSupply(address token, uint256 timestamp) → uint256

Returns the total supply at a specific past timestamp.

Parameters:

  • token (address): Token contract address
  • timestamp (uint256): Past timestamp to query (must be < block.timestamp)

Returns:

  • uint256: Total supply at the specified timestamp

Requirements:

  • Timestamp must be in the past (< block.timestamp)

Ownership Calculation Functions

ownershipAt(address token, address account, uint256 timestamp) → uint256

Calculates cumulative time-weighted ownership for an account up to a specific timestamp.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • timestamp (uint256): Timestamp to calculate ownership up to

Returns:

  • uint256: Cumulative time-weighted ownership (amount × time)

totalOwnershipAt(address token, uint256 timestamp) → uint256

Calculates cumulative time-weighted total ownership up to a specific timestamp.

Parameters:

  • token (address): Token contract address
  • timestamp (uint256): Timestamp to calculate ownership up to

Returns:

  • uint256: Cumulative time-weighted total ownership (amount × time)

ownershipForPeriod(address token, address account, uint256 startTimestamp, uint256 endTimestamp) → uint256

Calculates time-weighted ownership for an account over a specific period.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • startTimestamp (uint256): Period start timestamp
  • endTimestamp (uint256): Period end timestamp

Returns:

  • uint256: Time-weighted ownership for the period (amount × duration)

Requirements:

  • startTimestamp must be less than endTimestamp

totalOwnershipForPeriod(address token, uint256 startTimestamp, uint256 endTimestamp) → uint256

Calculates total time-weighted ownership over a specific period.

Parameters:

  • token (address): Token contract address
  • startTimestamp (uint256): Period start timestamp
  • endTimestamp (uint256): Period end timestamp

Returns:

  • uint256: Total time-weighted ownership for the period

Requirements:

  • startTimestamp must be less than endTimestamp

calculateOwnershipForPeriod(uint256 amount, uint256 periodStart, uint256 periodEnd) → uint256

Pure function to calculate ownership weight for a given amount and time period.

Parameters:

  • amount (uint256): Token amount
  • periodStart (uint256): Period start timestamp
  • periodEnd (uint256): Period end timestamp

Returns:

  • uint256: Ownership weight (amount × (periodEnd - periodStart))

Information Query Functions

addressInfo(address token, address account) → WalletInfo

Returns wallet information for a specific account and token.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query

Returns:

  • WalletInfo: Struct containing account information

WalletInfo Structure:

struct WalletInfo {
uint256 latestAccrualTimestamp; // Last timestamp when periods were updated
uint256 totalAccruedOwnership; // Cumulative time-weighted ownership
uint256 periodCount; // Number of periods recorded
}

supplyInfo(address token) → WalletInfo

Returns total supply information for a token.

Parameters:

  • token (address): Token contract address

Returns:

  • WalletInfo: Struct containing total supply information

Period Access Functions

walletPeriodByIndex(address token, address account, uint256 index) → Period

Returns a specific period for an account by index.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • index (uint256): Period index

Returns:

  • Period: Struct containing period information

Period Structure:

struct Period {
uint256 start; // Period start timestamp
uint256 end; // Period end timestamp
uint256 totalAccruedOwnership; // Cumulative ownership up to this period
uint256 accruedOwnership; // Ownership accrued in this period only
}

totalSupplyPeriodByIndex(address token, uint256 index) → Period

Returns a specific total supply period by index.

Parameters:

  • token (address): Token contract address
  • index (uint256): Period index

Returns:

  • Period: Struct containing period information

walletPeriodCount(address token, address account) → uint256

Returns the number of periods recorded for an account.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query

Returns:

  • uint256: Number of periods

totalSupplyPeriodCount(address token) → uint256

Returns the number of total supply periods recorded for a token.

Parameters:

  • token (address): Token contract address

Returns:

  • uint256: Number of periods

walletPeriodAccruedOwnership(address token, address account, uint256 index) → uint256

Returns the cumulative accrued ownership up to a specific period for an account.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • index (uint256): Period index

Returns:

  • uint256: Cumulative accrued ownership

totalSupplyPeriodAccruedOwnership(address token, uint256 index) → uint256

Returns the cumulative accrued ownership up to a specific period for total supply.

Parameters:

  • token (address): Token contract address
  • index (uint256): Period index

Returns:

  • uint256: Cumulative accrued ownership

Period Search Functions

findPeriodIndexForTimestamp(address token, address account, uint256 timestamp) → uint256

Finds the period index that ends before or includes a given timestamp for an account.

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • timestamp (uint256): Timestamp to search for

Returns:

  • uint256: Period index, or type(uint256).max if no suitable period found

findTotalSupplyPeriodIndexForTimestamp(address token, uint256 timestamp) → uint256

Finds the period index that ends before or includes a given timestamp for total supply.

Parameters:

  • token (address): Token contract address
  • timestamp (uint256): Timestamp to search for

Returns:

  • uint256: Period index, or type(uint256).max if no suitable period found

Storage Access Functions

walletInfo(address token, address account) → (uint256, uint256, uint256)

Direct access to wallet information storage (returns individual values).

Parameters:

  • token (address): Token contract address
  • account (address): Account to query

Returns:

  • uint256: Latest accrual timestamp
  • uint256: Total accrued ownership
  • uint256: Period count

totalSupplyInfo(address token) → (uint256, uint256, uint256)

Direct access to total supply information storage (returns individual values).

Parameters:

  • token (address): Token contract address

Returns:

  • uint256: Latest accrual timestamp
  • uint256: Total accrued ownership
  • uint256: Period count

walletPeriods(address token, address account, uint256 index) → (uint256, uint256, uint256, uint256)

Direct access to wallet period storage (returns individual values).

Parameters:

  • token (address): Token contract address
  • account (address): Account to query
  • index (uint256): Period index

Returns:

  • uint256: Period start timestamp
  • uint256: Period end timestamp
  • uint256: Total accrued ownership
  • uint256: Accrued ownership for this period

totalSupplyPeriods(address token, uint256 index) → (uint256, uint256, uint256, uint256)

Direct access to total supply period storage (returns individual values).

Parameters:

  • token (address): Token contract address
  • index (uint256): Period index

Returns:

  • uint256: Period start timestamp
  • uint256: Period end timestamp
  • uint256: Total accrued ownership
  • uint256: Accrued ownership for this period

Utility Functions

INTERFACE_ID() → bytes4

Returns the interface ID for ERC-165 support.

Returns:

  • bytes4: The interface identifier

supportsInterface(bytes4 interfaceId) → bool

Checks if the contract supports a specific interface (ERC-165).

Parameters:

  • interfaceId (bytes4): Interface identifier to check

Returns:

  • bool: True if the interface is supported

Custom Errors

SnapshotPeriods_InvalidToken()

Thrown when an invalid token address is provided.


SnapshotPeriods_UnauthorizedCaller()

Thrown when onUpdate is called by an address other than the token contract.


SnapshotPeriods_TimestampInFuture()

Thrown when attempting to query historical data with a future timestamp.