difftreelog
feat SelfSponsoring migration
in: master
1 file changed
pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth1// 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};22use evm_coder::AbiCoder;23pub use pallet::*;24pub use eth::*;25use scale_info::TypeInfo;26use frame_support::storage::bounded_btree_map::BoundedBTreeMap;27pub mod eth;2829/// Maximum number of methods per contract that could have fee limit30pub const MAX_FEE_LIMITED_METHODS: u32 = 5;3132#[frame_support::pallet]33pub mod pallet {34 pub use super::*;35 use crate::eth::ContractHelpersEvents;36 use frame_support::pallet_prelude::*;37 use pallet_evm_coder_substrate::DispatchResult;38 use sp_core::{H160, U256};39 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};40 use up_data_structs::SponsorshipState;41 use evm_coder::ToLog;4243 #[pallet::config]44 pub trait Config:45 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config46 {47 /// Overarching event type.48 type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;4950 /// Address, under which magic contract will be available51 #[pallet::constant]52 type ContractAddress: Get<H160>;5354 /// In case of enabled sponsoring, but no sponsoring rate limit set,55 /// this value will be used implicitly56 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;57 }5859 #[pallet::error]60 pub enum Error<T> {61 /// This method is only executable by contract owner62 NoPermission,6364 /// No pending sponsor for contract.65 NoPendingSponsor,6667 /// Number of methods that sponsored limit is defined for exceeds maximum.68 TooManyMethodsHaveSponsoredLimit,69 }7071 #[pallet::pallet]72 #[pallet::generate_store(trait Store)]73 pub struct Pallet<T>(_);7475 /// Store owner for contract.76 ///77 /// * **Key** - contract address.78 /// * **Value** - owner for contract.79 #[pallet::storage]80 pub(super) type Owner<T: Config> =81 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;8283 /// Deprecated: this storage is deprecated84 #[pallet::storage]85 type SelfSponsoring<T: Config> =86 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8788 /// Store for contract sponsorship state.89 ///90 /// * **Key** - contract address.91 /// * **Value** - sponsorship state.92 #[pallet::storage]93 pub(super) type Sponsoring<T: Config> = StorageMap<94 Hasher = Twox64Concat,95 Key = H160,96 Value = SponsorshipState<T::CrossAccountId>,97 QueryKind = ValueQuery,98 >;99100 /// Store for sponsoring mode.101 ///102 /// ### Usage103 /// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).104 ///105 /// * **Key** - contract address.106 /// * **Value** - [`sponsoring mode`](SponsoringModeT).107 #[pallet::storage]108 pub(super) type SponsoringMode<T: Config> =109 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;110111 /// Storage for sponsoring rate limit in blocks.112 ///113 /// * **Key** - contract address.114 /// * **Value** - amount of sponsored blocks.115 #[pallet::storage]116 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<117 Hasher = Twox128,118 Key = H160,119 Value = T::BlockNumber,120 QueryKind = ValueQuery,121 OnEmpty = T::DefaultSponsoringRateLimit,122 >;123124 /// Storage for last sponsored block.125 ///126 /// * **Key1** - contract address.127 /// * **Key2** - sponsored user address.128 /// * **Value** - last sponsored block number.129 #[pallet::storage]130 pub(super) type SponsoringFeeLimit<T: Config> = StorageMap<131 Hasher = Twox128,132 Key = H160,133 Value = BoundedBTreeMap<u32, U256, ConstU32<MAX_FEE_LIMITED_METHODS>>,134 QueryKind = ValueQuery,135 >;136137 #[pallet::storage]138 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<139 Hasher1 = Twox128,140 Key1 = H160,141 Hasher2 = Twox128,142 Key2 = H160,143 Value = T::BlockNumber,144 QueryKind = OptionQuery,145 >;146147 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.148 ///149 /// ### Usage150 /// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.151 ///152 /// * **Key** - contract address.153 /// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.154 #[pallet::storage]155 pub(super) type AllowlistEnabled<T: Config> =156 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;157158 /// Storage for users that allowed for sponsorship.159 ///160 /// ### Usage161 /// Prefer to delete record from storage if user no more allowed for sponsorship.162 ///163 /// * **Key1** - contract address.164 /// * **Key2** - user that allowed for sponsorship.165 /// * **Value** - allowance for sponsorship.166 #[pallet::storage]167 pub(super) type Allowlist<T: Config> = StorageDoubleMap<168 Hasher1 = Twox128,169 Key1 = H160,170 Hasher2 = Twox128,171 Key2 = H160,172 Value = bool,173 QueryKind = ValueQuery,174 >;175176 #[pallet::event]177 #[pallet::generate_deposit(fn deposit_event)]178 pub enum Event<T: Config> {179 /// Contract sponsor was set.180 ContractSponsorSet(181 /// Contract address of the affected collection.182 H160,183 /// New sponsor address.184 T::AccountId,185 ),186187 /// New sponsor was confirm.188 ContractSponsorshipConfirmed(189 /// Contract address of the affected collection.190 H160,191 /// New sponsor address.192 T::AccountId,193 ),194195 /// Collection sponsor was removed.196 ContractSponsorRemoved(197 /// Contract address of the affected collection.198 H160,199 ),200 }201202 impl<T: Config> Pallet<T> {203 /// Get contract owner.204 pub fn contract_owner(contract: H160) -> H160 {205 <Owner<T>>::get(contract)206 }207208 /// Set `sponsor` for `contract`.209 ///210 /// `sender` must be owner of contract.211 pub fn set_sponsor(212 sender: &T::CrossAccountId,213 contract: H160,214 sponsor: &T::CrossAccountId,215 ) -> DispatchResult {216 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;217 Sponsoring::<T>::insert(218 contract,219 SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),220 );221222 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(223 contract,224 sponsor.as_sub().clone(),225 ));226 <PalletEvm<T>>::deposit_log(227 ContractHelpersEvents::ContractSponsorSet {228 contract_address: contract,229 sponsor: *sponsor.as_eth(),230 }231 .to_log(contract),232 );233 Ok(())234 }235236 /// Force set `sponsor` for `contract`.237 ///238 /// Differs from `set_sponsor` in that confirmation239 /// from the sponsor is not required.240 pub fn force_set_sponsor(241 contract_address: H160,242 sponsor: &T::CrossAccountId,243 ) -> DispatchResult {244 Sponsoring::<T>::insert(245 contract_address,246 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),247 );248249 let eth_sponsor = *sponsor.as_eth();250 let sub_sponsor = sponsor.as_sub().clone();251252 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(253 contract_address,254 sub_sponsor.clone(),255 ));256 <PalletEvm<T>>::deposit_log(257 ContractHelpersEvents::ContractSponsorSet {258 contract_address,259 sponsor: eth_sponsor,260 }261 .to_log(contract_address),262 );263264 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(265 contract_address,266 sub_sponsor,267 ));268 <PalletEvm<T>>::deposit_log(269 ContractHelpersEvents::ContractSponsorshipConfirmed {270 contract_address,271 sponsor: eth_sponsor,272 }273 .to_log(contract_address),274 );275276 Ok(())277 }278279 /// Remove sponsor for `contract`.280 ///281 /// `sender` must be owner of contract.282 pub fn remove_sponsor(283 sender: &T::CrossAccountId,284 contract_address: H160,285 ) -> DispatchResult {286 Self::ensure_owner(contract_address, *sender.as_eth())?;287 Self::force_remove_sponsor(contract_address)288 }289290 /// Force remove `sponsor` for `contract`.291 ///292 /// Differs from `remove_sponsor` in that293 /// it doesn't require consent from the `owner` of the contract.294 pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {295 Sponsoring::<T>::remove(contract_address);296297 Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));298 <PalletEvm<T>>::deposit_log(299 ContractHelpersEvents::ContractSponsorRemoved { contract_address }300 .to_log(contract_address),301 );302303 Ok(())304 }305306 /// Confirm sponsorship.307 ///308 /// `sender` must be same that set via [`set_sponsor`].309 pub fn confirm_sponsorship(310 sender: &T::CrossAccountId,311 contract_address: H160,312 ) -> DispatchResult {313 match Sponsoring::<T>::get(contract_address) {314 SponsorshipState::Unconfirmed(sponsor) => {315 ensure!(sponsor == *sender, Error::<T>::NoPermission);316 let eth_sponsor = *sponsor.as_eth();317 let sub_sponsor = sponsor.as_sub().clone();318 Sponsoring::<T>::insert(319 contract_address,320 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),321 );322323 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(324 contract_address,325 sub_sponsor,326 ));327 <PalletEvm<T>>::deposit_log(328 ContractHelpersEvents::ContractSponsorshipConfirmed {329 contract_address,330 sponsor: eth_sponsor,331 }332 .to_log(contract_address),333 );334335 Ok(())336 }337 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {338 Err(Error::<T>::NoPendingSponsor.into())339 }340 }341 }342343 /// Get sponsor.344 pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {345 match Sponsoring::<T>::get(contract) {346 SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,347 SponsorshipState::Confirmed(sponsor) => Some(sponsor),348 }349 }350351 /// Get current sponsoring mode, performing lazy migration from legacy storage352 /// Deprecated: this method is for deprecated storage353 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {354 <SponsoringMode<T>>::get(contract)355 .or_else(|| {356 #[allow(deprecated)]357 <SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)358 })359 .unwrap_or_default()360 }361362 /// Reconfigure contract sponsoring mode363 /// Deprecated: this method is for deprecated storage364 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {365 if mode == SponsoringModeT::Disabled {366 <SponsoringMode<T>>::remove(contract);367 } else {368 <SponsoringMode<T>>::insert(contract, mode);369 }370 #[allow(deprecated)]371 <SelfSponsoring<T>>::remove(contract)372 }373374 /// Set duration between two sponsored contract calls375 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {376 <SponsoringRateLimit<T>>::insert(contract, rate_limit);377 }378379 /// Set maximum for gas limit of transaction380 pub fn set_sponsoring_fee_limit(contract: H160, fee_limit: U256) -> DispatchResult {381 <SponsoringFeeLimit<T>>::try_mutate(contract, |limits_map| {382 limits_map383 .try_insert(0xffffffff, fee_limit)384 .map_err(|_| <Error<T>>::TooManyMethodsHaveSponsoredLimit)385 })?;386 Ok(())387 }388389 /// Is user added to allowlist, or he is owner of specified contract390 pub fn allowed(contract: H160, user: H160) -> bool {391 <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user392 }393394 /// Toggle contract allowlist access395 pub fn toggle_allowlist(contract: H160, enabled: bool) {396 <AllowlistEnabled<T>>::insert(contract, enabled)397 }398399 /// Toggle user presence in contract's allowlist400 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {401 <Allowlist<T>>::insert(contract, user, allowed);402 }403404 /// Throw error if user is not allowed to reconfigure target contract405 pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {406 ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);407 Ok(())408 }409 }410}411412/// Available contract sponsoring modes413#[derive(414 Encode, Decode, Debug, PartialEq, TypeInfo, MaxEncodedLen, Default, AbiCoder, Clone, Copy,415)]416#[repr(u8)]417pub enum SponsoringModeT {418 /// Sponsoring is disabled419 #[default]420 Disabled,421 /// Only users from allowlist will be sponsored422 Allowlisted,423 /// All users will be sponsored424 Generous,425}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};22use evm_coder::AbiCoder;23pub use pallet::*;24pub use eth::*;25use scale_info::TypeInfo;26use frame_support::storage::bounded_btree_map::BoundedBTreeMap;27pub mod eth;2829/// Maximum number of methods per contract that could have fee limit30pub const MAX_FEE_LIMITED_METHODS: u32 = 5;3132#[frame_support::pallet]33pub mod pallet {34 pub use super::*;35 use crate::eth::ContractHelpersEvents;36 use frame_support::{pallet_prelude::*, sp_runtime::DispatchResult};37 use frame_system::{pallet_prelude::OriginFor, ensure_root};38 use sp_core::{H160, U256};39 use sp_std::vec::Vec;40 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};41 use up_data_structs::SponsorshipState;42 use evm_coder::ToLog;4344 #[pallet::config]45 pub trait Config:46 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config47 {48 /// Overarching event type.49 type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;5051 /// Address, under which magic contract will be available52 #[pallet::constant]53 type ContractAddress: Get<H160>;5455 /// In case of enabled sponsoring, but no sponsoring rate limit set,56 /// this value will be used implicitly57 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;58 }5960 #[pallet::error]61 pub enum Error<T> {62 /// This method is only executable by contract owner63 NoPermission,6465 /// No pending sponsor for contract.66 NoPendingSponsor,6768 /// Number of methods that sponsored limit is defined for exceeds maximum.69 TooManyMethodsHaveSponsoredLimit,70 }7172 #[pallet::pallet]73 #[pallet::generate_store(trait Store)]74 pub struct Pallet<T>(_);7576 /// Store owner for contract.77 ///78 /// * **Key** - contract address.79 /// * **Value** - owner for contract.80 #[pallet::storage]81 pub(super) type Owner<T: Config> =82 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;8384 /// Deprecated: this storage is deprecated85 #[pallet::storage]86 type SelfSponsoring<T: Config> =87 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8889 /// Store for contract sponsorship state.90 ///91 /// * **Key** - contract address.92 /// * **Value** - sponsorship state.93 #[pallet::storage]94 pub(super) type Sponsoring<T: Config> = StorageMap<95 Hasher = Twox64Concat,96 Key = H160,97 Value = SponsorshipState<T::CrossAccountId>,98 QueryKind = ValueQuery,99 >;100101 /// Store for sponsoring mode.102 ///103 /// ### Usage104 /// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).105 ///106 /// * **Key** - contract address.107 /// * **Value** - [`sponsoring mode`](SponsoringModeT).108 #[pallet::storage]109 pub(super) type SponsoringMode<T: Config> =110 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;111112 /// Storage for sponsoring rate limit in blocks.113 ///114 /// * **Key** - contract address.115 /// * **Value** - amount of sponsored blocks.116 #[pallet::storage]117 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<118 Hasher = Twox128,119 Key = H160,120 Value = T::BlockNumber,121 QueryKind = ValueQuery,122 OnEmpty = T::DefaultSponsoringRateLimit,123 >;124125 /// Storage for last sponsored block.126 ///127 /// * **Key1** - contract address.128 /// * **Key2** - sponsored user address.129 /// * **Value** - last sponsored block number.130 #[pallet::storage]131 pub(super) type SponsoringFeeLimit<T: Config> = StorageMap<132 Hasher = Twox128,133 Key = H160,134 Value = BoundedBTreeMap<u32, U256, ConstU32<MAX_FEE_LIMITED_METHODS>>,135 QueryKind = ValueQuery,136 >;137138 #[pallet::storage]139 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<140 Hasher1 = Twox128,141 Key1 = H160,142 Hasher2 = Twox128,143 Key2 = H160,144 Value = T::BlockNumber,145 QueryKind = OptionQuery,146 >;147148 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.149 ///150 /// ### Usage151 /// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.152 ///153 /// * **Key** - contract address.154 /// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.155 #[pallet::storage]156 pub(super) type AllowlistEnabled<T: Config> =157 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;158159 /// Storage for users that allowed for sponsorship.160 ///161 /// ### Usage162 /// Prefer to delete record from storage if user no more allowed for sponsorship.163 ///164 /// * **Key1** - contract address.165 /// * **Key2** - user that allowed for sponsorship.166 /// * **Value** - allowance for sponsorship.167 #[pallet::storage]168 pub(super) type Allowlist<T: Config> = StorageDoubleMap<169 Hasher1 = Twox128,170 Key1 = H160,171 Hasher2 = Twox128,172 Key2 = H160,173 Value = bool,174 QueryKind = ValueQuery,175 >;176177 #[pallet::event]178 #[pallet::generate_deposit(fn deposit_event)]179 pub enum Event<T: Config> {180 /// Contract sponsor was set.181 ContractSponsorSet(182 /// Contract address of the affected collection.183 H160,184 /// New sponsor address.185 T::AccountId,186 ),187188 /// New sponsor was confirm.189 ContractSponsorshipConfirmed(190 /// Contract address of the affected collection.191 H160,192 /// New sponsor address.193 T::AccountId,194 ),195196 /// Collection sponsor was removed.197 ContractSponsorRemoved(198 /// Contract address of the affected collection.199 H160,200 ),201 }202203 #[pallet::call]204 impl<T: Config> Pallet<T> {205 /// Migrate contract to use `SponsoringMode` storage instead of `SelfSponsoring`206 #[pallet::call_index(0)]207 #[pallet::weight(<T as frame_system::Config>::DbWeight::get().reads_writes(208 addresses.len() as u64, addresses.len() as u64 * 2209 ))]210 pub fn migrate_from_self_sponsoring(211 origin: OriginFor<T>,212 addresses: Vec<H160>,213 ) -> DispatchResult {214 ensure_root(origin)?;215 for address in addresses {216 if <SelfSponsoring<T>>::get(address) {217 <SponsoringMode<T>>::set(address, Some(SponsoringModeT::Allowlisted));218 <SelfSponsoring<T>>::remove(address);219 }220 }221 Ok(())222 }223 }224225 impl<T: Config> Pallet<T> {226 /// Get contract owner.227 pub fn contract_owner(contract: H160) -> H160 {228 <Owner<T>>::get(contract)229 }230231 /// Set `sponsor` for `contract`.232 ///233 /// `sender` must be owner of contract.234 pub fn set_sponsor(235 sender: &T::CrossAccountId,236 contract: H160,237 sponsor: &T::CrossAccountId,238 ) -> DispatchResult {239 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;240 Sponsoring::<T>::insert(241 contract,242 SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),243 );244245 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(246 contract,247 sponsor.as_sub().clone(),248 ));249 <PalletEvm<T>>::deposit_log(250 ContractHelpersEvents::ContractSponsorSet {251 contract_address: contract,252 sponsor: *sponsor.as_eth(),253 }254 .to_log(contract),255 );256 Ok(())257 }258259 /// Force set `sponsor` for `contract`.260 ///261 /// Differs from `set_sponsor` in that confirmation262 /// from the sponsor is not required.263 pub fn force_set_sponsor(264 contract_address: H160,265 sponsor: &T::CrossAccountId,266 ) -> DispatchResult {267 Sponsoring::<T>::insert(268 contract_address,269 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor.clone()),270 );271272 let eth_sponsor = *sponsor.as_eth();273 let sub_sponsor = sponsor.as_sub().clone();274275 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(276 contract_address,277 sub_sponsor.clone(),278 ));279 <PalletEvm<T>>::deposit_log(280 ContractHelpersEvents::ContractSponsorSet {281 contract_address,282 sponsor: eth_sponsor,283 }284 .to_log(contract_address),285 );286287 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(288 contract_address,289 sub_sponsor,290 ));291 <PalletEvm<T>>::deposit_log(292 ContractHelpersEvents::ContractSponsorshipConfirmed {293 contract_address,294 sponsor: eth_sponsor,295 }296 .to_log(contract_address),297 );298299 Ok(())300 }301302 /// Remove sponsor for `contract`.303 ///304 /// `sender` must be owner of contract.305 pub fn remove_sponsor(306 sender: &T::CrossAccountId,307 contract_address: H160,308 ) -> DispatchResult {309 Self::ensure_owner(contract_address, *sender.as_eth())?;310 Self::force_remove_sponsor(contract_address)311 }312313 /// Force remove `sponsor` for `contract`.314 ///315 /// Differs from `remove_sponsor` in that316 /// it doesn't require consent from the `owner` of the contract.317 pub fn force_remove_sponsor(contract_address: H160) -> DispatchResult {318 Sponsoring::<T>::remove(contract_address);319320 Self::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));321 <PalletEvm<T>>::deposit_log(322 ContractHelpersEvents::ContractSponsorRemoved { contract_address }323 .to_log(contract_address),324 );325326 Ok(())327 }328329 /// Confirm sponsorship.330 ///331 /// `sender` must be same that set via [`set_sponsor`].332 pub fn confirm_sponsorship(333 sender: &T::CrossAccountId,334 contract_address: H160,335 ) -> DispatchResult {336 match Sponsoring::<T>::get(contract_address) {337 SponsorshipState::Unconfirmed(sponsor) => {338 ensure!(sponsor == *sender, Error::<T>::NoPermission);339 let eth_sponsor = *sponsor.as_eth();340 let sub_sponsor = sponsor.as_sub().clone();341 Sponsoring::<T>::insert(342 contract_address,343 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),344 );345346 <Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(347 contract_address,348 sub_sponsor,349 ));350 <PalletEvm<T>>::deposit_log(351 ContractHelpersEvents::ContractSponsorshipConfirmed {352 contract_address,353 sponsor: eth_sponsor,354 }355 .to_log(contract_address),356 );357358 Ok(())359 }360 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {361 Err(Error::<T>::NoPendingSponsor.into())362 }363 }364 }365366 /// Get sponsor.367 pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {368 match Sponsoring::<T>::get(contract) {369 SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,370 SponsorshipState::Confirmed(sponsor) => Some(sponsor),371 }372 }373374 /// Get current sponsoring mode, performing lazy migration from legacy storage375 /// Deprecated: this method is for deprecated storage376 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {377 <SponsoringMode<T>>::get(contract)378 .or_else(|| {379 #[allow(deprecated)]380 <SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)381 })382 .unwrap_or_default()383 }384385 /// Reconfigure contract sponsoring mode386 /// Deprecated: this method is for deprecated storage387 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {388 if mode == SponsoringModeT::Disabled {389 <SponsoringMode<T>>::remove(contract);390 } else {391 <SponsoringMode<T>>::insert(contract, mode);392 }393 #[allow(deprecated)]394 <SelfSponsoring<T>>::remove(contract)395 }396397 /// Set duration between two sponsored contract calls398 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {399 <SponsoringRateLimit<T>>::insert(contract, rate_limit);400 }401402 /// Set maximum for gas limit of transaction403 pub fn set_sponsoring_fee_limit(contract: H160, fee_limit: U256) -> DispatchResult {404 <SponsoringFeeLimit<T>>::try_mutate(contract, |limits_map| {405 limits_map406 .try_insert(0xffffffff, fee_limit)407 .map_err(|_| <Error<T>>::TooManyMethodsHaveSponsoredLimit)408 })?;409 Ok(())410 }411412 /// Is user added to allowlist, or he is owner of specified contract413 pub fn allowed(contract: H160, user: H160) -> bool {414 <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user415 }416417 /// Toggle contract allowlist access418 pub fn toggle_allowlist(contract: H160, enabled: bool) {419 <AllowlistEnabled<T>>::insert(contract, enabled)420 }421422 /// Toggle user presence in contract's allowlist423 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {424 <Allowlist<T>>::insert(contract, user, allowed);425 }426427 /// Throw error if user is not allowed to reconfigure target contract428 pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {429 ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);430 Ok(())431 }432 }433}434435/// Available contract sponsoring modes436#[derive(437 Encode, Decode, Debug, PartialEq, TypeInfo, MaxEncodedLen, Default, AbiCoder, Clone, Copy,438)]439#[repr(u8)]440pub enum SponsoringModeT {441 /// Sponsoring is disabled442 #[default]443 Disabled,444 /// Only users from allowlist will be sponsored445 Allowlisted,446 /// All users will be sponsored447 Generous,448}