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

difftreelog

source

pallets/evm-contract-helpers/src/lib.rs8.9 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#![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}