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:
An additional method called getMints MUST be added, which returns an array of all mint metadata for a given address:
structMintMetadata{// Amount of tokens minted.
uint256amount;// Timestamp of the mint, in seconds.
uint256time;// 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`.
uint256delay;}functiongetMints(addressuser)externalviewreturns(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:
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.