Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP-5058:Lockable ERC-721 Standard #5058

Merged
merged 48 commits into from
Aug 25, 2022
Merged
Changes from 2 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
72cafb2
EIP-5058:Lockable ERC-721 Standard
radiocaca Apr 29, 2022
4696368
update eip
radiocaca May 1, 2022
49c31ff
Update eip-5058.md
radiocaca May 4, 2022
6b21dd1
Update eip-5058.md proposal language
sfumato00 May 10, 2022
1e4c9a0
Update eip-5058.md proposal language
sfumato00 May 10, 2022
47a04f3
Merge pull request #1 from sfumato00/master
radiocaca May 10, 2022
1e5f664
Update eip-5058.md
radiocaca May 10, 2022
fa18ed6
Update eip-5058.md
radiocaca May 10, 2022
a49ef35
upload example
radiocaca May 11, 2022
07f7fe6
Update assets/eip-5058/factory/IERC721Bound.sol
radiocaca May 11, 2022
456c60e
Update assets/eip-5058/ERC721Lockable.sol
radiocaca May 11, 2022
cdbe439
Update assets/eip-5058/IERC721Lockable.sol
radiocaca May 11, 2022
2a7e737
Update assets/eip-5058/factory/IEIP5058Factory.sol
radiocaca May 11, 2022
fcd52e2
Update assets/eip-5058/factory/ERC721Bound.sol
radiocaca May 11, 2022
5415e9c
Update assets/eip-5058/factory/EIP5058Factory.sol
radiocaca May 11, 2022
2c29f8c
Update assets/eip-5058/extensions/EIP5058Bound.sol
radiocaca May 11, 2022
82b6584
rename to ERC5058
radiocaca May 11, 2022
9676777
update revert domain
radiocaca May 11, 2022
9002b06
Update EIPS/eip-5058.md
radiocaca May 13, 2022
06d1955
Update EIPS/eip-5058.md
radiocaca May 17, 2022
38c75b8
Update EIPS/eip-5058.md
radiocaca May 17, 2022
135a48b
remove all external links and add lockExpiredTime function
radiocaca Jul 31, 2022
df1c064
add tests
radiocaca Jul 31, 2022
9999772
rename from to owner
radiocaca Jul 31, 2022
9610e08
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
ba9ebea
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
552e313
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
e5f1160
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
3f3d037
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
9d3980a
Update assets/eip-5058/IERC5058.sol
radiocaca Aug 3, 2022
286289b
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
eb1fc00
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
724e277
Update EIPS/eip-5058.md
radiocaca Aug 3, 2022
4810780
Apply suggestions from code review
radiocaca Aug 3, 2022
051e456
Apply suggestions from code review
radiocaca Aug 3, 2022
9a95d53
fix lockFrom
radiocaca Aug 3, 2022
21731b2
update md
radiocaca Aug 3, 2022
adaad9e
fix lockFrom tests
radiocaca Aug 3, 2022
0c6ee82
remove oz deps
radiocaca Aug 14, 2022
2a29457
modify md for eip change
radiocaca Aug 15, 2022
18afdec
refine tests
radiocaca Aug 17, 2022
ade97bf
Merge branch 'master' into master
radiocaca Aug 18, 2022
c0dce9b
Merge branch 'master' into master
radiocaca Aug 18, 2022
d68547a
Merge branch 'master' into master
radiocaca Aug 18, 2022
08db345
Merge branch 'master' into master
radiocaca Aug 19, 2022
2cec9fa
Merge branch 'master' into master
radiocaca Aug 22, 2022
e822eeb
Merge branch 'master' into master
radiocaca Aug 25, 2022
78f8908
Merge branch 'master' into master
Pandapip1 Aug 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions EIPS/eip-5058.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
eip: 5058
title: Lockable ERC-721 Standard
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
description: Lockable ERC-721 can be uesed for locking, staking, lending, crowdfunding, etc.
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
author: Tyler(@radiocaca), Alex(@gojazdev)
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
discussions-to: <URL>
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
status: Draft
type: Standards Track
category: ERC
created: 2022-04-30
requires (*optional): 165,721
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
---

## Abstract
A secure locking standard for non-fungible tokens (NFTs). The NFT owner approve the operator to lock the NFT through `setLockApprovalForAll()` or `lockApprove()`. The apporved operator locks the NFT through `lockFrom`. The locked NFT cannot be transferred until the end of the lock period. NFTs that implement this standard can participate in NFTFi projects that are compatible with this protocol without leaving the owner's wallet.
radiocaca marked this conversation as resolved.
Show resolved Hide resolved

