Latent Fungible Token
Abstract
The following standard is an extension of EIP-20 that enables tokens to become fungible after some initial non-fungible period. Once minted, tokens are non-fungible until they reach maturity. At maturity, they become fungible and can be transferred, traded, and used in any way that a standard EIP-20 token can be used.
Motivation
Example use cases include:
- Receipt tokens that do not become active until a certain date or condition is met. For example, this can be used to enforce minimum deposit durations in lending protocols.
- Vesting tokens that cannot be transferred or used until the vesting period has elapsed.
Specification
All latent fungible tokens MUST implement EIP-20 to represent the token.
The balanceOf
and totalSupply
return quantities for all tokens, not just the matured, fungible tokens.
A new method called balanceOfMatured
MUST be added to the ABI.
This method returns the balance of matured tokens for a given address:
function balanceOfMatured(address user) external view returns (uint256);
An additional method called getMints
MUST be added, which returns an array of all mint metadata for a given address:
struct MintMetadata {
// Amount of tokens minted.
uint256 amount;
// Timestamp of the mint, in seconds.
uint256 time;
// Delay in seconds until these tokens mature and become fungible. When the
// delay is not known (e.g. if it's dependent on other factors aside from
// simply elapsed time), this value must be `type(uint256).max`.
uint256 delay;
}
function getMints(address user) external view returns (MintMetadata[] memory);
Note that the implementation does not require that each of the above metadata parameters are stored as a uint256
, just that they are returned as uint256
.
An additional method called mints
MAY be added.
This method returns the metadata for a mint based on its ID:
function mints(address user, uint256 id) external view returns (MintMetadata memory);
The ID is not prescriptive—it may be an index in an array, or may be generated by other means.
The transfer
and transferFrom
methods MAY be modified to revert when transferring tokens that have not matured.
Similarly, any methods that burn tokens MAY be modified to revert when burning tokens that have not matured.
All latent fungible tokens MUST implement EIP-20’s optional metadata extensions.
The name
and symbol
functions MUST reflect the underlying token’s name
and symbol
in some way.
Rationale
The mints
method is optional because the ID is optional. In some use cases such as vesting where a user may have a maximum of one mint, an ID is not required.
Similarly, vesting use cases may want to enforce non-transferrable tokens until maturity, whereas lending receipt tokens with a minimum deposit duration may want to support transfers at all times.
It is possible that the number of mints held by a user is so large that it is impractical to return all of them in a single eth_call
.
This is unlikely so it was not included in the spec.
If this is likely for a given use case, the implementer may choose to implement an alternative method that returns a subset of the mints, such as getMints(address user, uint256 startId, uint256 endId)
.
However, if IDs are not sequential, a different signature may be required, and therefore this was not included in the specification.
Backwards Compatibility
This proposal is fully backward compatible with the EIP-20 standard and has no known compatibility issues with other standards.
Security Considerations
Iterating over large arrays of mints is not recommended, as this is very expensive and may cause the protocol, or just a user’s interactions with it, to be stuck if this exceeds the block gas limit and reverts. There are some ways to mitigate this, with specifics dependent on the implementation.
Copyright
Copyright and related rights waived via CC0.