1

While testing ERC-721 implementation from https://github.com/m0t0k1ch1/ERC721-token-sample/blob/master/contracts/MyNonFungibleToken.sol and trying to query the method supportsInterface I got the expected result in this case:

// bytes4(keccak256('supportsInterface(bytes4)')) = 01ffc9a7
supportsInterface(0x01ffc9a7);
    bool: true

But not in this other case:

// Checking for example support for function tokensOfOwner()
supportsInterface(0x8462151c);
    bool: false

Any idea why returns false on second case? If worng, how should I properly query the function? Thx!

5

The supportsInterface shouldn't be used to check individual functions, each interface should have a single interfaceID, which as you see in the ERC-721 implementation you posted, is constructed as follows

bytes4 constant InterfaceID_someInterface =
    bytes4(keccak256('function1(address)')) ^
    bytes4(keccak256('function2(uint,etc)')) ^
    ...
    bytes4(keccak256('functionN()'));

In the case of the ERC165 interface, there is only one function in that interface, supportsInterface, so the interfaceID is just

bytes4 constant InterfaceID_ERC165 =
    bytes4(keccak256('supportsInterface(bytes4)'));
//0x01ffc9a7

But its important to note that when you call supportsInterface on 0x01ffc9a7 you are testing to see if your contract supports the whole ERC165 standard. It just so happens that that is only one function.

So you shouldn't be calling supportsInterface on 0x8462151c, this would checking be for an interface which only contained the function tokensOfOwner().

In stead you should be checking against the InterfaceID of the whole ERC721 interface. If your contract supports the whole interface, then by definition it will support any of the functions contained therein.

The idea is that anyone can find the specification for the interface, and just check the interfaceId of that interface against your contract.

BUT, there are two problems with the implementation posted. First of all, they didn't provide the ERC721 or 165 interfaces. They just provided an abstract contract which contains a few related functions. So they didn't really give the thing you should be checking against.

Also, I don't think this implementation is an up-to-date or proper implementation of ERC721. The standard is still a work in progress, but you can see the non-finalised standard here.

There are actually interfaces for 3 standards here:

ERC721 (0x80ac58cd)

ERC721Metadata (0x5b5e139f) (optional)

ERC721Enumerable (0x780e9d63) (optional)

ERC721 just implements the basic requirements of a NFT, ERC721Metadata adds name, symbol and URI data functionality, and ERC721Enumerable adds some other functionality to do with token indexes.

Why this is relevant to what you posted is because basic ERC721 does not implement any of the following:

name() (this is from ERC721Metadata)

symbol() (this is from ERC721Metadata)

totalSupply() (this is from ERC721Enumerable)

transfer(address,uint256) (this is from ERC20 spec, 721 uses transferFrom and safeTransferFrom)

tokensOfOwner(address) (not part of the standards).

There are also some functions in the standard which you will see aren't implemented in the one you provided. It's likely that it was written when the standard was at a much earlier age. And indeed, this sort of situation is partially the purpose of the ERC165 specification.

If standards are developing and evolving over time, then ERC721 version 0.0.1 (a number I just made up) may have an interfaceId of 0x9f40b779 (which is the value of InterfaceID_ERC721 in the contract you provided). However version 0.0.2 may add, change or remove a function, which would completely change the interfaceID to something else. So as long as you specify that your contract complies to ERC721 0.0.1, someone else can look up the interface, and check it against your contract.

So the very short answer to your question is, you shouldn't be checking supportsInterface against a single function, but rather against the whole interface.

But I also don't think you should be using the contract you provided because it seems out of date, and the whole purpose of standards is to be compliant.

  • Great answer. FYI, in the future we are considering whether to add an erc165 calculator directly into Solidity. Then you could use ERC721Enumerable.interfaceId. – William Entriken Jan 21 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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