Add ERC721URIStorage extension (#2555)

(cherry picked from commit 1705067e65)
This commit is contained in:
Hadrien Croubois
2021-03-03 16:13:09 +01:00
parent cb88e15b33
commit 4390b8df12
8 changed files with 243 additions and 12 deletions

View File

@ -7,7 +7,19 @@ import "../token/ERC721/extensions/ERC721Burnable.sol";
contract ERC721BurnableMock is ERC721Burnable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) { }
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
}

View File

@ -25,6 +25,10 @@ contract ERC721EnumerableMock is ERC721Enumerable {
return _baseURI();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}

View File

@ -11,18 +11,6 @@ import "../token/ERC721/extensions/ERC721Pausable.sol";
contract ERC721PausableMock is ERC721Pausable {
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function mint(address to, uint256 tokenId) public {
super._mint(to, tokenId);
}
function burn(uint256 tokenId) public {
super._burn(tokenId);
}
function exists(uint256 tokenId) public view returns (bool) {
return super._exists(tokenId);
}
function pause() external {
_pause();
}
@ -30,4 +18,24 @@ contract ERC721PausableMock is ERC721Pausable {
function unpause() external {
_unpause();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721URIStorage.sol";
/**
* @title ERC721Mock
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721URIStorageMock is ERC721URIStorage {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
_setTokenURI(tokenId, _tokenURI);
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -39,6 +39,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
{{ERC721Burnable}}
{{ERC721TokenUri}}
== Presets
These contracts are preconfigured combinations of the above features. They can be used through inheritance or as models to copy and paste their source code.

View File

@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC721.sol";
/**
* @dev ERC721 token with storage based token uri management.
*/
abstract contract ERC721URIStorage is ERC721 {
using Strings for uint256;
// Optional mapping for token URIs
mapping (uint256 => string) private _tokenURIs;
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = _baseURI();
// If there is no base URI, return the token URI.
if (bytes(base).length == 0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
return super.tokenURI(tokenId);
}
/**
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* 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;
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal virtual override {
super._burn(tokenId);
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
}