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

difftreelog

Merge commit '4359d76172511a9ab73cac61957cc6ddf47a2653' into feature/evm-call-sponsoring

Yaroslav Bolyukin2021-07-27parents: #1c1c248 #4359d76.patch.diff
in: master

31 files changed

modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -196,6 +196,7 @@
 					const_on_chain_schema: vec![],
 					variable_on_chain_schema: vec![],
 					limits: CollectionLimits::default(),
+					transfers_enabled: true,
 				},
 			)],
 			nft_item_id: vec![],
modifiedpallets/inflation/src/tests.rsdiffbeforeafterboth
--- a/pallets/inflation/src/tests.rs
+++ b/pallets/inflation/src/tests.rs
@@ -31,6 +31,8 @@
 	type ExistentialDeposit = ExistentialDeposit;
 	type WeightInfo = ();
 	type MaxLocks = MaxLocks;
+	type MaxReserves = ();
+	type ReserveIdentifier = ();
 }
 
 frame_support::construct_runtime!(
@@ -89,7 +91,6 @@
 	type InflationBlockInterval = InflationBlockInterval;
 }
 
-// Build genesis storage according to the mock runtime.
 pub fn new_test_ext() -> sp_io::TestExternalities {
 	frame_system::GenesisConfig::default()
 		.build_storage::<Test>()
@@ -108,7 +109,9 @@
 		// BlockInflation should be set after 1st block and
 		// first inflation deposit should be equal to BlockInflation
 		Inflation::on_initialize(1);
-		assert!(Inflation::block_inflation() > 0);
+
+		// SBP M2 review: Verify expected block inflation for year 1
+		assert_eq!(Inflation::block_inflation(), 1901);
 		assert_eq!(
 			Balances::free_balance(1234) - initial_issuance,
 			Inflation::block_inflation()
@@ -155,11 +158,24 @@
 		Inflation::on_initialize(1);
 		let block_inflation_year_0 = Inflation::block_inflation();
 
+		// SBP M2 review: go through all the block inflations for year 1,
+		// total issuance will be updated accordingly
+		for block in (100..YEAR).step_by(100) {
+			Inflation::on_initialize(block);
+		}
+		assert_eq!(
+			initial_issuance + (1901 * (YEAR / 100)),
+			<Balances as Currency<_>>::total_issuance()
+		);
+
 		Inflation::on_initialize(YEAR);
 		let block_inflation_year_1 = Inflation::block_inflation();
+		// SBP M2 review: Verify expected block inflation for year 2
+		assert_eq!(block_inflation_year_1, 1952);
 
+		// SBP M2 review: this is actually not true
 		// Assert that year 1 inflation is less than year 0
-		assert!(block_inflation_year_0 > block_inflation_year_1);
+		// assert!(block_inflation_year_0 > block_inflation_year_1);
 	});
 }
 
@@ -177,6 +193,7 @@
 			Inflation::on_initialize(YEAR * year);
 			let block_inflation_year_after = Inflation::block_inflation();
 
+			// SBP M2 review: this is actually not true (not for the first few years)
 			// Assert that next year inflation is less than previous year inflation
 			assert!(block_inflation_year_before > block_inflation_year_after);
 		}
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -174,6 +174,8 @@
 		BadCreateRefungibleCall,
 		/// Gas limit exceeded
 		OutOfGas,
+		/// Collection settings not allowing items transferring
+		TransferNotAllowed,
 	}
 }
 
@@ -526,6 +528,7 @@
 				variable_on_chain_schema: Vec::new(),
 				const_on_chain_schema: Vec::new(),
 				limits,
+				transfers_enabled: true,
 			};
 
 			// Add new collection to map
@@ -901,6 +904,32 @@
 			collection.submit_logs()
 		}
 
+		// TODO! transaction weight
+
+		/// Set transfers_enabled value for particular collection
+		///
+		/// # Permissions
+		///
+		/// * Collection Owner.
+		///
+		/// # Arguments
+		///
+		/// * collection_id: ID of the collection.
+		///
+		/// * value: New flag value.
+		#[weight = <T as Config>::WeightInfo::burn_item()]
+		#[transactional]
+		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			let mut target_collection = Self::get_collection(collection_id)?;
+
+			Self::check_owner_permissions(&target_collection, &sender)?;
+
+			target_collection.transfers_enabled = value;
+			target_collection.save()
+		}
+
 		/// Destroys a concrete instance of NFT.
 		///
 		/// # Permissions
@@ -1541,6 +1570,9 @@
 			Error::<T>::AccountTokenLimitExceeded
 		);
 
+		// preliminary transfer check
+		ensure!(collection.transfers_enabled, Error::<T>::TransferNotAllowed);
+
 		Ok(())
 	}
 
modifiedpallets/nft/src/mock.rsdiffbeforeafterboth
--- a/pallets/nft/src/mock.rs
+++ b/pallets/nft/src/mock.rs
@@ -74,6 +74,8 @@
 	type ExistentialDeposit = ExistentialDeposit;
 	type WeightInfo = ();
 	type MaxLocks = MaxLocks;
+	type MaxReserves = ();
+	type ReserveIdentifier = [u8; 8];
 }
 
 parameter_types! {
@@ -99,41 +101,6 @@
 
 type Timestamp = pallet_timestamp::Pallet<Test>;
 type Randomness = pallet_randomness_collective_flip::Pallet<Test>;
-
-parameter_types! {
-	pub const TombstoneDeposit: u64 = 1;
-	pub const DepositPerContract: u64 = 1;
-	pub const DepositPerStorageByte: u64 = 1;
-	pub const DepositPerStorageItem: u64 = 1;
-	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * 24 * 60 * 10);
-	pub const SurchargeReward: u64 = 1;
-	pub const SignedClaimHandicap: u32 = 2;
-	pub DeletionWeightLimit: u64 = u64::MAX;//Perbill::from_percent(10);
-	pub DeletionQueueDepth: u32 = 10;
-	pub Schedule: pallet_contracts::Schedule<Test> = Default::default();
-}
-
-impl pallet_contracts::Config for Test {
-	type Time = Timestamp;
-	type Randomness = Randomness;
-	type Currency = pallet_balances::Pallet<Test>;
-	type Event = ();
-	type RentPayment = ();
-	type SignedClaimHandicap = SignedClaimHandicap;
-	type TombstoneDeposit = TombstoneDeposit;
-	type DepositPerContract = DepositPerContract;
-	type DepositPerStorageByte = DepositPerStorageByte;
-	type DepositPerStorageItem = DepositPerStorageItem;
-	type RentFraction = RentFraction;
-	type SurchargeReward = SurchargeReward;
-	type DeletionWeightLimit = DeletionWeightLimit;
-	type DeletionQueueDepth = DeletionQueueDepth;
-	type ChainExtension = ();
-	type WeightPrice = ();
-	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
-	type Schedule = Schedule;
-	type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
 
 parameter_types! {
 	pub const CollectionCreationPrice: u32 = 0;
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -2351,3 +2351,62 @@
 		);
 	});
 }
