-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
draft sealed nft metadata #3569
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
48d7a04
draft sealed nft metadata
pizzarob c1854f8
adding rationale and other sections
pizzarob f8dd301
remove sentence
pizzarob 6327594
adding bullet point regarding reading and caching
pizzarob 37d0811
Update EIPS/eip-draft_sealed_nft_metadata.md
pizzarob eca077f
Update EIPS/eip-draft_sealed_nft_metadata.md
pizzarob 0eba097
add discussion link
pizzarob 831abba
update filename
pizzarob 7cffadf
Update description
pizzarob 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,139 @@ | ||
--- | ||
eip: 3569 | ||
title: Sealed NFT Metadata Standard | ||
author: Sean Papanikolas (@pizzarob) | ||
discussions-to: https://github.com/ethereum/EIPs/pull/3569 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2021-05-07 | ||
--- | ||
|
||
## Simple Summary | ||
|
||
The Sealed NFT Metadata Extension provides a mechanism to immortalize NFT metadata in a cost-effective manner. | ||
|
||
## Abstract | ||
|
||
This standard accomplishes three things; it provides a way for potential collectors to verify that the NFT metadata will not change, allows creators to immortalize metadata for multiple tokens at one time, and allows metadata for many NFTs to be read and cached from one file. A creator can call the `seal` function for a range of one or many sequential NFTs. Included as an argument is a URI which points to a decentralized storage service like IPFS and will be stored in the smart contract. The URI will return a JSON object in which the keys are token IDs and the values are either a string which is a URI pointing to a metadata file stored on a decentralized file system, or raw metadata JSON for each token ID. The token ID(s) will then be marked as sealed in the smart contract and cannot be sealed again. The `seal` function can be called after NFT creation, or during the NFT creation process. | ||
|
||
## Motivation | ||
|
||
In the original ERC-721 standard, the metadata extension specifies a `tokenURI` function which returns a URI for a single token ID. This may be hosted on IPFS or might be hosted on a centralized server. There's no guarantee that the NFT metadata will not change. This is the same for the ERC-1155 metadata extension. In addition to that - if you want to update the metadata for many NFTs you would need to do so in O(n) time, which as we know is not financially feasible at scale. By allowing for a decentralized URI to point to a JSON object of many NFT IDs we can solve this issue by providing metadata for many tokens at one time rather than one at a time. We can also provide methods which give transparency into whether the NFT has be explicitly "sealed" and that the metadata is hosted on a decentralized storage space. | ||
|
||
There is not a way for the smart contract layer to communicate with a storage layer and as such we need a solution which provides a way for potential NFT collectors on Ethereum to verify that their NFT will not be "rug pulled". This standard provides a solution for that. By allowing creators to seal their NFTs during or after creation, they are provided with full flexibility when it comes to creating their NFTs. Decentralized storage means permanence - in the fast-moving world of digital marketing campaigns, or art projects mistakes can happen. As such, it is important for creators to have flexibility when creating their projects. Therefore, this standard allows creators to opt in at a time of their choosing. Mistakes do happen and metadata should be flexible enough so that creators can fix mistakes or create dynamic NFTs (see Beeple's CROSSROAD NFT). If there comes a time when the NFT metadata should be immortalized, then the creator can call the `seal` method. Owners, potential owners, or platforms can verify that the NFT was sealed and can check the returned URI. If the `sealedURI` return value is not hosted on a decentralized storage platform, or the `isSealed` method does not return `true` for the given NFT ID then it can be said that one cannot trust that these NFTs will not change at a future date and can then decide if they want to proceed with collecting the given 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. | ||
|
||
``` | ||
interface SealedMetadata { | ||
/** | ||
@notice This function is used to set a sealed URI for the given range of tokens. | ||
@dev | ||
- If the sealed URI is being set for one token then the fromTokenId and toTokenId | ||
values MUST be the same. | ||
|
||
- If any token within the range of tokens specified has already | ||
been sealed then this function MUST throw. | ||
|
||
- This function MAY be called at the time of NFT creation, or after the NFTs have been created. | ||
|
||
- It is RECOMMENDED that this function only be executable by either the creator of the smart contract, | ||
or the creator of the NFTs, but this is OPTIONAL and should be implemented based on use case. | ||
|
||
- This function MUST emit the Sealed event | ||
|
||
- The URI argument SHOULD point to a JSON file hosted within a decentralized file system like IPFS | ||
|
||
@param fromTokenId The first token in a consecutive range of tokens | ||
@param toTokenId The ending token in a consecutive range of tokens | ||
@param uri A URI which points to a JSON file hosted on a decentralized file system. | ||
*/ | ||
function seal(uint256 fromTokenId, uint256 toTokenId, string memory uri) external; | ||
|
||
/** | ||
@notice This function returns the URI which the sealed metadata can be found for the given token ID | ||
@dev | ||
- This function MUST throw if the token ID does not exist, or is not sealed | ||
|
||
@param tokenId Token ID to retrieve the sealed URI for | ||
|
||
@return The sealed URI in which the metadata for the given token ID can be found | ||
*/ | ||
function sealedURI(uint256 tokenId) external view returns (string); | ||
|
||
/** | ||
@notice This function returns a boolean stating if the token ID is sealed or not | ||
@dev This function should throw if the token ID does not exist | ||
|
||
@param tokenId The token ID that will be checked if sealed or not | ||
|
||
@return Boolean stating if token ID is sealed | ||
*/ | ||
function isSealed(uint256 tokenId) external view returns (bool) | ||
|
||
/// @dev This emits when a range of tokens is sealed | ||
event Sealed(uint256 indexed fromTokenId, uint256 indexed toTokenId, string memory uri); | ||
|
||
} | ||
``` | ||
|
||
### Sealed Metadata JSON Format | ||
|
||
The sealed metadata JSON file MAY contain metadata for many different tokens. The top level keys of the JSON object MUST be token IDs. | ||
|
||
``` | ||
|
||
type ERC721Metadata = { | ||
name?: string; | ||
image?: string; | ||
description?: string; | ||
} | ||
|
||
type SealedMetaDataJson = { | ||
[tokenId: string]: string | ERC721Metadata; | ||
} | ||
|
||
const sealedMetadata: SealedMetaDataJson = { | ||
'1': { | ||
name: 'Metadata for token with ID 1' | ||
}, | ||
'2': { | ||
name: 'Metadata for token with ID 2' | ||
}, | ||
// Example pointing to another file | ||
'3': 'ipfs://SOME_HASH_ON_IPFS' | ||
}; | ||
``` | ||
|
||
## Rationale | ||
|
||
**Rationale for rule not explicitly requiring that sealed URI be hosted on decentralized filestorage** | ||
|
||
In order for this standard to remain future proof there is no validation within the smart contract that would verify the sealed URI is hosted on IPFS or another decentralized file storage system. The standard allows potential collectors and platforms to validate the URI on the client. | ||
|
||
**Rationale to include many NFT metadata objects, or URIs in one JSON file** | ||
|
||
By including metadata for many NFTs in one JSON file we can eliminate the need for many transactions to set the metadata for multiple NFTs. Given that this file should not change NFT platforms, or explorers can cache the metadata within the file. | ||
|
||
**Rationale for emitting `Sealed` event** | ||
|
||
Platforms and explorers can use the `Sealed` event to automatically cache metadata, or update information regarding specified NFTs. | ||
|
||
**Rationale for allowing URIs as values in the JSON file** | ||
|
||
If a token's metadata is very large, or there are many tokens you can save file space by referencing another URI rather than storing the metadata JSON within the top level metadata file. | ||
|
||
## Backwards Compatibility | ||
|
||
There is no backwards compatibility with existing standards. This is an extension which could be added to existing NFT standards. | ||
|
||
## Security Considerations | ||
|
||
There are no security considerations related directly to the implementation of this standard. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
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.
How was this merged with a PR as discussion url? 😅
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.
Sorry, this is my mistake. I've created a FEM thread and a PR to update: #4221