git.delta.rocks / unique-network / refs/commits / 8138c78fd9cb

difftreelog

Merge branch 'feature/app-staking' of https://github.com/UniqueNetwork/unique-chain into feature/app-staking

PraetorP2022-09-06parents: #fc5b26a #837c29c.patch.diff
in: master

11 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5735,6 +5735,7 @@
 name = "pallet-evm-contract-helpers"
 version = "0.2.0"
 dependencies = [
+ "ethereum",
  "evm-coder",
  "fp-evm-mapping",
  "frame-support",
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -9,6 +9,7 @@
     "derive",
 ] }
 log = { default-features = false, version = "0.4.14" }
+ethereum = { version = "0.12.0", default-features = false }
 
 # Substrate
 frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -17,7 +17,9 @@
 //! Implementation of magic contract
 
 use core::marker::PhantomData;
-use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{
+	abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
+};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};
 use pallet_evm::{
 	ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
@@ -33,6 +35,35 @@
 use up_sponsorship::SponsorshipHandler;
 use sp_std::vec::Vec;
 
+/// Pallet events.
+#[derive(ToLog)]
+pub enum ContractHelpersEvents {
+	/// Contract sponsor was set.
+	ContractSponsorSet {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+		/// New sponsor address.
+		sponsor: address,
+	},
+
+	/// New sponsor was confirm.
+	ContractSponsorshipConfirmed {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+		/// New sponsor address.
+		sponsor: address,
+	},
+
+	/// Collection sponsor was removed.
+	ContractSponsorRemoved {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+	},
+}
+
 /// See [`ContractHelpersCall`]
 pub struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
 impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
@@ -46,7 +77,7 @@
 }
 
 /// @title Magic contract, which allows users to reconfigure other contracts
-#[solidity_interface(name = ContractHelpers)]
+#[solidity_interface(name = ContractHelpers, events(ContractHelpersEvents))]
 impl<T: Config> ContractHelpers<T>
 where
 	T::AccountId: AsRef<[u8; 32]>,
