|
| 1 | +--- |
| 2 | +eip: 7818 |
| 3 | +title: Expirable ERC-20 |
| 4 | +description: An ERC-20 extension for creating fungible tokens with expiration, supporting time-limited use cases. |
| 5 | +author: sirawt (@MASDXI), ADISAKBOONMARK (@ADISAKBOONMARK) |
| 6 | +discussions-to: https://ethereum-magicians.org/t/erc-7818-expirable-erc20/21655 |
| 7 | +status: Draft |
| 8 | +type: Standards Track |
| 9 | +category: ERC |
| 10 | +created: 2024-11-13 |
| 11 | +requires: 20 |
| 12 | +--- |
| 13 | + |
| 14 | +## Abstract |
| 15 | + |
| 16 | +Introduces an extension for [ERC-20](./eip-20.md) tokens, which facilitates the implementation of an expiration mechanism. Through this extension, tokens have a predetermined validity period, after which they become invalid and can no longer be transferred or used. This functionality proves beneficial in scenarios such as time-limited bonds, loyalty rewards, or game tokens necessitating automatic invalidation after a specific duration. The extension is crafted to seamlessly align with the existing [ERC-20](./eip-20.md) standard, ensuring smooth integration with the prevailing token smart contract while introducing the capability to govern and enforce token expiration at the contract level. |
| 17 | + |
| 18 | +## Motivation |
| 19 | + |
| 20 | +This extension facilitates the development of [ERC-20](./eip-20.md) standard compatible tokens featuring expiration dates. This capability broadens the scope of potential applications, particularly those involving time-sensitive assets. Expirable tokens are well-suited for scenarios necessitating temporary validity, including |
| 21 | + |
| 22 | +- Bonds or financial instruments with defined maturity dates |
| 23 | +- Time-constrained assets within gaming ecosystems |
| 24 | +- Next-gen loyalty programs incorporating expiring rewards or points |
| 25 | +- Prepaid credits for utilities or services (e.g., cashback, data packages, fuel, computing resources) that expire if not used within a specified time frame |
| 26 | +- Postpaid telecom data package allocations that expire at the end of the billing cycle, motivating users to utilize their data before it resets |
| 27 | +- Tokenized e-Money for a closed-loop ecosystem, such as transportation, food court, and retail payments |
| 28 | + |
| 29 | +## Specification |
| 30 | + |
| 31 | +The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. |
| 32 | + |
| 33 | +Compatible implementations MUST inherit from [ERC-20](./eip-20.md)'s interface and **MUST** have all the following functions and all function behavior **MUST** meet the specification. |
| 34 | + |
| 35 | +```solidity |
| 36 | +// SPDX-License-Identifier: CC0-1.0 |
| 37 | +pragma solidity >=0.8.0 <0.9.0; |
| 38 | +
|
| 39 | +/** |
| 40 | + * @title ERC-7818: Expirable ERC20 |
| 41 | + * @dev Interface for creating expirable ERC20 tokens. |
| 42 | + */ |
| 43 | +
|
| 44 | +import "./IERC20.sol"; |
| 45 | +
|
| 46 | +interface IERC7818 is IERC20 { |
| 47 | +
|
| 48 | + /** |
| 49 | + * @dev Retrieves the balance of a specific `epoch` owned by an account. |
| 50 | + * @param account The address of the account. |
| 51 | + * @param epoch "MAY" represents an epoch, round, or period. |
| 52 | + * @return uint256 The balance of the specified `epoch`. |
| 53 | + * @notice `epoch` "MUST" represent a unique identifier, and its meaning "SHOULD" |
| 54 | + * align with how contract maintain the `epoch` in the implementing contract. |
| 55 | + */ |
| 56 | + function balanceOf( |
| 57 | + address account, |
| 58 | + uint256 epoch |
| 59 | + ) external view returns (uint256); |
| 60 | +
|
| 61 | + /** |
| 62 | + * @dev Retrieves the current epoch of the contract. |
| 63 | + * @return uint256 The current epoch of the token contract, |
| 64 | + * often used for determining active/expired states. |
| 65 | + */ |
| 66 | + function epoch() external view returns (uint256); |
| 67 | +
|
| 68 | + /** |
| 69 | + * @dev Retrieves the duration a token remains valid. |
| 70 | + * @return uint256 The validity duration. |
| 71 | + * @notice `duration` "MUST" specify the token's validity period. |
| 72 | + * The implementing contract "SHOULD" clearly document, |
| 73 | + * whether the unit is blocks or time in seconds. |
| 74 | + */ |
| 75 | + function duration() external view returns (uint256); |
| 76 | +
|
| 77 | + /** |
| 78 | + * @dev Checks whether a specific `epoch` is expired. |
| 79 | + * @param epoch "MAY" represents an epoch, round, or period. |
| 80 | + * @return bool True if the token is expired, false otherwise. |
| 81 | + * @notice Implementing contracts "MUST" define the logic for determining expiration, |
| 82 | + * typically by comparing the current `epoch()` with the given `epoch`. |
| 83 | + */ |
| 84 | + function expired(uint256 epoch) external view returns (bool); |
| 85 | +
|
| 86 | + /** |
| 87 | + * @dev Transfers a specific `epoch` and value to a recipient. |
| 88 | + * @param to The recipient address. |
| 89 | + * @param epoch "MAY" represents an epoch, round, or period. |
| 90 | + * @param value The amount to transfer. |
| 91 | + * @return bool True if the transfer succeeded, false or reverted if give `epoch` it's expired. |
| 92 | + * @notice The transfer "MUST" revert if the token `epoch` is expired. |
| 93 | + */ |
| 94 | + function transfer( |
| 95 | + address to, |
| 96 | + uint256 epoch, |
| 97 | + uint256 value |
| 98 | + ) external returns (bool); |
| 99 | +
|
| 100 | + /** |
| 101 | + * @dev Transfers a specific `epoch` and value from one account to another. |
| 102 | + * @param from The sender's address. |
| 103 | + * @param to The recipient's address. |
| 104 | + * @param epoch "MAY" represents an epoch, round, or period. |
| 105 | + * @param value The amount to transfer. |
| 106 | + * @return bool True if the transfer succeeded, false or reverted if give `epoch` it's expired. |
| 107 | + * @notice The transfer "MUST" revert if the token `epoch` is expired. |
| 108 | + */ |
| 109 | + function transferFrom( |
| 110 | + address from, |
| 111 | + address to, |
| 112 | + uint256 epoch, |
| 113 | + uint256 value |
| 114 | + ) external returns (bool); |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | +### Behavior specification |
| 119 | + |
| 120 | +- `balanceOf` **MUST** return the total balance of tokens held by an account that are still valid (i.e., have not expired). This includes any tokens associated with specific periods, epochs, or other identifiers, provided they remain within their validity duration. Expired tokens **MUST NOT** be included in the returned balance, ensuring that only actively usable tokens are reflected in the result. |
| 121 | +- `transfer` and `transferFrom` **MUST** exclusively transfer tokens that remain non-expired at the time of the transaction. Attempting to transfer expired tokens **MUST** revert the transaction or return false. Additionally, implementations **MAY** include logic to prioritize the automatic transfer of tokens closest to expiration, ensuring that the earliest expiring tokens are used first, provided they meet the non-expired condition. |
| 122 | +- `totalSupply` **SHOULD** be set to `0` or `type(uint256).max` due to the challenges of tracking only valid (non-expired) tokens. |
| 123 | +- The implementation **MAY** use a standardized custom error revert message, such as `ERC7818TransferredExpiredToken` or `ERC7818TransferredExpiredToken(address sender, uint256 epoch)`, to clearly indicate that the operation failed due to attempting to transfer expired tokens. |
| 124 | + |
| 125 | +## Rationale |
| 126 | + |
| 127 | +The rationale for developing an expirable [ERC-20](./eip-20.md) token extension is based on several key requirements that ensure its practicality and adaptability for various applications to |
| 128 | + |
| 129 | +### Compatibility with the existing [ERC-20](./eip-20.md) standard. |
| 130 | +The extension should integrate smoothly with the [ERC-20](./eip-20.md) interface, This ensures compatibility with existing token ecosystems and third-party tools like wallets and blockchain explorers. |
| 131 | + |
| 132 | +### Flexible interface for various implementation. |
| 133 | +The smart contract should be extensible, allowing businesses to tailor the expiration functionality to their specific needs like expiry in bulk or each token independent expire, whether it’s dynamic reward systems or time-sensitive applications. |
| 134 | + |
| 135 | +## Backwards Compatibility |
| 136 | + |
| 137 | +This standard is fully [ERC-20](./eip-20.md) compatible. |
| 138 | + |
| 139 | +## Reference Implementation |
| 140 | + |
| 141 | +For reference implementation can be found [here](../assets/eip-7818/README.md), But in the reference implementation, we employ a sorted list to automatically select the token that nearest expires first with a First-In-First-Out (`FIFO`) and sliding window algorithm that operates based on the `block.number` as opposed to relying on `block.timestamp`, which has been criticized for its lack of security and resilience, particularly given the increasing usage of Layer 2 (L2) networks over Layer 1 (L1) networks. Many L2 networks exhibit centralization and instability, which directly impacts asset integrity, rendering them potentially unusable during periods of network halting, as they are still reliant on the timestamp. |
| 142 | + |
| 143 | +## Security Considerations |
| 144 | + |
| 145 | +### Denial Of Service |
| 146 | +Run out of gas problem due to the operation consuming higher gas if transferring multiple groups of small tokens or loop transfer. |
| 147 | + |
| 148 | +### Gas Limit Vulnerabilities |
| 149 | +Exceeds block gas limit if the blockchain has a block gas limit lower than the gas used in the transaction. |
| 150 | + |
| 151 | +### Block values as a proxy for time |
| 152 | +if using `block.timestamp` for calculating `epoch()` and In rare network halts, block production stops, freezing `block.timestamp` and disrupting time-based logic. This risks asset integrity and inconsistent states. |
| 153 | + |
| 154 | +### Fairness Concerns |
| 155 | +In a straightforward implementation, where all tokens within the same epoch share the same expiration (e.g., at `epoch`:`x`), bulk expiration occurs. |
| 156 | + |
| 157 | +### Risks in Liquidity Pools |
| 158 | +When tokens with expiration dates are deposited into liquidity pools (e.g., in DEXs), they may expire while still in the pool. |
| 159 | + |
| 160 | +## Copyright |
| 161 | + |
| 162 | +Copyright and related rights waived via [CC0](../LICENSE.md). |
0 commit comments