--- eip: 5744 title: Latent Fungible Token description: An interface for tokens that become fungible after a period of time. author: Cozy Finance (@cozyfinance), Tony Sheng (@tonysheng), Matt Solomon (@mds1), David Laprade (@davidlaprade), Payom Dousti (@payomdousti), Chad Fleming (@chad-js), Franz Chen (@Dendrimer) discussions-to: https://ethereum-magicians.org/t/eip-5744-latent-fungible-token/11111 status: Draft type: Standards Track category: ERC created: 2022-09-29 requires: 20, 2612 --- ## Abstract The following standard is an extension of [EIP-20](./eip-20.md) 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: ```solidity 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: ```solidity 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: ```solidity 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](../LICENSE.md).