@@ -91,8 +122,12 @@
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
-		Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)
-			.map_err(dispatch_to_evm::<T>)?;
+		Pallet::<T>::force_set_sponsor(
+			&T::CrossAccountId::from_eth(caller),
+			contract_address,
+			&T::CrossAccountId::from_eth(contract_address),
+		)
+		.map_err(dispatch_to_evm::<T>)?;
 
 		Ok(())
 	}
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#![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 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}
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#![warn(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 crate::eth::ContractHelpersEvents;31	use frame_support::pallet_prelude::*;32	use pallet_evm_coder_substrate::DispatchResult;33	use sp_core::H160;34	use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};35	use up_data_structs::SponsorshipState;36	use evm_coder::ToLog;3738	#[pallet::config]39	pub trait Config:40		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config41	{42		/// Overarching event type.43		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;4445		/// Address, under which magic contract will be available46		type ContractAddress: Get<H160>;4748		/// In case of enabled sponsoring, but no sponsoring rate limit set,49		/// this value will be used implicitly50		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;51	}5253	#[pallet::error]54	pub enum Error<T> {55		/// This method is only executable by contract owner56		NoPermission,5758		/// No pending sponsor for contract.59		NoPendingSponsor,60	}6162	#[pallet::pallet]63	#[pallet::generate_store(pub(super) trait Store)]64	pub struct Pallet<T>(_);6566	/// Store owner for contract.67	///68	/// * **Key** - contract address.69	/// * **Value** - owner for contract.70	#[pallet::storage]71	pub(super) type Owner<T: Config> =72		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;7374	#[pallet::storage]75	#[deprecated]76	pub(super) type SelfSponsoring<T: Config> =77		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;7879	/// Store for contract sponsorship state.80	///81	/// * **Key** - contract address.82	/// * **Value** - sponsorship state.83	#[pallet::storage]84	pub type Sponsoring<T: Config> = StorageMap<85		Hasher = Twox64Concat,86		Key = H160,87		Value = SponsorshipState<T::CrossAccountId>,88		QueryKind = ValueQuery,89	>;9091	/// Store for sponsoring mode.92	///93	/// ### Usage94	/// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).95	///96	/// * **Key** - contract address.97	/// * **Value** - [`sponsoring mode`](SponsoringModeT).98	#[pallet::storage]99	pub(super) type SponsoringMode<T: Config> =100		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;101102	/// Storage for sponsoring rate limit in blocks.103	///104	/// * **Key** - contract address.105	/// * **Value** - amount of sponsored blocks.106	#[pallet::storage]107	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<108		Hasher = Twox128,109		Key = H160,110		Value = T::BlockNumber,111		QueryKind = ValueQuery,112		OnEmpty = T::DefaultSponsoringRateLimit,113	>;114115	/// Storage for last sponsored block.116	///117	/// * **Key1** - contract address.118	/// * **Key2** - sponsored user address.119	/// * **Value** - last sponsored block number.120	#[pallet::storage]121	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<122		Hasher1 = Twox128,123		Key1 = H160,124		Hasher2 = Twox128,125		Key2 = H160,126		Value = T::BlockNumber,127		QueryKind = OptionQuery,128	>;129130	/// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.131	///132	/// ### Usage133	/// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.134	///135	/// * **Key** - contract address.136	/// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.137	#[pallet::storage]138	pub(super) type AllowlistEnabled<T: Config> =139		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;140141	/// Storage for users that allowed for sponsorship.142	///143	/// ### Usage144	/// Prefer to delete record from storage if user no more allowed for sponsorship.145	///146	/// * **Key1** - contract address.147	/// * **Key2** - user that allowed for sponsorship.148	/// * **Value** - allowance for sponsorship.149	#[pallet::storage]150	pub(super) type Allowlist<T: Config> = StorageDoubleMap<151		Hasher1 = Twox128,152		Key1 = H160,153		Hasher2 = Twox128,154		Key2 = H160,155		Value = bool,156		QueryKind = ValueQuery,157	>;158159	#[pallet::event]160	#[pallet::generate_deposit(pub fn deposit_event)]161	pub enum Event<T: Config> {162		/// Contract sponsor was set.163		ContractSponsorSet(164			/// Contract address of the affected collection.165			H160,166			/// New sponsor address.167			T::AccountId,168		),169170		/// New sponsor was confirm.171		ContractSponsorshipConfirmed(172			/// Contract address of the affected collection.173			H160,174			/// New sponsor address.175			T::AccountId,176		),177178		/// Collection sponsor was removed.179		ContractSponsorRemoved(180			/// Contract address of the affected collection.181			H160,182		),183	}184185	impl<T: Config> Pallet<T> {186		/// Get contract owner.187		pub fn contract_owner(contract: H160) -> H160 {188			<Owner<T>>::get(contract)189		}190191		/// Set `sponsor` for `contract`.192		///193		/// `sender` must be owner of contract.194		pub fn set_sponsor(195			sender: &T::CrossAccountId,196			contract: H160,197			sponsor: &T::CrossAccountId,198		) -> DispatchResult {199			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;200			Sponsoring::<T>::insert(201				contract,202				SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),203			);204205			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(206				contract,207				sponsor.as_sub().clone(),208			));209			<PalletEvm<T>>::deposit_log(210				ContractHelpersEvents::ContractSponsorSet {211					contract_address: contract,212					sponsor: *sponsor.as_eth(),213				}214				.to_log(contract),215			);216			Ok(())217		}218219		/// Set sponsor as already confirmed.220		///221		/// `sender` must be owner of contract.222		pub fn force_set_sponsor(223			sender: &T::CrossAccountId,224			contract_address: H160,225			sponsor: &T::CrossAccountId,226		) -> DispatchResult {227			Pallet::<T>::ensure_owner(contract_address, *sender.as_eth())?;228			Sponsoring::<T>::insert(229				contract_address,230				SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(231					contract_address,232				)),233			);234235			let eth_sponsor = *sponsor.as_eth();236			let sub_sponsor = sponsor.as_sub().clone();237238			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(239				contract_address,240				sub_sponsor.clone(),241			));242			<PalletEvm<T>>::deposit_log(243				ContractHelpersEvents::ContractSponsorSet {244					contract_address,245					sponsor: eth_sponsor,246				}247				.to_log(contract_address),248			);249250			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(251				contract_address,252				sub_sponsor,253			));254			<PalletEvm<T>>::deposit_log(255				ContractHelpersEvents::ContractSponsorshipConfirmed {256					contract_address,257					sponsor: eth_sponsor,258				}259				.to_log(contract_address),260			);261262			Ok(())263		}264265		/// Remove sponsor for `contract`.266		///267		/// `sender` must be owner of contract.268		pub fn remove_sponsor(sender: &T::CrossAccountId, contract_address: H160) -> DispatchResult {269			Pallet::<T>::ensure_owner(contract_address, *sender.as_eth())?;270			Sponsoring::<T>::remove(contract_address);271272			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));273			<PalletEvm<T>>::deposit_log(274				ContractHelpersEvents::ContractSponsorRemoved { contract_address }.to_log(contract_address),275			);276277			Ok(())278		}279280		/// Confirm sponsorship.281		///282		/// `sender` must be same that set via [`set_sponsor`].283		pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract_address: H160) -> DispatchResult {284			match Sponsoring::<T>::get(contract_address) {285				SponsorshipState::Unconfirmed(sponsor) => {286					ensure!(sponsor == *sender, Error::<T>::NoPermission);287					let eth_sponsor = *sponsor.as_eth();288					let sub_sponsor = sponsor.as_sub().clone();289					Sponsoring::<T>::insert(290						contract_address,291						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),292					);293294					<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(295						contract_address,296						sub_sponsor,297					));298					<PalletEvm<T>>::deposit_log(299						ContractHelpersEvents::ContractSponsorshipConfirmed {300							contract_address,301							sponsor: eth_sponsor,302						}303						.to_log(contract_address),304					);305306					Ok(())307				}308				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {309					Err(Error::<T>::NoPendingSponsor.into())310				}311			}312		}313314		/// Get sponsor.315		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {316			match Sponsoring::<T>::get(contract) {317				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,318				SponsorshipState::Confirmed(sponsor) => Some(sponsor),319			}320		}321322		/// Get current sponsoring mode, performing lazy migration from legacy storage323		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {324			<SponsoringMode<T>>::get(contract)325				.or_else(|| {326					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)327				})328				.unwrap_or_default()329		}330331		/// Reconfigure contract sponsoring mode332		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {333			if mode == SponsoringModeT::Disabled {334				<SponsoringMode<T>>::remove(contract);335			} else {336				<SponsoringMode<T>>::insert(contract, mode);337			}338			<SelfSponsoring<T>>::remove(contract)339		}340341		/// Set duration between two sponsored contract calls342		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {343			<SponsoringRateLimit<T>>::insert(contract, rate_limit);344		}345346		/// Is user added to allowlist, or he is owner of specified contract347		pub fn allowed(contract: H160, user: H160) -> bool {348			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user349		}350351		/// Toggle contract allowlist access352		pub fn toggle_allowlist(contract: H160, enabled: bool) {353			<AllowlistEnabled<T>>::insert(contract, enabled)354		}355356		/// Toggle user presence in contract's allowlist357		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {358			<Allowlist<T>>::insert(contract, user, allowed);359		}360361		/// Throw error if user is not allowed to reconfigure target contract362		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {363			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);364			Ok(())365		}366	}367}368369/// Available contract sponsoring modes370#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]371pub enum SponsoringModeT {372	/// Sponsoring is disabled373	#[default]374	Disabled,375	/// Only users from allowlist will be sponsored376	Allowlisted,377	/// All users will be sponsored378	Generous,379}380381impl SponsoringModeT {382	fn from_eth(v: u8) -> Option<Self> {383		Some(match v {384			0 => Self::Disabled,385			1 => Self::Allowlisted,386			2 => Self::Generous,387			_ => return None,388		})389	}390	fn to_eth(self) -> u8 {391		match self {392			SponsoringModeT::Disabled => 0,393			SponsoringModeT::Allowlisted => 1,394			SponsoringModeT::Generous => 2,395		}396	}397}
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
@@ -21,9 +21,19 @@
 	}
 }
 
