ERC-820 Pseudo-introspection registry (Pseudo-introspection Registry Contract)
Final · Other · created 2018-01-05
Defines a universal registry where any address, whether a contract or a regular account, can register which interfaces it supports and which contract is responsible for implementing them, and anyone can look this up.
Why it is needed
Existing ways to find out "which functions does this address support" on Ethereum had limits. ERC-165 has a contract answer for itself which interfaces it supports, so regular accounts with no code (wallet addresses used by people) cannot use it at all. Another attempt, ERC-672, used a reverse name service (reverse ENS), but it was needlessly complex and ENS itself is a centralized contract controlled by a multisig. There was also no way to make contracts whose code cannot be changed, such as already deployed multisigs or DAOs, support a new interface. If the registry address differs per chain, finding the correct address also becomes a problem. This standard solves these problems by deploying a single fully decentralized registry at the same address on every chain.
What to implement
function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address): Looks up whether an address supports a given interface and which contract implements it. If there is no registration, it returns 0x0.function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external: Registers the contract that implements an interface for a given address. Only that address's manager can call it.function setManager(address _addr, address _newManager) external: Changes an address's manager to a new address. The new manager gains the authority to register interfaces for that address.function getManager(address _addr) public view returns(address): Returns the manager of an address. If none was set, the address itself is its manager.function interfaceHash(string _interfaceName) external pure returns(bytes32): Computes the keccak256 hash of an interface name string onchain.function updateERC165Cache(address _contract, bytes4 _interfaceId) external: Updates the cache with whether a contract implements an ERC-165 interface. Anyone can call it.function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool): Checks whether a contract implements an ERC-165 interface. If a cache exists, it uses the cache.function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool): Directly checks whether a contract implements an ERC-165 interface, without reading or updating the cache.function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32): Returns the ERC820_ACCEPT_MAGIC value only if the proxy implementation contract implements the interface for the given address.event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);: Signals that a contract was registered as the interface implementer for an address.event ManagerChanged(address indexed addr, address indexed newManager);: Signals that an address's manager was changed to a new address.
In depth
Interface names and hash rules
An interface is identified by the keccak256 hash of its name string. For the interface of an approved ERC, the name must be in the form ERC###XXXXX (### is the ERC number and XXXXX is the CamelCase interface name). Examples are keccak256("ERC20Token"), keccak256("ERC777Token"), keccak256("ERC777TokensSender") and keccak256("ERC777TokensRecipient"). Anyone can create and use their own interface names, but they must not conflict with the reserved naming convention. The hash can also be computed onchain with the registry's interfaceHash(string _interfaceName) function.
Registration rules and ERC820_ACCEPT_MAGIC
setInterfaceImplementer can only be called by the manager of that address. If _addr is 0 it is treated as msg.sender, which makes the transaction data to sign the same regardless of the multisig instance address and so simplifies using a multisig. If _addr and _implementer differ, _implementer must implement ERC820ImplementerInterface, and the registration succeeds only if the call to canImplementInterfaceForAddress(interfaceHash, addr) returns ERC820_ACCEPT_MAGIC (the keccak256 hash of the string "ERC820_ACCEPT_MAGIC"). The reason for using a magic value instead of a boolean is to prevent a false positive in which the fallback function of a contract that does not implement the function runs without an exception and returns 1, which would look as if it returned true. _interfaceHash must not be an ERC-165 interface (last 28 bytes are 0).
Manager system
Only the manager of an address can register that address's interface implementer. By default every address is its own manager. With setManager(_addr, _newManager) the manager authority can be handed to another address, and the new manager can then call setInterfaceImplementer for that address. Setting _newManager to 0x0 returns the manager to _addr itself. getManager looks up the current manager.
ERC-165 compatibility and cache
If the last 28 bytes of the hash are 0, it is treated as an ERC-165 interface. In this case getInterfaceImplementer treats the first 4 bytes as the ERC-165 interface ID and asks the contract directly to check for support. The registry caches ERC-165 lookup results to save gas, and there is no automatic refresh or invalidation. If a contract changes its interfaces dynamically and relies on this cache, it must refresh manually by calling updateERC165Cache, and anyone can refresh on behalf of another contract. A lookup that bypasses the cache uses implementsERC165InterfaceNoCache. This standard is backward compatible with ERC-165, and the ERC-165 compatible part was designed together with William Entriken.
Keyless deployment gives the same address on every chain
The registry is deployed using a keyless deployment method with a single-use address (Nick's method). The deployment transaction does not use EIP-155 so that it can be replayed on any chain, and the gas price is set high at 100 Gwei. The signature has v set to 27 and r and s set to a repeating 820 pattern, which are human-chosen values, so it is guaranteed that no one knows the private key of the single-use deployment account (0xE6C244a1C10Aa0085b0cf92f04cdaD947C2988b8) recovered from this signature. If you first send exactly 0.08 ether to this account and then broadcast the transaction, the registry address is the same on every chain, 0x820b586C8C28125366C998641B09DCbE7d4cBF06, and no one can place another contract at that address.
ERC-1820 supersedes this standard
According to the notice at the top of the original text, ERC-1820 supersedes ERC-820. ERC-1820 fixes an incompatibility in the ERC-165 logic that arose from the Solidity 0.5 update, and apart from that fix it is functionally identical to ERC-820. The original states that ERC-1820 must be used instead of ERC-820. The status of this document is Final, but new implementations should follow ERC-1820.