0

I've read other similar questions but none of them applies to my smart contract current setup.

Currently I have a working smart contract that only implements ReentrancyGuard.

Here below an snippet of this code for major reference about what works:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "hardhat/console.sol";

contract NFTMarket is ReentrancyGuard {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIds;
    Counters.Counter private _tokensSold;

    address payable owner;

    uint256 listingPrice = 0.025 ether;

    constructor() {
        owner = payable(msg.sender);
    }

    struct MarketToken {
        uint256 itemId;
        address nftContract;
        uint256 tokenId;
        address payable seller;
        address payable owner;
        uint256 price;
        bool sold;
    }

    mapping(uint256 => MarketToken) private idToMarketToken;

    event MarketTokenMinted(
        uint256 indexed itemId,
        address indexed nftContract,
        uint256 indexed tokenId,
        address seller,
        address owner,
        uint256 price,
        bool sold
    );

    function makeMarketItem(
        address nftContract,
        uint256 tokenId,
        uint256 price
    ) public payable nonReentrant {
        // nonReentrant is a modifier to prevent reentry attack.

        require(price > 0, "Price must be at least one wei");
        require(
            msg.value == listingPrice,
            "Price must be equal to listing price"
        );

        _tokenIds.increment();
        uint256 itemId = _tokenIds.current();

        idToMarketToken[itemId] = MarketToken(
            itemId,
            nftContract,
            tokenId,
            payable(msg.sender),
            payable(address(0)),
            price,
            false
        );

        // NFT transaction.
        IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);

        emit MarketTokenMinted(
            itemId,
            nftContract,
            tokenId,
            msg.sender,
            address(0),
            price,
            false
        );
    }

// ...

Since it is discouraged to use transferFrom() as how this contract code from above has currently implemented inside the function makeMarketItem(), I wanted to update that line to use instead safeTransferFrom(), but in order for this new function to work properly my contract has to implement as well IERC721Receiver. However when I do add it along with ReentrancyGuard, I'll get the error "Contract "NFTMarket" should be marked as abstract".

Down below the code that produces the error:

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "hardhat/console.sol";

contract NFTMarket is IERC721Receiver, ReentrancyGuard {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIds;
    Counters.Counter private _tokensSold;

    address payable owner;

    uint256 listingPrice = 0.025 ether;

    constructor() {
        owner = payable(msg.sender);
    }

    struct MarketToken {
        uint256 itemId;
        address nftContract;
        uint256 tokenId;
        address payable seller;
        address payable owner;
        uint256 price;
        bool sold;
    }

    mapping(uint256 => MarketToken) private idToMarketToken;

    event MarketTokenMinted(
        uint256 indexed itemId,
        address indexed nftContract,
        uint256 indexed tokenId,
        address seller,
        address owner,
        uint256 price,
        bool sold
    );

    function makeMarketItem(
        address nftContract,
        uint256 tokenId,
        uint256 price
    ) public payable nonReentrant {
        // nonReentrant is a modifier to prevent reentry attack.

        require(price > 0, "Price must be at least one wei");
        require(
            msg.value == listingPrice,
            "Price must be equal to listing price"
        );

        _tokenIds.increment();
        uint256 itemId = _tokenIds.current();

        idToMarketToken[itemId] = MarketToken(
            itemId,
            nftContract,
            tokenId,
            payable(msg.sender),
            payable(address(0)),
            price,
            false
        );

        // NFT transaction.
        IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId);

        emit MarketTokenMinted(
            itemId,
            nftContract,
            tokenId,
            msg.sender,
            address(0),
            price,
            false
        );
    }

// ...

What I'm missing or how is the right way to set this up correctly?

2 Answers 2

0

Since you are inheriting from the interface IERC721Receiver you should implement the function onERC721Received.

The comments in the file indicate the expected behavior

function onERC721Received(
    address operator,
    address from,
    uint256 tokenId,
    bytes calldata data
) external returns (bytes4) {
    // ... do something inside the safeTransferFrom

    // Required to not revert
    return IERC721Receiver.onERC721Received.selector;
}
-2

Not sure if you still have this issue, but I just had the same problem and finally figured out why.

The problem isn't IERC721Receiver, the problem is that you are importing ERC721.sol, which also imports IERC721.sol, and this file has the root of the problem, as it then imports IERC165.sol enter image description here

interface IERC721 is IERC165

If we look at IERC165.sol, it only has one function:

function supportsInterface(bytes4 interfaceId) external view returns (bool);

Which if not implemented withing your NFTMarket contract, will give you the error 'Contract "NFTMarket" should be marked as abstract'

The solution is to just edit the IERC721 file so that it doesn't import IERC165.sol and doesn't implement it as part of the IERC721 interface:enter image description here

If you close out your NFTMarket.sol and re-open it, the error should be gone and you can then compile as normal.

Alternatively you can add the following to your contract without changing the IERC721.sol file and it should also get rid of the error:

import "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";

and then

contract NFTMarket is IERC721Receiver, ERC165Storage, ReentrancyGuard {

where ERC165Storage overrides the missing function from IERC165.sol and makes the compiler happy.

4
  • 1
    Locally editing an import is a super poor practice, anyone wanting to reuse the code or reproduce the test (including your CI) will then have the same original error. Instead, implement IERC165 (if you don't add interface you want to officially support, you can just override it by calling super, as in (pseudo-pseudocode): function supportsInterface(interfaceId) { super.supportsInterace(interfaceId); } ) May 21, 2022 at 12:14
  • 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
    May 21, 2022 at 12:14
  • @DrGorilla.eth as a relative newbie in this space, I am just trying to help this person get around the error they are experiencing. Yes, editing the import file is bad practice, which is why I offered a second solution, which is very similar to the solution you offered. This question was asked a month ago and with no solutions offered I stepped in, only to get downvoted lol. Why bother then
    – node zy
    May 24, 2022 at 17:11
  • The edit you made is another sub-optimal solution - importing and inheriting code you don't need to fix a compilation error is basically wasting gas for nothing. Don't take down-voting personally, it just flag your answer as "not so good" for other people bumping into it. I've posted the solution in comment. May 25, 2022 at 19:33

Your Answer

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

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