ERC721URIStorage.sol 2.4 KB

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