Sfoglia il codice sorgente

Add IERC4906 interface and use in ERC721 (#4012)

Co-authored-by: Francisco Giordano <fg@frang.io>
Hadrien Croubois 2 anni fa
parent
commit
96a2297e15

+ 5 - 0
.changeset/lovely-dragons-appear.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`IERC4906`: Add an interface for ERC-4906 that is now Final.

+ 5 - 0
.changeset/thirty-swans-exercise.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`.

+ 19 - 0
contracts/interfaces/IERC4906.sol

@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "./IERC165.sol";
+import "./IERC721.sol";
+
+/// @title EIP-721 Metadata Update Extension
+interface IERC4906 is IERC165, IERC721 {
+    /// @dev This event emits when the metadata of a token is changed.
+    /// So that the third-party platforms such as NFT market could
+    /// timely update the images and related attributes of the NFT.
+    event MetadataUpdate(uint256 _tokenId);
+
+    /// @dev This event emits when the metadata of a range of tokens is changed.
+    /// So that the third-party platforms such as NFT market could
+    /// timely update the images and related attributes of the NFTs.
+    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
+}

+ 6 - 1
contracts/token/ERC721/extensions/ERC721URIStorage.sol

@@ -4,11 +4,12 @@
 pragma solidity ^0.8.0;
 
 import "../ERC721.sol";
+import "../../../interfaces/IERC4906.sol";
 
 /**
  * @dev ERC721 token with storage based token URI management.
  */
-abstract contract ERC721URIStorage is ERC721 {
+abstract contract ERC721URIStorage is IERC4906, ERC721 {
     using Strings for uint256;
 
     // Optional mapping for token URIs
@@ -38,6 +39,8 @@ abstract contract ERC721URIStorage is ERC721 {
     /**
      * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
      *
+     * Emits {MetadataUpdate}.
+     *
      * Requirements:
      *
      * - `tokenId` must exist.
@@ -45,6 +48,8 @@ abstract contract ERC721URIStorage is ERC721 {
     function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
         require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
         _tokenURIs[tokenId] = _tokenURI;
+
+        emit MetadataUpdate(tokenId);
     }
 
     /**

+ 7 - 1
test/token/ERC721/extensions/ERC721URIStorage.test.js

@@ -1,4 +1,4 @@
-const { BN, expectRevert } = require('@openzeppelin/test-helpers');
+const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
 
 const { expect } = require('chai');
 
@@ -38,6 +38,12 @@ contract('ERC721URIStorage', function (accounts) {
       expect(await this.token.tokenURI(firstTokenId)).to.be.equal(sampleUri);
     });
 
+    it('setting the uri emits an event', async function () {
+      expectEvent(await this.token.$_setTokenURI(firstTokenId, sampleUri), 'MetadataUpdate', {
+        _tokenId: firstTokenId,
+      });
+    });
+
     it('reverts when setting for non existent token id', async function () {
       await expectRevert(
         this.token.$_setTokenURI(nonExistentTokenId, sampleUri),