In order to achieve our expressive interface identification scheme we implement EIP-165 in the Extendable Pattern.
The ERC165 standard is used by all Extensions to register and report which interfaces are implemented by them. This enables both ease of runtime introspection to allow users to find out what is implemented by each Extension but also provides us much deeper control over how Extendables manage their Extensions.
ERC165 specifies one main function:
function supportsInterface(bytes4 interfaceId) returns (bool);
registerInterface allows the Extension to be able to register itself as an implementer of a certain interfaceId. This is not limited to just the interfaceId, however, and we extended its use to include function selectors also. Being able to detect which interface is implemented might be helpful to those that know the interface, but for discoverability, it is important that we can report which functions are implemented also.
Once registered, Extensions will return true or false when asked if it supportsInterface for a given bytes4 interfaceId or function selector.
Extension Constructor
During deployment, Extensions execute their constructor function where a registration of its implementation occurs. It uses the very important getInterface() function that is required to be implemented by all Extensions to do this.
constructor() {
Interface[] memory interfaces = getInterface();
for (uint256 i = 0; i < interfaces.length; i++) {
registerInterface(interfaces[i].interfaceId);
for (uint256 j = 0; j < interfaces[i].functions.length; j++) {
registerInterface(interfaces[i].functions[j]);
}
}
registerInterface(type(IExtension).interfaceId);
}
The getInterface() function returns a list of interfaces, and the associated functions within each interface and registers them as implemented one by one. Once registered, any contract can query the Extension using supportsInterface to find out what it implements using the ERC165 interface.
ERC165 Singleton
Each Extension must implement ERC165, but requiring every Extension contract to duplicate this code goes against the principles of Extendable. In order to avoid these problems we abstracted the ERC165 functional logic into a separate contract. This gets referenced by all Extensions whenever an ERC165 function is called.
The ERC165Logic singleton is deployed deterministically at the address 0x99576C1caF6bFc959a1190418027E6F09380d384 on all networks. The singleton is deployed using EIP-2470 Singleton Factory which uses CREATE2 to deploy contracts to predetermined addresses.
If the singleton has not yet been deployed to a network that you are using, use the singleton factory and call the deploy(bytes memory _initcode, bytes32 _salt) function passing in the following parameters: