Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TokenEphemeral

Git Source

Inherits: ContextUpgradeable

Author: EVMAuth

Implements time-based token expiration with automatic balance pruning.

Abstract contract providing TTL functionality for tokens with FIFO spending logic. Expired tokens are automatically excluded from balances and pruned for gas optimization. Uses EIP-7201 storage pattern for upgrade safety.

State Variables

DEFAULT_MAX_BALANCE_RECORDS

Default limit for balance records per account per token.

Can be overridden via _maxBalanceRecords() function.

uint256 public constant DEFAULT_MAX_BALANCE_RECORDS = 100;

TokenEphemeralStorageLocation

EIP-7201 storage slot for TokenEphemeral state.

Computed as: keccak256(abi.encode(uint256(keccak256("tokenephemeral.storage.TokenEphemeral")) - 1)) & ~bytes32(uint256(0xff)). Prevents storage collisions in upgradeable contracts.

bytes32 private constant TokenEphemeralStorageLocation =
    0xec3c1253ecdf88a29ff53024f0721fc3faa1b42abcff612deb5b22d1f94e2d00;

Functions

_getTokenEphemeralStorage

Retrieves the storage struct for TokenEphemeral.

Internal function using inline assembly for direct storage access.

function _getTokenEphemeralStorage() private pure returns (TokenEphemeralStorage storage $);

Returns

NameTypeDescription
$TokenEphemeralStorageStorage pointer to TokenEphemeralStorage struct

__TokenEphemeral_init

Internal initializer for TokenEphemeral setup.

Currently empty as no initialization needed.

function __TokenEphemeral_init() internal onlyInitializing;

__TokenEphemeral_init_unchained

Unchained initializer for contract-specific storage.

Currently empty but reserved for future initialization.

function __TokenEphemeral_init_unchained() internal onlyInitializing;

balanceOf

Gets current balance excluding expired tokens.

Iterates through balance records and sums non-expired amounts.

function balanceOf(address account, uint256 id) public view virtual returns (uint256);

Parameters

NameTypeDescription
accountaddressAddress to check balance for
iduint256Token type identifier

Returns

NameTypeDescription
<none>uint256Total non-expired balance

balanceRecordsOf

Retrieves all balance records for an account and token.

Returns raw records including expired ones.

function balanceRecordsOf(address account, uint256 id) external view returns (BalanceRecord[] memory);

Parameters

NameTypeDescription
accountaddressAddress to query
iduint256Token type identifier

Returns

NameTypeDescription
<none>BalanceRecord[]Array of balance records for the account/token pair

tokenTTL

Gets time-to-live configuration for a token type.

Returns TTL in seconds, 0 indicates permanent tokens.

function tokenTTL(uint256 id) public view virtual returns (uint256);

Parameters

NameTypeDescription
iduint256Token type identifier

Returns

NameTypeDescription
<none>uint256TTL in seconds (0 = no expiration)

pruneBalanceRecords

Removes expired and zero-balance records for gas optimization.

Public function for manual storage cleanup. Automatically called during transfers.

Note: emits: ExpiredTokensPruned if any tokens were pruned.

function pruneBalanceRecords(address account, uint256 id) public virtual;

Parameters

NameTypeDescription
accountaddressAddress to prune records for
iduint256Token type identifier

_burnPrunedTokens

Internal hook to handle burning of pruned tokens.

Override this function to integrate with the token standard's burn mechanism. Called automatically during pruning if expired tokens are found.

function _burnPrunedTokens(address account, uint256 id, uint256 amount) internal virtual;

Parameters

NameTypeDescription
accountaddressAddress from which tokens were pruned
iduint256Token type identifier
amountuint256Quantity of tokens that were pruned (expired)

_setTTL

Internal function to configure token TTL.

Sets expiration duration for new tokens of this type.

function _setTTL(uint256 id, uint256 ttlSeconds) internal virtual;

Parameters

NameTypeDescription
iduint256Token type identifier
ttlSecondsuint256Duration in seconds (0 = permanent)

_expiresAt

Calculates bucketed expiration timestamp for a token.

