How do inherit from ERC721, ERC721Enumerable and ERC721URIStorage in v4 of OpenZeppelin Contracts?

Hi, I use the V4.0 of openzeppelin-contracts
How do I use ERC721 contract and inherit ERC721 extensions?

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract Foo is ERC721, ERC721Enumerable, ERC721URIStorage {
  constructor () ERC721("Foo", "FOO") { }
}
1 Like

Hi @rotcivegaf,

Welcome to the community :wave:

You could do something like the following.

You would need to add a mint function to meet your requirements for how you are setting the tokenURI. Your mint should be appropriately protected with AccessControl (we have a workshop on AccessControl next week: https://blog.openzeppelin.com/ozevents)

You may or may not want to include _baseURI depending on your requirements.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract Foo is ERC721, ERC721Enumerable, ERC721URIStorage {
    constructor() ERC721("Foo", "foo") {}

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function _baseURI() internal pure override returns (string memory) {
        return "https://foo.com/token/";
    }
}

1 Like

In the function supportsInterface you need override IERC165 also:

function supportsInterface(bytes4 interfaceId)
    public
    view
    override(IERC165, ERC721, ERC721Enumerable)
    returns (bool)
{
    return super.supportsInterface(interfaceId);
}

With this change works for me
Thanks a lot

1 Like

Hi @rotcivegaf,

I just used OpenZeppelin Contracts Wizard (https://blog.openzeppelin.com/wizard) and was able to compile the following in Remix.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
    constructor() ERC721("MyToken", "MTK") {}

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function safeMint(address to, uint256 tokenId) public onlyOwner {
        _safeMint(to, tokenId);
    }
}

Thanks, yes it works
I have more heredity in my contracts…

1 Like