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:
- When token transfers, mints, or burns occur, the
RestrictedLockupToken
contract calls theonUpdate
function in SnapshotPeriods. - SnapshotPeriods creates and maintains periods that record the token balances and timestamps for both individual accounts and the total supply.
- 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 momentgetPastTotalSupply(token, timestamp)
: Retrieves the total token supply at a specific past momentownershipForPeriod(token, account, startTimestamp, endTimestamp)
: Calculates time-weighted ownership for an account over a given periodtotalOwnershipForPeriod(token, startTimestamp, endTimestamp)
: Calculates the total time-weighted ownership over a given periodcalculateOwnershipForPeriod(amount, periodStart, periodEnd)
: Helper function to calculate ownership weight asamount × (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:
- Interest Payment periods are created with specific start and end timestamps
- When tokens are claimed, the SnapshotPeriods contract calculates each account's proportional ownership during that period
- 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 callfrom
(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 addressaccount
(address): Account to querytimestamp
(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 addresstimestamp
(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 addressaccount
(address): Account to querytimestamp
(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 addresstimestamp
(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 addressaccount
(address): Account to querystartTimestamp
(uint256): Period start timestampendTimestamp
(uint256): Period end timestamp
Returns:
uint256
: Time-weighted ownership for the period (amount × duration)
Requirements:
startTimestamp
must be less thanendTimestamp
totalOwnershipForPeriod(address token, uint256 startTimestamp, uint256 endTimestamp) → uint256
Calculates total time-weighted ownership over a specific period.
Parameters:
token
(address): Token contract addressstartTimestamp
(uint256): Period start timestampendTimestamp
(uint256): Period end timestamp
Returns:
uint256
: Total time-weighted ownership for the period
Requirements:
startTimestamp
must be less thanendTimestamp
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 amountperiodStart
(uint256): Period start timestampperiodEnd
(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 addressaccount
(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 addressaccount
(address): Account to queryindex
(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 addressindex
(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 addressaccount
(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 addressaccount
(address): Account to queryindex
(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 addressindex
(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 addressaccount
(address): Account to querytimestamp
(uint256): Timestamp to search for
Returns:
uint256
: Period index, ortype(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 addresstimestamp
(uint256): Timestamp to search for
Returns:
uint256
: Period index, ortype(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 addressaccount
(address): Account to query
Returns:
uint256
: Latest accrual timestampuint256
: Total accrued ownershipuint256
: 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 timestampuint256
: Total accrued ownershipuint256
: 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 addressaccount
(address): Account to queryindex
(uint256): Period index
Returns:
uint256
: Period start timestampuint256
: Period end timestampuint256
: Total accrued ownershipuint256
: 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 addressindex
(uint256): Period index
Returns:
uint256
: Period start timestampuint256
: Period end timestampuint256
: Total accrued ownershipuint256
: 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.