+
+#[test]
+fn collection_transfer_flag_works() {
+	new_test_ext().execute_with(|| {
+		default_limits();
+
+		let origin1 = Origin::signed(1);
+
+		let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+		assert_ok!(TemplateModule::set_transfers_enabled_flag(origin1, 1, true));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(TemplateModule::balance_count(1, 1), 1);
+		assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
+
+		let origin1 = Origin::signed(1);
+
+		// default scenario
+		assert_ok!(TemplateModule::transfer(origin1, account(2), 1, 1, 1000));
+		assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().owner, account(2));
+		assert_eq!(TemplateModule::balance_count(1, 1), 0);
+		assert_eq!(TemplateModule::balance_count(1, 2), 1);
+
+		assert_eq!(TemplateModule::address_tokens(1, 2), [1]);
+	});
+}
+
+#[test]
+fn collection_transfer_flag_works_neg() {
+	new_test_ext().execute_with(|| {
+		default_limits();
+
+		let origin1 = Origin::signed(1);
+
+		let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+		assert_ok!(TemplateModule::set_transfers_enabled_flag(
+			origin1, 1, false
+		));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(TemplateModule::balance_count(1, 1), 1);
+		assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
+
+		let origin1 = Origin::signed(1);
+
+		// default scenario
+		assert_noop!(
+			TemplateModule::transfer(origin1, account(2), 1, 1, 1000),
+			Error::<Test>::TransferNotAllowed
+		);
+		assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().owner, account(1));
+		assert_eq!(TemplateModule::balance_count(1, 1), 1);
+		assert_eq!(TemplateModule::balance_count(1, 2), 0);
+
+		assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
+	});
+}
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
before · pallets/scheduler/src/lib.rs
1// This file is part of Substrate.23// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.1718//! # Scheduler19//! A module for scheduling dispatches.20//!21//! - [`Config`]22//! - [`Call`]23//! - [`Module`]24//!25//! ## Overview26//!27//! This module exposes capabilities for scheduling dispatches to occur at a28//! specified block number or at a specified period. These scheduled dispatches29//! may be named or anonymous and may be canceled.30//!31//! **NOTE:** The scheduled calls will be dispatched with the default filter32//! for the origin: namely `frame_system::Config::BaseCallFilter` for all origin33//! except root which will get no filter. And not the filter contained in origin34//! use to call `fn schedule`.35//!36//! If a call is scheduled using proxy or whatever mecanism which adds filter,37//! then those filter will not be used when dispatching the schedule call.38//!39//! ## Interface40//!41//! ### Dispatchable Functions42//!43//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a44//!   specified block and with a specified priority.45//! * `cancel` - cancel a scheduled dispatch, specified by block number and46//!   index.47//! * `schedule_named` - augments the `schedule` interface with an additional48//!   `Vec<u8>` parameter that can be used for identification.49//! * `cancel_named` - the named complement to the cancel function.5051// Ensure we're `no_std` when compiling for Wasm.52#![cfg_attr(not(feature = "std"), no_std)]53#![allow(clippy::type_complexity, clippy::boxed_local, clippy::unused_unit)]5455mod benchmarking;56pub mod weights;5758use sp_std::{prelude::*, marker::PhantomData, borrow::Borrow};59use codec::{Encode, Decode, Codec};60use sp_runtime::{61	RuntimeDebug,62	traits::{Zero, One, BadOrigin, Saturating},63};64use frame_support::{65	decl_module, decl_storage, decl_event, decl_error, IterableStorageMap,66	dispatch::{Dispatchable, DispatchError, DispatchResult, Parameter},67	traits::{68		Get,69		schedule::{self, DispatchTime},70		OriginTrait, EnsureOrigin, IsType,71	},72	weights::{GetDispatchInfo, Weight},73};74use frame_system::{self as system, ensure_signed};75pub use weights::WeightInfo;76use up_sponsorship::SponsorshipHandler;7778/// Our pallet's configuration trait. All our types and constants go in here. If the79/// pallet is dependent on specific other pallets, then their configuration traits80/// should be added to our implied traits list.81///82/// `system::Config` should always be included in our implied traits.83/// //84pub trait Config: system::Config {85	/// The overarching event type.86	type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;8788	/// The aggregated origin which the dispatch will take.89	type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>90		+ From<Self::PalletsOrigin>91		+ IsType<<Self as system::Config>::Origin>;9293	/// The caller origin, overarching type of all pallets origins.94	type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq;9596	/// The aggregated call type.97	type Call: Parameter98		+ Dispatchable<Origin = <Self as Config>::Origin>99		+ GetDispatchInfo100		+ From<system::Call<Self>>;101102	/// The maximum weight that may be scheduled per block for any dispatchables of less priority103	/// than `schedule::HARD_DEADLINE`.104	type MaximumWeight: Get<Weight>;105106	/// Required origin to schedule or cancel calls.107	type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;108109	/// The maximum number of scheduled calls in the queue for a single block.110	/// Not strictly enforced, but used for weight estimation.111	type MaxScheduledPerBlock: Get<u32>;112113	/// Sponsoring function114	type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;115116	/// Weight information for extrinsics in this pallet.117	type WeightInfo: WeightInfo;118}119120// pub type SelfWeightInfo<T> = <T as system::Config>::WeightInfo;121122/// Just a simple index for naming period tasks.123pub type PeriodicIndex = u32;124/// The location of a scheduled task that can be used to remove it.125pub type TaskAddress<BlockNumber> = (BlockNumber, u32);126127#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]128#[derive(Clone, RuntimeDebug, Encode, Decode)]129struct ScheduledV1<Call, BlockNumber> {130	maybe_id: Option<Vec<u8>>,131	priority: schedule::Priority,132	call: Call,133	maybe_periodic: Option<schedule::Period<BlockNumber>>,134}135136/// Information regarding an item to be executed in the future.137#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]138#[derive(Clone, RuntimeDebug, Encode, Decode)]139pub struct ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId> {140	/// The unique identity for this task, if there is one.141	maybe_id: Option<Vec<u8>>,142	/// This task's priority.143	priority: schedule::Priority,144	/// The call to be dispatched.145	call: Call,146	/// If the call is periodic, then this points to the information concerning that.147	maybe_periodic: Option<schedule::Period<BlockNumber>>,148	/// The origin to dispatch the call.149	origin: PalletsOrigin,150	_phantom: PhantomData<AccountId>,151}152153/// The current version of Scheduled struct.154pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =155	ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId>;156157// A value placed in storage that represents the current version of the Scheduler storage.158// This value is used by the `on_runtime_upgrade` logic to determine whether we run159// storage migration logic.160#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]161enum Releases {162	V1,163	V2,164}165166impl Default for Releases {167	fn default() -> Self {168		Releases::V1169	}170}171172#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]173pub struct CallSpec {174	module: u32,175	method: u32,176}177178decl_storage! {179	trait Store for Module<T: Config> as Scheduler {180		/// Items to be executed, indexed by the block number that they should be executed on.181		pub Agenda: map hasher(twox_64_concat) T::BlockNumber182			=> Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>;183184		pub SpecAgenda: map hasher(twox_64_concat) T::BlockNumber185			=> Vec<Option<CallSpec>>;186187		/// Lookup from identity to the block number and index of the task.188		Lookup: map hasher(twox_64_concat) Vec<u8> => Option<TaskAddress<T::BlockNumber>>;189190		/// Storage version of the pallet.191		///192		/// New networks start with last version.193		StorageVersion build(|_| Releases::V2): Releases;194	}195}196197decl_event!(198	pub enum Event<T> where <T as system::Config>::BlockNumber {199		/// Scheduled some task. \[when, index\]200		Scheduled(BlockNumber, u32),201		/// Canceled some task. \[when, index\]202		Canceled(BlockNumber, u32),203		/// Dispatched some task. \[task, id, result\]204		Dispatched(TaskAddress<BlockNumber>, Option<Vec<u8>>, DispatchResult),205	}206);207208decl_error! {209	pub enum Error for Module<T: Config> {210		/// Failed to schedule a call211		FailedToSchedule,212		/// Cannot find the scheduled call.213		NotFound,214		/// Given target block number is in the past.215		TargetBlockNumberInPast,216		/// Reschedule failed because it does not change scheduled time.217		RescheduleNoChange,218	}219}220221decl_module! {222	/// Scheduler module declaration.223	pub struct Module<T: Config> for enum Call224	where225		origin: <T as system::Config>::Origin226	{227		type Error = Error<T>;228		fn deposit_event() = default;229230231		/// Anonymously schedule a task.232		///233		/// # <weight>234		/// - S = Number of already scheduled calls235		/// - Base Weight: 22.29 + .126 * S µs236		/// - DB Weight:237		///     - Read: Agenda238		///     - Write: Agenda239		/// - Will use base weight of 25 which should be good for up to 30 scheduled calls240		/// # </weight>241		#[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]242		fn schedule(origin,243			when: T::BlockNumber,244			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,245			priority: schedule::Priority,246			call: Box<<T as Config>::Call>,247		)248		{249			let origin = <T as Config>::Origin::from(origin);250			Self::do_schedule(DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call)?;251		}252253		/// Cancel an anonymously scheduled task.254		///255		/// # <weight>256		/// - S = Number of already scheduled calls257		/// - Base Weight: 22.15 + 2.869 * S µs258		/// - DB Weight:259		///     - Read: Agenda260		///     - Write: Agenda, Lookup261		/// - Will use base weight of 100 which should be good for up to 30 scheduled calls262		/// # </weight>263		#[weight = <T as Config>::WeightInfo::cancel(T::MaxScheduledPerBlock::get())]264		fn cancel(origin, when: T::BlockNumber, index: u32) {265			T::ScheduleOrigin::ensure_origin(origin.clone())?;266			let origin = <T as Config>::Origin::from(origin);267			Self::do_cancel(Some(origin.caller().clone()), (when, index))?;268		}269270		/// Schedule a named task.271		///272		/// # <weight>273		/// - S = Number of already scheduled calls274		/// - Base Weight: 29.6 + .159 * S µs275		/// - DB Weight:276		///     - Read: Agenda, Lookup277		///     - Write: Agenda, Lookup278		/// - Will use base weight of 35 which should be good for more than 30 scheduled calls279		/// # </weight>280		#[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]281		fn schedule_named(origin,282			id: Vec<u8>,283			when: T::BlockNumber,284			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,285			priority: schedule::Priority,286			call: Box<<T as Config>::Call>,287		) {288			T::ScheduleOrigin::ensure_origin(origin.clone())?;289			let origin = <T as Config>::Origin::from(origin);290			Self::do_schedule_named(291				id, DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call292			)?;293		}294295		/// Cancel a named scheduled task.296		///297		/// # <weight>298		/// - S = Number of already scheduled calls299		/// - Base Weight: 24.91 + 2.907 * S µs300		/// - DB Weight:301		///     - Read: Agenda, Lookup302		///     - Write: Agenda, Lookup303		/// - Will use base weight of 100 which should be good for up to 30 scheduled calls304		/// # </weight>305		#[weight = <T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get())]306		fn cancel_named(origin, id: Vec<u8>) {307			T::ScheduleOrigin::ensure_origin(origin.clone())?;308			let origin = <T as Config>::Origin::from(origin);309			Self::do_cancel_named(Some(origin.caller().clone()), id)?;310		}311312		/// Anonymously schedule a task after a delay.313		///314		/// # <weight>315		/// Same as [`schedule`].316		/// # </weight>317		#[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]318		fn schedule_after(origin,319			after: T::BlockNumber,320			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,321			priority: schedule::Priority,322			call: Box<<T as Config>::Call>,323		) {324			T::ScheduleOrigin::ensure_origin(origin.clone())?;325			let origin = <T as Config>::Origin::from(origin);326			Self::do_schedule(327				DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call328			)?;329		}330331		/// Schedule a named task after a delay.332		///333		/// # <weight>334		/// Same as [`schedule_named`].335		/// # </weight>336		#[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]337		fn schedule_named_after(origin,338			id: Vec<u8>,339			after: T::BlockNumber,340			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,341			priority: schedule::Priority,342			call: Box<<T as Config>::Call>,343		) {344			T::ScheduleOrigin::ensure_origin(origin.clone())?;345			let origin = <T as Config>::Origin::from(origin);346			Self::do_schedule_named(347				id, DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call348			)?;349		}350351		/// Execute the scheduled calls352		///353		/// # <weight>354		/// - S = Number of already scheduled calls355		/// - N = Named scheduled calls356		/// - P = Periodic Calls357		/// - Base Weight: 9.243 + 23.45 * S µs358		/// - DB Weight:359		///     - Read: Agenda + Lookup * N + Agenda(Future) * P360		///     - Write: Agenda + Lookup * N  + Agenda(future) * P361		/// # </weight>362		fn on_initialize(now: T::BlockNumber) -> Weight {363			let limit = T::MaximumWeight::get();364			let mut queued = Agenda::<T>::take(now).into_iter()365				.enumerate()366				.filter_map(|(index, s)| s.map(|inner| (index as u32, inner)))367				.collect::<Vec<_>>();368			if queued.len() as u32 > T::MaxScheduledPerBlock::get() {369				log::warn!(370					target: "runtime::scheduler",371					"Warning: This block has more items queued in Scheduler than \372					expected from the runtime configuration. An update might be needed."373				);374			}375			queued.sort_by_key(|(_, s)| s.priority);376			let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next)377			let mut total_weight: Weight = 0;378			queued.into_iter()379				.enumerate()380				.scan(base_weight, |cumulative_weight, (order, (index, s))| {381					*cumulative_weight = cumulative_weight382						.saturating_add(s.call.get_dispatch_info().weight);383384					let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(385						s.origin.clone()386					).into();387388					if ensure_signed(origin).is_ok() {389						 // AccountData for inner call origin accountdata.390						*cumulative_weight = cumulative_weight391							.saturating_add(T::DbWeight::get().reads_writes(1, 1));392					}393394					if s.maybe_id.is_some() {395						// Remove/Modify Lookup396						*cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().writes(1));397					}398					if s.maybe_periodic.is_some() {399						// Read/Write Agenda for future block400						*cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));401					}402403					Some((order, index, *cumulative_weight, s))404				})405				.filter_map(|(order, index, cumulative_weight, mut s)| {406					// We allow a scheduled call if any is true:407					// - It's priority is `HARD_DEADLINE`408					// - It does not push the weight past the limit.409					// - It is the first item in the schedule410					if s.priority <= schedule::HARD_DEADLINE || cumulative_weight <= limit || order == 0 {411412						let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(413							s.origin.clone()414						).into();415						let sender = ensure_signed(origin).unwrap_or_default();416						let who_will_pay = T::SponsorshipHandler::get_sponsor(&sender, &s.call).unwrap_or(sender);417						let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));418						let r = s.call.clone().dispatch(sponsor.into());419						let maybe_id = s.maybe_id.clone();420						if let Some((period, count)) = s.maybe_periodic {421							if count > 1 {422								s.maybe_periodic = Some((period, count - 1));423							} else {424								s.maybe_periodic = None;425							}426							let next = now + period;427							// If scheduled is named, place it's information in `Lookup`428							if let Some(ref id) = s.maybe_id {429								let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0);430								Lookup::<T>::insert(id, (next, next_index as u32));431							}432							Agenda::<T>::append(next, Some(s));433						} else if let Some(ref id) = s.maybe_id {434									  Lookup::<T>::remove(id);435								  }436						Self::deposit_event(RawEvent::Dispatched(437							(now, index),438							maybe_id,439							r.map(|_| ()).map_err(|e| e.error)440						));441						total_weight = cumulative_weight;442						None443					} else {444						Some(Some(s))445					}446				})447				.for_each(|unused| {448					let next = now + One::one();449					Agenda::<T>::append(next, unused);450				});451452			total_weight453		}454	}455}456457impl<T: Config> Module<T> {458	/// Migrate storage format from V1 to V2.459	/// Return true if migration is performed.460	pub fn migrate_v1_to_t2() -> bool {461		if StorageVersion::get() == Releases::V1 {462			StorageVersion::put(Releases::V2);463464			Agenda::<T>::translate::<465				Vec<Option<ScheduledV1<<T as Config>::Call, T::BlockNumber>>>,466				_,467			>(|_, agenda| {468				Some(469					agenda470						.into_iter()471						.map(|schedule| {472							schedule.map(|schedule| ScheduledV2 {473								maybe_id: schedule.maybe_id,474								priority: schedule.priority,475								call: schedule.call,476								maybe_periodic: schedule.maybe_periodic,477								origin: system::RawOrigin::Root.into(),478								_phantom: Default::default(),479							})480						})481						.collect::<Vec<_>>(),482				)483			});484485			true486		} else {487			false488		}489	}490491	/// Helper to migrate scheduler when the pallet origin type has changed.492	pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {493		Agenda::<T>::translate::<494			Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, OldOrigin, T::AccountId>>>,495			_,496		>(|_, agenda| {497			Some(498				agenda499					.into_iter()500					.map(|schedule| {501						schedule.map(|schedule| Scheduled {502							maybe_id: schedule.maybe_id,503							priority: schedule.priority,504							call: schedule.call,505							maybe_periodic: schedule.maybe_periodic,506							origin: schedule.origin.into(),507							_phantom: Default::default(),508						})509					})510					.collect::<Vec<_>>(),511			)512		});513	}514515	fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {516		let now = frame_system::Pallet::<T>::block_number();517518		let when = match when {519			DispatchTime::At(x) => x,520			// The current block has already completed it's scheduled tasks, so521			// Schedule the task at lest one block after this current block.522			DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()),523		};524525		if when <= now {526			return Err(Error::<T>::TargetBlockNumberInPast.into());527		}528529		Ok(when)530	}531532	fn do_schedule(533		when: DispatchTime<T::BlockNumber>,534		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,535		priority: schedule::Priority,536		origin: T::PalletsOrigin,537		call: <T as Config>::Call,538	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {539		let when = Self::resolve_time(when)?;540541		// sanitize maybe_periodic542		let maybe_periodic = maybe_periodic543			.filter(|p| p.1 > 1 && !p.0.is_zero())544			// Remove one from the number of repetitions since we will schedule one now.545			.map(|(p, c)| (p, c - 1));546		let s = Some(Scheduled {547			maybe_id: None,548			priority,549			call,550			maybe_periodic,551			origin,552			_phantom: PhantomData::<T::AccountId>::default(),553		});554		Agenda::<T>::append(when, s);555		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;556		if index > T::MaxScheduledPerBlock::get() {557			log::warn!(558				target: "runtime::scheduler",559				"Warning: There are more items queued in the Scheduler than \560				expected from the runtime configuration. An update might be needed.",561			);562		}563		Self::deposit_event(RawEvent::Scheduled(when, index));564565		Ok((when, index))566	}567568	fn do_cancel(569		origin: Option<T::PalletsOrigin>,570		(when, index): TaskAddress<T::BlockNumber>,571	) -> Result<(), DispatchError> {572		let scheduled = Agenda::<T>::try_mutate(when, |agenda| {573			agenda.get_mut(index as usize).map_or(574				Ok(None),575				|s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {576					if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {577						if *o != s.origin {578							return Err(BadOrigin.into());579						}580					};581					Ok(s.take())582				},583			)584		})?;585		if let Some(s) = scheduled {586			if let Some(id) = s.maybe_id {587				Lookup::<T>::remove(id);588			}589			Self::deposit_event(RawEvent::Canceled(when, index));590			Ok(())591		} else {592			Err(Error::<T>::NotFound.into())593		}594	}595596	fn do_reschedule(597		(when, index): TaskAddress<T::BlockNumber>,598		new_time: DispatchTime<T::BlockNumber>,599	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {600		let new_time = Self::resolve_time(new_time)?;601602		if new_time == when {603			return Err(Error::<T>::RescheduleNoChange.into());604		}605606		Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {607			let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;608			let task = task.take().ok_or(Error::<T>::NotFound)?;609			Agenda::<T>::append(new_time, Some(task));610			Ok(())611		})?;612613		let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;614		Self::deposit_event(RawEvent::Canceled(when, index));615		Self::deposit_event(RawEvent::Scheduled(new_time, new_index));616617		Ok((new_time, new_index))618	}619620	fn do_schedule_named(621		id: Vec<u8>,622		when: DispatchTime<T::BlockNumber>,623		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,624		priority: schedule::Priority,625		origin: T::PalletsOrigin,626		call: <T as Config>::Call,627	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {628		// ensure id it is unique629		if Lookup::<T>::contains_key(&id) {630			return Err(Error::<T>::FailedToSchedule.into());631		}632633		let when = Self::resolve_time(when)?;634635		// sanitize maybe_periodic636		let maybe_periodic = maybe_periodic637			.filter(|p| p.1 > 1 && !p.0.is_zero())638			// Remove one from the number of repetitions since we will schedule one now.639			.map(|(p, c)| (p, c - 1));640641		let s = Scheduled {642			maybe_id: Some(id.clone()),643			priority,644			call,645			maybe_periodic,646			origin,647			_phantom: Default::default(),648		};649		Agenda::<T>::append(when, Some(s));650		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;651		if index > T::MaxScheduledPerBlock::get() {652			log::warn!(653				target: "runtime::scheduler",654				"Warning: There are more items queued in the Scheduler than \655				expected from the runtime configuration. An update might be needed.",656			);657		}658		let address = (when, index);659		Lookup::<T>::insert(&id, &address);660		Self::deposit_event(RawEvent::Scheduled(when, index));661662		Ok(address)663	}664665	fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: Vec<u8>) -> DispatchResult {666		Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {667			if let Some((when, index)) = lookup.take() {668				let i = index as usize;669				Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {670					if let Some(s) = agenda.get_mut(i) {671						if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {672							if *o != s.origin {673								return Err(BadOrigin.into());674							}675						}676						*s = None;677					}678					Ok(())679				})?;680				Self::deposit_event(RawEvent::Canceled(when, index));681				Ok(())682			} else {683				Err(Error::<T>::NotFound.into())684			}685		})686	}687688	fn do_reschedule_named(689		id: Vec<u8>,690		new_time: DispatchTime<T::BlockNumber>,691	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {692		let new_time = Self::resolve_time(new_time)?;693694		Lookup::<T>::try_mutate_exists(695			id,696			|lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {697				let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;698699				if new_time == when {700					return Err(Error::<T>::RescheduleNoChange.into());701				}702703				Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {704					let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;705					let task = task.take().ok_or(Error::<T>::NotFound)?;706					Agenda::<T>::append(new_time, Some(task));707708					Ok(())709				})?;710711				let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;712				Self::deposit_event(RawEvent::Canceled(when, index));713				Self::deposit_event(RawEvent::Scheduled(new_time, new_index));714715				*lookup = Some((new_time, new_index));716717				Ok((new_time, new_index))718			},719		)720	}721}722723impl<T: Config> schedule::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>724	for Module<T>725{726	type Address = TaskAddress<T::BlockNumber>;727728	fn schedule(729		when: DispatchTime<T::BlockNumber>,730		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,731		priority: schedule::Priority,732		origin: T::PalletsOrigin,733		call: <T as Config>::Call,734	) -> Result<Self::Address, DispatchError> {735		Self::do_schedule(when, maybe_periodic, priority, origin, call)736	}737738	fn cancel((when, index): Self::Address) -> Result<(), ()> {739		Self::do_cancel(None, (when, index)).map_err(|_| ())740	}741742	fn reschedule(743		address: Self::Address,744		when: DispatchTime<T::BlockNumber>,745	) -> Result<Self::Address, DispatchError> {746		Self::do_reschedule(address, when)747	}748749	fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {750		Agenda::<T>::get(when)751			.get(index as usize)752			.ok_or(())753			.map(|_| when)754	}755}756757impl<T: Config> schedule::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>758	for Module<T>759{760	type Address = TaskAddress<T::BlockNumber>;761762	fn schedule_named(763		id: Vec<u8>,764		when: DispatchTime<T::BlockNumber>,765		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,766		priority: schedule::Priority,767		origin: T::PalletsOrigin,768		call: <T as Config>::Call,769	) -> Result<Self::Address, ()> {770		Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ())771	}772773	fn cancel_named(id: Vec<u8>) -> Result<(), ()> {774		Self::do_cancel_named(None, id).map_err(|_| ())775	}776777	fn reschedule_named(778		id: Vec<u8>,779		when: DispatchTime<T::BlockNumber>,780	) -> Result<Self::Address, DispatchError> {781		Self::do_reschedule_named(id, when)782	}783784	fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {785		Lookup::<T>::get(id)786			.and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))787			.ok_or(())788	}789}790791#[cfg(test)]792#[allow(clippy::from_over_into)]793mod tests {794	use super::*;795796	use frame_support::{797		parameter_types, assert_ok, ord_parameter_types, assert_noop, assert_err, Hashable,798		traits::{OnInitialize, OnFinalize, Filter},799		weights::constants::RocksDbWeight,800	};801	use sp_core::H256;802	use sp_runtime::{803		Perbill,804		testing::Header,805		traits::{BlakeTwo256, IdentityLookup},806	};807	use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy};808	use substrate_test_utils::assert_eq_uvec;809	use crate as scheduler;810811	mod logger {812		use super::*;813		use std::cell::RefCell;814815		thread_local! {816			static LOG: RefCell<Vec<(OriginCaller, u32)>> = RefCell::new(Vec::new());817		}818		pub fn log() -> Vec<(OriginCaller, u32)> {819			LOG.with(|log| log.borrow().clone())820		}821		pub trait Config: system::Config {822			type Event: From<Event> + Into<<Self as system::Config>::Event>;823		}824		decl_event! {825			pub enum Event {826				Logged(u32, Weight),827			}828		}829		decl_module! {830			pub struct Module<T: Config> for enum Call831			where832				origin: <T as system::Config>::Origin,833				<T as system::Config>::Origin: OriginTrait<PalletsOrigin = OriginCaller>834			{835				fn deposit_event() = default;836837				#[weight = *weight]838				fn log(origin, i: u32, weight: Weight) {839					Self::deposit_event(Event::Logged(i, weight));840					LOG.with(|log| {841						log.borrow_mut().push((origin.caller().clone(), i));842					})843				}844845				#[weight = *weight]846				fn log_without_filter(origin, i: u32, weight: Weight) {847					Self::deposit_event(Event::Logged(i, weight));848					LOG.with(|log| {849						log.borrow_mut().push((origin.caller().clone(), i));850					})851				}852			}853		}854	}855856	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;857	type Block = frame_system::mocking::MockBlock<Test>;858859	frame_support::construct_runtime!(860		pub enum Test where861			Block = Block,862			NodeBlock = Block,863			UncheckedExtrinsic = UncheckedExtrinsic,864		{865			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},866			Logger: logger::{Pallet, Call, Event},867			Scheduler: scheduler::{Pallet, Call, Storage, Event<T>},868		}869	);870871	// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used.872	pub struct BaseFilter;873	impl Filter<Call> for BaseFilter {874		fn filter(call: &Call) -> bool {875			!matches!(call, Call::Logger(logger::Call::log(_, _)))876		}877	}878879	parameter_types! {880		pub const BlockHashCount: u64 = 250;881		pub BlockWeights: frame_system::limits::BlockWeights =882			frame_system::limits::BlockWeights::simple_max(2_000_000_000_000);883	}884	impl system::Config for Test {885		type BaseCallFilter = BaseFilter;886		type BlockWeights = ();887		type BlockLength = ();888		type DbWeight = RocksDbWeight;889		type Origin = Origin;890		type Call = Call;891		type Index = u64;892		type BlockNumber = u64;893		type Hash = H256;894		type Hashing = BlakeTwo256;895		type AccountId = u64;896		type Lookup = IdentityLookup<Self::AccountId>;897		type Header = Header;898		type Event = Event;899		type BlockHashCount = BlockHashCount;900		type Version = ();901		type PalletInfo = PalletInfo;902		type AccountData = ();903		type OnNewAccount = ();904		type OnKilledAccount = ();905		type SystemWeightInfo = ();906		type SS58Prefix = ();907		type OnSetCode = ();908	}909	impl logger::Config for Test {910		type Event = Event;911	}912	parameter_types! {913		pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;914		pub const MaxScheduledPerBlock: u32 = 10;915	}916	ord_parameter_types! {917		pub const One: u64 = 1;918	}919920	impl Config for Test {921		type Event = Event;922		type Origin = Origin;923		type PalletsOrigin = OriginCaller;924		type Call = Call;925		type MaximumWeight = MaximumSchedulerWeight;926		type ScheduleOrigin = EnsureOneOf<u64, EnsureRoot<u64>, EnsureSignedBy<One, u64>>;927		type MaxScheduledPerBlock = MaxScheduledPerBlock;928		type WeightInfo = ();929		type SponsorshipHandler = ();930	}931932	pub fn new_test_ext() -> sp_io::TestExternalities {933		let t = system::GenesisConfig::default()934			.build_storage::<Test>()935			.unwrap();936		t.into()937	}938939	fn run_to_block(n: u64) {940		while System::block_number() < n {941			Scheduler::on_finalize(System::block_number());942			System::set_block_number(System::block_number() + 1);943			Scheduler::on_initialize(System::block_number());944		}945	}946947	fn root() -> OriginCaller {948		system::RawOrigin::Root.into()949	}950951	#[test]952	fn basic_scheduling_works() {953		new_test_ext().execute_with(|| {954			let call = Call::Logger(logger::Call::log(42, 1000));955			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(956				&call957			));958			assert_ok!(Scheduler::do_schedule(959				DispatchTime::At(4),960				None,961				127,962				root(),963				call964			));965			run_to_block(3);966			assert!(logger::log().is_empty());967			run_to_block(4);968			assert_eq!(logger::log(), vec![(root(), 42u32)]);969			run_to_block(100);970			assert_eq!(logger::log(), vec![(root(), 42u32)]);971		});972	}973974	#[test]975	fn schedule_after_works() {976		new_test_ext().execute_with(|| {977			run_to_block(2);978			let call = Call::Logger(logger::Call::log(42, 1000));979			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(980				&call981			));982			// This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6983			assert_ok!(Scheduler::do_schedule(984				DispatchTime::After(3),985				None,986				127,987				root(),988				call989			));990			run_to_block(5);991			assert!(logger::log().is_empty());992			run_to_block(6);993			assert_eq!(logger::log(), vec![(root(), 42u32)]);994			run_to_block(100);995			assert_eq!(logger::log(), vec![(root(), 42u32)]);996		});997	}998999	#[test]1000	fn schedule_after_zero_works() {1001		new_test_ext().execute_with(|| {1002			run_to_block(2);1003			let call = Call::Logger(logger::Call::log(42, 1000));1004			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(1005				&call1006			));1007			assert_ok!(Scheduler::do_schedule(1008				DispatchTime::After(0),1009				None,1010				127,1011				root(),1012				call1013			));1014			// Will trigger on the next block.1015			run_to_block(3);1016			assert_eq!(logger::log(), vec![(root(), 42u32)]);1017			run_to_block(100);1018			assert_eq!(logger::log(), vec![(root(), 42u32)]);1019		});1020	}10211022	#[test]1023	fn periodic_scheduling_works() {1024		new_test_ext().execute_with(|| {1025			// at #4, every 3 blocks, 3 times.1026			assert_ok!(Scheduler::do_schedule(1027				DispatchTime::At(4),1028				Some((3, 3)),1029				127,1030				root(),1031				Call::Logger(logger::Call::log(42, 1000))1032			));1033			run_to_block(3);1034			assert!(logger::log().is_empty());1035			run_to_block(4);1036			assert_eq!(logger::log(), vec![(root(), 42u32)]);1037			run_to_block(6);1038			assert_eq!(logger::log(), vec![(root(), 42u32)]);1039			run_to_block(7);1040			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);1041			run_to_block(9);1042			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);1043			run_to_block(10);1044			assert_eq!(1045				logger::log(),1046				vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]1047			);1048			run_to_block(100);1049			assert_eq!(1050				logger::log(),1051				vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]1052			);1053		});1054	}10551056	#[test]1057	fn reschedule_works() {1058		new_test_ext().execute_with(|| {1059			let call = Call::Logger(logger::Call::log(42, 1000));1060			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(1061				&call1062			));1063			assert_eq!(1064				Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call).unwrap(),1065				(4, 0)1066			);10671068			run_to_block(3);1069			assert!(logger::log().is_empty());10701071			assert_eq!(1072				Scheduler::do_reschedule((4, 0), DispatchTime::At(6)).unwrap(),1073				(6, 0)1074			);10751076			assert_noop!(1077				Scheduler::do_reschedule((6, 0), DispatchTime::At(6)),1078				Error::<Test>::RescheduleNoChange1079			);10801081			run_to_block(4);1082			assert!(logger::log().is_empty());10831084			run_to_block(6);1085			assert_eq!(logger::log(), vec![(root(), 42u32)]);10861087			run_to_block(100);1088			assert_eq!(logger::log(), vec![(root(), 42u32)]);1089		});1090	}10911092	#[test]1093	fn reschedule_named_works() {1094		new_test_ext().execute_with(|| {1095			let call = Call::Logger(logger::Call::log(42, 1000));1096			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(1097				&call1098			));1099			assert_eq!(1100				Scheduler::do_schedule_named(1101					1u32.encode(),1102					DispatchTime::At(4),1103					None,1104					127,1105					root(),1106					call1107				)1108				.unwrap(),1109				(4, 0)1110			);11111112			run_to_block(3);1113			assert!(logger::log().is_empty());11141115			assert_eq!(1116				Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(),1117				(6, 0)1118			);11191120			assert_noop!(1121				Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)),1122				Error::<Test>::RescheduleNoChange1123			);11241125			run_to_block(4);1126			assert!(logger::log().is_empty());11271128			run_to_block(6);1129			assert_eq!(logger::log(), vec![(root(), 42u32)]);11301131			run_to_block(100);1132			assert_eq!(logger::log(), vec![(root(), 42u32)]);1133		});1134	}11351136	#[test]1137	fn reschedule_named_perodic_works() {1138		new_test_ext().execute_with(|| {1139			let call = Call::Logger(logger::Call::log(42, 1000));1140			assert!(!<Test as frame_system::Config>::BaseCallFilter::filter(1141				&call1142			));1143			assert_eq!(1144				Scheduler::do_schedule_named(1145					1u32.encode(),1146					DispatchTime::At(4),1147					Some((3, 3)),1148					127,1149					root(),1150					call1151				)1152				.unwrap(),1153				(4, 0)1154			);11551156			run_to_block(3);1157			assert!(logger::log().is_empty());11581159			assert_eq!(1160				Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(),1161				(5, 0)1162			);1163			assert_eq!(1164				Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(),1165				(6, 0)1166			);11671168			run_to_block(5);1169			assert!(logger::log().is_empty());11701171			run_to_block(6);1172			assert_eq!(logger::log(), vec![(root(), 42u32)]);11731174			assert_eq!(1175				Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(),1176				(10, 0)1177			);11781179			run_to_block(9);1180			assert_eq!(logger::log(), vec![(root(), 42u32)]);11811182			run_to_block(10);1183			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);11841185			run_to_block(13);1186			assert_eq!(1187				logger::log(),1188				vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]1189			);11901191			run_to_block(100);1192			assert_eq!(1193				logger::log(),1194				vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]1195			);1196		});1197	}11981199	#[test]1200	fn cancel_named_scheduling_works_with_normal_cancel() {1201		new_test_ext().execute_with(|| {1202			// at #4.1203			Scheduler::do_schedule_named(1204				1u32.encode(),1205				DispatchTime::At(4),1206				None,1207				127,1208				root(),1209				Call::Logger(logger::Call::log(69, 1000)),1210			)1211			.unwrap();1212			let i = Scheduler::do_schedule(1213				DispatchTime::At(4),1214				None,1215				127,1216				root(),1217				Call::Logger(logger::Call::log(42, 1000)),1218			)1219			.unwrap();1220			run_to_block(3);1221			assert!(logger::log().is_empty());1222			assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));1223			assert_ok!(Scheduler::do_cancel(None, i));1224			run_to_block(100);1225			assert!(logger::log().is_empty());1226		});1227	}12281229	#[test]1230	fn cancel_named_periodic_scheduling_works() {1231		new_test_ext().execute_with(|| {1232			// at #4, every 3 blocks, 3 times.1233			Scheduler::do_schedule_named(1234				1u32.encode(),1235				DispatchTime::At(4),1236				Some((3, 3)),1237				127,1238				root(),1239				Call::Logger(logger::Call::log(42, 1000)),1240			)1241			.unwrap();1242			// same id results in error.1243			assert!(Scheduler::do_schedule_named(1244				1u32.encode(),1245				DispatchTime::At(4),1246				None,1247				127,1248				root(),1249				Call::Logger(logger::Call::log(69, 1000))1250			)1251			.is_err());1252			// different id is ok.1253			Scheduler::do_schedule_named(1254				2u32.encode(),1255				DispatchTime::At(8),1256				None,1257				127,1258				root(),1259				Call::Logger(logger::Call::log(69, 1000)),1260			)1261			.unwrap();1262			run_to_block(3);1263			assert!(logger::log().is_empty());1264			run_to_block(4);1265			assert_eq!(logger::log(), vec![(root(), 42u32)]);1266			run_to_block(6);1267			assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode()));1268			run_to_block(100);1269			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1270		});1271	}12721273	#[test]1274	fn scheduler_respects_weight_limits() {1275		new_test_ext().execute_with(|| {1276			assert_ok!(Scheduler::do_schedule(1277				DispatchTime::At(4),1278				None,1279				127,1280				root(),1281				Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1282			));1283			assert_ok!(Scheduler::do_schedule(1284				DispatchTime::At(4),1285				None,1286				127,1287				root(),1288				Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1289			));1290			// 69 and 42 do not fit together1291			run_to_block(4);1292			assert_eq!(logger::log(), vec![(root(), 42u32)]);1293			run_to_block(5);1294			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1295		});1296	}12971298	#[test]1299	fn scheduler_respects_hard_deadlines_more() {1300		new_test_ext().execute_with(|| {1301			assert_ok!(Scheduler::do_schedule(1302				DispatchTime::At(4),1303				None,1304				0,1305				root(),1306				Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1307			));1308			assert_ok!(Scheduler::do_schedule(1309				DispatchTime::At(4),1310				None,1311				0,1312				root(),1313				Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1314			));1315			// With base weights, 69 and 42 should not fit together, but do because of hard deadlines1316			run_to_block(4);1317			assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);1318		});1319	}13201321	#[test]1322	fn scheduler_respects_priority_ordering() {1323		new_test_ext().execute_with(|| {1324			assert_ok!(Scheduler::do_schedule(1325				DispatchTime::At(4),1326				None,1327				1,1328				root(),1329				Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 2))1330			));1331			assert_ok!(Scheduler::do_schedule(1332				DispatchTime::At(4),1333				None,1334				0,1335				root(),1336				Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1337			));1338			run_to_block(4);1339			assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]);1340		});1341	}13421343	#[test]1344	fn scheduler_respects_priority_ordering_with_soft_deadlines() {1345		new_test_ext().execute_with(|| {1346			assert_ok!(Scheduler::do_schedule(1347				DispatchTime::At(4),1348				None,1349				255,1350				root(),1351				Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3))1352			));1353			assert_ok!(Scheduler::do_schedule(1354				DispatchTime::At(4),1355				None,1356				127,1357				root(),1358				Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1359			));1360			assert_ok!(Scheduler::do_schedule(1361				DispatchTime::At(4),1362				None,1363				126,1364				root(),1365				Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2))1366			));13671368			// 2600 does not fit with 69 or 42, but has higher priority, so will go through1369			run_to_block(4);1370			assert_eq!(logger::log(), vec![(root(), 2600u32)]);1371			// 69 and 42 fit together1372			run_to_block(5);1373			assert_eq!(1374				logger::log(),1375				vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]1376			);1377		});1378	}13791380	#[test]1381	fn on_initialize_weight_is_correct() {1382		new_test_ext().execute_with(|| {1383			let base_weight: Weight =1384				<Test as frame_system::Config>::DbWeight::get().reads_writes(1, 2);1385			let base_multiplier = 0;1386			let named_multiplier = <Test as frame_system::Config>::DbWeight::get().writes(1);1387			let periodic_multiplier =1388				<Test as frame_system::Config>::DbWeight::get().reads_writes(1, 1);13891390			// Named1391			assert_ok!(Scheduler::do_schedule_named(1392				1u32.encode(),1393				DispatchTime::At(1),1394				None,1395				255,1396				root(),1397				Call::Logger(logger::Call::log(3, MaximumSchedulerWeight::get() / 3))1398			));1399			// Anon Periodic1400			assert_ok!(Scheduler::do_schedule(1401				DispatchTime::At(1),1402				Some((1000, 3)),1403				128,1404				root(),1405				Call::Logger(logger::Call::log(42, MaximumSchedulerWeight::get() / 3))1406			));1407			// Anon1408			assert_ok!(Scheduler::do_schedule(1409				DispatchTime::At(1),1410				None,1411				127,1412				root(),1413				Call::Logger(logger::Call::log(69, MaximumSchedulerWeight::get() / 2))1414			));1415			// Named Periodic1416			assert_ok!(Scheduler::do_schedule_named(1417				2u32.encode(),1418				DispatchTime::At(1),1419				Some((1000, 3)),1420				126,1421				root(),1422				Call::Logger(logger::Call::log(2600, MaximumSchedulerWeight::get() / 2))1423			));14241425			// Will include the named periodic only1426			let actual_weight = Scheduler::on_initialize(1);1427			let call_weight = MaximumSchedulerWeight::get() / 2;1428			assert_eq!(1429				actual_weight,1430				call_weight1431					+ base_weight + base_multiplier1432					+ named_multiplier + periodic_multiplier1433			);1434			assert_eq!(logger::log(), vec![(root(), 2600u32)]);14351436			// Will include anon and anon periodic1437			let actual_weight = Scheduler::on_initialize(2);1438			let call_weight = MaximumSchedulerWeight::get() / 2 + MaximumSchedulerWeight::get() / 3;1439			assert_eq!(1440				actual_weight,1441				call_weight + base_weight + base_multiplier * 2 + periodic_multiplier1442			);1443			assert_eq!(1444				logger::log(),1445				vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]1446			);14471448			// Will include named only1449			let actual_weight = Scheduler::on_initialize(3);1450			let call_weight = MaximumSchedulerWeight::get() / 3;1451			assert_eq!(1452				actual_weight,1453				call_weight + base_weight + base_multiplier + named_multiplier1454			);1455			assert_eq!(1456				logger::log(),1457				vec![1458					(root(), 2600u32),1459					(root(), 69u32),1460					(root(), 42u32),1461					(root(), 3u32)1462				]1463			);14641465			// Will contain none1466			let actual_weight = Scheduler::on_initialize(4);1467			assert_eq!(actual_weight, 0);1468		});1469	}14701471	#[test]1472	fn root_calls_works() {1473		new_test_ext().execute_with(|| {1474			let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1475			let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1476			assert_ok!(Scheduler::schedule_named(1477				Origin::root(),1478				1u32.encode(),1479				4,1480				None,1481				127,1482				call1483			));1484			assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2));1485			run_to_block(3);1486			// Scheduled calls are in the agenda.1487			assert_eq!(Agenda::<Test>::get(4).len(), 2);1488			assert!(logger::log().is_empty());1489			assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode()));1490			assert_ok!(Scheduler::cancel(Origin::root(), 4, 1));1491			// Scheduled calls are made NONE, so should not effect state1492			run_to_block(100);1493			assert!(logger::log().is_empty());1494		});1495	}14961497	#[test]1498	fn fails_to_schedule_task_in_the_past() {1499		new_test_ext().execute_with(|| {1500			run_to_block(3);15011502			let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1503			let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));15041505			assert_err!(1506				Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call),1507				Error::<Test>::TargetBlockNumberInPast,1508			);15091510			assert_err!(1511				Scheduler::schedule(Origin::root(), 2, None, 127, call2.clone()),1512				Error::<Test>::TargetBlockNumberInPast,1513			);15141515			assert_err!(1516				Scheduler::schedule(Origin::root(), 3, None, 127, call2),1517				Error::<Test>::TargetBlockNumberInPast,1518			);1519		});1520	}15211522	#[test]1523	fn should_use_orign() {1524		new_test_ext().execute_with(|| {1525			let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1526			let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1527			assert_ok!(Scheduler::schedule_named(1528				system::RawOrigin::Signed(1).into(),1529				1u32.encode(),1530				4,1531				None,1532				127,1533				call1534			));1535			assert_ok!(Scheduler::schedule(1536				system::RawOrigin::Signed(1).into(),1537				4,1538				None,1539				127,1540				call21541			));1542			run_to_block(3);1543			// Scheduled calls are in the agenda.1544			assert_eq!(Agenda::<Test>::get(4).len(), 2);1545			assert!(logger::log().is_empty());1546			assert_ok!(Scheduler::cancel_named(1547				system::RawOrigin::Signed(1).into(),1548				1u32.encode()1549			));1550			assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1));1551			// Scheduled calls are made NONE, so should not effect state1552			run_to_block(100);1553			assert!(logger::log().is_empty());1554		});1555	}15561557	#[test]1558	fn should_check_orign() {1559		new_test_ext().execute_with(|| {1560			let call = Box::new(Call::Logger(logger::Call::log(69, 1000)));1561			let call2 = Box::new(Call::Logger(logger::Call::log(42, 1000)));1562			assert_noop!(1563				Scheduler::schedule_named(1564					system::RawOrigin::Signed(2).into(),1565					1u32.encode(),1566					4,1567					None,1568					127,1569					call1570				),1571				BadOrigin1572			);1573			assert_noop!(1574				Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, 127, call2),1575				BadOrigin1576			);1577		});1578	}15791580	#[test]1581	fn should_check_orign_for_cancel() {1582		new_test_ext().execute_with(|| {1583			let call = Box::new(Call::Logger(logger::Call::log_without_filter(69, 1000)));1584			let call2 = Box::new(Call::Logger(logger::Call::log_without_filter(42, 1000)));1585			assert_ok!(Scheduler::schedule_named(1586				system::RawOrigin::Signed(1).into(),1587				1u32.encode(),1588				4,1589				None,1590				127,1591				call1592			));1593			assert_ok!(Scheduler::schedule(1594				system::RawOrigin::Signed(1).into(),1595				4,1596				None,1597				127,1598				call21599			));1600			run_to_block(3);1601			// Scheduled calls are in the agenda.1602			assert_eq!(Agenda::<Test>::get(4).len(), 2);1603			assert!(logger::log().is_empty());1604			assert_noop!(1605				Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()),1606				BadOrigin1607			);1608			assert_noop!(1609				Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1),1610				BadOrigin1611			);1612			assert_noop!(1613				Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()),1614				BadOrigin1615			);1616			assert_noop!(1617				Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1),1618				BadOrigin1619			);1620			run_to_block(5);1621			assert_eq!(1622				logger::log(),1623				vec![1624					(system::RawOrigin::Signed(1).into(), 69u32),1625					(system::RawOrigin::Signed(1).into(), 42u32)1626				]1627			);1628		});1629	}16301631	#[test]1632	fn migration_to_v2_works() {1633		new_test_ext().execute_with(|| {1634			for i in 0..3u64 {1635				let k = i.twox_64_concat();1636				let old = vec![1637					Some(ScheduledV1 {1638						maybe_id: None,1639						priority: i as u8 + 10,1640						call: Call::Logger(logger::Call::log(96, 100)),1641						maybe_periodic: None,1642					}),1643					None,1644					Some(ScheduledV1 {1645						maybe_id: Some(b"test".to_vec()),1646						priority: 123,1647						call: Call::Logger(logger::Call::log(69, 1000)),1648						maybe_periodic: Some((456u64, 10)),1649					}),1650				];1651				frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);1652			}16531654			assert_eq!(StorageVersion::get(), Releases::V1);16551656			assert!(Scheduler::migrate_v1_to_t2());16571658			assert_eq_uvec!(1659				Agenda::<Test>::iter().collect::<Vec<_>>(),1660				vec![1661					(1662						0,1663						vec![1664							Some(ScheduledV2 {1665								maybe_id: None,1666								priority: 10,1667								call: Call::Logger(logger::Call::log(96, 100)),1668								maybe_periodic: None,1669								origin: root(),1670								_phantom: PhantomData::<u64>::default(),1671							}),1672							None,1673							Some(ScheduledV2 {1674								maybe_id: Some(b"test".to_vec()),1675								priority: 123,1676								call: Call::Logger(logger::Call::log(69, 1000)),1677								maybe_periodic: Some((456u64, 10)),1678								origin: root(),1679								_phantom: PhantomData::<u64>::default(),1680							}),1681						]1682					),1683					(1684						1,1685						vec![1686							Some(ScheduledV2 {1687								maybe_id: None,1688								priority: 11,1689								call: Call::Logger(logger::Call::log(96, 100)),1690								maybe_periodic: None,1691								origin: root(),1692								_phantom: PhantomData::<u64>::default(),1693							}),1694							None,1695							Some(ScheduledV2 {1696								maybe_id: Some(b"test".to_vec()),1697								priority: 123,1698								call: Call::Logger(logger::Call::log(69, 1000)),1699								maybe_periodic: Some((456u64, 10)),1700								origin: root(),1701								_phantom: PhantomData::<u64>::default(),1702							}),1703						]1704					),1705					(1706						2,1707						vec![1708							Some(ScheduledV2 {1709								maybe_id: None,1710								priority: 12,1711								call: Call::Logger(logger::Call::log(96, 100)),1712								maybe_periodic: None,1713								origin: root(),1714								_phantom: PhantomData::<u64>::default(),1715							}),1716							None,1717							Some(ScheduledV2 {1718								maybe_id: Some(b"test".to_vec()),1719								priority: 123,1720								call: Call::Logger(logger::Call::log(69, 1000)),1721								maybe_periodic: Some((456u64, 10)),1722								origin: root(),1723								_phantom: PhantomData::<u64>::default(),1724							}),1725						]1726					)1727				]1728			);17291730			assert_eq!(StorageVersion::get(), Releases::V2);1731		});1732	}17331734	#[test]1735	fn test_migrate_origin() {1736		new_test_ext().execute_with(|| {1737			for i in 0..3u64 {1738				let k = i.twox_64_concat();1739				let old: Vec<Option<Scheduled<_, _, u32, u64>>> = vec![1740					Some(Scheduled {1741						maybe_id: None,1742						priority: i as u8 + 10,1743						call: Call::Logger(logger::Call::log(96, 100)),1744						origin: 3u32,1745						maybe_periodic: None,1746						_phantom: Default::default(),1747					}),1748					None,1749					Some(Scheduled {1750						maybe_id: Some(b"test".to_vec()),1751						priority: 123,1752						origin: 2u32,1753						call: Call::Logger(logger::Call::log(69, 1000)),1754						maybe_periodic: Some((456u64, 10)),1755						_phantom: Default::default(),1756					}),1757				];1758				frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old);1759			}17601761			impl From<u32> for OriginCaller {1762				fn from(value: u32) -> Self {1763					match value {1764						3 => system::RawOrigin::Root.into(),1765						2 => system::RawOrigin::None.into(),1766						_ => unimplemented!(),1767					}1768				}1769			}17701771			Scheduler::migrate_origin::<u32>();17721773			assert_eq_uvec!(1774				Agenda::<Test>::iter().collect::<Vec<_>>(),1775				vec![1776					(1777						0,1778						vec![1779							Some(ScheduledV2::<_, _, OriginCaller, u64> {1780								maybe_id: None,1781								priority: 10,1782								call: Call::Logger(logger::Call::log(96, 100)),1783								maybe_periodic: None,1784								origin: system::RawOrigin::Root.into(),1785								_phantom: PhantomData::<u64>::default(),1786							}),1787							None,1788							Some(ScheduledV2 {1789								maybe_id: Some(b"test".to_vec()),1790								priority: 123,1791								call: Call::Logger(logger::Call::log(69, 1000)),1792								maybe_periodic: Some((456u64, 10)),1793								origin: system::RawOrigin::None.into(),1794								_phantom: PhantomData::<u64>::default(),1795							}),1796						]1797					),1798					(1799						1,1800						vec![1801							Some(ScheduledV2 {1802								maybe_id: None,1803								priority: 11,1804								call: Call::Logger(logger::Call::log(96, 100)),1805								maybe_periodic: None,1806								origin: system::RawOrigin::Root.into(),1807								_phantom: PhantomData::<u64>::default(),1808							}),1809							None,1810							Some(ScheduledV2 {1811								maybe_id: Some(b"test".to_vec()),1812								priority: 123,1813								call: Call::Logger(logger::Call::log(69, 1000)),1814								maybe_periodic: Some((456u64, 10)),1815								origin: system::RawOrigin::None.into(),1816								_phantom: PhantomData::<u64>::default(),1817							}),1818						]1819					),1820					(1821						2,1822						vec![1823							Some(ScheduledV2 {1824								maybe_id: None,1825								priority: 12,1826								call: Call::Logger(logger::Call::log(96, 100)),1827								maybe_periodic: None,1828								origin: system::RawOrigin::Root.into(),1829								_phantom: PhantomData::<u64>::default(),1830							}),1831							None,1832							Some(ScheduledV2 {1833								maybe_id: Some(b"test".to_vec()),1834								priority: 123,1835								call: Call::Logger(logger::Call::log(69, 1000)),1836								maybe_periodic: Some((456u64, 10)),1837								origin: system::RawOrigin::None.into(),1838								_phantom: PhantomData::<u64>::default(),1839							}),1840						]1841					)1842				]1843			);1844		});1845	}1846}
after · pallets/scheduler/src/lib.rs
1// This file is part of Substrate.23// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.4// SPDX-License-Identifier: Apache-2.056// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// 	http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.1718//! # Scheduler19//! A module for scheduling dispatches.20//!21//! - [`Config`]22//! - [`Call`]23//! - [`Module`]24//!25//! ## Overview26//!27//! This module exposes capabilities for scheduling dispatches to occur at a28//! specified block number or at a specified period. These scheduled dispatches29//! may be named or anonymous and may be canceled.30//!31//! **NOTE:** The scheduled calls will be dispatched with the default filter32//! for the origin: namely `frame_system::Config::BaseCallFilter` for all origin33//! except root which will get no filter. And not the filter contained in origin34//! use to call `fn schedule`.35//!36//! If a call is scheduled using proxy or whatever mecanism which adds filter,37//! then those filter will not be used when dispatching the schedule call.38//!39//! ## Interface40//!41//! ### Dispatchable Functions42//!43//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a44//!   specified block and with a specified priority.45//! * `cancel` - cancel a scheduled dispatch, specified by block number and46//!   index.47//! * `schedule_named` - augments the `schedule` interface with an additional48//!   `Vec<u8>` parameter that can be used for identification.49//! * `cancel_named` - the named complement to the cancel function.5051// Ensure we're `no_std` when compiling for Wasm.52#![cfg_attr(not(feature = "std"), no_std)]53#![allow(clippy::type_complexity, clippy::boxed_local, clippy::unused_unit)]5455mod benchmarking;56pub mod weights;5758use sp_std::{prelude::*, marker::PhantomData, borrow::Borrow};59use codec::{Encode, Decode, Codec};60use sp_runtime::{61	RuntimeDebug,62	traits::{Zero, One, BadOrigin, Saturating},63};64use frame_support::{65	decl_module, decl_storage, decl_event, decl_error, IterableStorageMap,66	dispatch::{Dispatchable, DispatchError, DispatchResult, Parameter},67	traits::{68		Get,69		schedule::{self, DispatchTime},70		OriginTrait, EnsureOrigin, IsType,71	},72	weights::{GetDispatchInfo, Weight},73};74use frame_system::{self as system, ensure_signed};75pub use weights::WeightInfo;76use up_sponsorship::SponsorshipHandler;7778/// Our pallet's configuration trait. All our types and constants go in here. If the79/// pallet is dependent on specific other pallets, then their configuration traits80/// should be added to our implied traits list.81///82/// `system::Config` should always be included in our implied traits.83/// //84pub trait Config: system::Config {85	/// The overarching event type.86	type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;8788	/// The aggregated origin which the dispatch will take.89	type Origin: OriginTrait<PalletsOrigin = Self::PalletsOrigin>90		+ From<Self::PalletsOrigin>91		+ IsType<<Self as system::Config>::Origin>;9293	/// The caller origin, overarching type of all pallets origins.94	type PalletsOrigin: From<system::RawOrigin<Self::AccountId>> + Codec + Clone + Eq;9596	/// The aggregated call type.97	type Call: Parameter98		+ Dispatchable<Origin = <Self as Config>::Origin>99		+ GetDispatchInfo100		+ From<system::Call<Self>>;101102	/// The maximum weight that may be scheduled per block for any dispatchables of less priority103	/// than `schedule::HARD_DEADLINE`.104	type MaximumWeight: Get<Weight>;105106	/// Required origin to schedule or cancel calls.107	type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::Origin>;108109	/// The maximum number of scheduled calls in the queue for a single block.110	/// Not strictly enforced, but used for weight estimation.111	type MaxScheduledPerBlock: Get<u32>;112113	/// Sponsoring function114	type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;115116	/// Weight information for extrinsics in this pallet.117	type WeightInfo: WeightInfo;118}119120// pub type SelfWeightInfo<T> = <T as system::Config>::WeightInfo;121122/// Just a simple index for naming period tasks.123pub type PeriodicIndex = u32;124/// The location of a scheduled task that can be used to remove it.125pub type TaskAddress<BlockNumber> = (BlockNumber, u32);126127#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]128#[derive(Clone, RuntimeDebug, Encode, Decode)]129struct ScheduledV1<Call, BlockNumber> {130	maybe_id: Option<Vec<u8>>,131	priority: schedule::Priority,132	call: Call,133	maybe_periodic: Option<schedule::Period<BlockNumber>>,134}135136/// Information regarding an item to be executed in the future.137#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))]138#[derive(Clone, RuntimeDebug, Encode, Decode)]139pub struct ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId> {140	/// The unique identity for this task, if there is one.141	maybe_id: Option<Vec<u8>>,142	/// This task's priority.143	priority: schedule::Priority,144	/// The call to be dispatched.145	call: Call,146	/// If the call is periodic, then this points to the information concerning that.147	maybe_periodic: Option<schedule::Period<BlockNumber>>,148	/// The origin to dispatch the call.149	origin: PalletsOrigin,150	_phantom: PhantomData<AccountId>,151}152153/// The current version of Scheduled struct.154pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =155	ScheduledV2<Call, BlockNumber, PalletsOrigin, AccountId>;156157// A value placed in storage that represents the current version of the Scheduler storage.158// This value is used by the `on_runtime_upgrade` logic to determine whether we run159// storage migration logic.160#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]161enum Releases {162	V1,163	V2,164}165166impl Default for Releases {167	fn default() -> Self {168		Releases::V1169	}170}171172#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]173pub struct CallSpec {174	module: u32,175	method: u32,176}177178decl_storage! {179	trait Store for Module<T: Config> as Scheduler {180		/// Items to be executed, indexed by the block number that they should be executed on.181		pub Agenda: map hasher(twox_64_concat) T::BlockNumber182			=> Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, T::PalletsOrigin, T::AccountId>>>;183184		pub SpecAgenda: map hasher(twox_64_concat) T::BlockNumber185			=> Vec<Option<CallSpec>>;186187		/// Lookup from identity to the block number and index of the task.188		Lookup: map hasher(twox_64_concat) Vec<u8> => Option<TaskAddress<T::BlockNumber>>;189190		/// Storage version of the pallet.191		///192		/// New networks start with last version.193		StorageVersion build(|_| Releases::V2): Releases;194	}195}196197decl_event!(198	pub enum Event<T> where <T as system::Config>::BlockNumber {199		/// Scheduled some task. \[when, index\]200		Scheduled(BlockNumber, u32),201		/// Canceled some task. \[when, index\]202		Canceled(BlockNumber, u32),203		/// Dispatched some task. \[task, id, result\]204		Dispatched(TaskAddress<BlockNumber>, Option<Vec<u8>>, DispatchResult),205	}206);207208decl_error! {209	pub enum Error for Module<T: Config> {210		/// Failed to schedule a call211		FailedToSchedule,212		/// Cannot find the scheduled call.213		NotFound,214		/// Given target block number is in the past.215		TargetBlockNumberInPast,216		/// Reschedule failed because it does not change scheduled time.217		RescheduleNoChange,218	}219}220221decl_module! {222	/// Scheduler module declaration.223	pub struct Module<T: Config> for enum Call224	where225		origin: <T as system::Config>::Origin226	{227		type Error = Error<T>;228		fn deposit_event() = default;229230231		/// Anonymously schedule a task.232		///233		/// # <weight>234		/// - S = Number of already scheduled calls235		/// - Base Weight: 22.29 + .126 * S µs236		/// - DB Weight:237		///     - Read: Agenda238		///     - Write: Agenda239		/// - Will use base weight of 25 which should be good for up to 30 scheduled calls240		/// # </weight>241		#[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]242		fn schedule(origin,243			when: T::BlockNumber,244			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,245			priority: schedule::Priority,246			call: Box<<T as Config>::Call>,247		)248		{249			let origin = <T as Config>::Origin::from(origin);250			Self::do_schedule(DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call)?;251		}252253		/// Cancel an anonymously scheduled task.254		///255		/// # <weight>256		/// - S = Number of already scheduled calls257		/// - Base Weight: 22.15 + 2.869 * S µs258		/// - DB Weight:259		///     - Read: Agenda260		///     - Write: Agenda, Lookup261		/// - Will use base weight of 100 which should be good for up to 30 scheduled calls262		/// # </weight>263		#[weight = <T as Config>::WeightInfo::cancel(T::MaxScheduledPerBlock::get())]264		fn cancel(origin, when: T::BlockNumber, index: u32) {265			T::ScheduleOrigin::ensure_origin(origin.clone())?;266			let origin = <T as Config>::Origin::from(origin);267			Self::do_cancel(Some(origin.caller().clone()), (when, index))?;268		}269270		/// Schedule a named task.271		///272		/// # <weight>273		/// - S = Number of already scheduled calls274		/// - Base Weight: 29.6 + .159 * S µs275		/// - DB Weight:276		///     - Read: Agenda, Lookup277		///     - Write: Agenda, Lookup278		/// - Will use base weight of 35 which should be good for more than 30 scheduled calls279		/// # </weight>280		#[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]281		fn schedule_named(origin,282			id: Vec<u8>,283			when: T::BlockNumber,284			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,285			priority: schedule::Priority,286			call: Box<<T as Config>::Call>,287		) {288			T::ScheduleOrigin::ensure_origin(origin.clone())?;289			let origin = <T as Config>::Origin::from(origin);290			Self::do_schedule_named(291				id, DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), *call292			)?;293		}294295		/// Cancel a named scheduled task.296		///297		/// # <weight>298		/// - S = Number of already scheduled calls299		/// - Base Weight: 24.91 + 2.907 * S µs300		/// - DB Weight:301		///     - Read: Agenda, Lookup302		///     - Write: Agenda, Lookup303		/// - Will use base weight of 100 which should be good for up to 30 scheduled calls304		/// # </weight>305		#[weight = <T as Config>::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get())]306		fn cancel_named(origin, id: Vec<u8>) {307			T::ScheduleOrigin::ensure_origin(origin.clone())?;308			let origin = <T as Config>::Origin::from(origin);309			Self::do_cancel_named(Some(origin.caller().clone()), id)?;310		}311312		/// Anonymously schedule a task after a delay.313		///314		/// # <weight>315		/// Same as [`schedule`].316		/// # </weight>317		#[weight = <T as Config>::WeightInfo::schedule(T::MaxScheduledPerBlock::get())]318		fn schedule_after(origin,319			after: T::BlockNumber,320			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,321			priority: schedule::Priority,322			call: Box<<T as Config>::Call>,323		) {324			T::ScheduleOrigin::ensure_origin(origin.clone())?;325			let origin = <T as Config>::Origin::from(origin);326			Self::do_schedule(327				DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call328			)?;329		}330331		/// Schedule a named task after a delay.332		///333		/// # <weight>334		/// Same as [`schedule_named`].335		/// # </weight>336		#[weight = <T as Config>::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get())]337		fn schedule_named_after(origin,338			id: Vec<u8>,339			after: T::BlockNumber,340			maybe_periodic: Option<schedule::Period<T::BlockNumber>>,341			priority: schedule::Priority,342			call: Box<<T as Config>::Call>,343		) {344			T::ScheduleOrigin::ensure_origin(origin.clone())?;345			let origin = <T as Config>::Origin::from(origin);346			Self::do_schedule_named(347				id, DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), *call348			)?;349		}350351		/// Execute the scheduled calls352		///353		/// # <weight>354		/// - S = Number of already scheduled calls355		/// - N = Named scheduled calls356		/// - P = Periodic Calls357		/// - Base Weight: 9.243 + 23.45 * S µs358		/// - DB Weight:359		///     - Read: Agenda + Lookup * N + Agenda(Future) * P360		///     - Write: Agenda + Lookup * N  + Agenda(future) * P361		/// # </weight>362		fn on_initialize(now: T::BlockNumber) -> Weight {363			let limit = T::MaximumWeight::get();364			let mut queued = Agenda::<T>::take(now).into_iter()365				.enumerate()366				.filter_map(|(index, s)| s.map(|inner| (index as u32, inner)))367				.collect::<Vec<_>>();368			if queued.len() as u32 > T::MaxScheduledPerBlock::get() {369				log::warn!(370					target: "runtime::scheduler",371					"Warning: This block has more items queued in Scheduler than \372					expected from the runtime configuration. An update might be needed."373				);374			}375			queued.sort_by_key(|(_, s)| s.priority);376			let base_weight: Weight = T::DbWeight::get().reads_writes(1, 2); // Agenda + Agenda(next)377			let mut total_weight: Weight = 0;378			queued.into_iter()379				.enumerate()380				.scan(base_weight, |cumulative_weight, (order, (index, s))| {381					*cumulative_weight = cumulative_weight382						.saturating_add(s.call.get_dispatch_info().weight);383384					let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(385						s.origin.clone()386					).into();387388					if ensure_signed(origin).is_ok() {389						 // AccountData for inner call origin accountdata.390						*cumulative_weight = cumulative_weight391							.saturating_add(T::DbWeight::get().reads_writes(1, 1));392					}393394					if s.maybe_id.is_some() {395						// Remove/Modify Lookup396						*cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().writes(1));397					}398					if s.maybe_periodic.is_some() {399						// Read/Write Agenda for future block400						*cumulative_weight = cumulative_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));401					}402403					Some((order, index, *cumulative_weight, s))404				})405				.filter_map(|(order, index, cumulative_weight, mut s)| {406					// We allow a scheduled call if any is true:407					// - It's priority is `HARD_DEADLINE`408					// - It does not push the weight past the limit.409					// - It is the first item in the schedule410					if s.priority <= schedule::HARD_DEADLINE || cumulative_weight <= limit || order == 0 {411412						let origin = <<T as Config>::Origin as From<T::PalletsOrigin>>::from(413							s.origin.clone()414						).into();415						let sender = ensure_signed(origin).unwrap_or_default();416						let who_will_pay = T::SponsorshipHandler::get_sponsor(&sender, &s.call).unwrap_or(sender);417						let sponsor = T::PalletsOrigin::from(system::RawOrigin::Signed(who_will_pay));418						let r = s.call.clone().dispatch(sponsor.into());419						let maybe_id = s.maybe_id.clone();420						if let Some((period, count)) = s.maybe_periodic {421							if count > 1 {422								s.maybe_periodic = Some((period, count - 1));423							} else {424								s.maybe_periodic = None;425							}426							let next = now + period;427							// If scheduled is named, place it's information in `Lookup`428							if let Some(ref id) = s.maybe_id {429								let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0);430								Lookup::<T>::insert(id, (next, next_index as u32));431							}432							Agenda::<T>::append(next, Some(s));433						} else if let Some(ref id) = s.maybe_id {434									  Lookup::<T>::remove(id);435								  }436						Self::deposit_event(RawEvent::Dispatched(437							(now, index),438							maybe_id,439							r.map(|_| ()).map_err(|e| e.error)440						));441						total_weight = cumulative_weight;442						None443					} else {444						Some(Some(s))445					}446				})447				.for_each(|unused| {448					let next = now + One::one();449					Agenda::<T>::append(next, unused);450				});451452			total_weight453		}454	}455}456457impl<T: Config> Module<T> {458	/// Migrate storage format from V1 to V2.459	/// Return true if migration is performed.460	pub fn migrate_v1_to_t2() -> bool {461		if StorageVersion::get() == Releases::V1 {462			StorageVersion::put(Releases::V2);463464			Agenda::<T>::translate::<465				Vec<Option<ScheduledV1<<T as Config>::Call, T::BlockNumber>>>,466				_,467			>(|_, agenda| {468				Some(469					agenda470						.into_iter()471						.map(|schedule| {472							schedule.map(|schedule| ScheduledV2 {473								maybe_id: schedule.maybe_id,474								priority: schedule.priority,475								call: schedule.call,476								maybe_periodic: schedule.maybe_periodic,477								origin: system::RawOrigin::Root.into(),478								_phantom: Default::default(),479							})480						})481						.collect::<Vec<_>>(),482				)483			});484485			true486		} else {487			false488		}489	}490491	/// Helper to migrate scheduler when the pallet origin type has changed.492	pub fn migrate_origin<OldOrigin: Into<T::PalletsOrigin> + codec::Decode>() {493		Agenda::<T>::translate::<494			Vec<Option<Scheduled<<T as Config>::Call, T::BlockNumber, OldOrigin, T::AccountId>>>,495			_,496		>(|_, agenda| {497			Some(498				agenda499					.into_iter()500					.map(|schedule| {501						schedule.map(|schedule| Scheduled {502							maybe_id: schedule.maybe_id,503							priority: schedule.priority,504							call: schedule.call,505							maybe_periodic: schedule.maybe_periodic,506							origin: schedule.origin.into(),507							_phantom: Default::default(),508						})509					})510					.collect::<Vec<_>>(),511			)512		});513	}514515	fn resolve_time(when: DispatchTime<T::BlockNumber>) -> Result<T::BlockNumber, DispatchError> {516		let now = frame_system::Pallet::<T>::block_number();517518		let when = match when {519			DispatchTime::At(x) => x,520			// The current block has already completed it's scheduled tasks, so521			// Schedule the task at lest one block after this current block.522			DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()),523		};524525		if when <= now {526			return Err(Error::<T>::TargetBlockNumberInPast.into());527		}528529		Ok(when)530	}531532	fn do_schedule(533		when: DispatchTime<T::BlockNumber>,534		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,535		priority: schedule::Priority,536		origin: T::PalletsOrigin,537		call: <T as Config>::Call,538	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {539		let when = Self::resolve_time(when)?;540541		// sanitize maybe_periodic542		let maybe_periodic = maybe_periodic543			.filter(|p| p.1 > 1 && !p.0.is_zero())544			// Remove one from the number of repetitions since we will schedule one now.545			.map(|(p, c)| (p, c - 1));546		let s = Some(Scheduled {547			maybe_id: None,548			priority,549			call,550			maybe_periodic,551			origin,552			_phantom: PhantomData::<T::AccountId>::default(),553		});554		Agenda::<T>::append(when, s);555		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;556		if index > T::MaxScheduledPerBlock::get() {557			log::warn!(558				target: "runtime::scheduler",559				"Warning: There are more items queued in the Scheduler than \560				expected from the runtime configuration. An update might be needed.",561			);562		}563		Self::deposit_event(RawEvent::Scheduled(when, index));564565		Ok((when, index))566	}567568	fn do_cancel(569		origin: Option<T::PalletsOrigin>,570		(when, index): TaskAddress<T::BlockNumber>,571	) -> Result<(), DispatchError> {572		let scheduled = Agenda::<T>::try_mutate(when, |agenda| {573			agenda.get_mut(index as usize).map_or(574				Ok(None),575				|s| -> Result<Option<Scheduled<_, _, _, _>>, DispatchError> {576					if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {577						if *o != s.origin {578							return Err(BadOrigin.into());579						}580					};581					Ok(s.take())582				},583			)584		})?;585		if let Some(s) = scheduled {586			if let Some(id) = s.maybe_id {587				Lookup::<T>::remove(id);588			}589			Self::deposit_event(RawEvent::Canceled(when, index));590			Ok(())591		} else {592			Err(Error::<T>::NotFound.into())593		}594	}595596	fn do_reschedule(597		(when, index): TaskAddress<T::BlockNumber>,598		new_time: DispatchTime<T::BlockNumber>,599	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {600		let new_time = Self::resolve_time(new_time)?;601602		if new_time == when {603			return Err(Error::<T>::RescheduleNoChange.into());604		}605606		Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {607			let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;608			let task = task.take().ok_or(Error::<T>::NotFound)?;609			Agenda::<T>::append(new_time, Some(task));610			Ok(())611		})?;612613		let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;614		Self::deposit_event(RawEvent::Canceled(when, index));615		Self::deposit_event(RawEvent::Scheduled(new_time, new_index));616617		Ok((new_time, new_index))618	}619620	fn do_schedule_named(621		id: Vec<u8>,622		when: DispatchTime<T::BlockNumber>,623		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,624		priority: schedule::Priority,625		origin: T::PalletsOrigin,626		call: <T as Config>::Call,627	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {628		// ensure id it is unique629		if Lookup::<T>::contains_key(&id) {630			return Err(Error::<T>::FailedToSchedule.into());631		}632633		let when = Self::resolve_time(when)?;634635		// sanitize maybe_periodic636		let maybe_periodic = maybe_periodic637			.filter(|p| p.1 > 1 && !p.0.is_zero())638			// Remove one from the number of repetitions since we will schedule one now.639			.map(|(p, c)| (p, c - 1));640641		let s = Scheduled {642			maybe_id: Some(id.clone()),643			priority,644			call,645			maybe_periodic,646			origin,647			_phantom: Default::default(),648		};649		Agenda::<T>::append(when, Some(s));650		let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;651		if index > T::MaxScheduledPerBlock::get() {652			log::warn!(653				target: "runtime::scheduler",654				"Warning: There are more items queued in the Scheduler than \655				expected from the runtime configuration. An update might be needed.",656			);657		}658		let address = (when, index);659		Lookup::<T>::insert(&id, &address);660		Self::deposit_event(RawEvent::Scheduled(when, index));661662		Ok(address)663	}664665	fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: Vec<u8>) -> DispatchResult {666		Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {667			if let Some((when, index)) = lookup.take() {668				let i = index as usize;669				Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {670					if let Some(s) = agenda.get_mut(i) {671						if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {672							if *o != s.origin {673								return Err(BadOrigin.into());674							}675						}676						*s = None;677					}678					Ok(())679				})?;680				Self::deposit_event(RawEvent::Canceled(when, index));681				Ok(())682			} else {683				Err(Error::<T>::NotFound.into())684			}685		})686	}687688	fn do_reschedule_named(689		id: Vec<u8>,690		new_time: DispatchTime<T::BlockNumber>,691	) -> Result<TaskAddress<T::BlockNumber>, DispatchError> {692		let new_time = Self::resolve_time(new_time)?;693694		Lookup::<T>::try_mutate_exists(695			id,696			|lookup| -> Result<TaskAddress<T::BlockNumber>, DispatchError> {697				let (when, index) = lookup.ok_or(Error::<T>::NotFound)?;698699				if new_time == when {700					return Err(Error::<T>::RescheduleNoChange.into());701				}702703				Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {704					let task = agenda.get_mut(index as usize).ok_or(Error::<T>::NotFound)?;705					let task = task.take().ok_or(Error::<T>::NotFound)?;706					Agenda::<T>::append(new_time, Some(task));707708					Ok(())709				})?;710711				let new_index = Agenda::<T>::decode_len(new_time).unwrap_or(1) as u32 - 1;712				Self::deposit_event(RawEvent::Canceled(when, index));713				Self::deposit_event(RawEvent::Scheduled(new_time, new_index));714715				*lookup = Some((new_time, new_index));716717				Ok((new_time, new_index))718			},719		)720	}721}722723impl<T: Config> schedule::Anon<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>724	for Module<T>725{726	type Address = TaskAddress<T::BlockNumber>;727728	fn schedule(729		when: DispatchTime<T::BlockNumber>,730		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,731		priority: schedule::Priority,732		origin: T::PalletsOrigin,733		call: <T as Config>::Call,734	) -> Result<Self::Address, DispatchError> {735		Self::do_schedule(when, maybe_periodic, priority, origin, call)736	}737738	fn cancel((when, index): Self::Address) -> Result<(), ()> {739		Self::do_cancel(None, (when, index)).map_err(|_| ())740	}741742	fn reschedule(743		address: Self::Address,744		when: DispatchTime<T::BlockNumber>,745	) -> Result<Self::Address, DispatchError> {746		Self::do_reschedule(address, when)747	}748749	fn next_dispatch_time((when, index): Self::Address) -> Result<T::BlockNumber, ()> {750		Agenda::<T>::get(when)751			.get(index as usize)752			.ok_or(())753			.map(|_| when)754	}755}756757impl<T: Config> schedule::Named<T::BlockNumber, <T as Config>::Call, T::PalletsOrigin>758	for Module<T>759{760	type Address = TaskAddress<T::BlockNumber>;761762	fn schedule_named(763		id: Vec<u8>,764		when: DispatchTime<T::BlockNumber>,765		maybe_periodic: Option<schedule::Period<T::BlockNumber>>,766		priority: schedule::Priority,767		origin: T::PalletsOrigin,768		call: <T as Config>::Call,769	) -> Result<Self::Address, ()> {770		Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ())771	}772773	fn cancel_named(id: Vec<u8>) -> Result<(), ()> {774		Self::do_cancel_named(None, id).map_err(|_| ())775	}776777	fn reschedule_named(778		id: Vec<u8>,779		when: DispatchTime<T::BlockNumber>,780	) -> Result<Self::Address, DispatchError> {781		Self::do_reschedule_named(id, when)782	}783784	fn next_dispatch_time(id: Vec<u8>) -> Result<T::BlockNumber, ()> {785		Lookup::<T>::get(id)786			.and_then(|(when, index)| Agenda::<T>::get(when).get(index as usize).map(|_| when))787			.ok_or(())788	}789}790791#[cfg(test)]792#[allow(clippy::from_over_into)]793mod tests {794	use super::*;795796	use frame_support::{797		parameter_types, assert_ok, ord_parameter_types, assert_noop, assert_err, Hashable,798		traits::{OnInitialize, OnFinalize, Filter},799		weights::constants::RocksDbWeight,800	};801	use sp_core::H256;802	use sp_runtime::{803		Perbill,804		testing::Header,805		traits::{BlakeTwo256, IdentityLookup},806	};807	use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy};808	use substrate_test_utils::assert_eq_uvec;809	use crate as scheduler;810811	mod logger {812		use super::*;813		use std::cell::RefCell;814815		thread_local! {816			static LOG: RefCell<Vec<(OriginCaller, u32)>> = RefCell::new(Vec::new());817		}818		pub fn log() -> Vec<(OriginCaller, u32)> {819			LOG.with(|log| log.borrow().clone())820		}821		pub trait Config: system::Config {822			type Event: From<Event> + Into<<Self as system::Config>::Event>;823		}824		decl_event! {825			pub enum Event {826				Logged(u32, Weight),827			}828		}829		decl_module! {830			pub struct Module<T: Config> for enum Call831			where832				origin: <T as system::Config>::Origin,833				<T as system::Config>::Origin: OriginTrait<PalletsOrigin = OriginCaller>834			{835				fn deposit_event() = default;836837				#[weight = *weight]838				fn log(origin, i: u32, weight: Weight) {839					Self::deposit_event(Event::Logged(i, weight));840					LOG.with(|log| {841						log.borrow_mut().push((origin.caller().clone(), i));842					})843				}844845				#[weight = *weight]846				fn log_without_filter(origin, i: u32, weight: Weight) {847					Self::deposit_event(Event::Logged(i, weight));848					LOG.with(|log| {849						log.borrow_mut().push((origin.caller().clone(), i));850					})851				}852			}853		}854	}855856	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;857	type Block = frame_system::mocking::MockBlock<Test>;858859	frame_support::construct_runtime!(860		pub enum Test where861			Block = Block,862			NodeBlock = Block,863			UncheckedExtrinsic = UncheckedExtrinsic,864		{865			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},866			Logger: logger::{Pallet, Call, Event},867			Scheduler: scheduler::{Pallet, Call, Storage, Event<T>},868		}869	);870871	// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used.872	pub struct BaseFilter;873	impl Filter<Call> for BaseFilter {874		fn filter(call: &Call) -> bool {875			!matches!(call, Call::Logger(logger::Call::log(_, _)))876		}877	}878879	parameter_types! {880		pub const BlockHashCount: u64 = 250;881		pub BlockWeights: frame_system::limits::BlockWeights =882			frame_system::limits::BlockWeights::simple_max(2_000_000_000_000);883	}884	impl system::Config for Test {885		type BaseCallFilter = BaseFilter;886		type BlockWeights = ();887		type BlockLength = ();888		type DbWeight = RocksDbWeight;889		type Origin = Origin;890		type Call = Call;891		type Index = u64;892		type BlockNumber = u64;893		type Hash = H256;894		type Hashing = BlakeTwo256;895		type AccountId = u64;896		type Lookup = IdentityLookup<Self::AccountId>;897		type Header = Header;898		type Event = Event;899		type BlockHashCount = BlockHashCount;900		type Version = ();901		type PalletInfo = PalletInfo;902		type AccountData = ();903		type OnNewAccount = ();904		type OnKilledAccount = ();905		type SystemWeightInfo = ();906		type SS58Prefix = ();907		type OnSetCode = ();908	}909	impl logger::Config for Test {910		type Event = Event;911	}912	parameter_types! {913		pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block;914		pub const MaxScheduledPerBlock: u32 = 10;915	}916	ord_parameter_types! {917		pub const One: u64 = 1;918	}919920	impl Config for Test {921		type Event = Event;922		type Origin = Origin;923		type PalletsOrigin = OriginCaller;924		type Call = Call;925		type MaximumWeight = MaximumSchedulerWeight;926		type ScheduleOrigin = EnsureOneOf<u64, EnsureRoot<u64>, EnsureSignedBy<One, u64>>;927		type MaxScheduledPerBlock = MaxScheduledPerBlock;928		type WeightInfo = ();929		type SponsorshipHandler = ();930	}931932	pub fn new_test_ext() -> sp_io::TestExternalities {933		let t = system::GenesisConfig::default()934			.build_storage::<Test>()935			.unwrap();936		t.into()937	}938939	fn run_to_block(n: u64) {940		while System::block_number() < n {941			Scheduler::on_finalize(System::block_number());942			System::set_block_number(System::block_number() + 1);943			Scheduler::on_initialize(System::block_number());944		}945	}946947	fn root() -> OriginCaller {948		system::RawOrigin::Root.into()949	}950}
modifiedprimitives/nft/src/lib.rsdiffbeforeafterboth
--- a/primitives/nft/src/lib.rs
+++ b/primitives/nft/src/lib.rs
@@ -144,6 +144,7 @@
 	pub limits: CollectionLimits<T::BlockNumber>, // Collection private restrictions
 	pub variable_on_chain_schema: Vec<u8>,        //
 	pub const_on_chain_schema: Vec<u8>,           //
