Introspection example mentioned in OZ code comment

In the OZ ERC165 implementation an example is mentioned of how to override the supportInterface method

 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```

My question is regarding the second condition. Why would you want to confirm the support of a given interface if its just the interface of the IERC165 by OZ which only has a single function namely supportInterface()

Something like this seems more useful no?

 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId;
 * }
 * ```

Each contract that implements the ERC-165 standard (or some other standard that extends it, e.g. ERC-721), should return true for supportsInterface(0x01ffc9a7) and false for supportsInterface(0xffffffff).

It is a sign that your contract really implements this specific standard, and that it's not just a coincidence in naming the function.

Hey thanks for the reply. In our case we use it to validate that an address we pass to a function implements a specific interface ( Not just the ERC165 interface). Just implementing the ERC165 interface would not be enough and should not pass the validation

Is our use case maybe not the standard way of using ERC165 standard?

Based on your description, it does seem like a good way of using ERC165.

For example this snippet from the EIP page validates that the Homer class implements the Simpson interface:

interface Simpson {
    function is2D() external returns (bool);
    function skinColor() external returns (string);
}

contract Homer is ERC165, Simpson {
    function supportsInterface(bytes4 interfaceID) external view returns (bool) {
        return
          interfaceID == this.supportsInterface.selector || // ERC165
          interfaceID == this.is2D.selector
                         ^ this.skinColor.selector; // Simpson
    }

    function is2D() external returns (bool){}
    function skinColor() external returns (string){}
}

Applied to your case, your method should return true for 0x01ffc9a7 (ERC165) as well as for the interface ID of MyInterface.

hmm but my point is i dont want it to return true for 0x01ffc9a7 (ERC165) i just want it to return true if the interface ID is MyInterface

I don't think I understand your motivation behind that. But if you want to implement the rest of the standard without showing that you implement the standard (i.e. not fully implementing it), then sure, you can technically do that by not calling the parent method.

Exactly as you mentioned in your question:

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    // purposely omitting the parent method call
    return interfaceId == type(MyInterface).interfaceId;
}

The reason is that we have a registry contract that registers addresses that comply with a given MyInterface. If they comply they get registered in the registry contract. A contract that only implements ERC165 but not my interface should not be registered. Maybe in our case we should not inherit ther ERC165 OZ contract at all and just write our own method without an override:

function supportsInterface(bytes4 interfaceId) public view returns (bool) {
// purposely omitting the parent method call
return interfaceId == type(MyInterface).interfaceId;
}

If you do not return true for 0x01ffc9a7, then you are not following the ERC165 standard. Its that simple.

ERC165 says that a contract that follows it should

  • return true for 0x01ffc9a7
  • return false for 0xffffffff
  • return true for any other interface.

If for some strange reason you are not ok with that, then you should not use ERC165, and should create a different mechanism.

I see thanks for clarifying. Its not for some strange reason i guess we just want to validate contracts that get passed into a function to support a specific interface. So we should never have used the ERC165 standard i suppose. Btw by any other interface you mean not any but those you have specified as MyInterface right?

Any you want to advertize. in your case type(MyInterface).interfaceId.

The reason for ERC165 asking for 0x01ffc9a7 to return true ... is that if someone "just" look for your interface, and doesn't get the value it expects, its not sure if its because the interface is not supported, of because ERC165 is not supported or not working correctly. That is why one should check 0x01ffc9a7 first, if that that returns the expected value, then do the real query.

i see thanks for clarifying. Btw why does the standard specifically say 0xffffffff has to return false?

To detect cases where supportsInterface(bytes4) is not implemented, and there is a fallback function that returns some value. This value would possibly be interpreted as true.

By checking that 0x01ffc9a7 returns true and 0xffffffff returns false, you have some good reason to assume the function that answered is EIP-165 compliant.

I see thanks but what does 0xffffffff stand for apart from being a very high number?

0x00000000 is to specific to be used that way
0xffffffff is type(uint32).max ... its the last/maximum bytes4.

IMO that is a way better choice than using a "random" value