## Motivation
With the continuous development of the NFT ecosystem, the market value of NFTs is growing, and more and more blue-chip NFTs have appeared in the market. The problem of poor liquidity of NFTs has become increasingly prominent. Many projects have also introduced solutions to solve the liquidity of NFTs, such as: [NFTFi](https://www.nftfi.com/), [BendDAO](https://www.benddao.xyz/), etc., based on the current ERC-721 protocol standard, when users use these projects, they must transfer their NFTs to the project contract. This behavior has huge risks:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
With the continuous development of the NFT ecosystem, the market value of NFTs is growing, and more and more blue-chip NFTs have appeared in the market. The problem of poor liquidity of NFTs has become increasingly prominent. Many projects have also introduced solutions to solve the liquidity of NFTs, such as: [NFTFi](https://www.nftfi.com/), [BendDAO](https://www.benddao.xyz/), etc., based on the current ERC-721 protocol standard, when users use these projects, they must transfer their NFTs to the project contract. This behavior has huge risks:
With the continuous development of the NFT ecosystem, the market value of NFTs is growing, and more and more blue-chip NFTs have appeared in the market. The problem of poor liquidity of NFTs has become increasingly prominent. Many projects have also introduced solutions to solve the liquidity of NFTs, such as NFTFi and BendDAO, based on the current [EIP-721](./EIP-721.md) protocol standard. However, when users use these projects, they must transfer their NFTs to the project contract. This has risks:

No eternal links, ERCs are to be mentioned in-text as EIPs, link to the EIP, changed wording.


1. Potential bugs in NFTFi project contracts may lead to loss of users' NFTs
2. NFT has its use value, such as being used as PFP, when the user wallet does not own the NFT after mortgage, the use value of NFT is limited.
3. Many NFTs have airdrops. When NFTs are pledged, users cannot directly receive airdrops, which brings huge losses to users.

This standard perfectly solves the problems caused by the lack of the above [ERC-721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) standard:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This standard perfectly solves the problems caused by the lack of the above [ERC-721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) standard:
This standard solves the aforementioned problems with the [EIP-721](./EIP-721.md) standard:

Change link to be relative, change wording.


1. Compared with transferring the NFT to the project contract, it is more secure and guarantees the user's ownership of the NFT. Unless sold and transferred, in any other scenario, the NFT can participate and can be kept in the user's wallet.
2. When the NFT is locked, it just cannot be transferred, it does not affect the use of the NFT, and the various rights and uses brought by the NFT can be enjoyed without distinction.
3. The NFT is always kept in the user's wallet. Even if the NFT is locked due to participating in the pledge, the NFT airdrop can still be claimed directly.

This standard manages the control of NFTs in a safer and more convenient way, enabling NFTs to natively support NFTFi activities such as locking, staking, lending, crowdfunding, etc., which will encourage NFT holders to participate more actively in NFTFi projects, indirectly Solve the value liquidity of NFT.

## Specification
The key words “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.

Lockable ERC-721 **MUST** implement the `IERC721Lockable` interfaces:
```solidity
// SPDX-License-Identifier: MIT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: CC0-1.0

This MUST be CC0

// Creator: [email protected]

pragma solidity ^0.8.8;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
radiocaca marked this conversation as resolved.
Show resolved Hide resolved

/**
* @dev ERC-721 Non-Fungible Token Standard, optional lockable extension
* ERC721 Token that can be locked for a certain period and cannot be transferred.
* This is designed for a non-escrow staking contract that comes later to lock a user's NFT
* while still letting them keep it in their wallet.
* This extension can ensure the security of user tokens during the staking period.
* If the nft lending protocol is compatible with this extension, the trouble caused by the NFT
* airdrop can be avoided, because the airdrop is still in the user's wallet
*/
interface IERC721Lockable is IERC165 {
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
/**
* @dev Emitted when `tokenId` token is locked from `from`.
*/
event Locked(address indexed operator, address indexed from, uint256 indexed tokenId, uint256 expired);

/**
* @dev Emitted when `tokenId` token is unlocked from `from`.
*/
event Unlocked(address indexed operator, address indexed from, uint256 indexed tokenId);

/**
* @dev Emitted when `owner` enables `approved` to lock the `tokenId` token.
*/
event LockApproval(address indexed owner, address indexed approved, uint256 indexed tokenId);

/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to lock all of its tokens.
*/
event LockApprovalForAll(address indexed owner, address indexed operator, bool approved);

/**
* @dev Returns the current locker of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function lockerOf(uint256 tokenId) external view returns (address locker);

/**
* @dev Lock `tokenId` token until `expired` from `from`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - `expired` must be greater than block.timestamp
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
* - If the caller is not `from`, it must be approved to lock this token
* by either {lockApprove} or {setLockApprovalForAll}.
*
* Emits a {Locked} event.
*/
function lockFrom(
address from,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
address from,
address owner,

uint256 tokenId,
uint256 expired
) external;

/**
* @dev Unlock `tokenId` token until `expired` from `from`.
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - the caller must be the operator who locks the token by {lockFrom}
*
* Emits a {Unlocked} event.
*/
function unlockFrom(address from, uint256 tokenId) external;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems we don't have this implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also I wanted to know whether from is also needed to change owner or not.


/**
* @dev Gives permission to `to` to lock `tokenId` token.
*
* Requirements:
*
* - The caller must own the token or be an approved lock operator.
* - `tokenId` must exist.
*
* Emits an {LockApproval} event.
*/
function lockApprove(address to, uint256 tokenId) external;
radiocaca marked this conversation as resolved.
Show resolved Hide resolved

/**
* @dev Approve or remove `operator` as an lock operator for the caller.
* Operators can call {lockFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {LockApprovalForAll} event.
*/
function setLockApprovalForAll(address operator, bool _approved) external;

/**
* @dev Returns the account lock approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getLockApproved(uint256 tokenId) external view returns (address operator);

/**
* @dev Returns if the `operator` is allowed to lock all of the assets of `owner`.
*
* See {setLockApprovalForAll}
*/
function isLockApprovedForAll(address owner, address operator) external view returns (bool);

/**
* @dev Returns if the `tokenId` token is locked.
*/
function isLocked(uint256 tokenId) external view returns (bool);
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
}

```

## Rationale

### NFT lock approvals
The NFT owner can give another trusted operator the right to lock his NFT through the approve function. The `lockApprove()` function only approve the specified NFT, and `setLockApprovalForAll()` approve all NFTs of the collection under the user wallet. When a user participates in NFTFi, the NFTFi project contract calls `lockFrom()` to lock the user's NFT.Locked NFT will not be able to be transferred, the NFTFi project contract can also use the unlock function (`unlockFrom()`) to unlock the NFT.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The NFT owner can give another trusted operator the right to lock his NFT through the approve function. The `lockApprove()` function only approve the specified NFT, and `setLockApprovalForAll()` approve all NFTs of the collection under the user wallet. When a user participates in NFTFi, the NFTFi project contract calls `lockFrom()` to lock the user's NFT.Locked NFT will not be able to be transferred, the NFTFi project contract can also use the unlock function (`unlockFrom()`) to unlock the NFT.
The NFT owner can give another trusted operator the right to lock his NFT through the approve function. The `lockApprove()` function only approves the specified NFT, and `setLockApprovalForAll()` approves all NFTs of the collection under the user wallet. When a user participates in NFTFi, the NFTFi project contract calls `lockFrom()` to lock the user's NFT. Locked NFT will not be able to be transferred. The NFTFi project contract can later use the unlock function (`unlockFrom()`) to unlock the NFT.

Small grammar fixes (still needs a bit of improvement). Why these decisions were made is also not explained.


### NFT lock period
When the NFT is locked, the lock expiration time needs to be set. The expiration time must be greater than the current block time. After the lock expires, the NFT is automatically released and can be transferred.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When the NFT is locked, the lock expiration time needs to be set. The expiration time must be greater than the current block time. After the lock expires, the NFT is automatically released and can be transferred.
When the NFT is locked, the lock expiration block needs to be set. The expiration block must be greater than the current block. After the lock expires, the NFT is automatically released and can be transferred.

I recommend you change this to block because there is no reliable way of getting on-chain timestamps. Why these decisions were made is also not explained.


### Bound NFT
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
This standard takes into account that some NFTFi projects want to learn more about NFT participation, such as viewing NFT information through lock-up contracts, so we designed a boundNFT. When the lock contract locks the NFT, it can choose to mint the boundNFT of the NFT to the lock contract address. The boundNFT is consistent with the original NFT metadata and other information, but the boundNFT has no value and cannot be transferred. It is just a lock certificate. When the user's NFT lockup ends, the boundNFT will be destroyed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section should not be part of the rationale. If anything, this should be in the motivation.



## Backwards Compatibility
This standard is compatible with current ERC-721 standards.

## Reference Implementation
You can find an implementation of this standard in [RadioCaca](https://github.com/radiocaca/ERC721L/tree/main/contracts/EIP5058).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You can find an implementation of this standard in [RadioCaca](https://github.com/radiocaca/ERC721L/tree/main/contracts/EIP5058).
You can find an implementation of this standard in the assets folder.

No external links.


## Security Considerations
There are no security considerations related directly to the implementation of this standard.
radiocaca marked this conversation as resolved.
Show resolved Hide resolved

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
radiocaca marked this conversation as resolved.
Show resolved Hide resolved
radiocaca marked this conversation as resolved.
Show resolved Hide resolved