Introspection

This set of interfaces and contracts deal with [type introspection](https://en.wikipedia.org/wiki/Type_introspection) of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract’s interface.

Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. ERC20 tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract declaring its interface can be very helpful in preventing errors.

There are two main ways to approach this.

  • Locally, where a contract implements IERC165 and declares an interface, and a second one queries it directly via ERC165Checker.

  • Globally, where a global and unique registry (IERC1820Registry) is used to register implementers of a certain interface (IERC1820Implementer). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.

Note that, in all cases, accounts simply declare their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see ERC777), but it must not be relied on for security.

Local

IERC165

Interface of the ERC165 standard, as defined in the EIP.

Implementers can declare support of contract interfaces, which can then be queried by others (ERC165Checker).

For an implementation, see ERC165.

supportsInterface(bytes4 interfaceId) → bool

Returns true if this contract implements the interface defined by interfaceId. See the corresponding EIP section to learn more about how these ids are created.

This function call must use less than 30 000 gas.

ERC165

Implementation of the IERC165 interface.

Contracts may inherit from this and call _registerInterface to declare their support of an interface.

constructor()

supportsInterface(bytes4 interfaceId) → bool

Time complexity O(1), guaranteed to always use less than 30 000 gas.

_registerInterface(bytes4 interfaceId)

Registers the contract as an implementer of the interface defined by interfaceId. Support of the actual ERC165 interface is automatic and registering its interface id is not required.

Requirements:

  • interfaceId cannot be the ERC165 invalid interface (0xffffffff).

ERC165Checker

Library used to query support of an interface declared via IERC165.

Note that these functions return the actual result of the query: they do not revert if an interface is not supported. It is up to the caller to decide what to do in these cases.

_supportsERC165(address account) → bool

Returns true if account supports the IERC165 interface,

_supportsInterface(address account, bytes4 interfaceId) → bool

Returns true if account supports the interface defined by interfaceId. Support for IERC165 itself is queried automatically.

_supportsAllInterfaces(address account, bytes4[] interfaceIds) → bool

Returns true if account supports all the interfaces defined in interfaceIds. Support for IERC165 itself is queried automatically.

Batch-querying can lead to gas savings by skipping repeated checks for IERC165 support.

Global

IERC1820Registry

Interface of the global ERC1820 Registry, as defined in the EIP. Accounts may register implementers for interfaces in this registry, as well as query support.

Implementers may be shared by multiple accounts, and can also implement more than a single interface for each account. Contracts can implement interfaces for themselves, but externally-owned accounts (EOA) must delegate this to a contract.

IERC165 interfaces can also be queried via the registry.

For an in-depth explanation and source code analysis, see the EIP text.

setManager(address account, address newManager)

Sets newManager as the manager for account. A manager of an account is able to set interface implementers for it.

By default, each account is its own manager. Passing a value of 0x0 in newManager will reset the manager to this initial state.

Emits a ManagerChanged event.

Requirements:

  • the caller must be the current manager for account.

getManager(address account) → address

Returns the manager for account.

See setManager.

setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer)

Sets the implementer contract as account’s implementer for `interfaceHash.

account being the zero address is an alias for the caller’s address. The zero address can also be used in implementer to remove an old one.

See interfaceHash to learn how these are created.

Emits an InterfaceImplementerSet event.

Requirements:

getInterfaceImplementer(address account, bytes32 interfaceHash) → address

Returns the implementer of interfaceHash for account. If no such implementer is registered, returns the zero address.

If interfaceHash is an IERC165 interface id (i.e. it ends with 28 zeroes), account will be queried for support of it.

account being the zero address is an alias for the caller’s address.

interfaceHash(string interfaceName) → bytes32

Returns the interface hash for an interfaceName, as defined in the corresponding section of the EIP.

updateERC165Cache(address account, bytes4 interfaceId)

implementsERC165Interface(address account, bytes4 interfaceId) → bool

implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) → bool

InterfaceImplementerSet(address account, bytes32 interfaceHash, address implementer)

ManagerChanged(address account, address newManager)

IERC1820Implementer

Interface for an ERC1820 implementer, as defined in the EIP. Used by contracts that will be registered as implementers in the IERC1820Registry.

canImplementInterfaceForAddress(bytes32 interfaceHash, address account) → bytes32

Returns a special value (ERC1820_ACCEPT_MAGIC) if this contract implements interfaceHash for account.

ERC1820Implementer

Implementation of the IERC1820Implementer interface.

Contracts may inherit from this and call _registerInterfaceForAddress to declare their willingness to be implementers. IERC1820Registry.setInterfaceImplementer should then be called for the registration to be complete.

canImplementInterfaceForAddress(bytes32 interfaceHash, address account) → bytes32

_registerInterfaceForAddress(bytes32 interfaceHash, address account)

Declares the contract as willing to be an implementer of interfaceHash for account.