Introspection
| This document is better viewed at https://docs.openzeppelin.com/contracts/api/introspection |
This set of interfaces and contracts deal with 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
IERC165and declares an interface, and a second one queries it directly viaERC165Checker. -
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 external
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.
supportsInterface(bytes4 interfaceId) → bool public
Time complexity O(1), guaranteed to always use less than 30 000 gas.
_registerInterface(bytes4 interfaceId) internal
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:
-
interfaceIdcannot 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 internal
Returns true if account supports the IERC165 interface,
supportsInterface(address account, bytes4 interfaceId) → bool internal
Returns true if account supports the interface defined by
interfaceId. Support for IERC165 itself is queried automatically.
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) external
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.
setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external
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:
-
the caller must be the current manager for
account. -
interfaceHashmust not be anIERC165interface id (i.e. it must not end in 28 zeroes). -
implementermust implementIERC1820Implementerand return true when queried for support, unlessimplementeris the caller. SeeIERC1820Implementer.canImplementInterfaceForAddress.
getInterfaceImplementer(address account, bytes32 _interfaceHash) → address external
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 external
Returns the interface hash for an interfaceName, as defined in the
corresponding
section of the EIP.
IERC1820Implementer
Interface for an ERC1820 implementer, as defined in the
EIP.
Used by contracts that will be registered as implementers in the
IERC1820Registry.
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.