git.delta.rocks / unique-network / refs/commits / 4efa9ce62081

difftreelog

doc(pallet-evm-contract-helpers): document public api

Yaroslav Bolyukin2022-07-12parent: #c098935.patch.diff
in: master

7 files changed

addedpallets/evm-contract-helpers/README.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/evm-contract-helpers/README.md
@@ -0,0 +1,13 @@
+# EVM Contract Helpers
+
+This pallet extends pallet-evm contracts with several new functions.
+
+## Overview
+
+Evm contract helpers pallet provides ability to
+
+- Tracking and getting of user, which deployed contract
+- Sponsoring EVM contract calls (Make transaction calls to be free for users, instead making them being paid from contract address)
+- Allowlist access mode
+
+As most of those functions are intented to be consumed by ethereum users, only API provided by this pallet is [ContractHelpers magic contract](./src/stubs/ContractHelpers.sol)
\ No newline at end of file
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! Implementation of magic contract
+
 use core::marker::PhantomData;
 use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};
@@ -31,7 +33,8 @@
 use up_sponsorship::SponsorshipHandler;
 use sp_std::vec::Vec;
 
-struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
+/// See [`ContractHelpersCall`]
+pub struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
 impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
 	fn recorder(&self) -> &SubstrateRecorder<T> {
 		&self.0
@@ -42,21 +45,24 @@
 	}
 }
 
+/// @title Magic contract, which allows users to reconfigure other contracts
 #[solidity_interface(name = ContractHelpers)]
 impl<T: Config> ContractHelpers<T>
 where
 	T::AccountId: AsRef<[u8; 32]>,
 {
-	/// Get contract ovner
-	///
-	/// @param contractAddress contract for which the owner is being determined.
-	/// @return Contract owner.
+	/// Get user, which deployed specified contract
+	/// @dev May return zero address in case if contract is deployed
+	///  using uniquenetwork evm-migration pallet, or using other terms not
+	///  intended by pallet-evm
+	/// @dev Returns zero address if contract does not exists
+	/// @param contractAddress Contract to get owner of
+	/// @return address Owner of contract
 	fn contract_owner(&self, contract_address: address) -> Result<address> {
 		Ok(<Owner<T>>::get(contract_address))
 	}
 
 	/// Set sponsor.
-	///
 	/// @param contractAddress Contract for which a sponsor is being established.
 	/// @param sponsor User address who set as pending sponsor.
 	fn set_sponsor(
@@ -163,6 +169,7 @@
 		&mut self,
 		caller: caller,
 		contract_address: address,
+		// TODO: implement support for enums in evm-coder
 		mode: uint8,
 	) -> Result<void> {
 		self.recorder().consume_sload()?;
@@ -175,10 +182,21 @@
 		Ok(())
 	}
 
-	fn sponsoring_mode(&self, contract_address: address) -> Result<uint8> {
-		Ok(<Pallet<T>>::sponsoring_mode(contract_address).to_eth())
+	/// Get current contract sponsoring rate limit
+	/// @param contractAddress Contract to get sponsoring mode of
+	/// @return uint32 Amount of blocks between two sponsored transactions
+	fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
+		Ok(<SponsoringRateLimit<T>>::get(contract_address)
+			.try_into()
+			.map_err(|_| "rate limit > u32::MAX")?)
 	}
 
+	/// Set contract sponsoring rate limit
+	/// @dev Sponsoring rate limit - is a minimum amount of blocks that should
+	///  pass between two sponsored transactions
+	/// @param contractAddress Contract to change sponsoring rate limit of
+	/// @param rateLimit Target rate limit
+	/// @dev Only contract owner can change this setting
 	fn set_sponsoring_rate_limit(
 		&mut self,
 		caller: caller,
@@ -190,57 +208,70 @@
 
 		<Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;
 		<Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());
-
 		Ok(())
 	}
 
-	fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
-		Ok(<SponsoringRateLimit<T>>::get(contract_address)
-			.try_into()
-			.map_err(|_| "rate limit > u32::MAX")?)
-	}
-
+	/// Is specified user present in contract allow list
+	/// @dev Contract owner always implicitly included
+	/// @param contractAddress Contract to check allowlist of
+	/// @param user User to check
+	/// @return bool Is specified users exists in contract allowlist
 	fn allowed(&self, contract_address: address, user: address) -> Result<bool> {
 		self.0.consume_sload()?;
 		Ok(<Pallet<T>>::allowed(contract_address, user))
 	}
 
-	fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
-		Ok(<AllowlistEnabled<T>>::get(contract_address))
-	}
-
-	fn toggle_allowlist(
+	/// Toggle user presence in contract allowlist
+	/// @param contractAddress Contract to change allowlist of
+	/// @param user Which user presence should be toggled
+	/// @param isAllowed `true` if user should be allowed to be sponsored
+	///  or call this contract, `false` otherwise
+	/// @dev Only contract owner can change this setting
+	fn toggle_allowed(
 		&mut self,
 		caller: caller,
 		contract_address: address,
-		enabled: bool,
+		user: address,
+		is_allowed: bool,
 	) -> Result<void> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
 		<Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;
-		<Pallet<T>>::toggle_allowlist(contract_address, enabled);
+		<Pallet<T>>::toggle_allowed(contract_address, user, is_allowed);
 
 		Ok(())
 	}
 
