difftreelog
code refactor
in: master
4 files changed
pallets/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",
-] }
pallets/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,
pallets/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>
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};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}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}