git.delta.rocks / unique-network / refs/commits / 5f0218ad9241

difftreelog

Merge pull request #691 from UniqueNetwork/feature/pallet-scheduler-v2

Yaroslav Bolyukin2022-11-21parents: #20c695f #f71c05b.patch.diff
in: master
Feature/pallet scheduler v2

32 files changed

modifiedCargo.lockdiffbeforeafterboth
5389 "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]
67326733
6733[[package]]6734[[package]]
6851]6852]
68526853
6853[[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]
68716871
6872[[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",
modifiedMakefilediffbeforeafterboth
118118
119.PHONY: bench-scheduler119.PHONY: bench-scheduler
120bench-scheduler:120bench-scheduler:
121 make _bench PALLET=unique-scheduler PALLET_DIR=scheduler121 make _bench PALLET=unique-scheduler-v2 PALLET_DIR=scheduler-v2
122122
123.PHONY: bench-rmrk-core123.PHONY: bench-rmrk-core
124bench-rmrk-core:124bench-rmrk-core:
addedpallets/scheduler-v2/Cargo.tomldiffbeforeafterboth

no changes

addedpallets/scheduler-v2/src/benchmarking.rsdiffbeforeafterboth

no changes

addedpallets/scheduler-v2/src/lib.rsdiffbeforeafterboth

no changes

addedpallets/scheduler-v2/src/mock.rsdiffbeforeafterboth

no changes

addedpallets/scheduler-v2/src/tests.rsdiffbeforeafterboth

no changes

addedpallets/scheduler-v2/src/weights.rsdiffbeforeafterboth

no changes

deletedpallets/scheduler/CHANGELOG.mddiffbeforeafterboth

no changes

deletedpallets/scheduler/Cargo.tomldiffbeforeafterboth

no changes

deletedpallets/scheduler/README.mddiffbeforeafterboth

no changes

deletedpallets/scheduler/src/benchmarking.rsdiffbeforeafterboth

no changes

deletedpallets/scheduler/src/lib.rsdiffbeforeafterboth

no changes

deletedpallets/scheduler/src/weights.rsdiffbeforeafterboth

no changes

modifiedruntime/common/config/pallets/scheduler.rsdiffbeforeafterboth
25use 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;
3232
33parameter_types! {33parameter_types! {
70 }70 }
71}71}
7272
73impl 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}
8987
modifiedruntime/common/config/test_pallets.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17use crate::{Runtime, RuntimeEvent};17use crate::{Runtime, RuntimeEvent, RuntimeCall};
1818
19impl 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}
2223
modifiedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
58 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,58 Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
5959
60 #[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,
6262
63 Configuration: pallet_configuration::{Pallet, Call, Storage} = 63,63 Configuration: pallet_configuration::{Pallet, Call, Storage} = 63,
6464
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
683 #[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);
685685
686 // #[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);
688688
689 #[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);
745745
746 // #[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);
748748
749 #[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);
modifiedruntime/common/scheduler.rsdiffbeforeafterboth
15// 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/>.
1616
17use 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;
33
34type SponsorshipChargeTransactionPayment =
35 pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
3631
37/// 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);
4738
48fn 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),
6146
62pub struct SchedulerPaymentExecutor;47pub struct SchedulerPaymentExecutor;
6348
64impl<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 SchedulerPaymentExecutor
66where51where
67 <T as frame_system::Config>::RuntimeCall: Member52 <T as frame_system::Config>::RuntimeCall: Member
71 + 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 }
108
109 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());
119
120 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(
121 &id,
122 &(sponsor.into()),
123 weight,
124 )
125 }
126
127 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 }
143
144 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}
15794
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
41 '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 }
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
40 '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 }
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
40 '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 }
modifiedtest-pallets/utils/Cargo.tomldiffbeforeafterboth
10scale-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" }
1416
15[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"]
2528
modifiedtest-pallets/utils/src/lib.rsdiffbeforeafterboth
2222
23#[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};
2833
29 #[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>;
37
38 /// The overarching call type.
39 type RuntimeCall: Parameter
40 + Dispatchable<
41 RuntimeOrigin = <Self as frame_system::Config>::RuntimeOrigin,
42 PostInfo = PostDispatchInfo,
43 > + GetDispatchInfo
44 + 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 }
3349
34 #[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 }
4057
41 #[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())?;
101119
102 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 }
107123
114 Ok(())130 Ok(())
115 }131 }
132
133 #[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())?;
139
140 let is_root = ensure_root(origin.clone()).is_ok();
141
142 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 }
157
158 Self::deposit_event(Event::BatchCompleted);
159 Ok(None::<Weight>.into())
160 }
116 }161 }
117}162}
118163
modifiedtests/src/eth/scheduling.test.tsdiffbeforeafterboth
15// 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/>.
1616
17import {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';
2020
21describe('Scheduing EVM smart contracts', () => {21describe('Scheduing EVM smart contracts', () => {
26 });26 });
27 });27 });
2828
29 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);
3232
33 const scheduledId = await helper.arrange.makeScheduledId();33 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
3434
35 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 };
4646
47 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,
modifiedtests/src/eth/util/index.tsdiffbeforeafterboth
88
9import {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';
1112
12export {EthUniqueHelper} from './playgrounds/unique.dev';13export {EthUniqueHelper} from './playgrounds/unique.dev';
1314
82itEthIfWithPallet.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;
85
86export 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;
97
98function 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}
84101
modifiedtests/src/maintenanceMode.seqtest.tsdiffbeforeafterboth
1616
17import {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';
2121
22async 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 });
164164
165 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);
167167
168 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);
171171
172 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);
177181
178 const blocksToWait = 6;182 const blocksToWait = 6;
179183
180 // Scheduling works before the maintenance184 // Scheduling works before the maintenance
181 await nftBeforeMM.scheduleAfter(scheduledIdBeforeMM, blocksToWait)185 await nftBeforeMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdBeforeMM})
182 .transfer(bob, {Substrate: superuser.address});186 .transfer(bob, {Substrate: superuser.address});
183187
184 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});
186190
187 // Schedule a transaction that should occur *during* the maintenance191 // Schedule a transaction that should occur *during* the maintenance
188 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 maintenance
192 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});
194198
195 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});
201205
202 // Any attempts to schedule a tx during the MM should be rejected206 // Any attempts to schedule a tx during the MM should be rejected
203 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/);
206210
207 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;
209213
210 // Scheduling works after the maintenance214 // Scheduling works after the maintenance
211 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);
modifiedtests/src/scheduler.seqtest.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17import {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';
2020
21describe('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;
2526
26 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');
3130
31 superuser = await privateKey('//Alice');
32 const donor = await privateKey({filename: __filename});
33 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
34
32 await helper.testUtils.enable();35 await helper.testUtils.enable();
33 });36 });
34 });37 });
3538
36 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 });
44
45 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;
4454
45 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});55 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
4656
47 await helper.wait.newBlocks(blocksBeforeExecution + 1);57 await helper.wait.forParachainBlockNumber(executionBlock);
4858
49 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 });
5161
52 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;
5565
56 const amount = 1n * helper.balance.getOneTokenNominal();66 const amount = 1n * helper.balance.getOneTokenNominal();
6171
62 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);72 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
6373
64 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;
6677
67 await helper.wait.newBlocks(waitForBlocks + 1);78 await helper.wait.forParachainBlockNumber(executionBlock);
6879
69 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 );
7586
76 await helper.wait.newBlocks(periodic.period);87 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
7788
78 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 });
8596
86 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);
89100
90 const scheduledId = await helper.arrange.makeScheduledId();101 const scheduledId = helper.arrange.makeScheduledId();
91 const waitForBlocks = 4;102 const waitForBlocks = 4;
92103
93 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});104 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});
94105
95 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;
97109
98 await helper.scheduler.cancelScheduled(alice, scheduledId);110 await helper.scheduler.cancelScheduled(alice, scheduledId);
99111
100 await helper.wait.newBlocks(waitForBlocks + 1);112 await helper.wait.forParachainBlockNumber(executionBlock);
101113
102 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 });
104116
105 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 };
111123
112 const scheduledId = await helper.arrange.makeScheduledId();124 const scheduledId = helper.arrange.makeScheduledId();
113125
114 const amount = 1n * helper.balance.getOneTokenNominal();126 const amount = 1n * helper.balance.getOneTokenNominal();
115127
116 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);128 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
117129
118 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;
120133
121 await helper.wait.newBlocks(waitForBlocks + 1);134 await helper.wait.forParachainBlockNumber(executionBlock);
122135
123 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);136 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);
124137
129 );142 );
130143
131 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);
133146
134 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 });
141154
142 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 }
165
166 // 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;
173
174 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks;
175
176 const amount = 1n * helper.balance.getOneTokenNominal();
177
178 const balanceBefore = await helper.balance.getSubstrate(bob.address);
179
180 // Fill the target block
181 for (let i = 0; i < maxScheduledPerBlock; i++) {
182 await helper.scheduler.scheduleAt(executionBlock, {scheduledId: fillScheduledIds[i]})
183 .balance.transferToSubstrate(superuser, bob.address, amount);
184 }
185
186 // Try to schedule a task into a full block
187 await expect(helper.scheduler.scheduleAt(executionBlock, {scheduledId: extraScheduledId})
188 .balance.transferToSubstrate(superuser, bob.address, amount))
189 .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/);
190
191 await helper.wait.forParachainBlockNumber(executionBlock);
192
193 const balanceAfter = await helper.balance.getSubstrate(bob.address);
194
195 expect(balanceAfter > balanceBefore).to.be.true;
196
197 const diff = balanceAfter - balanceBefore;
198 expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock));
199 });
200
201 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;
145204
146 const initTestVal = 42;205 const initTestVal = 42;
147 const changedTestVal = 111;206 const changedTestVal = 111;
148207
149 await helper.testUtils.setTestValue(alice, initTestVal);208 await helper.testUtils.setTestValue(alice, initTestVal);
150209
151 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;
153213
154 await helper.wait.newBlocks(waitForBlocks + 1);214 await helper.wait.forParachainBlockNumber(executionBlock);
155215
156 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 });
160220
161 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();
174234
175 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;
177238
178 await helper.wait.newBlocks(1);
179
180 const aliceInitBalance = await helper.balance.getSubstrate(alice.address);239 const aliceInitBalance = await helper.balance.getSubstrate(alice.address);
181 let diff;240 let diff;
182241
183 await helper.wait.newBlocks(waitForBlocks);242 await helper.wait.forParachainBlockNumber(executionBlock);
184243
185 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 );
196255
197 await helper.wait.newBlocks(periodic.period);256 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
198257
199 const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);258 const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);
200 expect(259 expect(
211270
212 // Check if we can cancel a scheduled periodic operation271 // Check if we can cancel a scheduled periodic operation
213 // in the same block in which it is running272 // in the same block in which it is running
214 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;
218277
219 const [278 const [
220 scheduledId,279 scheduledId,
221 scheduledCancelId,280 scheduledCancelId,
222 ] = await helper.arrange.makeScheduledIds(2);281 ] = helper.arrange.makeScheduledIds(2);
223282
224 const periodic = {283 const periodic = {
225 period: 5,284 period: 5,
232291
233 await helper.testUtils.setTestValue(alice, initTestVal);292 await helper.testUtils.setTestValue(alice, initTestVal);
234293
235 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);
237296
238 // Cancel the inc tx after 2 executions297 // Cancel the inc tx after 2 executions
239 // *in the same block* in which the second execution is scheduled298 // *in the same block* in which the second execution is scheduled
240 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);
244303
245 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);304 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
261 }320 }
262 });321 });
263322
264 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,
274333
275 await helper.testUtils.setTestValue(alice, initTestVal);334 await helper.testUtils.setTestValue(alice, initTestVal);
276335
277 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;
279339
280 await helper.wait.newBlocks(waitForBlocks + 1);340 await helper.wait.forParachainBlockNumber(executionBlock);
281341
282 // execution #0342 // execution #0
283 expect(await helper.testUtils.testValue())343 expect(await helper.testUtils.testValue())
284 .to.be.equal(initTestVal + 1);344 .to.be.equal(initTestVal + 1);
285345
286 await helper.wait.newBlocks(periodic.period);346 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);
287347
288 // execution #1348 // execution #1
289 expect(await helper.testUtils.testValue())349 expect(await helper.testUtils.testValue())
290 .to.be.equal(initTestVal + 2);350 .to.be.equal(initTestVal + 2);
291351
292 await helper.wait.newBlocks(periodic.period);352 await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period);
293353
294 // <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 });
298358
299 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);
302362
303 const scheduledId = await helper.arrange.makeScheduledId();363 const scheduledId = helper.arrange.makeScheduledId();
304 const waitForBlocks = 4;364 const waitForBlocks = 4;
305365
306 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;
308369
309 await helper.getSudo().scheduler.cancelScheduled(alice, scheduledId);370 await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId);
310371
311 await helper.wait.newBlocks(waitForBlocks + 1);372 await helper.wait.forParachainBlockNumber(executionBlock);
312373
313 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 });
315376
316 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;
319380
320 const amount = 42n * helper.balance.getOneTokenNominal();381 const amount = 42n * helper.balance.getOneTokenNominal();
321382
322 const balanceBefore = await helper.balance.getSubstrate(charlie.address);383 const balanceBefore = await helper.balance.getSubstrate(charlie.address);
323384
324 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;
327389
328 await helper.wait.newBlocks(waitForBlocks + 1);390 await helper.wait.forParachainBlockNumber(executionBlock);
329391
330 const balanceAfter = await helper.balance.getSubstrate(charlie.address);392 const balanceAfter = await helper.balance.getSubstrate(charlie.address);
331393
335 expect(diff).to.be.equal(amount);397 expect(diff).to.be.equal(amount);
336 });398 });
337399
338 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);
341403
342 const scheduledId = await helper.arrange.makeScheduledId();404 const scheduledId = helper.arrange.makeScheduledId();
343 const waitForBlocks = 6;405 const waitForBlocks = 6;
344406
345 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;
347410
348 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);
350413
351 const priorityChanged = await helper.wait.event(414 const priorityChanged = await helper.wait.event(
352 waitForBlocks,415 waitForBlocks,
355 );418 );
356419
357 expect(priorityChanged !== null).to.be.true;420 expect(priorityChanged !== null).to.be.true;
421
422 const [blockNumber, index] = priorityChanged!.event.data[0].toJSON() as any[];
423 expect(blockNumber).to.be.equal(executionBlock);
424 expect(index).to.be.equal(0);
425
358 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 });
360428
361 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);
366434
367 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();
380448
381 // 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 priority
382 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);
384455
385 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);
387461
388 const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');462 const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');
389463
390 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);464 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
391465
392 // Flip priorities466 // Flip priorities
393 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);
395469
396 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);470 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);
397471
410 expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);484 expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);
411 });485 });
486
487 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);
493
494 const fillScheduleFn = scheduleKind == 'named' ? 'scheduleNamed' : 'schedule';
495
496 const initTestVal = 0;
497 const firstExecTestVal = 1;
498 const secondExecTestVal = 2;
499 await helper.testUtils.setTestValue(alice, initTestVal);
500
501 const currentBlockNumber = await helper.chain.getLatestBlockNumber();
502 const blocksBeforeExecution = 8;
503 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;
504
505 const period = 5;
506
507 const periodic = {
508 period,
509 repetitions: 2,
510 };
511
512 // Fill `numFilledBlocks` blocks beginning from the block in which the second execution should occur
513 const txs = [];
514 for (let offset = 0; offset < numFilledBlocks; offset ++) {
515 for (let i = 0; i < maxScheduledPerBlock; i++) {
516
517 const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);
518
519 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;
524
525 const tx = helper.constructApiCall(`api.tx.scheduler.${fillScheduleFn}`, scheduleArgs);
526
527 txs.push(tx);
528 }
529 }
530 await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true);
531
532 await helper.scheduler.scheduleAt<DevUniqueHelper>(firstExecutionBlockNumber, {
533 scheduledId: periodicId,
534 periodic,
535 }).testUtils.incTestValue(alice);
536
537 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);
538 expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal);
539
540 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks);
541
542 // 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 }
546
547 // After the `numFilledBlocks` the periodic operation will eventually be executed
548 expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal);
549 });
550
551 itSched('scheduled operations does not change nonce', async (scheduleKind, {helper}) => {
552 const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined;
553 const blocksBeforeExecution = 4;
554
555 await helper.scheduler
556 .scheduleAfter<DevUniqueHelper>(blocksBeforeExecution, {scheduledId})
557 .balance.transferToSubstrate(alice, bob.address, 1n);
558 const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;
559
560 const initNonce = await helper.chain.getNonce(alice.address);
561
562 await helper.wait.forParachainBlockNumber(executionBlock);
563
564 const finalNonce = await helper.chain.getNonce(alice.address);
565
566 expect(initNonce).to.be.equal(finalNonce);
567 });
412});568});
413569
414describe('Negative Test: Scheduling', () => {570describe('Negative Test: Scheduling', () => {
415 let alice: IKeyringPair;571 let alice: IKeyringPair;
416 let bob: IKeyringPair;572 let bob: IKeyringPair;
417573
418 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');
422577
578 const donor = await privateKey({filename: __filename});
579 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
580
423 await helper.testUtils.enable();581 await helper.testUtils.enable();
424 });582 });
425 });583 });
426584
427 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);
430588
431 const scheduledId = await helper.arrange.makeScheduledId();589 const scheduledId = helper.arrange.makeScheduledId();
432 const waitForBlocks = 4;590 const waitForBlocks = 4;
433591
434 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;
436595
437 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/);
440599
441 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);600 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);
442601
443 await helper.wait.newBlocks(waitForBlocks + 1);602 await helper.wait.forParachainBlockNumber(executionBlock);
444603
445 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);604 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);
446605
447 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 });
450609
451 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 });
456615
457 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);
460619
461 const scheduledId = await helper.arrange.makeScheduledId();620 const scheduledId = helper.arrange.makeScheduledId();
462 const waitForBlocks = 4;621 const waitForBlocks = 4;
463622
464 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;
466626
467 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/);
469629
470 await helper.wait.newBlocks(waitForBlocks + 1);630 await helper.wait.forParachainBlockNumber(executionBlock);
471631
472 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 });
474634
475 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;
478638
479 const amount = 42n * helper.balance.getOneTokenNominal();639 const amount = 42n * helper.balance.getOneTokenNominal();
480640
481 const balanceBefore = await helper.balance.getSubstrate(bob.address);641 const balanceBefore = await helper.balance.getSubstrate(bob.address);
482642
483 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/);
647
648 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;
487649
488 await helper.wait.newBlocks(waitForBlocks + 1);650 await helper.wait.forParachainBlockNumber(executionBlock);
489651
490 const balanceAfter = await helper.balance.getSubstrate(bob.address);652 const balanceAfter = await helper.balance.getSubstrate(bob.address);
491653
492 expect(balanceAfter).to.be.equal(balanceBefore);654 expect(balanceAfter).to.be.equal(balanceBefore);
493 });655 });
494656
495 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);
498660
499 const scheduledId = await helper.arrange.makeScheduledId();661 const scheduledId = helper.arrange.makeScheduledId();
500 const waitForBlocks = 4;662 const waitForBlocks = 4;
501663
502 await token.scheduleAfter(scheduledId, waitForBlocks)664 await token.scheduleAfter(waitForBlocks, {scheduledId})
503 .transfer(bob, {Substrate: alice.address});665 .transfer(bob, {Substrate: alice.address});
504666
505 const priority = 112;667 const priority = 112;
522 // let bob: IKeyringPair;684 // let bob: IKeyringPair;
523685
524 // 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 // });
530692
550 });712 });
551713
552 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 account
555 // const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);717 // const zeroBalance = await findUnusedAddress(api, privateKey);
556718
557 // const collectionId = await createCollectionExpectSuccess();719 // const collectionId = await createCollectionExpectSuccess();
558720
591 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();
593755
594 // 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);
598760
622 // await setCollectionSponsorExpectSuccess(collectionId, bob.address);784 // await setCollectionSponsorExpectSuccess(collectionId, bob.address);
623 // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');785 // await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
624786
625 // 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);
627789
628 // await enablePublicMintingExpectSuccess(alice, collectionId);790 // await enablePublicMintingExpectSuccess(alice, collectionId);
629 // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);791 // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
modifiedtests/src/util/index.tsdiffbeforeafterboth
130itSubIfWithPallet.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;
132
133export type SchedKind = 'anon' | 'named';
134
135export 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;
146
147function 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}
132150
133export 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.skip
modifiedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
172}172}
173173
174export interface ISchedulerOptions {174export interface ISchedulerOptions {
175 scheduledId?: string,
175 priority?: number,176 priority?: number,
176 periodic?: {177 periodic?: {
177 period: number,178 period: number,
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
308 return encodeAddress(address);308 return encodeAddress(address);
309 }309 }
310310
311 async makeScheduledIds(num: number): Promise<string[]> {311 makeScheduledIds(num: number): string[] {
312 await this.helper.wait.noScheduledTasks();
313
314 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;
318316
330 return ids;328 return ids;
331 }329 }
332330
333 async makeScheduledId(): Promise<string> {331 makeScheduledId(): string {
334 return (await this.makeScheduledIds(1))[0];332 return (this.makeScheduledIds(1))[0];
335 }333 }
336334
337 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 }
539537
540 async testValue() {538 async testValue(blockIdx?: number) {
539 const api = blockIdx
541 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();
542
543 return (await api.query.testUtils.testValue()).toJSON();
542 }544 }
543545
544 async justTakeFee(signer: TSigner) {546 async justTakeFee(signer: TSigner) {
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
2560 }2560 }
25612561
2562 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 }
25692568
2570 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 }
25772575
2578 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-convention
2585 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-convention
2875function 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;
28812876
2882 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: ISchedulerOptions
2889 };2883 };
28902884
2891 super(logger);2885 super(logger);
28922886
2893 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 }
28982891
2899 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 = [
2902
2903 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;
2904
2905 if (this.options.scheduledId) {
2906 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];
2907
2908 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 }
2917
2918 const extrinsic = 'api.tx.scheduler.' + scheduleFn;
2919
2920 return super.executeExtrinsic(
2921 sender,
2922 extrinsic,
2923 schedArgs,
2924 expectSuccess,
2925 );
2915 }2926 }
2916 };2927 };
2917}2928}
3046 }3057 }
30473058
3048 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 }
30563066
3057 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 }
30653074
3155 }3164 }
31563165
3157 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 }
31653173
3166 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 }
31743181
3260 }3267 }
32613268
3262 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 }
32703276
3271 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 }
32793284
3329 }3334 }
33303335
3331 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 }
33393343
3340 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 }
33483351
3388 }3391 }
33893392
3390 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 }
33983400
3399 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 }
34073408
3468 }3469 }
34693470
3470 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 }
34783478
3479 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 }
34873486
3543 }3542 }
35443543
3545 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 }
35533551
3554 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