difftreelog
Merge pull request #691 from UniqueNetwork/feature/pallet-scheduler-v2
in: master
Feature/pallet scheduler v2
32 files changed
Cargo.lockdiffbeforeafterboth5389 "pallet-transaction-payment-rpc-runtime-api",5389 "pallet-transaction-payment-rpc-runtime-api",5390 "pallet-treasury",5390 "pallet-treasury",5391 "pallet-unique",5391 "pallet-unique",5392 "pallet-unique-scheduler",5392 "pallet-unique-scheduler-v2",5393 "pallet-xcm",5393 "pallet-xcm",5394 "parachain-info",5394 "parachain-info",5395 "parity-scale-codec 3.2.1",5395 "parity-scale-codec 3.2.1",6725dependencies = [6725dependencies = [6726 "frame-support",6726 "frame-support",6727 "frame-system",6727 "frame-system",6728 "pallet-unique-scheduler",6728 "pallet-unique-scheduler-v2",6729 "parity-scale-codec 3.2.1",6729 "parity-scale-codec 3.2.1",6730 "scale-info",6730 "scale-info",6731 "sp-std",6731]6732]673267336733[[package]]6734[[package]]6851]6852]685268536853[[package]]6854[[package]]6854name = "pallet-unique-scheduler"6855name = "pallet-unique-scheduler-v2"6855version = "0.1.1"6856version = "0.1.0"6856dependencies = [6857dependencies = [6857 "frame-benchmarking",6858 "frame-benchmarking",6858 "frame-support",6859 "frame-support",6859 "frame-system",6860 "frame-system",6860 "log",6861 "log",6862 "pallet-preimage",6861 "parity-scale-codec 3.2.1",6863 "parity-scale-codec 3.2.1",6862 "scale-info",6864 "scale-info",6863 "serde",6864 "sp-core",6865 "sp-core",6865 "sp-io",6866 "sp-io",6866 "sp-runtime",6867 "sp-runtime",6867 "sp-std",6868 "sp-std",6868 "substrate-test-utils",6869 "substrate-test-utils",6869 "up-sponsorship",6870]6870]687168716872[[package]]6872[[package]]8861 "pallet-transaction-payment-rpc-runtime-api",8861 "pallet-transaction-payment-rpc-runtime-api",8862 "pallet-treasury",8862 "pallet-treasury",8863 "pallet-unique",8863 "pallet-unique",8864 "pallet-unique-scheduler",8865 "pallet-xcm",8864 "pallet-xcm",8866 "parachain-info",8865 "parachain-info",8867 "parity-scale-codec 3.2.1",8866 "parity-scale-codec 3.2.1",12992 "pallet-transaction-payment-rpc-runtime-api",12991 "pallet-transaction-payment-rpc-runtime-api",12993 "pallet-treasury",12992 "pallet-treasury",12994 "pallet-unique",12993 "pallet-unique",12995 "pallet-unique-scheduler",12996 "pallet-xcm",12994 "pallet-xcm",12997 "parachain-info",12995 "parachain-info",12998 "parity-scale-codec 3.2.1",12996 "parity-scale-codec 3.2.1",Makefilediffbeforeafterboth118118119.PHONY: bench-scheduler119.PHONY: bench-scheduler120bench-scheduler:120bench-scheduler:121 make _bench PALLET=unique-scheduler PALLET_DIR=scheduler121 make _bench PALLET=unique-scheduler-v2 PALLET_DIR=scheduler-v2122122123.PHONY: bench-rmrk-core123.PHONY: bench-rmrk-core124bench-rmrk-core:124bench-rmrk-core:pallets/scheduler-v2/Cargo.tomldiffbeforeafterbothno changes
pallets/scheduler-v2/src/benchmarking.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/lib.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/mock.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/tests.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/weights.rsdiffbeforeafterbothno changes
pallets/scheduler/CHANGELOG.mddiffbeforeafterbothno changes
pallets/scheduler/Cargo.tomldiffbeforeafterbothno changes
pallets/scheduler/README.mddiffbeforeafterbothno changes
pallets/scheduler/src/benchmarking.rsdiffbeforeafterbothno changes
pallets/scheduler/src/lib.rsdiffbeforeafterbothno changes
pallets/scheduler/src/weights.rsdiffbeforeafterbothno changes
runtime/common/config/pallets/scheduler.rsdiffbeforeafterboth25use codec::Decode;25use codec::Decode;26use crate::{26use crate::{27 runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},27 runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},28 Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller, Balances,28 Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller,29};29};30use pallet_unique_scheduler::ScheduledEnsureOriginSuccess;30use pallet_unique_scheduler_v2::ScheduledEnsureOriginSuccess;31use up_common::types::AccountId;31use up_common::types::AccountId;323233parameter_types! {33parameter_types! {70 }70 }71}71}727273impl pallet_unique_scheduler::Config for Runtime {73impl pallet_unique_scheduler_v2::Config for Runtime {74 type RuntimeEvent = RuntimeEvent;74 type RuntimeEvent = RuntimeEvent;75 type RuntimeOrigin = RuntimeOrigin;75 type RuntimeOrigin = RuntimeOrigin;76 type Currency = Balances;77 type PalletsOrigin = OriginCaller;76 type PalletsOrigin = OriginCaller;78 type RuntimeCall = RuntimeCall;77 type RuntimeCall = RuntimeCall;79 type MaximumWeight = MaximumSchedulerWeight;78 type MaximumWeight = MaximumSchedulerWeight;80 type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;79 type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;81 type PrioritySetOrigin = EnsureRoot<AccountId>;80 type OriginPrivilegeCmp = EqualOrRootOnly;82 type MaxScheduledPerBlock = MaxScheduledPerBlock;81 type MaxScheduledPerBlock = MaxScheduledPerBlock;83 type WeightInfo = ();82 type WeightInfo = ();84 type CallExecutor = SchedulerPaymentExecutor;83 type Preimages = ();85 type OriginPrivilegeCmp = EqualOrRootOnly;84 type CallExecutor = SchedulerPaymentExecutor;86 type PreimageProvider = ();85 type PrioritySetOrigin = EnsureRoot<AccountId>;87 type NoPreimagePostponement = NoPreimagePostponement;88}86}8987runtime/common/config/test_pallets.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617use crate::{Runtime, RuntimeEvent};17use crate::{Runtime, RuntimeEvent, RuntimeCall};181819impl pallet_test_utils::Config for Runtime {19impl pallet_test_utils::Config for Runtime {20 type RuntimeEvent = RuntimeEvent;20 type RuntimeEvent = RuntimeEvent;21 type RuntimeCall = RuntimeCall;21}22}2223runtime/common/construct_runtime/mod.rsdiffbeforeafterboth58 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,58 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,595960 #[runtimes(opal)]60 #[runtimes(opal)]61 Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,61 Scheduler: pallet_unique_scheduler_v2::{Pallet, Call, Storage, Event<T>} = 62,626263 Configuration: pallet_configuration::{Pallet, Call, Storage} = 63,63 Configuration: pallet_configuration::{Pallet, Call, Storage} = 63,6464runtime/common/runtime_apis.rsdiffbeforeafterboth683 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]683 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]684 list_benchmark!(list, extra, pallet_refungible, Refungible);684 list_benchmark!(list, extra, pallet_refungible, Refungible);685685686 // #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]686 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]687 // list_benchmark!(list, extra, pallet_unique_scheduler, Scheduler);687 list_benchmark!(list, extra, pallet_unique_scheduler_v2, Scheduler);688688689 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]689 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]690 list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);690 list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);743 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]743 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]744 add_benchmark!(params, batches, pallet_refungible, Refungible);744 add_benchmark!(params, batches, pallet_refungible, Refungible);745745746 // #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]746 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]747 // add_benchmark!(params, batches, pallet_unique_scheduler, Scheduler);747 add_benchmark!(params, batches, pallet_unique_scheduler_v2, Scheduler);748748749 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]749 #[cfg(not(any(feature = "unique-runtime", feature = "quartz-runtime")))]750 add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);750 add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);runtime/common/scheduler.rsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617use frame_support::{17use frame_support::{18 traits::NamedReservableCurrency,19 dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},18 dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},20};19};21use sp_runtime::{20use sp_runtime::{22 traits::{Dispatchable, Applyable, Member},21 traits::{Dispatchable, Applyable, Member},23 generic::Era,24 transaction_validity::TransactionValidityError,22 transaction_validity::TransactionValidityError,25 DispatchErrorWithPostInfo, DispatchError,23 DispatchErrorWithPostInfo,26};24};27use codec::Encode;25use codec::Encode;28use crate::{Runtime, RuntimeCall, RuntimeOrigin, Balances, maintenance};26use crate::{Runtime, RuntimeCall, RuntimeOrigin, maintenance};29use up_common::types::{AccountId, Balance};27use up_common::types::AccountId;30use fp_self_contained::SelfContainedCall;28use fp_self_contained::SelfContainedCall;31use pallet_unique_scheduler::DispatchCall;29use pallet_unique_scheduler_v2::DispatchCall;32use pallet_transaction_payment::ChargeTransactionPayment;30use pallet_transaction_payment::ChargeTransactionPayment;3334type SponsorshipChargeTransactionPayment =35 pallet_charge_transaction::ChargeTransactionPayment<Runtime>;363137/// The SignedExtension to the basic transaction logic.32/// The SignedExtension to the basic transaction logic.38pub type SignedExtraScheduler = (33pub type SignedExtraScheduler = (39 frame_system::CheckSpecVersion<Runtime>,40 frame_system::CheckGenesis<Runtime>,41 frame_system::CheckEra<Runtime>,42 frame_system::CheckNonce<Runtime>,43 frame_system::CheckWeight<Runtime>,34 frame_system::CheckWeight<Runtime>,44 maintenance::CheckMaintenance,35 maintenance::CheckMaintenance,45 ChargeTransactionPayment<Runtime>,36 ChargeTransactionPayment<Runtime>,46);37);473848fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {39fn get_signed_extras() -> SignedExtraScheduler {49 (40 (50 frame_system::CheckSpecVersion::<Runtime>::new(),51 frame_system::CheckGenesis::<Runtime>::new(),52 frame_system::CheckEra::<Runtime>::from(Era::Immortal),53 frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(54 from,55 )),56 frame_system::CheckWeight::<Runtime>::new(),41 frame_system::CheckWeight::<Runtime>::new(),57 maintenance::CheckMaintenance,42 maintenance::CheckMaintenance,58 ChargeTransactionPayment::<Runtime>::from(0),43 ChargeTransactionPayment::<Runtime>::from(0),614662pub struct SchedulerPaymentExecutor;47pub struct SchedulerPaymentExecutor;634864impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>49impl<T: frame_system::Config + pallet_unique_scheduler_v2::Config, SelfContainedSignedInfo>65 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor50 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor66where51where67 <T as frame_system::Config>::RuntimeCall: Member52 <T as frame_system::Config>::RuntimeCall: Member71 + From<frame_system::Call<Runtime>>,56 + From<frame_system::Call<Runtime>>,72 SelfContainedSignedInfo: Send + Sync + 'static,57 SelfContainedSignedInfo: Send + Sync + 'static,73 RuntimeCall: From<<T as frame_system::Config>::RuntimeCall>58 RuntimeCall: From<<T as frame_system::Config>::RuntimeCall>74 + From<<T as pallet_unique_scheduler::Config>::RuntimeCall>59 + From<<T as pallet_unique_scheduler_v2::Config>::RuntimeCall>75 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,60 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,76 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,61 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,77{62{78 fn dispatch_call(63 fn dispatch_call(79 signer: Option<<T as frame_system::Config>::AccountId>,64 signer: Option<<T as frame_system::Config>::AccountId>,80 call: <T as pallet_unique_scheduler::Config>::RuntimeCall,65 call: <T as pallet_unique_scheduler_v2::Config>::RuntimeCall,81 ) -> Result<66 ) -> Result<82 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,67 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,83 TransactionValidityError,68 TransactionValidityError,88 let signed = match signer {73 let signed = match signer {89 Some(signer) => fp_self_contained::CheckedSignature::Signed(74 Some(signer) => fp_self_contained::CheckedSignature::Signed(90 signer.clone().into(),75 signer.clone().into(),91 get_signed_extras(signer.into()),76 get_signed_extras(),92 ),77 ),93 None => fp_self_contained::CheckedSignature::Unsigned,78 None => fp_self_contained::CheckedSignature::Unsigned,94 };79 };106 extrinsic.apply::<Runtime>(&dispatch_info, len)91 extrinsic.apply::<Runtime>(&dispatch_info, len)107 }92 }108109 fn reserve_balance(110 id: [u8; 16],111 sponsor: <T as frame_system::Config>::AccountId,112 call: <T as pallet_unique_scheduler::Config>::RuntimeCall,113 count: u32,114 ) -> Result<(), DispatchError> {115 let dispatch_info = call.get_dispatch_info();116 let weight: Balance =117 SponsorshipChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)118 .saturating_mul(count.into());119120 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(121 &id,122 &(sponsor.into()),123 weight,124 )125 }126127 fn pay_for_call(128 id: [u8; 16],129 sponsor: <T as frame_system::Config>::AccountId,130 call: <T as pallet_unique_scheduler::Config>::RuntimeCall,131 ) -> Result<u128, DispatchError> {132 let dispatch_info = call.get_dispatch_info();133 let weight: Balance =134 SponsorshipChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);135 Ok(136 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(137 &id,138 &(sponsor.into()),139 weight,140 ),141 )142 }143144 fn cancel_reserve(145 id: [u8; 16],146 sponsor: <T as frame_system::Config>::AccountId,147 ) -> Result<u128, DispatchError> {148 Ok(149 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(150 &id,151 &(sponsor.into()),152 u128::MAX,153 ),154 )155 }156}93}15794runtime/opal/Cargo.tomldiffbeforeafterboth41 'pallet-unique/runtime-benchmarks',41 'pallet-unique/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',43 'pallet-app-promotion/runtime-benchmarks',43 'pallet-app-promotion/runtime-benchmarks',44 'pallet-unique-scheduler/runtime-benchmarks',44 'pallet-unique-scheduler-v2/runtime-benchmarks',45 'pallet-xcm/runtime-benchmarks',45 'pallet-xcm/runtime-benchmarks',46 'sp-runtime/runtime-benchmarks',46 'sp-runtime/runtime-benchmarks',47 'xcm-builder/runtime-benchmarks',47 'xcm-builder/runtime-benchmarks',71 'cumulus-pallet-dmp-queue/try-runtime',71 'cumulus-pallet-dmp-queue/try-runtime',72 'pallet-inflation/try-runtime',72 'pallet-inflation/try-runtime',73 'pallet-unique/try-runtime',73 'pallet-unique/try-runtime',74 'pallet-unique-scheduler/try-runtime',75 'pallet-configuration/try-runtime',74 'pallet-configuration/try-runtime',76 'pallet-charge-transaction/try-runtime',75 'pallet-charge-transaction/try-runtime',77 'pallet-common/try-runtime',76 'pallet-common/try-runtime',142 'pallet-proxy-rmrk-core/std',141 'pallet-proxy-rmrk-core/std',143 'pallet-proxy-rmrk-equip/std',142 'pallet-proxy-rmrk-equip/std',144 'pallet-unique/std',143 'pallet-unique/std',145 'pallet-unique-scheduler/std',144 'pallet-unique-scheduler-v2/std',146 'pallet-charge-transaction/std',145 'pallet-charge-transaction/std',147 'up-data-structs/std',146 'up-data-structs/std',148 'sp-api/std',147 'sp-api/std',474pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }473pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }475pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }474pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }476pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }475pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }477pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }478pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }476pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }477pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false }479pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }478pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }480pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }479pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }481pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }480pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }runtime/quartz/Cargo.tomldiffbeforeafterboth40 'pallet-unique/runtime-benchmarks',40 'pallet-unique/runtime-benchmarks',41 'pallet-foreign-assets/runtime-benchmarks',41 'pallet-foreign-assets/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',43 'pallet-unique-scheduler/runtime-benchmarks',44 'pallet-xcm/runtime-benchmarks',43 'pallet-xcm/runtime-benchmarks',45 'sp-runtime/runtime-benchmarks',44 'sp-runtime/runtime-benchmarks',46 'xcm-builder/runtime-benchmarks',45 'xcm-builder/runtime-benchmarks',70 'cumulus-pallet-dmp-queue/try-runtime',69 'cumulus-pallet-dmp-queue/try-runtime',71 'pallet-inflation/try-runtime',70 'pallet-inflation/try-runtime',72 'pallet-unique/try-runtime',71 'pallet-unique/try-runtime',73 'pallet-unique-scheduler/try-runtime',74 'pallet-configuration/try-runtime',72 'pallet-configuration/try-runtime',75 'pallet-charge-transaction/try-runtime',73 'pallet-charge-transaction/try-runtime',76 'pallet-common/try-runtime',74 'pallet-common/try-runtime',139 'pallet-proxy-rmrk-core/std',137 'pallet-proxy-rmrk-core/std',140 'pallet-proxy-rmrk-equip/std',138 'pallet-proxy-rmrk-equip/std',141 'pallet-unique/std',139 'pallet-unique/std',142 'pallet-unique-scheduler/std',143 'pallet-charge-transaction/std',140 'pallet-charge-transaction/std',144 'up-data-structs/std',141 'up-data-structs/std',145 'sp-api/std',142 'sp-api/std',475pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }472pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }476pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }473pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }477pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }474pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }478pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }479# pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }475# pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }480pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }476pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }481pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }477pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }runtime/unique/Cargo.tomldiffbeforeafterboth40 'pallet-unique/runtime-benchmarks',40 'pallet-unique/runtime-benchmarks',41 'pallet-foreign-assets/runtime-benchmarks',41 'pallet-foreign-assets/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',43 'pallet-unique-scheduler/runtime-benchmarks',44 'pallet-xcm/runtime-benchmarks',43 'pallet-xcm/runtime-benchmarks',45 'sp-runtime/runtime-benchmarks',44 'sp-runtime/runtime-benchmarks',46 'xcm-builder/runtime-benchmarks',45 'xcm-builder/runtime-benchmarks',71 'cumulus-pallet-dmp-queue/try-runtime',70 'cumulus-pallet-dmp-queue/try-runtime',72 'pallet-inflation/try-runtime',71 'pallet-inflation/try-runtime',73 'pallet-unique/try-runtime',72 'pallet-unique/try-runtime',74 'pallet-unique-scheduler/try-runtime',75 'pallet-configuration/try-runtime',73 'pallet-configuration/try-runtime',76 'pallet-charge-transaction/try-runtime',74 'pallet-charge-transaction/try-runtime',77 'pallet-common/try-runtime',75 'pallet-common/try-runtime',140 'pallet-proxy-rmrk-core/std',138 'pallet-proxy-rmrk-core/std',141 'pallet-proxy-rmrk-equip/std',139 'pallet-proxy-rmrk-equip/std',142 'pallet-unique/std',140 'pallet-unique/std',143 'pallet-unique-scheduler/std',144 'pallet-charge-transaction/std',141 'pallet-charge-transaction/std',145 'up-data-structs/std',142 'up-data-structs/std',146 'sp-api/std',143 'sp-api/std',469pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }466pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }470pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }467pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }471pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }468pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }472pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }473# pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }469# pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }474pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }470pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }475pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }471pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }test-pallets/utils/Cargo.tomldiffbeforeafterboth10scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }10scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }11frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }11frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }12frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }12frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }13# pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }13pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }14pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false }15sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }141615[features]17[features]16default = ["std"]18default = ["std"]19 "scale-info/std",21 "scale-info/std",20 "frame-support/std",22 "frame-support/std",21 "frame-system/std",23 "frame-system/std",22 "pallet-unique-scheduler/std",24 "pallet-unique-scheduler-v2/std",25 "sp-std/std",23]26]24try-runtime = ["frame-support/try-runtime", "pallet-unique-scheduler/try-runtime"]27try-runtime = ["frame-support/try-runtime", "pallet-unique-scheduler-v2/try-runtime"]2528test-pallets/utils/src/lib.rsdiffbeforeafterboth222223#[frame_support::pallet]23#[frame_support::pallet]24pub mod pallet {24pub mod pallet {25 use frame_support::pallet_prelude::*;25 use frame_support::{26 pallet_prelude::*,27 dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo},28 traits::{UnfilteredDispatchable, IsSubType, OriginTrait},29 };26 use frame_system::pallet_prelude::*;30 use frame_system::pallet_prelude::*;31 use sp_std::vec::Vec;27 use pallet_unique_scheduler::{ScheduledId, Pallet as SchedulerPallet};32 use pallet_unique_scheduler_v2::{TaskName, Pallet as SchedulerPallet};283329 #[pallet::config]34 #[pallet::config]30 pub trait Config: frame_system::Config + pallet_unique_scheduler::Config {35 pub trait Config: frame_system::Config + pallet_unique_scheduler_v2::Config {31 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;36 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;3738 /// The overarching call type.39 type RuntimeCall: Parameter40 + Dispatchable<41 RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin,42 PostInfo = PostDispatchInfo,43 > + GetDispatchInfo44 + From<frame_system::Call<Self>>45 + UnfilteredDispatchable<RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin>46 + IsSubType<Call<Self>>47 + IsType<<Self as frame_system::Config>::RuntimeCall>;32 }48 }334934 #[pallet::event]50 #[pallet::event]35 #[pallet::generate_deposit(pub(super) fn deposit_event)]51 #[pallet::generate_deposit(pub(super) fn deposit_event)]36 pub enum Event<T: Config> {52 pub enum Event<T: Config> {37 ValueIsSet,53 ValueIsSet,38 ShouldRollback,54 ShouldRollback,55 BatchCompleted,39 }56 }405741 #[pallet::pallet]58 #[pallet::pallet]94 #[pallet::weight(10_000)]111 #[pallet::weight(10_000)]95 pub fn self_canceling_inc(112 pub fn self_canceling_inc(96 origin: OriginFor<T>,113 origin: OriginFor<T>,97 id: ScheduledId,114 id: TaskName,98 max_test_value: u32,115 max_test_value: u32,99 ) -> DispatchResult {116 ) -> DispatchResult {100 Self::ensure_origin_and_enabled(origin.clone())?;117 Self::ensure_origin_and_enabled(origin.clone())?;118 Self::inc_test_value(origin.clone())?;101119102 if <TestValue<T>>::get() < max_test_value {120 if <TestValue<T>>::get() == max_test_value {103 Self::inc_test_value(origin)?;104 } else {105 SchedulerPallet::<T>::cancel_named(origin, id)?;121 SchedulerPallet::<T>::cancel_named(origin, id)?;106 }122 }107123114 Ok(())130 Ok(())115 }131 }132133 #[pallet::weight(10_000)]134 pub fn batch_all(135 origin: OriginFor<T>,136 calls: Vec<<T as Config>::RuntimeCall>,137 ) -> DispatchResultWithPostInfo {138 Self::ensure_origin_and_enabled(origin.clone())?;139140 let is_root = ensure_root(origin.clone()).is_ok();141142 for call in calls {143 if is_root {144 call.dispatch_bypass_filter(origin.clone())?;145 } else {146 let mut filtered_origin = origin.clone();147 // Don't allow users to nest `batch_all` calls.148 filtered_origin.add_filter(149 move |c: &<T as frame_system::Config>::RuntimeCall| {150 let c = <T as Config>::RuntimeCall::from_ref(c);151 !matches!(c.is_sub_type(), Some(Call::batch_all { .. }))152 },153 );154 call.dispatch(filtered_origin)?;155 }156 }157158 Self::deposit_event(Event::BatchCompleted);159 Ok(None::<Weight>.into())160 }116 }161 }117}162}118163tests/src/eth/scheduling.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {expect} from 'chai';17import {expect} from 'chai';18import {EthUniqueHelper, itEth} from './util';18import {EthUniqueHelper, itSchedEth} from './util';19import {Pallets, usingPlaygrounds} from '../util';19import {Pallets, usingPlaygrounds} from '../util';202021describe('Scheduing EVM smart contracts', () => {21describe('Scheduing EVM smart contracts', () => {26 });26 });27 });27 });282829 itEth.ifWithPallets('Successfully schedules and periodically executes an EVM contract', [Pallets.Scheduler], async ({helper, privateKey}) => {29 itSchedEth.ifWithPallets('Successfully schedules and periodically executes an EVM contract', [Pallets.Scheduler], async (scheduleKind, {helper, privateKey}) => {30 const donor = await privateKey({filename: __filename});30 const donor = await privateKey({filename: __filename});31 const [alice] = await helper.arrange.createAccounts([1000n], donor);31 const [alice] = await helper.arrange.createAccounts([1000n], donor);323233 const scheduledId = await helper.arrange.makeScheduledId();33 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;343435 const deployer = await helper.eth.createAccountWithBalance(alice);35 const deployer = await helper.eth.createAccountWithBalance(alice);36 const flipper = await helper.eth.deployFlipper(deployer);36 const flipper = await helper.eth.deployFlipper(deployer);44 repetitions: 2,44 repetitions: 2,45 };45 };464647 await helper.scheduler.scheduleAfter<EthUniqueHelper>(scheduledId, waitForBlocks, {periodic})47 await helper.scheduler.scheduleAfter<EthUniqueHelper>(waitForBlocks, {scheduledId, periodic})48 .eth.sendEVM(48 .eth.sendEVM(49 alice,49 alice,50 flipper.options.address,50 flipper.options.address,tests/src/eth/util/index.tsdiffbeforeafterboth889import {EthUniqueHelper} from './playgrounds/unique.dev';9import {EthUniqueHelper} from './playgrounds/unique.dev';10import {SilentLogger, SilentConsole} from '../../util/playgrounds/unique.dev';10import {SilentLogger, SilentConsole} from '../../util/playgrounds/unique.dev';11import {SchedKind} from '../../util';111212export {EthUniqueHelper} from './playgrounds/unique.dev';13export {EthUniqueHelper} from './playgrounds/unique.dev';131482itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});83itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});83itEth.ifWithPallets = itEthIfWithPallet;84itEth.ifWithPallets = itEthIfWithPallet;8586export function itSchedEth(87 name: string,88 cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any,89 opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},90) {91 itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);92 itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts);93}94itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {only: true});95itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {skip: true});96itSchedEth.ifWithPallets = itSchedIfWithPallets;9798function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {99 return itSchedEth(name, cb, {requiredPallets: required, ...opts});100}84101tests/src/maintenanceMode.seqtest.tsdiffbeforeafterboth161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {ApiPromise} from '@polkadot/api';18import {ApiPromise} from '@polkadot/api';19import {expect, itSub, Pallets, usingPlaygrounds} from './util';19import {expect, itSched, itSub, Pallets, usingPlaygrounds} from './util';20import {itEth} from './eth/util';20import {itEth} from './eth/util';212122async function maintenanceEnabled(api: ApiPromise): Promise<boolean> {22async function maintenanceEnabled(api: ApiPromise): Promise<boolean> {162 await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;162 await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled;163 });163 });164164165 itSub.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.Scheduler], async ({helper}) => {165 itSched.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.Scheduler], async (scheduleKind, {helper}) => {166 const collection = await helper.nft.mintCollection(bob);166 const collection = await helper.nft.mintCollection(bob);167167168 const nftBeforeMM = await collection.mintToken(bob);168 const nftBeforeMM = await collection.mintToken(bob);169 const nftDuringMM = await collection.mintToken(bob);169 const nftDuringMM = await collection.mintToken(bob);170 const nftAfterMM = await collection.mintToken(bob);170 const nftAfterMM = await collection.mintToken(bob);171171172 const scheduledIdBeforeMM = '0x' + '0'.repeat(31) + '0';172 const [173 const scheduledIdDuringMM = '0x' + '0'.repeat(31) + '1';173 scheduledIdBeforeMM,174 const scheduledIdBunkerThroughMM = '0x' + '0'.repeat(31) + '2';174 scheduledIdDuringMM,175 const scheduledIdAttemptDuringMM = '0x' + '0'.repeat(31) + '3';175 scheduledIdBunkerThroughMM,176 const scheduledIdAfterMM = '0x' + '0'.repeat(31) + '4';176 scheduledIdAttemptDuringMM,177 scheduledIdAfterMM,178 ] = scheduleKind == 'named'179 ? helper.arrange.makeScheduledIds(5)180 : new Array(5);177181178 const blocksToWait = 6;182 const blocksToWait = 6;179183180 // Scheduling works before the maintenance184 // Scheduling works before the maintenance181 await nftBeforeMM.scheduleAfter(scheduledIdBeforeMM, blocksToWait)185 await nftBeforeMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdBeforeMM})182 .transfer(bob, {Substrate: superuser.address});186 .transfer(bob, {Substrate: superuser.address});183187184 await helper.wait.newBlocks(blocksToWait + 1);188 await helper.wait.newBlocks(blocksToWait + 1);185 expect(await nftBeforeMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});189 expect(await nftBeforeMM.getOwner()).to.be.deep.equal({Substrate: superuser.address});186190187 // Schedule a transaction that should occur *during* the maintenance191 // Schedule a transaction that should occur *during* the maintenance188 await nftDuringMM.scheduleAfter(scheduledIdDuringMM, blocksToWait)192 await nftDuringMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdDuringMM})189 .transfer(bob, {Substrate: superuser.address});193 .transfer(bob, {Substrate: superuser.address});190 194 191 // Schedule a transaction that should occur *after* the maintenance195 // Schedule a transaction that should occur *after* the maintenance192 await nftDuringMM.scheduleAfter(scheduledIdBunkerThroughMM, blocksToWait * 2)196 await nftDuringMM.scheduleAfter(blocksToWait * 2, {scheduledId: scheduledIdBunkerThroughMM})193 .transfer(bob, {Substrate: superuser.address});197 .transfer(bob, {Substrate: superuser.address});194198195 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);199 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []);200 expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: bob.address});204 expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: bob.address});201205202 // Any attempts to schedule a tx during the MM should be rejected206 // Any attempts to schedule a tx during the MM should be rejected203 await expect(nftDuringMM.scheduleAfter(scheduledIdAttemptDuringMM, blocksToWait)207 await expect(nftDuringMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAttemptDuringMM})204 .transfer(bob, {Substrate: superuser.address}))208 .transfer(bob, {Substrate: superuser.address}))205 .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);209 .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/);206210207 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);211 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []);208 expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;212 expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false;209213210 // Scheduling works after the maintenance214 // Scheduling works after the maintenance211 await nftAfterMM.scheduleAfter(scheduledIdAfterMM, blocksToWait)215 await nftAfterMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAfterMM})212 .transfer(bob, {Substrate: superuser.address});216 .transfer(bob, {Substrate: superuser.address});213 217 214 await helper.wait.newBlocks(blocksToWait + 1);218 await helper.wait.newBlocks(blocksToWait + 1);tests/src/scheduler.seqtest.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {expect, itSub, Pallets, usingPlaygrounds} from './util';17import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {DevUniqueHelper} from './util/playgrounds/unique.dev';19import {DevUniqueHelper} from './util/playgrounds/unique.dev';202021describe('Scheduling token and balance transfers', () => {21describe('Scheduling token and balance transfers', () => {22 let superuser: IKeyringPair;22 let alice: IKeyringPair;23 let alice: IKeyringPair;23 let bob: IKeyringPair;24 let bob: IKeyringPair;24 let charlie: IKeyringPair;25 let charlie: IKeyringPair;252626 before(async () => {27 before(async function() {27 await usingPlaygrounds(async (helper, privateKeyWrapper) => {28 await usingPlaygrounds(async (helper, privateKey) => {28 alice = await privateKeyWrapper('//Alice');29 requirePalletsOrSkip(this, helper, [Pallets.Scheduler]);29 bob = await privateKeyWrapper('//Bob');30 charlie = await privateKeyWrapper('//Charlie');313031 superuser = await privateKey('//Alice');32 const donor = await privateKey({filename: __filename});33 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);3432 await helper.testUtils.enable();35 await helper.testUtils.enable();33 });36 });34 });37 });353836 itSub.ifWithPallets('Can delay a transfer of an owned token', [Pallets.Scheduler], async ({helper}) => {39 beforeEach(async () => {40 await usingPlaygrounds(async (helper) => {41 await helper.wait.noScheduledTasks();42 });43 });4445 itSched('Can delay a transfer of an owned token', async (scheduleKind, {helper}) => {37 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});46 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});38 const token = await collection.mintToken(alice);47 const token = await collection.mintToken(alice);39 const schedulerId = await helper.arrange.makeScheduledId();48 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;40 const blocksBeforeExecution = 4;49 const blocksBeforeExecution = 4;4150 42 await token.scheduleAfter(schedulerId, blocksBeforeExecution)51 await token.scheduleAfter(blocksBeforeExecution, {scheduledId})43 .transfer(alice, {Substrate: bob.address});52 .transfer(alice, {Substrate: bob.address});53 const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;445445 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});55 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});465647 await helper.wait.newBlocks(blocksBeforeExecution + 1);57 await helper.wait.forParachainBlockNumber(executionBlock);485849 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});59 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});50 });60 });516152 itSub.ifWithPallets('Can transfer funds periodically', [Pallets.Scheduler], async ({helper}) => {62 itSched('Can transfer funds periodically', async (scheduleKind, {helper}) => {53 const scheduledId = await helper.arrange.makeScheduledId();63 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;54 const waitForBlocks = 1;64 const waitForBlocks = 1;556556 const amount = 1n * helper.balance.getOneTokenNominal();66 const amount = 1n * helper.balance.getOneTokenNominal();617162 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);72 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);637364 await helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {periodic})74 await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})65 .balance.transferToSubstrate(alice, bob.address, amount);75 .balance.transferToSubstrate(alice, bob.address, amount);76 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;667767 await helper.wait.newBlocks(waitForBlocks + 1);78 await helper.wait.forParachainBlockNumber(executionBlock);687969 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);80 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);70 expect(bobsBalanceAfterFirst)81 expect(bobsBalanceAfterFirst)73 '#1 Balance of the recipient should be increased by 1 * amount',84 '#1 Balance of the recipient should be increased by 1 * amount',74 );85 );758676 await helper.wait.newBlocks(periodic.period);87 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);778878 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);89 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);79 expect(bobsBalanceAfterSecond)90 expect(bobsBalanceAfterSecond)83 );94 );84 });95 });859686 itSub.ifWithPallets('Can cancel a scheduled operation which has not yet taken effect', [Pallets.Scheduler], async ({helper}) => {97 itSub('Can cancel a scheduled operation which has not yet taken effect', async ({helper}) => {87 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});98 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});88 const token = await collection.mintToken(alice);99 const token = await collection.mintToken(alice);8910090 const scheduledId = await helper.arrange.makeScheduledId();101 const scheduledId = helper.arrange.makeScheduledId();91 const waitForBlocks = 4;102 const waitForBlocks = 4;9210393 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});104 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});9410595 await token.scheduleAfter(scheduledId, waitForBlocks)106 await token.scheduleAfter(waitForBlocks, {scheduledId})96 .transfer(alice, {Substrate: bob.address});107 .transfer(alice, {Substrate: bob.address});108 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;9710998 await helper.scheduler.cancelScheduled(alice, scheduledId);110 await helper.scheduler.cancelScheduled(alice, scheduledId);99111100 await helper.wait.newBlocks(waitForBlocks + 1);112 await helper.wait.forParachainBlockNumber(executionBlock);101113102 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});114 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});103 });115 });104116105 itSub.ifWithPallets('Can cancel a periodic operation (transfer of funds)', [Pallets.Scheduler], async ({helper}) => {117 itSub('Can cancel a periodic operation (transfer of funds)', async ({helper}) => {106 const waitForBlocks = 1;118 const waitForBlocks = 1;107 const periodic = {119 const periodic = {108 period: 3,120 period: 3,109 repetitions: 2,121 repetitions: 2,110 };122 };111123112 const scheduledId = await helper.arrange.makeScheduledId();124 const scheduledId = helper.arrange.makeScheduledId();113125114 const amount = 1n * helper.balance.getOneTokenNominal();126 const amount = 1n * helper.balance.getOneTokenNominal();115127116 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);128 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);117129118 await helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {periodic})130 await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic})119 .balance.transferToSubstrate(alice, bob.address, amount);131 .balance.transferToSubstrate(alice, bob.address, amount);132 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;120133121 await helper.wait.newBlocks(waitForBlocks + 1);134 await helper.wait.forParachainBlockNumber(executionBlock);122135123 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);136 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);124137129 );142 );130143131 await helper.scheduler.cancelScheduled(alice, scheduledId);144 await helper.scheduler.cancelScheduled(alice, scheduledId);132 await helper.wait.newBlocks(periodic.period);145 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);133146134 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);147 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);135 expect(bobsBalanceAfterSecond)148 expect(bobsBalanceAfterSecond)139 );152 );140 });153 });141154142 itSub.ifWithPallets('Scheduled tasks are transactional', [Pallets.Scheduler, Pallets.TestUtils], async ({helper}) => {155 itSched('scheduler will not insert more tasks than allowed', async (scheduleKind, {helper}) => {156 const maxScheduledPerBlock = 50;157 let fillScheduledIds = new Array(maxScheduledPerBlock);158 let extraScheduledId = undefined;159 160 if (scheduleKind == 'named') {161 const scheduledIds = helper.arrange.makeScheduledIds(maxScheduledPerBlock + 1);162 fillScheduledIds = scheduledIds.slice(0, maxScheduledPerBlock);163 extraScheduledId = scheduledIds[maxScheduledPerBlock];164 }165166 // Since the dev node has Instant Seal,167 // we need a larger gap between the current block and the target one.168 //169 // We will schedule `maxScheduledPerBlock` transaction into the target block,170 // so we need at least `maxScheduledPerBlock`-wide gap.171 // We add some additional blocks to this gap to mitigate possible PolkadotJS delays.172 const waitForBlocks = await helper.arrange.isDevNode() ? maxScheduledPerBlock + 5 : 5;173174 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks;175176 const amount = 1n * helper.balance.getOneTokenNominal();177178 const balanceBefore = await helper.balance.getSubstrate(bob.address);179180 // Fill the target block181 for (let i = 0; i < maxScheduledPerBlock; i++) {182 await helper.scheduler.scheduleAt(executionBlock, {scheduledId: fillScheduledIds[i]})183 .balance.transferToSubstrate(superuser, bob.address, amount);184 }185186 // Try to schedule a task into a full block187 await expect(helper.scheduler.scheduleAt(executionBlock, {scheduledId: extraScheduledId})188 .balance.transferToSubstrate(superuser, bob.address, amount))189 .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/);190191 await helper.wait.forParachainBlockNumber(executionBlock);192193 const balanceAfter = await helper.balance.getSubstrate(bob.address);194195 expect(balanceAfter > balanceBefore).to.be.true;196197 const diff = balanceAfter - balanceBefore;198 expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock));199 });200201 itSched.ifWithPallets('Scheduled tasks are transactional', [Pallets.TestUtils], async (scheduleKind, {helper}) => {143 const scheduledId = await helper.arrange.makeScheduledId();202 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;144 const waitForBlocks = 4;203 const waitForBlocks = 4;145204146 const initTestVal = 42;205 const initTestVal = 42;147 const changedTestVal = 111;206 const changedTestVal = 111;148207149 await helper.testUtils.setTestValue(alice, initTestVal);208 await helper.testUtils.setTestValue(alice, initTestVal);150209151 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks)210 await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId})152 .testUtils.setTestValueAndRollback(alice, changedTestVal);211 .testUtils.setTestValueAndRollback(alice, changedTestVal);212 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;153213154 await helper.wait.newBlocks(waitForBlocks + 1);214 await helper.wait.forParachainBlockNumber(executionBlock);155215156 const testVal = await helper.testUtils.testValue();216 const testVal = await helper.testUtils.testValue();157 expect(testVal, 'The test value should NOT be commited')217 expect(testVal, 'The test value should NOT be commited')158 .to.be.equal(initTestVal);218 .to.be.equal(initTestVal);159 });219 });160220161 itSub.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.Scheduler, Pallets.TestUtils], async function({helper}) {221 itSched.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.TestUtils], async function(scheduleKind, {helper}) {162 const scheduledId = await helper.arrange.makeScheduledId();222 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;163 const waitForBlocks = 4;223 const waitForBlocks = 4;164 const periodic = {224 const periodic = {165 period: 2,225 period: 2,172 const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen))232 const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen))173 .partialFee.toBigInt();233 .partialFee.toBigInt();174234175 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks, {periodic})235 await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})176 .testUtils.justTakeFee(alice);236 .testUtils.justTakeFee(alice);237 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;177238178 await helper.wait.newBlocks(1);179180 const aliceInitBalance = await helper.balance.getSubstrate(alice.address);239 const aliceInitBalance = await helper.balance.getSubstrate(alice.address);181 let diff;240 let diff;182241183 await helper.wait.newBlocks(waitForBlocks);242 await helper.wait.forParachainBlockNumber(executionBlock);184243185 const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address);244 const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address);186 expect(245 expect(194 'Scheduled task should take the right amount of fees',253 'Scheduled task should take the right amount of fees',195 );254 );196255197 await helper.wait.newBlocks(periodic.period);256 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);198257199 const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);258 const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);200 expect(259 expect(211270212 // Check if we can cancel a scheduled periodic operation271 // Check if we can cancel a scheduled periodic operation213 // in the same block in which it is running272 // in the same block in which it is running214 itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.Scheduler, Pallets.TestUtils], async ({helper}) => {273 itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.TestUtils], async ({helper}) => {215 const currentBlockNumber = await helper.chain.getLatestBlockNumber();274 const currentBlockNumber = await helper.chain.getLatestBlockNumber();216 const blocksBeforeExecution = 10;275 const blocksBeforeExecution = 10;217 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;276 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;218277219 const [278 const [220 scheduledId,279 scheduledId,221 scheduledCancelId,280 scheduledCancelId,222 ] = await helper.arrange.makeScheduledIds(2);281 ] = helper.arrange.makeScheduledIds(2);223282224 const periodic = {283 const periodic = {225 period: 5,284 period: 5,232291233 await helper.testUtils.setTestValue(alice, initTestVal);292 await helper.testUtils.setTestValue(alice, initTestVal);234293235 await helper.scheduler.scheduleAt<DevUniqueHelper>(scheduledId, firstExecutionBlockNumber, {periodic})294 await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {scheduledId, periodic})236 .testUtils.incTestValue(alice);295 .testUtils.incTestValue(alice);237296238 // Cancel the inc tx after 2 executions297 // Cancel the inc tx after 2 executions239 // *in the same block* in which the second execution is scheduled298 // *in the same block* in which the second execution is scheduled240 await helper.scheduler.scheduleAt(299 await helper.scheduler.scheduleAt(241 scheduledCancelId,242 firstExecutionBlockNumber + periodic.period,300 firstExecutionBlockNumber + periodic.period,301 {scheduledId: scheduledCancelId},243 ).scheduler.cancelScheduled(alice, scheduledId);302 ).scheduler.cancelScheduled(alice, scheduledId);244303245 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);304 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);261 }320 }262 });321 });263322264 itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.Scheduler, Pallets.TestUtils], async ({helper}) => {323 itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.TestUtils], async ({helper}) => {265 const scheduledId = await helper.arrange.makeScheduledId();324 const scheduledId = helper.arrange.makeScheduledId();266 const waitForBlocks = 4;325 const waitForBlocks = 4;267 const periodic = {326 const periodic = {268 period: 2,327 period: 2,274333275 await helper.testUtils.setTestValue(alice, initTestVal);334 await helper.testUtils.setTestValue(alice, initTestVal);276335277 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks, {periodic})336 await helper.scheduler.scheduleAfter<DevUniqueHelper>(waitForBlocks, {scheduledId, periodic})278 .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal);337 .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal);338 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;279339280 await helper.wait.newBlocks(waitForBlocks + 1);340 await helper.wait.forParachainBlockNumber(executionBlock);281341282 // execution #0342 // execution #0283 expect(await helper.testUtils.testValue())343 expect(await helper.testUtils.testValue())284 .to.be.equal(initTestVal + 1);344 .to.be.equal(initTestVal + 1);285345286 await helper.wait.newBlocks(periodic.period);346 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);287347288 // execution #1348 // execution #1289 expect(await helper.testUtils.testValue())349 expect(await helper.testUtils.testValue())290 .to.be.equal(initTestVal + 2);350 .to.be.equal(initTestVal + 2);291351292 await helper.wait.newBlocks(periodic.period);352 await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period);293353294 // <canceled>354 // <canceled>295 expect(await helper.testUtils.testValue())355 expect(await helper.testUtils.testValue())296 .to.be.equal(initTestVal + 2);356 .to.be.equal(initTestVal + 2);297 });357 });298358299 itSub.ifWithPallets('Root can cancel any scheduled operation', [Pallets.Scheduler], async ({helper}) => {359 itSub('Root can cancel any scheduled operation', async ({helper}) => {300 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});360 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});301 const token = await collection.mintToken(bob);361 const token = await collection.mintToken(bob);302362303 const scheduledId = await helper.arrange.makeScheduledId();363 const scheduledId = helper.arrange.makeScheduledId();304 const waitForBlocks = 4;364 const waitForBlocks = 4;305365306 await token.scheduleAfter(scheduledId, waitForBlocks)366 await token.scheduleAfter(waitForBlocks, {scheduledId})307 .transfer(bob, {Substrate: alice.address});367 .transfer(bob, {Substrate: alice.address});368 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;308369309 await helper.getSudo().scheduler.cancelScheduled(alice, scheduledId);370 await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId);310371311 await helper.wait.newBlocks(waitForBlocks + 1);372 await helper.wait.forParachainBlockNumber(executionBlock);312373313 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});374 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});314 });375 });315376316 itSub.ifWithPallets('Root can set prioritized scheduled operation', [Pallets.Scheduler], async ({helper}) => {377 itSched('Root can set prioritized scheduled operation', async (scheduleKind, {helper}) => {317 const scheduledId = await helper.arrange.makeScheduledId();378 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;318 const waitForBlocks = 4;379 const waitForBlocks = 4;319380320 const amount = 42n * helper.balance.getOneTokenNominal();381 const amount = 42n * helper.balance.getOneTokenNominal();321382322 const balanceBefore = await helper.balance.getSubstrate(charlie.address);383 const balanceBefore = await helper.balance.getSubstrate(charlie.address);323384324 await helper.getSudo()385 await helper.getSudo()325 .scheduler.scheduleAfter(scheduledId, waitForBlocks, {priority: 42})386 .scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42})326 .balance.forceTransferToSubstrate(alice, bob.address, charlie.address, amount);387 .balance.forceTransferToSubstrate(superuser, bob.address, charlie.address, amount);388 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;327389328 await helper.wait.newBlocks(waitForBlocks + 1);390 await helper.wait.forParachainBlockNumber(executionBlock);329391330 const balanceAfter = await helper.balance.getSubstrate(charlie.address);392 const balanceAfter = await helper.balance.getSubstrate(charlie.address);331393335 expect(diff).to.be.equal(amount);397 expect(diff).to.be.equal(amount);336 });398 });337399338 itSub.ifWithPallets("Root can change scheduled operation's priority", [Pallets.Scheduler], async ({helper}) => {400 itSub("Root can change scheduled operation's priority", async ({helper}) => {339 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});401 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});340 const token = await collection.mintToken(bob);402 const token = await collection.mintToken(bob);341403342 const scheduledId = await helper.arrange.makeScheduledId();404 const scheduledId = helper.arrange.makeScheduledId();343 const waitForBlocks = 6;405 const waitForBlocks = 6;344406345 await token.scheduleAfter(scheduledId, waitForBlocks)407 await token.scheduleAfter(waitForBlocks, {scheduledId})346 .transfer(bob, {Substrate: alice.address});408 .transfer(bob, {Substrate: alice.address});409 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;347410348 const priority = 112;411 const priority = 112;349 await helper.getSudo().scheduler.changePriority(alice, scheduledId, priority);412 await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority);350413351 const priorityChanged = await helper.wait.event(414 const priorityChanged = await helper.wait.event(352 waitForBlocks,415 waitForBlocks,355 );418 );356419357 expect(priorityChanged !== null).to.be.true;420 expect(priorityChanged !== null).to.be.true;421422 const [blockNumber, index] = priorityChanged!.event.data[0].toJSON() as any[];423 expect(blockNumber).to.be.equal(executionBlock);424 expect(index).to.be.equal(0);425358 expect(priorityChanged!.event.data[2].toString()).to.be.equal(priority.toString());426 expect(priorityChanged!.event.data[1].toString()).to.be.equal(priority.toString());359 });427 });360428361 itSub.ifWithPallets('Prioritized operations executes in valid order', [Pallets.Scheduler], async ({helper}) => {429 itSub('Prioritized operations execute in valid order', async ({helper}) => {362 const [430 const [363 scheduledFirstId,431 scheduledFirstId,364 scheduledSecondId,432 scheduledSecondId,365 ] = await helper.arrange.makeScheduledIds(2);433 ] = helper.arrange.makeScheduledIds(2);366434367 const currentBlockNumber = await helper.chain.getLatestBlockNumber();435 const currentBlockNumber = await helper.chain.getLatestBlockNumber();368 const blocksBeforeExecution = 6;436 const blocksBeforeExecution = 6;379 const amount = 1n * helper.balance.getOneTokenNominal();447 const amount = 1n * helper.balance.getOneTokenNominal();380448381 // Scheduler a task with a lower priority first, then with a higher priority449 // Scheduler a task with a lower priority first, then with a higher priority382 await helper.getSudo().scheduler.scheduleAt(scheduledFirstId, firstExecutionBlockNumber, {priority: prioLow, periodic})450 await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {451 scheduledId: scheduledFirstId,452 priority: prioLow,453 periodic,383 .balance.forceTransferToSubstrate(alice, alice.address, bob.address, amount);454 }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);384455385 await helper.getSudo().scheduler.scheduleAt(scheduledSecondId, firstExecutionBlockNumber, {priority: prioHigh, periodic})456 await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, {457 scheduledId: scheduledSecondId,458 priority: prioHigh,459 periodic,386 .balance.forceTransferToSubstrate(alice, alice.address, bob.address, amount);460 }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);387461388 const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');462 const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');389463390 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);464 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);391465392 // Flip priorities466 // Flip priorities393 await helper.getSudo().scheduler.changePriority(alice, scheduledFirstId, prioHigh);467 await helper.getSudo().scheduler.changePriority(superuser, scheduledFirstId, prioHigh);394 await helper.getSudo().scheduler.changePriority(alice, scheduledSecondId, prioLow);468 await helper.getSudo().scheduler.changePriority(superuser, scheduledSecondId, prioLow);395469396 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);470 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);397471410 expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);484 expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);411 });485 });486487 itSched('Periodic operations always can be rescheduled', async (scheduleKind, {helper}) => {488 const maxScheduledPerBlock = 50;489 const numFilledBlocks = 3;490 const ids = helper.arrange.makeScheduledIds(numFilledBlocks * maxScheduledPerBlock + 1);491 const periodicId = scheduleKind == 'named' ? ids[0] : undefined;492 const fillIds = ids.slice(1);493494 const fillScheduleFn = scheduleKind == 'named' ? 'scheduleNamed' : 'schedule';495496 const initTestVal = 0;497 const firstExecTestVal = 1;498 const secondExecTestVal = 2;499 await helper.testUtils.setTestValue(alice, initTestVal);500501 const currentBlockNumber = await helper.chain.getLatestBlockNumber();502 const blocksBeforeExecution = 8;503 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;504505 const period = 5;506507 const periodic = {508 period,509 repetitions: 2,510 };511512 // Fill `numFilledBlocks` blocks beginning from the block in which the second execution should occur513 const txs = [];514 for (let offset = 0; offset < numFilledBlocks; offset ++) {515 for (let i = 0; i < maxScheduledPerBlock; i++) {516517 const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);518519 const when = firstExecutionBlockNumber + period + offset;520 const mandatoryArgs = [when, null, null, scheduledTx];521 const scheduleArgs = scheduleKind == 'named'522 ? [fillIds[i + offset * maxScheduledPerBlock], ...mandatoryArgs]523 : mandatoryArgs;524525 const tx = helper.constructApiCall(`api.tx.scheduler.${fillScheduleFn}`, scheduleArgs);526527 txs.push(tx);528 }529 }530 await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true);531532 await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {533 scheduledId: periodicId,534 periodic,535 }).testUtils.incTestValue(alice);536537 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);538 expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal);539540 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks);541542 // The periodic operation should be postponed by `numFilledBlocks`543 for (let i = 0; i < numFilledBlocks; i++) {544 expect(await helper.testUtils.testValue(firstExecutionBlockNumber + period + i)).to.be.equal(firstExecTestVal);545 }546547 // After the `numFilledBlocks` the periodic operation will eventually be executed548 expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal);549 });550551 itSched('scheduled operations does not change nonce', async (scheduleKind, {helper}) => {552 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;553 const blocksBeforeExecution = 4;554555 await helper.scheduler556 .scheduleAfter<DevUniqueHelper>(blocksBeforeExecution, {scheduledId})557 .balance.transferToSubstrate(alice, bob.address, 1n);558 const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;559560 const initNonce = await helper.chain.getNonce(alice.address);561562 await helper.wait.forParachainBlockNumber(executionBlock);563564 const finalNonce = await helper.chain.getNonce(alice.address);565566 expect(initNonce).to.be.equal(finalNonce);567 });412});568});413569414describe('Negative Test: Scheduling', () => {570describe('Negative Test: Scheduling', () => {415 let alice: IKeyringPair;571 let alice: IKeyringPair;416 let bob: IKeyringPair;572 let bob: IKeyringPair;417573418 before(async () => {574 before(async function() {419 await usingPlaygrounds(async (helper, privateKeyWrapper) => {575 await usingPlaygrounds(async (helper, privateKey) => {420 alice = await privateKeyWrapper('//Alice');576 requirePalletsOrSkip(this, helper, [Pallets.Scheduler]);421 bob = await privateKeyWrapper('//Bob');422577578 const donor = await privateKey({filename: __filename});579 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);580423 await helper.testUtils.enable();581 await helper.testUtils.enable();424 });582 });425 });583 });426584427 itSub.ifWithPallets("Can't overwrite a scheduled ID", [Pallets.Scheduler], async ({helper}) => {585 itSub("Can't overwrite a scheduled ID", async ({helper}) => {428 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});586 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});429 const token = await collection.mintToken(alice);587 const token = await collection.mintToken(alice);430588431 const scheduledId = await helper.arrange.makeScheduledId();589 const scheduledId = helper.arrange.makeScheduledId();432 const waitForBlocks = 4;590 const waitForBlocks = 4;433591434 await token.scheduleAfter(scheduledId, waitForBlocks)592 await token.scheduleAfter(waitForBlocks, {scheduledId})435 .transfer(alice, {Substrate: bob.address});593 .transfer(alice, {Substrate: bob.address});594 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;436595437 const scheduled = helper.scheduler.scheduleAfter(scheduledId, waitForBlocks);596 const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId});438 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal()))597 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal()))439 .to.be.rejectedWith(/scheduler\.FailedToSchedule/);598 .to.be.rejectedWith(/scheduler\.FailedToSchedule/);440599441 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);600 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);442601443 await helper.wait.newBlocks(waitForBlocks + 1);602 await helper.wait.forParachainBlockNumber(executionBlock);444603445 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);604 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);446605447 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});606 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});448 expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter);607 expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter);449 });608 });450609451 itSub.ifWithPallets("Can't cancel an operation which is not scheduled", [Pallets.Scheduler], async ({helper}) => {610 itSub("Can't cancel an operation which is not scheduled", async ({helper}) => {452 const scheduledId = await helper.arrange.makeScheduledId();611 const scheduledId = helper.arrange.makeScheduledId();453 await expect(helper.scheduler.cancelScheduled(alice, scheduledId))612 await expect(helper.scheduler.cancelScheduled(alice, scheduledId))454 .to.be.rejectedWith(/scheduler\.NotFound/);613 .to.be.rejectedWith(/scheduler\.NotFound/);455 });614 });456615457 itSub.ifWithPallets("Can't cancel a non-owned scheduled operation", [Pallets.Scheduler], async ({helper}) => {616 itSub("Can't cancel a non-owned scheduled operation", async ({helper}) => {458 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});617 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});459 const token = await collection.mintToken(alice);618 const token = await collection.mintToken(alice);460619461 const scheduledId = await helper.arrange.makeScheduledId();620 const scheduledId = helper.arrange.makeScheduledId();462 const waitForBlocks = 4;621 const waitForBlocks = 4;463622464 await token.scheduleAfter(scheduledId, waitForBlocks)623 await token.scheduleAfter(waitForBlocks, {scheduledId})465 .transfer(alice, {Substrate: bob.address});624 .transfer(alice, {Substrate: bob.address});625 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;466626467 await expect(helper.scheduler.cancelScheduled(bob, scheduledId))627 await expect(helper.scheduler.cancelScheduled(bob, scheduledId))468 .to.be.rejectedWith(/BadOrigin/);628 .to.be.rejectedWith(/BadOrigin/);469629470 await helper.wait.newBlocks(waitForBlocks + 1);630 await helper.wait.forParachainBlockNumber(executionBlock);471631472 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});632 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});473 });633 });474634475 itSub.ifWithPallets("Regular user can't set prioritized scheduled operation", [Pallets.Scheduler], async ({helper}) => {635 itSched("Regular user can't set prioritized scheduled operation", async (scheduleKind, {helper}) => {476 const scheduledId = await helper.arrange.makeScheduledId();636 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;477 const waitForBlocks = 4;637 const waitForBlocks = 4;478638479 const amount = 42n * helper.balance.getOneTokenNominal();639 const amount = 42n * helper.balance.getOneTokenNominal();480640481 const balanceBefore = await helper.balance.getSubstrate(bob.address);641 const balanceBefore = await helper.balance.getSubstrate(bob.address);482642483 const scheduled = helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {priority: 42});643 const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42});484 644 485 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount))645 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount))486 .to.be.rejectedWith(/BadOrigin/);646 .to.be.rejectedWith(/BadOrigin/);647648 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;487649488 await helper.wait.newBlocks(waitForBlocks + 1);650 await helper.wait.forParachainBlockNumber(executionBlock);489651490 const balanceAfter = await helper.balance.getSubstrate(bob.address);652 const balanceAfter = await helper.balance.getSubstrate(bob.address);491653492 expect(balanceAfter).to.be.equal(balanceBefore);654 expect(balanceAfter).to.be.equal(balanceBefore);493 });655 });494656495 itSub.ifWithPallets("Regular user can't change scheduled operation's priority", [Pallets.Scheduler], async ({helper}) => {657 itSub("Regular user can't change scheduled operation's priority", async ({helper}) => {496 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});658 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});497 const token = await collection.mintToken(bob);659 const token = await collection.mintToken(bob);498660499 const scheduledId = await helper.arrange.makeScheduledId();661 const scheduledId = helper.arrange.makeScheduledId();500 const waitForBlocks = 4;662 const waitForBlocks = 4;501663502 await token.scheduleAfter(scheduledId, waitForBlocks)664 await token.scheduleAfter(waitForBlocks, {scheduledId})503 .transfer(bob, {Substrate: alice.address});665 .transfer(bob, {Substrate: alice.address});504666505 const priority = 112;667 const priority = 112;522 // let bob: IKeyringPair;684 // let bob: IKeyringPair;523685524 // before(async() => {686 // before(async() => {525 // await usingApi(async (_, privateKeyWrapper) => {687 // await usingApi(async (_, privateKey) => {526 // alice = privateKeyWrapper('//Alice');688 // alice = privateKey('//Alice');527 // bob = privateKeyWrapper('//Bob');689 // bob = privateKey('//Bob');528 // });690 // });529 // });691 // });530692550 });712 });551713552 it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {714 it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {553 // await usingApi(async (api, privateKeyWrapper) => {715 // await usingApi(async (api, privateKey) => {554 // // Find an empty, unused account716 // // Find an empty, unused account555 // const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);717 // const zeroBalance = await findUnusedAddress(api, privateKey);556718557 // const collectionId = await createCollectionExpectSuccess();719 // const collectionId = await createCollectionExpectSuccess();558720591 it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {753 it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {592 // const collectionId = await createCollectionExpectSuccess();754 // const collectionId = await createCollectionExpectSuccess();593755594 // await usingApi(async (api, privateKeyWrapper) => {756 // await usingApi(async (api, privateKey) => {595 // const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);757 // const zeroBalance = await findUnusedAddress(api, privateKey);596 // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);758 // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);597 // await submitTransactionAsync(alice, balanceTx);759 // await submitTransactionAsync(alice, balanceTx);598760622 // await setCollectionSponsorExpectSuccess(collectionId, bob.address);784 // await setCollectionSponsorExpectSuccess(collectionId, bob.address);623 // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');785 // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');624786625 // await usingApi(async (api, privateKeyWrapper) => {787 // await usingApi(async (api, privateKey) => {626 // const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);788 // const zeroBalance = await findUnusedAddress(api, privateKey);627789628 // await enablePublicMintingExpectSuccess(alice, collectionId);790 // await enablePublicMintingExpectSuccess(alice, collectionId);629 // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);791 // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);tests/src/util/index.tsdiffbeforeafterboth130itSubIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {skip: true});130itSubIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSubIfWithPallet(name, required, cb, {skip: true});131itSub.ifWithPallets = itSubIfWithPallet;131itSub.ifWithPallets = itSubIfWithPallet;132133export type SchedKind = 'anon' | 'named';134135export function itSched(136 name: string,137 cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any,138 opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},139) {140 itSub(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);141 itSub(name + ' (named scheduling)', (apis) => cb('named', apis), opts);142}143itSched.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {only: true});144itSched.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any) => itSched(name, cb, {skip: true});145itSched.ifWithPallets = itSchedIfWithPallets;146147function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise<IKeyringPair> }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {148 return itSched(name, cb, {requiredPallets: required, ...opts});149}132150133export function describeXCM(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {151export function describeXCM(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) {134 (process.env.RUN_XCM_TESTS && !opts.skip152 (process.env.RUN_XCM_TESTS && !opts.skiptests/src/util/playgrounds/types.tsdiffbeforeafterboth172}172}173173174export interface ISchedulerOptions {174export interface ISchedulerOptions {175 scheduledId?: string,175 priority?: number,176 priority?: number,176 periodic?: {177 periodic?: {177 period: number,178 period: number,tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth308 return encodeAddress(address);308 return encodeAddress(address);309 }309 }310310311 async makeScheduledIds(num: number): Promise<string[]> {311 makeScheduledIds(num: number): string[] {312 await this.helper.wait.noScheduledTasks();313314 function makeId(slider: number) {312 function makeId(slider: number) {315 const scheduledIdSize = 32;313 const scheduledIdSize = 64;316 const hexId = slider.toString(16);314 const hexId = slider.toString(16);317 const prefixSize = scheduledIdSize - hexId.length;315 const prefixSize = scheduledIdSize - hexId.length;318316330 return ids;328 return ids;331 }329 }332330333 async makeScheduledId(): Promise<string> {331 makeScheduledId(): string {334 return (await this.makeScheduledIds(1))[0];332 return (this.makeScheduledIds(1))[0];335 }333 }336334337 async captureEvents(eventSection: string, eventMethod: string): Promise<EventCapture> {335 async captureEvents(eventSection: string, eventMethod: string): Promise<EventCapture> {537 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true);535 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true);538 }536 }539537540 async testValue() {538 async testValue(blockIdx?: number) {539 const api = blockIdx541 return (await this.helper.callRpc('api.query.testUtils.testValue', [])).toNumber();540 ? await this.helper.getApi().at(await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockIdx]))541 : this.helper.getApi();542543 return (await api.query.testUtils.testValue()).toJSON();542 }544 }543545544 async justTakeFee(signer: TSigner) {546 async justTakeFee(signer: TSigner) {tests/src/util/playgrounds/unique.tsdiffbeforeafterboth2560 }2560 }256125612562 scheduleAt<T extends UniqueHelper>(2562 scheduleAt<T extends UniqueHelper>(2563 scheduledId: string,2564 executionBlockNumber: number,2563 executionBlockNumber: number,2565 options: ISchedulerOptions = {},2564 options: ISchedulerOptions = {},2566 ) {2565 ) {2567 return this.schedule<T>('scheduleNamed', scheduledId, executionBlockNumber, options);2566 return this.schedule<T>('schedule', executionBlockNumber, options);2568 }2567 }256925682570 scheduleAfter<T extends UniqueHelper>(2569 scheduleAfter<T extends UniqueHelper>(2571 scheduledId: string,2572 blocksBeforeExecution: number,2570 blocksBeforeExecution: number,2573 options: ISchedulerOptions = {},2571 options: ISchedulerOptions = {},2574 ) {2572 ) {2575 return this.schedule<T>('scheduleNamedAfter', scheduledId, blocksBeforeExecution, options);2573 return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2576 }2574 }257725752578 schedule<T extends UniqueHelper>(2576 schedule<T extends UniqueHelper>(2579 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter',2577 scheduleFn: 'schedule' | 'scheduleAfter',2580 scheduledId: string,2581 blocksNum: number,2578 blocksNum: number,2582 options: ISchedulerOptions = {},2579 options: ISchedulerOptions = {},2583 ) {2580 ) {2584 // eslint-disable-next-line @typescript-eslint/naming-convention2581 // eslint-disable-next-line @typescript-eslint/naming-convention2585 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2582 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2586 return this.helper.clone(ScheduledHelperType, {2583 return this.helper.clone(ScheduledHelperType, {2587 scheduleFn,2584 scheduleFn,2588 scheduledId,2589 blocksNum,2585 blocksNum,2590 options,2586 options,2591 }) as T;2587 }) as T;2874// eslint-disable-next-line @typescript-eslint/naming-convention2870// eslint-disable-next-line @typescript-eslint/naming-convention2875function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2871function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2876 return class extends Base {2872 return class extends Base {2877 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter';2873 scheduleFn: 'schedule' | 'scheduleAfter';2878 scheduledId: string;2879 blocksNum: number;2874 blocksNum: number;2880 options: ISchedulerOptions;2875 options: ISchedulerOptions;288128762882 constructor(...args: any[]) {2877 constructor(...args: any[]) {2883 const logger = args[0] as ILogger;2878 const logger = args[0] as ILogger;2884 const options = args[1] as {2879 const options = args[1] as {2885 scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter',2880 scheduleFn: 'schedule' | 'scheduleAfter',2886 scheduledId: string,2887 blocksNum: number,2881 blocksNum: number,2888 options: ISchedulerOptions2882 options: ISchedulerOptions2889 };2883 };289028842891 super(logger);2885 super(logger);289228862893 this.scheduleFn = options.scheduleFn;2887 this.scheduleFn = options.scheduleFn;2894 this.scheduledId = options.scheduledId;2895 this.blocksNum = options.blocksNum;2888 this.blocksNum = options.blocksNum;2896 this.options = options.options;2889 this.options = options.options;2897 }2890 }289828912899 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2892 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2900 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2893 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2894 2901 const extrinsic = 'api.tx.scheduler.' + this.scheduleFn;2895 const mandatorySchedArgs = [29022903 return super.executeExtrinsic(2904 sender,2905 extrinsic,2906 [2907 this.scheduledId,2908 this.blocksNum,2896 this.blocksNum,2909 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2897 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2910 this.options.priority ?? null,2898 this.options.priority ?? null,2911 {Value: scheduledTx},2899 scheduledTx,2912 ],2900 ];2913 expectSuccess,2901 2914 );2902 let schedArgs;2903 let scheduleFn;29042905 if (this.options.scheduledId) {2906 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];29072908 if (this.scheduleFn == 'schedule') {2909 scheduleFn = 'scheduleNamed';2910 } else if (this.scheduleFn == 'scheduleAfter') {2911 scheduleFn = 'scheduleNamedAfter';2912 }2913 } else {2914 schedArgs = mandatorySchedArgs;2915 scheduleFn = this.scheduleFn;2916 }29172918 const extrinsic = 'api.tx.scheduler.' + scheduleFn;29192920 return super.executeExtrinsic(2921 sender,2922 extrinsic,2923 schedArgs,2924 expectSuccess,2925 );2915 }2926 }2916 };2927 };2917}2928}3046 }3057 }304730583048 scheduleAt<T extends UniqueHelper>(3059 scheduleAt<T extends UniqueHelper>(3049 scheduledId: string,3050 executionBlockNumber: number,3060 executionBlockNumber: number,3051 options: ISchedulerOptions = {},3061 options: ISchedulerOptions = {},3052 ) {3062 ) {3053 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);3063 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3054 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3064 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3055 }3065 }305630663057 scheduleAfter<T extends UniqueHelper>(3067 scheduleAfter<T extends UniqueHelper>(3058 scheduledId: string,3059 blocksBeforeExecution: number,3068 blocksBeforeExecution: number,3060 options: ISchedulerOptions = {},3069 options: ISchedulerOptions = {},3061 ) {3070 ) {3062 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3071 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3063 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3072 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3064 }3073 }306530743155 }3164 }315631653157 scheduleAt<T extends UniqueHelper>(3166 scheduleAt<T extends UniqueHelper>(3158 scheduledId: string,3159 executionBlockNumber: number,3167 executionBlockNumber: number,3160 options: ISchedulerOptions = {},3168 options: ISchedulerOptions = {},3161 ) {3169 ) {3162 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);3170 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3163 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3171 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3164 }3172 }316531733166 scheduleAfter<T extends UniqueHelper>(3174 scheduleAfter<T extends UniqueHelper>(3167 scheduledId: string,3168 blocksBeforeExecution: number,3175 blocksBeforeExecution: number,3169 options: ISchedulerOptions = {},3176 options: ISchedulerOptions = {},3170 ) {3177 ) {3171 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3178 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3172 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3179 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3173 }3180 }317431813260 }3267 }326132683262 scheduleAt<T extends UniqueHelper>(3269 scheduleAt<T extends UniqueHelper>(3263 scheduledId: string,3264 executionBlockNumber: number,3270 executionBlockNumber: number,3265 options: ISchedulerOptions = {},3271 options: ISchedulerOptions = {},3266 ) {3272 ) {3267 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);3273 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3268 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3274 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3269 }3275 }327032763271 scheduleAfter<T extends UniqueHelper>(3277 scheduleAfter<T extends UniqueHelper>(3272 scheduledId: string,3273 blocksBeforeExecution: number,3278 blocksBeforeExecution: number,3274 options: ISchedulerOptions = {},3279 options: ISchedulerOptions = {},3275 ) {3280 ) {3276 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3281 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3277 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3282 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3278 }3283 }327932843329 }3334 }333033353331 scheduleAt<T extends UniqueHelper>(3336 scheduleAt<T extends UniqueHelper>(3332 scheduledId: string,3333 executionBlockNumber: number,3337 executionBlockNumber: number,3334 options: ISchedulerOptions = {},3338 options: ISchedulerOptions = {},3335 ) {3339 ) {3336 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(scheduledId, executionBlockNumber, options);3340 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3337 return new UniqueFTCollection(this.collectionId, scheduledHelper);3341 return new UniqueFTCollection(this.collectionId, scheduledHelper);3338 }3342 }333933433340 scheduleAfter<T extends UniqueHelper>(3344 scheduleAfter<T extends UniqueHelper>(3341 scheduledId: string,3342 blocksBeforeExecution: number,3345 blocksBeforeExecution: number,3343 options: ISchedulerOptions = {},3346 options: ISchedulerOptions = {},3344 ) {3347 ) {3345 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3348 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3346 return new UniqueFTCollection(this.collectionId, scheduledHelper);3349 return new UniqueFTCollection(this.collectionId, scheduledHelper);3347 }3350 }334833513388 }3391 }338933923390 scheduleAt<T extends UniqueHelper>(3393 scheduleAt<T extends UniqueHelper>(3391 scheduledId: string,3392 executionBlockNumber: number,3394 executionBlockNumber: number,3393 options: ISchedulerOptions = {},3395 options: ISchedulerOptions = {},3394 ) {3396 ) {3395 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);3397 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3396 return new UniqueBaseToken(this.tokenId, scheduledCollection);3398 return new UniqueBaseToken(this.tokenId, scheduledCollection);3397 }3399 }339834003399 scheduleAfter<T extends UniqueHelper>(3401 scheduleAfter<T extends UniqueHelper>(3400 scheduledId: string,3401 blocksBeforeExecution: number,3402 blocksBeforeExecution: number,3402 options: ISchedulerOptions = {},3403 options: ISchedulerOptions = {},3403 ) {3404 ) {3404 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3405 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3405 return new UniqueBaseToken(this.tokenId, scheduledCollection);3406 return new UniqueBaseToken(this.tokenId, scheduledCollection);3406 }3407 }340734083468 }3469 }346934703470 scheduleAt<T extends UniqueHelper>(3471 scheduleAt<T extends UniqueHelper>(3471 scheduledId: string,3472 executionBlockNumber: number,3472 executionBlockNumber: number,3473 options: ISchedulerOptions = {},3473 options: ISchedulerOptions = {},3474 ) {3474 ) {3475 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);3475 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3476 return new UniqueNFToken(this.tokenId, scheduledCollection);3476 return new UniqueNFToken(this.tokenId, scheduledCollection);3477 }3477 }347834783479 scheduleAfter<T extends UniqueHelper>(3479 scheduleAfter<T extends UniqueHelper>(3480 scheduledId: string,3481 blocksBeforeExecution: number,3480 blocksBeforeExecution: number,3482 options: ISchedulerOptions = {},3481 options: ISchedulerOptions = {},3483 ) {3482 ) {3484 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3483 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3485 return new UniqueNFToken(this.tokenId, scheduledCollection);3484 return new UniqueNFToken(this.tokenId, scheduledCollection);3486 }3485 }348734863543 }3542 }354435433545 scheduleAt<T extends UniqueHelper>(3544 scheduleAt<T extends UniqueHelper>(3546 scheduledId: string,3547 executionBlockNumber: number,3545 executionBlockNumber: number,3548 options: ISchedulerOptions = {},3546 options: ISchedulerOptions = {},3549 ) {3547 ) {3550 const scheduledCollection = this.collection.scheduleAt<T>(scheduledId, executionBlockNumber, options);3548 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3551 return new UniqueRFToken(this.tokenId, scheduledCollection);3549 return new UniqueRFToken(this.tokenId, scheduledCollection);3552 }3550 }355335513554 scheduleAfter<T extends UniqueHelper>(3552 scheduleAfter<T extends UniqueHelper>(3555 scheduledId: string,3556 blocksBeforeExecution: number,3553 blocksBeforeExecution: number,3557 options: ISchedulerOptions = {},3554 options: ISchedulerOptions = {},3558 ) {3555 ) {3559 const scheduledCollection = this.collection.scheduleAfter<T>(scheduledId, blocksBeforeExecution, options);3556 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3560 return new UniqueRFToken(this.tokenId, scheduledCollection);3557 return new UniqueRFToken(this.tokenId, scheduledCollection);3561 }3558 }35623559