git.delta.rocks / unique-network / refs/commits / 95510b917c06

difftreelog

code refactor

PraetorP2022-09-07parent: #8c250ff.patch.diff
in: master

4 files changed

modifiedpallets/app-promotion/Cargo.tomldiffbeforeafterboth
--- a/pallets/app-promotion/Cargo.toml
+++ b/pallets/app-promotion/Cargo.toml
@@ -15,7 +15,7 @@
 targets = ['x86_64-unknown-linux-gnu']
 
 [features]
-default = ['std',]
+default = ['std']
 runtime-benchmarks = [
     'frame-benchmarking',
     'frame-support/runtime-benchmarks',
@@ -38,104 +38,36 @@
     'serde/std',
 
 ]
-
+[dependencies]
+scale-info = { version = "2.0.1", default-features = false, features = [
+    "derive",
+] }
 ################################################################################
 # Substrate Dependencies
-
-[dependencies.codec]
-default-features = false
-features = ['derive']
-package = 'parity-scale-codec'
-version = '3.1.2'
-
-[dependencies.frame-benchmarking]
-default-features = false
-optional = true
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.frame-support]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.frame-system]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
 
-[dependencies.pallet-balances]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.pallet-timestamp]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.pallet-randomness-collective-flip]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.sp-std]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.serde]
-default-features = false
-features = ['derive']
-version = '1.0.130'
-
-[dependencies.sp-runtime]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.sp-core]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.sp-io]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.27"
-
-[dependencies.pallet-evm]
-default-features = false
-git = "https://github.com/uniquenetwork/frontier"
-branch = "unique-polkadot-v0.9.27"
+codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '3.1.2' }
+frame-benchmarking = {default-features = false, optional = true,  git = "https://github.com/paritytech/substrate",  branch = "polkadot-v0.9.27" }
+frame-support = { default-features = false,  git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+frame-system ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-balances ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-timestamp ={ default-features = false,  git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-randomness-collective-flip ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+pallet-evm ={ default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27" }
+sp-std ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+sp-io ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
+serde = { default-features = false, features = ['derive'], version = '1.0.130' }
 
 ################################################################################
 # local dependencies
-[dependencies.up-data-structs]
-default-features = false
-path = "../../primitives/data-structs"
 
-[dependencies.pallet-common]
-default-features = false
-path = "../common"
-
-[dependencies.pallet-unique]
-default-features = false
-path = "../unique"
+up-data-structs ={ default-features = false, path = "../../primitives/data-structs" }
+pallet-common ={ default-features = false, path = "../common" }
+pallet-unique ={ default-features = false, path = "../unique" }
+pallet-evm-contract-helpers ={ default-features = false, path = "../evm-contract-helpers" }
 
-[dependencies.pallet-evm-contract-helpers]
-default-features = false
-path = "../evm-contract-helpers"
-
 [dev-dependencies]
-[dependencies.pallet-evm-migration]
-default-features = false
-path = "../evm-migration"
-
+pallet-evm-migration ={ default-features = false, path = "../evm-migration" }
 
 ################################################################################
-
-[dependencies]
-scale-info = { version = "2.0.1", default-features = false, features = [
-    "derive",
-] }
modifiedpallets/app-promotion/src/lib.rsdiffbeforeafterboth
--- a/pallets/app-promotion/src/lib.rs
+++ b/pallets/app-promotion/src/lib.rs
@@ -110,10 +110,6 @@
 		#[pallet::constant]
 		type PendingInterval: Get<Self::BlockNumber>;
 
-		// /// In chain blocks.
-		// #[pallet::constant]
-		// type Day: Get<Self::BlockNumber>; // useless
-
 		#[pallet::constant]
 		type Nominal: Get<BalanceOf<Self>>;
 
@@ -160,7 +156,7 @@
 		NotSufficientFunds,
 		PendingForBlockOverflow,
 		/// An error related to the fact that an invalid argument was passed to perform an action
-		InvalidArgument,
+		SponsorNotSet,
 	}
 
 	#[pallet::storage]
@@ -184,16 +180,6 @@
 	pub type StakesPerAccount<T: Config> =
 		StorageMap<_, Blake2_128Concat, T::AccountId, u8, ValueQuery>;
 
-	/// Amount of tokens pending unstake per user per block.
-	// #[pallet::storage]
-	// pub type PendingUnstake<T: Config> = StorageNMap<
-	// 	Key = (
-	// 		Key<Blake2_128Concat, T::AccountId>,
-	// 		Key<Twox64Concat, T::BlockNumber>,
-	// 	),
-	// 	Value = BalanceOf<T>,
-	// 	QueryKind = ValueQuery,
-	// >;
 	#[pallet::storage]
 	pub type PendingUnstake<T: Config> = StorageMap<
 		_,
@@ -202,16 +188,6 @@
 		BoundedVec<(T::AccountId, BalanceOf<T>), ConstU32<PENDING_LIMIT_PER_BLOCK>>,
 		ValueQuery,
 	>;
-
-	// /// A block when app-promotion has started .I think this is redundant, because we only need `NextInterestBlock`.
-	// #[pallet::storage]
-	// pub type StartBlock<T: Config> = StorageValue<Value = T::BlockNumber, QueryKind = ValueQuery>;
-
-	// /// Next target block when interest is recalculated
-	// #[pallet::storage]
-	// #[pallet::getter(fn get_interest_block)]
-	// pub type NextInterestBlock<T: Config> =
-	// 	StorageValue<Value = T::BlockNumber, QueryKind = ValueQuery>;
 
 	/// Stores hash a record for which the last revenue recalculation was performed.
 	/// If `None`, then recalculation has not yet been performed or calculations have been completed for all stakers.
@@ -228,7 +204,6 @@
 		{
 			let block_pending = PendingUnstake::<T>::take(current_block_number);
 			let counter = block_pending.len() as u32;
-			// add_weight(0, 1, 0);
 
 			if !block_pending.is_empty() {
 				block_pending.into_iter().for_each(|(staker, amount)| {
@@ -393,7 +368,7 @@
 			);
 
 			ensure!(
-				T::CollectionHandler::sponsor(collection_id)?.ok_or(<Error<T>>::InvalidArgument)?
+				T::CollectionHandler::sponsor(collection_id)?.ok_or(<Error<T>>::SponsorNotSet)?
 					== Self::account_id(),
 				<Error<T>>::NoPermission
 			);
@@ -425,7 +400,7 @@
 			);
 
 			ensure!(
-				T::ContractHandler::sponsor(contract_id)?.ok_or(<Error<T>>::InvalidArgument)?
+				T::ContractHandler::sponsor(contract_id)?.ok_or(<Error<T>>::SponsorNotSet)?
 					== T::CrossAccountId::from_sub(Self::account_id()),
 				<Error<T>>::NoPermission
 			);
@@ -712,14 +687,13 @@
 		staker.map_or(Some(<TotalStaked<T>>::get()), |s| {
 			Self::total_staked_by_id(s.as_sub())
 		})
-		// Self::total_staked_by_id(staker.as_sub())
 	}
 
-	pub fn cross_id_locked_balance(staker: T::CrossAccountId) -> BalanceOf<T> {
-		Self::get_locked_balance(staker.as_sub())
-			.map(|l| l.amount)
-			.unwrap_or_default()
-	}
+	// pub fn cross_id_locked_balance(staker: T::CrossAccountId) -> BalanceOf<T> {
+	// 	Self::get_locked_balance(staker.as_sub())
+	// 		.map(|l| l.amount)
+	// 		.unwrap_or_default()
+	// }
 
 	pub fn cross_id_total_staked_per_block(
 		staker: T::CrossAccountId,
modifiedpallets/app-promotion/src/types.rsdiffbeforeafterboth
--- a/pallets/app-promotion/src/types.rs
+++ b/pallets/app-promotion/src/types.rs
@@ -5,9 +5,9 @@
 use pallet_common::CollectionHandle;
 
 use sp_runtime::DispatchError;
-use up_data_structs::{CollectionId, SponsorshipState};
+use up_data_structs::{CollectionId};
 use sp_std::borrow::ToOwned;
-use pallet_evm_contract_helpers::{Pallet as EvmHelpersPallet, Config as EvmHelpersConfig, Sponsoring};
+use pallet_evm_contract_helpers::{Pallet as EvmHelpersPallet, Config as EvmHelpersConfig};
 
 pub trait ExtendedLockableCurrency<AccountId: Parameter>: LockableCurrency<AccountId> {
 	fn locks<KArg>(who: KArg) -> WeakBoundedVec<BalanceLock<Self::Balance>, Self::MaxLocks>
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#![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		/// TO-DO220		///221		///222		pub fn force_set_sponsor(223			contract_address: H160,224			sponsor: &T::CrossAccountId,225		) -> DispatchResult {226			Sponsoring::<T>::insert(227				contract_address,228				SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),229			);230231			let eth_sponsor = *sponsor.as_eth();232			let sub_sponsor = sponsor.as_sub().clone();233234			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(235				contract_address,236				sub_sponsor.clone(),237			));238			<PalletEvm<T>>::deposit_log(239				ContractHelpersEvents::ContractSponsorSet {240					contract_address,241					sponsor: eth_sponsor,242				}243				.to_log(contract_address),244			);245246			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(247				contract_address,248				sub_sponsor,249			));250			<PalletEvm<T>>::deposit_log(251				ContractHelpersEvents::ContractSponsorshipConfirmed {252					contract_address,253					sponsor: eth_sponsor,254				}255				.to_log(contract_address),256			);257258			Ok(())259		}260261		/// Remove sponsor for `contract`.262		///263		/// `sender` must be owner of contract.264		pub fn remove_sponsor(265			sender: &T::CrossAccountId,266			contract_address: H160,267		) -> DispatchResult {268			Self::ensure_owner(contract_address, *sender.as_eth())?;269			Self::force_remove_sponsor(contract_address)270		}271272		/// TO-DO273		///274		///275		pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {276			Sponsoring::<T>::remove(contract_address);277278			Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));279			<PalletEvm<T>>::deposit_log(280				ContractHelpersEvents::ContractSponsorRemoved { contract_address }281					.to_log(contract_address),282			);283284			Ok(())285		}286287		/// Confirm sponsorship.288		///289		/// `sender` must be same that set via [`set_sponsor`].290		pub fn confirm_sponsorship(291			sender: &T::CrossAccountId,292			contract_address: H160,293		) -> DispatchResult {294			match Sponsoring::<T>::get(contract_address) {295				SponsorshipState::Unconfirmed(sponsor) => {296					ensure!(sponsor == *sender, Error::<T>::NoPermission);297					let eth_sponsor = *sponsor.as_eth();298					let sub_sponsor = sponsor.as_sub().clone();299					Sponsoring::<T>::insert(300						contract_address,301						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),302					);303304					<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(305						contract_address,306						sub_sponsor,307					));308					<PalletEvm<T>>::deposit_log(309						ContractHelpersEvents::ContractSponsorshipConfirmed {310							contract_address,311							sponsor: eth_sponsor,312						}313						.to_log(contract_address),314					);315316					Ok(())317				}318				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {319					Err(Error::<T>::NoPendingSponsor.into())320				}321			}322		}323324		/// Get sponsor.325		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {326			match Sponsoring::<T>::get(contract) {327				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,328				SponsorshipState::Confirmed(sponsor) => Some(sponsor),329			}330		}331332		/// Get current sponsoring mode, performing lazy migration from legacy storage333		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {334			<SponsoringMode<T>>::get(contract)335				.or_else(|| {336					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)337				})338				.unwrap_or_default()339		}340341		/// Reconfigure contract sponsoring mode342		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {343			if mode == SponsoringModeT::Disabled {344				<SponsoringMode<T>>::remove(contract);345			} else {346				<SponsoringMode<T>>::insert(contract, mode);347			}348			<SelfSponsoring<T>>::remove(contract)349		}350351		/// Set duration between two sponsored contract calls352		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {353			<SponsoringRateLimit<T>>::insert(contract, rate_limit);354		}355356		/// Is user added to allowlist, or he is owner of specified contract357		pub fn allowed(contract: H160, user: H160) -> bool {358			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user359		}360361		/// Toggle contract allowlist access362		pub fn toggle_allowlist(contract: H160, enabled: bool) {363			<AllowlistEnabled<T>>::insert(contract, enabled)364		}365366		/// Toggle user presence in contract's allowlist367		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {368			<Allowlist<T>>::insert(contract, user, allowed);369		}370371		/// Throw error if user is not allowed to reconfigure target contract372		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {373			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);374			Ok(())375		}376	}377}378379/// Available contract sponsoring modes380#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]381pub enum SponsoringModeT {382	/// Sponsoring is disabled383	#[default]384	Disabled,385	/// Only users from allowlist will be sponsored386	Allowlisted,387	/// All users will be sponsored388	Generous,389}390391impl SponsoringModeT {392	fn from_eth(v: u8) -> Option<Self> {393		Some(match v {394			0 => Self::Disabled,395			1 => Self::Allowlisted,396			2 => Self::Generous,397			_ => return None,398		})399	}400	fn to_eth(self) -> u8 {401		match self {402			SponsoringModeT::Disabled => 0,403			SponsoringModeT::Allowlisted => 1,404			SponsoringModeT::Generous => 2,405		}406	}407}
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(super) 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		/// TO-DO220		///221		///222		pub fn force_set_sponsor(223			contract_address: H160,224			sponsor: &T::CrossAccountId,225		) -> DispatchResult {226			Sponsoring::<T>::insert(227				contract_address,228				SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),229			);230231			let eth_sponsor = *sponsor.as_eth();232			let sub_sponsor = sponsor.as_sub().clone();233234			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(235				contract_address,236				sub_sponsor.clone(),237			));238			<PalletEvm<T>>::deposit_log(239				ContractHelpersEvents::ContractSponsorSet {240					contract_address,241					sponsor: eth_sponsor,242				}243				.to_log(contract_address),244			);245246			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(247				contract_address,248				sub_sponsor,249			));250			<PalletEvm<T>>::deposit_log(251				ContractHelpersEvents::ContractSponsorshipConfirmed {252					contract_address,253					sponsor: eth_sponsor,254				}255				.to_log(contract_address),256			);257258			Ok(())259		}260261		/// Remove sponsor for `contract`.262		///263		/// `sender` must be owner of contract.264		pub fn remove_sponsor(265			sender: &T::CrossAccountId,266			contract_address: H160,267		) -> DispatchResult {268			Self::ensure_owner(contract_address, *sender.as_eth())?;269			Self::force_remove_sponsor(contract_address)270		}271272		/// TO-DO273		///274		///275		pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {276			Sponsoring::<T>::remove(contract_address);277278			Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));279			<PalletEvm<T>>::deposit_log(280				ContractHelpersEvents::ContractSponsorRemoved { contract_address }281					.to_log(contract_address),282			);283284			Ok(())285		}286287		/// Confirm sponsorship.288		///289		/// `sender` must be same that set via [`set_sponsor`].290		pub fn confirm_sponsorship(291			sender: &T::CrossAccountId,292			contract_address: H160,293		) -> DispatchResult {294			match Sponsoring::<T>::get(contract_address) {295				SponsorshipState::Unconfirmed(sponsor) => {296					ensure!(sponsor == *sender, Error::<T>::NoPermission);297					let eth_sponsor = *sponsor.as_eth();298					let sub_sponsor = sponsor.as_sub().clone();299					Sponsoring::<T>::insert(300						contract_address,301						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),302					);303304					<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(305						contract_address,306						sub_sponsor,307					));308					<PalletEvm<T>>::deposit_log(309						ContractHelpersEvents::ContractSponsorshipConfirmed {310							contract_address,311							sponsor: eth_sponsor,312						}313						.to_log(contract_address),314					);315316					Ok(())317				}318				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {319					Err(Error::<T>::NoPendingSponsor.into())320				}321			}322		}323324		/// Get sponsor.325		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {326			match Sponsoring::<T>::get(contract) {327				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,328				SponsorshipState::Confirmed(sponsor) => Some(sponsor),329			}330		}331332		/// Get current sponsoring mode, performing lazy migration from legacy storage333		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {334			<SponsoringMode<T>>::get(contract)335				.or_else(|| {336					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)337				})338				.unwrap_or_default()339		}340341		/// Reconfigure contract sponsoring mode342		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {343			if mode == SponsoringModeT::Disabled {344				<SponsoringMode<T>>::remove(contract);345			} else {346				<SponsoringMode<T>>::insert(contract, mode);347			}348			<SelfSponsoring<T>>::remove(contract)349		}350351		/// Set duration between two sponsored contract calls352		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {353			<SponsoringRateLimit<T>>::insert(contract, rate_limit);354		}355356		/// Is user added to allowlist, or he is owner of specified contract357		pub fn allowed(contract: H160, user: H160) -> bool {358			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user359		}360361		/// Toggle contract allowlist access362		pub fn toggle_allowlist(contract: H160, enabled: bool) {363			<AllowlistEnabled<T>>::insert(contract, enabled)364		}365366		/// Toggle user presence in contract's allowlist367		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {368			<Allowlist<T>>::insert(contract, user, allowed);369		}370371		/// Throw error if user is not allowed to reconfigure target contract372		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {373			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);374			Ok(())375		}376	}377}378379/// Available contract sponsoring modes380#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]381pub enum SponsoringModeT {382	/// Sponsoring is disabled383	#[default]384	Disabled,385	/// Only users from allowlist will be sponsored386	Allowlisted,387	/// All users will be sponsored388	Generous,389}390391impl SponsoringModeT {392	fn from_eth(v: u8) -> Option<Self> {393		Some(match v {394			0 => Self::Disabled,395			1 => Self::Allowlisted,396			2 => Self::Generous,397			_ => return None,398		})399	}400	fn to_eth(self) -> u8 {401		match self {402			SponsoringModeT::Disabled => 0,403			SponsoringModeT::Allowlisted => 1,404			SponsoringModeT::Generous => 2,405		}406	}407}