+	pub transfers_enabled: bool,
 }
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq)]
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -154,7 +154,7 @@
 	transaction_version: 1,
 };
 
-pub const MILLISECS_PER_BLOCK: u64 = 12000;
+pub const MILLISECS_PER_BLOCK: u64 = 1200;
 
 pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
 
@@ -449,7 +449,7 @@
 }
 
 impl pallet_transaction_payment::Config for Runtime {
-	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, ()>;
+	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
 	type TransactionByteFee = TransactionByteFee;
 	type WeightToFee = LinearFee<Balance>;
 	type FeeMultiplierUpdate = ();
modifiedruntime_types.jsondiffbeforeafterboth
--- a/runtime_types.json
+++ b/runtime_types.json
@@ -62,7 +62,8 @@
       "Sponsorship": "SponsorshipState",
       "Limits": "CollectionLimits",
       "VariableOnChainSchema": "Vec<u8>",
-      "ConstOnChainSchema": "Vec<u8>"
+      "ConstOnChainSchema": "Vec<u8>",
+      "TransfersEnabled": "bool"
     },
     "RawData": "Vec<u8>",
     "Address": "MultiAddress",
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -1,12 +1,12 @@
 {
-  "name": "NftTests",
+  "name": "nfttests",
   "version": "1.0.0",
   "description": "Substrate Nft tests",
   "main": "",
   "devDependencies": {
     "@polkadot/dev": "0.62.43",
     "@polkadot/ts": "0.3.89",
-    "@polkadot/typegen": "4.15.1",
+    "@polkadot/typegen": "5.0.1",
     "@types/chai": "^4.2.17",
     "@types/chai-as-promised": "^7.1.3",
     "@types/mocha": "^8.2.2",
@@ -59,15 +59,15 @@
     "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
     "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
     "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
-    "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts"
+    "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
+    "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts"
   },
   "author": "",
   "license": "SEE LICENSE IN ../LICENSE",
   "homepage": "",
   "dependencies": {
-    "@polkadot/api": "4.15.1",
-    "@polkadot/api-contract": "4.15.1",
-    "@polkadot/util": "6.9.1",
+    "@polkadot/api": "5.0.1",
+    "@polkadot/api-contract": "5.0.1",
     "bignumber.js": "^9.0.1",
     "chai-as-promised": "^7.1.1",
     "solc": "^0.8.6",
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/addCollectionAdmin.test.ts
+++ b/tests/src/addCollectionAdmin.test.ts
@@ -22,7 +22,7 @@
       const bob = privateKey('//Bob');
 
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(alice.address));
+      expect(collection.Owner).to.be.equal(alice.address);
 
       const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));
       await submitTransactionAsync(alice, changeAdminTx);
