TypeError: Derived contract must override function "supportsInterface". Two or more base classes define function with same name and parameter types.

--> royalty.sol:9:1: | 9 | contract NftMarketplace is ERC721URIStorage,ERC2981 { | ^ (Relevant source part starts here and spans across multiple lines). Note: Definition in "ERC721": --> @openzeppelin/contracts/token/ERC721/ERC721.sol:52:5: | 52 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { | ^ (Relevant source part starts here and spans across multiple lines). Note: Definition in "ERC2981": --> @openzeppelin/contracts/token/common/ERC2981.sol:36:5: | 36 | function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { | ^ (Relevant source part starts here and spans across multiple lines). ---------------code------------------------------------------------- // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/token/common/ERC2981.sol"; import "hardhat/console.sol";

contract NftMarketplace is ERC721URIStorage,ERC2981 { using Counters for Counters.Counter; //_tokenIds variable has the most recent minted tokenId Counters.Counter private _tokenIds; //Keeps track of the number of items sold on the marketplace Counters.Counter private _itemsSold; //owner is the contract address that created the smart contract address payable owner; //The fee charged by the marketplace to be allowed to list an NFT uint256 listPrice = 0.01 ether;

//The structure to store info about a listed token
struct ListedToken {
    uint256 tokenId;
    address payable owner;
    address payable seller;
    uint256 price;
    bool currentlyListed;

//the event emitted when a token is successfully listed
event TokenListedSuccess(
    uint256 indexed tokenId,
    address owner,
    address seller,
    uint256 price,
    bool currentlyListed

//This mapping maps tokenId to token info and is helpful when retrieving details about a tokenId
mapping(uint256 => ListedToken) private idToListedToken;

constructor() ERC721("NFTMarketplace", "NFTM") {
    owner = payable(msg.sender);

function updateListPrice(uint256 _listPrice) public payable {
    require(owner == msg.sender, "Only owner can update listing price");
    listPrice = _listPrice;

function getListPrice() public view returns (uint256) {
    return listPrice;

function getLatestIdToListedToken()
    returns (ListedToken memory)
    uint256 currentTokenId = _tokenIds.current();
    return idToListedToken[currentTokenId];

function getListedTokenForId(
    uint256 tokenId
) public view returns (ListedToken memory) {
    return idToListedToken[tokenId];

function getCurrentToken() public view returns (uint256) {
    return _tokenIds.current();

//The first time a token is created, it is listed here
function createToken(
    string memory tokenURI,
    uint256 price,
    uint96 feeNumerator
) public payable returns (uint) {
    //Increment the tokenId counter, which is keeping track of the number of minted NFTs
    uint256 newTokenId = _tokenIds.current();

    //Mint the NFT with tokenId newTokenId to the address who called createToken
    _safeMint(msg.sender, newTokenId);

    //Map the tokenId to the tokenURI (which is an IPFS URL with the NFT metadata)
    _setTokenURI(newTokenId, tokenURI);

    //Helper function to update Global variables and emit an event
    createListedToken(newTokenId, price,feeNumerator);

    return newTokenId;

function createListedToken(uint256 tokenId, uint256 price,uint96 feeNumerator) private {
    //Make sure the sender sent enough ETH to pay for listing
    require(msg.value == listPrice, "Have to send ether equal to the listing price");
    //Just sanity check
    require(price > 0, "Make sure the price isn't negative");

    //Update the mapping of tokenId's to Token details, useful for retrieval functions
    idToListedToken[tokenId] = ListedToken(

    _transfer(msg.sender, address(this), tokenId);
    //Emit the event for successful transfer. The frontend parses this message and updates the end user
    emit TokenListedSuccess(

//This will return all the NFTs currently listed to be sold on the marketplace
function getAllNFTs() public view returns (ListedToken[] memory) {
    uint nftCount = _tokenIds.current();
    ListedToken[] memory tokens = new ListedToken[](nftCount);
    uint currentIndex = 0;
    uint currentId;
    //at the moment currentlyListed is true for all, if it becomes false in the future we will
    //filter out currentlyListed == false over here
    for (uint i = 0; i < nftCount; i++) {
        currentId = i + 1;
        ListedToken storage currentItem = idToListedToken[currentId];
        tokens[currentIndex] = currentItem;
        currentIndex += 1;
    //the array 'tokens' has the list of all NFTs in the marketplace
    return tokens;

//Returns all the NFTs that the current user is owner or seller in
function getMyNFTs() public view returns (ListedToken[] memory) {
    uint totalItemCount = _tokenIds.current();
    uint itemCount = 0;
    uint currentIndex = 0;
    uint currentId;
    //Important to get a count of all the NFTs that belong to the user before we can make an array for them
    for (uint i = 0; i < totalItemCount; i++) {
        if (
            idToListedToken[i + 1].owner == msg.sender ||
            idToListedToken[i + 1].seller == msg.sender
        ) {
            itemCount += 1;

    //Once you have the count of relevant NFTs, create an array then store all the NFTs in it
    ListedToken[] memory items = new ListedToken[](itemCount);
    for (uint i = 0; i < totalItemCount; i++) {
        if (
            idToListedToken[i + 1].owner == msg.sender ||
            idToListedToken[i + 1].seller == msg.sender
        ) {
            currentId = i + 1;
            ListedToken storage currentItem = idToListedToken[currentId];
            items[currentIndex] = currentItem;
            currentIndex += 1;
    return items;

function executeSale(uint256 tokenId) public payable {
    uint price = idToListedToken[tokenId].price;
    address seller = idToListedToken[tokenId].seller;
        msg.value == price,
        "Please submit the asking price in order to complete the purchase"

    //update the details of the token
    idToListedToken[tokenId].currentlyListed = true;
    idToListedToken[tokenId].seller = payable(msg.sender);

    //Actually transfer the token to the new owner
    _transfer(address(this), msg.sender, tokenId);
    //approve the marketplace to sell NFTs on your behalf
    approve(address(this), tokenId);
    //fetching royalty info 
    (address recipient, uint256 amount) = royaltyInfo(tokenId, price);
    //transfer royalty amount to the artist
    //Transfer the listing fee to the marketplace creator
    //Transfer the proceeds from the sale to the seller of the NFT

//We might add a resell token function in the future
//In that case, tokens won't be listed by default but users can send a request to actually list a token
//Currently NFTs are listed by default


1 Answer 1


Just use an OR statement for the return. Here's an example:

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) {
        return (ERC721.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId));

Here's a link to OZ forum: https://forum.openzeppelin.com/t/derived-contract-must-override-function-supportsinterface/6315/10

  • I believe the error most likely stems from a missing override up the inheritance line. In the inheritance line, the latest child using supportInterface() should first override the function that is being overriden from the parents contracts, and then ,as you said, define if the input interface is one of the interfaces to be checked with OR statements.
    – Torof
    Aug 11 at 16:27
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Aug 11 at 16:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.