ERC721Metadata.sol 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. pragma solidity ^0.5.0;
  2. import "../../GSN/Context.sol";
  3. import "./ERC721.sol";
  4. import "./IERC721Metadata.sol";
  5. import "../../introspection/ERC165.sol";
  6. contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
  7. // Token name
  8. string private _name;
  9. // Token symbol
  10. string private _symbol;
  11. // Base URI
  12. string private _baseURI;
  13. // Optional mapping for token URIs
  14. mapping(uint256 => string) private _tokenURIs;
  15. /*
  16. * bytes4(keccak256('name()')) == 0x06fdde03
  17. * bytes4(keccak256('symbol()')) == 0x95d89b41
  18. * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
  19. *
  20. * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
  21. */
  22. bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
  23. /**
  24. * @dev Constructor function
  25. */
  26. constructor (string memory name, string memory symbol) public {
  27. _name = name;
  28. _symbol = symbol;
  29. // register the supported interfaces to conform to ERC721 via ERC165
  30. _registerInterface(_INTERFACE_ID_ERC721_METADATA);
  31. }
  32. /**
  33. * @dev Gets the token name.
  34. * @return string representing the token name
  35. */
  36. function name() external view returns (string memory) {
  37. return _name;
  38. }
  39. /**
  40. * @dev Gets the token symbol.
  41. * @return string representing the token symbol
  42. */
  43. function symbol() external view returns (string memory) {
  44. return _symbol;
  45. }
  46. /**
  47. * @dev Returns the URI for a given token ID. May return an empty string.
  48. *
  49. * If the token's URI is non-empty and a base URI was set (via
  50. * {_setBaseURI}), it will be added to the token ID's URI as a prefix.
  51. *
  52. * Reverts if the token ID does not exist.
  53. */
  54. function tokenURI(uint256 tokenId) external view returns (string memory) {
  55. require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
  56. string memory _tokenURI = _tokenURIs[tokenId];
  57. // Even if there is a base URI, it is only appended to non-empty token-specific URIs
  58. if (bytes(_tokenURI).length == 0) {
  59. return "";
  60. } else {
  61. // abi.encodePacked is being used to concatenate strings
  62. return string(abi.encodePacked(_baseURI, _tokenURI));
  63. }
  64. }
  65. /**
  66. * @dev Returns the base URI set via {_setBaseURI}. This will be
  67. * automatically added as a preffix in {tokenURI} to each token's URI, when
  68. * they are non-empty.
  69. */
  70. function baseURI() external view returns (string memory) {
  71. return _baseURI;
  72. }
  73. /**
  74. * @dev Internal function to set the token URI for a given token.
  75. *
  76. * Reverts if the token ID does not exist.
  77. *
  78. * TIP: if all token IDs share a prefix (e.g. if your URIs look like
  79. * `http://api.myproject.com/token/<id>`), use {_setBaseURI} to store
  80. * it and save gas.
  81. */
  82. function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal {
  83. require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
  84. _tokenURIs[tokenId] = _tokenURI;
  85. }
  86. /**
  87. * @dev Internal function to set the base URI for all token IDs. It is
  88. * automatically added as a prefix to the value returned in {tokenURI}.
  89. *
  90. * _Available since v2.5.0._
  91. */
  92. function _setBaseURI(string memory baseURI) internal {
  93. _baseURI = baseURI;
  94. }
  95. /**
  96. * @dev Internal function to burn a specific token.
  97. * Reverts if the token does not exist.
  98. * Deprecated, use _burn(uint256) instead.
  99. * @param owner owner of the token to burn
  100. * @param tokenId uint256 ID of the token being burned by the msg.sender
  101. */
  102. function _burn(address owner, uint256 tokenId) internal {
  103. super._burn(owner, tokenId);
  104. // Clear metadata (if any)
  105. if (bytes(_tokenURIs[tokenId]).length != 0) {
  106. delete _tokenURIs[tokenId];
  107. }
  108. }
  109. }