@@ -40,7 +40,7 @@
       const Charlie = privateKey('//CHARLIE');
 
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.equal(Alice.address);
 
       const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(Bob.address));
       await submitTransactionAsync(Alice, changeAdminTx);
modifiedtests/src/addToContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/addToContractWhiteList.test.ts
+++ b/tests/src/addToContractWhiteList.test.ts
@@ -17,7 +17,7 @@
 chai.use(chaiAsPromised);
 const expect = chai.expect;
 
-describe('Integration Test addToContractWhiteList', () => {
+describe.skip('Integration Test addToContractWhiteList', () => {
 
   it('Add an address to a contract white list', async () => {
     await usingApi(async api => {
@@ -56,7 +56,7 @@
   });
 });
 
-describe('Negative Integration Test addToContractWhiteList', () => {
+describe.skip('Negative Integration Test addToContractWhiteList', () => {
 
   it('Add an address to a white list of a non-contract', async () => {
     await usingApi(async api => {
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -7,26 +7,26 @@
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
 import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
-import { createCollectionExpectSuccess, normalizeAccountId } from './util/helpers';
+import { createCollectionExpectSuccess } from './util/helpers';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
 
 describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => {
-  it('Changing owner changes owner.', async () => {
+  it('Changing owner changes owner address', async () => {
     await usingApi(async api => {
       const collectionId = await createCollectionExpectSuccess();
       const alice = privateKey('//Alice');
       const bob = privateKey('//Bob');
 
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(alice.address));
+      expect(collection.Owner).to.be.deep.eq(alice.address);
 
-      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, normalizeAccountId(bob.address));
+      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
       await submitTransactionAsync(alice, changeOwnerTx);
 
       const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collectionAfterOwnerChange.Owner).to.be.deep.eq(normalizeAccountId(bob.address));
+      expect(collectionAfterOwnerChange.Owner).to.be.deep.eq(bob.address);
     });
   });
 });
@@ -38,23 +38,23 @@
       const alice = privateKey('//Alice');
       const bob = privateKey('//Bob');
 
-      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, normalizeAccountId(bob.address));
+      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
       await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected;
 
       const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collectionAfterOwnerChange.Owner).to.be.deep.eq(normalizeAccountId(alice.address));
+      expect(collectionAfterOwnerChange.Owner).to.be.deep.eq(alice.address);
 
       // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
       await createCollectionExpectSuccess();
     });
   });
-  it('Can\'t change owner of not existing collection.', async () => {
+  it('Can\'t change owner of a non-existing collection.', async () => {
     await usingApi(async api => {
       const collectionId = (1<<32) - 1;
       const alice = privateKey('//Alice');
       const bob = privateKey('//Bob');
 
-      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, normalizeAccountId(bob.address));
+      const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
       await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;
 
       // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -226,7 +226,7 @@
       const result1 = getGenericResult(events1);
 
       const AsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString());
-      await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);
+      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;
       const BsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString());
 
       // Try again after Zero gets some balance - now it should succeed
@@ -327,7 +327,7 @@
 
 });
 
-describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => {
+describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {
   before(async () => {
     await usingApi(async () => {
       const keyring = new Keyring({ type: 'sr25519' });
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -36,7 +36,7 @@
 const gasLimit = 9000n * 1000000n;
 const marketContractAddress = '5CYN9j3YvRkqxewoxeSvRbhAym4465C57uMmX5j4yz99L5H6';
 
-describe('Contracts', () => {
+describe.skip('Contracts', () => {
   it('Can deploy smart contract Flipper, instantiate it and call it\'s get and flip messages.', async () => {
     await usingApi(async api => {
       const [contract, deployer] = await deployFlipper(api);
@@ -62,7 +62,7 @@
   });
 });
 
-describe.only('Chain extensions', () => {
+describe.skip('Chain extensions', () => {
   it('Transfer CE', async () => {
     await usingApi(async api => {
       const alice = privateKey('//Alice');
modifiedtests/src/enableContractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/enableContractSponsoring.test.ts
+++ b/tests/src/enableContractSponsoring.test.ts
@@ -19,7 +19,7 @@
 chai.use(chaiAsPromised);
 const expect = chai.expect;
 
-describe('Integration Test enableContractSponsoring', () => {
+describe.skip('Integration Test enableContractSponsoring', () => {
   it('ensure tx fee is paid from endowment', async () => {
     await usingApi(async (api) => {
       const user = await findUnusedAddress(api);
@@ -64,7 +64,7 @@
 
 });
 
-describe('Negative Integration Test enableContractSponsoring', () => {
+describe.skip('Negative Integration Test enableContractSponsoring', () => {
   let alice: IKeyringPair;
 
   before(async () => {
addedtests/src/enableDisableTransfer.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/enableDisableTransfer.test.ts
@@ -0,0 +1,64 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import privateKey from './substrate/privateKey';
+import usingApi from './substrate/substrate-api';
+import {
+  createItemExpectSuccess,
+  createCollectionExpectSuccess,
+  transferExpectSuccess,
+  transferExpectFailure,
+  setTransferFlagExpectSuccess,
+  setTransferFlagExpectFailure,
+} from './util/helpers';
+
+chai.use(chaiAsPromised);
+
+describe('Enable/Disable Transfers', () => {
+  it('User can transfer token with enabled transfer flag', async () => {
+    await usingApi(async () => {
+      const Alice = privateKey('//Alice');
+      const Bob = privateKey('//Bob');
+      // nft
+      const nftCollectionId = await createCollectionExpectSuccess();
+      const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+
+      // explicitely set transfer flag
+      await setTransferFlagExpectSuccess(Alice, nftCollectionId, true);
+
+      await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1);
+    });
+  });
+
+  it('User can\'n transfer token with disabled transfer flag', async () => {
+    await usingApi(async () => {
+      const Alice = privateKey('//Alice');
+      const Bob = privateKey('//Bob');
+      // nft
+      const nftCollectionId = await createCollectionExpectSuccess();
+      const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+
+      // explicitely set transfer flag
+      await setTransferFlagExpectSuccess(Alice, nftCollectionId, false);
+
+      await transferExpectFailure(nftCollectionId, newNftTokenId, Alice, Bob, 1);
+    });
+  });
+});
+
+describe('Negative Enable/Disable Transfers', () => {
+  it('Non-owner cannot change transfer flag', async () => {
+    await usingApi(async () => {
+      const Bob = privateKey('//Bob');
+      // nft
+      const nftCollectionId = await createCollectionExpectSuccess();
+
+      // Change transfer flag
+      await setTransferFlagExpectFailure(Bob, nftCollectionId, false);
+    });
+  });
+});
modifiedtests/src/overflow.test.tsdiffbeforeafterboth
--- a/tests/src/overflow.test.ts
+++ b/tests/src/overflow.test.ts
@@ -8,7 +8,7 @@
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
 import usingApi from './substrate/substrate-api';
-import { approveExpectFail, approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, getAllowance, getFungibleBalance, transferExpectFail, transferExpectSuccess, transferFromExpectFail, transferFromExpectSuccess, U128_MAX } from './util/helpers';
+import { approveExpectFail, approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, getAllowance, getFungibleBalance, transferExpectFailure, transferExpectSuccess, transferFromExpectFail, transferFromExpectSuccess, U128_MAX } from './util/helpers';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -33,7 +33,7 @@
     await transferExpectSuccess(fungibleCollectionId, 0, alice, bob, U128_MAX, 'Fungible');
 
     await createFungibleItemExpectSuccess(alice, fungibleCollectionId, { Value: 1n });
-    await transferExpectFail(fungibleCollectionId, 0, alice, bob, 1, 'Fungible');
+    await transferExpectFailure(fungibleCollectionId, 0, alice, bob, 1);
 
     expect(await getFungibleBalance(fungibleCollectionId, alice.address)).to.equal(1n);
     expect(await getFungibleBalance(fungibleCollectionId, bob.address)).to.equal(U128_MAX);
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -13,13 +13,33 @@
 
 // Pallets that must always be present
 const requiredPallets = [
-  'nft', 'inflation', 'balances', 'contracts', 'randomnesscollectiveflip', 'system', 'timestamp', 'transactionpayment', 'treasury', 'vesting', 'evm', 'ethereum',
-  'scheduler', 'nftpayment', 'charging',
+  'balances',
+  'randomnesscollectiveflip',
+  'timestamp',
+  'transactionpayment',
+  'treasury',
+  'system',
+  'vesting',
+  'parachainsystem',
+  'parachaininfo',
+  'evm',
+  'ethereum',
+  'xcmpqueue',
+  'polkadotxcm',
+  'cumulusxcm',
+  'dmpqueue',
+  'inflation',
+  'nft',
+  'scheduler',
+  'nftpayment',
+  'charging',
 ];
 
 // Pallets that depend on consensus and governance configuration
 const consensusPallets = [
-  'sudo', 'aura',
+  'sudo',
+  'aura',
+  'auraext',
 ];
 
 describe('Pallet presence', () => {
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -20,7 +20,7 @@
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.deep.eq(Alice.address);
       // first - add collection admin Bob
       const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(Bob.address));
       await submitTransactionAsync(Alice, addAdminTx);
modifiedtests/src/removeCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionSponsor.test.ts
+++ b/tests/src/removeCollectionSponsor.test.ts
@@ -38,7 +38,7 @@
     });
   });
 
-  it('Remove NFT collection sponsor stops sponsorship', async () => {
+  it('Removing NFT collection sponsor stops sponsorship', async () => {
     const collectionId = await createCollectionExpectSuccess();
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
modifiedtests/src/removeFromContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/removeFromContractWhiteList.test.ts
+++ b/tests/src/removeFromContractWhiteList.test.ts
@@ -10,7 +10,7 @@
 import { IKeyringPair } from '@polkadot/types/types';
 import { expect } from 'chai';
 
-describe('Integration Test removeFromContractWhiteList', () => {
+describe.skip('Integration Test removeFromContractWhiteList', () => {
   let bob: IKeyringPair;
 
   before(async () => {
@@ -54,7 +54,7 @@
   });
 });
 
-describe('Negative Integration Test removeFromContractWhiteList', () => {
+describe.skip('Negative Integration Test removeFromContractWhiteList', () => {
   let alice: IKeyringPair;
   let bob: IKeyringPair;
 
modifiedtests/src/scheduler.test.tsdiffbeforeafterboth
--- a/tests/src/scheduler.test.ts
+++ b/tests/src/scheduler.test.ts
@@ -28,7 +28,7 @@
       await setCollectionSponsorExpectSuccess(nftCollectionId, Alice.address);
       await confirmSponsorshipExpectSuccess(nftCollectionId);
 
-      await scheduleTransferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+      await scheduleTransferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 6000, 4);
     });
   });
 });
modifiedtests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setConstOnChainSchema.test.ts
+++ b/tests/src/setConstOnChainSchema.test.ts
@@ -11,7 +11,6 @@
 import {
   createCollectionExpectSuccess,
   destroyCollectionExpectSuccess,
-  normalizeAccountId,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -38,7 +37,7 @@
     await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.eq(Alice.address);
       const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
       await submitTransactionAsync(Alice, setShema);
     });
@@ -88,7 +87,7 @@
     await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.eq(Alice.address);
       const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
       await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected;
     });
modifiedtests/src/setContractSponsoringRateLimit.test.tsdiffbeforeafterboth
--- a/tests/src/setContractSponsoringRateLimit.test.ts
+++ b/tests/src/setContractSponsoringRateLimit.test.ts
@@ -15,7 +15,7 @@
   setContractSponsoringRateLimitExpectSuccess,
 } from './util/helpers';
 
-describe('Integration Test setContractSponsoringRateLimit', () => {
+describe.skip('Integration Test setContractSponsoringRateLimit', () => {
   it('ensure sponsored contract can\'t be called twice without pause for free', async () => {
     await usingApi(async (api) => {
       const user = await findUnusedAddress(api);
@@ -42,7 +42,7 @@
   });
 });
 
-describe('Negative Integration Test setContractSponsoringRateLimit', () => {
+describe.skip('Negative Integration Test setContractSponsoringRateLimit', () => {
   let alice: IKeyringPair;
 
   before(async () => {
modifiedtests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableOnChainSchema.test.ts
+++ b/tests/src/setVariableOnChainSchema.test.ts
@@ -11,7 +11,6 @@
 import {
   createCollectionExpectSuccess,
   destroyCollectionExpectSuccess,
-  normalizeAccountId,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -38,7 +37,7 @@
     await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.eq(Alice.address);
       const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
       await submitTransactionAsync(Alice, setSchema);
     });
@@ -88,7 +87,7 @@
     await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
       const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
-      expect(collection.Owner).to.be.deep.eq(normalizeAccountId(Alice.address));
+      expect(collection.Owner).to.be.eq(Alice.address);
       const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
       await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
     });
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
--- a/tests/src/substrate/substrate-api.ts
+++ b/tests/src/substrate/substrate-api.ts
@@ -33,11 +33,20 @@
   // TODO: Remove, this is temporary: Filter unneeded API output 
   // (Jaco promised it will be removed in the next version)
   const consoleErr = console.error;
-  console.error = (message: string) => {
-    if (!message.includes('StorageChangeSet:: WebSocket is not connected') || message.includes('2021-'))
+  const consoleLog = console.log;
+  const consoleWarn = console.warn;
+
+  const outFn = (message: string) => {
+    if (!message.includes('StorageChangeSet:: WebSocket is not connected') && 
+        !message.includes('2021-') &&
+        !message.includes('StorageChangeSet:: Normal connection closure'))
       consoleErr(message);
   };
 
+  console.error = outFn;
+  console.log = outFn;
+  console.warn = outFn;
+
   try {
     await promisifySubstrate(api, async () => {
       if (api) {
@@ -48,6 +57,8 @@
   } finally {
     await api.disconnect();
     console.error = consoleErr;
+    console.log = consoleLog;
+    console.warn = consoleWarn;
   }
   return result as T;
 }
modifiedtests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/toggleContractWhiteList.test.ts
+++ b/tests/src/toggleContractWhiteList.test.ts
@@ -21,7 +21,7 @@
 const value = 0;
 const gasLimit = 3000n * 1000000n;
 
-describe('Integration Test toggleContractWhiteList', () => {
+describe.skip('Integration Test toggleContractWhiteList', () => {
 
   it('Enable white list contract mode', async () => {
     await usingApi(async api => {
@@ -121,7 +121,7 @@
 
 });
 
-describe('Negative Integration Test toggleContractWhiteList', () => {
+describe.skip('Negative Integration Test toggleContractWhiteList', () => {
 
   it('Enable white list for a non-contract', async () => {
     await usingApi(async api => {
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -16,7 +16,7 @@
   findUnusedAddress,
   getCreateCollectionResult,
   getCreateItemResult,
-  transferExpectFail,
+  transferExpectFailure,
   transferExpectSuccess,
 } from './util/helpers';
 
@@ -103,13 +103,13 @@
     await usingApi(async (api) => {
       // nft
       const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
-      await transferExpectFail(nftCollectionCount + 1, 1, Alice, Bob, 1);
+      await transferExpectFailure(nftCollectionCount + 1, 1, Alice, Bob, 1);
       // fungible
       const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
-      await transferExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob, 1);
+      await transferExpectFailure(fungibleCollectionCount + 1, 1, Alice, Bob, 1);
       // reFungible
       const reFungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
-      await transferExpectFail(reFungibleCollectionCount + 1, 1, Alice, Bob, 1);
+      await transferExpectFailure(reFungibleCollectionCount + 1, 1, Alice, Bob, 1);
     });
   });
   it('Transfer with deleted collection_id', async () => {
@@ -117,43 +117,41 @@
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
     await destroyCollectionExpectSuccess(nftCollectionId);
-    await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+    await transferExpectFailure(nftCollectionId, newNftTokenId, Alice, Bob, 1);
     // fungible
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
     await destroyCollectionExpectSuccess(fungibleCollectionId);
-    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+    await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1);
     // reFungible
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await destroyCollectionExpectSuccess(reFungibleCollectionId);
-    await transferExpectFail(
+    await transferExpectFailure(
       reFungibleCollectionId,
       newReFungibleTokenId,
       Alice,
       Bob,
       1,
-      'ReFungible',
     );
   });
   it('Transfer with not existed item_id', async () => {
     // nft
     const nftCollectionId = await createCollectionExpectSuccess();
-    await transferExpectFail(nftCollectionId, 2, Alice, Bob, 1, 'NFT');
+    await transferExpectFailure(nftCollectionId, 2, Alice, Bob, 1);
     // fungible
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-    await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');
+    await transferExpectFailure(fungibleCollectionId, 2, Alice, Bob, 1);
     // reFungible
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-    await transferExpectFail(
+    await transferExpectFailure(
       reFungibleCollectionId,
       2,
       Alice,
       Bob,
       1,
-      'ReFungible',
     );
   });
   it('Transfer with deleted item_id', async () => {
@@ -161,46 +159,44 @@
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
     await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);
-    await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+    await transferExpectFailure(nftCollectionId, newNftTokenId, Alice, Bob, 1);
     // fungible
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
     await burnItemExpectSuccess(Alice, fungibleCollectionId, newFungibleTokenId, 10);
-    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+    await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1);
     // reFungible
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
-    await transferExpectFail(
+    await transferExpectFailure(
       reFungibleCollectionId,
       newReFungibleTokenId,
       Alice,
       Bob,
       1,
-      'ReFungible',
     );
   });
   it('Transfer with recipient that is not owner', async () => {
     // nft
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
-    await transferExpectFail(nftCollectionId, newNftTokenId, Charlie, Bob, 1, 'NFT');
+    await transferExpectFailure(nftCollectionId, newNftTokenId, Charlie, Bob, 1);
     // fungible
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
-    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1, 'Fungible');
+    await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1);
     // reFungible
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
-    await transferExpectFail(
+    await transferExpectFailure(
       reFungibleCollectionId,
       newReFungibleTokenId,
       Charlie,
       Bob,
       1,
-      'ReFungible',
     );
   });
 });
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -84,7 +84,7 @@
 }
 
 interface ITokenDataType {
-  Owner: number[];
+  Owner: IKeyringPair;
   ConstData: number[];
   VariableData: number[];
 }
@@ -523,6 +523,30 @@
   });
 }
 
+export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {
+
+  await usingApi(async (api) => {
+
+    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);
+    const events = await submitTransactionAsync(sender, tx);
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.true;
+  }); 
+}
+
+export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {
+
+  await usingApi(async (api) => {
+
+    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);
+    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.false;
+  }); 
+}
+
 export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {
   await usingApi(async (api) => {
     const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);
@@ -543,9 +567,9 @@
   });
 }
 
-export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string) {
+export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {
   await usingApi(async (api) => {
-    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);
+    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, value);
     const events = await submitTransactionAsync(sender, tx);
     const result = getGenericResult(events);
 
@@ -748,29 +772,31 @@
   sender: IKeyringPair,
   recipient: IKeyringPair,
   value: number | bigint = 1,
+  blockTimeMs: number,
+  blockSchedule: number,
 ) {
   await usingApi(async (api: ApiPromise) => {
     const blockNumber: number | undefined = await getBlockNumber(api);
-    const expectedBlockNumber = blockNumber + 2;
+    const expectedBlockNumber = blockNumber + blockSchedule;
 
     expect(blockNumber).to.be.greaterThan(0);
-    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 
+    const transferTx = await api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value); 
     const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);
 
     await submitTransactionAsync(sender, scheduleTx);
 
     const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());
 
-    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;
-    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);
+    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as any as ITokenDataType;
+    expect(toSubstrateAddress(nftItemDataBefore.Owner)).to.be.equal(sender.address);
 
-    // sleep for 2 blocks
-    await new Promise(resolve => setTimeout(resolve, 6000 * 2));
+    // sleep for 4 blocks
+    await new Promise(resolve => setTimeout(resolve, blockTimeMs * (blockSchedule + 1)));
 
     const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());
 
     const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;
-    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);
+    expect(toSubstrateAddress(nftItemData.Owner)).to.be.equal(recipient.address);
     expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());
   });
 }
@@ -820,7 +846,7 @@
 }
 
 export async function
-transferExpectFail(
+transferExpectFailure(
   collectionId: number,
   tokenId: number,
   sender: IKeyringPair,
@@ -895,7 +921,8 @@
       const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };
       tx = api.tx.nft.createItem(collectionId, to, createData);
     } else {
-      tx = api.tx.nft.createItem(collectionId, to, createMode);
+      const createData = { nft: { const_data: [], variable_data: [] } };
+      tx = api.tx.nft.createItem(collectionId, to, createData);
     }
 
     const events = await submitTransactionAsync(sender, tx);
modifiedtests/yarn.lockdiffbeforeafterboth
--- a/tests/yarn.lock
+++ b/tests/yarn.lock
@@ -42,7 +42,7 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08"
   integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==
 
-"@babel/core@^7.1.0", "@babel/core@^7.14.5", "@babel/core@^7.14.6", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
+"@babel/core@^7.1.0", "@babel/core@^7.14.6", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
   version "7.14.6"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab"
   integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==
@@ -971,7 +971,7 @@
     pirates "^4.0.0"
     source-map-support "^0.5.16"
 
-"@babel/runtime@^7.13.9", "@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.8.4":
+"@babel/runtime@^7.14.6", "@babel/runtime@^7.8.4":
   version "7.14.6"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
   integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
@@ -1019,21 +1019,6 @@
   version "0.4.2"
   resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.2.tgz#f63d0ef06f5c0c57d76c4ab5f63d3835c51b0179"
   integrity sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==
-  dependencies:
-    ajv "^6.12.4"
-    debug "^4.1.1"
-    espree "^7.3.0"
-    globals "^13.9.0"
-    ignore "^4.0.6"
-    import-fresh "^3.2.1"
-    js-yaml "^3.13.1"
-    minimatch "^3.0.4"
-    strip-json-comments "^3.1.1"
-
-"@eslint/eslintrc@^0.4.3":
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
-  integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
   dependencies:
     ajv "^6.12.4"
     debug "^4.1.1"
@@ -1559,47 +1544,46 @@
   dependencies:
     "@octokit/openapi-types" "^7.3.2"
 
-"@polkadot/api-contract@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-4.15.1.tgz#bfa5aa67b2cdc3c203ed09cfd14c396469eeafa2"
-  integrity sha512-TyKc6fyBMJnrHhnicM2hTCQMZMfd5Baarz4L75QMxkWFLTpxQ68BnYFcdupfH6fNXHZeHdRpSW/KPBj47UYgeA==
+"@polkadot/api-contract@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-5.0.1.tgz#520a7b3cd990a76374b79e12eca5bf629cc565a1"
+  integrity sha512-qZ2wnXHDyU2c1/V9GKpbcZKBfVua4YFsU/LHKevZLkJfnGFBgNRdwAuKgVe5h2FCt2W2/pt618WgxG0UDWwjcw==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/api" "4.15.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/x-rxjs" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/api" "5.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
+    rxjs "^7.2.0"
 
-"@polkadot/api-derive@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-4.15.1.tgz#841ae233142f4b509d4db1fbcf76db15a77bed0f"
-  integrity sha512-gAkKg4w09PThemRz0VI4YDzTy3RfCJrjpR0ZnYT93lZWsspSDiQIzMOTPbOn7MvC7FujeRIT0zqpzDeqKc4wFQ==
+"@polkadot/api-derive@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-5.0.1.tgz#08064c10ed159826ffd07013dcdde1d8b63186a0"
+  integrity sha512-JZpH1JVLu3PvX4+A71iDLtNr6LL103dAFou61DxyJF4obyTmS2lzigG3xXqUFShiPDb19ywxQpsE4gAOP6emuQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/api" "4.15.1"
-    "@polkadot/rpc-core" "4.15.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/util-crypto" "^6.9.1"
-    "@polkadot/x-rxjs" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/api" "5.0.1"
+    "@polkadot/rpc-core" "5.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
+    "@polkadot/util-crypto" "^7.0.1"
+    rxjs "^7.2.0"
 
-"@polkadot/api@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-4.15.1.tgz#c9a041b855639a98d6df0706c7546e076a8d5727"
-  integrity sha512-MsGKpTAmnkxIN+Zu21NPKWot4xLsDGn/cdranf+P2OjqB80E6m8zkQOE7ug3912WIi5byZp55TSOE9UUzAAW3Q==
+"@polkadot/api@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-5.0.1.tgz#9607b53009322f9264f7dcc8705c466bd33aa516"
+  integrity sha512-5JDpM2Fjc80gHBju1B/rMBGDfAvY8UiU4XVlivJRk+mTVD3OTwbtTro4nmwJOub05xQCJvD/bnCuxG8eFSoq+Q==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/api-derive" "4.15.1"
-    "@polkadot/keyring" "^6.9.1"
-    "@polkadot/metadata" "4.15.1"
-    "@polkadot/rpc-core" "4.15.1"
-    "@polkadot/rpc-provider" "4.15.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/types-known" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/util-crypto" "^6.9.1"
-    "@polkadot/x-rxjs" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/api-derive" "5.0.1"
+    "@polkadot/keyring" "^7.0.1"
+    "@polkadot/rpc-core" "5.0.1"
+    "@polkadot/rpc-provider" "5.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/types-known" "5.0.1"
+    "@polkadot/util" "^7.0.1"
+    "@polkadot/util-crypto" "^7.0.1"
     eventemitter3 "^4.0.7"
+    rxjs "^7.2.0"
 
 "@polkadot/dev@0.62.43":
   version "0.62.43"
@@ -1665,57 +1649,45 @@
     typescript "^4.3.4"
     yargs "^17.0.1"
 
-"@polkadot/keyring@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-6.9.1.tgz#a92dd2d4ef8ccb999bc7d443ef4a13e6ef9b2ce2"
-  integrity sha512-UF+9psVwVlar7LRJYWJB/xETYBPu1OcyVrxDe88w17Y+ZIsIeNfcR9quVS4M7AdAhplmscsz/wgEMjmggXH9/Q==
-  dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/util" "6.9.1"
-    "@polkadot/util-crypto" "6.9.1"
-
-"@polkadot/metadata@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/metadata/-/metadata-4.15.1.tgz#3cd2392b956577edf96090793fd8b9b392a67502"
-  integrity sha512-pnOgJSFCVgQpZtp7ghS0AS7xWCp6POKrb5LhY1CK7XTy6iQ6VHcGnr1N4wfia1c3o5ZOPj8Xic29Da61tkjp2Q==
+"@polkadot/keyring@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-7.0.1.tgz#666e903661b98279dc16d512be69f5ace4b58d8d"
+  integrity sha512-eSvG8Q4gUTRDFWj2lqTY/9NekGP8dtp+W6WmouKh0DDwHRawaVeDaq6UJYQv6XoBG1i+ZGPvErRQeGMPOn/mUQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/types-known" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/util-crypto" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/util" "7.0.1"
+    "@polkadot/util-crypto" "7.0.1"
 
-"@polkadot/networks@6.9.1", "@polkadot/networks@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-6.9.1.tgz#8d66338569c9891a00cc6737e18c1dbffd7153f5"
-  integrity sha512-imBPIrLN0W+7zuosD4WBtOkMzXc/271NhWn6dQmyA0xEoJx+6coJHQH/04fqO/gfZd4M1R70f3Gt5hlsfzCwlA==
+"@polkadot/networks@7.0.1", "@polkadot/networks@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-7.0.1.tgz#e07c4b88e25711433e76d24fce4c7273c25dd38b"
+  integrity sha512-bJSvI7UgEpxmBKS8TMh+I1mfmCMwhClGdSs29kwU+K61IjBTKTt3yQJ/SflYIQV7QftGbz3oMfSkGbQbRHZqvQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
+    "@babel/runtime" "^7.14.6"
 
-"@polkadot/rpc-core@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-4.15.1.tgz#2e14edcdf8cd4e6f9658ecbd90540a9d39c3e929"
-  integrity sha512-g9NxsHgOBzqLBWGV+hbXd8tmDWBdIZSxr3b107xY090wbQQ0R9I6D6wi+d7mJtcH1tazuhQgWQqyvvsbr2xPZg==
+"@polkadot/rpc-core@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-5.0.1.tgz#8460287532fe61c31505564df53e92ef6feba875"
+  integrity sha512-JMNOVQijjyJZNu9B8CJwIrQzGYzAp03uCBSbqYfzWBFnYVLKh7JmvOlkLnODM8uUYq0gVN4BaDUSPc39GpELAQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/metadata" "4.15.1"
-    "@polkadot/rpc-provider" "4.15.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/x-rxjs" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/rpc-provider" "5.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
+    rxjs "^7.2.0"
 
-"@polkadot/rpc-provider@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-4.15.1.tgz#18a61b5353388da73f722f30905f23927b2c5e31"
-  integrity sha512-NfgdBsLP56XAIrSu29iKmqLb4ZAbK50VINGv3Qi99s5V2FiFOAvZq22arkoCmFo1q4zFpQeQqul3ZyZv8QX/Kg==
+"@polkadot/rpc-provider@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-5.0.1.tgz#ef022a123eb9073634b59c6e0f6e1705e96066a5"
+  integrity sha512-t+VKhMtQfQVgkZDqYnP/44KlBDmcCVo1/MvJ+DoNd7RUWUIBJt3v71G5gDSNeGMTyvxn0KK0qL4j+Nqr6c4FUQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/util-crypto" "^6.9.1"
-    "@polkadot/x-fetch" "^6.9.1"
-    "@polkadot/x-global" "^6.9.1"
-    "@polkadot/x-ws" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
+    "@polkadot/util-crypto" "^7.0.1"
+    "@polkadot/x-fetch" "^7.0.1"
+    "@polkadot/x-global" "^7.0.1"
+    "@polkadot/x-ws" "^7.0.1"
     eventemitter3 "^4.0.7"
 
 "@polkadot/ts@0.3.89":
@@ -1725,57 +1697,55 @@
   dependencies:
     "@types/chrome" "^0.0.144"
 
-"@polkadot/typegen@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-4.15.1.tgz#e04d5ef70712bfc91707723a1ae0198e5309ed75"
-  integrity sha512-gIk3GdgNuRp0GnbrljUVUgrsT7GLbGcNmI/Jbnt64Zyw20beMrvPQyDkoRBWrN4aN14B1SW1xIXQz4axVy7Tug==
+"@polkadot/typegen@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-5.0.1.tgz#718b517f4f1578441911096603577bd0a2a968e0"
+  integrity sha512-iFLJoWgIkn+J6MDw3AUWveP9qxVn1C+VeLJbpZ21St5WyeE148Tml0BmYnKLSXlaPMhZEwB+/IV3jpQ35dH4bw==
   dependencies:
-    "@babel/core" "^7.14.5"
+    "@babel/core" "^7.14.6"
     "@babel/register" "^7.14.5"
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/api" "4.15.1"
-    "@polkadot/metadata" "4.15.1"
-    "@polkadot/rpc-provider" "4.15.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/api" "5.0.1"
+    "@polkadot/rpc-provider" "5.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
     handlebars "^4.7.7"
     websocket "^1.0.34"
     yargs "^17.0.1"
 
-"@polkadot/types-known@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-4.15.1.tgz#d60cfb1e4ed315f2c82646795243a34df6b21fd3"
-  integrity sha512-yj2fVwEyYrc6eBoW6W3JQ5h1FZjcyyhDzfrtxronSLdT7H6zUtlLqn1A5uzkxPD0eSXkesh960GHeYzAi+p4cw==
+"@polkadot/types-known@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-5.0.1.tgz#21feb327fc4323733bf027c8d874a2aa3014b21f"
+  integrity sha512-AIhPlN4r14ZW4wdwHZD2nIe1DE61ZO9PsyrCyAU3ysl6Cw6TI+txDCN3aS/8XYuC7wDLEgLB9vJv2sVWdCzqJg==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/networks" "^6.9.1"
-    "@polkadot/types" "4.15.1"
-    "@polkadot/util" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/networks" "^7.0.1"
+    "@polkadot/types" "5.0.1"
+    "@polkadot/util" "^7.0.1"
 
-"@polkadot/types@4.15.1":
-  version "4.15.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-4.15.1.tgz#03f32fd4ce81d69c43368d3e476c0421cedb8607"
-  integrity sha512-daCblGDkiNHyDNkVDOQ0x/hblK7zkGAFQy+ykMt6euGGllUiKaAbCKlQN803aKmsB/5m8zQU63MHQC65tkpWXg==
+"@polkadot/types@5.0.1":
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-5.0.1.tgz#2a4e23e452f999eeae175b595470df0e426a930d"
+  integrity sha512-aN6JKeF7ZYi5irYAaUoDqth6qlOlB15C5vhlDOojEorYLfRs/R+GCrO+lPSs+bKmSxh7BSRh500ikI/xD4nx5A==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/metadata" "4.15.1"
-    "@polkadot/util" "^6.9.1"
-    "@polkadot/util-crypto" "^6.9.1"
-    "@polkadot/x-rxjs" "^6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/util" "^7.0.1"
+    "@polkadot/util-crypto" "^7.0.1"
+    rxjs "^7.2.0"
 
-"@polkadot/util-crypto@6.9.1", "@polkadot/util-crypto@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-6.9.1.tgz#175a2bbc040785599730baee35f0235226b8343e"
-  integrity sha512-lniY8bhRoayA8PD3NHyvpAL2N9YETDll6HbxaOIkGS9nnVmlOjIvslcd343b30rj7/qSV72w+8qkReHj650aQw==
+"@polkadot/util-crypto@7.0.1", "@polkadot/util-crypto@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-7.0.1.tgz#03109dc11323dad174fb2214d395855495def16a"
+  integrity sha512-dbvdsICoyOVw/K45RmHOP7wXE/7vj+NzEKGcKbiDt39nglHm6g2BTJ947PwwyNusTTAx82Q2iJ9vIZ1Kl0xG+g==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/networks" "6.9.1"
-    "@polkadot/util" "6.9.1"
-    "@polkadot/wasm-crypto" "^4.0.2"
-    "@polkadot/x-randomvalues" "6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/networks" "7.0.1"
+    "@polkadot/util" "7.0.1"
+    "@polkadot/wasm-crypto" "^4.1.2"
+    "@polkadot/x-randomvalues" "7.0.1"
     base-x "^3.0.8"
     base64-js "^1.5.1"
-    blakejs "^1.1.0"
+    blakejs "^1.1.1"
     bn.js "^4.11.9"
     create-hash "^1.2.0"
     elliptic "^6.5.4"
@@ -1785,101 +1755,91 @@
     tweetnacl "^1.0.3"
     xxhashjs "^0.2.2"
 
-"@polkadot/util@6.9.1", "@polkadot/util@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-6.9.1.tgz#009a9e0771523398517dbf3a978285b071f6081c"
-  integrity sha512-RTIn8+Xdgywj8Bl7D12557zi8iIoUvDpAJztp/CwIq4O3jEw6Y/7lqNX/K6OXhZm/gZf7tFgFnvGlsIuNbtYcQ==
+"@polkadot/util@7.0.1", "@polkadot/util@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-7.0.1.tgz#79afd40473016876f51d65ebb9900a20108fe0a4"
+  integrity sha512-EtQlZL6ok0Ep+zRz2QHMUoJo/b3kFHVN2qqyD2+9sdqg0FGLmkzNFM+K6dasCMLXieJ1l0HoFsQppSo/leUeaA==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-textdecoder" "6.9.1"
-    "@polkadot/x-textencoder" "6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-textdecoder" "7.0.1"
+    "@polkadot/x-textencoder" "7.0.1"
     "@types/bn.js" "^4.11.6"
     bn.js "^4.11.9"
     camelcase "^5.3.1"
     ip-regex "^4.3.0"
 
-"@polkadot/wasm-crypto-asmjs@^4.0.2":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.0.2.tgz#f42c353a64e1243841daf90e4bd54eff01a4e3cf"
-  integrity sha512-hlebqtGvfjg2ZNm4scwBGVHwOwfUhy2yw5RBHmPwkccUif3sIy4SAzstpcVBIVMdAEvo746bPWEInA8zJRcgJA==
+"@polkadot/wasm-crypto-asmjs@^4.1.2":
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-4.1.2.tgz#094b3eeeb5fd39a93db177583b48454511874cfc"
+  integrity sha512-3Q+vVUxDAC2tXgKMM3lKzx2JW+tarDpTjkvdxIKATyi8Ek69KkUqvMyJD0VL/iFZOFZED0YDX9UU4XOJ/astlg==
   dependencies:
-    "@babel/runtime" "^7.13.9"
+    "@babel/runtime" "^7.14.6"
 
-"@polkadot/wasm-crypto-wasm@^4.0.2":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.0.2.tgz#89f9e0a1e4d076784d4a42bea37fc8b06bdd8bb6"
-  integrity sha512-de/AfNPZ0uDKFWzOZ1rJCtaUbakGN29ks6IRYu6HZTRg7+RtqvE1rIkxabBvYgQVHIesmNwvEA9DlIkS6hYRFQ==
+"@polkadot/wasm-crypto-wasm@^4.1.2":
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-4.1.2.tgz#773c78c1d65886671d3ba1d66c31afd86c93d02f"
+  integrity sha512-/l4IBEdQ41szHdHkuF//z1qr+XmWuLHlpBA7s9Eb221m1Fir6AKoCHoh1hp1r3v0ecZYLKvak1B225w6JAU3Fg==
   dependencies:
-    "@babel/runtime" "^7.13.9"
+    "@babel/runtime" "^7.14.6"
 
-"@polkadot/wasm-crypto@^4.0.2":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-4.0.2.tgz#9649057adee8383cc86433d107ba526b718c5a3b"
-  integrity sha512-2h9FuQFkBc+B3TwSapt6LtyPvgtd0Hq9QsHW8g8FrmKBFRiiFKYRpfJKHCk0aCZzuRf9h95bQl/X6IXAIWF2ng==
+"@polkadot/wasm-crypto@^4.1.2":
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-4.1.2.tgz#dead71ae5d2f7722d23aed5be2112e1732d315e9"
+  integrity sha512-2EKdOjIrD2xHP2rC+0G/3Qo6926nL/18vCFkd34lBd9zP9YNF2GDEtDY+zAeDIRFKe1sQHTpsKgNdYSWoV2eBg==
   dependencies:
-    "@babel/runtime" "^7.13.9"
-    "@polkadot/wasm-crypto-asmjs" "^4.0.2"
-    "@polkadot/wasm-crypto-wasm" "^4.0.2"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/wasm-crypto-asmjs" "^4.1.2"
+    "@polkadot/wasm-crypto-wasm" "^4.1.2"
 
-"@polkadot/x-fetch@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-6.9.1.tgz#89ff2741b35f2bb9fdc30a22cdb0debf72248597"
-  integrity sha512-CckiiRiGM+7WGOw1WijDeN9NJcTBEjZ96LRMaUng+BNvNhUQplsmX6CUt86Qn6T1O8TQaAg93wtqb+deykkn2g==
+"@polkadot/x-fetch@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-7.0.1.tgz#2db6fa19f4f4d9b2f4cf50ba78bf3aa947d7b982"
+  integrity sha512-9R38FjtlJcvdpEA7tVGmTmH4aiBCTABuLJdVSn3cYkgWfxDHeFMqjdFzTJ6Asa5cY0Ds3ZKsh9uccTQBQzV/HQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-global" "6.9.1"
-    "@types/node-fetch" "^2.5.10"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-global" "7.0.1"
+    "@types/node-fetch" "^2.5.11"
     node-fetch "^2.6.1"
 
-"@polkadot/x-global@6.9.1", "@polkadot/x-global@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-6.9.1.tgz#c3d7482e2ac62c306379592550d476fc60ce7dfe"
-  integrity sha512-/pVzvQUObccuk/f2BGcs0WMjveLQPr1Qf+uiSF/7ae9BZHIG4ydLz0/Lnzbt4YQkIEaRNvVFD1Vph5hyjo4VCA==
+"@polkadot/x-global@7.0.1", "@polkadot/x-global@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-7.0.1.tgz#44fb248d3aaea557753318327149772969e96bff"
+  integrity sha512-gVVACSdRhHYRJejLEAL0mM9BZfY8N50VT2+15A7ALD1tVqwS4tz3P9vRW3Go7ZjfyAc83aEmh0PiQ8Nm1R+2Cg==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@types/node-fetch" "^2.5.10"
-    node-fetch "^2.6.1"
+    "@babel/runtime" "^7.14.6"
 
-"@polkadot/x-randomvalues@6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-6.9.1.tgz#e289e79849e332777fb96e8544b1193a4e793e59"
-  integrity sha512-L1c5ddjzyPAvzRkbnrbVgQTUskM4vRtfxblOV/tmM1BP6mB1U3rWo0FeHNWN/uiUoibVFIDNUKqUnZ5vhYs1qg==
+"@polkadot/x-randomvalues@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-7.0.1.tgz#32036ae5d48645a062f6a1c3ebbf227236c806b8"
+  integrity sha512-UNoIFaz1xJPozruT+lo8BTeT8A3NM3PgWuru7Vs8OsIz0Phkg7lUWlpHu9PZHyQCyKlUryvkOA692IlVlNYy2Q==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-global" "6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-global" "7.0.1"
 
-"@polkadot/x-rxjs@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-rxjs/-/x-rxjs-6.9.1.tgz#713a399568922aff10fe47c3875dba44a139d6c6"
-  integrity sha512-sfQNA7so5KoeFEIIx7OGZL5D+0Hn0SRZJMbZSuGRFMKjyovpyzWi+Mjs3l6T6OXbKm972XAseNGDUWSVG4EpLQ==
+"@polkadot/x-textdecoder@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-7.0.1.tgz#bb9bba94b2eb1612dd35c299f43ab74515db74d9"
+  integrity sha512-CFRnpI0cp1h2N1+ec551BLVLwV6OHG6Gj62EYcIOXR+o/SX/6MXm3Qcehm2YvfTKqktyIUSWmTwbWjGjuqPrpA==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    rxjs "^6.6.7"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-global" "7.0.1"
 
-"@polkadot/x-textdecoder@6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-6.9.1.tgz#dab6e95b35c9386550c4907fd1efb195ab605ec9"
-  integrity sha512-U7Cu7PbY5CG5kjbKqAQ/e07FfvPYZwHZZbC+343vDHUnJlyONKxp+jhod+A1pepu15fsYH/iZC0Os6RwfKoEAA==
+"@polkadot/x-textencoder@7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-7.0.1.tgz#181d403c5dc1d94fd1e2147fd1c5c528d30d8805"
+  integrity sha512-m+QL1HNiu5GMz6cfr/udSA6fUTv3RyIybJb7v43EQCxqlj/L0J3cUHapFd6tqH9PElD6jPkH1pXcgYN8e7dWTQ==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-global" "6.9.1"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-global" "7.0.1"
 
-"@polkadot/x-textencoder@6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-6.9.1.tgz#cf98a3f248ad9a4cdb2559f950ff6559d009b619"
-  integrity sha512-M9VNm7IpbBwQnCZhEBAXSQ+/g2psEv4zjJYdX4/HTcWNpnYEUHeayIVTw91Wkgo3dN8wBL245vVp/8apfKfMkQ==
-  dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-global" "6.9.1"
-
-"@polkadot/x-ws@^6.9.1":
-  version "6.9.1"
-  resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-6.9.1.tgz#ac4d0cf22c333359a426f4104581c9e394d7f6e5"
-  integrity sha512-BeoVqFFLatrt3k8Leyi6LsOMz5rkdXbQ5oE2Db0V+ezfh5aEV/JjoLsaPkX+i6xsCYibB43rY64FBhpJ2O0iYg==
+"@polkadot/x-ws@^7.0.1":
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-7.0.1.tgz#8c22a61c0dd9b82865c7631e22ac147c2b73b118"
+  integrity sha512-VUn/6sCJUpvW9WhUK+DKo1uDrw4yO84twRcy5JSzvSiBTaSplhU9Q4qGFl2Atr3WIzAYYx1jQSm/j6AhPRji1w==
   dependencies:
-    "@babel/runtime" "^7.14.5"
-    "@polkadot/x-global" "6.9.1"
-    "@types/websocket" "^1.0.2"
+    "@babel/runtime" "^7.14.6"
+    "@polkadot/x-global" "7.0.1"
+    "@types/websocket" "^1.0.3"
     websocket "^1.0.34"
 
 "@rushstack/eslint-patch@^1.0.6":
@@ -2046,10 +2006,10 @@
   resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0"
   integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==
 
-"@types/node-fetch@^2.5.10":
-  version "2.5.10"
-  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
-  integrity sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==
+"@types/node-fetch@^2.5.11":
+  version "2.5.11"
+  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.11.tgz#ce22a2e65fc8999f4dbdb7ddbbcf187d755169e4"
+  integrity sha512-2upCKaqVZETDRb8A2VTaRymqFBEgH8u6yr96b/u3+1uQEPDRo3mJLEiPk7vdXBHRtjwkjqzFYMJXrt0Z9QsYjQ==
   dependencies:
     "@types/node" "*"
     form-data "^3.0.0"
@@ -2093,10 +2053,10 @@
   resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
   integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
 
-"@types/websocket@^1.0.2":
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.2.tgz#d2855c6a312b7da73ed16ba6781815bf30c6187a"
-  integrity sha512-B5m9aq7cbbD/5/jThEr33nUY8WEfVi6A2YKCTOvw5Ldy7mtsOkqRvGjnzy6g7iMMDsgu7xREuCzqATLDLQVKcQ==
+"@types/websocket@^1.0.3":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.3.tgz#49e09f939afd0ccdee4f7108d4712ec9feb0f153"
+  integrity sha512-ZdoTSwmDsKR7l1I8fpfQtmTI/hUwlOvE3q0iyJsp4tXU0MkdrYowimDzwxjhQvxU4qjhHLd3a6ig0OXRbLgIdw==
   dependencies:
     "@types/node" "*"
 
@@ -2826,6 +2786,11 @@
   resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5"
   integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U=
 
+blakejs@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702"
+  integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==
+
 bluebird@^3.1.1, bluebird@^3.5.0:
   version "3.7.2"
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -4307,12 +4272,12 @@
   integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
 
 eslint@^7.28.0:
-  version "7.31.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca"
-  integrity sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==
+  version "7.30.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.30.0.tgz#6d34ab51aaa56112fd97166226c9a97f505474f8"
+  integrity sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==
   dependencies:
     "@babel/code-frame" "7.12.11"
-    "@eslint/eslintrc" "^0.4.3"
+    "@eslint/eslintrc" "^0.4.2"
     "@humanwhocodes/config-array" "^0.5.0"
     ajv "^6.10.0"
     chalk "^4.0.0"
@@ -8557,13 +8522,20 @@
   dependencies:
     queue-microtask "^1.2.2"
 
-rxjs@^6.6.6, rxjs@^6.6.7:
+rxjs@^6.6.6:
   version "6.6.7"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
   integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
   dependencies:
     tslib "^1.9.0"
 
+rxjs@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.2.0.tgz#5cd12409639e9514a71c9f5f9192b2c4ae94de31"
+  integrity sha512-aX8w9OpKrQmiPKfT1bqETtUr9JygIz6GZ+gql8v7CijClsP0laoFUdKzxFAoWuRdSlOdU2+crss+cMf+cqMTnw==
+  dependencies:
+    tslib "~2.1.0"
+
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
@@ -9422,6 +9394,11 @@
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
+tslib@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
+  integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
+
 tslint@^6.1.3:
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904"