git.delta.rocks / unique-network / refs/commits / bfcf3ca7e01c

difftreelog

source

pallets/evm-contract-helpers/src/lib.rs11.8 KiBsourcehistory
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, U256};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		/// In case of enabled sponsoring, but no sponsoring fee limit set,52		/// this value will be used implicitly53		type DefaultSponsoringFeeLimit: Get<U256>;54	}5556	#[pallet::error]57	pub enum Error<T> {58		/// This method is only executable by contract owner59		NoPermission,6061		/// No pending sponsor for contract.62		NoPendingSponsor,63	}6465	#[pallet::pallet]66	#[pallet::generate_store(pub(super) trait Store)]67	pub struct Pallet<T>(_);6869	/// Store owner for contract.70	///71	/// * **Key** - contract address.72	/// * **Value** - owner for contract.73	#[pallet::storage]74	pub(super) type Owner<T: Config> =75		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;7677	#[pallet::storage]78	#[deprecated]79	pub(super) type SelfSponsoring<T: Config> =80		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8182	/// Store for contract sponsorship state.83	///84	/// * **Key** - contract address.85	/// * **Value** - sponsorship state.86	#[pallet::storage]87	pub(super) type Sponsoring<T: Config> = StorageMap<88		Hasher = Twox64Concat,89		Key = H160,90		Value = SponsorshipState<T::CrossAccountId>,91		QueryKind = ValueQuery,92	>;9394	/// Store for sponsoring mode.95	///96	/// ### Usage97	/// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).98	///99	/// * **Key** - contract address.100	/// * **Value** - [`sponsoring mode`](SponsoringModeT).101	#[pallet::storage]102	pub(super) type SponsoringMode<T: Config> =103		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;104105	/// Storage for sponsoring rate limit in blocks.106	///107	/// * **Key** - contract address.108	/// * **Value** - amount of sponsored blocks.109	#[pallet::storage]110	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<111		Hasher = Twox128,112		Key = H160,113		Value = T::BlockNumber,114		QueryKind = ValueQuery,115		OnEmpty = T::DefaultSponsoringRateLimit,116	>;117118	/// Storage for last sponsored block.119	///120	/// * **Key1** - contract address.121	/// * **Key2** - sponsored user address.122	/// * **Value** - last sponsored block number.123	#[pallet::storage]124	pub(super) type SponsoringFeeLimit<T: Config> = StorageMap<125		Hasher = Twox128,126		Key = H160,127		Value = U256,128		QueryKind = ValueQuery,129		OnEmpty = T::DefaultSponsoringFeeLimit,130	>;131132	#[pallet::storage]133	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<134		Hasher1 = Twox128,135		Key1 = H160,136		Hasher2 = Twox128,137		Key2 = H160,138		Value = T::BlockNumber,139		QueryKind = OptionQuery,140	>;141142	/// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.143	///144	/// ### Usage145	/// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.146	///147	/// * **Key** - contract address.148	/// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.149	#[pallet::storage]150	pub(super) type AllowlistEnabled<T: Config> =151		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;152153	/// Storage for users that allowed for sponsorship.154	///155	/// ### Usage156	/// Prefer to delete record from storage if user no more allowed for sponsorship.157	///158	/// * **Key1** - contract address.159	/// * **Key2** - user that allowed for sponsorship.160	/// * **Value** - allowance for sponsorship.161	#[pallet::storage]162	pub(super) type Allowlist<T: Config> = StorageDoubleMap<163		Hasher1 = Twox128,164		Key1 = H160,165		Hasher2 = Twox128,166		Key2 = H160,167		Value = bool,168		QueryKind = ValueQuery,169	>;170171	#[pallet::event]172	#[pallet::generate_deposit(pub fn deposit_event)]173	pub enum Event<T: Config> {174		/// Contract sponsor was set.175		ContractSponsorSet(176			/// Contract address of the affected collection.177			H160,178			/// New sponsor address.179			T::AccountId,180		),181182		/// New sponsor was confirm.183		ContractSponsorshipConfirmed(184			/// Contract address of the affected collection.185			H160,186			/// New sponsor address.187			T::AccountId,188		),189190		/// Collection sponsor was removed.191		ContractSponsorRemoved(192			/// Contract address of the affected collection.193			H160,194		),195	}196197	impl<T: Config> Pallet<T> {198		/// Get contract owner.199		pub fn contract_owner(contract: H160) -> H160 {200			<Owner<T>>::get(contract)201		}202203		/// Set `sponsor` for `contract`.204		///205		/// `sender` must be owner of contract.206		pub fn set_sponsor(207			sender: &T::CrossAccountId,208			contract: H160,209			sponsor: &T::CrossAccountId,210		) -> DispatchResult {211			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;212			Sponsoring::<T>::insert(213				contract,214				SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),215			);216217			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(218				contract,219				sponsor.as_sub().clone(),220			));221			<PalletEvm<T>>::deposit_log(222				ContractHelpersEvents::ContractSponsorSet {223					contract_address: contract,224					sponsor: *sponsor.as_eth(),225				}226				.to_log(contract),227			);228			Ok(())229		}230231		/// TO-DO232		///233		///234		pub fn force_set_sponsor(235			contract_address: H160,236			sponsor: &T::CrossAccountId,237		) -> DispatchResult {238			Sponsoring::<T>::insert(239				contract_address,240				SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),241			);242243			let eth_sponsor = *sponsor.as_eth();244			let sub_sponsor = sponsor.as_sub().clone();245246			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(247				contract_address,248				sub_sponsor.clone(),249			));250			<PalletEvm<T>>::deposit_log(251				ContractHelpersEvents::ContractSponsorSet {252					contract_address,253					sponsor: eth_sponsor,254				}255				.to_log(contract_address),256			);257258			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(259				contract_address,260				sub_sponsor,261			));262			<PalletEvm<T>>::deposit_log(263				ContractHelpersEvents::ContractSponsorshipConfirmed {264					contract_address,265					sponsor: eth_sponsor,266				}267				.to_log(contract_address),268			);269270			Ok(())271		}272273		/// Remove sponsor for `contract`.274		///275		/// `sender` must be owner of contract.276		pub fn remove_sponsor(277			sender: &T::CrossAccountId,278			contract_address: H160,279		) -> DispatchResult {280			Self::ensure_owner(contract_address, *sender.as_eth())?;281			Self::force_remove_sponsor(contract_address)282		}283284		/// TO-DO285		///286		///287		pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {288			Sponsoring::<T>::remove(contract_address);289290			Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));291			<PalletEvm<T>>::deposit_log(292				ContractHelpersEvents::ContractSponsorRemoved { contract_address }293					.to_log(contract_address),294			);295296			Ok(())297		}298299		/// Confirm sponsorship.300		///301		/// `sender` must be same that set via [`set_sponsor`].302		pub fn confirm_sponsorship(303			sender: &T::CrossAccountId,304			contract_address: H160,305		) -> DispatchResult {306			match Sponsoring::<T>::get(contract_address) {307				SponsorshipState::Unconfirmed(sponsor) => {308					ensure!(sponsor == *sender, Error::<T>::NoPermission);309					let eth_sponsor = *sponsor.as_eth();310					let sub_sponsor = sponsor.as_sub().clone();311					Sponsoring::<T>::insert(312						contract_address,313						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),314					);315316					<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(317						contract_address,318						sub_sponsor,319					));320					<PalletEvm<T>>::deposit_log(321						ContractHelpersEvents::ContractSponsorshipConfirmed {322							contract_address,323							sponsor: eth_sponsor,324						}325						.to_log(contract_address),326					);327328					Ok(())329				}330				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {331					Err(Error::<T>::NoPendingSponsor.into())332				}333			}334		}335336		/// Get sponsor.337		pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {338			match Sponsoring::<T>::get(contract) {339				SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,340				SponsorshipState::Confirmed(sponsor) => Some(sponsor),341			}342		}343344		/// Get current sponsoring mode, performing lazy migration from legacy storage345		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {346			<SponsoringMode<T>>::get(contract)347				.or_else(|| {348					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)349				})350				.unwrap_or_default()351		}352353		/// Reconfigure contract sponsoring mode354		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {355			if mode == SponsoringModeT::Disabled {356				<SponsoringMode<T>>::remove(contract);357			} else {358				<SponsoringMode<T>>::insert(contract, mode);359			}360			<SelfSponsoring<T>>::remove(contract)361		}362363		/// Set duration between two sponsored contract calls364		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {365			<SponsoringRateLimit<T>>::insert(contract, rate_limit);366		}367368		/// Set maximum for gas limit of transaction369		pub fn set_sponsoring_fee_limit(contract: H160, fee_limit: U256) {370			<SponsoringFeeLimit<T>>::insert(contract, fee_limit);371		}372373		/// Is user added to allowlist, or he is owner of specified contract374		pub fn allowed(contract: H160, user: H160) -> bool {375			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user376		}377378		/// Toggle contract allowlist access379		pub fn toggle_allowlist(contract: H160, enabled: bool) {380			<AllowlistEnabled<T>>::insert(contract, enabled)381		}382383		/// Toggle user presence in contract's allowlist384		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {385			<Allowlist<T>>::insert(contract, user, allowed);386		}387388		/// Throw error if user is not allowed to reconfigure target contract389		pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {390			ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);391			Ok(())392		}393	}394}395396/// Available contract sponsoring modes397#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]398pub enum SponsoringModeT {399	/// Sponsoring is disabled400	#[default]401	Disabled,402	/// Only users from allowlist will be sponsored403	Allowlisted,404	/// All users will be sponsored405	Generous,406}407408impl SponsoringModeT {409	fn from_eth(v: u8) -> Option<Self> {410		Some(match v {411			0 => Self::Disabled,412			1 => Self::Allowlisted,413			2 => Self::Generous,414			_ => return None,415		})416	}417	fn to_eth(self) -> u8 {418		match self {419			SponsoringModeT::Disabled => 0,420			SponsoringModeT::Allowlisted => 1,421			SponsoringModeT::Generous => 2,422		}423	}424}