HomeEIPs
EIPsERC-7444
ERC-7444

Time Locks Maturity

Interface for conveying the date upon which a time-locked system becomes unlocked
DraftStandards Track: ERC
Created: 2023-06-05
Requires: EIP-165
Thanh Trinh (@thanhtrinh2003) <thanh@revest.finance>, Joshua Weintraub (@jhweintraub) <josh@revest.finance>, Rob Montgomery (@RobAnon) <rob@revest.finance>
DiscussionsOriginal linkEdit
1 min read
Anyone may contribute to propose contents.
Go propose
Video
Anyone may contribute to propose contents.
Go propose
Original

Abstract

This EIP defines a standardized method to communicate the date on which a time-locked system will become unlocked. This allows for the determination of maturities for a wide variety of asset classes and increases the ease with which these assets may be valued.

Motivation

Time-locks are ubiquitous, yet no standard on how to determine the date upon which they unlock exists. Time-locked assets experience theta-decay, where the time remaining until they become unlocked dictates their value. Providing a universal standard to view what date they mature on allows for improved on-chain valuations of the rights to these illiquid assets, particularly useful in cases where the rights to these illiquid assets may be passed between owners through semi-liquid assets such as ERC-721 or ERC-1155.

Specification

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.

Every ERC-7444 compliant contract must implement ERC-165 interface detection

// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.0; interface ERC-7444 { / * @notice This function returns the timestamp that the time lock specified by `id` unlocks at * @param id The identifier which describes a specific time lock * @return maturity The timestamp of the time lock when it unlocks */ function getMaturity(bytes32 id) external view returns (uint256 maturity); }

The maturity return parameter should be implemented in the Unix timestamp standard, which has been used widely in solidity. For example, block.timestamp represents the Unix timestamp when a block is mined in 256-bit value.

For singleton implementations on fungible assets, values passed to id SHOULD be ignored, and queries to such implementations should pass in 0x0

Rationale

Universal Maturities on Locked Assets

Locked Assets have become increasingly popular and used in different parts of defi, such as yield farming and vested escrow concept. This has increased the need to formalize and define an universal interface for all these timelocked assets.

Valuation of Locked Assets via the Black-Scholes Model

Locked Assets cannot be valued normally since the value of these assets can be varied through time and many other different factors throughout the locking time. For instance, The Black-Scholes Model or Black-Scholes-Merton model is an example of a suitable model to estimate the theoretical value of asset with the consideration of impact of time and other potential risks.

Black-Sholes Model

  • $C=\text{call option price}$
  • $N=\text{CDF of the normal distribution}$
  • $S_t=\text{spot price of an asset}$
  • $K=\text{strike price}$
  • $r=\text{risk-free interest rate}$
  • $t=\text{time to maturity}$
  • $\sigma=\text{volatility of the asset}$

Time to maturity plays an important role in evaluating the price of timelocked assets, thus the demand to have a common interface for retrieving the data is inevitable.

Backwards Compatibility

This standard can be implemented as an extension to ERC-721 and/or ERC-1155 tokens with time-locked functionality, many of which can be retrofitted with a designated contract to determine the point at which their time locks release.

Reference Implementation

Locked ERC-20 implementation

// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract LockedERC20ExampleContract implements ERC-7444{ ERC20 public immutable token; uint256 public totalLocked; //Timelock struct struct TimeLock { address owner; uint256 amount; uint256 maturity; bytes32 lockId; } //maps lockId to balance of the lock mapping(bytes32 => TimeLock) public idToLock; function constructor( address _token, ) public { token = ERC20(_token); } //Maturity is not appropriate error LockPeriodOngoing(); error InvalidReceiver(); error TransferFailed(); /// @dev Deposit tokens to be locked in the requested locking period /// @param amount The amount of tokens to deposit /// @param lockingPeriod length of locking period for the tokens to be locked function deposit(uint256 amount, uint256 lockingPeriod) external returns (bytes32 lockId) { uint256 maturity = block.timestamp + lockingPeriod; lockId = keccack256(abi.encode(msg.sender, amount, maturity)); require(idToLock[lockId].maturity == 0, "lock already exists"); if (!token.transferFrom(msg.sender, address(this), amount)) { revert TransferFailed(); } TimeLock memory newLock = TimeLock(msg.sender, amount, maturity, lockedId); totalLocked += amount; idToLock[lockId] = newLock; } /// @dev Withdraw tokens in the lock after the end of the locking period /// @param lockId id of the lock that user have deposited in function withdraw(bytes32 lockId) external { TimeLock memory lock = idToLock[lockId]; if (msg.sender != lock.owner) { revert InvalidReceiver(); } if (block.timestamp > lock.maturity) { revert LockPeriodOngoing(); } totalLocked -= lock.amount; //State cleanup delete idToLock[lockId]; if (!token.transfer(msg.sender, lock.amount)) { revert TransferFailed(); } } function getMaturity(bytes32 id) external view returns (uint256 maturity) { return idToLock[id].maturity; } }

Security Considerations

Extendable Time Locks

Users or developers should be aware of potential extendable timelocks, where the returned timestamp can be modified through protocols. Users or protocols should check the timestamp carefully before trading or lending with others.

Copyright and related rights waived via CC0.

Further reading
Anyone may contribute to propose contents.
Go propose
Adopted by projects
Anyone may contribute to propose contents.
Go propose

Not miss a beat of EIPs' update?

Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.

View all
Serve Ethereum Builders, Scale the Community.
Resources
GitHub
Supported by