-	fn toggle_allowed(
+	/// Is this contract has allowlist access enabled
+	/// @dev Allowlist always can have users, and it is used for two purposes:
+	///  in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
+	///  in case of allowlist access enabled, only users from allowlist may call this contract
+	/// @param contractAddress Contract to get allowlist access of
+	/// @return bool Is specified contract has allowlist access enabled
+	fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
+		Ok(<AllowlistEnabled<T>>::get(contract_address))
+	}
+
+	/// Toggle contract allowlist access
+	/// @param contractAddress Contract to change allowlist access of
+	/// @param enabled Should allowlist access to be enabled?
+	fn toggle_allowlist(
 		&mut self,
 		caller: caller,
 		contract_address: address,
-		user: address,
-		is_allowed: bool,
+		enabled: bool,
 	) -> Result<void> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
 		<Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;
-		<Pallet<T>>::toggle_allowed(contract_address, user, is_allowed);
-
+		<Pallet<T>>::toggle_allowlist(contract_address, enabled);
 		Ok(())
 	}
 }
 
+/// Implements [`OnMethodCall`], which delegates call to [`ContractHelpers`]
 pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);
 impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T>
 where
@@ -283,6 +314,7 @@
 	}
 }
 
+/// Hooks into contract creation, storing owner of newly deployed contract
 pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);
 impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {
 	fn on_create(owner: H160, contract: H160) {
@@ -290,6 +322,7 @@
 	}
 }
 