Rounds up to next time bucket to ensure minimum TTL guarantee. Bucketing prevents unbounded storage growth by limiting unique expiration times. Example: 30-day TTL with 100 max records creates 100 buckets of 25920 seconds (7.2 hours) each.

function _expiresAt(uint256 id) internal view returns (uint256);

Parameters

NameTypeDescription
iduint256Token type identifier

Returns

NameTypeDescription
<none>uint256Unix timestamp of expiration (type(uint256).max for permanent)

_maxBalanceRecords

Returns maximum balance records per account/token pair.

Limits storage to prevent DoS attacks. Override to customize. Affects expiration precision: actual expiry is anywhere from TTL to TTL + (TTL/maxRecords - 1) seconds.

function _maxBalanceRecords() internal view virtual returns (uint256);

Returns

NameTypeDescription
<none>uint256Maximum number of balance records (default: 100)

_updateBalanceRecords

Internal hook to update balance records on token transfers.

Handles minting, burning, and transfers with automatic pruning. Automatically prunes expired records before adding and/or after deducting balances.

function _updateBalanceRecords(address from, address to, uint256 id, uint256 amount) internal virtual;

Parameters

NameTypeDescription
fromaddressSource address (zero address for minting)
toaddressDestination address (zero address for burning)
iduint256Token type identifier
amountuint256Quantity transferred

_addToBalanceRecords

Internal function to add or update balance records.

Maintains chronological sorting and merges same-expiration records. In most cases, _updateBalanceRecords() should be called instead of calling this directly.

function _addToBalanceRecords(address account, uint256 id, uint256 amount, uint256 expiresAt) internal;

Parameters

NameTypeDescription
accountaddressAddress to update balance for
iduint256Token type identifier
amountuint256Quantity to add
expiresAtuint256Unix timestamp of expiration

_deductFromBalanceRecords

Internal function to deduct tokens using FIFO logic.

Consumes oldest tokens first, automatically prunes after deduction. In most cases, _updateBalanceRecords() should be called instead of calling this directly.

Note: throws: InsufficientBalance When account lacks sufficient non-expired balance

function _deductFromBalanceRecords(address account, uint256 id, uint256 amount) internal;

Parameters

NameTypeDescription
accountaddressAddress to deduct from
iduint256Token type identifier
amountuint256Quantity to deduct

_transferBalanceRecords

Internal function to transfer tokens preserving expiration.

Uses FIFO to transfer oldest tokens first, maintains expiration timestamps. In most cases, _updateBalanceRecords() should be called instead of calling this directly.

Note: throws: InsufficientBalance When sender lacks sufficient non-expired balance

function _transferBalanceRecords(address from, address to, uint256 id, uint256 amount) internal;

Parameters

NameTypeDescription
fromaddressSource address
toaddressDestination address
iduint256Token type identifier
amountuint256Quantity to transfer

Events

ExpiredTokensPruned

Emitted when pruned tokens are burned.

event ExpiredTokensPruned(address indexed from, uint256 indexed id, uint256 amount);

Parameters

NameTypeDescription
fromaddressAddress from which tokens were pruned
iduint256Token type identifier
amountuint256Quantity of tokens that were pruned (expired)

Errors

InsufficientBalance

Error for insufficient token balance.

error InsufficientBalance(address account, uint256 available, uint256 requested, uint256 id);

Parameters

NameTypeDescription
accountaddressAddress with insufficient balance.
availableuint256Current available balance
requesteduint256Amount requested
iduint256Token type identifier

Structs

BalanceRecord

Balance record with amount and expiration timestamp.

struct BalanceRecord {
    uint256 amount;
    uint256 expiresAt;
}

Properties

NameTypeDescription
amountuint256Token balance that expires
expiresAtuint256Unix timestamp of expiration (type(uint256).max for permanent)

TokenEphemeralStorage

Note: storage-location: erc7201:tokenephemeral.storage.TokenEphemeral

struct TokenEphemeralStorage {
    mapping(address account => mapping(uint256 id => BalanceRecord[])) balanceRecords;
    mapping(uint256 => uint256) ttls;
}