| eip | title | description | author | discussions-to | status | type | category | created | requires |
|---|---|---|---|---|---|---|---|---|---|
8054 |
Forkable ERC-20 Token |
Checkpoint-based ERC-20 tokens that can be efficiently forked to distribute new tokens to existing holders. |
Kevin (@kevzzsk), Fuxing (@fuxingloh) |
Draft |
Standards Track |
ERC |
2025-10-10 |
20 |
This standard extends ERC-20 to enable efficient token forking through checkpoint-based balance tracking. A forkable ERC-20 token records balance snapshots at each state change. A forked ERC-20 token inherits all balances from a specific checkpoint in the source token, allowing instant, gas-free distribution to holders without airdrops or claiming mechanisms.
Current methods for distributing new tokens based on existing ERC-20 token balances are inefficient:
- Manual airdrops: Taking snapshots and transferring tokens to each holder individually is expensive and gas-intensive.
- Merkle-based claims: While cheaper for deployers, this approach requires users to pay gas fees to claim tokens and provides poor UX due to claimer needing to provide proofs.
Both approaches are inefficient as they rely on off-chain data construction outside the protocol's trust domain, introducing potential inconsistencies and allowing for collusion within the Merkle structure.
This EIP proposes a standard for forkable ERC-20 tokens that:
- Enable zero-gas distribution to token holders
- Eliminate manual claiming processes
- Provide verifiable on-chain balance inheritance
- Maintain full ERC-20 compatibility
By implementing checkpointed balances, tokens can be efficiently forked at any historical point, with new token balances automatically derived from the source token without any state duplication or expensive operations.
Airdrops are a common use case for forkable tokens. Without forkable ERC-20 tokens, manual snapshotting and merkle root creation are required. Then users must manually claim the new ERC-20 token costing gas borne by the claimer.
With forkable ERC-20 tokens, users do not have to claim the new ERC-20 token. The forked ERC-20 token is automatically transferred (via inheritance) to the users who have positive balance at the fork point.
ERC-4626 is a popular standard for yield-bearing vaults that manage an underlying ERC-20 asset. Risk and yield are commonly rebased on the same underlying asset, and this works very well for single-dimensional yield and risk (Liquid PoS ETH).
However, for multidimensional yield and risk vaults, the underlying asset may be used for different yield-generating purposes each with their own risk profile. Forkable ERC-20 tokens allow for tokenization of risk and yield to its immediate beneficiaries. While this is not a foreign concept in the space, its implementation has so far been off-chain—with their own trust domain separate from the chain.
Protocol upgrades, tokenomics changes, or contract improvements often require migrating to a new token.
Without forkable ERC-20 tokens, migration requires complex processes:
- Taking manual snapshots of all holder balances
- Deploying the new token contract
- Either airdropping to all holders (expensive) or requiring users to manually claim their tokens via merkle proofs (poor UX)
With forkable ERC-20 tokens, migration becomes seamless:
- The new token is forked from the old token at a specific checkpoint
- All holder balances are automatically inherited from the checkpoint
- Users can immediately interact with the new token without claiming
- No gas costs for holders, no manual snapshot management required
Create governance tokens or voting power derivatives based on historical token holdings without affecting the original token's utility or requiring users to lock or migrate their holdings.
Distribute loyalty or reward tokens proportional to historical holdings or activity, tracked via checkpoints, without complex off-chain calculation and distribution logic.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Forkable ERC-20 tokens are ERC-20 compliant tokens that have their balances and total supply saved at every state-changing operation. Each checkpoint is associated with a monotonically increasing nonce.
All forkable ERC-20 tokens:
- MUST implement ERC-20
- MUST implement optional ERC-20 metadata that includes:
- name (string)
- symbol (string)
- decimals (uint8)
interface IERC20Checkpointed is IERC20, IERC20Metadata {
/**
* @dev Returns the amount of tokens in existence at specified checkpoint.
* @param checkpoint The checkpoint to get the total supply at.
*/
function totalSupplyAt(uint256 checkpoint) external view virtual returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account` at specified checkpoint.
* @param account The account to get the balance of.
* @param checkpoint The checkpoint to get the balance at.
*/
function balanceOfAt(address account, uint256 checkpoint) public view virtual returns (uint256);
/**
* @dev Returns the current checkpoint nonce.
*/
function checkpointNonce() external view returns (uint256);
}totalSupplyAt(checkpoint)MUST return the total supply of tokens at the specified checkpoint.balanceOfAt(account, checkpoint)MUST return the balance of tokens owned byaccountat the specified checkpoint.totalSupply()MUST return the latest checkpointed total supply of tokens.balanceOf(account)MUST return the latest checkpointed balance of token held by the account.- Any state changes (transfer, mint, burn) MUST push the latest checkpoint balances and total supply.
- Checkpoint nonces MUST be monotonically increasing.
- Querying a future checkpoint MUST revert.
Forked ERC-20 tokens are ERC-20 compliant tokens that are forked from a checkpointed token at a specific checkpoint nonce. They inherit all balances from that checkpoint.
All forked ERC-20 tokens:
- MUST implement ERC-20
- MUST implement optional ERC-20 metadata that includes:
name(string)symbol(string)decimals(uint8)
- MUST take as constructor (or initializer) inputs:
name(string) - The name of the forked tokensymbol(string) - The symbol of the forked tokencheckpointedNonce(uint256) - The checkpoint at which to forkcheckpointedToken(address) - The address of the source token implementingIERC20Checkpointed
- MUST set
decimalsequal to the source token’sdecimals. - checkpointed nonce supplied for the fork MUST be in the past or equal to the most recent checkpoint nonce.
- Initial
totalSupplyMUST equalIERC20Checkpointed(totalSupplyAt(checkpointedNonce)). - For any account A, the forked token’s initial balance MUST equal
IERC20Checkpointed(balanceOfAt(A, checkpointedNonce)). - MAY implement
IERC20Checkpointed, enabling recursive forking. - Allowances and nonces are NOT carried over, integrators should treat the fork as a fresh ERC-20 for approvals and permits.
- If the source token does not implement
IERC20Checkpointed, the fork mechanism is out-of-scope of this standard.
balanceOf(account)MUST returncheckpointedToken.balanceOfAt(account, checkpointedNonce)if no state changes have occurred for that account in the forked token since its creation.balanceOf(account)MUST return the forked token's own recorded balance if any state change has occurred for that account since the fork.balanceOf(account)MUST NOT query the source token for any checkpoint other thancheckpointedNonce.totalSupply()MUST accurately reflect state changes in the forked token, independent of the source token.- Any state changes MUST NOT affect the source token.
Checkpoints enable efficient point-in-time queries. By recording only when changes happens, the system maintains a compact, queryable history.
Checkpoints are also trustless and verifiable, albeit at higher gas cost for state updates.
Merkle trees introduce complexity and off-chain dependencies. They require users to provide proofs, which complicates UX and increases the risk of errors.
Merkle trees are also inefficient for continuous updates.
For forked tokens, querying balances from the source token only when needed (lazy loading) significantly reduces gas costs during fork creation and initial operations.
Using block numbers or timestamps as checkpoints can lead to vulnerability to reorgs and MEV attacks. On the fork block, transactions can be re-ordered to allow balance manipulation before the fork balance is finalized.
Using a monotonically increasing nonce (rather than block numbers or timestamps) ensures that the fork point is unambiguous and not susceptible to such manipulations. This is because each state update is recorded with a unique nonce, the fork can be precisely defined.
Forkable tokens MAY incur higher per-transaction costs due to checkpoint storage.
This trade-off could be acceptable for tokens where forkability provides significant value (airdrops, governance, migrations).
This EIP is fully backwards compatible with ERC-20. Forked tokens behave as standard ERC-20 tokens to any consumer. Forkable tokens add checkpoint functionality but maintain all ERC-20 behaviors.
Existing contracts and wallets that interact with ERC-20 tokens will work without modification with both forkable and forked tokens.
This repository provides a minimal reference:
├── contracts # Contains implementation contracts for ERC-8054
│ ├── ERC20Checkpointed.sol # Forkable ERC-20 with checkpointed balances and total supply.
│ ├── ERC20FC.sol # Forked Forkable ERC-20 token from a source token (recursive fork).
│ ├── ERC20Forked.sol # Forked ERC-20 token from a source token.
│ └── interfaces
│ └── IERC20Checkpointed.sol # Forkable ERC-20 interface.
└── tests
├── ERC20Checkpointed.t.sol
├── ERC20CheckpointedGas.t.sol
├── ERC20Forked.t.sol
└── ERC20ForkedGas.t.solNote: The reference implementation is provided for illustrative purposes. Production implementations should undergo thorough security audits.
Approvals are not inherited. When a token is forked, all allowances reset to zero. Users and dApps MUST re-approve spending for the forked token.
Tokens with non-standard behaviors (rebasing, fee-on-transfer, deflationary mechanisms) may not fork correctly:
- Rebasing tokens: Balance changes after the checkpoint may not be reflected in the fork
- Fee-on-transfer tokens: Forked balances will not account for fees incurred after the checkpoint
Auditors and integrators SHOULD carefully review source token mechanics before forking
Forked tokens MUST use the same decimals as the source token to prevent balance inconsistencies and loss of precision. Mismatched decimals MAY lead to incorrect balances and loss of precision.
Querying a future checkpoint MUST revert with an error. This prevents forking at a future checkpoint and ensures forked token balances remain consistent. Implementations MUST check that the requested checkpoint does not exceed the current checkpoint nonce.
Implementations should consider the implications of checkpoint nonce overflow when using a smaller uint type.
This work is made available under CC0-1.0. See LICENSE for repository licensing.