+/// Bridge to pallet-sponsoring
 pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);
 impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>
 	for HelpersContractSponsoring<T>
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
before · pallets/evm-contract-helpers/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use codec::{Decode, Encode, MaxEncodedLen};20pub use pallet::*;21pub use eth::*;22use scale_info::TypeInfo;23pub mod eth;2425#[frame_support::pallet]26pub mod pallet {27	pub use super::*;28	use frame_support::pallet_prelude::*;29	use pallet_evm_coder_substrate::DispatchResult;30	use sp_core::H160;31	use pallet_evm::account::CrossAccountId;32	use up_data_structs::SponsorshipState;3334	#[pallet::config]35	pub trait Config:36		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config37	{38		type ContractAddress: Get<H160>;39		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;40	}4142	#[pallet::error]43	pub enum Error<T> {44		/// This method is only executable by owner.45		NoPermission,4647		/// No pending sponsor for contract.48		NoPendingSponsor,49	}5051	#[pallet::pallet]52	#[pallet::generate_store(pub(super) trait Store)]53	pub struct Pallet<T>(_);5455	/// Store owner for contract.56	///57	/// * **Key** - contract address.58	/// * **Value** - owner for contract.59	#[pallet::storage]60	pub(super) type Owner<T: Config> =61		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;6263	#[pallet::storage]64	#[deprecated]65	pub(super) type SelfSponsoring<T: Config> =66		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;6768	/// Store for contract sponsorship state.69	///70	/// * **Key** - contract address.71	/// * **Value** - sponsorship state.72	#[pallet::storage]73	pub(super) type Sponsoring<T: Config> = StorageMap<74		Hasher = Twox64Concat,75		Key = H160,76		Value = SponsorshipState<T::CrossAccountId>,77		QueryKind = ValueQuery,78	>;7980	/// Store for sponsoring mode.81	///82	/// ### Usage83	/// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).84	///85	/// * **Key** - contract address.86	/// * **Value** - [`sponsoring mode`](SponsoringModeT).87	#[pallet::storage]88	pub(super) type SponsoringMode<T: Config> =89		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;9091	/// Storage for sponsoring rate limit in blocks.92	///93	/// * **Key** - contract address.94	/// * **Value** - amount of sponsored blocks.95	#[pallet::storage]96	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<97		Hasher = Twox128,98		Key = H160,99		Value = T::BlockNumber,100		QueryKind = ValueQuery,101		OnEmpty = T::DefaultSponsoringRateLimit,102	>;103104	/// Storage for last sponsored block.105	///106	/// * **Key1** - contract address.107	/// * **Key2** - sponsored user address.108	/// * **Value** - last sponsored block number.109	#[pallet::storage]110	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<111		Hasher1 = Twox128,112		Key1 = H160,113		Hasher2 = Twox128,114		Key2 = H160,115		Value = T::BlockNumber,116		QueryKind = OptionQuery,117	>;118119	/// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.120	///121	/// ### Usage122	/// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.123	///124	/// * **Key** - contract address.125	/// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.126	#[pallet::storage]127	pub(super) type AllowlistEnabled<T: Config> =128		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;129130	/// Storage for users that allowed for sponsorship.131	///132	/// ### Usage133	/// Prefer to delete record from storage if user no more allowed for sponsorship.134	///135	/// * **Key1** - contract address.136	/// * **Key2** - user that allowed for sponsorship.137	/// * **Value** - allowance for sponsorship.138	#[pallet::storage]139	pub(super) type Allowlist<T: Config> = StorageDoubleMap<140		Hasher1 = Twox128,141		Key1 = H160,142		Hasher2 = Twox128,143		Key2 = H160,144		Value = bool,145		QueryKind = ValueQuery,146	>;147148	impl<T: Config> Pallet<T> {149		/// Get contract owner.150		pub fn contract_owner(contract: H160) -> H160 {151			<Owner<T>>::get(contract)152		}153154		/// Set `sponsor` for `contract`.155		///156		/// `sender` must be owner of contract.157		pub fn set_sponsor(158			sender: &T::CrossAccountId,159			contract: H160,160			sponsor: &T::CrossAccountId,161		) -> DispatchResult {162			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;163			Sponsoring::<T>::insert(164				contract,165				SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),166			);167			Ok(())168		}169170		/// Set `contract` as self sponsored.171		///172		/// `sender` must be owner of contract.173		pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {174			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;175			Sponsoring::<T>::insert(176				contract,177				SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(178					contract,179				)),180			);181			Ok(())182		}183184		/// Remove sponsor for `contract`.185		///186		/// `sender` must be owner of contract.187		pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {188			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;189			Sponsoring::<T>::remove(contract);190			Ok(())191		}192193		/// Confirm sponsorship.194		///195		/// `sender` must be same that set via [`set_sponsor`].196		pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {197			match Sponsoring::<T>::get(contract) {198				SponsorshipState::Unconfirmed(sponsor) => {199					ensure!(sponsor == *sender, Error::<T>::NoPermission);200					Sponsoring::<T>::insert(201						contract,202						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),203					);204					Ok(())205				}206				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {207					Err(Error::<T>::NoPendingSponsor.into())208				}209			}210		}211212		/// Get sponsor.213		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {214			match Sponsoring::<T>::get(contract) {215				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,216				SponsorshipState::Confirmed(sponsor) => Some(sponsor),217			}218		}219220		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {221			<SponsoringMode<T>>::get(contract)222				.or_else(|| {223					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)224				})225				.unwrap_or_default()226		}227228		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {229			if mode == SponsoringModeT::Disabled {230				<SponsoringMode<T>>::remove(contract);231			} else {232				<SponsoringMode<T>>::insert(contract, mode);233			}234			<SelfSponsoring<T>>::remove(contract)235		}236237		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {238			<SponsoringRateLimit<T>>::insert(contract, rate_limit);239		}240241		pub fn allowed(contract: H160, user: H160) -> bool {242			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user243		}244245		pub fn toggle_allowlist(contract: H160, enabled: bool) {246			<AllowlistEnabled<T>>::insert(contract, enabled)247		}248249		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {250			<Allowlist<T>>::insert(contract, user, allowed);251		}252253		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {254			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);255			Ok(())256		}257	}258}259260#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]261pub enum SponsoringModeT {262	Disabled,263	Allowlisted,264	Generous,265}266267impl SponsoringModeT {268	fn from_eth(v: u8) -> Option<Self> {269		Some(match v {270			0 => Self::Disabled,271			1 => Self::Allowlisted,272			2 => Self::Generous,273			_ => return None,274		})275	}276	fn to_eth(self) -> u8 {277		match self {278			SponsoringModeT::Disabled => 0,279			SponsoringModeT::Allowlisted => 1,280			SponsoringModeT::Generous => 2,281		}282	}283}284285impl Default for SponsoringModeT {286	fn default() -> Self {287		Self::Disabled288	}289}
after · pallets/evm-contract-helpers/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![doc = include_str!("../README.md")]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]2021use codec::{Decode, Encode, MaxEncodedLen};22pub use pallet::*;23pub use eth::*;24use scale_info::TypeInfo;25pub mod eth;2627#[frame_support::pallet]28pub mod pallet {29	pub use super::*;30	use frame_support::pallet_prelude::*;31	use pallet_evm_coder_substrate::DispatchResult;32	use sp_core::H160;33	use pallet_evm::account::CrossAccountId;34	use up_data_structs::SponsorshipState;3536	#[pallet::config]37	pub trait Config:38		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config39	{40		/// Address, under which magic contract will be available41		type ContractAddress: Get<H160>;42		/// In case of enabled sponsoring, but no sponsoring rate limit set,43		/// this value will be used implicitly44		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;45	}4647	#[pallet::error]48	pub enum Error<T> {49		/// This method is only executable by contract owner50		NoPermission,5152		/// No pending sponsor for contract.53		NoPendingSponsor,54	}5556	#[pallet::pallet]57	#[pallet::generate_store(pub(super) trait Store)]58	pub struct Pallet<T>(_);5960	/// Store owner for contract.61	///62	/// * **Key** - contract address.63	/// * **Value** - owner for contract.64	#[pallet::storage]65	pub(super) type Owner<T: Config> =66		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;6768	#[pallet::storage]69	#[deprecated]70	pub(super) type SelfSponsoring<T: Config> =71		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;7273	/// Store for contract sponsorship state.74	///75	/// * **Key** - contract address.76	/// * **Value** - sponsorship state.77	#[pallet::storage]78	pub(super) type Sponsoring<T: Config> = StorageMap<79		Hasher = Twox64Concat,80		Key = H160,81		Value = SponsorshipState<T::CrossAccountId>,82		QueryKind = ValueQuery,83	>;8485	/// Store for sponsoring mode.86	///87	/// ### Usage88	/// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).89	///90	/// * **Key** - contract address.91	/// * **Value** - [`sponsoring mode`](SponsoringModeT).92	#[pallet::storage]93	pub(super) type SponsoringMode<T: Config> =94		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;9596	/// Storage for sponsoring rate limit in blocks.97	///98	/// * **Key** - contract address.99	/// * **Value** - amount of sponsored blocks.100	#[pallet::storage]101	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<102		Hasher = Twox128,103		Key = H160,104		Value = T::BlockNumber,105		QueryKind = ValueQuery,106		OnEmpty = T::DefaultSponsoringRateLimit,107	>;108109	/// Storage for last sponsored block.110	///111	/// * **Key1** - contract address.112	/// * **Key2** - sponsored user address.113	/// * **Value** - last sponsored block number.114	#[pallet::storage]115	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<116		Hasher1 = Twox128,117		Key1 = H160,118		Hasher2 = Twox128,119		Key2 = H160,120		Value = T::BlockNumber,121		QueryKind = OptionQuery,122	>;123124	/// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.125	///126	/// ### Usage127	/// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.128	///129	/// * **Key** - contract address.130	/// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.131	#[pallet::storage]132	pub(super) type AllowlistEnabled<T: Config> =133		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;134135	/// Storage for users that allowed for sponsorship.136	///137	/// ### Usage138	/// Prefer to delete record from storage if user no more allowed for sponsorship.139	///140	/// * **Key1** - contract address.141	/// * **Key2** - user that allowed for sponsorship.142	/// * **Value** - allowance for sponsorship.143	#[pallet::storage]144	pub(super) type Allowlist<T: Config> = StorageDoubleMap<145		Hasher1 = Twox128,146		Key1 = H160,147		Hasher2 = Twox128,148		Key2 = H160,149		Value = bool,150		QueryKind = ValueQuery,151	>;152153	impl<T: Config> Pallet<T> {154		/// Get contract owner.155		pub fn contract_owner(contract: H160) -> H160 {156			<Owner<T>>::get(contract)157		}158159		/// Set `sponsor` for `contract`.160		///161		/// `sender` must be owner of contract.162		pub fn set_sponsor(163			sender: &T::CrossAccountId,164			contract: H160,165			sponsor: &T::CrossAccountId,166		) -> DispatchResult {167			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;168			Sponsoring::<T>::insert(169				contract,170				SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),171			);172			Ok(())173		}174175		/// Set `contract` as self sponsored.176		///177		/// `sender` must be owner of contract.178		pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {179			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;180			Sponsoring::<T>::insert(181				contract,182				SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(183					contract,184				)),185			);186			Ok(())187		}188189		/// Remove sponsor for `contract`.190		///191		/// `sender` must be owner of contract.192		pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {193			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;194			Sponsoring::<T>::remove(contract);195			Ok(())196		}197198		/// Confirm sponsorship.199		///200		/// `sender` must be same that set via [`set_sponsor`].201		pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {202			match Sponsoring::<T>::get(contract) {203				SponsorshipState::Unconfirmed(sponsor) => {204					ensure!(sponsor == *sender, Error::<T>::NoPermission);205					Sponsoring::<T>::insert(206						contract,207						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),208					);209					Ok(())210				}211				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {212					Err(Error::<T>::NoPendingSponsor.into())213				}214			}215		}216217		/// Get sponsor.218		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {219			match Sponsoring::<T>::get(contract) {220				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,221				SponsorshipState::Confirmed(sponsor) => Some(sponsor),222			}223		}224225		/// Get current sponsoring mode, performing lazy migration from legacy storage226		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {227			<SponsoringMode<T>>::get(contract)228				.or_else(|| {229					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)230				})231				.unwrap_or_default()232		}233234		/// Reconfigure contract sponsoring mode235		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {236			if mode == SponsoringModeT::Disabled {237				<SponsoringMode<T>>::remove(contract);238			} else {239				<SponsoringMode<T>>::insert(contract, mode);240			}241			<SelfSponsoring<T>>::remove(contract)242		}243244		/// Set duration between two sponsored contract calls245		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {246			<SponsoringRateLimit<T>>::insert(contract, rate_limit);247		}248249		/// Is user added to allowlist, or he is owner of specified contract250		pub fn allowed(contract: H160, user: H160) -> bool {251			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user252		}253254		/// Toggle contract allowlist access255		pub fn toggle_allowlist(contract: H160, enabled: bool) {256			<AllowlistEnabled<T>>::insert(contract, enabled)257		}258259		/// Toggle user presence in contract's allowlist260		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {261			<Allowlist<T>>::insert(contract, user, allowed);262		}263264		/// Throw error if user is not allowed to reconfigure target contract265		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {266			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);267			Ok(())268		}269	}270}271272/// Available contract sponsoring modes273#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]274pub enum SponsoringModeT {275	/// Sponsoring is disabled276	#[default]277	Disabled,278	/// Only users from allowlist will be sponsored279	Allowlisted,280	/// All users will be sponsored281	Generous,282}283284impl SponsoringModeT {285	fn from_eth(v: u8) -> Option<Self> {286		Some(match v {287			0 => Self::Disabled,288			1 => Self::Allowlisted,289			2 => Self::Generous,290			_ => return None,291		})292	}293	fn to_eth(self) -> u8 {294		match self {295			SponsoringModeT::Disabled => 0,296			SponsoringModeT::Allowlisted => 1,297			SponsoringModeT::Generous => 2,298		}299	}300}
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -3,12 +3,6 @@
 
 pragma solidity >=0.8.0 <0.9.0;
 
