ERC721URIStorage.sol 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721URIStorage.sol)
  3. pragma solidity ^0.8.19;
  4. import "../ERC721.sol";
  5. import "../../../interfaces/IERC4906.sol";
  6. /**
  7. * @dev ERC721 token with storage based token URI management.
  8. */
  9. abstract contract ERC721URIStorage is IERC4906, ERC721 {
  10. using Strings for uint256;
  11. // Optional mapping for token URIs
  12. mapping(uint256 => string) private _tokenURIs;
  13. /**
  14. * @dev See {IERC165-supportsInterface}
  15. */
  16. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) {
  17. return interfaceId == bytes4(0x49064906) || super.supportsInterface(interfaceId);
  18. }
  19. /**
  20. * @dev See {IERC721Metadata-tokenURI}.
  21. */
  22. function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
  23. _requireMinted(tokenId);
  24. string memory _tokenURI = _tokenURIs[tokenId];
  25. string memory base = _baseURI();
  26. // If there is no base URI, return the token URI.
  27. if (bytes(base).length == 0) {
  28. return _tokenURI;
  29. }
  30. // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
  31. if (bytes(_tokenURI).length > 0) {
  32. return string(abi.encodePacked(base, _tokenURI));
  33. }
  34. return super.tokenURI(tokenId);
  35. }
  36. /**
  37. * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
  38. *
  39. * Emits {MetadataUpdate}.
  40. *
  41. * Requirements:
  42. *
  43. * - `tokenId` must exist.
  44. */
  45. function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
  46. if (!_exists(tokenId)) {
  47. revert ERC721NonexistentToken(tokenId);
  48. }
  49. _tokenURIs[tokenId] = _tokenURI;
  50. emit MetadataUpdate(tokenId);
  51. }
  52. /**
  53. * @dev See {ERC721-_burn}. This override additionally checks to see if a
  54. * token-specific URI was set for the token, and if so, it deletes the token URI from
  55. * the storage mapping.
  56. */
  57. function _burn(uint256 tokenId) internal virtual override {
  58. super._burn(tokenId);
  59. if (bytes(_tokenURIs[tokenId]).length != 0) {
  60. delete _tokenURIs[tokenId];
  61. }
  62. }
  63. }