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

Add IERC4906 interface and use in ERC721 #4012

Merged
merged 9 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lovely-dragons-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`IERC4906`: Add an interface for ERC-4906 that is now Final.
5 changes: 5 additions & 0 deletions .changeset/thirty-swans-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`.
19 changes: 19 additions & 0 deletions contracts/interfaces/IERC4906.sol
Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 6 additions & 1 deletion contracts/token/ERC721/extensions/ERC721URIStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -38,13 +39,17 @@ abstract contract ERC721URIStorage is ERC721 {
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Emits {MetadataUpdate}.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;

emit MetadataUpdate(tokenId);
}

/**
Expand Down
8 changes: 7 additions & 1 deletion test/token/ERC721/extensions/ERC721URIStorage.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { BN, expectRevert } = require('@openzeppelin/test-helpers');
const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');

const { expect } = require('chai');

Expand Down Expand Up @@ -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),
Expand Down