-/// @dev anonymous struct
-struct Tuple0 {
-	address field_0;
-	uint256 field_1;
-}
-
 /// @dev common stubs holder
 contract Dummy {
 	uint8 dummy;
@@ -27,14 +21,18 @@
 	}
 }
 
-/// @dev the ERC-165 identifier for this interface is 0x6073d917
+/// @title Magic contract, which allows users to reconfigure other contracts
+/// @dev the ERC-165 identifier for this interface is 0xd77fab70
 contract ContractHelpers is Dummy, ERC165 {
-	/// Get contract ovner
-	///
-	/// @param contractAddress contract for which the owner is being determined.
-	/// @return Contract owner.
-	///
-	/// Selector: contractOwner(address) 5152b14c
+	/// Get user, which deployed specified contract
+	/// @dev May return zero address in case if contract is deployed
+	///  using uniquenetwork evm-migration pallet, or using other terms not
+	///  intended by pallet-evm
+	/// @dev Returns zero address if contract does not exists
+	/// @param contractAddress Contract to get owner of
+	/// @return address Owner of contract
+	/// @dev EVM selector for this function is: 0x5152b14c,
+	///  or in textual repr: contractOwner(address)
 	function contractOwner(address contractAddress)
 		public
 		view
@@ -47,11 +45,10 @@
 	}
 
 	/// Set sponsor.
