Skip to main content

ERC165

Component help Contract to creates a standard method to publish and detect what interfaces a smart contract implements.

The details of the ERC165 can see ERC165.

In ink!, the message interface id is same to EVM, so we make a marco to help develop to impl the erc165.

Dependency#

no additional dependency other than metis_lang

Usage Example#

For example, a contract looks like:

    impl Flipper {        /// Creates a new flipper smart contract initialized with the given value.        #[ink(constructor)]        pub fn new(init_value: bool) -> Self {            Self { value: init_value }        }
        /// Creates a new flipper smart contract initialized to `false`.        #[ink(constructor)]        pub fn default() -> Self {            Self::new(Default::default())        }
        /// Flips the current value of the Flipper's bool.        #[ink(message)]        pub fn flip(&mut self) {            // logics        }
        /// Flips set the current value        #[ink(message)]        pub fn set(&mut self, value: bool) {            // logics        }
        /// Returns the current value of the Flipper's bool.        #[ink(message)]        pub fn get(&self) -> bool {            // logics        }    }

We can define a interface contains get and set message, so the supports_interface should be:

        impl Flipper {            fn supports_interface(&self, interface_id: u32) -> bool {                match interface_id {                    0x633aa551_u32 ^ 0x2f865bd9_u32 => true, // get and set                    0xe6113a8a_u32 => true, // supports_interface                    _ => false,                }            }        }

Note if impl supports_interface then also support the interface of erc165 self, so the 0xe6113a8a_u32 should also true.

The erc165 marco help us to impl the supports_interface message:

    #[metis::supports(interface(new, default), interface(flip, get))]    impl Flipper {        /// Return the contract is support the interface_id        #[ink(message)]        pub fn supports_interface(&self, interface_id: u32) -> bool {            // _supports_interface gen by marco            self._supports_interface(interface_id)        }    }

The code above is equivalent to:

    impl Flipper {        fn _supports_interface(&self, interface_id: u32) -> bool {            const INIT_INTERFACE_ID: u32 = 0x9bae9d5e_u32 ^ 0xed4b9d1b_u32;            const FLIP_INTERFACE_ID: u32 = 0x633aa551_u32 ^ 0x2f865bd9_u32;
            match interface_id {                INIT_INTERFACE_ID => true, // new and default                FLIP_INTERFACE_ID => true, // flip get                0xe6113a8a_u32 => true, // supports_interface                _ => false,            }        }
        /// Return the contract is support the interface_id        #[ink(message)]        pub fn supports_interface(&self, interface_id: u32) -> bool {            self._supports_interface(interface_id)        }    }

The marco will not make supports_interface but a generic _supports_interface for developer to impl supports_interface.

The marco looks like:

    #[metis::supports(interface(new, default), interface(flip, get))]    impl Flipper {}

For a contract, it will support multi interfaces, so there is a array of interfaces, which contains the required message name.

Note: if use marco, the contract will support the supports_interface interface(0xe6113a8a_u32) auto.