-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Update EIP-5521: Add more descriptions #5563
Merged
Merged
Changes from 28 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
59bbdb4
Create eip-referable-NFT.md
OniReimu f6253d1
Update eip-***.md
OniReimu 4cb5d13
Update eip-referableNFT.md
OniReimu c7bb8b8
update eip name
OniReimu ce5750a
Update eip-0000.md
OniReimu 26536e7
Update eip-0000.md
OniReimu 9228835
Update eip-0000.md
OniReimu 4bfe81e
Update eip-0000.md
OniReimu c3060a8
Update eip-0000.md
OniReimu 38e3c28
Update eip-0000.md
OniReimu e9c4731
Update eip number
OniReimu bf68206
Update EIPS/eip-5521.md
OniReimu e7275a2
Update EIPS/eip-5521.md
OniReimu e33b053
Update EIPS/eip-5521.md
OniReimu 9aa7f3d
Update EIPS/eip-5521.md
OniReimu 44fb0b8
Update EIPS/eip-5521.md
OniReimu e34fe37
Update EIPS/eip-5521.md
OniReimu 32baeb1
Update EIPS/eip-5521.md
OniReimu b81b3ea
Update EIPS/eip-5521.md
OniReimu a6ee02f
Update EIPS/eip-5521.md
OniReimu adb67d3
Update EIPS/eip-5521.md
OniReimu 5a1df32
Update EIPS/eip-5521.md
OniReimu 478c0fb
Update EIPS/eip-5521.md
OniReimu bca965b
Merge branch 'master' into master
OniReimu 26435d5
Update eip-5521.md
OniReimu 726a11a
Update eip-5521.md
OniReimu 5541afe
Update eip-5521.md
OniReimu 9d1846d
Update eip-5521.md
OniReimu a2ca608
Merge branch 'master' into master
OniReimu f648722
Update
OniReimu 5fd1b53
Merge branch 'master' of https://github.com/OniReimu/EIPs
OniReimu eb9ebc3
Update .gitignore
OniReimu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
--- | ||
eip: 5521 | ||
title: Referable NFT | ||
description: An EIP-721 extension to construct reference relationships among NFTs | ||
author: Saber Yu (@OniReimu), Qin Wang <[email protected]>, Shange Fu <[email protected]>, Shiping Chen <[email protected]>, Sherry Xu <[email protected]>, Jiangshan Yu <[email protected]> | ||
discussions-to: https://ethereum-magicians.org/t/eip-x-erc-721-referable-nft/10310 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2022-08-10 | ||
requires: 165, 721, 5006 | ||
--- | ||
|
||
## Abstract | ||
This standard is an extension of [EIP-721](./eip-721.md). It proposes two referrable indicators, referring and referred, and a time-based indicator `createdTimestamp`. The relationship between each NFT forms a Directed acyclic graph (DAG). The standard allows users to query, track and analyze their relationships. | ||
|
||
## Motivation | ||
Many scenarios require inheritance, reference, and extension of NFTs. For instance, an artist may develop his NFT work based on a previous NFT, or a DJ may remix his record by referring to two pop songs, etc. Proposing a referable solution for existing NFTs and enabling efficient queries on cross-references make much sense. | ||
|
||
By adding the `referring` indicator, users can mint new NFTs (e.g., C, D, E) by referring to existing NFTs (e.g., A, B), while `referred` enables the referred NFTs (A, B) to be aware that who has quoted it (e.g., A ← D; C ← E; B ← E, and A ← E). The `createdTimestamp` is an indicator used to show the creation time of NFTs (A, B, C, D, E). | ||
|
||
## 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. | ||
|
||
`referring`: an out-degree indicator, used to show the users this NFT refers to; | ||
`referred`: an in-degree indicator, used to show the users who have refereed this NFT; | ||
`createdTimestamp`: a time-based indicator, used to compare the timestamp of mint. | ||
|
||
`safeMint`: mint a new rNFT; | ||
`setNode`: set the referring list of an rNFT and update the referred list of each one in the referring list; | ||
`setNodeReferring`: set the referring list of an rNFT; | ||
`setNodeReferred`: set the referred list of the given rNFTs; | ||
`referringOf`: Get the referring list of an rNFT; | ||
`referredOf`: Get the referred list of an rNFT. | ||
|
||
## Rationale | ||
This standard is intended to establish the referable DAG for queries on cross-relationship and accordingly provide the simplest functions. It provides advantages as follows. | ||
|
||
*Clear ownership inheritance*: This standard extends the static NFT into a virtually extensible NFT network. Artists do not have to create work isolated from others. The ownership inheritance avoids reinventing the same wheel. | ||
|
||
*Incentive Compatibility*: This standard clarifies the referable relationship across different NFTs, helping to integrate multiple up-layer incentive models for both original NFT owners and new creators. | ||
|
||
*Easy Integration*: This standard makes it easier for the existing token standards or third-party protocols. For instance, the referable NFT can be applied to rentable scenarios (cf. [EIP-5006](./eip-5006.md) to build a hierarchical rental market, where multiple users can rent the same NFT during the same time or one user can rent multiple NFTs during the same duration). | ||
|
||
## Backwards Compatibility | ||
This standard can be fully [EIP-721](./eip-721.md) compatible by adding an extension function set. | ||
|
||
## Test Cases | ||
Truffle and Openzeppelin are required to run the following in a test network. | ||
```node | ||
truffle develop | ||
rNFT = await ERC_rNFT.new("ERC_rNFT","ERC_rNFT") | ||
rNFT.safeMint(1,[]) | ||
rNFT.referredOf(1) | ||
rNFT.referringOf(1) | ||
|
||
rNFT.safeMint(2,[1]) | ||
rNFT.referredOf(2) | ||
rNFT.referringOf(2) | ||
|
||
rNFT.safeMint(3,[1,2]) | ||
rNFT.referredOf(2) | ||
rNFT.referredOf(3) | ||
rNFT.referringOf(3) | ||
|
||
``` | ||
|
||
## Reference Implementation | ||
```solidity | ||
// SPDX-License-Identifier: CC0-1.0 | ||
pragma solidity ^0.8.4; | ||
|
||
interface IERC_rNFT { | ||
|
||
// Logged when a node in the rNFT gets referred and changed | ||
/// @notice Emitted when the `node` (i.e., an rNFT) is changed | ||
event UpdateNode(uint256 indexed tokenId, address indexed owner, uint256[] _referringList, uint256[] _referredList); | ||
|
||
/// @notice Set the referred and referring relationship of an rNFT | ||
/// Throws if `tokenId` is not valid rNFT | ||
/// @param _tokenIds The list of the rNFTs that `tokenId` refers to | ||
function setNode(uint256 tokenId, uint256[] memory _tokenIds) external; | ||
|
||
/// @notice Get the list of the rNFTs that `tokenId` refers to | ||
/// Throws if `tokenId` is not valid rNFT | ||
/// @param tokenId The rNFT of the referring list | ||
function referringOf(uint256 tokenId) external view returns(uint256[] memory); | ||
|
||
/// @notice Get the list of the rNFT that refers to `tokenId` | ||
/// Throws if `tokenId` is not valid rNFT | ||
/// @param tokenId The rNFT of the referred list | ||
function referredOf(uint256 tokenId) external view returns(uint256[] memory); | ||
} | ||
``` | ||
|
||
```solidity | ||
// SPDX-License-Identifier: CC0-1.0 | ||
pragma solidity ^0.8.4; | ||
|
||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
import "./IERC_rNFT.sol"; | ||
|
||
contract ERC_rNFT is ERC721, IERC_rNFT { | ||
|
||
struct Relationship { | ||
uint256[] referring; // referring list | ||
uint256[] referred; // referred list | ||
uint256 createdTimestamp; // unix timestamp when the rNFT is being created | ||
} | ||
|
||
mapping (uint256 => Relationship) internal _relationship; | ||
address contractOwner = address(0); | ||
|
||
constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) { | ||
contractOwner = msg.sender; | ||
} | ||
|
||
function safeMint(uint256 tokenId, uint256[] memory _tokenIds) public { | ||
_safeMint(msg.sender, tokenId); | ||
setNode(tokenId, _tokenIds); | ||
} | ||
|
||
/// @notice set the referring list of an rNFT | ||
/// Throws if `tokenId` is not a valid rNFT | ||
/// @param _tokenIds array of rNFTs | ||
function setNodeReferring(uint256 tokenId, uint256[] memory _tokenIds) private { | ||
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC_rNFT: transfer caller is not owner nor approved"); | ||
if (contractOwner != msg.sender && _tokenIds.length == 0) { revert("ERC_rNFT: the referring list cannot be empty"); } | ||
|
||
Relationship storage relationship = _relationship[tokenId]; | ||
relationship.referring = _tokenIds; | ||
relationship.createdTimestamp = block.timestamp; | ||
emit UpdateNode(tokenId, msg.sender, relationship.referring, relationship.referred); | ||
} | ||
|
||
/// @notice set the referred list of an rNFT | ||
/// Throws if `tokenId` is not a valid rNFT | ||
/// @param _tokenIds array of rNFTs | ||
function setNodeReferred(uint256 tokenId, uint256[] memory _tokenIds) private { | ||
for (uint i = 0; i < _tokenIds.length; i++) { | ||
Relationship storage relationship = _relationship[_tokenIds[i]]; | ||
|
||
if (relationship.createdTimestamp >= block.timestamp) { revert("ERC_rNFT: the referred rNFT needs to be a predecessor"); } // Make sure the reference complies with the timing sequence | ||
|
||
relationship.referred.push(tokenId); | ||
emit UpdateNode(_tokenIds[i], ownerOf(_tokenIds[i]), relationship.referring, relationship.referred); | ||
} | ||
} | ||
|
||
/// @notice set the referred list of an rNFT and update the referring list of each one in the referred list | ||
/// Throws if `tokenId` is not a valid rNFT | ||
/// @param _tokenIds array of rNFTs | ||
function setNode(uint256 tokenId, uint256[] memory _tokenIds) public virtual override { | ||
setNodeReferring(tokenId, _tokenIds); | ||
setNodeReferred(tokenId, _tokenIds); | ||
} | ||
|
||
/// @notice Get the referring list of an rNFT | ||
/// @param tokenId The considered rNFT | ||
/// @return The referring list of an rNFT | ||
function referringOf(uint256 tokenId) external view virtual override returns(uint256[] memory) { | ||
require(_exists(tokenId), "ERC_rNFT: token ID not existed"); | ||
return _relationship[tokenId].referring; | ||
} | ||
|
||
/// @notice Get the referred list of an rNFT | ||
/// @param tokenId The considered rNFT | ||
/// @return The referred list of an rNFT | ||
function referredOf(uint256 tokenId) external view virtual override returns(uint256[] memory) { | ||
require(_exists(tokenId), "ERC_rNFT: token ID not existed"); | ||
return _relationship[tokenId].referred; | ||
} | ||
|
||
/// @dev See {IERC165-supportsInterface}. | ||
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { | ||
return interfaceId == type(IERC_rNFT).interfaceId || super.supportsInterface(interfaceId); | ||
} | ||
} | ||
``` | ||
|
||
## Security Considerations | ||
The `createdTimestamp` only covers the block-level timestamp (based on block headers), which does not support fine-grained comparison such as transaction-level. | ||
|
||
## Copyright | ||
Copyright and related rights waived via [CC0](../LICENSE.md). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
csiso
is a typo.