-	///
 	/// @param contractAddress Contract for which a sponsor is being established.
 	/// @param sponsor User address who set as pending sponsor.
-	///
-	/// Selector: setSponsor(address,address) f01fba93
+	/// @dev EVM selector for this function is: 0xf01fba93,
+	///  or in textual repr: setSponsor(address,address)
 	function setSponsor(address contractAddress, address sponsor) public {
 		require(false, stub_error);
 		contractAddress;
@@ -62,8 +59,8 @@
 	/// Set contract as self sponsored.
 	///
 	/// @param contractAddress Contract for which a self sponsoring is being enabled.
-	///
-	/// Selector: selfSponsoredEnable(address) 89f7d9ae
+	/// @dev EVM selector for this function is: 0x89f7d9ae,
+	///  or in textual repr: selfSponsoredEnable(address)
 	function selfSponsoredEnable(address contractAddress) public {
 		require(false, stub_error);
 		contractAddress;
@@ -73,8 +70,8 @@
 	/// Remove sponsor.
 	///
 	/// @param contractAddress Contract for which a sponsorship is being removed.
-	///
-	/// Selector: removeSponsor(address) ef784250
+	/// @dev EVM selector for this function is: 0xef784250,
+	///  or in textual repr: removeSponsor(address)
 	function removeSponsor(address contractAddress) public {
 		require(false, stub_error);
 		contractAddress;
@@ -86,8 +83,8 @@
 	/// @dev Caller must be same that set via [`setSponsor`].
 	///
 	/// @param contractAddress Сontract for which need to confirm sponsorship.
-	///
-	/// Selector: confirmSponsorship(address) abc00001
+	/// @dev EVM selector for this function is: 0xabc00001,
+	///  or in textual repr: confirmSponsorship(address)
 	function confirmSponsorship(address contractAddress) public {
 		require(false, stub_error);
 		contractAddress;
@@ -98,8 +95,8 @@
 	///
 	/// @param contractAddress The contract for which a sponsor is requested.
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	///
-	/// Selector: getSponsor(address) 743fc745
+	/// @dev EVM selector for this function is: 0x743fc745,
+	///  or in textual repr: getSponsor(address)
 	function getSponsor(address contractAddress)
 		public
 		view
@@ -115,8 +112,8 @@
 	///
 	/// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
 	/// @return **true** if contract has confirmed sponsor.
-	///
-	/// Selector: hasSponsor(address) 97418603
+	/// @dev EVM selector for this function is: 0x97418603,
+	///  or in textual repr: hasSponsor(address)
 	function hasSponsor(address contractAddress) public view returns (bool) {
 		require(false, stub_error);
 		contractAddress;
@@ -128,8 +125,8 @@
 	///
 	/// @param contractAddress The contract for which the presence of a pending sponsor is checked.
 	/// @return **true** if contract has pending sponsor.
-	///
-	/// Selector: hasPendingSponsor(address) 39b9b242
+	/// @dev EVM selector for this function is: 0x39b9b242,
+	///  or in textual repr: hasPendingSponsor(address)
 	function hasPendingSponsor(address contractAddress)
 		public
 		view
@@ -141,7 +138,8 @@
 		return false;
 	}
 
-	/// Selector: sponsoringEnabled(address) 6027dc61
+	/// @dev EVM selector for this function is: 0x6027dc61,
+	///  or in textual repr: sponsoringEnabled(address)
 	function sponsoringEnabled(address contractAddress)
 		public
 		view
@@ -153,7 +151,8 @@
 		return false;
 	}
 
-	/// Selector: setSponsoringMode(address,uint8) fde8a560
+	/// @dev EVM selector for this function is: 0xfde8a560,
+	///  or in textual repr: setSponsoringMode(address,uint8)
 	function setSponsoringMode(address contractAddress, uint8 mode) public {
 		require(false, stub_error);
 		contractAddress;
@@ -161,11 +160,15 @@
 		dummy = 0;
 	}
 
-	/// Selector: sponsoringMode(address) b70c7267
-	function sponsoringMode(address contractAddress)
+	/// Get current contract sponsoring rate limit
+	/// @param contractAddress Contract to get sponsoring mode of
+	/// @return uint32 Amount of blocks between two sponsored transactions
+	/// @dev EVM selector for this function is: 0x610cfabd,
+	///  or in textual repr: getSponsoringRateLimit(address)
+	function getSponsoringRateLimit(address contractAddress)
 		public
 		view
-		returns (uint8)
+		returns (uint32)
 	{
 		require(false, stub_error);
 		contractAddress;
@@ -173,7 +176,14 @@
 		return 0;
 	}
 
-	/// Selector: setSponsoringRateLimit(address,uint32) 77b6c908
+	/// Set contract sponsoring rate limit
+	/// @dev Sponsoring rate limit - is a minimum amount of blocks that should
+	///  pass between two sponsored transactions
+	/// @param contractAddress Contract to change sponsoring rate limit of
+	/// @param rateLimit Target rate limit
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x77b6c908,
+	///  or in textual repr: setSponsoringRateLimit(address,uint32)
 	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
 		public
 	{
@@ -183,32 +193,53 @@
 		dummy = 0;
 	}
 
-	/// Selector: getSponsoringRateLimit(address) 610cfabd
-	function getSponsoringRateLimit(address contractAddress)
+	/// Is specified user present in contract allow list
+	/// @dev Contract owner always implicitly included
+	/// @param contractAddress Contract to check allowlist of
+	/// @param user User to check
+	/// @return bool Is specified users exists in contract allowlist
+	/// @dev EVM selector for this function is: 0x5c658165,
+	///  or in textual repr: allowed(address,address)
+	function allowed(address contractAddress, address user)
 		public
 		view
-		returns (uint32)
+		returns (bool)
 	{
 		require(false, stub_error);
 		contractAddress;
+		user;
 		dummy;
-		return 0;
+		return false;
 	}
 
-	/// Selector: allowed(address,address) 5c658165
-	function allowed(address contractAddress, address user)
-		public
-		view
-		returns (bool)
-	{
+	/// Toggle user presence in contract allowlist
+	/// @param contractAddress Contract to change allowlist of
+	/// @param user Which user presence should be toggled
+	/// @param isAllowed `true` if user should be allowed to be sponsored
+	///  or call this contract, `false` otherwise
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x4706cc1c,
+	///  or in textual repr: toggleAllowed(address,address,bool)
+	function toggleAllowed(
+		address contractAddress,
+		address user,
+		bool isAllowed
+	) public {
 		require(false, stub_error);
 		contractAddress;
 		user;
-		dummy;
-		return false;
+		isAllowed;
+		dummy = 0;
 	}
 
-	/// Selector: allowlistEnabled(address) c772ef6c
+	/// Is this contract has allowlist access enabled
+	/// @dev Allowlist always can have users, and it is used for two purposes:
+	///  in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
+	///  in case of allowlist access enabled, only users from allowlist may call this contract
+	/// @param contractAddress Contract to get allowlist access of
+	/// @return bool Is specified contract has allowlist access enabled
+	/// @dev EVM selector for this function is: 0xc772ef6c,
+	///  or in textual repr: allowlistEnabled(address)
 	function allowlistEnabled(address contractAddress)
 		public
 		view
@@ -220,24 +251,21 @@
 		return false;
 	}
 
-	/// Selector: toggleAllowlist(address,bool) 36de20f5
+	/// Toggle contract allowlist access
+	/// @param contractAddress Contract to change allowlist access of
+	/// @param enabled Should allowlist access to be enabled?
+	/// @dev EVM selector for this function is: 0x36de20f5,
+	///  or in textual repr: toggleAllowlist(address,bool)
 	function toggleAllowlist(address contractAddress, bool enabled) public {
 		require(false, stub_error);
 		contractAddress;
 		enabled;
 		dummy = 0;
 	}
+}
 
-	/// Selector: toggleAllowed(address,address,bool) 4706cc1c
-	function toggleAllowed(
-		address contractAddress,
-		address user,
-		bool isAllowed
-	) public {
-		require(false, stub_error);
-		contractAddress;
-		user;
-		isAllowed;
-		dummy = 0;
-	}
+/// @dev anonymous struct
+struct Tuple0 {
+	address field_0;
+	uint256 field_1;
 }
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -3,12 +3,6 @@
 
 pragma solidity >=0.8.0 <0.9.0;
 
-/// @dev anonymous struct
-struct Tuple0 {
-	address field_0;
-	uint256 field_1;
-}
-
 /// @dev common stubs holder
 interface Dummy {
 
@@ -18,39 +12,42 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
-/// @dev the ERC-165 identifier for this interface is 0x6073d917
+/// @title Magic contract, which allows users to reconfigure other contracts
+/// @dev the ERC-165 identifier for this interface is 0xd77fab70
 interface ContractHelpers is Dummy, ERC165 {
-	/// Get contract ovner
-	///
-	/// @param contractAddress contract for which the owner is being determined.
-	/// @return Contract owner.
-	///
-	/// Selector: contractOwner(address) 5152b14c
+	/// Get user, which deployed specified contract
+	/// @dev May return zero address in case if contract is deployed
+	///  using uniquenetwork evm-migration pallet, or using other terms not
+	///  intended by pallet-evm
+	/// @dev Returns zero address if contract does not exists
+	/// @param contractAddress Contract to get owner of
+	/// @return address Owner of contract
+	/// @dev EVM selector for this function is: 0x5152b14c,
+	///  or in textual repr: contractOwner(address)
 	function contractOwner(address contractAddress)
 		external
 		view
 		returns (address);
 
 	/// Set sponsor.
-	///
 	/// @param contractAddress Contract for which a sponsor is being established.
 	/// @param sponsor User address who set as pending sponsor.
-	///
-	/// Selector: setSponsor(address,address) f01fba93
+	/// @dev EVM selector for this function is: 0xf01fba93,
+	///  or in textual repr: setSponsor(address,address)
 	function setSponsor(address contractAddress, address sponsor) external;
 
 	/// Set contract as self sponsored.
 	///
 	/// @param contractAddress Contract for which a self sponsoring is being enabled.
-	///
-	/// Selector: selfSponsoredEnable(address) 89f7d9ae
+	/// @dev EVM selector for this function is: 0x89f7d9ae,
+	///  or in textual repr: selfSponsoredEnable(address)
 	function selfSponsoredEnable(address contractAddress) external;
 
 	/// Remove sponsor.
 	///
 	/// @param contractAddress Contract for which a sponsorship is being removed.
-	///
-	/// Selector: removeSponsor(address) ef784250
+	/// @dev EVM selector for this function is: 0xef784250,
+	///  or in textual repr: removeSponsor(address)
 	function removeSponsor(address contractAddress) external;
 
 	/// Confirm sponsorship.
@@ -58,16 +55,16 @@
 	/// @dev Caller must be same that set via [`setSponsor`].
 	///
 	/// @param contractAddress Сontract for which need to confirm sponsorship.
-	///
-	/// Selector: confirmSponsorship(address) abc00001
+	/// @dev EVM selector for this function is: 0xabc00001,
+	///  or in textual repr: confirmSponsorship(address)
 	function confirmSponsorship(address contractAddress) external;
 
 	/// Get current sponsor.
 	///
 	/// @param contractAddress The contract for which a sponsor is requested.
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	///
-	/// Selector: getSponsor(address) 743fc745
+	/// @dev EVM selector for this function is: 0x743fc745,
+	///  or in textual repr: getSponsor(address)
 	function getSponsor(address contractAddress)
 		external
 		view
@@ -77,65 +74,102 @@
 	///
 	/// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
 	/// @return **true** if contract has confirmed sponsor.
-	///
-	/// Selector: hasSponsor(address) 97418603
+	/// @dev EVM selector for this function is: 0x97418603,
+	///  or in textual repr: hasSponsor(address)
 	function hasSponsor(address contractAddress) external view returns (bool);
 
 	/// Check tat contract has pending sponsor.
 	///
 	/// @param contractAddress The contract for which the presence of a pending sponsor is checked.
 	/// @return **true** if contract has pending sponsor.
-	///
-	/// Selector: hasPendingSponsor(address) 39b9b242
+	/// @dev EVM selector for this function is: 0x39b9b242,
+	///  or in textual repr: hasPendingSponsor(address)
 	function hasPendingSponsor(address contractAddress)
 		external
 		view
 		returns (bool);
 
-	/// Selector: sponsoringEnabled(address) 6027dc61
+	/// @dev EVM selector for this function is: 0x6027dc61,
+	///  or in textual repr: sponsoringEnabled(address)
 	function sponsoringEnabled(address contractAddress)
 		external
 		view
 		returns (bool);
 
-	/// Selector: setSponsoringMode(address,uint8) fde8a560
+	/// @dev EVM selector for this function is: 0xfde8a560,
+	///  or in textual repr: setSponsoringMode(address,uint8)
 	function setSponsoringMode(address contractAddress, uint8 mode) external;
 
-	/// Selector: sponsoringMode(address) b70c7267
-	function sponsoringMode(address contractAddress)
+	/// Get current contract sponsoring rate limit
+	/// @param contractAddress Contract to get sponsoring mode of
+	/// @return uint32 Amount of blocks between two sponsored transactions
+	/// @dev EVM selector for this function is: 0x610cfabd,
+	///  or in textual repr: getSponsoringRateLimit(address)
+	function getSponsoringRateLimit(address contractAddress)
 		external
 		view
-		returns (uint8);
+		returns (uint32);
 
-	/// Selector: setSponsoringRateLimit(address,uint32) 77b6c908
+	/// Set contract sponsoring rate limit
+	/// @dev Sponsoring rate limit - is a minimum amount of blocks that should
+	///  pass between two sponsored transactions
+	/// @param contractAddress Contract to change sponsoring rate limit of
+	/// @param rateLimit Target rate limit
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x77b6c908,
+	///  or in textual repr: setSponsoringRateLimit(address,uint32)
 	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
 		external;
 
-	/// Selector: getSponsoringRateLimit(address) 610cfabd
-	function getSponsoringRateLimit(address contractAddress)
-		external
-		view
-		returns (uint32);
-
-	/// Selector: allowed(address,address) 5c658165
+	/// Is specified user present in contract allow list
+	/// @dev Contract owner always implicitly included
+	/// @param contractAddress Contract to check allowlist of
+	/// @param user User to check
+	/// @return bool Is specified users exists in contract allowlist
+	/// @dev EVM selector for this function is: 0x5c658165,
+	///  or in textual repr: allowed(address,address)
 	function allowed(address contractAddress, address user)
 		external
 		view
 		returns (bool);
 
-	/// Selector: allowlistEnabled(address) c772ef6c
+	/// Toggle user presence in contract allowlist
+	/// @param contractAddress Contract to change allowlist of
+	/// @param user Which user presence should be toggled
+	/// @param isAllowed `true` if user should be allowed to be sponsored
+	///  or call this contract, `false` otherwise
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x4706cc1c,
+	///  or in textual repr: toggleAllowed(address,address,bool)
+	function toggleAllowed(
+		address contractAddress,
+		address user,
+		bool isAllowed
+	) external;
+
+	/// Is this contract has allowlist access enabled
+	/// @dev Allowlist always can have users, and it is used for two purposes:
+	///  in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
+	///  in case of allowlist access enabled, only users from allowlist may call this contract
+	/// @param contractAddress Contract to get allowlist access of
+	/// @return bool Is specified contract has allowlist access enabled
+	/// @dev EVM selector for this function is: 0xc772ef6c,
+	///  or in textual repr: allowlistEnabled(address)
 	function allowlistEnabled(address contractAddress)
 		external
 		view
 		returns (bool);
 
-	/// Selector: toggleAllowlist(address,bool) 36de20f5
+	/// Toggle contract allowlist access
+	/// @param contractAddress Contract to change allowlist access of
+	/// @param enabled Should allowlist access to be enabled?
+	/// @dev EVM selector for this function is: 0x36de20f5,
+	///  or in textual repr: toggleAllowlist(address,bool)
 	function toggleAllowlist(address contractAddress, bool enabled) external;
+}
 
-	/// Selector: toggleAllowed(address,address,bool) 4706cc1c
-	function toggleAllowed(
-		address contractAddress,
-		address user,
-		bool isAllowed
-	) external;
+/// @dev anonymous struct
+struct Tuple0 {
+	address field_0;
+	uint256 field_1;
 }
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -197,19 +197,6 @@
   },
   {
     "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "sponsoringMode",
-    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
       { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
     ],
     "name": "supportsInterface",