From 38fb16886ece8a6cd6a60485ffb5271f6192f1a5 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Sun, 3 Mar 2024 01:46:30 +0000 Subject: [PATCH 1/9] ERC: Metadata Management for NFTs --- .../erc_draft_metadata_management_for_nfts.md | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 ERCS/erc_draft_metadata_management_for_nfts.md diff --git a/ERCS/erc_draft_metadata_management_for_nfts.md b/ERCS/erc_draft_metadata_management_for_nfts.md new file mode 100644 index 0000000000..8e8c35f8c7 --- /dev/null +++ b/ERCS/erc_draft_metadata_management_for_nfts.md @@ -0,0 +1,140 @@ +--- +title: Metadata Management for NFTs +description: This ERC proposes a standard for managing metadata of NFTs that allows owners and authorized addresses to update the metadata of their tokens. +author: Alexey Kureev (@Kureev) +discussions-to: +status: Draft +type: Standards Track +category: ERC +created: 2024-03-03 +requires: 721, 1155 +--- + +## Abstract + +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the ERC721 or ERC1155 standard. + +## Motivation + +Currently, the metadata of an NFT is immutable once it has been minted. This is problematic for use cases where the metadata of an NFT needs to be updated afterwards. For example, an NFT representing a digital artwork might need to have its metadata updated to reflect changes in the artwork's ownership or provenance. + +## Specification + +The MetadataManager contract provides the following functions: + +- `updateMetadata(address tokenAddress, uint256 tokenId, string memory newURI)`: Updates the metadata of a token. The sender must be the owner of the token or authorized to update the metadata. +- `getMetadata(address tokenAddress, uint256 tokenId)`: Returns the metadata of a token. If the metadata is not stored, it will try to fetch it from the NFT contract. +- `authorize(address tokenAddress, uint256 tokenId, address authorizedAddress)`: Authorizes an address to update the metadata of a token. Only the owner of the token can call this function. +- `revokeAuthorization(address tokenAddress, uint256 tokenId, address authorizedAddress)`: Revokes the authorization of an address to update the metadata of a token. Only the owner of the token can call this function. + +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. + +## Rationale + +This ERC provides a flexible and decentralized way to manage the metadata of NFTs. It allows the metadata of an NFT to be updated after it has been minted, and it allows the owner of an NFT to delegate the ability to update the metadata to other addresses. + +## Backwards Compatibility + +This ERC is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the ERC721 or ERC1155 standard. + +## Test Cases + +TBD + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: CC0-1.0 + +pragma solidity ^0.8.0; + +interface INFT { + function ownerOf(uint256 tokenId) external view returns (address owner); + function tokenURI(uint256 tokenId) external view returns (string memory); +} + +contract MetadataManager { + // tokenAddress => tokenId => URI of the metadata + mapping(address => mapping(uint256 => string)) public tokenMetadata; + + // tokenAddress => tokenId => authorizedAddress => bool + mapping(address => mapping(uint256 => mapping(address => bool))) public isAuthorized; + + // Emits when the metadata of a token is updated. + event MetadataUpdated(address indexed tokenAddress, uint256 indexed tokenId, string newUri); + + // Emits when an address is authorized to update the metadata of a token. + event AuthorizationGranted(address indexed tokenAddress, uint256 indexed tokenId, address indexed authorizedAddress); + + // Emits when an address is revoked from updating the metadata of a token. + event AuthorizationRevoked(address indexed tokenAddress, uint256 indexed tokenId, address indexed authorizedAddress); + + // Throws if the sender is not the owner of the token. + modifier onlyTokenOwner(address tokenAddress, uint256 tokenId) { + INFT nftContract = INFT(tokenAddress); + if (msg.sender != nftContract.ownerOf(tokenId)) { + revert NotOwner(); + } + _; + } + + /** + * Updates the metadata of a token. + * The sender must be the owner of the token or authorized to update the metadata. + * Emits a {MetadataUpdated} event. + */ + function updateMetadata(address tokenAddress, uint256 tokenId, string memory newURI) public { + INFT nftContract = INFT(tokenAddress); + + if (msg.sender != nftContract.ownerOf(tokenId) || !isAuthorized[tokenAddress][tokenId][msg.sender]) { + revert NotAuthorized(); + } + + tokenMetadata[tokenAddress][tokenId] = newURI; + emit MetadataUpdated(tokenAddress, tokenId, newURI); + } + + /** + * Returns the metadata of a token. + * If the metadata is not stored, it will try to fetch it from the NFT contract. + * If the NFT contract does not have a tokenURI function, it will revert. + */ + function getMetadata(address tokenAddress, uint256 tokenId) public view returns (string memory) { + string memory metadata = tokenMetadata[tokenAddress][tokenId]; + + if (bytes(metadata).length == 0) { + try INFT(tokenAddress).tokenURI(tokenId) returns (string memory uri) { + return uri; + } catch { + revert NoMetadata(); + } + } else { + return metadata; + } + } + + // Authorizes an address to update the metadata of a token. + function authorize(address tokenAddress, uint256 tokenId, address authorizedAddress) public onlyTokenOwner(tokenAddress, tokenId) { + isAuthorized[tokenAddress][tokenId][authorizedAddress] = true; + emit AuthorizationGranted(tokenAddress, tokenId, authorizedAddress); + } + + // Revokes the authorization of an address to update the metadata of a token. + function revokeAuthorization(address tokenAddress, uint256 tokenId, address authorizedAddress) public onlyTokenOwner(tokenAddress, tokenId) { + isAuthorized[tokenAddress][tokenId][authorizedAddress] = false; + emit AuthorizationRevoked(tokenAddress, tokenId, authorizedAddress); + } + + error NotAuthorized(); + error NotOwner(); + error NoMetadata(); +} +``` + +## Security Considerations + +The MetadataManager contract relies on the ownerOf function of the NFT contract to determine the owner of a token. If the NFT contract does not implement this function correctly, it could lead to security issues. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 33286bc6419e6ba9a87e09bb56b113ce57fe5987 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 10:44:36 +0000 Subject: [PATCH 2/9] Update ERC number Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- ERCS/erc_draft_metadata_management_for_nfts.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ERCS/erc_draft_metadata_management_for_nfts.md b/ERCS/erc_draft_metadata_management_for_nfts.md index 8e8c35f8c7..dded771023 100644 --- a/ERCS/erc_draft_metadata_management_for_nfts.md +++ b/ERCS/erc_draft_metadata_management_for_nfts.md @@ -1,4 +1,5 @@ --- +eip: 7646 title: Metadata Management for NFTs description: This ERC proposes a standard for managing metadata of NFTs that allows owners and authorized addresses to update the metadata of their tokens. author: Alexey Kureev (@Kureev) From 75b8156258e9648680285c639534b6da5394e1e1 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 10:48:07 +0000 Subject: [PATCH 3/9] Updated ERC to comply with erc-xxxx naming convention and added discussions-to link --- ERCS/{erc_draft_metadata_management_for_nfts.md => erc-7646.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename ERCS/{erc_draft_metadata_management_for_nfts.md => erc-7646.md} (98%) diff --git a/ERCS/erc_draft_metadata_management_for_nfts.md b/ERCS/erc-7646.md similarity index 98% rename from ERCS/erc_draft_metadata_management_for_nfts.md rename to ERCS/erc-7646.md index dded771023..38744f10cd 100644 --- a/ERCS/erc_draft_metadata_management_for_nfts.md +++ b/ERCS/erc-7646.md @@ -3,7 +3,7 @@ eip: 7646 title: Metadata Management for NFTs description: This ERC proposes a standard for managing metadata of NFTs that allows owners and authorized addresses to update the metadata of their tokens. author: Alexey Kureev (@Kureev) -discussions-to: +discussions-to: https://ethereum-magicians.org/t/erc-7646-metadata-management-for-nfts/19027 status: Draft type: Standards Track category: ERC From e97f640b09edd5d7f55638b41094b96524997d09 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:01:01 +0000 Subject: [PATCH 4/9] ERC-7646: Address EIP validator comments --- ERCS/erc-7646.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index 38744f10cd..63051dfc67 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -1,7 +1,7 @@ --- eip: 7646 title: Metadata Management for NFTs -description: This ERC proposes a standard for managing metadata of NFTs that allows owners and authorized addresses to update the metadata of their tokens. +description: This ERC allows NFT owners and authorized addresses to update their token metadata. author: Alexey Kureev (@Kureev) discussions-to: https://ethereum-magicians.org/t/erc-7646-metadata-management-for-nfts/19027 status: Draft @@ -13,7 +13,7 @@ requires: 721, 1155 ## Abstract -The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the ERC721 or ERC1155 standard. +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the ERC-721 or ERC-1155 standard. ## Motivation @@ -32,11 +32,11 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S ## Rationale -This ERC provides a flexible and decentralized way to manage the metadata of NFTs. It allows the metadata of an NFT to be updated after it has been minted, and it allows the owner of an NFT to delegate the ability to update the metadata to other addresses. +The rationale behind ERC-7646 is to provide a decentralized method for the management of NFT metadata, allowing updates post-mint, as well as the ability for the owner to assign metadata editing permissions. ## Backwards Compatibility -This ERC is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the ERC721 or ERC1155 standard. +ERC-7646 is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the ERC-721 or ERC-1155 standard. ## Test Cases From e973e9bd941d7ba6ffb7baaea4a7cc41144b6127 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:08:03 +0000 Subject: [PATCH 5/9] ERC-7646: Use links for ERC references --- ERCS/erc-7646.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index 63051dfc67..77b2caab3b 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -13,7 +13,7 @@ requires: 721, 1155 ## Abstract -The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the ERC-721 or ERC-1155 standard. +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. ## Motivation @@ -32,11 +32,11 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S ## Rationale -The rationale behind ERC-7646 is to provide a decentralized method for the management of NFT metadata, allowing updates post-mint, as well as the ability for the owner to assign metadata editing permissions. +The rationale behind [ERC-7646](./erc-7647.md) is to provide a decentralized method for the management of NFT metadata, allowing updates post-mint, as well as the ability for the owner to assign metadata editing permissions. ## Backwards Compatibility -ERC-7646 is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the ERC-721 or ERC-1155 standard. +[ERC-7646](./erc-7647.md) is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. ## Test Cases From 776a4ec1cc8dd01b3988852ae990c54e83db6588 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:10:05 +0000 Subject: [PATCH 6/9] ERC-7646: Avoid referencing the ERC itself --- ERCS/erc-7646.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index 77b2caab3b..40d1fb4a16 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -32,11 +32,11 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S ## Rationale -The rationale behind [ERC-7646](./erc-7647.md) is to provide a decentralized method for the management of NFT metadata, allowing updates post-mint, as well as the ability for the owner to assign metadata editing permissions. +The rationale behind this proposal is to provide a decentralized method for the management of NFT metadata, allowing updates post-mint, as well as the ability for the owner to assign metadata editing permissions. ## Backwards Compatibility -[ERC-7646](./erc-7647.md) is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. +This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. ## Test Cases From c24ea894e364bc7df222451aafe2cf392daee05b Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:22:07 +0000 Subject: [PATCH 7/9] ERC-7646: Update references to point to ercs.ethereum.com website --- ERCS/erc-7646.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index 40d1fb4a16..d395666e15 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -13,7 +13,7 @@ requires: 721, 1155 ## Abstract -The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](https://ercs.ethereum.org/ERCS/erc-721) or [ERC-1155](https://ercs.ethereum.org/ERCS/erc-1155) standard. ## Motivation @@ -36,7 +36,7 @@ The rationale behind this proposal is to provide a decentralized method for the ## Backwards Compatibility -This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. +This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](https://ercs.ethereum.org/ERCS/erc-721) or [ERC-1155](https://ercs.ethereum.org/ERCS/erc-1155) standard. ## Test Cases From cedc391caf8646ce92d2d18d480a4ee99667ba42 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:25:06 +0000 Subject: [PATCH 8/9] Revert "ERC-7646: Update references to point to ercs.ethereum.com website" This reverts commit 23aeccb22c69e7291d5a9b532f638c4133a3b132. --- ERCS/erc-7646.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index d395666e15..40d1fb4a16 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -13,7 +13,7 @@ requires: 721, 1155 ## Abstract -The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](https://ercs.ethereum.org/ERCS/erc-721) or [ERC-1155](https://ercs.ethereum.org/ERCS/erc-1155) standard. +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. ## Motivation @@ -36,7 +36,7 @@ The rationale behind this proposal is to provide a decentralized method for the ## Backwards Compatibility -This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](https://ercs.ethereum.org/ERCS/erc-721) or [ERC-1155](https://ercs.ethereum.org/ERCS/erc-1155) standard. +This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. ## Test Cases From c11f78350baab71f03454999b436f0f8410d1614 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Mon, 4 Mar 2024 11:34:50 +0000 Subject: [PATCH 9/9] DB-7646: EIP instead of ERC for relative references? --- ERCS/erc-7646.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-7646.md b/ERCS/erc-7646.md index 40d1fb4a16..9a40eece53 100644 --- a/ERCS/erc-7646.md +++ b/ERCS/erc-7646.md @@ -13,7 +13,7 @@ requires: 721, 1155 ## Abstract -The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. +The MetadataManager contract provides a mapping for storing metadata of NFTs. It also provides a mechanism for authorizing other addresses to update the metadata of a token. This contract can be used in conjunction with any NFT contract that implements the [ERC-721](./eip-721.md) or [ERC-1155](./eip-1155.md) standard. ## Motivation @@ -36,7 +36,7 @@ The rationale behind this proposal is to provide a decentralized method for the ## Backwards Compatibility -This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./erc-721.md) or [ERC-1155](./erc-1155.md) standard. +This proposal is fully backwards compatible with existing NFT standards. It can be used in conjunction with any NFT contract that implements the [ERC-721](./eip-721.md) or [ERC-1155](./eip-1155.md) standard. ## Test Cases