In https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/pull/76, we are rearranging the erc721metadata contract storage layout, so the new variable is added at the end. This commit applies the same change to the vanilla contracts repository, so migration from 2.5 to 3.0 is easier for users using the transpiler.
126 lines
3.8 KiB
Solidity
126 lines
3.8 KiB
Solidity
pragma solidity ^0.6.0;
|
|
|
|
import "../../GSN/Context.sol";
|
|
import "./ERC721.sol";
|
|
import "./IERC721Metadata.sol";
|
|
import "../../introspection/ERC165.sol";
|
|
|
|
contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
|
|
// Token name
|
|
string private _name;
|
|
|
|
// Token symbol
|
|
string private _symbol;
|
|
|
|
// Optional mapping for token URIs
|
|
mapping(uint256 => string) private _tokenURIs;
|
|
|
|
// Base URI
|
|
string private _baseURI;
|
|
|
|
/*
|
|
* bytes4(keccak256('name()')) == 0x06fdde03
|
|
* bytes4(keccak256('symbol()')) == 0x95d89b41
|
|
* bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
|
|
*
|
|
* => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
|
|
*/
|
|
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
|
|
|
|
/**
|
|
* @dev Constructor function
|
|
*/
|
|
constructor (string memory name, string memory symbol) public {
|
|
_name = name;
|
|
_symbol = symbol;
|
|
|
|
// register the supported interfaces to conform to ERC721 via ERC165
|
|
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
|
|
}
|
|
|
|
/**
|
|
* @dev Gets the token name.
|
|
* @return string representing the token name
|
|
*/
|
|
function name() external view override returns (string memory) {
|
|
return _name;
|
|
}
|
|
|
|
/**
|
|
* @dev Gets the token symbol.
|
|
* @return string representing the token symbol
|
|
*/
|
|
function symbol() external view override returns (string memory) {
|
|
return _symbol;
|
|
}
|
|
|
|
/**
|
|
* @dev Returns the URI for a given token ID. May return an empty string.
|
|
*
|
|
* If the token's URI is non-empty and a base URI was set (via
|
|
* {_setBaseURI}), it will be added to the token ID's URI as a prefix.
|
|
*
|
|
* Reverts if the token ID does not exist.
|
|
*/
|
|
function tokenURI(uint256 tokenId) external view override returns (string memory) {
|
|
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
|
|
|
|
string memory _tokenURI = _tokenURIs[tokenId];
|
|
|
|
// Even if there is a base URI, it is only appended to non-empty token-specific URIs
|
|
if (bytes(_tokenURI).length == 0) {
|
|
return "";
|
|
} else {
|
|
// abi.encodePacked is being used to concatenate strings
|
|
return string(abi.encodePacked(_baseURI, _tokenURI));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Internal function to set the token URI for a given token.
|
|
*
|
|
* Reverts if the token ID does not exist.
|
|
*
|
|
* TIP: if all token IDs share a prefix (e.g. if your URIs look like
|
|
* `http://api.myproject.com/token/<id>`), use {_setBaseURI} to store
|
|
* it and save gas.
|
|
*/
|
|
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
|
|
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
|
|
_tokenURIs[tokenId] = _tokenURI;
|
|
}
|
|
|
|
/**
|
|
* @dev Internal function to set the base URI for all token IDs. It is
|
|
* automatically added as a prefix to the value returned in {tokenURI}.
|
|
*
|
|
* _Available since v2.5.0._
|
|
*/
|
|
function _setBaseURI(string memory baseURI) internal virtual {
|
|
_baseURI = baseURI;
|
|
}
|
|
|
|
/**
|
|
* @dev Returns the base URI set via {_setBaseURI}. This will be
|
|
* automatically added as a preffix in {tokenURI} to each token's URI, when
|
|
* they are non-empty.
|
|
*
|
|
* _Available since v2.5.0._
|
|
*/
|
|
function baseURI() external view returns (string memory) {
|
|
return _baseURI;
|
|
}
|
|
|
|
|
|
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
|
|
super._beforeTokenTransfer(from, to, tokenId);
|
|
|
|
if (to == address(0)) { // When burning tokens
|
|
// Clear metadata (if any)
|
|
if (bytes(_tokenURIs[tokenId]).length != 0) {
|
|
delete _tokenURIs[tokenId];
|
|
}
|
|
}
|
|
}
|
|
}
|