Remix: IERC721 ownerOf() Function Infinite Gas Costs

Hi, i wanted to make a smart contract which checks if a specific address has a specific NFT. I already created the NFT and my Code in the Goerli Testnet. But when i want to run my function it gives me an Error, probably because in remix, next to my function, it says Infinite Gas Costs.

Here's the Error:

call to NFTChecker.checkNFT 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.

Here's my Code:

pragma solidity ^0.8.8;


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

contract NFTChecker {
    function checkNFT(address _wallet, address _nftContractAddress, uint256 _tokenId) public view returns (bool) {
        IERC721 nftContract = IERC721(_nftContractAddress);
        return (nftContract.ownerOf(_tokenId) == _wallet);
    }
}

Looks like the call you are making also sends eth and as your function does not include the payable keyword it fails.

So make sure you call the function without.

Hey @fabs2901,

The reason it shows Infinite Gas Costs is because Remix runs an estimation for the function. However, the estimation is usually a binary search trying to find the value in which a call doesn't revert. If it reverts, the estimation goes to infinity.

In regards to why it's reverting, it's because the call to an arbitrary address will fail if it doesn't implement the interface of ERC721 correctly or if it's not a contract.

I suggest you use the Address utility from our contracts library, so you can bubble up the revert reason and get a better sense of what's going on. It will also return true if the _wallet is indeed the owner.

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

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

contract NFTChecker {
    using Address for address;

    function checkNFT(
        address _wallet,
        address _nftContractAddress,
        uint256 _tokenId
    ) public view returns (bool) {
        bytes memory returnData = _nftContractAddress.functionStaticCall(
            abi.encodeCall(IERC721.ownerOf, (_tokenId))
        );
        address owner = abi.decode(returnData, (address));
        return owner == _wallet;
    }
}

Alternatively, you can also check first check if the target contract correctly implements the IERC721 interface by using the ERC165Checker.