Introspection
Outdated Version
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
IERC165
and 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.
Functions
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.
Functions
constructor() *internal*
supportsInterface(bytes4 interfaceId) → bool *public*
See IERC165-supportsInterface.
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.
See IERC165-supportsInterface.
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.
Functions
supportsERC165(account)
supportsInterface(account, interfaceId)
getSupportedInterfaces(account, interfaceIds)
supportsAllInterfaces(account, interfaceIds)
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.
See IERC165-supportsInterface.
getSupportedInterfaces(address account, bytes4[] interfaceIds) → bool[] *internal*
Returns a boolean array where each value corresponds to the interfaces passed in and whether they’re supported or not. This allows you to batch check interfaces for a contract where your expectation is that some interfaces may not be supported.
See IERC165-supportsInterface.
Available since v3.4.
supportsAllInterfaces(address account, bytes4[] interfaceIds) → bool *internal*
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.
See IERC165-supportsInterface.
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.
Functions
setManager(account, newManager)
getManager(account)
setInterfaceImplementer(account, _interfaceHash, implementer)
getInterfaceImplementer(account, _interfaceHash)
interfaceHash(interfaceName)
updateERC165Cache(account, interfaceId)
implementsERC165Interface(account, interfaceId)
implementsERC165InterfaceNoCache(account, interfaceId)
Events
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
.
getManager(address account) → address *external*
Returns the manager for account
.
See setManager.
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
. interfaceHash
must not be an IERC165 interface id (i.e. it must not end in 28 zeroes).implementer
must implement IERC1820Implementer and return true when queried for support, unlessimplementer
is the caller. See IERC1820Implementer-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.
updateERC165Cache(address account, bytes4 interfaceId) *external*
implementsERC165Interface(address account, bytes4 interfaceId) → bool *external*
implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) → bool *external*
InterfaceImplementerSet(address account, bytes32 interfaceHash, address implementer) *event*
ManagerChanged(address account, address newManager) *event*
IERC1820Implementer
Interface for an ERC1820 implementer, as defined in the EIP. Used by contracts that will be registered as implementers in the IERC1820Registry.
Functions
canImplementInterfaceForAddress(bytes32 interfaceHash, address account) → bytes32 *external*
Returns a special value (ERC1820_ACCEPT_MAGIC
) if this contract
implements interfaceHash
for account
.
See IERC1820Registry-setInterfaceImplementer.
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.
Functions
canImplementInterfaceForAddress(interfaceHash, account)
_registerInterfaceForAddress(interfaceHash, account)
canImplementInterfaceForAddress(bytes32 interfaceHash, address account) → bytes32 *public*
_registerInterfaceForAddress(bytes32 interfaceHash, address account) *internal*
Declares the contract as willing to be an implementer of
interfaceHash
for account
.
See IERC1820Registry-setInterfaceImplementer and IERC1820Registry-interfaceHash.