TokenEphemeral
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
Name | Type | Description |
---|---|---|
$ | TokenEphemeralStorage | Storage 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
Name | Type | Description |
---|---|---|
account | address | Address to check balance for |
id | uint256 | Token type identifier |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Total 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
Name | Type | Description |
---|---|---|
account | address | Address to query |
id | uint256 | Token type identifier |
Returns
Name | Type | Description |
---|---|---|
<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
Name | Type | Description |
---|---|---|
id | uint256 | Token type identifier |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | TTL 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
Name | Type | Description |
---|---|---|
account | address | Address to prune records for |
id | uint256 | Token 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
Name | Type | Description |
---|---|---|
account | address | Address from which tokens were pruned |
id | uint256 | Token type identifier |
amount | uint256 | Quantity 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
Name | Type | Description |
---|---|---|
id | uint256 | Token type identifier |
ttlSeconds | uint256 | Duration 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
Name | Type | Description |
---|---|---|
id | uint256 | Token type identifier |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Unix 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
Name | Type | Description |
---|---|---|
<none> | uint256 | Maximum 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
Name | Type | Description |
---|---|---|
from | address | Source address (zero address for minting) |
to | address | Destination address (zero address for burning) |
id | uint256 | Token type identifier |
amount | uint256 | Quantity 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
Name | Type | Description |
---|---|---|
account | address | Address to update balance for |
id | uint256 | Token type identifier |
amount | uint256 | Quantity to add |
expiresAt | uint256 | Unix 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
Name | Type | Description |
---|---|---|
account | address | Address to deduct from |
id | uint256 | Token type identifier |
amount | uint256 | Quantity 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
Name | Type | Description |
---|---|---|
from | address | Source address |
to | address | Destination address |
id | uint256 | Token type identifier |
amount | uint256 | Quantity to transfer |
Events
ExpiredTokensPruned
Emitted when pruned tokens are burned.
event ExpiredTokensPruned(address indexed from, uint256 indexed id, uint256 amount);
Parameters
Name | Type | Description |
---|---|---|
from | address | Address from which tokens were pruned |
id | uint256 | Token type identifier |
amount | uint256 | Quantity of tokens that were pruned (expired) |
Errors
InsufficientBalance
Error for insufficient token balance.
error InsufficientBalance(address account, uint256 available, uint256 requested, uint256 id);
Parameters
Name | Type | Description |
---|---|---|
account | address | Address with insufficient balance. |
available | uint256 | Current available balance |
requested | uint256 | Amount requested |
id | uint256 | Token type identifier |
Structs
BalanceRecord
Balance record with amount and expiration timestamp.
struct BalanceRecord {
uint256 amount;
uint256 expiresAt;
}
Properties
Name | Type | Description |
---|---|---|
amount | uint256 | Token balance that expires |
expiresAt | uint256 | Unix 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;
}