+/// @dev inlined interface
+contract ContractHelpersEvents {
+	event ContractSponsorSet(address indexed contractAddress, address sponsor);
+	event ContractSponsorshipConfirmed(
+		address indexed contractAddress,
+		address sponsor
+	);
+	event ContractSponsorRemoved(address indexed contractAddress);
+}
+
 /// @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 {
+contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
 	/// 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
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
--- a/runtime/common/config/ethereum.rs
+++ b/runtime/common/config/ethereum.rs
@@ -112,6 +112,7 @@
 }
 
 impl pallet_evm_contract_helpers::Config for Runtime {
+	type Event = Event;
 	type ContractAddress = HelpersContractAddress;
 	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
 }
modifiedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
--- a/runtime/common/construct_runtime/mod.rs
+++ b/runtime/common/construct_runtime/mod.rs
@@ -85,7 +85,7 @@
                 Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
 
                 EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
-                EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
+                EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage, Event<T>} = 151,
                 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
                 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
             }
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -12,9 +12,19 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
+/// @dev inlined interface
+interface ContractHelpersEvents {
+	event ContractSponsorSet(address indexed contractAddress, address sponsor);
+	event ContractSponsorshipConfirmed(
+		address indexed contractAddress,
+		address sponsor
+	);
+	event ContractSponsorRemoved(address indexed contractAddress);
+}
+
 /// @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 {
+interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
 	/// 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
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -24,6 +24,7 @@
   SponsoringMode,
   createEthAccount,
   ethBalanceViaSub,
+  normalizeEvents,
 } from './util/helpers';
 
 describe('Sponsoring EVM contracts', () => {
@@ -36,6 +37,33 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
   });
 
+  itWeb3.only('Set self sponsored events', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    
+    const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorSet',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: flipper.options.address,
+        },
+      },
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorshipConfirmed',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: flipper.options.address,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -75,6 +103,26 @@
     expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
   });
   
+  itWeb3('Set sponsor event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    
+    const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorSet',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: sponsor,
+        },
+      },
+    ]);
+  });
+  
   itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -97,6 +145,26 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
   });
 
+  itWeb3('Confirm sponsorship event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
+    const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorshipConfirmed',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: sponsor,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -160,6 +228,28 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
   });
 
+  itWeb3('Remove sponsor event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+
+    await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+    await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+    
+    const result = await helpers.methods.removeSponsor(flipper.options.address).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorRemoved',
+        args: {
+          contractAddress: flipper.options.address,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -1,5 +1,56 @@
 [
   {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorRemoved",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "address",
+        "name": "sponsor",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorSet",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "address",
+        "name": "sponsor",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorshipConfirmed",
+    "type": "event"
+  },
+  {
     "inputs": [
       {
         "internalType": "address",