ERC165Checker; is it required to check support for ERC-165 AND any given interface, or just the latter?

My contract needs to check whether an external contract supports a standard interface, I want the function to be as cheap as possible, therefore my question is; does the checking contract need to detect support for ERC-165 AND the other given interface, or just the latter?

I mean, technically it is possible to implement a supportsInterface function that only returns true for the given interface and not for ERC-165, which would make it non compliant to the standard, but do I really need to check for both?

My contract is an NFT marketplace, therefore NFTs should support eip165 by default; would it be unwise to check directly for support of the particular interface I am interested in? The NatSpec comments above the private _supportsERC165Interface function read:

@dev Assumes that account contains a contract that supports ERC165, otherwise the behavior of this method is undefined.

What's the worse that could happen?

Thank you in advance. Kind regards.

edit: i read the question wrong, so ignore my previous answer.

All your contract wants to know if the other contract supports an interface, so you will only have check if that interface is supported. You do not have to implement ERC-165 yourself.

However if you call supportsInterface on the external contract, then you are already assuming the external contract implements ERC-165 :slight_smile: Which might not be true.

Calling the supportsInterface from ERC165Checker will perform the supportsERC165 check before it check the actual interface you are checking for. So to answer the question in the title, no you do not have to check for ERC-165 itself.
Checking in your contract if the contract supports the interface you are looking for directly instead of using the ERC165Checker might be slightly cheaper however as your check will only perform 1 call instead of 2.

1 Like

Hello @CryptoWorld ! Thank you for your reply.

Checking in your contract if the contract supports the interface you are looking for directly instead of using the ERC165Checker might be slightly cheaper however as your check will only perform 1 call instead of 2.

So why does OZ check for ERC165 as well by default if it is cheaper to just check using the private function:

function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
        (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);
        if (result.length < 32) return false;
        return success && abi.decode(result, (bool));
    }

I have basically copy/pasted that same function and used it internally in my NFT marketplace to check support for ERC2981 royalties standard interface like so:

if ( _supportsERC165Interface(_collection, 0x2a55205a) ) {
  (royaltyReceiver, royaltyAmount) = IERC2981(
      _collection
  ).royaltyInfo(_tokenId, _price);
}

Is this safe?

Best regards,
Cosimo

Sorry for the late reply, swamped with projects atm.

That function unfortunately won't work how you expect it unless the token you are checking implements ERC165 itself.

'bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);'

Is taking the supportsInterface function and adds the function you want to check as a parameter and calls that function on the contract/token you are checking.

If the other contract has the supportsInterface and the function you check for it will return true and otherwise it will return false

You could modify the function using the function you want + the parameters it expect and then compare the result. The function will be called staticly, so no save action is performed.

1 Like

What do you mean it won't work as expected?

The is what I expected, so is it correct? If the supportsInterface function does not exist will it return false or will it throw?

Thanks again

In that case, yes you are correct.

The function should return false when not supported, it shouldn't revert. However you can easily test it to make sure.

Btw, openzeppelin have updated IERC165Checker contract with the function supportsERC165InterfaceUnchecked which does exactly this. However the changes haven't been released yet.

1 Like