0

We can interact with a contract that we have a sample of. To make it clear, please see how Proxy contract interact with Name contract in this response.

In my scenario, I want to check if the msg.sender is the owner of an NFT. So, I'm trying to interact with any ERC721 contract using the same way instead direct contract call. Like this:

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

import "@openzeppelin/contracts@4.5.0/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts@4.5.0/token/ERC721/IERC721.sol";

contract Market { function putOnSale(address _nftContract, uint256 _tokenId, uint256 _price) public payable { address tokenOwner = ERC721(_nftContract).ownerOf(_tokenId); // ??? require(tokenOwner == msg.sender, 'Only owner...');

    // Rest of the code...
}

}

However, I'm getting this error when I call putOnSale method:

transact to Market.putOnSale errored: VM error: revert.

revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

Can't I interact with another ERC721 contract using this way?

Note: I'm doing this all in Remix IDE JavaScript VM.

Thanks in advance!

anileates
  • 17
  • 5
  • Try to inject into Testnet and test it. I tried on Rinkeby testnet and it works! – Antonio Carito Mar 21 '22 at 14:31
  • @Kerry99 did you mean injected Web3? I tried but it didn't work. – anileates Mar 21 '22 at 16:46
  • Are you trying to send any Ether when you call putOnSale? If not, that's what flagging your error. You only want to declare a method payable if you intend on directly sending Ether (specifically, not any other ERC-20) to it. – Joe Habel Mar 22 '22 at 01:10
  • Yes, I'm sending Ether on call. I tried to remove payable and call without Ether also. @JoeHabel – anileates Mar 22 '22 at 06:13

1 Answers1

0

In what little you've provided, the only thing I can see is that you're using the contract where you should be using the interface. i.e. This line:

   address tokenOwner = ERC721(_nftContract).ownerOf(_tokenId); // ???

should be:

    address tokenOwner = IERC721(_nftContract).ownerOf(_tokenId)

If you're not coming from a language where you're used to working with pointers, the difference between these two likely is pretty confusing. In short, you use:

  • The interface when you want to call out to an already deployed contract (IERC721).
  • The contract when you want to deploy a new contract (ERC721).

What you have written now reads like you're trying to deploy a new ERC721 contract, with _nftContract as the name, and then immediately ask for the owner of the given token. The problem here is that according to OpenZepplin's ERC721 API docs, this method requires that the tokenId exists. Since you haven't minted any tokens at this point, this is going to revert the transaction.

If you're still new to Solidity and aren't entirely sure of these things, I recommend avoiding any initial temptation to reduce code down to one liners. You'll find that sometimes VM error: revert is all the more insight that you'll get from the EVM error message. If you have multiple function calls on line, this can be harder to think through.

Writing this as:

    IERC721 nft = IERC721(_nftContract);
    address tokenOwner = nft.ownerOf(_tokenId);

or when deploying new contracts, like this:

    ERC721 nft = new ERC721(_nftName, _nftSymbol);
    nft.mint(msg.sender, _tokenId);

can make it easier to know exactly where things are going wrong, especially since you might not know if the address coming through actually is an ERC721.

Joe Habel
  • 116
  • 2
  • Thank you for the great explanation and information, @Joe Habel! You saved me. I tested your suggestions and I found the solution. But, the problem is not about using or not using the interface. In both cases, I can interact with the contract I want. But make sure that contract is in the same chain, I mean, it must be in the Rinkeby for example as we're working in Rinkeby. :) I was trying to call a main-net contract, so there is no contract to interact with. I recognized it after I write the code in multiple lines. – anileates Mar 23 '22 at 14:29