git.delta.rocks / unique-network / refs/commits / 282c701e6ebe

difftreelog

Merge pull request #462 from UniqueNetwork/fix/pallets_disabled

Yaroslav Bolyukin2022-08-11parents: #54cf093 #fcb85ee.patch.diff
in: master

98 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5291,6 +5291,7 @@
  "cumulus-primitives-timestamp",
  "cumulus-primitives-utility",
  "derivative",
+ "evm-coder",
  "fp-evm-mapping",
  "fp-rpc",
  "fp-self-contained",
@@ -5352,9 +5353,10 @@
  "sp-transaction-pool",
  "sp-version",
  "substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
  "up-data-structs",
  "up-rpc",
+ "up-sponsorship",
  "xcm",
  "xcm-builder",
  "xcm-executor",
@@ -8605,6 +8607,7 @@
  "cumulus-primitives-timestamp",
  "cumulus-primitives-utility",
  "derivative",
+ "evm-coder",
  "fp-evm-mapping",
  "fp-rpc",
  "fp-self-contained",
@@ -8666,9 +8669,10 @@
  "sp-transaction-pool",
  "sp-version",
  "substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
  "up-data-structs",
  "up-rpc",
+ "up-sponsorship",
  "xcm",
  "xcm-builder",
  "xcm-executor",
@@ -11881,6 +11885,7 @@
 name = "tests"
 version = "0.1.0"
 dependencies = [
+ "evm-coder",
  "fp-evm-mapping",
  "frame-support",
  "frame-system",
@@ -11902,8 +11907,8 @@
  "sp-io",
  "sp-runtime",
  "sp-std",
- "unique-runtime-common",
  "up-data-structs",
+ "up-sponsorship",
 ]
 
 [[package]]
@@ -12387,7 +12392,6 @@
  "sp-core",
  "sp-rpc",
  "sp-runtime",
- "unique-runtime-common",
  "up-data-structs",
  "up-rpc",
 ]
@@ -12541,7 +12545,7 @@
  "try-runtime-cli",
  "unique-rpc",
  "unique-runtime",
- "unique-runtime-common",
+ "up-common",
  "up-data-structs",
  "up-rpc",
 ]
@@ -12590,7 +12594,7 @@
  "substrate-frame-rpc-system",
  "tokio 0.2.25",
  "uc-rpc",
- "unique-runtime-common",
+ "up-common",
  "up-data-structs",
  "up-rpc",
 ]
@@ -12608,6 +12612,7 @@
  "cumulus-primitives-timestamp",
  "cumulus-primitives-utility",
  "derivative",
+ "evm-coder",
  "fp-evm-mapping",
  "fp-rpc",
  "fp-self-contained",
@@ -12669,41 +12674,16 @@
  "sp-transaction-pool",
  "sp-version",
  "substrate-wasm-builder",
- "unique-runtime-common",
+ "up-common",
  "up-data-structs",
  "up-rpc",
+ "up-sponsorship",
  "xcm",
  "xcm-builder",
  "xcm-executor",
 ]
 
 [[package]]
-name = "unique-runtime-common"
-version = "0.9.24"
-dependencies = [
- "evm-coder",
- "fp-rpc",
- "frame-support",
- "frame-system",
- "pallet-common",
- "pallet-evm",
- "pallet-fungible",
- "pallet-nonfungible",
- "pallet-refungible",
- "pallet-unique",
- "pallet-unique-scheduler",
- "parity-scale-codec 3.1.5",
- "rmrk-rpc",
- "scale-info",
- "sp-consensus-aura",
- "sp-core",
- "sp-runtime",
- "sp-std",
- "up-data-structs",
- "up-sponsorship",
-]
-
-[[package]]
 name = "universal-hash"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -12732,6 +12712,19 @@
 checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
 [[package]]
+name = "up-common"
+version = "0.9.24"
+dependencies = [
+ "fp-rpc",
+ "frame-support",
+ "pallet-evm",
+ "sp-consensus-aura",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
 name = "up-data-structs"
 version = "0.2.1"
 dependencies = [
modifiedclient/rpc/Cargo.tomldiffbeforeafterboth
--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -5,7 +5,6 @@
 edition = "2021"
 
 [dependencies]
-unique-runtime-common = { default-features = false, path = "../../runtime/common" }
 pallet-common = { default-features = false, path = '../../pallets/common' }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
 up-rpc = { path = "../../primitives/rpc" }
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -253,9 +253,8 @@
 ################################################################################
 # Local dependencies
 
-[dependencies.unique-runtime-common]
-default-features = false
-path = "../../runtime/common"
+[dependencies.up-common]
+path = "../../primitives/common"
 
 [dependencies.unique-runtime]
 path = '../../runtime/unique'
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -23,7 +23,7 @@
 use serde::{Deserialize, Serialize};
 use serde_json::map::Map;
 
-use unique_runtime_common::types::*;
+use up_common::types::opaque::*;
 
 #[cfg(feature = "unique-runtime")]
 pub use unique_runtime as default_runtime;
modifiednode/cli/src/command.rsdiffbeforeafterboth
--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -64,7 +64,7 @@
 use sp_runtime::traits::{AccountIdConversion, Block as BlockT};
 use std::{io::Write, net::SocketAddr, time::Duration};
 
-use unique_runtime_common::types::Block;
+use up_common::types::opaque::Block;
 
 macro_rules! no_runtime_err {
 	($chain_name:expr) => {
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -63,7 +63,7 @@
 use fc_rpc_core::types::FilterPool;
 use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};
 
-use unique_runtime_common::types::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
+use up_common::types::opaque::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
 
 // RMRK
 use up_data_structs::{
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -49,7 +49,7 @@
 fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 
 pallet-common = { default-features = false, path = "../../pallets/common" }
-unique-runtime-common = { default-features = false, path = "../../runtime/common" }
+up-common = { path = "../../primitives/common" }
 pallet-unique = { path = "../../pallets/unique" }
 uc-rpc = { path = "../../client/rpc" }
 up-rpc = { path = "../../primitives/rpc" }
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -40,9 +40,8 @@
 use sc_service::TransactionPool;
 use std::{collections::BTreeMap, sync::Arc};
 
-use unique_runtime_common::types::{
-	Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance,
-};
+use up_common::types::opaque::{Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance};
+
 // RMRK
 use up_data_structs::{
 	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
before · pallets/common/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63	ensure,64	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65	weights::Pays,66	transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70	COLLECTION_NUMBER_LIMIT,71	Collection,72	RpcCollection,73	CollectionId,74	CreateItemData,75	MAX_TOKEN_PREFIX_LENGTH,76	COLLECTION_ADMINS_LIMIT,77	TokenId,78	TokenChild,79	CollectionStats,80	MAX_TOKEN_OWNERSHIP,81	CollectionMode,82	NFT_SPONSOR_TRANSFER_TIMEOUT,83	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,84	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,85	MAX_SPONSOR_TIMEOUT,86	CUSTOM_DATA_LIMIT,87	CollectionLimits,88	CreateCollectionData,89	SponsorshipState,90	CreateItemExData,91	SponsoringRateLimit,92	budget::Budget,93	PhantomType,94	Property,95	Properties,96	PropertiesPermissionMap,97	PropertyKey,98	PropertyValue,99	PropertyPermission,100	PropertiesError,101	PropertyKeyPermission,102	TokenData,103	TrySetProperty,104	PropertyScope,105	// RMRK106	RmrkCollectionInfo,107	RmrkInstanceInfo,108	RmrkResourceInfo,109	RmrkPropertyInfo,110	RmrkBaseInfo,111	RmrkPartType,112	RmrkBoundedTheme,113	RmrkNftChild,114	CollectionPermissions,115	SchemaVersion,116};117118pub use pallet::*;119use sp_core::H160;120use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};121#[cfg(feature = "runtime-benchmarks")]122pub mod benchmarking;123pub mod dispatch;124pub mod erc;125pub mod eth;126pub mod weights;127128/// Weight info.129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]138pub struct CollectionHandle<T: Config> {139	/// Collection id140	pub id: CollectionId,141	collection: Collection<T::AccountId>,142	/// Substrate recorder for counting consumed gas143	pub recorder: SubstrateRecorder<T>,144}145146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {147	fn recorder(&self) -> &SubstrateRecorder<T> {148		&self.recorder149	}150	fn into_recorder(self) -> SubstrateRecorder<T> {151		self.recorder152	}153}154155impl<T: Config> CollectionHandle<T> {156	/// Same as [CollectionHandle::new] but with an explicit gas limit.157	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {158		<CollectionById<T>>::get(id).map(|collection| Self {159			id,160			collection,161			recorder: SubstrateRecorder::new(gas_limit),162		})163	}164165	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].166	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {167		<CollectionById<T>>::get(id).map(|collection| Self {168			id,169			collection,170			recorder,171		})172	}173174	/// Retrives collection data from storage and creates collection handle with default parameters.175	/// If collection not found return `None`176	pub fn new(id: CollectionId) -> Option<Self> {177		Self::new_with_gas_limit(id, u64::MAX)178	}179180	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.181	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {182		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)183	}184185	/// Consume gas for reading.186	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {187		self.recorder188			.consume_gas(T::GasWeightMapping::weight_to_gas(189				<T as frame_system::Config>::DbWeight::get()190					.read191					.saturating_mul(reads),192			))193	}194195	/// Consume gas for writing.196	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {197		self.recorder198			.consume_gas(T::GasWeightMapping::weight_to_gas(199				<T as frame_system::Config>::DbWeight::get()200					.write201					.saturating_mul(writes),202			))203	}204205	/// Save collection to storage.206	pub fn save(self) -> DispatchResult {207		<CollectionById<T>>::insert(self.id, self.collection);208		Ok(())209	}210211	/// Set collection sponsor.212	///213	/// Unique collections allows sponsoring for certain actions.214	/// This method allows you to set the sponsor of the collection.215	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].216	pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {217		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);218		Ok(())219	}220221	/// Confirm sponsorship222	///223	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.224	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].225	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {226		if self.collection.sponsorship.pending_sponsor() != Some(sender) {227			return Ok(false);228		}229230		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());231		Ok(true)232	}233234	/// Checks that the collection was created with, and must be operated upon through **Unique API**.235	/// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.236	pub fn check_is_internal(&self) -> DispatchResult {237		if self.external_collection {238			return Err(<Error<T>>::CollectionIsExternal)?;239		}240241		Ok(())242	}243244	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.245	/// Now check only the `external_collection` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.246	pub fn check_is_external(&self) -> DispatchResult {247		if !self.external_collection {248			return Err(<Error<T>>::CollectionIsInternal)?;249		}250251		Ok(())252	}253}254255impl<T: Config> Deref for CollectionHandle<T> {256	type Target = Collection<T::AccountId>;257258	fn deref(&self) -> &Self::Target {259		&self.collection260	}261}262263impl<T: Config> DerefMut for CollectionHandle<T> {264	fn deref_mut(&mut self) -> &mut Self::Target {265		&mut self.collection266	}267}268269impl<T: Config> CollectionHandle<T> {270	/// Checks if the `user` is the owner of the collection.271	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {272		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);273		Ok(())274	}275276	/// Returns **true** if the `user` is the owner or administrator of the collection.277	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {278		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))279	}280281	/// Checks if the `user` is the owner or administrator of the collection.282	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {283		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);284		Ok(())285	}286287	/// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.288	pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {289		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)290	}291292	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.293	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {294		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)295	}296297	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.298	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {299		ensure!(300			<Allowlist<T>>::get((self.id, user)),301			<Error<T>>::AddressNotInAllowlist302		);303		Ok(())304	}305}306307#[frame_support::pallet]308pub mod pallet {309	use super::*;310	use pallet_evm::account;311	use dispatch::CollectionDispatch;312	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};313	use frame_system::pallet_prelude::*;314	use frame_support::traits::Currency;315	use up_data_structs::{TokenId, mapping::TokenAddressMapping};316	use scale_info::TypeInfo;317	use weights::WeightInfo;318319	#[pallet::config]320	pub trait Config:321		frame_system::Config322		+ pallet_evm_coder_substrate::Config323		+ pallet_evm::Config324		+ TypeInfo325		+ account::Config326	{327		/// Weight information for functions of this pallet.328		type WeightInfo: WeightInfo;329330		/// Events compatible with [`frame_system::Config::Event`].331		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;332333		/// Handler of accounts and payment.334		type Currency: Currency<Self::AccountId>;335336		/// Set price to create a collection.337		#[pallet::constant]338		type CollectionCreationPrice: Get<339			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,340		>;341342		/// Dispatcher of operations on collections.343		type CollectionDispatch: CollectionDispatch<Self>;344345		/// Account which holds the chain's treasury.346		type TreasuryAccountId: Get<Self::AccountId>;347348		/// Address under which the CollectionHelper contract would be available.349		type ContractAddress: Get<H160>;350351		/// Mapper for token addresses to Ethereum addresses.352		type EvmTokenAddressMapping: TokenAddressMapping<H160>;353354		/// Mapper for token addresses to [`CrossAccountId`].355		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;356	}357358	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);359360	#[pallet::pallet]361	#[pallet::storage_version(STORAGE_VERSION)]362	#[pallet::generate_store(pub(super) trait Store)]363	pub struct Pallet<T>(_);364365	#[pallet::extra_constants]366	impl<T: Config> Pallet<T> {367		/// Maximum admins per collection.368		pub fn collection_admins_limit() -> u32 {369			COLLECTION_ADMINS_LIMIT370		}371	}372373	#[pallet::event]374	#[pallet::generate_deposit(pub fn deposit_event)]375	pub enum Event<T: Config> {376		/// New collection was created377		CollectionCreated(378			/// Globally unique identifier of newly created collection.379			CollectionId,380			/// [`CollectionMode`] converted into _u8_.381			u8,382			/// Collection owner.383			T::AccountId,384		),385386		/// New collection was destroyed387		CollectionDestroyed(388			/// Globally unique identifier of collection.389			CollectionId,390		),391392		/// New item was created.393		ItemCreated(394			/// Id of the collection where item was created.395			CollectionId,396			/// Id of an item. Unique within the collection.397			TokenId,398			/// Owner of newly created item399			T::CrossAccountId,400			/// Always 1 for NFT401			u128,402		),403404		/// Collection item was burned.405		ItemDestroyed(406			/// Id of the collection where item was destroyed.407			CollectionId,408			/// Identifier of burned NFT.409			TokenId,410			/// Which user has destroyed its tokens.411			T::CrossAccountId,412			/// Amount of token pieces destroed. Always 1 for NFT.413			u128,414		),415416		/// Item was transferred417		Transfer(418			/// Id of collection to which item is belong.419			CollectionId,420			/// Id of an item.421			TokenId,422			/// Original owner of item.423			T::CrossAccountId,424			/// New owner of item.425			T::CrossAccountId,426			/// Amount of token pieces transfered. Always 1 for NFT.427			u128,428		),429430		/// Amount pieces of token owned by `sender` was approved for `spender`.431		Approved(432			/// Id of collection to which item is belong.433			CollectionId,434			/// Id of an item.435			TokenId,436			/// Original owner of item.437			T::CrossAccountId,438			/// Id for which the approval was granted.439			T::CrossAccountId,440			/// Amount of token pieces transfered. Always 1 for NFT.441			u128,442		),443444		/// The colletion property has been added or edited.445		CollectionPropertySet(446			/// Id of collection to which property has been set.447			CollectionId,448			/// The property that was set.449			PropertyKey,450		),451452		/// The property has been deleted.453		CollectionPropertyDeleted(454			/// Id of collection to which property has been deleted.455			CollectionId,456			/// The property that was deleted.457			PropertyKey,458		),459460		/// The token property has been added or edited.461		TokenPropertySet(462			/// Identifier of the collection whose token has the property set.463			CollectionId,464			/// The token for which the property was set.465			TokenId,466			/// The property that was set.467			PropertyKey,468		),469470		/// The token property has been deleted.471		TokenPropertyDeleted(472			/// Identifier of the collection whose token has the property deleted.473			CollectionId,474			/// The token for which the property was deleted.475			TokenId,476			/// The property that was deleted.477			PropertyKey,478		),479480		/// The token property permission of a collection has been set.481		PropertyPermissionSet(482			/// ID of collection to which property permission has been set.483			CollectionId,484			/// The property permission that was set.485			PropertyKey,486		),487	}488489	#[pallet::error]490	pub enum Error<T> {491		/// This collection does not exist.492		CollectionNotFound,493		/// Sender parameter and item owner must be equal.494		MustBeTokenOwner,495		/// No permission to perform action496		NoPermission,497		/// Destroying only empty collections is allowed498		CantDestroyNotEmptyCollection,499		/// Collection is not in mint mode.500		PublicMintingNotAllowed,501		/// Address is not in allow list.502		AddressNotInAllowlist,503504		/// Collection name can not be longer than 63 char.505		CollectionNameLimitExceeded,506		/// Collection description can not be longer than 255 char.507		CollectionDescriptionLimitExceeded,508		/// Token prefix can not be longer than 15 char.509		CollectionTokenPrefixLimitExceeded,510		/// Total collections bound exceeded.511		TotalCollectionsLimitExceeded,512		/// Exceeded max admin count513		CollectionAdminCountExceeded,514		/// Collection limit bounds per collection exceeded515		CollectionLimitBoundsExceeded,516		/// Tried to enable permissions which are only permitted to be disabled517		OwnerPermissionsCantBeReverted,518		/// Collection settings not allowing items transferring519		TransferNotAllowed,520		/// Account token limit exceeded per collection521		AccountTokenLimitExceeded,522		/// Collection token limit exceeded523		CollectionTokenLimitExceeded,524		/// Metadata flag frozen525		MetadataFlagFrozen,526527		/// Item does not exist528		TokenNotFound,529		/// Item is balance not enough530		TokenValueTooLow,531		/// Requested value is more than the approved532		ApprovedValueTooLow,533		/// Tried to approve more than owned534		CantApproveMoreThanOwned,535536		/// Can't transfer tokens to ethereum zero address537		AddressIsZero,538		/// Target collection doesn't support this operation539		UnsupportedOperation,540541		/// Insufficient funds to perform an action542		NotSufficientFounds,543544		/// User does not satisfy the nesting rule545		UserIsNotAllowedToNest,546		/// Only tokens from specific collections may nest tokens under this one547		SourceCollectionIsNotAllowedToNest,548549		/// Tried to store more data than allowed in collection field550		CollectionFieldSizeExceeded,551552		/// Tried to store more property data than allowed553		NoSpaceForProperty,554555		/// Tried to store more property keys than allowed556		PropertyLimitReached,557558		/// Property key is too long559		PropertyKeyIsTooLong,560561		/// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed562		InvalidCharacterInPropertyKey,563564		/// Empty property keys are forbidden565		EmptyPropertyKey,566567		/// Tried to access an external collection with an internal API568		CollectionIsExternal,569570		/// Tried to access an internal collection with an external API571		CollectionIsInternal,572	}573574	/// Storage of the count of created collections. Essentially contains the last collection ID.575	#[pallet::storage]576	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;577578	/// Storage of the count of deleted collections.579	#[pallet::storage]580	pub type DestroyedCollectionCount<T> =581		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;582583	/// Storage of collection info.584	#[pallet::storage]585	pub type CollectionById<T> = StorageMap<586		Hasher = Blake2_128Concat,587		Key = CollectionId,588		Value = Collection<<T as frame_system::Config>::AccountId>,589		QueryKind = OptionQuery,590	>;591592	/// Storage of collection properties.593	#[pallet::storage]594	#[pallet::getter(fn collection_properties)]595	pub type CollectionProperties<T> = StorageMap<596		Hasher = Blake2_128Concat,597		Key = CollectionId,598		Value = Properties,599		QueryKind = ValueQuery,600		OnEmpty = up_data_structs::CollectionProperties,601	>;602603	/// Storage of token property permissions of a collection.604	#[pallet::storage]605	#[pallet::getter(fn property_permissions)]606	pub type CollectionPropertyPermissions<T> = StorageMap<607		Hasher = Blake2_128Concat,608		Key = CollectionId,609		Value = PropertiesPermissionMap,610		QueryKind = ValueQuery,611	>;612613	/// Storage of the amount of collection admins.614	#[pallet::storage]615	pub type AdminAmount<T> = StorageMap<616		Hasher = Blake2_128Concat,617		Key = CollectionId,618		Value = u32,619		QueryKind = ValueQuery,620	>;621622	/// List of collection admins.623	#[pallet::storage]624	pub type IsAdmin<T: Config> = StorageNMap<625		Key = (626			Key<Blake2_128Concat, CollectionId>,627			Key<Blake2_128Concat, T::CrossAccountId>,628		),629		Value = bool,630		QueryKind = ValueQuery,631	>;632633	/// Allowlisted collection users.634	#[pallet::storage]635	pub type Allowlist<T: Config> = StorageNMap<636		Key = (637			Key<Blake2_128Concat, CollectionId>,638			Key<Blake2_128Concat, T::CrossAccountId>,639		),640		Value = bool,641		QueryKind = ValueQuery,642	>;643644	/// Not used by code, exists only to provide some types to metadata.645	#[pallet::storage]646	pub type DummyStorageValue<T: Config> = StorageValue<647		Value = (648			CollectionStats,649			CollectionId,650			TokenId,651			TokenChild,652			PhantomType<(653				TokenData<T::CrossAccountId>,654				RpcCollection<T::AccountId>,655				// RMRK656				RmrkCollectionInfo<T::AccountId>,657				RmrkInstanceInfo<T::AccountId>,658				RmrkResourceInfo,659				RmrkPropertyInfo,660				RmrkBaseInfo<T::AccountId>,661				RmrkPartType,662				RmrkBoundedTheme,663				RmrkNftChild,664			)>,665		),666		QueryKind = OptionQuery,667	>;668669	#[pallet::hooks]670	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {671		fn on_runtime_upgrade() -> Weight {672			StorageVersion::new(1).put::<Pallet<T>>();673674			0675		}676	}677}678679impl<T: Config> Pallet<T> {680	/// Enshure that receiver address is correct.681	///682	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.683	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {684		ensure!(685			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,686			<Error<T>>::AddressIsZero687		);688		Ok(())689	}690691	/// Get a vector of collection admins.692	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {693		<IsAdmin<T>>::iter_prefix((collection,))694			.map(|(a, _)| a)695			.collect()696	}697698	/// Get a vector of users allowed to mint tokens.699	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {700		<Allowlist<T>>::iter_prefix((collection,))701			.map(|(a, _)| a)702			.collect()703	}704705	/// Is `user` allowed to mint token in `collection`.706	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {707		<Allowlist<T>>::get((collection, user))708	}709710	/// Get statistics of collections.711	pub fn collection_stats() -> CollectionStats {712		let created = <CreatedCollectionCount<T>>::get();713		let destroyed = <DestroyedCollectionCount<T>>::get();714		CollectionStats {715			created: created.0,716			destroyed: destroyed.0,717			alive: created.0 - destroyed.0,718		}719	}720721	/// Get the effective limits for the collection.722	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {723		let collection = <CollectionById<T>>::get(collection);724		if collection.is_none() {725			return None;726		}727728		let collection = collection.unwrap();729		let limits = collection.limits;730		let effective_limits = CollectionLimits {731			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),732			sponsored_data_size: Some(limits.sponsored_data_size()),733			sponsored_data_rate_limit: Some(734				limits735					.sponsored_data_rate_limit736					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),737			),738			token_limit: Some(limits.token_limit()),739			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(740				match collection.mode {741					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,742					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,743					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,744				},745			)),746			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),747			owner_can_transfer: Some(limits.owner_can_transfer()),748			owner_can_destroy: Some(limits.owner_can_destroy()),749			transfers_enabled: Some(limits.transfers_enabled()),750		};751752		Some(effective_limits)753	}754755	/// Returns information about the `collection` adapted for rpc.756	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {757		let Collection {758			name,759			description,760			owner,761			mode,762			token_prefix,763			sponsorship,764			limits,765			permissions,766			external_collection,767		} = <CollectionById<T>>::get(collection)?;768769		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)770			.into_iter()771			.map(|(key, permission)| PropertyKeyPermission { key, permission })772			.collect();773774		let properties = <CollectionProperties<T>>::get(collection)775			.into_iter()776			.map(|(key, value)| Property { key, value })777			.collect();778779		let permissions = CollectionPermissions {780			access: Some(permissions.access()),781			mint_mode: Some(permissions.mint_mode()),782			nesting: Some(permissions.nesting().clone()),783		};784785		Some(RpcCollection {786			name: name.into_inner(),787			description: description.into_inner(),788			owner,789			mode,790			token_prefix: token_prefix.into_inner(),791			sponsorship,792			limits,793			permissions,794			token_property_permissions,795			properties,796			read_only: external_collection,797		})798	}799}800801macro_rules! limit_default {802	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{803		$(804			if let Some($new) = $new.$field {805				let $old = $old.$field($($arg)?);806				let _ = $new;807				let _ = $old;808				$check809			} else {810				$new.$field = $old.$field811			}812		)*813	}};814}815macro_rules! limit_default_clone {816	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{817		$(818			if let Some($new) = $new.$field.clone() {819				let $old = $old.$field($($arg)?);820				let _ = $new;821				let _ = $old;822				$check823			} else {824				$new.$field = $old.$field.clone()825			}826		)*827	}};828}829830impl<T: Config> Pallet<T> {831	/// Create new collection.832	///833	/// * `owner` - The owner of the collection.834	/// * `data` - Description of the created collection.835	/// * `is_external` - Marks that collection managet by not "Unique network".836	pub fn init_collection(837		owner: T::CrossAccountId,838		data: CreateCollectionData<T::AccountId>,839		is_external: bool,840	) -> Result<CollectionId, DispatchError> {841		{842			ensure!(843				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,844				Error::<T>::CollectionTokenPrefixLimitExceeded845			);846		}847848		let created_count = <CreatedCollectionCount<T>>::get()849			.0850			.checked_add(1)851			.ok_or(ArithmeticError::Overflow)?;852		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;853		let id = CollectionId(created_count);854855		// bound Total number of collections856		ensure!(857			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,858			<Error<T>>::TotalCollectionsLimitExceeded859		);860861		// =========862863		let collection = Collection {864			owner: owner.as_sub().clone(),865			name: data.name,866			mode: data.mode.clone(),867			description: data.description,868			token_prefix: data.token_prefix,869			sponsorship: data870				.pending_sponsor871				.map(SponsorshipState::Unconfirmed)872				.unwrap_or_default(),873			limits: data874				.limits875				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))876				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,877			permissions: data878				.permissions879				.map(|permissions| {880					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)881				})882				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,883			external_collection: is_external,884		};885886		let mut collection_properties = up_data_structs::CollectionProperties::get();887		collection_properties888			.try_set_from_iter(data.properties.into_iter())889			.map_err(<Error<T>>::from)?;890891		CollectionProperties::<T>::insert(id, collection_properties);892893		let mut token_props_permissions = PropertiesPermissionMap::new();894		token_props_permissions895			.try_set_from_iter(data.token_property_permissions.into_iter())896			.map_err(<Error<T>>::from)?;897898		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);899900		// Take a (non-refundable) deposit of collection creation901		{902			let mut imbalance =903				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();904			imbalance.subsume(905				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(906					&T::TreasuryAccountId::get(),907					T::CollectionCreationPrice::get(),908				),909			);910			<T as Config>::Currency::settle(911				owner.as_sub(),912				imbalance,913				WithdrawReasons::TRANSFER,914				ExistenceRequirement::KeepAlive,915			)916			.map_err(|_| Error::<T>::NotSufficientFounds)?;917		}918919		<CreatedCollectionCount<T>>::put(created_count);920		<Pallet<T>>::deposit_event(Event::CollectionCreated(921			id,922			data.mode.id(),923			owner.as_sub().clone(),924		));925		<PalletEvm<T>>::deposit_log(926			erc::CollectionHelpersEvents::CollectionCreated {927				owner: *owner.as_eth(),928				collection_id: eth::collection_id_to_address(id),929			}930			.to_log(T::ContractAddress::get()),931		);932		<CollectionById<T>>::insert(id, collection);933		Ok(id)934	}935936	/// Destroy collection.937	///938	/// * `collection` - Collection handler.939	/// * `sender` - The owner or administrator of the collection.940	pub fn destroy_collection(941		collection: CollectionHandle<T>,942		sender: &T::CrossAccountId,943	) -> DispatchResult {944		ensure!(945			collection.limits.owner_can_destroy(),946			<Error<T>>::NoPermission,947		);948		collection.check_is_owner(sender)?;949950		let destroyed_collections = <DestroyedCollectionCount<T>>::get()951			.0952			.checked_add(1)953			.ok_or(ArithmeticError::Overflow)?;954955		// =========956957		<DestroyedCollectionCount<T>>::put(destroyed_collections);958		<CollectionById<T>>::remove(collection.id);959		<AdminAmount<T>>::remove(collection.id);960		<IsAdmin<T>>::remove_prefix((collection.id,), None);961		<Allowlist<T>>::remove_prefix((collection.id,), None);962		<CollectionProperties<T>>::remove(collection.id);963964		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));965		Ok(())966	}967968	/// Set collection property.969	///970	/// * `collection` - Collection handler.971	/// * `sender` - The owner or administrator of the collection.972	/// * `property` - The property to set.973	pub fn set_collection_property(974		collection: &CollectionHandle<T>,975		sender: &T::CrossAccountId,976		property: Property,977	) -> DispatchResult {978		collection.check_is_owner_or_admin(sender)?;979980		CollectionProperties::<T>::try_mutate(collection.id, |properties| {981			let property = property.clone();982			properties.try_set(property.key, property.value)983		})984		.map_err(<Error<T>>::from)?;985986		Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));987988		Ok(())989	}990991	/// Set scouped collection property.992	///993	/// * `collection_id` - ID of the collection for which the property is being set.994	/// * `scope` - Property scope.995	/// * `property` - The property to set.996	pub fn set_scoped_collection_property(997		collection_id: CollectionId,998		scope: PropertyScope,999		property: Property,1000	) -> DispatchResult {1001		CollectionProperties::<T>::try_mutate(collection_id, |properties| {1002			properties.try_scoped_set(scope, property.key, property.value)1003		})1004		.map_err(<Error<T>>::from)?;10051006		Ok(())1007	}10081009	/// Set scouped collection properties.1010	///1011	/// * `collection_id` - ID of the collection for which the properties is being set.1012	/// * `scope` - Property scope.1013	/// * `properties` - The properties to set.1014	pub fn set_scoped_collection_properties(1015		collection_id: CollectionId,1016		scope: PropertyScope,1017		properties: impl Iterator<Item = Property>,1018	) -> DispatchResult {1019		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1020			stored_properties.try_scoped_set_from_iter(scope, properties)1021		})1022		.map_err(<Error<T>>::from)?;10231024		Ok(())1025	}10261027	/// Set collection properties.1028	///1029	/// * `collection` - Collection handler.1030	/// * `sender` - The owner or administrator of the collection.1031	/// * `properties` - The properties to set.1032	#[transactional]1033	pub fn set_collection_properties(1034		collection: &CollectionHandle<T>,1035		sender: &T::CrossAccountId,1036		properties: Vec<Property>,1037	) -> DispatchResult {1038		for property in properties {1039			Self::set_collection_property(collection, sender, property)?;1040		}10411042		Ok(())1043	}10441045	/// Delete collection property.1046	///1047	/// * `collection` - Collection handler.1048	/// * `sender` - The owner or administrator of the collection.1049	/// * `property` - The property to delete.1050	pub fn delete_collection_property(1051		collection: &CollectionHandle<T>,1052		sender: &T::CrossAccountId,1053		property_key: PropertyKey,1054	) -> DispatchResult {1055		collection.check_is_owner_or_admin(sender)?;10561057		CollectionProperties::<T>::try_mutate(collection.id, |properties| {1058			properties.remove(&property_key)1059		})1060		.map_err(<Error<T>>::from)?;10611062		Self::deposit_event(Event::CollectionPropertyDeleted(1063			collection.id,1064			property_key,1065		));10661067		Ok(())1068	}10691070	/// Delete collection properties.1071	///1072	/// * `collection` - Collection handler.1073	/// * `sender` - The owner or administrator of the collection.1074	/// * `properties` - The properties to delete.1075	#[transactional]1076	pub fn delete_collection_properties(1077		collection: &CollectionHandle<T>,1078		sender: &T::CrossAccountId,1079		property_keys: Vec<PropertyKey>,1080	) -> DispatchResult {1081		for key in property_keys {1082			Self::delete_collection_property(collection, sender, key)?;1083		}10841085		Ok(())1086	}10871088	/// Set collection propetry permission without any checks.1089	///1090	/// Used for migrations.1091	///1092	/// * `collection` - Collection handler.1093	/// * `property_permissions` - Property permissions.1094	pub fn set_property_permission_unchecked(1095		collection: CollectionId,1096		property_permission: PropertyKeyPermission,1097	) -> DispatchResult {1098		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1099			permissions.try_set(property_permission.key, property_permission.permission)1100		})1101		.map_err(<Error<T>>::from)?;1102		Ok(())1103	}11041105	/// Set collection property permission.1106	///1107	/// * `collection` - Collection handler.1108	/// * `sender` - The owner or administrator of the collection.1109	/// * `property_permission` - Property permission.1110	pub fn set_property_permission(1111		collection: &CollectionHandle<T>,1112		sender: &T::CrossAccountId,1113		property_permission: PropertyKeyPermission,1114	) -> DispatchResult {1115		collection.check_is_owner_or_admin(sender)?;11161117		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1118		let current_permission = all_permissions.get(&property_permission.key);1119		if matches![1120			current_permission,1121			Some(PropertyPermission { mutable: false, .. })1122		] {1123			return Err(<Error<T>>::NoPermission.into());1124		}11251126		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1127			let property_permission = property_permission.clone();1128			permissions.try_set(property_permission.key, property_permission.permission)1129		})1130		.map_err(<Error<T>>::from)?;11311132		Self::deposit_event(Event::PropertyPermissionSet(1133			collection.id,1134			property_permission.key,1135		));11361137		Ok(())1138	}11391140	/// Set token property permission.1141	///1142	/// * `collection` - Collection handler.1143	/// * `sender` - The owner or administrator of the collection.1144	/// * `property_permissions` - Property permissions.1145	#[transactional]1146	pub fn set_token_property_permissions(1147		collection: &CollectionHandle<T>,1148		sender: &T::CrossAccountId,1149		property_permissions: Vec<PropertyKeyPermission>,1150	) -> DispatchResult {1151		for prop_pemission in property_permissions {1152			Self::set_property_permission(collection, sender, prop_pemission)?;1153		}11541155		Ok(())1156	}11571158	/// Get collection property.1159	pub fn get_collection_property(1160		collection_id: CollectionId,1161		key: &PropertyKey,1162	) -> Option<PropertyValue> {1163		Self::collection_properties(collection_id).get(key).cloned()1164	}11651166	/// Convert byte vector to property key vector.1167	pub fn bytes_keys_to_property_keys(1168		keys: Vec<Vec<u8>>,1169	) -> Result<Vec<PropertyKey>, DispatchError> {1170		keys.into_iter()1171			.map(|key| -> Result<PropertyKey, DispatchError> {1172				key.try_into()1173					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1174			})1175			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1176	}11771178	/// Get properties according to given keys.1179	pub fn filter_collection_properties(1180		collection_id: CollectionId,1181		keys: Option<Vec<PropertyKey>>,1182	) -> Result<Vec<Property>, DispatchError> {1183		let properties = Self::collection_properties(collection_id);11841185		let properties = keys1186			.map(|keys| {1187				keys.into_iter()1188					.filter_map(|key| {1189						properties.get(&key).map(|value| Property {1190							key,1191							value: value.clone(),1192						})1193					})1194					.collect()1195			})1196			.unwrap_or_else(|| {1197				properties1198					.into_iter()1199					.map(|(key, value)| Property { key, value })1200					.collect()1201			});12021203		Ok(properties)1204	}12051206	/// Get property permissions according to given keys.1207	pub fn filter_property_permissions(1208		collection_id: CollectionId,1209		keys: Option<Vec<PropertyKey>>,1210	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1211		let permissions = Self::property_permissions(collection_id);12121213		let key_permissions = keys1214			.map(|keys| {1215				keys.into_iter()1216					.filter_map(|key| {1217						permissions1218							.get(&key)1219							.map(|permission| PropertyKeyPermission {1220								key,1221								permission: permission.clone(),1222							})1223					})1224					.collect()1225			})1226			.unwrap_or_else(|| {1227				permissions1228					.into_iter()1229					.map(|(key, permission)| PropertyKeyPermission { key, permission })1230					.collect()1231			});12321233		Ok(key_permissions)1234	}12351236	/// Toggle `user` participation in the `collection`'s allow list.1237	pub fn toggle_allowlist(1238		collection: &CollectionHandle<T>,1239		sender: &T::CrossAccountId,1240		user: &T::CrossAccountId,1241		allowed: bool,1242	) -> DispatchResult {1243		collection.check_is_owner_or_admin(sender)?;12441245		// =========12461247		if allowed {1248			<Allowlist<T>>::insert((collection.id, user), true);1249		} else {1250			<Allowlist<T>>::remove((collection.id, user));1251		}12521253		Ok(())1254	}12551256	/// Toggle `user` participation in the `collection`'s admin list.1257	pub fn toggle_admin(1258		collection: &CollectionHandle<T>,1259		sender: &T::CrossAccountId,1260		user: &T::CrossAccountId,1261		admin: bool,1262	) -> DispatchResult {1263		collection.check_is_owner(sender)?;12641265		let was_admin = <IsAdmin<T>>::get((collection.id, user));1266		if was_admin == admin {1267			return Ok(());1268		}1269		let amount = <AdminAmount<T>>::get(collection.id);12701271		if admin {1272			let amount = amount1273				.checked_add(1)1274				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1275			ensure!(1276				amount <= Self::collection_admins_limit(),1277				<Error<T>>::CollectionAdminCountExceeded,1278			);12791280			// =========12811282			<AdminAmount<T>>::insert(collection.id, amount);1283			<IsAdmin<T>>::insert((collection.id, user), true);1284		} else {1285			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1286			<IsAdmin<T>>::remove((collection.id, user));1287		}12881289		Ok(())1290	}12911292	/// Merge set fields from `new_limit` to `old_limit`.1293	pub fn clamp_limits(1294		mode: CollectionMode,1295		old_limit: &CollectionLimits,1296		mut new_limit: CollectionLimits,1297	) -> Result<CollectionLimits, DispatchError> {1298		let limits = old_limit;1299		limit_default!(old_limit, new_limit,1300			account_token_ownership_limit => ensure!(1301				new_limit <= MAX_TOKEN_OWNERSHIP,1302				<Error<T>>::CollectionLimitBoundsExceeded,1303			),1304			sponsored_data_size => ensure!(1305				new_limit <= CUSTOM_DATA_LIMIT,1306				<Error<T>>::CollectionLimitBoundsExceeded,1307			),13081309			sponsored_data_rate_limit => {},1310			token_limit => ensure!(1311				old_limit >= new_limit && new_limit > 0,1312				<Error<T>>::CollectionTokenLimitExceeded1313			),13141315			sponsor_transfer_timeout(match mode {1316				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1317				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1318				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1319			}) => ensure!(1320				new_limit <= MAX_SPONSOR_TIMEOUT,1321				<Error<T>>::CollectionLimitBoundsExceeded,1322			),1323			sponsor_approve_timeout => {},1324			owner_can_transfer => ensure!(1325				!limits.owner_can_transfer_instaled() ||1326				old_limit || !new_limit,1327				<Error<T>>::OwnerPermissionsCantBeReverted,1328			),1329			owner_can_destroy => ensure!(1330				old_limit || !new_limit,1331				<Error<T>>::OwnerPermissionsCantBeReverted,1332			),1333			transfers_enabled => {},1334		);1335		Ok(new_limit)1336	}13371338	/// Merge set fields from `new_permission` to `old_permission`.1339	pub fn clamp_permissions(1340		_mode: CollectionMode,1341		old_permission: &CollectionPermissions,1342		mut new_permission: CollectionPermissions,1343	) -> Result<CollectionPermissions, DispatchError> {1344		limit_default_clone!(old_permission, new_permission,1345			access => {},1346			mint_mode => {},1347			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1348		);1349		Ok(new_permission)1350	}1351}13521353/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1354#[macro_export]1355macro_rules! unsupported {1356	() => {1357		Err(<Error<T>>::UnsupportedOperation.into())1358	};1359}13601361/// Return weights for various worst-case operations.1362pub trait CommonWeightInfo<CrossAccountId> {1363	/// Weight of item creation.1364	fn create_item() -> Weight;13651366	/// Weight of items creation.1367	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;13681369	/// Weight of items creation.1370	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;13711372	/// The weight of the burning item.1373	fn burn_item() -> Weight;13741375	/// Property setting weight.1376	///1377	/// * `amount`- The number of properties to set.1378	fn set_collection_properties(amount: u32) -> Weight;13791380	/// Collection property deletion weight.1381	///1382	/// * `amount`- The number of properties to set.1383	fn delete_collection_properties(amount: u32) -> Weight;13841385	/// Token property setting weight.1386	///1387	/// * `amount`- The number of properties to set.1388	fn set_token_properties(amount: u32) -> Weight;13891390	/// Token property deletion weight.1391	///1392	/// * `amount`- The number of properties to delete.1393	fn delete_token_properties(amount: u32) -> Weight;13941395	/// Token property permissions set weight.1396	///1397	/// * `amount`- The number of property permissions to set.1398	fn set_token_property_permissions(amount: u32) -> Weight;13991400	/// Transfer price of the token or its parts.1401	fn transfer() -> Weight;14021403	/// The price of setting the permission of the operation from another user.1404	fn approve() -> Weight;14051406	/// Transfer price from another user.1407	fn transfer_from() -> Weight;14081409	/// The price of burning a token from another user.1410	fn burn_from() -> Weight;14111412	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1413	/// whole users's balance.1414	///1415	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1416	fn burn_recursively_self_raw() -> Weight;14171418	/// Cost of iterating over `amount` children while burning, without counting child burning itself.1419	///1420	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1421	fn burn_recursively_breadth_raw(amount: u32) -> Weight;14221423	/// The price of recursive burning a token.1424	///1425	/// `max_selfs` - The maximum burning weight of the token itself.1426	/// `max_breadth` - The maximum number of nested tokens to burn.1427	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1428		Self::burn_recursively_self_raw()1429			.saturating_mul(max_selfs.max(1) as u64)1430			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1431	}1432}14331434/// Weight info extension trait for refungible pallet.1435pub trait RefungibleExtensionsWeightInfo {1436	/// Weight of token repartition.1437	fn repartition() -> Weight;1438}14391440/// Common collection operations.1441///1442/// It wraps methods in Fungible, Nonfungible and Refungible pallets1443/// and adds weight info.1444pub trait CommonCollectionOperations<T: Config> {1445	/// Create token.1446	///1447	/// * `sender` - The user who mint the token and pays for the transaction.1448	/// * `to` - The user who will own the token.1449	/// * `data` - Token data.1450	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1451	fn create_item(1452		&self,1453		sender: T::CrossAccountId,1454		to: T::CrossAccountId,1455		data: CreateItemData,1456		nesting_budget: &dyn Budget,1457	) -> DispatchResultWithPostInfo;14581459	/// Create multiple tokens.1460	///1461	/// * `sender` - The user who mint the token and pays for the transaction.1462	/// * `to` - The user who will own the token.1463	/// * `data` - Token data.1464	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1465	fn create_multiple_items(1466		&self,1467		sender: T::CrossAccountId,1468		to: T::CrossAccountId,1469		data: Vec<CreateItemData>,1470		nesting_budget: &dyn Budget,1471	) -> DispatchResultWithPostInfo;14721473	/// Create multiple tokens.1474	///1475	/// * `sender` - The user who mint the token and pays for the transaction.1476	/// * `to` - The user who will own the token.1477	/// * `data` - Token data.1478	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1479	fn create_multiple_items_ex(1480		&self,1481		sender: T::CrossAccountId,1482		data: CreateItemExData<T::CrossAccountId>,1483		nesting_budget: &dyn Budget,1484	) -> DispatchResultWithPostInfo;14851486	/// Burn token.1487	///1488	/// * `sender` - The user who owns the token.1489	/// * `token` - Token id that will burned.1490	/// * `amount` - The number of parts of the token that will be burned.1491	fn burn_item(1492		&self,1493		sender: T::CrossAccountId,1494		token: TokenId,1495		amount: u128,1496	) -> DispatchResultWithPostInfo;14971498	/// Burn token and all nested tokens recursievly.1499	///1500	/// * `sender` - The user who owns the token.1501	/// * `token` - Token id that will burned.1502	/// * `self_budget` - The budget that can be spent on burning tokens.1503	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.1504	fn burn_item_recursively(1505		&self,1506		sender: T::CrossAccountId,1507		token: TokenId,1508		self_budget: &dyn Budget,1509		breadth_budget: &dyn Budget,1510	) -> DispatchResultWithPostInfo;15111512	/// Set collection properties.1513	///1514	/// * `sender` - Must be either the owner of the collection or its admin.1515	/// * `properties` - Properties to be set.1516	fn set_collection_properties(1517		&self,1518		sender: T::CrossAccountId,1519		properties: Vec<Property>,1520	) -> DispatchResultWithPostInfo;15211522	/// Delete collection properties.1523	///1524	/// * `sender` - Must be either the owner of the collection or its admin.1525	/// * `properties` - The properties to be removed.1526	fn delete_collection_properties(1527		&self,1528		sender: &T::CrossAccountId,1529		property_keys: Vec<PropertyKey>,1530	) -> DispatchResultWithPostInfo;15311532	/// Set token properties.1533	///1534	/// The appropriate [`PropertyPermission`] for the token property1535	/// must be set with [`Self::set_token_property_permissions`].1536	///1537	/// * `sender` - Must be either the owner of the token or its admin.1538	/// * `token_id` - The token for which the properties are being set.1539	/// * `properties` - Properties to be set.1540	/// * `budget` - Budget for setting properties.1541	fn set_token_properties(1542		&self,1543		sender: T::CrossAccountId,1544		token_id: TokenId,1545		properties: Vec<Property>,1546		budget: &dyn Budget,1547	) -> DispatchResultWithPostInfo;15481549	/// Remove token properties.1550	///1551	/// The appropriate [`PropertyPermission`] for the token property1552	/// must be set with [`Self::set_token_property_permissions`].1553	///1554	/// * `sender` - Must be either the owner of the token or its admin.1555	/// * `token_id` - The token for which the properties are being remove.1556	/// * `property_keys` - Keys to remove corresponding properties.1557	/// * `budget` - Budget for removing properties.1558	fn delete_token_properties(1559		&self,1560		sender: T::CrossAccountId,1561		token_id: TokenId,1562		property_keys: Vec<PropertyKey>,1563		budget: &dyn Budget,1564	) -> DispatchResultWithPostInfo;15651566	/// Set token property permissions.1567	///1568	/// * `sender` - Must be either the owner of the token or its admin.1569	/// * `token_id` - The token for which the properties are being set.1570	/// * `properties` - Properties to be set.1571	/// * `budget` - Budget for setting properties.1572	fn set_token_property_permissions(1573		&self,1574		sender: &T::CrossAccountId,1575		property_permissions: Vec<PropertyKeyPermission>,1576	) -> DispatchResultWithPostInfo;15771578	/// Transfer amount of token pieces.1579	///1580	/// * `sender` - Donor user.1581	/// * `to` - Recepient user.1582	/// * `token` - The token of which parts are being sent.1583	/// * `amount` - The number of parts of the token that will be transferred.1584	/// * `budget` - The maximum budget that can be spent on the transfer.1585	fn transfer(1586		&self,1587		sender: T::CrossAccountId,1588		to: T::CrossAccountId,1589		token: TokenId,1590		amount: u128,1591		budget: &dyn Budget,1592	) -> DispatchResultWithPostInfo;15931594	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].1595	///1596	/// * `sender` - The user who grants access to the token.1597	/// * `spender` - The user to whom the rights are granted.1598	/// * `token` - The token to which access is granted.1599	/// * `amount` - The amount of pieces that another user can dispose of.1600	fn approve(1601		&self,1602		sender: T::CrossAccountId,1603		spender: T::CrossAccountId,1604		token: TokenId,1605		amount: u128,1606	) -> DispatchResultWithPostInfo;16071608	/// Send parts of a token owned by another user.1609	///1610	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1611	///1612	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).1613	/// * `from` - The user who owns the token.1614	/// * `to` - Recepient user.1615	/// * `token` - The token of which parts are being sent.1616	/// * `amount` - The number of parts of the token that will be transferred.1617	/// * `budget` - The maximum budget that can be spent on the transfer.1618	fn transfer_from(1619		&self,1620		sender: T::CrossAccountId,1621		from: T::CrossAccountId,1622		to: T::CrossAccountId,1623		token: TokenId,1624		amount: u128,1625		budget: &dyn Budget,1626	) -> DispatchResultWithPostInfo;16271628	/// Burn parts of a token owned by another user.1629	///1630	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1631	///1632	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).1633	/// * `from` - The user who owns the token.1634	/// * `token` - The token of which parts are being sent.1635	/// * `amount` - The number of parts of the token that will be transferred.1636	/// * `budget` - The maximum budget that can be spent on the burn.1637	fn burn_from(1638		&self,1639		sender: T::CrossAccountId,1640		from: T::CrossAccountId,1641		token: TokenId,1642		amount: u128,1643		budget: &dyn Budget,1644	) -> DispatchResultWithPostInfo;16451646	/// Check permission to nest token.1647	///1648	/// * `sender` - The user who initiated the check.1649	/// * `from` - The token that is checked for embedding.1650	/// * `under` - Token under which to check.1651	/// * `budget` - The maximum budget that can be spent on the check.1652	fn check_nesting(1653		&self,1654		sender: T::CrossAccountId,1655		from: (CollectionId, TokenId),1656		under: TokenId,1657		budget: &dyn Budget,1658	) -> DispatchResult;16591660	/// Nest one token into another.1661	///1662	/// * `under` - Token holder.1663	/// * `to_nest` - Nested token.1664	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16651666	/// Unnest token.1667	///1668	/// * `under` - Token holder.1669	/// * `to_nest` - Token to unnest.1670	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));16711672	/// Get all user tokens.1673	///1674	/// * `account` - Account for which you need to get tokens.1675	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;16761677	/// Get all the tokens in the collection.1678	fn collection_tokens(&self) -> Vec<TokenId>;16791680	/// Check if the token exists.1681	///1682	/// * `token` - Id token to check.1683	fn token_exists(&self, token: TokenId) -> bool;16841685	/// Get the id of the last minted token.1686	fn last_token_id(&self) -> TokenId;16871688	/// Get the owner of the token.1689	///1690	/// * `token` - The token for which you need to find out the owner.1691	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;16921693	/// Returns 10 tokens owners in no particular order.1694	///1695	/// * `token` - The token for which you need to find out the owners.1696	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;16971698	/// Get the value of the token property by key.1699	///1700	/// * `token` - Token with the property to get.1701	/// * `key` - Property name.1702	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;17031704	/// Get a set of token properties by key vector.1705	///1706	/// * `token` - Token with the property to get.1707	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),1708	/// then all properties are returned.1709	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;17101711	/// Amount of unique collection tokens1712	fn total_supply(&self) -> u32;17131714	/// Amount of different tokens account has.1715	///1716	/// * `account` - The account for which need to get the balance.1717	fn account_balance(&self, account: T::CrossAccountId) -> u32;17181719	/// Amount of specific token account have.1720	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;17211722	/// Amount of token pieces1723	fn total_pieces(&self, token: TokenId) -> Option<u128>;17241725	/// Get the number of parts of the token that a trusted user can manage.1726	///1727	/// * `sender` - Trusted user.1728	/// * `spender` - Owner of the token.1729	/// * `token` - The token for which to get the value.1730	fn allowance(1731		&self,1732		sender: T::CrossAccountId,1733		spender: T::CrossAccountId,1734		token: TokenId,1735	) -> u128;17361737	/// Get extension for RFT collection.1738	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1739}17401741/// Extension for RFT collection.1742pub trait RefungibleExtensions<T>1743where1744	T: Config,1745{1746	/// Change the number of parts of the token.1747	///1748	/// When the value changes down, this function is equivalent to burning parts of the token.1749	///1750	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.1751	/// * `token` - The token for which you want to change the number of parts.1752	/// * `amount` - The new value of the parts of the token.1753	fn repartition(1754		&self,1755		sender: &T::CrossAccountId,1756		token: TokenId,1757		amount: u128,1758	) -> DispatchResultWithPostInfo;1759}17601761/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].1762///1763/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.1764pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1765	let post_info = PostDispatchInfo {1766		actual_weight: Some(weight),1767		pays_fee: Pays::Yes,1768	};1769	match res {1770		Ok(()) => Ok(post_info),1771		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1772	}1773}17741775impl<T: Config> From<PropertiesError> for Error<T> {1776	fn from(error: PropertiesError) -> Self {1777		match error {1778			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1779			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1780			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1781			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1782			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1783		}1784	}1785}
addedprimitives/common/Cargo.tomldiffbeforeafterboth
--- /dev/null
+++ b/primitives/common/Cargo.toml
@@ -0,0 +1,56 @@
+[package]
+authors = ['Unique Network <support@uniquenetwork.io>']
+description = 'Unique Runtime Common Primitives'
+edition = '2021'
+homepage = 'https://unique.network'
+license = 'All Rights Reserved'
+name = 'up-common'
+repository = 'https://github.com/UniqueNetwork/unique-chain'
+version = '0.9.24'
+
+[features]
+default = ['std']
+std = [
+    'sp-std/std',
+    'frame-support/std',
+    'sp-runtime/std',
+    'sp-core/std',
+    'sp-consensus-aura/std',
+    'fp-rpc/std',
+    'pallet-evm/std',
+]
+
+[dependencies.sp-std]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.frame-support]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-runtime]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-core]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.sp-consensus-aura]
+default-features = false
+git = "https://github.com/paritytech/substrate"
+branch = "polkadot-v0.9.24"
+
+[dependencies.fp-rpc]
+default-features = false
+git = "https://github.com/uniquenetwork/frontier"
+branch = "unique-polkadot-v0.9.24"
+
+[dependencies.pallet-evm]
+default-features = false
+git = "https://github.com/uniquenetwork/frontier"
+branch = "unique-polkadot-v0.9.24"
addedprimitives/common/src/constants.rsdiffbeforeafterboth
--- /dev/null
+++ b/primitives/common/src/constants.rs
@@ -0,0 +1,55 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::Perbill;
+use frame_support::{
+	parameter_types,
+	weights::{Weight, constants::WEIGHT_PER_SECOND},
+};
+use crate::types::{BlockNumber, Balance};
+
+pub const MILLISECS_PER_BLOCK: u64 = 12000;
+
+pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
+
+// These time units are defined in number of blocks.
+pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
+pub const HOURS: BlockNumber = MINUTES * 60;
+pub const DAYS: BlockNumber = HOURS * 24;
+
+pub const MICROUNIQUE: Balance = 1_000_000_000_000;
+pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
+pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
+pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
+
+// Targeting 0.1 UNQ per transfer
+pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
+
+// Targeting 0.15 UNQ per transfer via ETH
+pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
+
+/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
+/// This is used to limit the maximal weight of a single extrinsic.
+pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
+/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
+/// by  Operational  extrinsics.
+pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
+/// We allow for 2 seconds of compute with a 6 second average block time.
+pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
+
+parameter_types! {
+	pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
+}
addedprimitives/common/src/lib.rsdiffbeforeafterboth
--- /dev/null
+++ b/primitives/common/src/lib.rs
@@ -0,0 +1,20 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+pub mod constants;
+pub mod types;
addedprimitives/common/src/types.rsdiffbeforeafterboth
--- /dev/null
+++ b/primitives/common/src/types.rs
@@ -0,0 +1,81 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::{
+	generic,
+	traits::{Verify, IdentifyAccount},
+	MultiSignature,
+};
+
+/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
+/// the specifics of the runtime. They can then be made to be agnostic over specific formats
+/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
+/// to even the core data structures.
+pub mod opaque {
+	pub use sp_runtime::{generic, traits::BlakeTwo256, OpaqueExtrinsic as UncheckedExtrinsic};
+
+	pub use super::{BlockNumber, Signature, AccountId, Balance, Index, Hash, AuraId};
+
+	/// Opaque block header type.
+	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
+
+	/// Opaque block type.
+	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+
+	pub trait RuntimeInstance {
+		type CrossAccountId: pallet_evm::account::CrossAccountId<sp_runtime::AccountId32>
+			+ Send
+			+ Sync
+			+ 'static;
+
+		type TransactionConverter: fp_rpc::ConvertTransaction<UncheckedExtrinsic>
+			+ Send
+			+ Sync
+			+ 'static;
+
+		fn get_transaction_converter() -> Self::TransactionConverter;
+	}
+}
+
+pub type SessionHandlers = ();
+
+/// An index to a block.
+pub type BlockNumber = u32;
+
+/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
+pub type Signature = MultiSignature;
+
+/// Some way of identifying an account on the chain. We intentionally make it equivalent
+/// to the public key of our transaction signing scheme.
+pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
+
+/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
+/// never know...
+pub type AccountIndex = u32;
+
+/// Balance of an account.
+pub type Balance = u128;
+
+/// Index of a transaction in the chain.
+pub type Index = u32;
+
+/// A hash of some data used by the chain.
+pub type Hash = sp_core::H256;
+
+/// Digest item type.
+pub type DigestItem = generic::DigestItem;
+
+pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
deletedruntime/common/Cargo.tomldiffbeforeafterboth
--- a/runtime/common/Cargo.toml
+++ /dev/null
@@ -1,115 +0,0 @@
-[package]
-authors = ['Unique Network <support@uniquenetwork.io>']
-description = 'Unique Runtime Common'
-edition = '2021'
-homepage = 'https://unique.network'
-license = 'All Rights Reserved'
-name = 'unique-runtime-common'
-repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = '0.9.24'
-
-[features]
-default = ['std']
-std = [
-    'sp-core/std',
-    'sp-std/std',
-    'sp-runtime/std',
-    'codec/std',
-    'frame-support/std',
-    'frame-system/std',
-    'sp-consensus-aura/std',
-    'pallet-common/std',
-    'pallet-unique/std',
-    'pallet-fungible/std',
-    'pallet-nonfungible/std',
-    'pallet-refungible/std',
-    'up-data-structs/std',
-    'pallet-evm/std',
-    'fp-rpc/std',
-]
-runtime-benchmarks = [
-    'sp-runtime/runtime-benchmarks',
-    'frame-support/runtime-benchmarks',
-    'frame-system/runtime-benchmarks',
-]
-
-[dependencies.sp-core]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.sp-std]
-default-features = false
-git = 'https://github.com/paritytech/substrate'
-branch = 'polkadot-v0.9.24'
-
-[dependencies.sp-runtime]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.codec]
-default-features = false
-features = ['derive']
-package = 'parity-scale-codec'
-version = '3.1.2'
-
-[dependencies.scale-info]
-default-features = false
-features = ["derive"]
-version = "2.0.1"
-
-[dependencies.frame-support]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.frame-system]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.pallet-common]
-default-features = false
-path = "../../pallets/common"
-
-[dependencies.pallet-unique]
-default-features = false
-path = "../../pallets/unique"
-
-[dependencies.pallet-fungible]
-default-features = false
-path = "../../pallets/fungible"
-
-[dependencies.pallet-nonfungible]
-default-features = false
-path = "../../pallets/nonfungible"
-
-[dependencies.pallet-refungible]
-default-features = false
-path = "../../pallets/refungible"
-
-[dependencies.pallet-unique-scheduler]
-default-features = false
-path = "../../pallets/scheduler"
-
-[dependencies.up-data-structs]
-default-features = false
-path = "../../primitives/data-structs"
-
-[dependencies.sp-consensus-aura]
-default-features = false
-git = "https://github.com/paritytech/substrate"
-branch = "polkadot-v0.9.24"
-
-[dependencies.fp-rpc]
-default-features = false
-git = "https://github.com/uniquenetwork/frontier"
-branch = "unique-polkadot-v0.9.24"
-
-[dependencies]
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
-evm-coder = { default-features = false, path = '../../crates/evm-coder' }
-up-sponsorship = { default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
-
-rmrk-rpc = { default-features = false, path = "../../primitives/rmrk-rpc" }
addedruntime/common/config/ethereum.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/ethereum.rs
@@ -0,0 +1,131 @@
+use sp_core::{U256, H160};
+use frame_support::{
+	weights::{Weight, constants::WEIGHT_PER_SECOND},
+	traits::{FindAuthor},
+	parameter_types, ConsensusEngineId,
+};
+use sp_runtime::{RuntimeAppPublic, Perbill};
+use crate::{
+	runtime_common::{
+		dispatch::CollectionDispatchT, ethereum::sponsoring::EvmSponsorshipHandler,
+		config::sponsoring::DefaultSponsoringRateLimit, DealWithFees,
+	},
+	Runtime, Aura, Balances, Event, ChainId,
+};
+use pallet_evm::{EnsureAddressTruncated, HashedAddressMapping};
+use up_common::constants::*;
+
+pub type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
+
+impl pallet_evm::account::Config for Runtime {
+	type CrossAccountId = CrossAccountId;
+	type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
+	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
+}
+
+// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
+// (contract, which only writes a lot of data),
+// approximating on top of our real store write weight
+parameter_types! {
+	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
+	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
+	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
+}
+
+/// Limiting EVM execution to 50% of block for substrate users and management tasks
+/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
+/// scheduled fairly
+const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
+parameter_types! {
+	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
+}
+
+pub enum FixedGasWeightMapping {}
+impl pallet_evm::GasWeightMapping for FixedGasWeightMapping {
+	fn gas_to_weight(gas: u64) -> Weight {
+		gas.saturating_mul(WeightPerGas::get())
+	}
+	fn weight_to_gas(weight: Weight) -> u64 {
+		weight / WeightPerGas::get()
+	}
+}
+
+pub struct FixedFee;
+impl pallet_evm::FeeCalculator for FixedFee {
+	fn min_gas_price() -> (U256, u64) {
+		(MIN_GAS_PRICE.into(), 0)
+	}
+}
+
+pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
+impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
+	fn find_author<'a, I>(digests: I) -> Option<H160>
+	where
+		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
+	{
+		if let Some(author_index) = F::find_author(digests) {
+			let authority_id = Aura::authorities()[author_index as usize].clone();
+			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
+		}
+		None
+	}
+}
+
+impl pallet_evm::Config for Runtime {
+	type BlockGasLimit = BlockGasLimit;
+	type FeeCalculator = FixedFee;
+	type GasWeightMapping = FixedGasWeightMapping;
+	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
+	type CallOrigin = EnsureAddressTruncated<Self>;
+	type WithdrawOrigin = EnsureAddressTruncated<Self>;
+	type AddressMapping = HashedAddressMapping<Self::Hashing>;
+	type PrecompilesType = ();
+	type PrecompilesValue = ();
+	type Currency = Balances;
+	type Event = Event;
+	type OnMethodCall = (
+		pallet_evm_migration::OnMethodCall<Self>,
+		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
+		CollectionDispatchT<Self>,
+		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
+	);
+	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
+	type ChainId = ChainId;
+	type Runner = pallet_evm::runner::stack::Runner<Self>;
+	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
+	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
+	type FindAuthor = EthereumFindAuthor<Aura>;
+}
+
+impl pallet_evm_migration::Config for Runtime {
+	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
+}
+
+impl pallet_ethereum::Config for Runtime {
+	type Event = Event;
+	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
+}
+
+parameter_types! {
+	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049
+	pub const HelpersContractAddress: H160 = H160([
+		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
+	]);
+
+	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
+	pub const EvmCollectionHelpersAddress: H160 = H160([
+		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
+	]);
+}
+
+impl pallet_evm_contract_helpers::Config for Runtime {
+	type ContractAddress = HelpersContractAddress;
+	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
+}
+
+impl pallet_evm_coder_substrate::Config for Runtime {}
+
+impl pallet_evm_transaction_payment::Config for Runtime {
+	type EvmSponsorshipHandler = EvmSponsorshipHandler;
+	type Currency = Balances;
+}
addedruntime/common/config/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/mod.rs
@@ -0,0 +1,23 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod ethereum;
+pub mod orml;
+pub mod pallets;
+pub mod parachain;
+pub mod sponsoring;
+pub mod substrate;
+pub mod xcm;
addedruntime/common/config/orml.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/orml.rs
@@ -0,0 +1,38 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use frame_system::EnsureSigned;
+use crate::{Runtime, Event, RelayChainBlockNumberProvider};
+use up_common::{
+	types::{AccountId, Balance},
+	constants::*,
+};
+
+parameter_types! {
+	pub const MinVestedTransfer: Balance = 10 * UNIQUE;
+	pub const MaxVestingSchedules: u32 = 28;
+}
+
+impl orml_vesting::Config for Runtime {
+	type Event = Event;
+	type Currency = pallet_balances::Pallet<Runtime>;
+	type MinVestedTransfer = MinVestedTransfer;
+	type VestedTransferOrigin = EnsureSigned<AccountId>;
+	type WeightInfo = ();
+	type MaxVestingSchedules = MaxVestingSchedules;
+	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
+}
addedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/pallets/mod.rs
@@ -0,0 +1,93 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use sp_runtime::traits::AccountIdConversion;
+use crate::{
+	runtime_common::{
+		dispatch::CollectionDispatchT,
+		config::{substrate::TreasuryModuleId, ethereum::EvmCollectionHelpersAddress},
+		weights::CommonWeights,
+		RelayChainBlockNumberProvider,
+	},
+	Runtime, Event, Call, Balances,
+};
+use up_common::{
+	types::{AccountId, Balance, BlockNumber},
+	constants::*,
+};
+use up_data_structs::{
+	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
+};
+
+#[cfg(feature = "rmrk")]
+pub mod rmrk;
+
+#[cfg(feature = "scheduler")]
+pub mod scheduler;
+
+parameter_types! {
+	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
+	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
+}
+
+impl pallet_common::Config for Runtime {
+	type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
+	type Event = Event;
+	type Currency = Balances;
+	type CollectionCreationPrice = CollectionCreationPrice;
+	type TreasuryAccountId = TreasuryAccountId;
+	type CollectionDispatch = CollectionDispatchT<Self>;
+
+	type EvmTokenAddressMapping = EvmTokenAddressMapping;
+	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+	type ContractAddress = EvmCollectionHelpersAddress;
+}
+
+impl pallet_structure::Config for Runtime {
+	type Event = Event;
+	type Call = Call;
+	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
+}
+
+impl pallet_fungible::Config for Runtime {
+	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
+}
+impl pallet_refungible::Config for Runtime {
+	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
+}
+impl pallet_nonfungible::Config for Runtime {
+	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
+}
+
+parameter_types! {
+	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
+}
+
+/// Used for the pallet inflation
+impl pallet_inflation::Config for Runtime {
+	type Currency = Balances;
+	type TreasuryAccountId = TreasuryAccountId;
+	type InflationBlockInterval = InflationBlockInterval;
+	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
+}
+
+impl pallet_unique::Config for Runtime {
+	type Event = Event;
+	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
+	type CommonWeightInfo = CommonWeights<Self>;
+	type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
+}
addedruntime/common/config/pallets/rmrk.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/pallets/rmrk.rs
@@ -0,0 +1,27 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use crate::{Runtime, Event};
+
+impl pallet_proxy_rmrk_core::Config for Runtime {
+	type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
+	type Event = Event;
+}
+
+impl pallet_proxy_rmrk_equip::Config for Runtime {
+	type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
+	type Event = Event;
+}
addedruntime/common/config/pallets/scheduler.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/pallets/scheduler.rs
@@ -0,0 +1,59 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{traits::PrivilegeCmp, weights::Weight, parameter_types};
+use frame_system::EnsureSigned;
+use sp_runtime::Perbill;
+use sp_std::cmp::Ordering;
+use crate::{
+	runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},
+	Runtime, Call, Event, Origin, OriginCaller, Balances,
+};
+use up_common::types::AccountId;
+
+parameter_types! {
+	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
+		RuntimeBlockWeights::get().max_block;
+	pub const MaxScheduledPerBlock: u32 = 50;
+
+	pub const NoPreimagePostponement: Option<u32> = Some(10);
+	pub const Preimage: Option<u32> = Some(10);
+}
+
+/// Used the compare the privilege of an origin inside the scheduler.
+pub struct OriginPrivilegeCmp;
+
+impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
+	fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
+		Some(Ordering::Equal)
+	}
+}
+
+impl pallet_unique_scheduler::Config for Runtime {
+	type Event = Event;
+	type Origin = Origin;
+	type Currency = Balances;
+	type PalletsOrigin = OriginCaller;
+	type Call = Call;
+	type MaximumWeight = MaximumSchedulerWeight;
+	type ScheduleOrigin = EnsureSigned<AccountId>;
+	type MaxScheduledPerBlock = MaxScheduledPerBlock;
+	type WeightInfo = ();
+	type CallExecutor = SchedulerPaymentExecutor;
+	type OriginPrivilegeCmp = OriginPrivilegeCmp;
+	type PreimageProvider = ();
+	type NoPreimagePostponement = NoPreimagePostponement;
+}
addedruntime/common/config/parachain.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/parachain.rs
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{weights::Weight, parameter_types};
+use crate::{Runtime, Event, XcmpQueue, DmpQueue};
+use up_common::constants::*;
+
+parameter_types! {
+	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
+	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
+}
+
+impl cumulus_pallet_parachain_system::Config for Runtime {
+	type Event = Event;
+	type SelfParaId = parachain_info::Pallet<Self>;
+	type OnSystemEvent = ();
+	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
+	// 	MaxDownwardMessageWeight,
+	// 	XcmExecutor<XcmConfig>,
+	// 	Call,
+	// >;
+	type OutboundXcmpMessageSource = XcmpQueue;
+	type DmpMessageHandler = DmpQueue;
+	type ReservedDmpWeight = ReservedDmpWeight;
+	type ReservedXcmpWeight = ReservedXcmpWeight;
+	type XcmpMessageHandler = XcmpQueue;
+}
+
+impl parachain_info::Config for Runtime {}
+
+impl cumulus_pallet_aura_ext::Config for Runtime {}
addedruntime/common/config/sponsoring.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/sponsoring.rs
@@ -0,0 +1,35 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::parameter_types;
+use crate::{
+	runtime_common::{sponsoring::UniqueSponsorshipHandler},
+	Runtime,
+};
+use up_common::{types::BlockNumber, constants::*};
+
+parameter_types! {
+	pub const DefaultSponsoringRateLimit: BlockNumber = 1 * DAYS;
+}
+
+type SponsorshipHandler = (
+	UniqueSponsorshipHandler<Runtime>,
+	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
+);
+
+impl pallet_charge_transaction::Config for Runtime {
+	type SponsorshipHandler = SponsorshipHandler;
+}
addedruntime/common/config/substrate.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/substrate.rs
@@ -0,0 +1,237 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+	traits::{Everything, ConstU32},
+	weights::{
+		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
+		DispatchClass, WeightToFeePolynomial, WeightToFeeCoefficients, ConstantMultiplier,
+		WeightToFeeCoefficient,
+	},
+	parameter_types, PalletId,
+};
+use sp_runtime::{
+	generic,
+	traits::{BlakeTwo256, AccountIdLookup},
+	Perbill, Permill, Percent,
+};
+use frame_system::{
+	limits::{BlockLength, BlockWeights},
+	EnsureRoot,
+};
+use sp_arithmetic::traits::{BaseArithmetic, Unsigned};
+use smallvec::smallvec;
+use crate::{
+	runtime_common::DealWithFees, Runtime, Event, Call, Origin, PalletInfo, System, Balances,
+	Treasury, SS58Prefix, Version,
+};
+use up_common::{types::*, constants::*};
+
+parameter_types! {
+	pub const BlockHashCount: BlockNumber = 2400;
+	pub RuntimeBlockLength: BlockLength =
+		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
+	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
+	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
+	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
+		.base_block(BlockExecutionWeight::get())
+		.for_class(DispatchClass::all(), |weights| {
+			weights.base_extrinsic = ExtrinsicBaseWeight::get();
+		})
+		.for_class(DispatchClass::Normal, |weights| {
+			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
+		})
+		.for_class(DispatchClass::Operational, |weights| {
+			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
+			// Operational transactions have some extra reserved space, so that they
+			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
+			weights.reserved = Some(
+				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
+			);
+		})
+		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
+		.build_or_panic();
+}
+
+impl frame_system::Config for Runtime {
+	/// The data to be stored in an account.
+	type AccountData = pallet_balances::AccountData<Balance>;
+	/// The identifier used to distinguish between accounts.
+	type AccountId = AccountId;
+	/// The basic call filter to use in dispatchable.
+	type BaseCallFilter = Everything;
+	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
+	type BlockHashCount = BlockHashCount;
+	/// The maximum length of a block (in bytes).
+	type BlockLength = RuntimeBlockLength;
+	/// The index type for blocks.
+	type BlockNumber = BlockNumber;
+	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
+	type BlockWeights = RuntimeBlockWeights;
+	/// The aggregated dispatch type that is available for extrinsics.
+	type Call = Call;
+	/// The weight of database operations that the runtime can invoke.
+	type DbWeight = RocksDbWeight;
+	/// The ubiquitous event type.
+	type Event = Event;
+	/// The type for hashing blocks and tries.
+	type Hash = Hash;
+	/// The hashing algorithm used.
+	type Hashing = BlakeTwo256;
+	/// The header type.
+	type Header = generic::Header<BlockNumber, BlakeTwo256>;
+	/// The index type for storing how many extrinsics an account has signed.
+	type Index = Index;
+	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
+	type Lookup = AccountIdLookup<AccountId, ()>;
+	/// What to do if an account is fully reaped from the system.
+	type OnKilledAccount = ();
+	/// What to do if a new account is created.
+	type OnNewAccount = ();
+	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
+	/// The ubiquitous origin type.
+	type Origin = Origin;
+	/// This type is being generated by `construct_runtime!`.
+	type PalletInfo = PalletInfo;
+	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
+	type SS58Prefix = SS58Prefix;
+	/// Weight information for the extrinsics of this pallet.
+	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
+	/// Version of the runtime.
+	type Version = Version;
+	type MaxConsumers = ConstU32<16>;
+}
+
+impl pallet_randomness_collective_flip::Config for Runtime {}
+
+parameter_types! {
+	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
+}
+
+impl pallet_timestamp::Config for Runtime {
+	/// A timestamp: milliseconds since the unix epoch.
+	type Moment = u64;
+	type OnTimestampSet = ();
+	type MinimumPeriod = MinimumPeriod;
+	type WeightInfo = ();
+}
+
+parameter_types! {
+	// pub const ExistentialDeposit: u128 = 500;
+	pub const ExistentialDeposit: u128 = 0;
+	pub const MaxLocks: u32 = 50;
+	pub const MaxReserves: u32 = 50;
+}
+
+impl pallet_balances::Config for Runtime {
+	type MaxLocks = MaxLocks;
+	type MaxReserves = MaxReserves;
+	type ReserveIdentifier = [u8; 16];
+	/// The type for recording an account's balance.
+	type Balance = Balance;
+	/// The ubiquitous event type.
+	type Event = Event;
+	type DustRemoval = Treasury;
+	type ExistentialDeposit = ExistentialDeposit;
+	type AccountStore = System;
+	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
+}
+
+parameter_types! {
+	/// This value increases the priority of `Operational` transactions by adding
+	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
+	pub const OperationalFeeMultiplier: u8 = 5;
+}
+
+/// Linear implementor of `WeightToFeePolynomial`
+pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
+
+impl<T> WeightToFeePolynomial for LinearFee<T>
+where
+	T: BaseArithmetic + From<u32> + Copy + Unsigned,
+{
+	type Balance = T;
+
+	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
+		smallvec!(WeightToFeeCoefficient {
+			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
+			coeff_frac: Perbill::zero(),
+			negative: false,
+			degree: 1,
+		})
+	}
+}
+
+impl pallet_transaction_payment::Config for Runtime {
+	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
+	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
+	type OperationalFeeMultiplier = OperationalFeeMultiplier;
+	type WeightToFee = LinearFee<Balance>;
+	type FeeMultiplierUpdate = ();
+}
+
+parameter_types! {
+	pub const ProposalBond: Permill = Permill::from_percent(5);
+	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
+	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
+	pub const SpendPeriod: BlockNumber = 5 * MINUTES;
+	pub const Burn: Permill = Permill::from_percent(0);
+	pub const TipCountdown: BlockNumber = 1 * DAYS;
+	pub const TipFindersFee: Percent = Percent::from_percent(20);
+	pub const TipReportDepositBase: Balance = 1 * UNIQUE;
+	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
+	pub const BountyDepositBase: Balance = 1 * UNIQUE;
+	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
+	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
+	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
+	pub const MaximumReasonLength: u32 = 16384;
+	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
+	pub const BountyValueMinimum: Balance = 5 * UNIQUE;
+	pub const MaxApprovals: u32 = 100;
+}
+
+impl pallet_treasury::Config for Runtime {
+	type PalletId = TreasuryModuleId;
+	type Currency = Balances;
+	type ApproveOrigin = EnsureRoot<AccountId>;
+	type RejectOrigin = EnsureRoot<AccountId>;
+	type Event = Event;
+	type OnSlash = ();
+	type ProposalBond = ProposalBond;
+	type ProposalBondMinimum = ProposalBondMinimum;
+	type ProposalBondMaximum = ProposalBondMaximum;
+	type SpendPeriod = SpendPeriod;
+	type Burn = Burn;
+	type BurnDestination = ();
+	type SpendFunds = ();
+	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
+	type MaxApprovals = MaxApprovals;
+}
+
+impl pallet_sudo::Config for Runtime {
+	type Event = Event;
+	type Call = Call;
+}
+
+parameter_types! {
+	pub const MaxAuthorities: u32 = 100_000;
+}
+
+impl pallet_aura::Config for Runtime {
+	type AuthorityId = AuraId;
+	type DisabledValidators = ();
+	type MaxAuthorities = MaxAuthorities;
+}
addedruntime/common/config/xcm.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/config/xcm.rs
@@ -0,0 +1,295 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+	traits::{
+		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Get, Everything,
+	},
+	weights::{Weight, WeightToFeePolynomial, WeightToFee},
+	parameter_types, match_types,
+};
+use frame_system::EnsureRoot;
+use sp_runtime::{
+	traits::{Saturating, CheckedConversion, Zero},
+	SaturatedConversion,
+};
+use pallet_xcm::XcmPassthrough;
+use polkadot_parachain::primitives::Sibling;
+use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
+use xcm::latest::{
+	AssetId::{Concrete},
+	Fungibility::Fungible as XcmFungible,
+	MultiAsset, Error as XcmError,
+};
+use xcm_executor::traits::{MatchesFungible, WeightTrader};
+use xcm_builder::{
+	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, CurrencyAdapter, EnsureXcmOrigin,
+	FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser, RelayChainAsNative,
+	SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
+	SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, ParentIsPreset,
+};
+use xcm_executor::{Config, XcmExecutor, Assets};
+use sp_std::marker::PhantomData;
+use crate::{
+	runtime_common::config::substrate::LinearFee, Runtime, Call, Event, Origin, Balances,
+	ParachainInfo, ParachainSystem, PolkadotXcm, XcmpQueue,
+};
+use up_common::{
+	types::{AccountId, Balance},
+	constants::*,
+};
+
+parameter_types! {
+	pub const RelayLocation: MultiLocation = MultiLocation::parent();
+	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
+	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
+	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
+}
+
+/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
+/// when determining ownership of accounts for asset transacting and when attempting to use XCM
+/// `Transact` in order to determine the dispatch Origin.
+pub type LocationToAccountId = (
+	// The parent (Relay-chain) origin converts to the default `AccountId`.
+	ParentIsPreset<AccountId>,
+	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
+	SiblingParachainConvertsVia<Sibling, AccountId>,
+	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
+	AccountId32Aliases<RelayNetwork, AccountId>,
+);
+
+pub struct OnlySelfCurrency;
+impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
+	fn matches_fungible(a: &MultiAsset) -> Option<B> {
+		match (&a.id, &a.fun) {
+			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
+			_ => None,
+		}
+	}
+}
+
+/// Means for transacting assets on this chain.
+pub type LocalAssetTransactor = CurrencyAdapter<
+	// Use this currency:
+	Balances,
+	// Use this currency when it is a fungible asset matching the given location or name:
+	OnlySelfCurrency,
+	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
+	LocationToAccountId,
+	// Our chain's account ID type (we can't get away without mentioning it explicitly):
+	AccountId,
+	// We don't track any teleports.
+	(),
+>;
+
+/// No local origins on this chain are allowed to dispatch XCM sends/executions.
+pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
+
+/// The means for routing XCM messages which are not for local execution into the right message
+/// queues.
+pub type XcmRouter = (
+	// Two routers - use UMP to communicate with the relay chain:
+	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
+	// ..and XCMP to communicate with the sibling chains.
+	XcmpQueue,
+);
+
+/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
+/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
+/// biases the kind of local `Origin` it will become.
+pub type XcmOriginToTransactDispatchOrigin = (
+	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
+	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
+	// foreign chains who want to have a local sovereign account on this chain which they control.
+	SovereignSignedViaLocation<LocationToAccountId, Origin>,
+	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
+	// recognised.
+	RelayChainAsNative<RelayOrigin, Origin>,
+	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
+	// recognised.
+	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
+	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
+	// transaction from the Root origin.
+	ParentAsSuperuser<Origin>,
+	// Native signed account converter; this just converts an `AccountId32` origin into a normal
+	// `Origin::Signed` origin of the same 32-byte value.
+	SignedAccountId32AsNative<RelayNetwork, Origin>,
+	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
+	XcmPassthrough<Origin>,
+);
+
+parameter_types! {
+	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
+	pub UnitWeightCost: Weight = 1_000_000;
+	// 1200 UNIQUEs buy 1 second of weight.
+	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
+	pub const MaxInstructions: u32 = 100;
+}
+
+match_types! {
+	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
+		MultiLocation { parents: 1, interior: Here } |
+		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
+	};
+}
+
+pub type Barrier = (
+	TakeWeightCredit,
+	AllowTopLevelPaidExecutionFrom<Everything>,
+	// ^^^ Parent & its unit plurality gets free execution
+);
+
+pub struct UsingOnlySelfCurrencyComponents<
+	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+	AssetId: Get<MultiLocation>,
+	AccountId,
+	Currency: CurrencyT<AccountId>,
+	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+>(
+	Weight,
+	Currency::Balance,
+	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
+);
+impl<
+		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+		AssetId: Get<MultiLocation>,
+		AccountId,
+		Currency: CurrencyT<AccountId>,
+		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+	> WeightTrader
+	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
+{
+	fn new() -> Self {
+		Self(0, Zero::zero(), PhantomData)
+	}
+
+	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
+		let amount = WeightToFee::weight_to_fee(&weight);
+		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
+
+		// location to this parachain through relay chain
+		let option1: xcm::v1::AssetId = Concrete(MultiLocation {
+			parents: 1,
+			interior: X1(Parachain(ParachainInfo::parachain_id().into())),
+		});
+		// direct location
+		let option2: xcm::v1::AssetId = Concrete(MultiLocation {
+			parents: 0,
+			interior: Here,
+		});
+
+		let required = if payment.fungible.contains_key(&option1) {
+			(option1, u128_amount).into()
+		} else if payment.fungible.contains_key(&option2) {
+			(option2, u128_amount).into()
+		} else {
+			(Concrete(MultiLocation::default()), u128_amount).into()
+		};
+
+		let unused = payment
+			.checked_sub(required)
+			.map_err(|_| XcmError::TooExpensive)?;
+		self.0 = self.0.saturating_add(weight);
+		self.1 = self.1.saturating_add(amount);
+		Ok(unused)
+	}
+
+	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
+		let weight = weight.min(self.0);
+		let amount = WeightToFee::weight_to_fee(&weight);
+		self.0 -= weight;
+		self.1 = self.1.saturating_sub(amount);
+		let amount: u128 = amount.saturated_into();
+		if amount > 0 {
+			Some((AssetId::get(), amount).into())
+		} else {
+			None
+		}
+	}
+}
+impl<
+		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
+		AssetId: Get<MultiLocation>,
+		AccountId,
+		Currency: CurrencyT<AccountId>,
+		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
+	> Drop
+	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
+{
+	fn drop(&mut self) {
+		OnUnbalanced::on_unbalanced(Currency::issue(self.1));
+	}
+}
+
+pub struct XcmConfig;
+impl Config for XcmConfig {
+	type Call = Call;
+	type XcmSender = XcmRouter;
+	// How to withdraw and deposit an asset.
+	type AssetTransactor = LocalAssetTransactor;
+	type OriginConverter = XcmOriginToTransactDispatchOrigin;
+	type IsReserve = NativeAsset;
+	type IsTeleporter = (); // Teleportation is disabled
+	type LocationInverter = LocationInverter<Ancestry>;
+	type Barrier = Barrier;
+	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
+	type Trader =
+		UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
+	type ResponseHandler = (); // Don't handle responses for now.
+	type SubscriptionService = PolkadotXcm;
+
+	type AssetTrap = PolkadotXcm;
+	type AssetClaims = PolkadotXcm;
+}
+
+impl pallet_xcm::Config for Runtime {
+	type Event = Event;
+	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
+	type XcmRouter = XcmRouter;
+	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
+	type XcmExecuteFilter = Everything;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+	type XcmTeleportFilter = Everything;
+	type XcmReserveTransferFilter = Everything;
+	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
+	type LocationInverter = LocationInverter<Ancestry>;
+	type Origin = Origin;
+	type Call = Call;
+	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
+	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
+}
+
+impl cumulus_pallet_xcm::Config for Runtime {
+	type Event = Event;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+}
+
+impl cumulus_pallet_xcmp_queue::Config for Runtime {
+	type WeightInfo = ();
+	type Event = Event;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+	type ChannelInfo = ParachainSystem;
+	type VersionWrapper = ();
+	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+	type ControllerOrigin = EnsureRoot<AccountId>;
+	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
+}
+
+impl cumulus_pallet_dmp_queue::Config for Runtime {
+	type Event = Event;
+	type XcmExecutor = XcmExecutor<XcmConfig>;
+	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
+}
addedruntime/common/constants.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/constants.rs
@@ -0,0 +1,55 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_runtime::Perbill;
+use frame_support::{
+	parameter_types,
+	weights::{Weight, constants::WEIGHT_PER_SECOND},
+};
+use up_common::types::{BlockNumber, Balance};
+
+pub const MILLISECS_PER_BLOCK: u64 = 12000;
+
+pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
+
+// These time units are defined in number of blocks.
+pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
+pub const HOURS: BlockNumber = MINUTES * 60;
+pub const DAYS: BlockNumber = HOURS * 24;
+
+pub const MICROUNIQUE: Balance = 1_000_000_000_000;
+pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
+pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
+pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
+
+// Targeting 0.1 UNQ per transfer
+pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
+
+// Targeting 0.15 UNQ per transfer via ETH
+pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
+
+/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
+/// This is used to limit the maximal weight of a single extrinsic.
+pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
+/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
+/// by  Operational  extrinsics.
+pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
+/// We allow for 2 seconds of compute with a 6 second average block time.
+pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
+
+parameter_types! {
+	pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
+}
addedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/construct_runtime/mod.rs
@@ -0,0 +1,90 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+mod util;
+
+#[macro_export]
+macro_rules! construct_runtime {
+    ($select_runtime:ident) => {
+        $crate::construct_runtime_impl! {
+            select_runtime($select_runtime);
+
+            pub enum Runtime where
+                Block = Block,
+                NodeBlock = opaque::Block,
+                UncheckedExtrinsic = UncheckedExtrinsic
+            {
+                ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
+                ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
+
+                Aura: pallet_aura::{Pallet, Config<T>} = 22,
+                AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
+
+                Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
+                RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
+                Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
+                TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
+                Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
+                Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
+                System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
+                Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
+                // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
+                // Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
+
+                // XCM helpers.
+                XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
+                PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
+                CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
+                DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
+
+                // Unique Pallets
+                Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
+                Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
+
+                #[runtimes(opal)]
+                Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
+
+                // free = 63
+
+                Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
+                // ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
+                Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
+                Fungible: pallet_fungible::{Pallet, Storage} = 67,
+
+                #[runtimes(opal)]
+                Refungible: pallet_refungible::{Pallet, Storage} = 68,
+
+                Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
+                Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
+
+                #[runtimes(opal)]
+                RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
+
+                #[runtimes(opal)]
+                RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
+
+                // Frontier
+                EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
+                Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
+
+                EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
+                EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
+                EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
+                EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
+            }
+        }
+    }
+}
addedruntime/common/construct_runtime/util.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/construct_runtime/util.rs
@@ -0,0 +1,222 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_export]
+macro_rules! construct_runtime_impl {
+    (
+        select_runtime($select_runtime:ident);
+
+        pub enum Runtime where
+            $($where_ident:ident = $where_ty:ty),* $(,)?
+        {
+            $(
+                $(#[runtimes($($pallet_runtimes:ident),+ $(,)?)])?
+                $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal
+            ),*
+            $(,)?
+        }
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime($select_runtime),
+            selected_pallets(),
+
+            where_clause($($where_ident = $where_ty),*),
+            pallets(
+                $(
+                    $(#[runtimes($($pallet_runtimes),+)])?
+                    $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index
+                ),*,
+            )
+        }
+    }
+}
+
+#[macro_export]
+macro_rules! construct_runtime_helper {
+    (
+        select_runtime($select_runtime:ident),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            #[runtimes($($pallet_runtimes:ident),+)]
+            $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::add_runtime_specific_pallets! {
+            select_runtime($select_runtime),
+            runtimes($($pallet_runtimes),+,),
+            selected_pallets($($selected_pallets)*),
+
+            where_clause($($where_clause)*),
+            pallets(
+                $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+                $($pallets_tl)*
+            )
+        }
+    };
+
+    (
+        select_runtime($select_runtime:ident),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime($select_runtime),
+            selected_pallets(
+                $($selected_pallets)*
+                $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+            ),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets_tl)*)
+        }
+    };
+
+    (
+        select_runtime($select_runtime:ident),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets()
+    ) => {
+        frame_support::construct_runtime! {
+            pub enum Runtime where
+                $($where_clause)*
+            {
+                $($selected_pallets)*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! add_runtime_specific_pallets {
+    (
+        select_runtime(opal),
+        runtimes(opal, $($_runtime_tl:tt)*),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime(opal),
+            selected_pallets(
+                $($selected_pallets)*
+                $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+            ),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets_tl)*)
+        }
+    };
+
+    (
+        select_runtime(quartz),
+        runtimes(quartz, $($_runtime_tl:tt)*),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime(quartz),
+            selected_pallets(
+                $($selected_pallets)*
+                $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+            ),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets_tl)*)
+        }
+    };
+
+    (
+        select_runtime(unique),
+        runtimes(unique, $($_runtime_tl:tt)*),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            $pallet_name:ident: $pallet_mod:ident::{$($pallet_parts:ty),*} = $index:literal,
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime(unique),
+            selected_pallets(
+                $($selected_pallets)*
+                $pallet_name: $pallet_mod::{$($pallet_parts),*} = $index,
+            ),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets_tl)*)
+        }
+    };
+
+    (
+        select_runtime($select_runtime:ident),
+        runtimes($_current_runtime:ident, $($runtime_tl:tt)*),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets($($pallets:tt)*)
+    ) => {
+        $crate::add_runtime_specific_pallets! {
+            select_runtime($select_runtime),
+            runtimes($($runtime_tl)*),
+            selected_pallets($($selected_pallets)*),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets)*)
+        }
+    };
+
+    (
+        select_runtime($select_runtime:ident),
+        runtimes(),
+        selected_pallets($($selected_pallets:tt)*),
+
+        where_clause($($where_clause:tt)*),
+        pallets(
+            $_pallet_name:ident: $_pallet_mod:ident::{$($_pallet_parts:ty),*} = $_index:literal,
+            $($pallets_tl:tt)*
+        )
+    ) => {
+        $crate::construct_runtime_helper! {
+            select_runtime($select_runtime),
+            selected_pallets($($selected_pallets)*),
+
+            where_clause($($where_clause)*),
+            pallets($($pallets_tl)*)
+        }
+    };
+}
addedruntime/common/dispatch.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/dispatch.rs
@@ -0,0 +1,189 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{dispatch::DispatchResult, ensure};
+use pallet_evm::{PrecompileHandle, PrecompileResult};
+use sp_core::H160;
+use sp_runtime::DispatchError;
+use sp_std::{borrow::ToOwned, vec::Vec};
+use pallet_common::{
+	CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,
+	eth::map_eth_to_id,
+};
+pub use pallet_common::dispatch::CollectionDispatch;
+use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
+use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
+use pallet_refungible::{
+	Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
+};
+use up_data_structs::{
+	CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
+	CollectionId,
+};
+
+#[cfg(not(feature = "refungible"))]
+use pallet_common::unsupported;
+
+pub enum CollectionDispatchT<T>
+where
+	T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,
+{
+	Fungible(FungibleHandle<T>),
+	Nonfungible(NonfungibleHandle<T>),
+	Refungible(RefungibleHandle<T>),
+}
+impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
+where
+	T: pallet_common::Config
+		+ pallet_unique::Config
+		+ pallet_fungible::Config
+		+ pallet_nonfungible::Config
+		+ pallet_refungible::Config,
+{
+	fn create(
+		sender: T::CrossAccountId,
+		data: CreateCollectionData<T::AccountId>,
+	) -> Result<CollectionId, DispatchError> {
+		let id = match data.mode {
+			CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
+			CollectionMode::Fungible(decimal_points) => {
+				// check params
+				ensure!(
+					decimal_points <= MAX_DECIMAL_POINTS,
+					pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
+				);
+				<PalletFungible<T>>::init_collection(sender, data)?
+			}
+
+			#[cfg(feature = "refungible")]
+			CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
+
+			#[cfg(not(feature = "refungible"))]
+			CollectionMode::ReFungible => return unsupported!(T),
+		};
+		Ok(id)
+	}
+
+	fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {
+		match collection.mode {
+			CollectionMode::ReFungible => {
+				PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?
+			}
+			CollectionMode::Fungible(_) => {
+				PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?
+			}
+			CollectionMode::NFT => {
+				PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?
+			}
+		}
+		Ok(())
+	}
+
+	fn dispatch(handle: CollectionHandle<T>) -> Self {
+		match handle.mode {
+			CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
+			CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
+			CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
+		}
+	}
+
+	fn into_inner(self) -> CollectionHandle<T> {
+		match self {
+			Self::Fungible(f) => f.into_inner(),
+			Self::Nonfungible(f) => f.into_inner(),
+			Self::Refungible(f) => f.into_inner(),
+		}
+	}
+
+	fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
+		match self {
+			Self::Fungible(h) => h,
+			Self::Nonfungible(h) => h,
+			Self::Refungible(h) => h,
+		}
+	}
+}
+
+impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>
+where
+	T: pallet_common::Config
+		+ pallet_unique::Config
+		+ pallet_fungible::Config
+		+ pallet_nonfungible::Config
+		+ pallet_refungible::Config,
+	T::AccountId: From<[u8; 32]>,
+{
+	fn is_reserved(target: &H160) -> bool {
+		map_eth_to_id(target).is_some()
+	}
+	fn is_used(target: &H160) -> bool {
+		map_eth_to_id(target)
+			.map(<CollectionById<T>>::contains_key)
+			.unwrap_or(false)
+	}
+	fn get_code(target: &H160) -> Option<Vec<u8>> {
+		if let Some(collection_id) = map_eth_to_id(target) {
+			let collection = <CollectionById<T>>::get(collection_id)?;
+			Some(
+				match collection.mode {
+					CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,
+					CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,
+					CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,
+				}
+				.to_owned(),
+			)
+		} else if let Some((collection_id, _token_id)) =
+			<T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)
+		{
+			let collection = <CollectionById<T>>::get(collection_id)?;
+			if collection.mode != CollectionMode::ReFungible {
+				return None;
+			}
+			// TODO: check token existence
+			Some(<RefungibleTokenHandle<T>>::CODE.to_owned())
+		} else {
+			None
+		}
+	}
+	fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
+		if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
+			let collection =
+				<CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
+			let dispatched = Self::dispatch(collection);
+
+			match dispatched {
+				Self::Fungible(h) => h.call(handle),
+				Self::Nonfungible(h) => h.call(handle),
+				Self::Refungible(h) => h.call(handle),
+			}
+		} else if let Some((collection_id, token_id)) =
+			<T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
+				&handle.code_address(),
+			) {
+			let collection =
+				<CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
+			if collection.mode != CollectionMode::ReFungible {
+				return None;
+			}
+
+			let h = RefungibleHandle::cast(collection);
+			// TODO: check token existence
+			RefungibleTokenHandle(h, token_id).call(handle)
+		} else {
+			None
+		}
+	}
+}
addedruntime/common/ethereum/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/ethereum/mod.rs
@@ -0,0 +1,19 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod self_contained_call;
+pub mod sponsoring;
+pub mod transaction_converter;
addedruntime/common/ethereum/self_contained_call.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/ethereum/self_contained_call.rs
@@ -0,0 +1,74 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use sp_core::H160;
+use sp_runtime::{
+	traits::{Dispatchable, DispatchInfoOf, PostDispatchInfoOf},
+	transaction_validity::{TransactionValidityError, TransactionValidity},
+};
+use crate::{Origin, Call};
+
+impl fp_self_contained::SelfContainedCall for Call {
+	type SignedInfo = H160;
+
+	fn is_self_contained(&self) -> bool {
+		match self {
+			Call::Ethereum(call) => call.is_self_contained(),
+			_ => false,
+		}
+	}
+
+	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
+		match self {
+			Call::Ethereum(call) => call.check_self_contained(),
+			_ => None,
+		}
+	}
+
+	fn validate_self_contained(
+		&self,
+		info: &Self::SignedInfo,
+		dispatch_info: &DispatchInfoOf<Call>,
+		len: usize,
+	) -> Option<TransactionValidity> {
+		match self {
+			Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
+			_ => None,
+		}
+	}
+
+	fn pre_dispatch_self_contained(
+		&self,
+		info: &Self::SignedInfo,
+	) -> Option<Result<(), TransactionValidityError>> {
+		match self {
+			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
+			_ => None,
+		}
+	}
+
+	fn apply_self_contained(
+		self,
+		info: Self::SignedInfo,
+	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
+		match self {
+			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
+				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
+			)),
+			_ => None,
+		}
+	}
+}
addedruntime/common/ethereum/sponsoring.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/ethereum/sponsoring.rs
@@ -0,0 +1,127 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! Implements EVM sponsoring logic via TransactionValidityHack
+
+use evm_coder::{Call, abi::AbiReader};
+use pallet_common::{CollectionHandle, eth::map_eth_to_id};
+use sp_core::H160;
+use sp_std::prelude::*;
+use up_sponsorship::SponsorshipHandler;
+use core::marker::PhantomData;
+use core::convert::TryInto;
+use pallet_evm::account::CrossAccountId;
+use up_data_structs::{TokenId, CreateItemData, CreateNftData, CollectionMode};
+use pallet_unique::Config as UniqueConfig;
+
+use crate::{Runtime, runtime_common::sponsoring::*};
+
+use pallet_nonfungible::erc::{
+	UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call, TokenPropertiesCall,
+};
+use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
+use pallet_fungible::Config as FungibleConfig;
+use pallet_nonfungible::Config as NonfungibleConfig;
+use pallet_refungible::Config as RefungibleConfig;
+
+pub type EvmSponsorshipHandler = (
+	UniqueEthSponsorshipHandler<Runtime>,
+	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
+);
+
+pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);
+impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>
+	SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)> for UniqueEthSponsorshipHandler<T>
+{
+	fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {
+		let collection_id = map_eth_to_id(&call.0)?;
+		let collection = <CollectionHandle<T>>::new(collection_id)?;
+		let sponsor = collection.sponsorship.sponsor()?.clone();
+		let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
+		Some(T::CrossAccountId::from_sub(match &collection.mode {
+			CollectionMode::NFT => {
+				let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
+				match call {
+					UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {
+						token_id,
+						key,
+						value,
+						..
+					}) => {
+						let token_id: TokenId = token_id.try_into().ok()?;
+						withdraw_set_token_property::<T>(
+							&collection,
+							&who,
+							&token_id,
+							key.len() + value.len(),
+						)
+						.map(|()| sponsor)
+					}
+					UniqueNFTCall::ERC721UniqueExtensions(
+						ERC721UniqueExtensionsCall::Transfer { token_id, .. },
+					) => {
+						let token_id: TokenId = token_id.try_into().ok()?;
+						withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
+					}
+					UniqueNFTCall::ERC721Mintable(
+						ERC721MintableCall::Mint { token_id, .. }
+						| ERC721MintableCall::MintWithTokenUri { token_id, .. },
+					) => {
+						let _token_id: TokenId = token_id.try_into().ok()?;
+						withdraw_create_item::<T>(
+							&collection,
+							&who,
+							&CreateItemData::NFT(CreateNftData::default()),
+						)
+						.map(|()| sponsor)
+					}
+					UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, from, .. }) => {
+						let token_id: TokenId = token_id.try_into().ok()?;
+						let from = T::CrossAccountId::from_eth(from);
+						withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)
+					}
+					UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {
+						let token_id: TokenId = token_id.try_into().ok()?;
+						withdraw_approve::<T>(&collection, who.as_sub(), &token_id)
+							.map(|()| sponsor)
+					}
+					_ => None,
+				}
+			}
+			CollectionMode::Fungible(_) => {
+				let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
+				#[allow(clippy::single_match)]
+				match call {
+					UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
+						withdraw_transfer::<T>(&collection, who, &TokenId::default())
+							.map(|()| sponsor)
+					}
+					UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {
+						let from = T::CrossAccountId::from_eth(from);
+						withdraw_transfer::<T>(&collection, &from, &TokenId::default())
+							.map(|()| sponsor)
+					}
+					UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {
+						withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())
+							.map(|()| sponsor)
+					}
+					_ => None,
+				}
+			}
+			_ => None,
+		}?))
+	}
+}
addedruntime/common/ethereum/transaction_converter.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/ethereum/transaction_converter.rs
@@ -0,0 +1,42 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use codec::{Encode, Decode};
+use crate::{opaque, Runtime, UncheckedExtrinsic};
+
+pub struct TransactionConverter;
+
+impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
+	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
+		UncheckedExtrinsic::new_unsigned(
+			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+		)
+	}
+}
+
+impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
+	fn convert_transaction(
+		&self,
+		transaction: pallet_ethereum::Transaction,
+	) -> opaque::UncheckedExtrinsic {
+		let extrinsic = UncheckedExtrinsic::new_unsigned(
+			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+		);
+		let encoded = extrinsic.encode();
+		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
+			.expect("Encoded extrinsic is always valid")
+	}
+}
addedruntime/common/instance.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/instance.rs
@@ -0,0 +1,16 @@
+use crate::{
+	runtime_common::{
+		config::ethereum::CrossAccountId, ethereum::transaction_converter::TransactionConverter,
+	},
+	Runtime,
+};
+use up_common::types::opaque::RuntimeInstance;
+
+impl RuntimeInstance for Runtime {
+	type CrossAccountId = CrossAccountId;
+	type TransactionConverter = TransactionConverter;
+
+	fn get_transaction_converter() -> TransactionConverter {
+		TransactionConverter
+	}
+}
addedruntime/common/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/mod.rs
@@ -0,0 +1,168 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+pub mod config;
+pub mod constants;
+pub mod construct_runtime;
+pub mod dispatch;
+pub mod ethereum;
+pub mod instance;
+pub mod runtime_apis;
+pub mod scheduler;
+pub mod sponsoring;
+pub mod weights;
+
+use sp_core::H160;
+use frame_support::traits::{Currency, OnUnbalanced, Imbalance};
+use sp_runtime::{
+	generic,
+	traits::{BlakeTwo256, BlockNumberProvider},
+	impl_opaque_keys,
+};
+use sp_std::vec::Vec;
+
+#[cfg(feature = "std")]
+use sp_version::NativeVersion;
+
+use crate::{
+	Runtime, Call, Balances, Treasury, Aura, Signature, AllPalletsReversedWithSystemFirst,
+	InherentDataExt,
+};
+use up_common::types::{AccountId, BlockNumber};
+
+#[macro_export]
+macro_rules! unsupported {
+	() => {
+		pallet_common::unsupported!($crate::Runtime)
+	};
+}
+
+/// The address format for describing accounts.
+pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
+/// Block header type as expected by this runtime.
+pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
+/// Block type as expected by this runtime.
+pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+/// A Block signed with a Justification
+pub type SignedBlock = generic::SignedBlock<Block>;
+/// BlockId type as expected by this runtime.
+pub type BlockId = generic::BlockId<Block>;
+
+impl_opaque_keys! {
+	pub struct SessionKeys {
+		pub aura: Aura,
+	}
+}
+
+/// The version information used to identify this runtime when compiled natively.
+#[cfg(feature = "std")]
+pub fn native_version() -> NativeVersion {
+	NativeVersion {
+		runtime_version: crate::VERSION,
+		can_author_with: Default::default(),
+	}
+}
+
+pub type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
+
+pub type SignedExtra = (
+	frame_system::CheckSpecVersion<Runtime>,
+	// system::CheckTxVersion<Runtime>,
+	frame_system::CheckGenesis<Runtime>,
+	frame_system::CheckEra<Runtime>,
+	frame_system::CheckNonce<Runtime>,
+	frame_system::CheckWeight<Runtime>,
+	ChargeTransactionPayment,
+	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
+	pallet_ethereum::FakeTransactionFinalizer<Runtime>,
+);
+
+/// Unchecked extrinsic type as expected by this runtime.
+pub type UncheckedExtrinsic =
+	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
+
+/// Extrinsic type that has already been checked.
+pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
+
+/// Executive: handles dispatch to the various modules.
+pub type Executive = frame_executive::Executive<
+	Runtime,
+	Block,
+	frame_system::ChainContext<Runtime>,
+	Runtime,
+	AllPalletsReversedWithSystemFirst,
+>;
+
+type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
+
+pub struct DealWithFees;
+impl OnUnbalanced<NegativeImbalance> for DealWithFees {
+	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
+		if let Some(fees) = fees_then_tips.next() {
+			// for fees, 100% to treasury
+			let mut split = fees.ration(100, 0);
+			if let Some(tips) = fees_then_tips.next() {
+				// for tips, if any, 100% to treasury
+				tips.ration_merge_into(100, 0, &mut split);
+			}
+			Treasury::on_unbalanced(split.0);
+			// Author::on_unbalanced(split.1);
+		}
+	}
+}
+
+pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
+
+impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
+	for RelayChainBlockNumberProvider<T>
+{
+	type BlockNumber = BlockNumber;
+
+	fn current_block_number() -> Self::BlockNumber {
+		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
+			.map(|d| d.relay_parent_number)
+			.unwrap_or_default()
+	}
+}
+
+pub(crate) struct CheckInherents;
+
+impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
+	fn check_inherents(
+		block: &Block,
+		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
+	) -> sp_inherents::CheckInherentsResult {
+		let relay_chain_slot = relay_state_proof
+			.read_slot()
+			.expect("Could not read the relay chain slot from the proof");
+
+		let inherent_data =
+			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
+				relay_chain_slot,
+				sp_std::time::Duration::from_secs(6),
+			)
+			.create_inherent_data()
+			.expect("Could not create the timestamp inherent data");
+
+		inherent_data.check_extrinsics(block)
+	}
+}
+
+#[derive(codec::Encode, codec::Decode)]
+pub enum XCMPMessage<XAccountId, XBalance> {
+	/// Transfer tokens to the given account from the Parachain account.
+	TransferToken(XAccountId, XBalance),
+}
addedruntime/common/runtime_apis.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/runtime_apis.rs
@@ -0,0 +1,724 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_export]
+macro_rules! dispatch_unique_runtime {
+	($collection:ident.$method:ident($($name:ident),*)) => {{
+		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
+		let dispatch = collection.as_dyn();
+
+		Ok::<_, DispatchError>(dispatch.$method($($name),*))
+	}};
+}
+
+#[macro_export]
+macro_rules! impl_common_runtime_apis {
+    (
+        $(
+            #![custom_apis]
+
+            $($custom_apis:tt)+
+        )?
+    ) => {
+        use sp_std::prelude::*;
+        use sp_api::impl_runtime_apis;
+        use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
+        use sp_runtime::{
+            Permill,
+            traits::Block as BlockT,
+            transaction_validity::{TransactionSource, TransactionValidity},
+            ApplyExtrinsicResult, DispatchError,
+        };
+        use fp_rpc::TransactionStatus;
+        use pallet_transaction_payment::{
+            FeeDetails, RuntimeDispatchInfo,
+        };
+        use pallet_evm::{
+            Runner, account::CrossAccountId as _,
+            Account as EVMAccount, FeeCalculator,
+        };
+        use runtime_common::{
+            sponsoring::{SponsorshipPredict, UniqueSponsorshipPredict},
+            dispatch::CollectionDispatch,
+            config::ethereum::CrossAccountId,
+        };
+        use up_data_structs::*;
+
+
+        impl_runtime_apis! {
+            $($($custom_apis)+)?
+
+            impl up_rpc::UniqueApi<Block, CrossAccountId, AccountId> for Runtime {
+                fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>, DispatchError> {
+                    dispatch_unique_runtime!(collection.account_tokens(account))
+                }
+                fn collection_tokens(collection: CollectionId) -> Result<Vec<TokenId>, DispatchError> {
+                    dispatch_unique_runtime!(collection.collection_tokens())
+                }
+                fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool, DispatchError> {
+                    dispatch_unique_runtime!(collection.token_exists(token))
+                }
+
+                fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
+                    dispatch_unique_runtime!(collection.token_owner(token))
+                }
+
+                fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError>  {
+                   dispatch_unique_runtime!(collection.token_owners(token))
+                }
+
+                fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
+                    let budget = up_data_structs::budget::Value::new(10);
+
+                    Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
+                }
+                fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
+                    Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
+                }
+                fn collection_properties(
+                    collection: CollectionId,
+                    keys: Option<Vec<Vec<u8>>>
+                ) -> Result<Vec<Property>, DispatchError> {
+                    let keys = keys.map(
+                        |keys| Common::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
+
+                    Common::filter_collection_properties(collection, keys)
+                }
+
+                fn token_properties(
+                    collection: CollectionId,
+                    token_id: TokenId,
+                    keys: Option<Vec<Vec<u8>>>
+                ) -> Result<Vec<Property>, DispatchError> {
+                    let keys = keys.map(
+                        |keys| Common::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
+
+                    dispatch_unique_runtime!(collection.token_properties(token_id, keys))
+                }
+
+                fn property_permissions(
+                    collection: CollectionId,
+                    keys: Option<Vec<Vec<u8>>>
+                ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
+                    let keys = keys.map(
+                        |keys| Common::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
+
+                    Common::filter_property_permissions(collection, keys)
+                }
+
+                fn token_data(
+                    collection: CollectionId,
+                    token_id: TokenId,
+                    keys: Option<Vec<Vec<u8>>>
+                ) -> Result<TokenData<CrossAccountId>, DispatchError> {
+                    let token_data = TokenData {
+                        properties: Self::token_properties(collection, token_id, keys)?,
+                        owner: Self::token_owner(collection, token_id)?,
+                        pieces: Self::total_pieces(collection, token_id)?.unwrap_or(0),
+                    };
+
+                    Ok(token_data)
+                }
+
+                fn total_supply(collection: CollectionId) -> Result<u32, DispatchError> {
+                    dispatch_unique_runtime!(collection.total_supply())
+                }
+                fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32, DispatchError> {
+                    dispatch_unique_runtime!(collection.account_balance(account))
+                }
+                fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128, DispatchError> {
+                    dispatch_unique_runtime!(collection.balance(account, token))
+                }
+                fn allowance(
+                    collection: CollectionId,
+                    sender: CrossAccountId,
+                    spender: CrossAccountId,
+                    token: TokenId,
+                ) -> Result<u128, DispatchError> {
+                    dispatch_unique_runtime!(collection.allowance(sender, spender, token))
+                }
+
+                fn adminlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::adminlist(collection))
+                }
+                fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::allowlist(collection))
+                }
+                fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::allowed(collection, user))
+                }
+                fn last_token_id(collection: CollectionId) -> Result<TokenId, DispatchError> {
+                    dispatch_unique_runtime!(collection.last_token_id())
+                }
+                fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::rpc_collection(collection))
+                }
+                fn collection_stats() -> Result<CollectionStats, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::collection_stats())
+                }
+                fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>, DispatchError> {
+                    Ok(<UniqueSponsorshipPredict<Runtime> as SponsorshipPredict<Runtime>>::predict(
+                        collection,
+                        account,
+                        token
+                    ))
+                }
+
+                fn effective_collection_limits(collection: CollectionId) -> Result<Option<CollectionLimits>, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::effective_collection_limits(collection))
+                }
+
+                fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result<Option<u128>, DispatchError> {
+                    dispatch_unique_runtime!(collection.total_pieces(token_id))
+                }
+            }
+
+            impl rmrk_rpc::RmrkApi<
+                Block,
+                AccountId,
+                RmrkCollectionInfo<AccountId>,
+                RmrkInstanceInfo<AccountId>,
+                RmrkResourceInfo,
+                RmrkPropertyInfo,
+                RmrkBaseInfo<AccountId>,
+                RmrkPartType,
+                RmrkTheme
+            > for Runtime {
+                fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>();
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn collection_properties(
+                    collection_id: RmrkCollectionId,
+                    filter_keys: Option<Vec<RmrkPropertyKey>>
+                ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn nft_properties(
+                    collection_id: RmrkCollectionId,
+                    nft_id: RmrkNftId,
+                    filter_keys: Option<Vec<RmrkPropertyKey>>
+                ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn nft_resources(collection_id: RmrkCollectionId,nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn nft_resource_priority(
+                    collection_id: RmrkCollectionId,
+                    nft_id: RmrkNftId,
+                    resource_id: RmrkResourceId
+                ) -> Result<Option<u32>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+
+                #[allow(unused_variables)]
+                fn theme(
+                    base_id: RmrkBaseId,
+                    theme_name: RmrkThemeName,
+                    filter_keys: Option<Vec<RmrkPropertyKey>>
+                ) -> Result<Option<RmrkTheme>, DispatchError> {
+                    #[cfg(feature = "rmrk")]
+                    return pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys);
+
+                    #[cfg(not(feature = "rmrk"))]
+                    return unsupported!();
+                }
+            }
+
+            impl sp_api::Core<Block> for Runtime {
+                fn version() -> RuntimeVersion {
+                    VERSION
+                }
+
+                fn execute_block(block: Block) {
+                    Executive::execute_block(block)
+                }
+
+                fn initialize_block(header: &<Block as BlockT>::Header) {
+                    Executive::initialize_block(header)
+                }
+            }
+
+            impl sp_api::Metadata<Block> for Runtime {
+                fn metadata() -> OpaqueMetadata {
+                    OpaqueMetadata::new(Runtime::metadata().into())
+                }
+            }
+
+            impl sp_block_builder::BlockBuilder<Block> for Runtime {
+                fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
+                    Executive::apply_extrinsic(extrinsic)
+                }
+
+                fn finalize_block() -> <Block as BlockT>::Header {
+                    Executive::finalize_block()
+                }
+
+                fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
+                    data.create_extrinsics()
+                }
+
+                fn check_inherents(
+                    block: Block,
+                    data: sp_inherents::InherentData,
+                ) -> sp_inherents::CheckInherentsResult {
+                    data.check_extrinsics(&block)
+                }
+
+                // fn random_seed() -> <Block as BlockT>::Hash {
+                //     RandomnessCollectiveFlip::random_seed().0
+                // }
+            }
+
+            impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
+                fn validate_transaction(
+                    source: TransactionSource,
+                    tx: <Block as BlockT>::Extrinsic,
+                    hash: <Block as BlockT>::Hash,
+                ) -> TransactionValidity {
+                    Executive::validate_transaction(source, tx, hash)
+                }
+            }
+
+            impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
+                fn offchain_worker(header: &<Block as BlockT>::Header) {
+                    Executive::offchain_worker(header)
+                }
+            }
+
+            impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
+                fn chain_id() -> u64 {
+                    <Runtime as pallet_evm::Config>::ChainId::get()
+                }
+
+                fn account_basic(address: H160) -> EVMAccount {
+                    let (account, _) = EVM::account_basic(&address);
+                    account
+                }
+
+                fn gas_price() -> U256 {
+                    let (price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
+                    price
+                }
+
+                fn account_code_at(address: H160) -> Vec<u8> {
+                    EVM::account_codes(address)
+                }
+
+                fn author() -> H160 {
+                    <pallet_evm::Pallet<Runtime>>::find_author()
+                }
+
+                fn storage_at(address: H160, index: U256) -> H256 {
+                    let mut tmp = [0u8; 32];
+                    index.to_big_endian(&mut tmp);
+                    EVM::account_storages(address, H256::from_slice(&tmp[..]))
+                }
+
+                #[allow(clippy::redundant_closure)]
+                fn call(
+                    from: H160,
+                    to: H160,
+                    data: Vec<u8>,
+                    value: U256,
+                    gas_limit: U256,
+                    max_fee_per_gas: Option<U256>,
+                    max_priority_fee_per_gas: Option<U256>,
+                    nonce: Option<U256>,
+                    estimate: bool,
+                    access_list: Option<Vec<(H160, Vec<H256>)>>,
+                ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
+                    let config = if estimate {
+                        let mut config = <Runtime as pallet_evm::Config>::config().clone();
+                        config.estimate = true;
+                        Some(config)
+                    } else {
+                        None
+                    };
+
+                    let is_transactional = false;
+                    <Runtime as pallet_evm::Config>::Runner::call(
+                        CrossAccountId::from_eth(from),
+                        to,
+                        data,
+                        value,
+                        gas_limit.low_u64(),
+                        max_fee_per_gas,
+                        max_priority_fee_per_gas,
+                        nonce,
+                        access_list.unwrap_or_default(),
+                        is_transactional,
+                        config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
+                    ).map_err(|err| err.error.into())
+                }
+
+                #[allow(clippy::redundant_closure)]
+                fn create(
+                    from: H160,
+                    data: Vec<u8>,
+                    value: U256,
+                    gas_limit: U256,
+                    max_fee_per_gas: Option<U256>,
+                    max_priority_fee_per_gas: Option<U256>,
+                    nonce: Option<U256>,
+                    estimate: bool,
+                    access_list: Option<Vec<(H160, Vec<H256>)>>,
+                ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
+                    let config = if estimate {
+                        let mut config = <Runtime as pallet_evm::Config>::config().clone();
+                        config.estimate = true;
+                        Some(config)
+                    } else {
+                        None
+                    };
+
+                    let is_transactional = false;
+                    <Runtime as pallet_evm::Config>::Runner::create(
+                        CrossAccountId::from_eth(from),
+                        data,
+                        value,
+                        gas_limit.low_u64(),
+                        max_fee_per_gas,
+                        max_priority_fee_per_gas,
+                        nonce,
+                        access_list.unwrap_or_default(),
+                        is_transactional,
+                        config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
+                    ).map_err(|err| err.error.into())
+                }
+
+                fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
+                    Ethereum::current_transaction_statuses()
+                }
+
+                fn current_block() -> Option<pallet_ethereum::Block> {
+                    Ethereum::current_block()
+                }
+
+                fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
+                    Ethereum::current_receipts()
+                }
+
+                fn current_all() -> (
+                    Option<pallet_ethereum::Block>,
+                    Option<Vec<pallet_ethereum::Receipt>>,
+                    Option<Vec<TransactionStatus>>
+                ) {
+                    (
+                        Ethereum::current_block(),
+                        Ethereum::current_receipts(),
+                        Ethereum::current_transaction_statuses()
+                    )
+                }
+
+                fn extrinsic_filter(xts: Vec<<Block as sp_api::BlockT>::Extrinsic>) -> Vec<pallet_ethereum::Transaction> {
+                    xts.into_iter().filter_map(|xt| match xt.0.function {
+                        Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction),
+                        _ => None
+                    }).collect()
+                }
+
+                fn elasticity() -> Option<Permill> {
+                    None
+                }
+            }
+
+            impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
+                fn convert_transaction(transaction: pallet_ethereum::Transaction) -> <Block as BlockT>::Extrinsic  {
+                    UncheckedExtrinsic::new_unsigned(
+                        pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
+                    )
+                }
+            }
+
+            impl sp_session::SessionKeys<Block> for Runtime {
+                fn decode_session_keys(
+                    encoded: Vec<u8>,
+                ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
+                    SessionKeys::decode_into_raw_public_keys(&encoded)
+                }
+
+                fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
+                    SessionKeys::generate(seed)
+                }
+            }
+
+            impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
+                fn slot_duration() -> sp_consensus_aura::SlotDuration {
+                    sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
+                }
+
+                fn authorities() -> Vec<AuraId> {
+                    Aura::authorities().to_vec()
+                }
+            }
+
+            impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
+                fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
+                    ParachainSystem::collect_collation_info(header)
+                }
+            }
+
+            impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
+                fn account_nonce(account: AccountId) -> Index {
+                    System::account_nonce(account)
+                }
+            }
+
+            impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
+                fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
+                    TransactionPayment::query_info(uxt, len)
+                }
+                fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {
+                    TransactionPayment::query_fee_details(uxt, len)
+                }
+            }
+
+            /*
+            impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash>
+                for Runtime
+            {
+                fn call(
+                    origin: AccountId,
+                    dest: AccountId,
+                    value: Balance,
+                    gas_limit: u64,
+                    input_data: Vec<u8>,
+                ) -> pallet_contracts_primitives::ContractExecResult {
+                    Contracts::bare_call(origin, dest, value, gas_limit, input_data, false)
+                }
+
+                fn instantiate(
+                    origin: AccountId,
+                    endowment: Balance,
+                    gas_limit: u64,
+                    code: pallet_contracts_primitives::Code<Hash>,
+                    data: Vec<u8>,
+                    salt: Vec<u8>,
+                ) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, BlockNumber>
+                {
+                    Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true, false)
+                }
+
+                fn get_storage(
+                    address: AccountId,
+                    key: [u8; 32],
+                ) -> pallet_contracts_primitives::GetStorageResult {
+                    Contracts::get_storage(address, key)
+                }
+
+                fn rent_projection(
+                    address: AccountId,
+                ) -> pallet_contracts_primitives::RentProjectionResult<BlockNumber> {
+                    Contracts::rent_projection(address)
+                }
+            }
+            */
+
+            #[cfg(feature = "runtime-benchmarks")]
+            impl frame_benchmarking::Benchmark<Block> for Runtime {
+                fn benchmark_metadata(extra: bool) -> (
+                    Vec<frame_benchmarking::BenchmarkList>,
+                    Vec<frame_support::traits::StorageInfo>,
+                ) {
+                    use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
+                    use frame_support::traits::StorageInfoTrait;
+
+                    let mut list = Vec::<BenchmarkList>::new();
+
+                    list_benchmark!(list, extra, pallet_evm_migration, EvmMigration);
+                    list_benchmark!(list, extra, pallet_common, Common);
+                    list_benchmark!(list, extra, pallet_unique, Unique);
+                    list_benchmark!(list, extra, pallet_structure, Structure);
+                    list_benchmark!(list, extra, pallet_inflation, Inflation);
+                    list_benchmark!(list, extra, pallet_fungible, Fungible);
+                    list_benchmark!(list, extra, pallet_refungible, Refungible);
+                    list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
+                    list_benchmark!(list, extra, pallet_unique_scheduler, Scheduler);
+
+                    #[cfg(not(feature = "unique-runtime"))]
+                    list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);
+
+                    #[cfg(not(feature = "unique-runtime"))]
+                    list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip);
+
+                    // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);
+
+                    let storage_info = AllPalletsReversedWithSystemFirst::storage_info();
+
+                    return (list, storage_info)
+                }
+
+                fn dispatch_benchmark(
+                    config: frame_benchmarking::BenchmarkConfig
+                ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
+                    use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
+
+                    let allowlist: Vec<TrackedStorageKey> = vec![
+                        // Total Issuance
+                        hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
+
+                        // Block Number
+                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
+                        // Execution Phase
+                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
+                        // Event Count
+                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
+                        // System Events
+                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
+
+                        // Evm CurrentLogs
+                        hex_literal::hex!("1da53b775b270400e7e61ed5cbc5a146547f210cec367e9af919603343b9cb56").to_vec().into(),
+
+                        // Transactional depth
+                        hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a").to_vec().into(),
+                    ];
+
+                    let mut batches = Vec::<BenchmarkBatch>::new();
+                    let params = (&config, &allowlist);
+
+                    add_benchmark!(params, batches, pallet_evm_migration, EvmMigration);
+                    add_benchmark!(params, batches, pallet_common, Common);
+                    add_benchmark!(params, batches, pallet_unique, Unique);
+                    add_benchmark!(params, batches, pallet_structure, Structure);
+                    add_benchmark!(params, batches, pallet_inflation, Inflation);
+                    add_benchmark!(params, batches, pallet_fungible, Fungible);
+                    add_benchmark!(params, batches, pallet_refungible, Refungible);
+                    add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
+                    add_benchmark!(params, batches, pallet_unique_scheduler, Scheduler);
+
+                    #[cfg(not(feature = "unique-runtime"))]
+                    add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);
+
+                    #[cfg(not(feature = "unique-runtime"))]
+                    add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip);
+
+                    // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);
+
+                    if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
+                    Ok(batches)
+                }
+            }
+
+            #[cfg(feature = "try-runtime")]
+            impl frame_try_runtime::TryRuntime<Block> for Runtime {
+                fn on_runtime_upgrade() -> (Weight, Weight) {
+                    log::info!("try-runtime::on_runtime_upgrade unique-chain.");
+                    let weight = Executive::try_runtime_upgrade().unwrap();
+                    (weight, RuntimeBlockWeights::get().max_block)
+                }
+
+                fn execute_block_no_check(block: Block) -> Weight {
+                    Executive::execute_block_no_check(block)
+                }
+            }
+        }
+    }
+}
addedruntime/common/scheduler.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/scheduler.rs
@@ -0,0 +1,141 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use frame_support::{
+	traits::NamedReservableCurrency,
+	weights::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},
+};
+use sp_runtime::{
+	traits::{Dispatchable, Applyable, Member},
+	generic::Era,
+	transaction_validity::TransactionValidityError,
+	DispatchErrorWithPostInfo, DispatchError,
+};
+use crate::{Runtime, Call, Origin, Balances, ChargeTransactionPayment};
+use up_common::types::{AccountId, Balance};
+use fp_self_contained::SelfContainedCall;
+use pallet_unique_scheduler::DispatchCall;
+
+/// The SignedExtension to the basic transaction logic.
+pub type SignedExtraScheduler = (
+	frame_system::CheckSpecVersion<Runtime>,
+	frame_system::CheckGenesis<Runtime>,
+	frame_system::CheckEra<Runtime>,
+	frame_system::CheckNonce<Runtime>,
+	frame_system::CheckWeight<Runtime>,
+);
+
+fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
+	(
+		frame_system::CheckSpecVersion::<Runtime>::new(),
+		frame_system::CheckGenesis::<Runtime>::new(),
+		frame_system::CheckEra::<Runtime>::from(Era::Immortal),
+		frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
+			from,
+		)),
+		frame_system::CheckWeight::<Runtime>::new(),
+		// sponsoring transaction logic
+		// pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
+	)
+}
+
+pub struct SchedulerPaymentExecutor;
+
+impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
+	DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
+where
+	<T as frame_system::Config>::Call: Member
+		+ Dispatchable<Origin = Origin, Info = DispatchInfo>
+		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
+		+ GetDispatchInfo
+		+ From<frame_system::Call<Runtime>>,
+	SelfContainedSignedInfo: Send + Sync + 'static,
+	Call: From<<T as frame_system::Config>::Call>
+		+ From<<T as pallet_unique_scheduler::Config>::Call>
+		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
+	sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
+{
+	fn dispatch_call(
+		signer: <T as frame_system::Config>::AccountId,
+		call: <T as pallet_unique_scheduler::Config>::Call,
+	) -> Result<
+		Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
+		TransactionValidityError,
+	> {
+		let dispatch_info = call.get_dispatch_info();
+		let extrinsic = fp_self_contained::CheckedExtrinsic::<
+			AccountId,
+			Call,
+			SignedExtraScheduler,
+			SelfContainedSignedInfo,
+		> {
+			signed: fp_self_contained::CheckedSignature::<
+				AccountId,
+				SignedExtraScheduler,
+				SelfContainedSignedInfo,
+			>::Signed(signer.clone().into(), get_signed_extras(signer.into())),
+			function: call.into(),
+		};
+
+		extrinsic.apply::<Runtime>(&dispatch_info, 0)
+	}
+
+	fn reserve_balance(
+		id: [u8; 16],
+		sponsor: <T as frame_system::Config>::AccountId,
+		call: <T as pallet_unique_scheduler::Config>::Call,
+		count: u32,
+	) -> Result<(), DispatchError> {
+		let dispatch_info = call.get_dispatch_info();
+		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
+			.saturating_mul(count.into());
+
+		<Balances as NamedReservableCurrency<AccountId>>::reserve_named(
+			&id,
+			&(sponsor.into()),
+			weight,
+		)
+	}
+
+	fn pay_for_call(
+		id: [u8; 16],
+		sponsor: <T as frame_system::Config>::AccountId,
+		call: <T as pallet_unique_scheduler::Config>::Call,
+	) -> Result<u128, DispatchError> {
+		let dispatch_info = call.get_dispatch_info();
+		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
+		Ok(
+			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
+				&id,
+				&(sponsor.into()),
+				weight,
+			),
+		)
+	}
+
+	fn cancel_reserve(
+		id: [u8; 16],
+		sponsor: <T as frame_system::Config>::AccountId,
+	) -> Result<u128, DispatchError> {
+		Ok(
+			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
+				&id,
+				&(sponsor.into()),
+				u128::MAX,
+			),
+		)
+	}
+}
addedruntime/common/sponsoring.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/sponsoring.rs
@@ -0,0 +1,359 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use core::marker::PhantomData;
+use up_sponsorship::SponsorshipHandler;
+use frame_support::{
+	traits::{IsSubType},
+	storage::{StorageMap, StorageDoubleMap, StorageNMap},
+};
+use up_data_structs::{
+	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
+	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,
+};
+use sp_runtime::traits::Saturating;
+use pallet_common::{CollectionHandle};
+use pallet_evm::account::CrossAccountId;
+use pallet_unique::{
+	Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
+	NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
+	NftTransferBasket, TokenPropertyBasket,
+};
+use pallet_fungible::Config as FungibleConfig;
+use pallet_nonfungible::Config as NonfungibleConfig;
+use pallet_refungible::Config as RefungibleConfig;
+
+pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+impl<T> Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+
+// TODO: permission check?
+pub fn withdraw_set_token_property<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::CrossAccountId,
+	item_id: &TokenId,
+	data_size: usize,
+) -> Option<()> {
+	// preliminary sponsoring correctness check
+	match collection.mode {
+		CollectionMode::NFT => {
+			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
+			if !owner.conv_eq(who) {
+				return None;
+			}
+		}
+		CollectionMode::Fungible(_) => {
+			// Fungible tokens have no properties
+			return None;
+		}
+		CollectionMode::ReFungible => {
+			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
+				return None;
+			}
+		}
+	}
+
+	if data_size > collection.limits.sponsored_data_size() as usize {
+		return None;
+	}
+
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection.limits.sponsored_data_rate_limit()?;
+
+	if let Some(last_tx_block) = TokenPropertyBasket::<T>::get(collection.id, item_id) {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
+
+	<TokenPropertyBasket<T>>::insert(collection.id, item_id, block_number);
+
+	Some(())
+}
+
+pub fn withdraw_transfer<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::CrossAccountId,
+	item_id: &TokenId,
+) -> Option<()> {
+	// preliminary sponsoring correctness check
+	match collection.mode {
+		CollectionMode::NFT => {
+			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
+			if !owner.conv_eq(who) {
+				return None;
+			}
+		}
+		CollectionMode::Fungible(_) => {
+			if item_id != &TokenId::default() {
+				return None;
+			}
+			if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
+				return None;
+			}
+		}
+		CollectionMode::ReFungible => {
+			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
+				return None;
+			}
+		}
+	}
+
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection
+		.limits
+		.sponsor_transfer_timeout(match collection.mode {
+			CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
+			CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+			CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+		});
+
+	let last_tx_block = match collection.mode {
+		CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),
+		CollectionMode::Fungible(_) => {
+			<FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
+		}
+		CollectionMode::ReFungible => {
+			<ReFungibleTransferBasket<T>>::get((collection.id, item_id, who.as_sub()))
+		}
+	};
+
+	if let Some(last_tx_block) = last_tx_block {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
+
+	match collection.mode {
+		CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),
+		CollectionMode::Fungible(_) => {
+			<FungibleTransferBasket<T>>::insert(collection.id, who.as_sub(), block_number)
+		}
+		CollectionMode::ReFungible => <ReFungibleTransferBasket<T>>::insert(
+			(collection.id, item_id, who.as_sub()),
+			block_number,
+		),
+	};
+
+	Some(())
+}
+
+pub fn withdraw_create_item<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::CrossAccountId,
+	properties: &CreateItemData,
+) -> Option<()> {
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection
+		.limits
+		.sponsor_transfer_timeout(match properties {
+			CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
+			CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+			CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+		});
+
+	if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, who.as_sub())) {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
+
+	CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);
+
+	Some(())
+}
+
+pub fn withdraw_approve<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::AccountId,
+	item_id: &TokenId,
+) -> Option<()> {
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection.limits.sponsor_approve_timeout();
+
+	let last_tx_block = match collection.mode {
+		CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),
+		CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),
+		CollectionMode::ReFungible => {
+			<RefungibleApproveBasket<T>>::get((collection.id, item_id, who))
+		}
+	};
+
+	if let Some(last_tx_block) = last_tx_block {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
+
+	match collection.mode {
+		CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),
+		CollectionMode::Fungible(_) => {
+			<FungibleApproveBasket<T>>::insert(collection.id, who, block_number)
+		}
+		CollectionMode::ReFungible => {
+			<RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)
+		}
+	};
+
+	Some(())
+}
+
+fn load<T: UniqueConfig>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {
+	let collection = CollectionHandle::new(id)?;
+	let sponsor = collection.sponsorship.sponsor().cloned()?;
+	Some((sponsor, collection))
+}
+
+pub struct UniqueSponsorshipHandler<T>(PhantomData<T>);
+impl<T, C> SponsorshipHandler<T::AccountId, C> for UniqueSponsorshipHandler<T>
+where
+	T: Config,
+	C: IsSubType<UniqueCall<T>>,
+{
+	fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
+		match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {
+			UniqueCall::set_token_properties {
+				collection_id,
+				token_id,
+				properties,
+				..
+			} => {
+				let (sponsor, collection) = load::<T>(*collection_id)?;
+				withdraw_set_token_property(
+					&collection,
+					&T::CrossAccountId::from_sub(who.clone()),
+					&token_id,
+					// No overflow may happen, as data larger than usize can't reach here
+					properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
+				)
+				.map(|()| sponsor)
+			}
+			UniqueCall::create_item {
+				collection_id,
+				data,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_create_item::<T>(
+					&collection,
+					&T::CrossAccountId::from_sub(who.clone()),
+					data,
+				)
+				.map(|()| sponsor)
+			}
+			UniqueCall::transfer {
+				collection_id,
+				item_id,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_transfer::<T>(
+					&collection,
+					&T::CrossAccountId::from_sub(who.clone()),
+					item_id,
+				)
+				.map(|()| sponsor)
+			}
+			UniqueCall::transfer_from {
+				collection_id,
+				item_id,
+				from,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)
+			}
+			UniqueCall::approve {
+				collection_id,
+				item_id,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
+			}
+			_ => None,
+		}
+	}
+}
+
+pub trait SponsorshipPredict<T: Config> {
+	fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option<u64>
+	where
+		u64: From<<T as frame_system::Config>::BlockNumber>;
+}
+
+pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
+
+impl<T: Config> SponsorshipPredict<T> for UniqueSponsorshipPredict<T> {
+	fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option<u64>
+	where
+		u64: From<<T as frame_system::Config>::BlockNumber>,
+	{
+		let collection = <CollectionHandle<T>>::try_get(collection_id).ok()?;
+		let _ = collection.sponsorship.sponsor()?;
+
+		// sponsor timeout
+		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+		let limit = collection
+			.limits
+			.sponsor_transfer_timeout(match collection.mode {
+				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
+				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+			});
+
+		let last_tx_block = match collection.mode {
+			CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, token),
+			CollectionMode::Fungible(_) => {
+				<FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
+			}
+			CollectionMode::ReFungible => {
+				<ReFungibleTransferBasket<T>>::get((collection.id, token, who.as_sub()))
+			}
+		};
+
+		if let Some(last_tx_block) = last_tx_block {
+			return Some(
+				last_tx_block
+					.saturating_add(limit.into())
+					.saturating_sub(block_number)
+					.into(),
+			);
+		}
+
+		let token_exists = match collection.mode {
+			CollectionMode::NFT => {
+				<pallet_nonfungible::TokenData<T>>::contains_key((collection.id, token))
+			}
+			CollectionMode::Fungible(_) => token == TokenId::default(),
+			CollectionMode::ReFungible => {
+				<pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
+			}
+		};
+
+		if token_exists {
+			Some(0)
+		} else {
+			None
+		}
+	}
+}
deletedruntime/common/src/constants.rsdiffbeforeafterboth
--- a/runtime/common/src/constants.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_runtime::Perbill;
-use frame_support::{
-	parameter_types,
-	weights::{Weight, constants::WEIGHT_PER_SECOND},
-};
-use crate::types::{BlockNumber, Balance};
-
-pub const MILLISECS_PER_BLOCK: u64 = 12000;
-
-pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
-
-// These time units are defined in number of blocks.
-pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
-pub const HOURS: BlockNumber = MINUTES * 60;
-pub const DAYS: BlockNumber = HOURS * 24;
-
-pub const MICROUNIQUE: Balance = 1_000_000_000_000;
-pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
-pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
-pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
-
-// Targeting 0.1 UNQ per transfer
-pub const WEIGHT_TO_FEE_COEFF: u32 = 207_890_902;
-
-// Targeting 0.15 UNQ per transfer via ETH
-pub const MIN_GAS_PRICE: u64 = 1_019_493_469_850;
-
-/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
-/// This is used to limit the maximal weight of a single extrinsic.
-pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
-/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used
-/// by  Operational  extrinsics.
-pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
-/// We allow for 2 seconds of compute with a 6 second average block time.
-pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
-
-parameter_types! {
-	pub const DefaultSponsoringRateLimit: BlockNumber = 1 * DAYS;
-
-	pub const TransactionByteFee: Balance = 501 * MICROUNIQUE;
-}
deletedruntime/common/src/dispatch.rsdiffbeforeafterboth
--- a/runtime/common/src/dispatch.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use frame_support::{dispatch::DispatchResult, ensure};
-use pallet_evm::{PrecompileHandle, PrecompileResult};
-use sp_core::H160;
-use sp_runtime::DispatchError;
-use sp_std::{borrow::ToOwned, vec::Vec};
-use pallet_common::{
-	CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,
-	eth::map_eth_to_id,
-};
-pub use pallet_common::dispatch::CollectionDispatch;
-use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
-use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
-use pallet_refungible::{
-	Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
-};
-use up_data_structs::{
-	CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
-	CollectionId,
-};
-
-pub enum CollectionDispatchT<T>
-where
-	T: pallet_fungible::Config + pallet_nonfungible::Config + pallet_refungible::Config,
-{
-	Fungible(FungibleHandle<T>),
-	Nonfungible(NonfungibleHandle<T>),
-	Refungible(RefungibleHandle<T>),
-}
-impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
-where
-	T: pallet_common::Config
-		+ pallet_unique::Config
-		+ pallet_fungible::Config
-		+ pallet_nonfungible::Config
-		+ pallet_refungible::Config,
-{
-	fn create(
-		sender: T::CrossAccountId,
-		data: CreateCollectionData<T::AccountId>,
-	) -> Result<CollectionId, DispatchError> {
-		let id = match data.mode {
-			CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
-			CollectionMode::Fungible(decimal_points) => {
-				// check params
-				ensure!(
-					decimal_points <= MAX_DECIMAL_POINTS,
-					pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
-				);
-				<PalletFungible<T>>::init_collection(sender, data)?
-			}
-			CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
-		};
-		Ok(id)
-	}
-
-	fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {
-		match collection.mode {
-			CollectionMode::ReFungible => {
-				PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?
-			}
-			CollectionMode::Fungible(_) => {
-				PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?
-			}
-			CollectionMode::NFT => {
-				PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?
-			}
-		}
-		Ok(())
-	}
-
-	fn dispatch(handle: CollectionHandle<T>) -> Self {
-		match handle.mode {
-			CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
-			CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
-			CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
-		}
-	}
-
-	fn into_inner(self) -> CollectionHandle<T> {
-		match self {
-			Self::Fungible(f) => f.into_inner(),
-			Self::Nonfungible(f) => f.into_inner(),
-			Self::Refungible(f) => f.into_inner(),
-		}
-	}
-
-	fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
-		match self {
-			Self::Fungible(h) => h,
-			Self::Nonfungible(h) => h,
-			Self::Refungible(h) => h,
-		}
-	}
-}
-
-impl<T> pallet_evm::OnMethodCall<T> for CollectionDispatchT<T>
-where
-	T: pallet_common::Config
-		+ pallet_unique::Config
-		+ pallet_fungible::Config
-		+ pallet_nonfungible::Config
-		+ pallet_refungible::Config,
-	T::AccountId: From<[u8; 32]>,
-{
-	fn is_reserved(target: &H160) -> bool {
-		map_eth_to_id(target).is_some()
-	}
-	fn is_used(target: &H160) -> bool {
-		map_eth_to_id(target)
-			.map(<CollectionById<T>>::contains_key)
-			.unwrap_or(false)
-	}
-	fn get_code(target: &H160) -> Option<Vec<u8>> {
-		if let Some(collection_id) = map_eth_to_id(target) {
-			let collection = <CollectionById<T>>::get(collection_id)?;
-			Some(
-				match collection.mode {
-					CollectionMode::NFT => <NonfungibleHandle<T>>::CODE,
-					CollectionMode::Fungible(_) => <FungibleHandle<T>>::CODE,
-					CollectionMode::ReFungible => <RefungibleHandle<T>>::CODE,
-				}
-				.to_owned(),
-			)
-		} else if let Some((collection_id, _token_id)) =
-			<T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(target)
-		{
-			let collection = <CollectionById<T>>::get(collection_id)?;
-			if collection.mode != CollectionMode::ReFungible {
-				return None;
-			}
-			// TODO: check token existence
-			Some(<RefungibleTokenHandle<T>>::CODE.to_owned())
-		} else {
-			None
-		}
-	}
-	fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
-		if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
-			let collection =
-				<CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
-			let dispatched = Self::dispatch(collection);
-
-			match dispatched {
-				Self::Fungible(h) => h.call(handle),
-				Self::Nonfungible(h) => h.call(handle),
-				Self::Refungible(h) => h.call(handle),
-			}
-		} else if let Some((collection_id, token_id)) =
-			<T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
-				&handle.code_address(),
-			) {
-			let collection =
-				<CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
-			if collection.mode != CollectionMode::ReFungible {
-				return None;
-			}
-
-			let h = RefungibleHandle::cast(collection);
-			// TODO: check token existence
-			RefungibleTokenHandle(h, token_id).call(handle)
-		} else {
-			None
-		}
-	}
-}
deletedruntime/common/src/eth_sponsoring.rsdiffbeforeafterboth
--- a/runtime/common/src/eth_sponsoring.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-//! Implements EVM sponsoring logic via TransactionValidityHack
-
-use evm_coder::{Call, abi::AbiReader};
-use pallet_common::{CollectionHandle, eth::map_eth_to_id};
-use sp_core::H160;
-use sp_std::prelude::*;
-use up_sponsorship::SponsorshipHandler;
-use core::marker::PhantomData;
-use core::convert::TryInto;
-use pallet_evm::account::CrossAccountId;
-use up_data_structs::{TokenId, CreateItemData, CreateNftData, CollectionMode};
-use pallet_unique::Config as UniqueConfig;
-
-use crate::sponsoring::*;
-
-use pallet_nonfungible::erc::{
-	UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call, TokenPropertiesCall,
-};
-use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
-use pallet_fungible::Config as FungibleConfig;
-use pallet_nonfungible::Config as NonfungibleConfig;
-use pallet_refungible::Config as RefungibleConfig;
-
-pub struct UniqueEthSponsorshipHandler<T: UniqueConfig>(PhantomData<*const T>);
-impl<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>
-	SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)> for UniqueEthSponsorshipHandler<T>
-{
-	fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {
-		let collection_id = map_eth_to_id(&call.0)?;
-		let collection = <CollectionHandle<T>>::new(collection_id)?;
-		let sponsor = collection.sponsorship.sponsor()?.clone();
-		let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
-		Some(T::CrossAccountId::from_sub(match &collection.mode {
-			CollectionMode::NFT => {
-				let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
-				match call {
-					UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty {
-						token_id,
-						key,
-						value,
-						..
-					}) => {
-						let token_id: TokenId = token_id.try_into().ok()?;
-						withdraw_set_token_property::<T>(
-							&collection,
-							&who,
-							&token_id,
-							key.len() + value.len(),
-						)
-						.map(|()| sponsor)
-					}
-					UniqueNFTCall::ERC721UniqueExtensions(
-						ERC721UniqueExtensionsCall::Transfer { token_id, .. },
-					) => {
-						let token_id: TokenId = token_id.try_into().ok()?;
-						withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
-					}
-					UniqueNFTCall::ERC721Mintable(
-						ERC721MintableCall::Mint { token_id, .. }
-						| ERC721MintableCall::MintWithTokenUri { token_id, .. },
-					) => {
-						let _token_id: TokenId = token_id.try_into().ok()?;
-						withdraw_create_item::<T>(
-							&collection,
-							&who,
-							&CreateItemData::NFT(CreateNftData::default()),
-						)
-						.map(|()| sponsor)
-					}
-					UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, from, .. }) => {
-						let token_id: TokenId = token_id.try_into().ok()?;
-						let from = T::CrossAccountId::from_eth(from);
-						withdraw_transfer::<T>(&collection, &from, &token_id).map(|()| sponsor)
-					}
-					UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {
-						let token_id: TokenId = token_id.try_into().ok()?;
-						withdraw_approve::<T>(&collection, who.as_sub(), &token_id)
-							.map(|()| sponsor)
-					}
-					_ => None,
-				}
-			}
-			CollectionMode::Fungible(_) => {
-				let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
-				#[allow(clippy::single_match)]
-				match call {
-					UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
-						withdraw_transfer::<T>(&collection, who, &TokenId::default())
-							.map(|()| sponsor)
-					}
-					UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => {
-						let from = T::CrossAccountId::from_eth(from);
-						withdraw_transfer::<T>(&collection, &from, &TokenId::default())
-							.map(|()| sponsor)
-					}
-					UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {
-						withdraw_approve::<T>(&collection, who.as_sub(), &TokenId::default())
-							.map(|()| sponsor)
-					}
-					_ => None,
-				}
-			}
-			_ => None,
-		}?))
-	}
-}
deletedruntime/common/src/lib.rsdiffbeforeafterboth
--- a/runtime/common/src/lib.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-pub mod constants;
-pub mod dispatch;
-pub mod eth_sponsoring;
-pub mod runtime_apis;
-pub mod sponsoring;
-pub mod types;
-pub mod weights;
deletedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ /dev/null
@@ -1,546 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#[macro_export]
-macro_rules! impl_common_runtime_apis {
-    (
-        $(
-            #![custom_apis]
-
-            $($custom_apis:tt)+
-        )?
-    ) => {
-        impl_runtime_apis! {
-            $($($custom_apis)+)?
-
-            impl up_rpc::UniqueApi<Block, CrossAccountId, AccountId> for Runtime {
-                fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>, DispatchError> {
-                    dispatch_unique_runtime!(collection.account_tokens(account))
-                }
-                fn collection_tokens(collection: CollectionId) -> Result<Vec<TokenId>, DispatchError> {
-                    dispatch_unique_runtime!(collection.collection_tokens())
-                }
-                fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool, DispatchError> {
-                    dispatch_unique_runtime!(collection.token_exists(token))
-                }
-
-                fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
-                    dispatch_unique_runtime!(collection.token_owner(token))
-                }
-
-                fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError>  {
-                   dispatch_unique_runtime!(collection.token_owners(token))
-                }
-
-                fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
-                    let budget = up_data_structs::budget::Value::new(10);
-
-                    Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
-                }
-                fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
-                    Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
-                }
-                fn collection_properties(
-                    collection: CollectionId,
-                    keys: Option<Vec<Vec<u8>>>
-                ) -> Result<Vec<Property>, DispatchError> {
-                    let keys = keys.map(
-                        |keys| Common::bytes_keys_to_property_keys(keys)
-                    ).transpose()?;
-
-                    Common::filter_collection_properties(collection, keys)
-                }
-
-                fn token_properties(
-                    collection: CollectionId,
-                    token_id: TokenId,
-                    keys: Option<Vec<Vec<u8>>>
-                ) -> Result<Vec<Property>, DispatchError> {
-                    let keys = keys.map(
-                        |keys| Common::bytes_keys_to_property_keys(keys)
-                    ).transpose()?;
-
-                    dispatch_unique_runtime!(collection.token_properties(token_id, keys))
-                }
-
-                fn property_permissions(
-                    collection: CollectionId,
-                    keys: Option<Vec<Vec<u8>>>
-                ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
-                    let keys = keys.map(
-                        |keys| Common::bytes_keys_to_property_keys(keys)
-                    ).transpose()?;
-
-                    Common::filter_property_permissions(collection, keys)
-                }
-
-                fn token_data(
-                    collection: CollectionId,
-                    token_id: TokenId,
-                    keys: Option<Vec<Vec<u8>>>
-                ) -> Result<TokenData<CrossAccountId>, DispatchError> {
-                    let token_data = TokenData {
-                        properties: Self::token_properties(collection, token_id, keys)?,
-                        owner: Self::token_owner(collection, token_id)?,
-                        pieces: Self::total_pieces(collection, token_id)?.unwrap_or(0),
-                    };
-
-                    Ok(token_data)
-                }
-
-                fn total_supply(collection: CollectionId) -> Result<u32, DispatchError> {
-                    dispatch_unique_runtime!(collection.total_supply())
-                }
-                fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32, DispatchError> {
-                    dispatch_unique_runtime!(collection.account_balance(account))
-                }
-                fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128, DispatchError> {
-                    dispatch_unique_runtime!(collection.balance(account, token))
-                }
-                fn allowance(
-                    collection: CollectionId,
-                    sender: CrossAccountId,
-                    spender: CrossAccountId,
-                    token: TokenId,
-                ) -> Result<u128, DispatchError> {
-                    dispatch_unique_runtime!(collection.allowance(sender, spender, token))
-                }
-
-                fn adminlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::adminlist(collection))
-                }
-                fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::allowlist(collection))
-                }
-                fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::allowed(collection, user))
-                }
-                fn last_token_id(collection: CollectionId) -> Result<TokenId, DispatchError> {
-                    dispatch_unique_runtime!(collection.last_token_id())
-                }
-                fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::rpc_collection(collection))
-                }
-                fn collection_stats() -> Result<CollectionStats, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::collection_stats())
-                }
-                fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>, DispatchError> {
-                    Ok(<$crate::sponsoring::UniqueSponsorshipPredict<Runtime> as
-                            $crate::sponsoring::SponsorshipPredict<Runtime>>::predict(
-                        collection,
-                        account,
-                        token))
-                }
-
-                fn effective_collection_limits(collection: CollectionId) -> Result<Option<CollectionLimits>, DispatchError> {
-                    Ok(<pallet_common::Pallet<Runtime>>::effective_collection_limits(collection))
-                }
-
-                fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result<Option<u128>, DispatchError> {
-                    dispatch_unique_runtime!(collection.total_pieces(token_id))
-                }
-            }
-
-            impl sp_api::Core<Block> for Runtime {
-                fn version() -> RuntimeVersion {
-                    VERSION
-                }
-
-                fn execute_block(block: Block) {
-                    Executive::execute_block(block)
-                }
-
-                fn initialize_block(header: &<Block as BlockT>::Header) {
-                    Executive::initialize_block(header)
-                }
-            }
-
-            impl sp_api::Metadata<Block> for Runtime {
-                fn metadata() -> OpaqueMetadata {
-                    OpaqueMetadata::new(Runtime::metadata().into())
-                }
-            }
-
-            impl sp_block_builder::BlockBuilder<Block> for Runtime {
-                fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
-                    Executive::apply_extrinsic(extrinsic)
-                }
-
-                fn finalize_block() -> <Block as BlockT>::Header {
-                    Executive::finalize_block()
-                }
-
-                fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
-                    data.create_extrinsics()
-                }
-
-                fn check_inherents(
-                    block: Block,
-                    data: sp_inherents::InherentData,
-                ) -> sp_inherents::CheckInherentsResult {
-                    data.check_extrinsics(&block)
-                }
-
-                // fn random_seed() -> <Block as BlockT>::Hash {
-                //     RandomnessCollectiveFlip::random_seed().0
-                // }
-            }
-
-            impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
-                fn validate_transaction(
-                    source: TransactionSource,
-                    tx: <Block as BlockT>::Extrinsic,
-                    hash: <Block as BlockT>::Hash,
-                ) -> TransactionValidity {
-                    Executive::validate_transaction(source, tx, hash)
-                }
-            }
-
-            impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
-                fn offchain_worker(header: &<Block as BlockT>::Header) {
-                    Executive::offchain_worker(header)
-                }
-            }
-
-            impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
-                fn chain_id() -> u64 {
-                    <Runtime as pallet_evm::Config>::ChainId::get()
-                }
-
-                fn account_basic(address: H160) -> EVMAccount {
-                    let (account, _) = EVM::account_basic(&address);
-                    account
-                }
-
-                fn gas_price() -> U256 {
-                    let (price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
-                    price
-                }
-
-                fn account_code_at(address: H160) -> Vec<u8> {
-                    EVM::account_codes(address)
-                }
-
-                fn author() -> H160 {
-                    <pallet_evm::Pallet<Runtime>>::find_author()
-                }
-
-                fn storage_at(address: H160, index: U256) -> H256 {
-                    let mut tmp = [0u8; 32];
-                    index.to_big_endian(&mut tmp);
-                    EVM::account_storages(address, H256::from_slice(&tmp[..]))
-                }
-
-                #[allow(clippy::redundant_closure)]
-                fn call(
-                    from: H160,
-                    to: H160,
-                    data: Vec<u8>,
-                    value: U256,
-                    gas_limit: U256,
-                    max_fee_per_gas: Option<U256>,
-                    max_priority_fee_per_gas: Option<U256>,
-                    nonce: Option<U256>,
-                    estimate: bool,
-                    access_list: Option<Vec<(H160, Vec<H256>)>>,
-                ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
-                    let config = if estimate {
-                        let mut config = <Runtime as pallet_evm::Config>::config().clone();
-                        config.estimate = true;
-                        Some(config)
-                    } else {
-                        None
-                    };
-
-                    let is_transactional = false;
-                    <Runtime as pallet_evm::Config>::Runner::call(
-                        CrossAccountId::from_eth(from),
-                        to,
-                        data,
-                        value,
-                        gas_limit.low_u64(),
-                        max_fee_per_gas,
-                        max_priority_fee_per_gas,
-                        nonce,
-                        access_list.unwrap_or_default(),
-                        is_transactional,
-                        config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
-                    ).map_err(|err| err.error.into())
-                }
-
-                #[allow(clippy::redundant_closure)]
-                fn create(
-                    from: H160,
-                    data: Vec<u8>,
-                    value: U256,
-                    gas_limit: U256,
-                    max_fee_per_gas: Option<U256>,
-                    max_priority_fee_per_gas: Option<U256>,
-                    nonce: Option<U256>,
-                    estimate: bool,
-                    access_list: Option<Vec<(H160, Vec<H256>)>>,
-                ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
-                    let config = if estimate {
-                        let mut config = <Runtime as pallet_evm::Config>::config().clone();
-                        config.estimate = true;
-                        Some(config)
-                    } else {
-                        None
-                    };
-
-                    let is_transactional = false;
-                    <Runtime as pallet_evm::Config>::Runner::create(
-                        CrossAccountId::from_eth(from),
-                        data,
-                        value,
-                        gas_limit.low_u64(),
-                        max_fee_per_gas,
-                        max_priority_fee_per_gas,
-                        nonce,
-                        access_list.unwrap_or_default(),
-                        is_transactional,
-                        config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
-                    ).map_err(|err| err.error.into())
-                }
-
-                fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
-                    Ethereum::current_transaction_statuses()
-                }
-
-                fn current_block() -> Option<pallet_ethereum::Block> {
-                    Ethereum::current_block()
-                }
-
-                fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
-                    Ethereum::current_receipts()
-                }
-
-                fn current_all() -> (
-                    Option<pallet_ethereum::Block>,
-                    Option<Vec<pallet_ethereum::Receipt>>,
-                    Option<Vec<TransactionStatus>>
-                ) {
-                    (
-                        Ethereum::current_block(),
-                        Ethereum::current_receipts(),
-                        Ethereum::current_transaction_statuses()
-                    )
-                }
-
-                fn extrinsic_filter(xts: Vec<<Block as sp_api::BlockT>::Extrinsic>) -> Vec<pallet_ethereum::Transaction> {
-                    xts.into_iter().filter_map(|xt| match xt.0.function {
-                        Call::Ethereum(pallet_ethereum::Call::transact { transaction }) => Some(transaction),
-                        _ => None
-                    }).collect()
-                }
-
-                fn elasticity() -> Option<Permill> {
-                    None
-                }
-            }
-
-            impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
-                fn convert_transaction(transaction: pallet_ethereum::Transaction) -> <Block as BlockT>::Extrinsic  {
-                    UncheckedExtrinsic::new_unsigned(
-                        pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-                    )
-                }
-            }
-
-            impl sp_session::SessionKeys<Block> for Runtime {
-                fn decode_session_keys(
-                    encoded: Vec<u8>,
-                ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
-                    SessionKeys::decode_into_raw_public_keys(&encoded)
-                }
-
-                fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
-                    SessionKeys::generate(seed)
-                }
-            }
-
-            impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
-                fn slot_duration() -> sp_consensus_aura::SlotDuration {
-                    sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
-                }
-
-                fn authorities() -> Vec<AuraId> {
-                    Aura::authorities().to_vec()
-                }
-            }
-
-            impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
-                fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
-                    ParachainSystem::collect_collation_info(header)
-                }
-            }
-
-            impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
-                fn account_nonce(account: AccountId) -> Index {
-                    System::account_nonce(account)
-                }
-            }
-
-            impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
-                fn query_info(uxt: <Block as BlockT>::Extrinsic, len: u32) -> RuntimeDispatchInfo<Balance> {
-                    TransactionPayment::query_info(uxt, len)
-                }
-                fn query_fee_details(uxt: <Block as BlockT>::Extrinsic, len: u32) -> FeeDetails<Balance> {
-                    TransactionPayment::query_fee_details(uxt, len)
-                }
-            }
-
-            /*
-            impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash>
-                for Runtime
-            {
-                fn call(
-                    origin: AccountId,
-                    dest: AccountId,
-                    value: Balance,
-                    gas_limit: u64,
-                    input_data: Vec<u8>,
-                ) -> pallet_contracts_primitives::ContractExecResult {
-                    Contracts::bare_call(origin, dest, value, gas_limit, input_data, false)
-                }
-
-                fn instantiate(
-                    origin: AccountId,
-                    endowment: Balance,
-                    gas_limit: u64,
-                    code: pallet_contracts_primitives::Code<Hash>,
-                    data: Vec<u8>,
-                    salt: Vec<u8>,
-                ) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, BlockNumber>
-                {
-                    Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true, false)
-                }
-
-                fn get_storage(
-                    address: AccountId,
-                    key: [u8; 32],
-                ) -> pallet_contracts_primitives::GetStorageResult {
-                    Contracts::get_storage(address, key)
-                }
-
-                fn rent_projection(
-                    address: AccountId,
-                ) -> pallet_contracts_primitives::RentProjectionResult<BlockNumber> {
-                    Contracts::rent_projection(address)
-                }
-            }
-            */
-
-            #[cfg(feature = "runtime-benchmarks")]
-            impl frame_benchmarking::Benchmark<Block> for Runtime {
-                fn benchmark_metadata(extra: bool) -> (
-                    Vec<frame_benchmarking::BenchmarkList>,
-                    Vec<frame_support::traits::StorageInfo>,
-                ) {
-                    use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
-                    use frame_support::traits::StorageInfoTrait;
-
-                    let mut list = Vec::<BenchmarkList>::new();
-
-                    list_benchmark!(list, extra, pallet_evm_migration, EvmMigration);
-                    list_benchmark!(list, extra, pallet_common, Common);
-                    list_benchmark!(list, extra, pallet_unique, Unique);
-                    list_benchmark!(list, extra, pallet_structure, Structure);
-                    list_benchmark!(list, extra, pallet_inflation, Inflation);
-                    list_benchmark!(list, extra, pallet_fungible, Fungible);
-                    list_benchmark!(list, extra, pallet_refungible, Refungible);
-                    list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
-                    list_benchmark!(list, extra, pallet_unique_scheduler, Scheduler);
-
-                    #[cfg(not(feature = "unique-runtime"))]
-                    list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);
-
-                    #[cfg(not(feature = "unique-runtime"))]
-                    list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip);
-
-                    // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);
-
-                    let storage_info = AllPalletsReversedWithSystemFirst::storage_info();
-
-                    return (list, storage_info)
-                }
-
-                fn dispatch_benchmark(
-                    config: frame_benchmarking::BenchmarkConfig
-                ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
-                    use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
-
-                    let allowlist: Vec<TrackedStorageKey> = vec![
-                        // Total Issuance
-                        hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
-
-                        // Block Number
-                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
-                        // Execution Phase
-                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
-                        // Event Count
-                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
-                        // System Events
-                        hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
-
-                        // Evm CurrentLogs
-                        hex_literal::hex!("1da53b775b270400e7e61ed5cbc5a146547f210cec367e9af919603343b9cb56").to_vec().into(),
-
-                        // Transactional depth
-                        hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a").to_vec().into(),
-                    ];
-
-                    let mut batches = Vec::<BenchmarkBatch>::new();
-                    let params = (&config, &allowlist);
-
-                    add_benchmark!(params, batches, pallet_evm_migration, EvmMigration);
-                    add_benchmark!(params, batches, pallet_common, Common);
-                    add_benchmark!(params, batches, pallet_unique, Unique);
-                    add_benchmark!(params, batches, pallet_structure, Structure);
-                    add_benchmark!(params, batches, pallet_inflation, Inflation);
-                    add_benchmark!(params, batches, pallet_fungible, Fungible);
-                    add_benchmark!(params, batches, pallet_refungible, Refungible);
-                    add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
-                    add_benchmark!(params, batches, pallet_unique_scheduler, Scheduler);
-
-                    #[cfg(not(feature = "unique-runtime"))]
-                    add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);
-
-                    #[cfg(not(feature = "unique-runtime"))]
-                    add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip);
-
-                    // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);
-
-                    if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
-                    Ok(batches)
-                }
-            }
-
-            #[cfg(feature = "try-runtime")]
-            impl frame_try_runtime::TryRuntime<Block> for Runtime {
-                fn on_runtime_upgrade() -> (Weight, Weight) {
-                    log::info!("try-runtime::on_runtime_upgrade unique-chain.");
-                    let weight = Executive::try_runtime_upgrade().unwrap();
-                    (weight, RuntimeBlockWeights::get().max_block)
-                }
-
-                fn execute_block_no_check(block: Block) -> Weight {
-                    Executive::execute_block_no_check(block)
-                }
-            }
-        }
-    }
-}
deletedruntime/common/src/sponsoring.rsdiffbeforeafterboth
--- a/runtime/common/src/sponsoring.rs
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use core::marker::PhantomData;
-use up_sponsorship::SponsorshipHandler;
-use frame_support::{
-	traits::{IsSubType},
-	storage::{StorageMap, StorageDoubleMap, StorageNMap},
-};
-use up_data_structs::{
-	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
-	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,
-};
-use sp_runtime::traits::Saturating;
-use pallet_common::{CollectionHandle};
-use pallet_evm::account::CrossAccountId;
-use pallet_unique::{
-	Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
-	NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
-	NftTransferBasket, TokenPropertyBasket,
-};
-use pallet_fungible::Config as FungibleConfig;
-use pallet_nonfungible::Config as NonfungibleConfig;
-use pallet_refungible::Config as RefungibleConfig;
-
-pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
-impl<T> Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}
-
-// TODO: permission check?
-pub fn withdraw_set_token_property<T: Config>(
-	collection: &CollectionHandle<T>,
-	who: &T::CrossAccountId,
-	item_id: &TokenId,
-	data_size: usize,
-) -> Option<()> {
-	// preliminary sponsoring correctness check
-	match collection.mode {
-		CollectionMode::NFT => {
-			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
-			if !owner.conv_eq(who) {
-				return None;
-			}
-		}
-		CollectionMode::Fungible(_) => {
-			// Fungible tokens have no properties
-			return None;
-		}
-		CollectionMode::ReFungible => {
-			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
-				return None;
-			}
-		}
-	}
-
-	if data_size > collection.limits.sponsored_data_size() as usize {
-		return None;
-	}
-
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection.limits.sponsored_data_rate_limit()?;
-
-	if let Some(last_tx_block) = TokenPropertyBasket::<T>::get(collection.id, item_id) {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	<TokenPropertyBasket<T>>::insert(collection.id, item_id, block_number);
-
-	Some(())
-}
-
-pub fn withdraw_transfer<T: Config>(
-	collection: &CollectionHandle<T>,
-	who: &T::CrossAccountId,
-	item_id: &TokenId,
-) -> Option<()> {
-	// preliminary sponsoring correctness check
-	match collection.mode {
-		CollectionMode::NFT => {
-			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
-			if !owner.conv_eq(who) {
-				return None;
-			}
-		}
-		CollectionMode::Fungible(_) => {
-			if item_id != &TokenId::default() {
-				return None;
-			}
-			if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
-				return None;
-			}
-		}
-		CollectionMode::ReFungible => {
-			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
-				return None;
-			}
-		}
-	}
-
-	// sponsor timeout
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection
-		.limits
-		.sponsor_transfer_timeout(match collection.mode {
-			CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
-			CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-			CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-		});
-
-	let last_tx_block = match collection.mode {
-		CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),
-		CollectionMode::Fungible(_) => {
-			<FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
-		}
-		CollectionMode::ReFungible => {
-			<ReFungibleTransferBasket<T>>::get((collection.id, item_id, who.as_sub()))
-		}
-	};
-
-	if let Some(last_tx_block) = last_tx_block {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	match collection.mode {
-		CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),
-		CollectionMode::Fungible(_) => {
-			<FungibleTransferBasket<T>>::insert(collection.id, who.as_sub(), block_number)
-		}
-		CollectionMode::ReFungible => <ReFungibleTransferBasket<T>>::insert(
-			(collection.id, item_id, who.as_sub()),
-			block_number,
-		),
-	};
-
-	Some(())
-}
-
-pub fn withdraw_create_item<T: Config>(
-	collection: &CollectionHandle<T>,
-	who: &T::CrossAccountId,
-	properties: &CreateItemData,
-) -> Option<()> {
-	// sponsor timeout
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection
-		.limits
-		.sponsor_transfer_timeout(match properties {
-			CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
-			CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-			CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-		});
-
-	if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, who.as_sub())) {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);
-
-	Some(())
-}
-
-pub fn withdraw_approve<T: Config>(
-	collection: &CollectionHandle<T>,
-	who: &T::AccountId,
-	item_id: &TokenId,
-) -> Option<()> {
-	// sponsor timeout
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection.limits.sponsor_approve_timeout();
-
-	let last_tx_block = match collection.mode {
-		CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),
-		CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),
-		CollectionMode::ReFungible => {
-			<RefungibleApproveBasket<T>>::get((collection.id, item_id, who))
-		}
-	};
-
-	if let Some(last_tx_block) = last_tx_block {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	match collection.mode {
-		CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),
-		CollectionMode::Fungible(_) => {
-			<FungibleApproveBasket<T>>::insert(collection.id, who, block_number)
-		}
-		CollectionMode::ReFungible => {
-			<RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)
-		}
-	};
-
-	Some(())
-}
-
-fn load<T: UniqueConfig>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {
-	let collection = CollectionHandle::new(id)?;
-	let sponsor = collection.sponsorship.sponsor().cloned()?;
-	Some((sponsor, collection))
-}
-
-pub struct UniqueSponsorshipHandler<T>(PhantomData<T>);
-impl<T, C> SponsorshipHandler<T::AccountId, C> for UniqueSponsorshipHandler<T>
-where
-	T: Config,
-	C: IsSubType<UniqueCall<T>>,
-{
-	fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
-		match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {
-			UniqueCall::set_token_properties {
-				collection_id,
-				token_id,
-				properties,
-				..
-			} => {
-				let (sponsor, collection) = load::<T>(*collection_id)?;
-				withdraw_set_token_property(
-					&collection,
-					&T::CrossAccountId::from_sub(who.clone()),
-					&token_id,
-					// No overflow may happen, as data larger than usize can't reach here
-					properties.iter().map(|p| p.key.len() + p.value.len()).sum(),
-				)
-				.map(|()| sponsor)
-			}
-			UniqueCall::create_item {
-				collection_id,
-				data,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_create_item::<T>(
-					&collection,
-					&T::CrossAccountId::from_sub(who.clone()),
-					data,
-				)
-				.map(|()| sponsor)
-			}
-			UniqueCall::transfer {
-				collection_id,
-				item_id,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_transfer::<T>(
-					&collection,
-					&T::CrossAccountId::from_sub(who.clone()),
-					item_id,
-				)
-				.map(|()| sponsor)
-			}
-			UniqueCall::transfer_from {
-				collection_id,
-				item_id,
-				from,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)
-			}
-			UniqueCall::approve {
-				collection_id,
-				item_id,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
-			}
-			_ => None,
-		}
-	}
-}
-
-pub trait SponsorshipPredict<T: Config> {
-	fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option<u64>
-	where
-		u64: From<<T as frame_system::Config>::BlockNumber>;
-}
-
-pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
-
-impl<T: Config> SponsorshipPredict<T> for UniqueSponsorshipPredict<T> {
-	fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option<u64>
-	where
-		u64: From<<T as frame_system::Config>::BlockNumber>,
-	{
-		let collection = <CollectionHandle<T>>::try_get(collection_id).ok()?;
-		let _ = collection.sponsorship.sponsor()?;
-
-		// sponsor timeout
-		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-		let limit = collection
-			.limits
-			.sponsor_transfer_timeout(match collection.mode {
-				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
-				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-			});
-
-		let last_tx_block = match collection.mode {
-			CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, token),
-			CollectionMode::Fungible(_) => {
-				<FungibleTransferBasket<T>>::get(collection.id, who.as_sub())
-			}
-			CollectionMode::ReFungible => {
-				<ReFungibleTransferBasket<T>>::get((collection.id, token, who.as_sub()))
-			}
-		};
-
-		if let Some(last_tx_block) = last_tx_block {
-			return Some(
-				last_tx_block
-					.saturating_add(limit.into())
-					.saturating_sub(block_number)
-					.into(),
-			);
-		}
-
-		let token_exists = match collection.mode {
-			CollectionMode::NFT => {
-				<pallet_nonfungible::TokenData<T>>::contains_key((collection.id, token))
-			}
-			CollectionMode::Fungible(_) => token == TokenId::default(),
-			CollectionMode::ReFungible => {
-				<pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
-			}
-		};
-
-		if token_exists {
-			Some(0)
-		} else {
-			None
-		}
-	}
-}
deletedruntime/common/src/types.rsdiffbeforeafterboth
--- a/runtime/common/src/types.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_runtime::{
-	traits::{Verify, IdentifyAccount, BlakeTwo256},
-	generic, MultiSignature,
-};
-
-pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
-
-/// Opaque block header type.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-
-/// Opaque block type.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-
-pub type SessionHandlers = ();
-
-/// An index to a block.
-pub type BlockNumber = u32;
-
-/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
-pub type Signature = MultiSignature;
-
-/// Some way of identifying an account on the chain. We intentionally make it equivalent
-/// to the public key of our transaction signing scheme.
-pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
-
-pub trait RuntimeInstance {
-	type CrossAccountId: pallet_evm::account::CrossAccountId<sp_runtime::AccountId32>
-		+ Send
-		+ Sync
-		+ 'static;
-
-	type TransactionConverter: fp_rpc::ConvertTransaction<UncheckedExtrinsic>
-		+ Send
-		+ Sync
-		+ 'static;
-
-	fn get_transaction_converter() -> Self::TransactionConverter;
-}
deletedruntime/common/src/weights.rsdiffbeforeafterboth
--- a/runtime/common/src/weights.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use core::marker::PhantomData;
-use frame_support::{weights::Weight};
-use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};
-
-use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
-use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
-use pallet_refungible::{
-	Config as RefungibleConfig, weights::WeightInfo, common::CommonWeights as RefungibleWeights,
-};
-use up_data_structs::{CreateItemExData, CreateItemData};
-
-macro_rules! max_weight_of {
-	($method:ident ( $($args:tt)* )) => {
-		<FungibleWeights<T>>::$method($($args)*)
-		.max(<NonfungibleWeights<T>>::$method($($args)*))
-		.max(<RefungibleWeights<T>>::$method($($args)*))
-	};
-}
-
-pub struct CommonWeights<T>(PhantomData<T>)
-where
-	T: FungibleConfig + NonfungibleConfig + RefungibleConfig;
-impl<T> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T>
-where
-	T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
-{
-	fn create_item() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(create_item())
-	}
-
-	fn create_multiple_items(data: &[CreateItemData]) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(create_multiple_items(data))
-	}
-
-	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(create_multiple_items_ex(data))
-	}
-
-	fn burn_item() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(burn_item())
-	}
-
-	fn set_collection_properties(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(set_collection_properties(amount))
-	}
-
-	fn delete_collection_properties(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(delete_collection_properties(amount))
-	}
-
-	fn set_token_properties(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(set_token_properties(amount))
-	}
-
-	fn delete_token_properties(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(delete_token_properties(amount))
-	}
-
-	fn set_token_property_permissions(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(set_token_property_permissions(amount))
-	}
-
-	fn transfer() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(transfer())
-	}
-
-	fn approve() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(approve())
-	}
-
-	fn transfer_from() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(transfer_from())
-	}
-
-	fn burn_from() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(burn_from())
-	}
-
-	fn burn_recursively_self_raw() -> Weight {
-		max_weight_of!(burn_recursively_self_raw())
-	}
-
-	fn burn_recursively_breadth_raw(amount: u32) -> Weight {
-		max_weight_of!(burn_recursively_breadth_raw(amount))
-	}
-}
-
-impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
-where
-	T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
-{
-	fn repartition() -> Weight {
-		dispatch_weight::<T>() + <<T as RefungibleConfig>::WeightInfo>::repartition_item()
-	}
-}
addedruntime/common/weights.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/weights.rs
@@ -0,0 +1,139 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use core::marker::PhantomData;
+use frame_support::{weights::Weight};
+use pallet_common::{CommonWeightInfo, dispatch::dispatch_weight, RefungibleExtensionsWeightInfo};
+
+use pallet_fungible::{Config as FungibleConfig, common::CommonWeights as FungibleWeights};
+use pallet_nonfungible::{Config as NonfungibleConfig, common::CommonWeights as NonfungibleWeights};
+
+#[cfg(feature = "refungible")]
+use pallet_refungible::{
+	Config as RefungibleConfig, weights::WeightInfo, common::CommonWeights as RefungibleWeights,
+};
+use up_data_structs::{CreateItemExData, CreateItemData};
+
+macro_rules! max_weight_of {
+	($method:ident ( $($args:tt)* )) => {{
+		let max_weight = <FungibleWeights<T>>::$method($($args)*)
+			.max(<NonfungibleWeights<T>>::$method($($args)*));
+
+		#[cfg(feature = "refungible")]
+		let max_weight = max_weight.max(<RefungibleWeights<T>>::$method($($args)*));
+
+		max_weight
+	}};
+}
+
+#[cfg(not(feature = "refungible"))]
+pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig {}
+
+#[cfg(not(feature = "refungible"))]
+impl<T: FungibleConfig + NonfungibleConfig> CommonWeightConfigs for T {}
+
+#[cfg(feature = "refungible")]
+pub trait CommonWeightConfigs: FungibleConfig + NonfungibleConfig + RefungibleConfig {}
+
+#[cfg(feature = "refungible")]
+impl<T: FungibleConfig + NonfungibleConfig + RefungibleConfig> CommonWeightConfigs for T {}
+
+pub struct CommonWeights<T>(PhantomData<T>);
+
+impl<T> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T>
+where
+	T: CommonWeightConfigs,
+{
+	fn create_item() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(create_item())
+	}
+
+	fn create_multiple_items(data: &[CreateItemData]) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(create_multiple_items(data))
+	}
+
+	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(create_multiple_items_ex(data))
+	}
+
+	fn burn_item() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(burn_item())
+	}
+
+	fn set_collection_properties(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(set_collection_properties(amount))
+	}
+
+	fn delete_collection_properties(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(delete_collection_properties(amount))
+	}
+
+	fn set_token_properties(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(set_token_properties(amount))
+	}
+
+	fn delete_token_properties(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(delete_token_properties(amount))
+	}
+
+	fn set_token_property_permissions(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(set_token_property_permissions(amount))
+	}
+
+	fn transfer() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(transfer())
+	}
+
+	fn approve() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(approve())
+	}
+
+	fn transfer_from() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(transfer_from())
+	}
+
+	fn burn_from() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(burn_from())
+	}
+
+	fn burn_recursively_self_raw() -> Weight {
+		max_weight_of!(burn_recursively_self_raw())
+	}
+
+	fn burn_recursively_breadth_raw(amount: u32) -> Weight {
+		max_weight_of!(burn_recursively_breadth_raw(amount))
+	}
+}
+
+#[cfg(feature = "refungible")]
+impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
+where
+	T: FungibleConfig + NonfungibleConfig + RefungibleConfig,
+{
+	fn repartition() -> Weight {
+		dispatch_weight::<T>() + <<T as RefungibleConfig>::WeightInfo>::repartition_item()
+	}
+}
+
+#[cfg(not(feature = "refungible"))]
+impl<T> RefungibleExtensionsWeightInfo for CommonWeights<T>
+where
+	T: FungibleConfig + NonfungibleConfig,
+{
+	fn repartition() -> Weight {
+		dispatch_weight::<T>()
+	}
+}
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -16,7 +16,7 @@
 targets = ['x86_64-unknown-linux-gnu']
 
 [features]
-default = ['std']
+default = ['std', 'opal-runtime']
 runtime-benchmarks = [
     'hex-literal',
     'frame-benchmarking',
@@ -113,13 +113,20 @@
     'xcm/std',
     'xcm-builder/std',
     'xcm-executor/std',
-    'unique-runtime-common/std',
+    'up-common/std',
     'rmrk-rpc/std',
+    'evm-coder/std',
+    'up-sponsorship/std',
 
     "orml-vesting/std",
 ]
 limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
+opal-runtime = ['refungible', 'scheduler', 'rmrk']
 
+refungible = []
+scheduler = []
+rmrk = []
+
 ################################################################################
 # Substrate Dependencies
 
@@ -396,7 +403,7 @@
 
 [dependencies]
 log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
@@ -426,6 +433,8 @@
 pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
 
 ################################################################################
 # Build Dependencies
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -25,168 +25,21 @@
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
-	Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
-	traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
-	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, RuntimeAppPublic,
-};
+use frame_support::parameter_types;
 
-use sp_std::prelude::*;
-
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
-	Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
-	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
-	OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
-	construct_runtime, match_types,
-	dispatch::DispatchResult,
-	PalletId, parameter_types, StorageValue, ConsensusEngineId,
-	traits::{
-		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
-		Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
-		OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
-	},
-	weights::{
-		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
-		DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
-		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
-		WeightToFee,
-	},
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
-	CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
-	CollectionStats, RpcCollection,
-	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
-	TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
-	RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
-	RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
 
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
-	self as frame_system, EnsureRoot, EnsureSigned,
-	limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
-	traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-// use scale_info::TypeInfo;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
-	traits::{
-		Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
-		Saturating, CheckedConversion,
-	},
-	generic::Era,
-	transaction_validity::TransactionValidityError,
-	DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
 
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
 
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
-	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
-	EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
-	RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
-	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
-	ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
-	//	Xcm,
-	AssetId::{Concrete},
-	Fungibility::Fungible as XcmFungible,
-	MultiAsset,
-	Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
-//use xcm_executor::traits::MatchesFungible;
+pub use runtime_common::*;
 
-use unique_runtime_common::{
-	impl_common_runtime_apis,
-	types::*,
-	constants::*,
-	dispatch::{CollectionDispatchT, CollectionDispatch},
-	sponsoring::UniqueSponsorshipHandler,
-	eth_sponsoring::UniqueEthSponsorshipHandler,
-	weights::CommonWeights,
-};
-
 pub const RUNTIME_NAME: &str = "opal";
 pub const TOKEN_SYMBOL: &str = "OPL";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
 
-impl RuntimeInstance for Runtime {
-	type CrossAccountId = self::CrossAccountId;
-	type TransactionConverter = self::TransactionConverter;
-
-	fn get_transaction_converter() -> TransactionConverter {
-		TransactionConverter
-	}
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
-	use sp_std::prelude::*;
-	use sp_runtime::impl_opaque_keys;
-	use super::Aura;
-
-	pub use unique_runtime_common::types::*;
-
-	impl_opaque_keys! {
-		pub struct SessionKeys {
-			pub aura: Aura,
-		}
-	}
-}
-
 /// This runtime version.
 pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -199,1206 +52,15 @@
 	state_version: 0,
 };
 
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
-	/// Transfer tokens to the given account from the Parachain account.
-	TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
-	NativeVersion {
-		runtime_version: VERSION,
-		can_author_with: Default::default(),
-	}
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
-	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
-		if let Some(fees) = fees_then_tips.next() {
-			// for fees, 100% to treasury
-			let mut split = fees.ration(100, 0);
-			if let Some(tips) = fees_then_tips.next() {
-				// for tips, if any, 100% to treasury
-				tips.ration_merge_into(100, 0, &mut split);
-			}
-			Treasury::on_unbalanced(split.0);
-			// Author::on_unbalanced(split.1);
-		}
-	}
-}
-
 parameter_types! {
-	pub const BlockHashCount: BlockNumber = 2400;
-	pub RuntimeBlockLength: BlockLength =
-		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
-	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
-	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
-	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
-		.base_block(BlockExecutionWeight::get())
-		.for_class(DispatchClass::all(), |weights| {
-			weights.base_extrinsic = ExtrinsicBaseWeight::get();
-		})
-		.for_class(DispatchClass::Normal, |weights| {
-			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
-		})
-		.for_class(DispatchClass::Operational, |weights| {
-			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
-			// Operational transactions have some extra reserved space, so that they
-			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
-			weights.reserved = Some(
-				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
-			);
-		})
-		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
-		.build_or_panic();
 	pub const Version: RuntimeVersion = VERSION;
 	pub const SS58Prefix: u8 = 42;
-}
-
-parameter_types! {
 	pub const ChainId: u64 = 8882;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
-	fn min_gas_price() -> (U256, u64) {
-		(MIN_GAS_PRICE.into(), 0)
-	}
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
-	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
-	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
-	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
 }
 
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
-	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
-}
-
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
-	fn gas_to_weight(gas: u64) -> Weight {
-		gas.saturating_mul(WeightPerGas::get())
-	}
-	fn weight_to_gas(weight: Weight) -> u64 {
-		weight / WeightPerGas::get()
-	}
-}
-
-impl pallet_evm::account::Config for Runtime {
-	type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
-	type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
-	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
-	type BlockGasLimit = BlockGasLimit;
-	type FeeCalculator = FixedFee;
-	type GasWeightMapping = FixedGasWeightMapping;
-	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
-	type CallOrigin = EnsureAddressTruncated<Self>;
-	type WithdrawOrigin = EnsureAddressTruncated<Self>;
-	type AddressMapping = HashedAddressMapping<Self::Hashing>;
-	type PrecompilesType = ();
-	type PrecompilesValue = ();
-	type Currency = Balances;
-	type Event = Event;
-	type OnMethodCall = (
-		pallet_evm_migration::OnMethodCall<Self>,
-		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
-		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
-	);
-	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
-	type ChainId = ChainId;
-	type Runner = pallet_evm::runner::stack::Runner<Self>;
-	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
-	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
-	type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
-	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
-	fn find_author<'a, I>(digests: I) -> Option<H160>
-	where
-		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
-	{
-		if let Some(author_index) = F::find_author(digests) {
-			let authority_id = Aura::authorities()[author_index as usize].clone();
-			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
-		}
-		None
-	}
-}
-
-impl pallet_ethereum::Config for Runtime {
-	type Event = Event;
-	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
-
-impl frame_system::Config for Runtime {
-	/// The data to be stored in an account.
-	type AccountData = pallet_balances::AccountData<Balance>;
-	/// The identifier used to distinguish between accounts.
-	type AccountId = AccountId;
-	/// The basic call filter to use in dispatchable.
-	type BaseCallFilter = Everything;
-	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
-	type BlockHashCount = BlockHashCount;
-	/// The maximum length of a block (in bytes).
-	type BlockLength = RuntimeBlockLength;
-	/// The index type for blocks.
-	type BlockNumber = BlockNumber;
-	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
-	type BlockWeights = RuntimeBlockWeights;
-	/// The aggregated dispatch type that is available for extrinsics.
-	type Call = Call;
-	/// The weight of database operations that the runtime can invoke.
-	type DbWeight = RocksDbWeight;
-	/// The ubiquitous event type.
-	type Event = Event;
-	/// The type for hashing blocks and tries.
-	type Hash = Hash;
-	/// The hashing algorithm used.
-	type Hashing = BlakeTwo256;
-	/// The header type.
-	type Header = generic::Header<BlockNumber, BlakeTwo256>;
-	/// The index type for storing how many extrinsics an account has signed.
-	type Index = Index;
-	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
-	type Lookup = AccountIdLookup<AccountId, ()>;
-	/// What to do if an account is fully reaped from the system.
-	type OnKilledAccount = ();
-	/// What to do if a new account is created.
-	type OnNewAccount = ();
-	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
-	/// The ubiquitous origin type.
-	type Origin = Origin;
-	/// This type is being generated by `construct_runtime!`.
-	type PalletInfo = PalletInfo;
-	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
-	type SS58Prefix = SS58Prefix;
-	/// Weight information for the extrinsics of this pallet.
-	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
-	/// Version of the runtime.
-	type Version = Version;
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
-	/// A timestamp: milliseconds since the unix epoch.
-	type Moment = u64;
-	type OnTimestampSet = ();
-	type MinimumPeriod = MinimumPeriod;
-	type WeightInfo = ();
-}
-
-parameter_types! {
-	// pub const ExistentialDeposit: u128 = 500;
-	pub const ExistentialDeposit: u128 = 0;
-	pub const MaxLocks: u32 = 50;
-	pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
-	type MaxLocks = MaxLocks;
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 16];
-	/// The type for recording an account's balance.
-	type Balance = Balance;
-	/// The ubiquitous event type.
-	type Event = Event;
-	type DustRemoval = Treasury;
-	type ExistentialDeposit = ExistentialDeposit;
-	type AccountStore = System;
-	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
-	items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
-	pub TombstoneDeposit: Balance = deposit(
-		1,
-		sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
-	);
-	pub DepositPerContract: Balance = TombstoneDeposit::get();
-	pub const DepositPerStorageByte: Balance = deposit(0, 1);
-	pub const DepositPerStorageItem: Balance = deposit(1, 0);
-	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
-	pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
-	pub const SignedClaimHandicap: u32 = 2;
-	pub const MaxDepth: u32 = 32;
-	pub const MaxValueSize: u32 = 16 * 1024;
-	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
-	// The lazy deletion runs inside on_initialize.
-	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
-		RuntimeBlockWeights::get().max_block;
-	// The weight needed for decoding the queue should be less or equal than a fifth
-	// of the overall weight dedicated to the lazy deletion.
-	pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
-		)) / 5) as u32;
-	pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
-	type Time = Timestamp;
-	type Randomness = RandomnessCollectiveFlip;
-	type Currency = Balances;
-	type Event = 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 WeightPrice = pallet_transaction_payment::Pallet<Self>;
-	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
-	type ChainExtension = NFTExtension;
-	type DeletionQueueDepth = DeletionQueueDepth;
-	type DeletionWeightLimit = DeletionWeightLimit;
-	type Schedule = Schedule;
-	type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
+construct_runtime!(opal);
 
-parameter_types! {
-	/// This value increases the priority of `Operational` transactions by adding
-	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
-	pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
-	T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
-	type Balance = T;
-
-	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
-		smallvec!(WeightToFeeCoefficient {
-			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
-			coeff_frac: Perbill::zero(),
-			negative: false,
-			degree: 1,
-		})
-	}
-}
-
-impl pallet_transaction_payment::Config for Runtime {
-	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
-	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
-	type OperationalFeeMultiplier = OperationalFeeMultiplier;
-	type WeightToFee = LinearFee<Balance>;
-	type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
-	pub const ProposalBond: Permill = Permill::from_percent(5);
-	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
-	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
-	pub const SpendPeriod: BlockNumber = 5 * MINUTES;
-	pub const Burn: Permill = Permill::from_percent(0);
-	pub const TipCountdown: BlockNumber = 1 * DAYS;
-	pub const TipFindersFee: Percent = Percent::from_percent(20);
-	pub const TipReportDepositBase: Balance = 1 * UNIQUE;
-	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
-	pub const BountyDepositBase: Balance = 1 * UNIQUE;
-	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
-	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
-	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
-	pub const MaximumReasonLength: u32 = 16384;
-	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
-	pub const BountyValueMinimum: Balance = 5 * UNIQUE;
-	pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
-	type PalletId = TreasuryModuleId;
-	type Currency = Balances;
-	type ApproveOrigin = EnsureRoot<AccountId>;
-	type RejectOrigin = EnsureRoot<AccountId>;
-	type Event = Event;
-	type OnSlash = ();
-	type ProposalBond = ProposalBond;
-	type ProposalBondMinimum = ProposalBondMinimum;
-	type ProposalBondMaximum = ProposalBondMaximum;
-	type SpendPeriod = SpendPeriod;
-	type Burn = Burn;
-	type BurnDestination = ();
-	type SpendFunds = ();
-	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
-	type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
-	for RelayChainBlockNumberProvider<T>
-{
-	type BlockNumber = BlockNumber;
-
-	fn current_block_number() -> Self::BlockNumber {
-		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
-			.map(|d| d.relay_parent_number)
-			.unwrap_or_default()
-	}
-}
-
-parameter_types! {
-	pub const MinVestedTransfer: Balance = 10 * UNIQUE;
-	pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
-	type Event = Event;
-	type Currency = pallet_balances::Pallet<Runtime>;
-	type MinVestedTransfer = MinVestedTransfer;
-	type VestedTransferOrigin = EnsureSigned<AccountId>;
-	type WeightInfo = ();
-	type MaxVestingSchedules = MaxVestingSchedules;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
-	type Event = Event;
-	type SelfParaId = parachain_info::Pallet<Self>;
-	type OnSystemEvent = ();
-	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
-	// 	MaxDownwardMessageWeight,
-	// 	XcmExecutor<XcmConfig>,
-	// 	Call,
-	// >;
-	type OutboundXcmpMessageSource = XcmpQueue;
-	type DmpMessageHandler = DmpQueue;
-	type ReservedDmpWeight = ReservedDmpWeight;
-	type ReservedXcmpWeight = ReservedXcmpWeight;
-	type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
-	pub const RelayLocation: MultiLocation = MultiLocation::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
-	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
-	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
-	// The parent (Relay-chain) origin converts to the default `AccountId`.
-	ParentIsPreset<AccountId>,
-	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
-	SiblingParachainConvertsVia<Sibling, AccountId>,
-	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
-	AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
-	fn matches_fungible(a: &MultiAsset) -> Option<B> {
-		match (&a.id, &a.fun) {
-			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
-			_ => None,
-		}
-	}
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
-	// Use this currency:
-	Balances,
-	// Use this currency when it is a fungible asset matching the given location or name:
-	OnlySelfCurrency,
-	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
-	LocationToAccountId,
-	// Our chain's account ID type (we can't get away without mentioning it explicitly):
-	AccountId,
-	// We don't track any teleports.
-	(),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
-	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
-	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
-	// foreign chains who want to have a local sovereign account on this chain which they control.
-	SovereignSignedViaLocation<LocationToAccountId, Origin>,
-	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
-	// recognised.
-	RelayChainAsNative<RelayOrigin, Origin>,
-	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
-	// recognised.
-	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
-	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
-	// transaction from the Root origin.
-	ParentAsSuperuser<Origin>,
-	// Native signed account converter; this just converts an `AccountId32` origin into a normal
-	// `Origin::Signed` origin of the same 32-byte value.
-	SignedAccountId32AsNative<RelayNetwork, Origin>,
-	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
-	XcmPassthrough<Origin>,
-);
-
-parameter_types! {
-	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
-	pub UnitWeightCost: Weight = 1_000_000;
-	// 1200 UNIQUEs buy 1 second of weight.
-	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
-	pub const MaxInstructions: u32 = 100;
-	pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
-	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
-		MultiLocation { parents: 1, interior: Here } |
-		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
-	};
-}
-
-pub type Barrier = (
-	TakeWeightCredit,
-	AllowTopLevelPaidExecutionFrom<Everything>,
-	// ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
-	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-	AssetId: Get<MultiLocation>,
-	AccountId,
-	Currency: CurrencyT<AccountId>,
-	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
-	Weight,
-	Currency::Balance,
-	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> WeightTrader
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn new() -> Self {
-		Self(0, Zero::zero(), PhantomData)
-	}
-
-	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
-		let amount = WeightToFee::weight_to_fee(&weight);
-		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
-		// location to this parachain through relay chain
-		let option1: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 1,
-			interior: X1(Parachain(ParachainInfo::parachain_id().into())),
-		});
-		// direct location
-		let option2: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 0,
-			interior: Here,
-		});
-
-		let required = if payment.fungible.contains_key(&option1) {
-			(option1, u128_amount).into()
-		} else if payment.fungible.contains_key(&option2) {
-			(option2, u128_amount).into()
-		} else {
-			(Concrete(MultiLocation::default()), u128_amount).into()
-		};
-
-		let unused = payment
-			.checked_sub(required)
-			.map_err(|_| XcmError::TooExpensive)?;
-		self.0 = self.0.saturating_add(weight);
-		self.1 = self.1.saturating_add(amount);
-		Ok(unused)
-	}
-
-	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
-		let weight = weight.min(self.0);
-		let amount = WeightToFee::weight_to_fee(&weight);
-		self.0 -= weight;
-		self.1 = self.1.saturating_sub(amount);
-		let amount: u128 = amount.saturated_into();
-		if amount > 0 {
-			Some((AssetId::get(), amount).into())
-		} else {
-			None
-		}
-	}
-}
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> Drop
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn drop(&mut self) {
-		OnUnbalanced::on_unbalanced(Currency::issue(self.1));
-	}
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
-	type Call = Call;
-	type XcmSender = XcmRouter;
-	// How to withdraw and deposit an asset.
-	type AssetTransactor = LocalAssetTransactor;
-	type OriginConverter = XcmOriginToTransactDispatchOrigin;
-	type IsReserve = NativeAsset;
-	type IsTeleporter = (); // Teleportation is disabled
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Barrier = Barrier;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type Trader =
-		UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
-	type ResponseHandler = (); // Don't handle responses for now.
-	type SubscriptionService = PolkadotXcm;
-
-	type AssetTrap = PolkadotXcm;
-	type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// 	pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
-	// Two routers - use UMP to communicate with the relay chain:
-	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
-	// ..and XCMP to communicate with the sibling chains.
-	XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmRouter = XcmRouter;
-	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmExecuteFilter = Everything;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type XcmTeleportFilter = Everything;
-	type XcmReserveTransferFilter = Everything;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Origin = Origin;
-	type Call = Call;
-	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
-	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
-	type WeightInfo = ();
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ChannelInfo = ParachainSystem;
-	type VersionWrapper = ();
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-	type ControllerOrigin = EnsureRoot<AccountId>;
-	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
-	type AuthorityId = AuraId;
-	type DisabledValidators = ();
-	type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
-	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
-	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
-	type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
-	type Event = Event;
-	type Currency = Balances;
-	type CollectionCreationPrice = CollectionCreationPrice;
-	type TreasuryAccountId = TreasuryAccountId;
-	type CollectionDispatch = CollectionDispatchT<Self>;
-
-	type EvmTokenAddressMapping = EvmTokenAddressMapping;
-	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
-	type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
-	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
-	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
-	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_proxy_rmrk_core::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
-	type Event = Event;
-}
-
-impl pallet_proxy_rmrk_equip::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
-	type Event = Event;
-}
-
-impl pallet_unique::Config for Runtime {
-	type Event = Event;
-	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
-	type CommonWeightInfo = CommonWeights<Self>;
-	type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
-	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
-	type Currency = Balances;
-	type TreasuryAccountId = TreasuryAccountId;
-	type InflationBlockInterval = InflationBlockInterval;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
-		RuntimeBlockWeights::get().max_block;
-	pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
-	(
-		frame_system::CheckSpecVersion::<Runtime>::new(),
-		frame_system::CheckGenesis::<Runtime>::new(),
-		frame_system::CheckEra::<Runtime>::from(Era::Immortal),
-		frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
-			from,
-		)),
-		frame_system::CheckWeight::<Runtime>::new(),
-		// sponsoring transaction logic
-		// pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
-	)
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
-	DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
-	<T as frame_system::Config>::Call: Member
-		+ Dispatchable<Origin = Origin, Info = DispatchInfo>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
-		+ GetDispatchInfo
-		+ From<frame_system::Call<Runtime>>,
-	SelfContainedSignedInfo: Send + Sync + 'static,
-	Call: From<<T as frame_system::Config>::Call>
-		+ From<<T as pallet_unique_scheduler::Config>::Call>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
-	sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
-	fn dispatch_call(
-		signer: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<
-		Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
-		TransactionValidityError,
-	> {
-		let dispatch_info = call.get_dispatch_info();
-		let extrinsic = fp_self_contained::CheckedExtrinsic::<
-			AccountId,
-			Call,
-			SignedExtraScheduler,
-			SelfContainedSignedInfo,
-		> {
-			signed:
-				CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
-					signer.clone().into(),
-					get_signed_extras(signer.into()),
-				),
-			function: call.into(),
-		};
-
-		extrinsic.apply::<Runtime>(&dispatch_info, 0)
-	}
-
-	fn reserve_balance(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-		count: u32,
-	) -> Result<(), DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
-			.saturating_mul(count.into());
-
-		<Balances as NamedReservableCurrency<AccountId>>::reserve_named(
-			&id,
-			&(sponsor.into()),
-			weight,
-		)
-	}
-
-	fn pay_for_call(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<u128, DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				weight,
-			),
-		)
-	}
-
-	fn cancel_reserve(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-	) -> Result<u128, DispatchError> {
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				u128::MAX,
-			),
-		)
-	}
-}
-
-parameter_types! {
-	pub const NoPreimagePostponement: Option<u32> = Some(10);
-	pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
-	fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
-		Some(Ordering::Equal)
-	}
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
-	type Event = Event;
-	type Origin = Origin;
-	type Currency = Balances;
-	type PalletsOrigin = OriginCaller;
-	type Call = Call;
-	type MaximumWeight = MaximumSchedulerWeight;
-	type ScheduleOrigin = EnsureSigned<AccountId>;
-	type MaxScheduledPerBlock = MaxScheduledPerBlock;
-	type WeightInfo = ();
-	type CallExecutor = SchedulerPaymentExecutor;
-	type OriginPrivilegeCmp = OriginPrivilegeCmp;
-	type PreimageProvider = ();
-	type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
-	UniqueEthSponsorshipHandler<Runtime>,
-	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-
-type SponsorshipHandler = (
-	UniqueSponsorshipHandler<Runtime>,
-	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
-	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
-	type EvmSponsorshipHandler = EvmSponsorshipHandler;
-	type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
-	type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-//	 type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
-	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049
-	pub const HelpersContractAddress: H160 = H160([
-		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
-	]);
-
-	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelpersAddress: H160 = H160([
-		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
-	]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
-	type ContractAddress = HelpersContractAddress;
-	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
-	pub enum Runtime where
-		Block = Block,
-		NodeBlock = opaque::Block,
-		UncheckedExtrinsic = UncheckedExtrinsic
-	{
-		ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
-		ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
-		Aura: pallet_aura::{Pallet, Config<T>} = 22,
-		AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
-		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
-		RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
-		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
-		TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
-		Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
-		Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
-		System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
-		Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
-		// Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
-		// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
-		// XCM helpers.
-		XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
-		PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
-		CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
-		DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
-		// Unique Pallets
-		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
-		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
-		Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
-		// free = 63
-		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
-		// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
-		Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
-		Fungible: pallet_fungible::{Pallet, Storage} = 67,
-		Refungible: pallet_refungible::{Pallet, Storage} = 68,
-		Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
-		Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
-		RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
-		RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
-
-		// Frontier
-		EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
-		Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
-		EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
-		EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
-		EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
-		EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
-	}
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
-		UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		)
-	}
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(
-		&self,
-		transaction: pallet_ethereum::Transaction,
-	) -> opaque::UncheckedExtrinsic {
-		let extrinsic = UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		);
-		let encoded = extrinsic.encode();
-		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
-			.expect("Encoded extrinsic is always valid")
-	}
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
-	frame_system::CheckSpecVersion<Runtime>,
-	// system::CheckTxVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-	ChargeTransactionPayment,
-	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
-	pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-pub type SignedExtraScheduler = (
-	frame_system::CheckSpecVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
-	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
-	Runtime,
-	Block,
-	frame_system::ChainContext<Runtime>,
-	Runtime,
-	AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
-	pub struct SessionKeys {
-		pub aura: Aura,
-	}
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
-	type SignedInfo = H160;
-
-	fn is_self_contained(&self) -> bool {
-		match self {
-			Call::Ethereum(call) => call.is_self_contained(),
-			_ => false,
-		}
-	}
-
-	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.check_self_contained(),
-			_ => None,
-		}
-	}
-
-	fn validate_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-		dispatch_info: &DispatchInfoOf<Call>,
-		len: usize,
-	) -> Option<TransactionValidity> {
-		match self {
-			Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
-			_ => None,
-		}
-	}
-
-	fn pre_dispatch_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-	) -> Option<Result<(), TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
-			_ => None,
-		}
-	}
-
-	fn apply_self_contained(
-		self,
-		info: Self::SignedInfo,
-	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
-		match self {
-			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
-				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
-			)),
-			_ => None,
-		}
-	}
-}
-
-macro_rules! dispatch_unique_runtime {
-	($collection:ident.$method:ident($($name:ident),*)) => {{
-		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
-		let dispatch = collection.as_dyn();
-
-		Ok::<_, DispatchError>(dispatch.$method($($name),*))
-	}};
-}
-
-impl_common_runtime_apis! {
-	#![custom_apis]
-
-	impl rmrk_rpc::RmrkApi<
-		Block,
-		AccountId,
-		RmrkCollectionInfo<AccountId>,
-		RmrkInstanceInfo<AccountId>,
-		RmrkResourceInfo,
-		RmrkPropertyInfo,
-		RmrkBaseInfo<AccountId>,
-		RmrkPartType,
-		RmrkTheme
-	> for Runtime {
-		fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>()
-		}
-
-		fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id)
-		}
-
-		fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id)
-		}
-
-		fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id)
-		}
-
-		fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id)
-		}
-
-		fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys)
-		}
-
-		fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys)
-		}
-
-		fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id)
-		}
-
-		fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id)
-		}
-
-		fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id)
-		}
-
-		fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id)
-		}
-
-		fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id)
-		}
-
-		fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys)
-		}
-	}
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
-	fn check_inherents(
-		block: &Block,
-		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
-	) -> sp_inherents::CheckInherentsResult {
-		let relay_chain_slot = relay_state_proof
-			.read_slot()
-			.expect("Could not read the relay chain slot from the proof");
-
-		let inherent_data =
-			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
-				relay_chain_slot,
-				sp_std::time::Duration::from_secs(6),
-			)
-			.create_inherent_data()
-			.expect("Could not create the timestamp inherent data");
-
-		inherent_data.check_extrinsics(block)
-	}
-}
+impl_common_runtime_apis!();
 
 cumulus_pallet_parachain_system::register_validate_block!(
 	Runtime = Runtime,
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -16,7 +16,7 @@
 targets = ['x86_64-unknown-linux-gnu']
 
 [features]
-default = ['std']
+default = ['std', 'quartz-runtime']
 runtime-benchmarks = [
     'hex-literal',
     'frame-benchmarking',
@@ -113,12 +113,17 @@
     'xcm/std',
     'xcm-builder/std',
     'xcm-executor/std',
-    'unique-runtime-common/std',
+    'up-common/std',
 
     "orml-vesting/std",
 ]
 limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
+quartz-runtime = []
 
+refungible = []
+scheduler = []
+rmrk = []
+
 ################################################################################
 # Substrate Dependencies
 
@@ -403,7 +408,7 @@
 
 [dependencies]
 log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
@@ -432,6 +437,8 @@
 pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
 
 ################################################################################
 # Build Dependencies
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -25,167 +25,21 @@
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
-	Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
-	traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
-	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, RuntimeAppPublic,
-};
+use frame_support::parameter_types;
 
-use sp_std::prelude::*;
-
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
-	Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
-	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
-	OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
-	construct_runtime, match_types,
-	dispatch::DispatchResult,
-	PalletId, parameter_types, StorageValue, ConsensusEngineId,
-	traits::{
-		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
-		Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
-		OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
-	},
-	weights::{
-		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
-		DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
-		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
-		WeightToFee,
-	},
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
-	CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
-	CollectionStats, RpcCollection,
-	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
-	TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
-	RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
-	RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
 
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
-	self as frame_system, EnsureRoot, EnsureSigned,
-	limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
-	traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
-	traits::{
-		Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
-		Saturating, CheckedConversion,
-	},
-	generic::Era,
-	transaction_validity::TransactionValidityError,
-	DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
 
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
 
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
-	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
-	EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
-	RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
-	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
-	ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
-	//	Xcm,
-	AssetId::{Concrete},
-	Fungibility::Fungible as XcmFungible,
-	MultiAsset,
-	Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
+pub use runtime_common::*;
 
-use unique_runtime_common::{
-	impl_common_runtime_apis,
-	types::*,
-	constants::*,
-	dispatch::{CollectionDispatchT, CollectionDispatch},
-	sponsoring::UniqueSponsorshipHandler,
-	eth_sponsoring::UniqueEthSponsorshipHandler,
-	weights::CommonWeights,
-};
-
 pub const RUNTIME_NAME: &str = "quartz";
 pub const TOKEN_SYMBOL: &str = "QTZ";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
-
-impl RuntimeInstance for Runtime {
-	type CrossAccountId = self::CrossAccountId;
-
-	type TransactionConverter = self::TransactionConverter;
-
-	fn get_transaction_converter() -> TransactionConverter {
-		TransactionConverter
-	}
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
 
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
-	use sp_std::prelude::*;
-	use sp_runtime::impl_opaque_keys;
-	use super::Aura;
-
-	pub use unique_runtime_common::types::*;
-
-	impl_opaque_keys! {
-		pub struct SessionKeys {
-			pub aura: Aura,
-		}
-	}
-}
-
 /// This runtime version.
 pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -198,1207 +52,15 @@
 	state_version: 0,
 };
 
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
-	/// Transfer tokens to the given account from the Parachain account.
-	TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
-	NativeVersion {
-		runtime_version: VERSION,
-		can_author_with: Default::default(),
-	}
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
-	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
-		if let Some(fees) = fees_then_tips.next() {
-			// for fees, 100% to treasury
-			let mut split = fees.ration(100, 0);
-			if let Some(tips) = fees_then_tips.next() {
-				// for tips, if any, 100% to treasury
-				tips.ration_merge_into(100, 0, &mut split);
-			}
-			Treasury::on_unbalanced(split.0);
-			// Author::on_unbalanced(split.1);
-		}
-	}
-}
-
 parameter_types! {
-	pub const BlockHashCount: BlockNumber = 2400;
-	pub RuntimeBlockLength: BlockLength =
-		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
-	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
-	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
-	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
-		.base_block(BlockExecutionWeight::get())
-		.for_class(DispatchClass::all(), |weights| {
-			weights.base_extrinsic = ExtrinsicBaseWeight::get();
-		})
-		.for_class(DispatchClass::Normal, |weights| {
-			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
-		})
-		.for_class(DispatchClass::Operational, |weights| {
-			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
-			// Operational transactions have some extra reserved space, so that they
-			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
-			weights.reserved = Some(
-				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
-			);
-		})
-		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
-		.build_or_panic();
 	pub const Version: RuntimeVersion = VERSION;
 	pub const SS58Prefix: u8 = 255;
-}
-
-parameter_types! {
 	pub const ChainId: u64 = 8881;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
-	fn min_gas_price() -> (U256, u64) {
-		(MIN_GAS_PRICE.into(), 0)
-	}
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
-	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
-	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
-	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
-}
-
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
-	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
 }
 
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
-	fn gas_to_weight(gas: u64) -> Weight {
-		gas.saturating_mul(WeightPerGas::get())
-	}
-	fn weight_to_gas(weight: Weight) -> u64 {
-		weight / WeightPerGas::get()
-	}
-}
-
-impl pallet_evm::account::Config for Runtime {
-	type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
-	type EvmAddressMapping = HashedAddressMapping<Self::Hashing>;
-	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
-	type BlockGasLimit = BlockGasLimit;
-	type FeeCalculator = FixedFee;
-	type GasWeightMapping = FixedGasWeightMapping;
-	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
-	type CallOrigin = EnsureAddressTruncated<Self>;
-	type WithdrawOrigin = EnsureAddressTruncated<Self>;
-	type AddressMapping = HashedAddressMapping<Self::Hashing>;
-	type PrecompilesType = ();
-	type PrecompilesValue = ();
-	type Currency = Balances;
-	type Event = Event;
-	type OnMethodCall = (
-		pallet_evm_migration::OnMethodCall<Self>,
-		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
-		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
-	);
-	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
-	type ChainId = ChainId;
-	type Runner = pallet_evm::runner::stack::Runner<Self>;
-	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
-	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
-	type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
-	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
-	fn find_author<'a, I>(digests: I) -> Option<H160>
-	where
-		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
-	{
-		if let Some(author_index) = F::find_author(digests) {
-			let authority_id = Aura::authorities()[author_index as usize].clone();
-			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
-		}
-		None
-	}
-}
-
-impl pallet_ethereum::Config for Runtime {
-	type Event = Event;
-	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
-
-impl frame_system::Config for Runtime {
-	/// The data to be stored in an account.
-	type AccountData = pallet_balances::AccountData<Balance>;
-	/// The identifier used to distinguish between accounts.
-	type AccountId = AccountId;
-	/// The basic call filter to use in dispatchable.
-	type BaseCallFilter = Everything;
-	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
-	type BlockHashCount = BlockHashCount;
-	/// The maximum length of a block (in bytes).
-	type BlockLength = RuntimeBlockLength;
-	/// The index type for blocks.
-	type BlockNumber = BlockNumber;
-	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
-	type BlockWeights = RuntimeBlockWeights;
-	/// The aggregated dispatch type that is available for extrinsics.
-	type Call = Call;
-	/// The weight of database operations that the runtime can invoke.
-	type DbWeight = RocksDbWeight;
-	/// The ubiquitous event type.
-	type Event = Event;
-	/// The type for hashing blocks and tries.
-	type Hash = Hash;
-	/// The hashing algorithm used.
-	type Hashing = BlakeTwo256;
-	/// The header type.
-	type Header = generic::Header<BlockNumber, BlakeTwo256>;
-	/// The index type for storing how many extrinsics an account has signed.
-	type Index = Index;
-	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
-	type Lookup = AccountIdLookup<AccountId, ()>;
-	/// What to do if an account is fully reaped from the system.
-	type OnKilledAccount = ();
-	/// What to do if a new account is created.
-	type OnNewAccount = ();
-	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
-	/// The ubiquitous origin type.
-	type Origin = Origin;
-	/// This type is being generated by `construct_runtime!`.
-	type PalletInfo = PalletInfo;
-	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
-	type SS58Prefix = SS58Prefix;
-	/// Weight information for the extrinsics of this pallet.
-	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
-	/// Version of the runtime.
-	type Version = Version;
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
-	/// A timestamp: milliseconds since the unix epoch.
-	type Moment = u64;
-	type OnTimestampSet = ();
-	type MinimumPeriod = MinimumPeriod;
-	type WeightInfo = ();
-}
-
-parameter_types! {
-	// pub const ExistentialDeposit: u128 = 500;
-	pub const ExistentialDeposit: u128 = 0;
-	pub const MaxLocks: u32 = 50;
-	pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
-	type MaxLocks = MaxLocks;
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 16];
-	/// The type for recording an account's balance.
-	type Balance = Balance;
-	/// The ubiquitous event type.
-	type Event = Event;
-	type DustRemoval = Treasury;
-	type ExistentialDeposit = ExistentialDeposit;
-	type AccountStore = System;
-	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
-	items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
-	pub TombstoneDeposit: Balance = deposit(
-		1,
-		sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
-	);
-	pub DepositPerContract: Balance = TombstoneDeposit::get();
-	pub const DepositPerStorageByte: Balance = deposit(0, 1);
-	pub const DepositPerStorageItem: Balance = deposit(1, 0);
-	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
-	pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
-	pub const SignedClaimHandicap: u32 = 2;
-	pub const MaxDepth: u32 = 32;
-	pub const MaxValueSize: u32 = 16 * 1024;
-	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
-	// The lazy deletion runs inside on_initialize.
-	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
-		RuntimeBlockWeights::get().max_block;
-	// The weight needed for decoding the queue should be less or equal than a fifth
-	// of the overall weight dedicated to the lazy deletion.
-	pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
-		)) / 5) as u32;
-	pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
-	type Time = Timestamp;
-	type Randomness = RandomnessCollectiveFlip;
-	type Currency = Balances;
-	type Event = 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 WeightPrice = pallet_transaction_payment::Pallet<Self>;
-	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
-	type ChainExtension = NFTExtension;
-	type DeletionQueueDepth = DeletionQueueDepth;
-	type DeletionWeightLimit = DeletionWeightLimit;
-	type Schedule = Schedule;
-	type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
+construct_runtime!(quartz);
 
-parameter_types! {
-	/// This value increases the priority of `Operational` transactions by adding
-	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
-	pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
-	T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
-	type Balance = T;
-
-	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
-		smallvec!(WeightToFeeCoefficient {
-			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
-			coeff_frac: Perbill::zero(),
-			negative: false,
-			degree: 1,
-		})
-	}
-}
-
-impl pallet_transaction_payment::Config for Runtime {
-	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
-	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
-	type OperationalFeeMultiplier = OperationalFeeMultiplier;
-	type WeightToFee = LinearFee<Balance>;
-	type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
-	pub const ProposalBond: Permill = Permill::from_percent(5);
-	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
-	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
-	pub const SpendPeriod: BlockNumber = 5 * MINUTES;
-	pub const Burn: Permill = Permill::from_percent(0);
-	pub const TipCountdown: BlockNumber = 1 * DAYS;
-	pub const TipFindersFee: Percent = Percent::from_percent(20);
-	pub const TipReportDepositBase: Balance = 1 * UNIQUE;
-	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
-	pub const BountyDepositBase: Balance = 1 * UNIQUE;
-	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
-	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
-	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
-	pub const MaximumReasonLength: u32 = 16384;
-	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
-	pub const BountyValueMinimum: Balance = 5 * UNIQUE;
-	pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
-	type PalletId = TreasuryModuleId;
-	type Currency = Balances;
-	type ApproveOrigin = EnsureRoot<AccountId>;
-	type RejectOrigin = EnsureRoot<AccountId>;
-	type Event = Event;
-	type OnSlash = ();
-	type ProposalBond = ProposalBond;
-	type ProposalBondMinimum = ProposalBondMinimum;
-	type ProposalBondMaximum = ProposalBondMaximum;
-	type SpendPeriod = SpendPeriod;
-	type Burn = Burn;
-	type BurnDestination = ();
-	type SpendFunds = ();
-	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
-	type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
-	for RelayChainBlockNumberProvider<T>
-{
-	type BlockNumber = BlockNumber;
-
-	fn current_block_number() -> Self::BlockNumber {
-		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
-			.map(|d| d.relay_parent_number)
-			.unwrap_or_default()
-	}
-}
-
-parameter_types! {
-	pub const MinVestedTransfer: Balance = 10 * UNIQUE;
-	pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
-	type Event = Event;
-	type Currency = pallet_balances::Pallet<Runtime>;
-	type MinVestedTransfer = MinVestedTransfer;
-	type VestedTransferOrigin = EnsureSigned<AccountId>;
-	type WeightInfo = ();
-	type MaxVestingSchedules = MaxVestingSchedules;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
-	type Event = Event;
-	type SelfParaId = parachain_info::Pallet<Self>;
-	type OnSystemEvent = ();
-	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
-	// 	MaxDownwardMessageWeight,
-	// 	XcmExecutor<XcmConfig>,
-	// 	Call,
-	// >;
-	type OutboundXcmpMessageSource = XcmpQueue;
-	type DmpMessageHandler = DmpQueue;
-	type ReservedDmpWeight = ReservedDmpWeight;
-	type ReservedXcmpWeight = ReservedXcmpWeight;
-	type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
-	pub const RelayLocation: MultiLocation = MultiLocation::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
-	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
-	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
-	// The parent (Relay-chain) origin converts to the default `AccountId`.
-	ParentIsPreset<AccountId>,
-	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
-	SiblingParachainConvertsVia<Sibling, AccountId>,
-	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
-	AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
-	fn matches_fungible(a: &MultiAsset) -> Option<B> {
-		match (&a.id, &a.fun) {
-			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
-			_ => None,
-		}
-	}
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
-	// Use this currency:
-	Balances,
-	// Use this currency when it is a fungible asset matching the given location or name:
-	OnlySelfCurrency,
-	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
-	LocationToAccountId,
-	// Our chain's account ID type (we can't get away without mentioning it explicitly):
-	AccountId,
-	// We don't track any teleports.
-	(),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
-	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
-	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
-	// foreign chains who want to have a local sovereign account on this chain which they control.
-	SovereignSignedViaLocation<LocationToAccountId, Origin>,
-	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
-	// recognised.
-	RelayChainAsNative<RelayOrigin, Origin>,
-	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
-	// recognised.
-	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
-	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
-	// transaction from the Root origin.
-	ParentAsSuperuser<Origin>,
-	// Native signed account converter; this just converts an `AccountId32` origin into a normal
-	// `Origin::Signed` origin of the same 32-byte value.
-	SignedAccountId32AsNative<RelayNetwork, Origin>,
-	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
-	XcmPassthrough<Origin>,
-);
-
-parameter_types! {
-	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
-	pub UnitWeightCost: Weight = 1_000_000;
-	// 1200 UNIQUEs buy 1 second of weight.
-	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
-	pub const MaxInstructions: u32 = 100;
-	pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
-	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
-		MultiLocation { parents: 1, interior: Here } |
-		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
-	};
-}
-
-pub type Barrier = (
-	TakeWeightCredit,
-	AllowTopLevelPaidExecutionFrom<Everything>,
-	// ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
-	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-	AssetId: Get<MultiLocation>,
-	AccountId,
-	Currency: CurrencyT<AccountId>,
-	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
-	Weight,
-	Currency::Balance,
-	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> WeightTrader
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn new() -> Self {
-		Self(0, Zero::zero(), PhantomData)
-	}
-
-	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
-		let amount = WeightToFee::weight_to_fee(&weight);
-		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
-		// location to this parachain through relay chain
-		let option1: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 1,
-			interior: X1(Parachain(ParachainInfo::parachain_id().into())),
-		});
-		// direct location
-		let option2: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 0,
-			interior: Here,
-		});
-
-		let required = if payment.fungible.contains_key(&option1) {
-			(option1, u128_amount).into()
-		} else if payment.fungible.contains_key(&option2) {
-			(option2, u128_amount).into()
-		} else {
-			(Concrete(MultiLocation::default()), u128_amount).into()
-		};
-
-		let unused = payment
-			.checked_sub(required)
-			.map_err(|_| XcmError::TooExpensive)?;
-		self.0 = self.0.saturating_add(weight);
-		self.1 = self.1.saturating_add(amount);
-		Ok(unused)
-	}
-
-	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
-		let weight = weight.min(self.0);
-		let amount = WeightToFee::weight_to_fee(&weight);
-		self.0 -= weight;
-		self.1 = self.1.saturating_sub(amount);
-		let amount: u128 = amount.saturated_into();
-		if amount > 0 {
-			Some((AssetId::get(), amount).into())
-		} else {
-			None
-		}
-	}
-}
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> Drop
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn drop(&mut self) {
-		OnUnbalanced::on_unbalanced(Currency::issue(self.1));
-	}
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
-	type Call = Call;
-	type XcmSender = XcmRouter;
-	// How to withdraw and deposit an asset.
-	type AssetTransactor = LocalAssetTransactor;
-	type OriginConverter = XcmOriginToTransactDispatchOrigin;
-	type IsReserve = NativeAsset;
-	type IsTeleporter = (); // Teleportation is disabled
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Barrier = Barrier;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type Trader =
-		UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
-	type ResponseHandler = (); // Don't handle responses for now.
-	type SubscriptionService = PolkadotXcm;
-
-	type AssetTrap = PolkadotXcm;
-	type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// 	pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
-	// Two routers - use UMP to communicate with the relay chain:
-	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
-	// ..and XCMP to communicate with the sibling chains.
-	XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmRouter = XcmRouter;
-	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmExecuteFilter = Everything;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type XcmTeleportFilter = Everything;
-	type XcmReserveTransferFilter = Everything;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Origin = Origin;
-	type Call = Call;
-	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
-	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
-	type WeightInfo = ();
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ChannelInfo = ParachainSystem;
-	type VersionWrapper = ();
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-	type ControllerOrigin = EnsureRoot<AccountId>;
-	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
-	type AuthorityId = AuraId;
-	type DisabledValidators = ();
-	type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
-	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
-	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
-	type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
-	type Event = Event;
-	type Currency = Balances;
-	type CollectionCreationPrice = CollectionCreationPrice;
-	type TreasuryAccountId = TreasuryAccountId;
-	type CollectionDispatch = CollectionDispatchT<Self>;
-
-	type EvmTokenAddressMapping = EvmTokenAddressMapping;
-	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
-	type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
-	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
-	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
-	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_proxy_rmrk_core::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
-	type Event = Event;
-}
-
-impl pallet_proxy_rmrk_equip::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
-	type Event = Event;
-}
-
-impl pallet_unique::Config for Runtime {
-	type Event = Event;
-	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
-	type CommonWeightInfo = CommonWeights<Self>;
-	type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
-	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
-	type Currency = Balances;
-	type TreasuryAccountId = TreasuryAccountId;
-	type InflationBlockInterval = InflationBlockInterval;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
-		RuntimeBlockWeights::get().max_block;
-	pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
-	(
-		frame_system::CheckSpecVersion::<Runtime>::new(),
-		frame_system::CheckGenesis::<Runtime>::new(),
-		frame_system::CheckEra::<Runtime>::from(Era::Immortal),
-		frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
-			from,
-		)),
-		frame_system::CheckWeight::<Runtime>::new(),
-		// sponsoring transaction logic
-		// pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
-	)
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
-	DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
-	<T as frame_system::Config>::Call: Member
-		+ Dispatchable<Origin = Origin, Info = DispatchInfo>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
-		+ GetDispatchInfo
-		+ From<frame_system::Call<Runtime>>,
-	SelfContainedSignedInfo: Send + Sync + 'static,
-	Call: From<<T as frame_system::Config>::Call>
-		+ From<<T as pallet_unique_scheduler::Config>::Call>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
-	sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
-	fn dispatch_call(
-		signer: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<
-		Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
-		TransactionValidityError,
-	> {
-		let dispatch_info = call.get_dispatch_info();
-		let extrinsic = fp_self_contained::CheckedExtrinsic::<
-			AccountId,
-			Call,
-			SignedExtraScheduler,
-			SelfContainedSignedInfo,
-		> {
-			signed:
-				CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
-					signer.clone().into(),
-					get_signed_extras(signer.into()),
-				),
-			function: call.into(),
-		};
-
-		extrinsic.apply::<Runtime>(&dispatch_info, 0)
-	}
-
-	fn reserve_balance(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-		count: u32,
-	) -> Result<(), DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
-			.saturating_mul(count.into());
-
-		<Balances as NamedReservableCurrency<AccountId>>::reserve_named(
-			&id,
-			&(sponsor.into()),
-			weight.into(),
-		)
-	}
-
-	fn pay_for_call(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<u128, DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				weight.into(),
-			),
-		)
-	}
-
-	fn cancel_reserve(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-	) -> Result<u128, DispatchError> {
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				u128::MAX,
-			),
-		)
-	}
-}
-
-parameter_types! {
-	pub const NoPreimagePostponement: Option<u32> = Some(10);
-	pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
-	fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
-		Some(Ordering::Equal)
-	}
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
-	type Event = Event;
-	type Origin = Origin;
-	type Currency = Balances;
-	type PalletsOrigin = OriginCaller;
-	type Call = Call;
-	type MaximumWeight = MaximumSchedulerWeight;
-	type ScheduleOrigin = EnsureSigned<AccountId>;
-	type MaxScheduledPerBlock = MaxScheduledPerBlock;
-	type WeightInfo = ();
-	type CallExecutor = SchedulerPaymentExecutor;
-	type OriginPrivilegeCmp = OriginPrivilegeCmp;
-	type PreimageProvider = ();
-	type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
-	UniqueEthSponsorshipHandler<Runtime>,
-	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-type SponsorshipHandler = (
-	UniqueSponsorshipHandler<Runtime>,
-	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
-	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
-	type EvmSponsorshipHandler = EvmSponsorshipHandler;
-	type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
-	type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-//	 type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
-	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049
-	pub const HelpersContractAddress: H160 = H160([
-		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
-	]);
-
-	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelpersAddress: H160 = H160([
-		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
-	]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
-	type ContractAddress = HelpersContractAddress;
-	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
-	pub enum Runtime where
-		Block = Block,
-		NodeBlock = opaque::Block,
-		UncheckedExtrinsic = UncheckedExtrinsic
-	{
-		ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
-		ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
-		Aura: pallet_aura::{Pallet, Config<T>} = 22,
-		AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
-		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
-		RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
-		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
-		TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
-		Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
-		Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
-		System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
-		Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
-		// Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
-		// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
-		// XCM helpers.
-		XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
-		PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
-		CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
-		DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
-		// Unique Pallets
-		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
-		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
-		Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
-		// free = 63
-		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
-		// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
-		Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
-		Fungible: pallet_fungible::{Pallet, Storage} = 67,
-		Refungible: pallet_refungible::{Pallet, Storage} = 68,
-		Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
-		Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
-		RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
-		RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
-
-		// Frontier
-		EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
-		Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
-		EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
-		EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
-		EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
-		EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
-	}
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
-		UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		)
-	}
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(
-		&self,
-		transaction: pallet_ethereum::Transaction,
-	) -> opaque::UncheckedExtrinsic {
-		let extrinsic = UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		);
-		let encoded = extrinsic.encode();
-		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
-			.expect("Encoded extrinsic is always valid")
-	}
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
-	frame_system::CheckSpecVersion<Runtime>,
-	// system::CheckTxVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-	ChargeTransactionPayment,
-	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
-	pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-
-pub type SignedExtraScheduler = (
-	frame_system::CheckSpecVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-	// pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
-	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
-	Runtime,
-	Block,
-	frame_system::ChainContext<Runtime>,
-	Runtime,
-	AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
-	pub struct SessionKeys {
-		pub aura: Aura,
-	}
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
-	type SignedInfo = H160;
-
-	fn is_self_contained(&self) -> bool {
-		match self {
-			Call::Ethereum(call) => call.is_self_contained(),
-			_ => false,
-		}
-	}
-
-	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.check_self_contained(),
-			_ => None,
-		}
-	}
-
-	fn validate_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-		dispatch_info: &DispatchInfoOf<Call>,
-		len: usize,
-	) -> Option<TransactionValidity> {
-		match self {
-			Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
-			_ => None,
-		}
-	}
-
-	fn pre_dispatch_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-	) -> Option<Result<(), TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
-			_ => None,
-		}
-	}
-
-	fn apply_self_contained(
-		self,
-		info: Self::SignedInfo,
-	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
-		match self {
-			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
-				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
-			)),
-			_ => None,
-		}
-	}
-}
-
-macro_rules! dispatch_unique_runtime {
-	($collection:ident.$method:ident($($name:ident),*)) => {{
-		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
-		let dispatch = collection.as_dyn();
-
-		Ok::<_, DispatchError>(dispatch.$method($($name),*))
-	}};
-}
-
-impl_common_runtime_apis! {
-	#![custom_apis]
-
-	impl rmrk_rpc::RmrkApi<
-		Block,
-		AccountId,
-		RmrkCollectionInfo<AccountId>,
-		RmrkInstanceInfo<AccountId>,
-		RmrkResourceInfo,
-		RmrkPropertyInfo,
-		RmrkBaseInfo<AccountId>,
-		RmrkPartType,
-		RmrkTheme
-	> for Runtime {
-		fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>()
-		}
-
-		fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id)
-		}
-
-		fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id)
-		}
-
-		fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id)
-		}
-
-		fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id)
-		}
-
-		fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys)
-		}
-
-		fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys)
-		}
-
-		fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id)
-		}
-
-		fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
-			pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id)
-		}
-
-		fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id)
-		}
-
-		fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id)
-		}
-
-		fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id)
-		}
-
-		fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
-			pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys)
-		}
-	}
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
-	fn check_inherents(
-		block: &Block,
-		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
-	) -> sp_inherents::CheckInherentsResult {
-		let relay_chain_slot = relay_state_proof
-			.read_slot()
-			.expect("Could not read the relay chain slot from the proof");
-
-		let inherent_data =
-			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
-				relay_chain_slot,
-				sp_std::time::Duration::from_secs(6),
-			)
-			.create_inherent_data()
-			.expect("Could not create the timestamp inherent data");
-
-		inherent_data.check_extrinsics(block)
-	}
-}
+impl_common_runtime_apis!();
 
 cumulus_pallet_parachain_system::register_validate_block!(
 	Runtime = Runtime,
modifiedruntime/tests/Cargo.tomldiffbeforeafterboth
--- a/runtime/tests/Cargo.toml
+++ b/runtime/tests/Cargo.toml
@@ -3,8 +3,12 @@
 version = "0.1.0"
 edition = "2021"
 
+[features]
+default = ['refungible']
+
+refungible = []
+
 [dependencies]
-unique-runtime-common = { path = '../common' }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
 
 sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.24' }
@@ -37,3 +41,6 @@
 	"derive",
 ] }
 scale-info = "*"
+
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -35,9 +35,18 @@
 use parity_scale_codec::{Encode, Decode, MaxEncodedLen};
 use scale_info::TypeInfo;
 
-use unique_runtime_common::{dispatch::CollectionDispatchT, weights::CommonWeights};
 use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};
 
+#[path = "../../common/dispatch.rs"]
+mod dispatch;
+
+use dispatch::CollectionDispatchT;
+
+#[path = "../../common/weights.rs"]
+mod weights;
+
+use weights::CommonWeights;
+
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
 type Block = frame_system::mocking::MockBlock<Test>;
 
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -114,13 +114,17 @@
     'xcm/std',
     'xcm-builder/std',
     'xcm-executor/std',
-    'unique-runtime-common/std',
+    'up-common/std',
 
     "orml-vesting/std",
 ]
 limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
 unique-runtime = []
 
+refungible = []
+scheduler = []
+rmrk = []
+
 ################################################################################
 # Substrate Dependencies
 
@@ -397,7 +401,7 @@
 
 [dependencies]
 log = { version = "0.4.16", default-features = false }
-unique-runtime-common = { path = "../common", default-features = false }
+up-common = { path = "../../primitives/common", default-features = false }
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
@@ -427,6 +431,8 @@
 fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
 fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.24' }
 
 ################################################################################
 # Build Dependencies
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -25,166 +25,21 @@
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
-use sp_api::impl_runtime_apis;
-use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};
-use sp_runtime::DispatchError;
-use fp_self_contained::*;
-// #[cfg(any(feature = "std", test))]
-// pub use sp_runtime::BuildStorage;
-
-use sp_runtime::{
-	Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
-	traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero, Member},
-	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, RuntimeAppPublic,
-};
-
-use sp_std::prelude::*;
+use frame_support::parameter_types;
 
-#[cfg(feature = "std")]
-use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
-pub use pallet_transaction_payment::{
-	Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,
-};
-// A few exports that help ease life for downstream crates.
-pub use pallet_balances::Call as BalancesCall;
-pub use pallet_evm::{
-	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
-	OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
-};
-pub use frame_support::{
-	construct_runtime, match_types,
-	dispatch::DispatchResult,
-	PalletId, parameter_types, StorageValue, ConsensusEngineId,
-	traits::{
-		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
-		Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
-		OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance, PrivilegeCmp,
-	},
-	weights::{
-		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
-		DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,
-		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,
-		WeightToFee,
-	},
-};
-use pallet_unique_scheduler::DispatchCall;
-use up_data_structs::{
-	CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
-	CollectionStats, RpcCollection,
-	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
-	TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo,
-	RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, RmrkNftId,
-	RmrkNftChild, RmrkPropertyKey, RmrkResourceId, RmrkBaseId,
-};
+use sp_runtime::create_runtime_str;
 
-// use pallet_contracts::weights::WeightInfo;
-// #[cfg(any(feature = "std", test))]
-use frame_system::{
-	self as frame_system, EnsureRoot, EnsureSigned,
-	limits::{BlockWeights, BlockLength},
-};
-use sp_arithmetic::{
-	traits::{BaseArithmetic, Unsigned},
-};
-use smallvec::smallvec;
-use codec::{Encode, Decode};
-use fp_rpc::TransactionStatus;
-use sp_runtime::{
-	traits::{
-		Applyable, BlockNumberProvider, Dispatchable, PostDispatchInfoOf, DispatchInfoOf,
-		Saturating, CheckedConversion,
-	},
-	generic::Era,
-	transaction_validity::TransactionValidityError,
-	DispatchErrorWithPostInfo, SaturatedConversion,
-};
+use up_common::types::*;
 
-// pub use pallet_timestamp::Call as TimestampCall;
-pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
+#[path = "../../common/mod.rs"]
+mod runtime_common;
 
-// Polkadot imports
-use pallet_xcm::XcmPassthrough;
-use polkadot_parachain::primitives::Sibling;
-use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
-use xcm_builder::{
-	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
-	EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
-	RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
-	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
-	ParentIsPreset,
-};
-use xcm_executor::{Config, XcmExecutor, Assets};
-use sp_std::{cmp::Ordering, marker::PhantomData};
-
-use xcm::latest::{
-	//	Xcm,
-	AssetId::{Concrete},
-	Fungibility::Fungible as XcmFungible,
-	MultiAsset,
-	Error as XcmError,
-};
-use xcm_executor::traits::{MatchesFungible, WeightTrader};
-
-use unique_runtime_common::{
-	impl_common_runtime_apis,
-	types::*,
-	constants::*,
-	dispatch::{CollectionDispatchT, CollectionDispatch},
-	sponsoring::UniqueSponsorshipHandler,
-	eth_sponsoring::UniqueEthSponsorshipHandler,
-	weights::CommonWeights,
-};
+pub use runtime_common::*;
 
 pub const RUNTIME_NAME: &str = "unique";
 pub const TOKEN_SYMBOL: &str = "UNQ";
-
-type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
-
-impl RuntimeInstance for Runtime {
-	type CrossAccountId = self::CrossAccountId;
-	type TransactionConverter = self::TransactionConverter;
-
-	fn get_transaction_converter() -> TransactionConverter {
-		TransactionConverter
-	}
-}
-
-/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
-/// never know...
-pub type AccountIndex = u32;
-
-/// Balance of an account.
-pub type Balance = u128;
-
-/// Index of a transaction in the chain.
-pub type Index = u32;
-
-/// A hash of some data used by the chain.
-pub type Hash = sp_core::H256;
-
-/// Digest item type.
-pub type DigestItem = generic::DigestItem;
-
-/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
-/// the specifics of the runtime. They can then be made to be agnostic over specific formats
-/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
-/// to even the core data structures.
-pub mod opaque {
-	use sp_std::prelude::*;
-	use sp_runtime::impl_opaque_keys;
-	use super::Aura;
-
-	pub use unique_runtime_common::types::*;
 
-	impl_opaque_keys! {
-		pub struct SessionKeys {
-			pub aura: Aura,
-		}
-	}
-}
-
 /// This runtime version.
 pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: create_runtime_str!(RUNTIME_NAME),
@@ -197,1194 +52,15 @@
 	state_version: 0,
 };
 
-#[derive(codec::Encode, codec::Decode)]
-pub enum XCMPMessage<XAccountId, XBalance> {
-	/// Transfer tokens to the given account from the Parachain account.
-	TransferToken(XAccountId, XBalance),
-}
-
-/// The version information used to identify this runtime when compiled natively.
-#[cfg(feature = "std")]
-pub fn native_version() -> NativeVersion {
-	NativeVersion {
-		runtime_version: VERSION,
-		can_author_with: Default::default(),
-	}
-}
-
-type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
-
-pub struct DealWithFees;
-impl OnUnbalanced<NegativeImbalance> for DealWithFees {
-	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
-		if let Some(fees) = fees_then_tips.next() {
-			// for fees, 100% to treasury
-			let mut split = fees.ration(100, 0);
-			if let Some(tips) = fees_then_tips.next() {
-				// for tips, if any, 100% to treasury
-				tips.ration_merge_into(100, 0, &mut split);
-			}
-			Treasury::on_unbalanced(split.0);
-			// Author::on_unbalanced(split.1);
-		}
-	}
-}
-
 parameter_types! {
-	pub const BlockHashCount: BlockNumber = 2400;
-	pub RuntimeBlockLength: BlockLength =
-		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
-	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
-	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
-	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
-		.base_block(BlockExecutionWeight::get())
-		.for_class(DispatchClass::all(), |weights| {
-			weights.base_extrinsic = ExtrinsicBaseWeight::get();
-		})
-		.for_class(DispatchClass::Normal, |weights| {
-			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
-		})
-		.for_class(DispatchClass::Operational, |weights| {
-			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
-			// Operational transactions have some extra reserved space, so that they
-			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
-			weights.reserved = Some(
-				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
-			);
-		})
-		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
-		.build_or_panic();
 	pub const Version: RuntimeVersion = VERSION;
 	pub const SS58Prefix: u16 = 7391;
-}
-
-parameter_types! {
 	pub const ChainId: u64 = 8880;
-}
-
-pub struct FixedFee;
-impl FeeCalculator for FixedFee {
-	fn min_gas_price() -> (U256, u64) {
-		(MIN_GAS_PRICE.into(), 0)
-	}
-}
-
-// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
-// (contract, which only writes a lot of data),
-// approximating on top of our real store write weight
-parameter_types! {
-	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;
-	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
-	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
 }
 
-/// Limiting EVM execution to 50% of block for substrate users and management tasks
-/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
-/// scheduled fairly
-const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
-parameter_types! {
-	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());
-}
-
-pub enum FixedGasWeightMapping {}
-impl GasWeightMapping for FixedGasWeightMapping {
-	fn gas_to_weight(gas: u64) -> Weight {
-		gas.saturating_mul(WeightPerGas::get())
-	}
-	fn weight_to_gas(weight: Weight) -> u64 {
-		weight / WeightPerGas::get()
-	}
-}
-
-impl pallet_evm::account::Config for Runtime {
-	type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;
-	type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
-	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
-impl pallet_evm::Config for Runtime {
-	type BlockGasLimit = BlockGasLimit;
-	type FeeCalculator = FixedFee;
-	type GasWeightMapping = FixedGasWeightMapping;
-	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
-	type CallOrigin = EnsureAddressTruncated<Self>;
-	type WithdrawOrigin = EnsureAddressTruncated<Self>;
-	type AddressMapping = HashedAddressMapping<Self::Hashing>;
-	type PrecompilesType = ();
-	type PrecompilesValue = ();
-	type Currency = Balances;
-	type Event = Event;
-	type OnMethodCall = (
-		pallet_evm_migration::OnMethodCall<Self>,
-		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
-		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
-	);
-	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
-	type ChainId = ChainId;
-	type Runner = pallet_evm::runner::stack::Runner<Self>;
-	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;
-	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;
-	type FindAuthor = EthereumFindAuthor<Aura>;
-}
-
-impl pallet_evm_migration::Config for Runtime {
-	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;
-}
-
-pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
-impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {
-	fn find_author<'a, I>(digests: I) -> Option<H160>
-	where
-		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
-	{
-		if let Some(author_index) = F::find_author(digests) {
-			let authority_id = Aura::authorities()[author_index as usize].clone();
-			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
-		}
-		None
-	}
-}
-
-impl pallet_ethereum::Config for Runtime {
-	type Event = Event;
-	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
-}
-
-impl pallet_randomness_collective_flip::Config for Runtime {}
+construct_runtime!(unique);
 
-impl frame_system::Config for Runtime {
-	/// The data to be stored in an account.
-	type AccountData = pallet_balances::AccountData<Balance>;
-	/// The identifier used to distinguish between accounts.
-	type AccountId = AccountId;
-	/// The basic call filter to use in dispatchable.
-	type BaseCallFilter = Everything;
-	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
-	type BlockHashCount = BlockHashCount;
-	/// The maximum length of a block (in bytes).
-	type BlockLength = RuntimeBlockLength;
-	/// The index type for blocks.
-	type BlockNumber = BlockNumber;
-	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.
-	type BlockWeights = RuntimeBlockWeights;
-	/// The aggregated dispatch type that is available for extrinsics.
-	type Call = Call;
-	/// The weight of database operations that the runtime can invoke.
-	type DbWeight = RocksDbWeight;
-	/// The ubiquitous event type.
-	type Event = Event;
-	/// The type for hashing blocks and tries.
-	type Hash = Hash;
-	/// The hashing algorithm used.
-	type Hashing = BlakeTwo256;
-	/// The header type.
-	type Header = generic::Header<BlockNumber, BlakeTwo256>;
-	/// The index type for storing how many extrinsics an account has signed.
-	type Index = Index;
-	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
-	type Lookup = AccountIdLookup<AccountId, ()>;
-	/// What to do if an account is fully reaped from the system.
-	type OnKilledAccount = ();
-	/// What to do if a new account is created.
-	type OnNewAccount = ();
-	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
-	/// The ubiquitous origin type.
-	type Origin = Origin;
-	/// This type is being generated by `construct_runtime!`.
-	type PalletInfo = PalletInfo;
-	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
-	type SS58Prefix = SS58Prefix;
-	/// Weight information for the extrinsics of this pallet.
-	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;
-	/// Version of the runtime.
-	type Version = Version;
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
-}
-
-impl pallet_timestamp::Config for Runtime {
-	/// A timestamp: milliseconds since the unix epoch.
-	type Moment = u64;
-	type OnTimestampSet = ();
-	type MinimumPeriod = MinimumPeriod;
-	type WeightInfo = ();
-}
-
-parameter_types! {
-	// pub const ExistentialDeposit: u128 = 500;
-	pub const ExistentialDeposit: u128 = 0;
-	pub const MaxLocks: u32 = 50;
-	pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for Runtime {
-	type MaxLocks = MaxLocks;
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 16];
-	/// The type for recording an account's balance.
-	type Balance = Balance;
-	/// The ubiquitous event type.
-	type Event = Event;
-	type DustRemoval = Treasury;
-	type ExistentialDeposit = ExistentialDeposit;
-	type AccountStore = System;
-	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
-}
-
-pub const fn deposit(items: u32, bytes: u32) -> Balance {
-	items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE
-}
-
-/*
-parameter_types! {
-	pub TombstoneDeposit: Balance = deposit(
-		1,
-		sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,
-	);
-	pub DepositPerContract: Balance = TombstoneDeposit::get();
-	pub const DepositPerStorageByte: Balance = deposit(0, 1);
-	pub const DepositPerStorageItem: Balance = deposit(1, 0);
-	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);
-	pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;
-	pub const SignedClaimHandicap: u32 = 2;
-	pub const MaxDepth: u32 = 32;
-	pub const MaxValueSize: u32 = 16 * 1024;
-	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb
-	// The lazy deletion runs inside on_initialize.
-	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
-		RuntimeBlockWeights::get().max_block;
-	// The weight needed for decoding the queue should be less or equal than a fifth
-	// of the overall weight dedicated to the lazy deletion.
-	pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -
-			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)
-		)) / 5) as u32;
-	pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
-}
-
-impl pallet_contracts::Config for Runtime {
-	type Time = Timestamp;
-	type Randomness = RandomnessCollectiveFlip;
-	type Currency = Balances;
-	type Event = 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 WeightPrice = pallet_transaction_payment::Pallet<Self>;
-	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
-	type ChainExtension = NFTExtension;
-	type DeletionQueueDepth = DeletionQueueDepth;
-	type DeletionWeightLimit = DeletionWeightLimit;
-	type Schedule = Schedule;
-	type CallStack = [pallet_contracts::Frame<Self>; 31];
-}
-*/
-
-parameter_types! {
-	/// This value increases the priority of `Operational` transactions by adding
-	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
-	pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-/// Linear implementor of `WeightToFeePolynomial`
-pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);
-
-impl<T> WeightToFeePolynomial for LinearFee<T>
-where
-	T: BaseArithmetic + From<u32> + Copy + Unsigned,
-{
-	type Balance = T;
-
-	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
-		smallvec!(WeightToFeeCoefficient {
-			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),
-			coeff_frac: Perbill::zero(),
-			negative: false,
-			degree: 1,
-		})
-	}
-}
-
-impl pallet_transaction_payment::Config for Runtime {
-	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;
-	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
-	type OperationalFeeMultiplier = OperationalFeeMultiplier;
-	type WeightToFee = LinearFee<Balance>;
-	type FeeMultiplierUpdate = ();
-}
-
-parameter_types! {
-	pub const ProposalBond: Permill = Permill::from_percent(5);
-	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;
-	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;
-	pub const SpendPeriod: BlockNumber = 5 * MINUTES;
-	pub const Burn: Permill = Permill::from_percent(0);
-	pub const TipCountdown: BlockNumber = 1 * DAYS;
-	pub const TipFindersFee: Percent = Percent::from_percent(20);
-	pub const TipReportDepositBase: Balance = 1 * UNIQUE;
-	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;
-	pub const BountyDepositBase: Balance = 1 * UNIQUE;
-	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
-	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
-	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
-	pub const MaximumReasonLength: u32 = 16384;
-	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
-	pub const BountyValueMinimum: Balance = 5 * UNIQUE;
-	pub const MaxApprovals: u32 = 100;
-}
-
-impl pallet_treasury::Config for Runtime {
-	type PalletId = TreasuryModuleId;
-	type Currency = Balances;
-	type ApproveOrigin = EnsureRoot<AccountId>;
-	type RejectOrigin = EnsureRoot<AccountId>;
-	type Event = Event;
-	type OnSlash = ();
-	type ProposalBond = ProposalBond;
-	type ProposalBondMinimum = ProposalBondMinimum;
-	type ProposalBondMaximum = ProposalBondMaximum;
-	type SpendPeriod = SpendPeriod;
-	type Burn = Burn;
-	type BurnDestination = ();
-	type SpendFunds = ();
-	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
-	type MaxApprovals = MaxApprovals;
-}
-
-impl pallet_sudo::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-}
-
-pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
-
-impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
-	for RelayChainBlockNumberProvider<T>
-{
-	type BlockNumber = BlockNumber;
-
-	fn current_block_number() -> Self::BlockNumber {
-		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
-			.map(|d| d.relay_parent_number)
-			.unwrap_or_default()
-	}
-}
-
-parameter_types! {
-	pub const MinVestedTransfer: Balance = 10 * UNIQUE;
-	pub const MaxVestingSchedules: u32 = 28;
-}
-
-impl orml_vesting::Config for Runtime {
-	type Event = Event;
-	type Currency = pallet_balances::Pallet<Runtime>;
-	type MinVestedTransfer = MinVestedTransfer;
-	type VestedTransferOrigin = EnsureSigned<AccountId>;
-	type WeightInfo = ();
-	type MaxVestingSchedules = MaxVestingSchedules;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
-}
-
-impl cumulus_pallet_parachain_system::Config for Runtime {
-	type Event = Event;
-	type SelfParaId = parachain_info::Pallet<Self>;
-	type OnSystemEvent = ();
-	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
-	// 	MaxDownwardMessageWeight,
-	// 	XcmExecutor<XcmConfig>,
-	// 	Call,
-	// >;
-	type OutboundXcmpMessageSource = XcmpQueue;
-	type DmpMessageHandler = DmpQueue;
-	type ReservedDmpWeight = ReservedDmpWeight;
-	type ReservedXcmpWeight = ReservedXcmpWeight;
-	type XcmpMessageHandler = XcmpQueue;
-}
-
-impl parachain_info::Config for Runtime {}
-
-impl cumulus_pallet_aura_ext::Config for Runtime {}
-
-parameter_types! {
-	pub const RelayLocation: MultiLocation = MultiLocation::parent();
-	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;
-	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();
-	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
-}
-
-/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used
-/// when determining ownership of accounts for asset transacting and when attempting to use XCM
-/// `Transact` in order to determine the dispatch Origin.
-pub type LocationToAccountId = (
-	// The parent (Relay-chain) origin converts to the default `AccountId`.
-	ParentIsPreset<AccountId>,
-	// Sibling parachain origins convert to AccountId via the `ParaId::into`.
-	SiblingParachainConvertsVia<Sibling, AccountId>,
-	// Straight up local `AccountId32` origins just alias directly to `AccountId`.
-	AccountId32Aliases<RelayNetwork, AccountId>,
-);
-
-pub struct OnlySelfCurrency;
-impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
-	fn matches_fungible(a: &MultiAsset) -> Option<B> {
-		match (&a.id, &a.fun) {
-			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
-			_ => None,
-		}
-	}
-}
-
-/// Means for transacting assets on this chain.
-pub type LocalAssetTransactor = CurrencyAdapter<
-	// Use this currency:
-	Balances,
-	// Use this currency when it is a fungible asset matching the given location or name:
-	OnlySelfCurrency,
-	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
-	LocationToAccountId,
-	// Our chain's account ID type (we can't get away without mentioning it explicitly):
-	AccountId,
-	// We don't track any teleports.
-	(),
->;
-
-/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
-/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
-/// biases the kind of local `Origin` it will become.
-pub type XcmOriginToTransactDispatchOrigin = (
-	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
-	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
-	// foreign chains who want to have a local sovereign account on this chain which they control.
-	SovereignSignedViaLocation<LocationToAccountId, Origin>,
-	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when
-	// recognised.
-	RelayChainAsNative<RelayOrigin, Origin>,
-	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
-	// recognised.
-	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,
-	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
-	// transaction from the Root origin.
-	ParentAsSuperuser<Origin>,
-	// Native signed account converter; this just converts an `AccountId32` origin into a normal
-	// `Origin::Signed` origin of the same 32-byte value.
-	SignedAccountId32AsNative<RelayNetwork, Origin>,
-	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
-	XcmPassthrough<Origin>,
-);
-
-parameter_types! {
-	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.
-	pub UnitWeightCost: Weight = 1_000_000;
-	// 1200 UNIQUEs buy 1 second of weight.
-	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);
-	pub const MaxInstructions: u32 = 100;
-	pub const MaxAuthorities: u32 = 100_000;
-}
-
-match_types! {
-	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
-		MultiLocation { parents: 1, interior: Here } |
-		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
-	};
-}
-
-pub type Barrier = (
-	TakeWeightCredit,
-	AllowTopLevelPaidExecutionFrom<Everything>,
-	// ^^^ Parent & its unit plurality gets free execution
-);
-
-pub struct UsingOnlySelfCurrencyComponents<
-	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-	AssetId: Get<MultiLocation>,
-	AccountId,
-	Currency: CurrencyT<AccountId>,
-	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
->(
-	Weight,
-	Currency::Balance,
-	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
-);
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> WeightTrader
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn new() -> Self {
-		Self(0, Zero::zero(), PhantomData)
-	}
-
-	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
-		let amount = WeightToFee::weight_to_fee(&weight);
-		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
-
-		// location to this parachain through relay chain
-		let option1: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 1,
-			interior: X1(Parachain(ParachainInfo::parachain_id().into())),
-		});
-		// direct location
-		let option2: xcm::v1::AssetId = Concrete(MultiLocation {
-			parents: 0,
-			interior: Here,
-		});
-
-		let required = if payment.fungible.contains_key(&option1) {
-			(option1, u128_amount).into()
-		} else if payment.fungible.contains_key(&option2) {
-			(option2, u128_amount).into()
-		} else {
-			(Concrete(MultiLocation::default()), u128_amount).into()
-		};
-
-		let unused = payment
-			.checked_sub(required)
-			.map_err(|_| XcmError::TooExpensive)?;
-		self.0 = self.0.saturating_add(weight);
-		self.1 = self.1.saturating_add(amount);
-		Ok(unused)
-	}
-
-	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
-		let weight = weight.min(self.0);
-		let amount = WeightToFee::weight_to_fee(&weight);
-		self.0 -= weight;
-		self.1 = self.1.saturating_sub(amount);
-		let amount: u128 = amount.saturated_into();
-		if amount > 0 {
-			Some((AssetId::get(), amount).into())
-		} else {
-			None
-		}
-	}
-}
-impl<
-		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
-		AssetId: Get<MultiLocation>,
-		AccountId,
-		Currency: CurrencyT<AccountId>,
-		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
-	> Drop
-	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
-{
-	fn drop(&mut self) {
-		OnUnbalanced::on_unbalanced(Currency::issue(self.1));
-	}
-}
-
-pub struct XcmConfig;
-impl Config for XcmConfig {
-	type Call = Call;
-	type XcmSender = XcmRouter;
-	// How to withdraw and deposit an asset.
-	type AssetTransactor = LocalAssetTransactor;
-	type OriginConverter = XcmOriginToTransactDispatchOrigin;
-	type IsReserve = NativeAsset;
-	type IsTeleporter = (); // Teleportation is disabled
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Barrier = Barrier;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type Trader =
-		UsingOnlySelfCurrencyComponents<LinearFee<Balance>, RelayLocation, AccountId, Balances, ()>;
-	type ResponseHandler = (); // Don't handle responses for now.
-	type SubscriptionService = PolkadotXcm;
-
-	type AssetTrap = PolkadotXcm;
-	type AssetClaims = PolkadotXcm;
-}
-
-// parameter_types! {
-// 	pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;
-// }
-
-/// No local origins on this chain are allowed to dispatch XCM sends/executions.
-pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);
-
-/// The means for routing XCM messages which are not for local execution into the right message
-/// queues.
-pub type XcmRouter = (
-	// Two routers - use UMP to communicate with the relay chain:
-	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,
-	// ..and XCMP to communicate with the sibling chains.
-	XcmpQueue,
-);
-
-impl pallet_evm_coder_substrate::Config for Runtime {}
-
-impl pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmRouter = XcmRouter;
-	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
-	type XcmExecuteFilter = Everything;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type XcmTeleportFilter = Everything;
-	type XcmReserveTransferFilter = Everything;
-	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
-	type LocationInverter = LocationInverter<Ancestry>;
-	type Origin = Origin;
-	type Call = Call;
-	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
-	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
-}
-
-impl cumulus_pallet_xcm::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-}
-
-impl cumulus_pallet_xcmp_queue::Config for Runtime {
-	type WeightInfo = ();
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ChannelInfo = ParachainSystem;
-	type VersionWrapper = ();
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-	type ControllerOrigin = EnsureRoot<AccountId>;
-	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-}
-
-impl cumulus_pallet_dmp_queue::Config for Runtime {
-	type Event = Event;
-	type XcmExecutor = XcmExecutor<XcmConfig>;
-	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
-}
-
-impl pallet_aura::Config for Runtime {
-	type AuthorityId = AuraId;
-	type DisabledValidators = ();
-	type MaxAuthorities = MaxAuthorities;
-}
-
-parameter_types! {
-	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();
-	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;
-}
-
-impl pallet_common::Config for Runtime {
-	type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;
-	type Event = Event;
-	type Currency = Balances;
-	type CollectionCreationPrice = CollectionCreationPrice;
-	type TreasuryAccountId = TreasuryAccountId;
-	type CollectionDispatch = CollectionDispatchT<Self>;
-
-	type EvmTokenAddressMapping = EvmTokenAddressMapping;
-	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
-	type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_structure::Config for Runtime {
-	type Event = Event;
-	type Call = Call;
-	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_fungible::Config for Runtime {
-	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_refungible::Config for Runtime {
-	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;
-}
-impl pallet_nonfungible::Config for Runtime {
-	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;
-}
-
-impl pallet_unique::Config for Runtime {
-	type Event = Event;
-	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
-	type CommonWeightInfo = CommonWeights<Self>;
-	type RefungibleExtensionsWeightInfo = CommonWeights<Self>;
-}
-
-parameter_types! {
-	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied
-}
-
-/// Used for the pallet inflation
-impl pallet_inflation::Config for Runtime {
-	type Currency = Balances;
-	type TreasuryAccountId = TreasuryAccountId;
-	type InflationBlockInterval = InflationBlockInterval;
-	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
-}
-
-parameter_types! {
-	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *
-		RuntimeBlockWeights::get().max_block;
-	pub const MaxScheduledPerBlock: u32 = 50;
-}
-
-type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
-use frame_support::traits::NamedReservableCurrency;
-
-fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {
-	(
-		frame_system::CheckSpecVersion::<Runtime>::new(),
-		frame_system::CheckGenesis::<Runtime>::new(),
-		frame_system::CheckEra::<Runtime>::from(Era::Immortal),
-		frame_system::CheckNonce::<Runtime>::from(frame_system::Pallet::<Runtime>::account_nonce(
-			from,
-		)),
-		frame_system::CheckWeight::<Runtime>::new(),
-		// sponsoring transaction logic
-		// pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),
-	)
-}
-
-pub struct SchedulerPaymentExecutor;
-impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>
-	DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor
-where
-	<T as frame_system::Config>::Call: Member
-		+ Dispatchable<Origin = Origin, Info = DispatchInfo>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>
-		+ GetDispatchInfo
-		+ From<frame_system::Call<Runtime>>,
-	SelfContainedSignedInfo: Send + Sync + 'static,
-	Call: From<<T as frame_system::Config>::Call>
-		+ From<<T as pallet_unique_scheduler::Config>::Call>
-		+ SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,
-	sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,
-{
-	fn dispatch_call(
-		signer: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<
-		Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,
-		TransactionValidityError,
-	> {
-		let dispatch_info = call.get_dispatch_info();
-		let extrinsic = fp_self_contained::CheckedExtrinsic::<
-			AccountId,
-			Call,
-			SignedExtraScheduler,
-			SelfContainedSignedInfo,
-		> {
-			signed:
-				CheckedSignature::<AccountId, SignedExtraScheduler, SelfContainedSignedInfo>::Signed(
-					signer.clone().into(),
-					get_signed_extras(signer.into()),
-				),
-			function: call.into(),
-		};
-
-		extrinsic.apply::<Runtime>(&dispatch_info, 0)
-	}
-
-	fn reserve_balance(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-		count: u32,
-	) -> Result<(), DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)
-			.saturating_mul(count.into());
-
-		<Balances as NamedReservableCurrency<AccountId>>::reserve_named(
-			&id,
-			&(sponsor.into()),
-			weight,
-		)
-	}
-
-	fn pay_for_call(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-		call: <T as pallet_unique_scheduler::Config>::Call,
-	) -> Result<u128, DispatchError> {
-		let dispatch_info = call.get_dispatch_info();
-		let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				weight,
-			),
-		)
-	}
-
-	fn cancel_reserve(
-		id: [u8; 16],
-		sponsor: <T as frame_system::Config>::AccountId,
-	) -> Result<u128, DispatchError> {
-		Ok(
-			<Balances as NamedReservableCurrency<AccountId>>::unreserve_named(
-				&id,
-				&(sponsor.into()),
-				u128::MAX,
-			),
-		)
-	}
-}
-
-parameter_types! {
-	pub const NoPreimagePostponement: Option<u32> = Some(10);
-	pub const Preimage: Option<u32> = Some(10);
-}
-
-/// Used the compare the privilege of an origin inside the scheduler.
-pub struct OriginPrivilegeCmp;
-
-impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {
-	fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {
-		Some(Ordering::Equal)
-	}
-}
-
-impl pallet_unique_scheduler::Config for Runtime {
-	type Event = Event;
-	type Origin = Origin;
-	type Currency = Balances;
-	type PalletsOrigin = OriginCaller;
-	type Call = Call;
-	type MaximumWeight = MaximumSchedulerWeight;
-	type ScheduleOrigin = EnsureSigned<AccountId>;
-	type MaxScheduledPerBlock = MaxScheduledPerBlock;
-	type WeightInfo = ();
-	type CallExecutor = SchedulerPaymentExecutor;
-	type OriginPrivilegeCmp = OriginPrivilegeCmp;
-	type PreimageProvider = ();
-	type NoPreimagePostponement = NoPreimagePostponement;
-}
-
-type EvmSponsorshipHandler = (
-	UniqueEthSponsorshipHandler<Runtime>,
-	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
-);
-type SponsorshipHandler = (
-	UniqueSponsorshipHandler<Runtime>,
-	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
-	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
-);
-
-impl pallet_evm_transaction_payment::Config for Runtime {
-	type EvmSponsorshipHandler = EvmSponsorshipHandler;
-	type Currency = Balances;
-}
-
-impl pallet_charge_transaction::Config for Runtime {
-	type SponsorshipHandler = SponsorshipHandler;
-}
-
-// impl pallet_contract_helpers::Config for Runtime {
-//	 type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-// }
-
-parameter_types! {
-	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049
-	pub const HelpersContractAddress: H160 = H160([
-		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
-	]);
-
-	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelpersAddress: H160 = H160([
-		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
-	]);
-}
-
-impl pallet_evm_contract_helpers::Config for Runtime {
-	type ContractAddress = HelpersContractAddress;
-	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
-}
-
-construct_runtime!(
-	pub enum Runtime where
-		Block = Block,
-		NodeBlock = opaque::Block,
-		UncheckedExtrinsic = UncheckedExtrinsic
-	{
-		ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,
-		ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,
-
-		Aura: pallet_aura::{Pallet, Config<T>} = 22,
-		AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,
-
-		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,
-		RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,
-		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,
-		TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,
-		Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
-		Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
-		System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,
-		Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
-		// Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
-		// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
-
-		// XCM helpers.
-		XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,
-		PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,
-		CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,
-		DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,
-
-		// Unique Pallets
-		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
-		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
-		Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
-		// free = 63
-		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
-		// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,
-		Common: pallet_common::{Pallet, Storage, Event<T>} = 66,
-		Fungible: pallet_fungible::{Pallet, Storage} = 67,
-		Refungible: pallet_refungible::{Pallet, Storage} = 68,
-		Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
-		Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
-
-		// Frontier
-		EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,
-		Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
-
-		EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
-		EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
-		EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
-		EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
-	}
-);
-
-pub struct TransactionConverter;
-
-impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
-		UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		)
-	}
-}
-
-impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
-	fn convert_transaction(
-		&self,
-		transaction: pallet_ethereum::Transaction,
-	) -> opaque::UncheckedExtrinsic {
-		let extrinsic = UncheckedExtrinsic::new_unsigned(
-			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
-		);
-		let encoded = extrinsic.encode();
-		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
-			.expect("Encoded extrinsic is always valid")
-	}
-}
-
-/// The address format for describing accounts.
-pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
-/// Block header type as expected by this runtime.
-pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
-/// Block type as expected by this runtime.
-pub type Block = generic::Block<Header, UncheckedExtrinsic>;
-/// A Block signed with a Justification
-pub type SignedBlock = generic::SignedBlock<Block>;
-/// BlockId type as expected by this runtime.
-pub type BlockId = generic::BlockId<Block>;
-/// The SignedExtension to the basic transaction logic.
-pub type SignedExtra = (
-	frame_system::CheckSpecVersion<Runtime>,
-	// system::CheckTxVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-	pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
-	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
-	pallet_ethereum::FakeTransactionFinalizer<Runtime>,
-);
-pub type SignedExtraScheduler = (
-	frame_system::CheckSpecVersion<Runtime>,
-	frame_system::CheckGenesis<Runtime>,
-	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
-	frame_system::CheckWeight<Runtime>,
-	// pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
-);
-/// Unchecked extrinsic type as expected by this runtime.
-pub type UncheckedExtrinsic =
-	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
-/// Extrinsic type that has already been checked.
-pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;
-/// Executive: handles dispatch to the various modules.
-pub type Executive = frame_executive::Executive<
-	Runtime,
-	Block,
-	frame_system::ChainContext<Runtime>,
-	Runtime,
-	AllPalletsReversedWithSystemFirst,
->;
-
-impl_opaque_keys! {
-	pub struct SessionKeys {
-		pub aura: Aura,
-	}
-}
-
-impl fp_self_contained::SelfContainedCall for Call {
-	type SignedInfo = H160;
-
-	fn is_self_contained(&self) -> bool {
-		match self {
-			Call::Ethereum(call) => call.is_self_contained(),
-			_ => false,
-		}
-	}
-
-	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.check_self_contained(),
-			_ => None,
-		}
-	}
-
-	fn validate_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-		dispatch_info: &DispatchInfoOf<Call>,
-		len: usize,
-	) -> Option<TransactionValidity> {
-		match self {
-			Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
-			_ => None,
-		}
-	}
-
-	fn pre_dispatch_self_contained(
-		&self,
-		info: &Self::SignedInfo,
-	) -> Option<Result<(), TransactionValidityError>> {
-		match self {
-			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),
-			_ => None,
-		}
-	}
-
-	fn apply_self_contained(
-		self,
-		info: Self::SignedInfo,
-	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
-		match self {
-			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(
-				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),
-			)),
-			_ => None,
-		}
-	}
-}
-
-macro_rules! dispatch_unique_runtime {
-	($collection:ident.$method:ident($($name:ident),*)) => {{
-		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
-		let dispatch = collection.as_dyn();
-
-		Ok::<_, DispatchError>(dispatch.$method($($name),*))
-	}};
-}
-
-impl_common_runtime_apis! {
-	#![custom_apis]
-
-	impl rmrk_rpc::RmrkApi<
-		Block,
-		AccountId,
-		RmrkCollectionInfo<AccountId>,
-		RmrkInstanceInfo<AccountId>,
-		RmrkResourceInfo,
-		RmrkPropertyInfo,
-		RmrkBaseInfo<AccountId>,
-		RmrkPartType,
-		RmrkTheme
-	> for Runtime {
-		fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn collection_by_id(_collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result<Option<u32>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn base(_base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn base_parts(_base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn theme_names(_base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
-			Ok(Default::default())
-		}
-
-		fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
-			Ok(Default::default())
-		}
-	}
-}
-
-struct CheckInherents;
-
-impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
-	fn check_inherents(
-		block: &Block,
-		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
-	) -> sp_inherents::CheckInherentsResult {
-		let relay_chain_slot = relay_state_proof
-			.read_slot()
-			.expect("Could not read the relay chain slot from the proof");
-
-		let inherent_data =
-			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
-				relay_chain_slot,
-				sp_std::time::Duration::from_secs(6),
-			)
-			.create_inherent_data()
-			.expect("Could not create the timestamp inherent data");
-
-		inherent_data.check_extrinsics(block)
-	}
-}
+impl_common_runtime_apis!();
 
 cumulus_pallet_parachain_system::register_validate_block!(
 	Runtime = Runtime,
modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -32,6 +32,8 @@
   getCreatedCollectionCount,
   transferFromExpectSuccess,
   transferFromExpectFail,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -49,34 +51,44 @@
     });
   });
 
-  it('Execute the extrinsic and check approvedList', async () => {
+  it('[nft] Execute the extrinsic and check approvedList', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
-    // fungible
+  });
+
+  it('[fungible] Execute the extrinsic and check approvedList', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-    // reFungible
+  });
+
+  it('[refungible] Execute the extrinsic and check approvedList', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
   });
 
-  it('Remove approval by using 0 amount', async () => {
+  it('[nft] Remove approval by using 0 amount', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 1);
     await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 0);
-    // fungible
+  });
+
+  it('[fungible] Remove approval by using 0 amount', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 1);
     await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 0);
-    // reFungible
+  });
+
+  it('[refungible] Remove approval by using 0 amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -117,7 +129,9 @@
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -151,7 +165,9 @@
     await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible');
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -188,7 +204,9 @@
     await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1);
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address);
     await approveExpectSuccess(collectionId, itemId, bob, charlie.address);
@@ -250,7 +268,9 @@
     await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, bob, charlie, 1);
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -285,7 +305,9 @@
     await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, charlie, 11);
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, charlie, 101);
@@ -325,7 +347,9 @@
     await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'Fungible');
   });
 
-  it('ReFungible up to an approved amount', async () => {
+  it('ReFungible up to an approved amount', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
     await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
     const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);
@@ -422,63 +446,87 @@
     });
   });
 
-  it('Approve for a collection that does not exist', async () => {
+  it('[nft] Approve for a collection that does not exist', async () => {
     await usingApi(async (api: ApiPromise) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
-      // fungible
+    });
+  });
+
+  it('[fungible] Approve for a collection that does not exist', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
-      // reFungible
+    });
+  });
+
+  it('[refungible] Approve for a collection that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
     });
   });
 
-  it('Approve for a collection that was destroyed', async () => {
-    // nft
+  it('[nft] Approve for a collection that was destroyed', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await destroyCollectionExpectSuccess(nftCollectionId);
     await approveExpectFail(nftCollectionId, 1, alice, bob);
-    // fungible
+  });
+
+  it('Approve for a collection that was destroyed', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await destroyCollectionExpectSuccess(fungibleCollectionId);
     await approveExpectFail(fungibleCollectionId, 0, alice, bob);
-    // reFungible
+  });
+
+  it('[refungible] Approve for a collection that was destroyed', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(reFungibleCollectionId);
     await approveExpectFail(reFungibleCollectionId, 1, alice, bob);
   });
 
-  it('Approve transfer of a token that does not exist', async () => {
-    // nft
+  it('[nft] Approve transfer of a token that does not exist', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await approveExpectFail(nftCollectionId, 2, alice, bob);
-    // reFungible
+  });
+
+  it('[refungible] Approve transfer of a token that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await approveExpectFail(reFungibleCollectionId, 2, alice, bob);
   });
 
-  it('Approve using the address that does not own the approved token', async () => {
+  it('[nft] Approve using the address that does not own the approved token', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
-    // nft
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice);
-    // fungible
+  });
+
+  it('[fungible] Approve using the address that does not own the approved token', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice);
-    // reFungible
+  });
+
+  it('[refungible] Approve using the address that does not own the approved token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId =
       await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, alice);
   });
 
-  it('should fail if approved more ReFungibles than owned', async () => {
+  it('should fail if approved more ReFungibles than owned', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'ReFungible');
     await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 100, 'ReFungible');
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -25,6 +25,8 @@
   getBalance,
   setCollectionLimitsExpectSuccess,
   isTokenExists,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 import chai from 'chai';
@@ -80,7 +82,9 @@
     });
   });
 
-  it('Burn item in ReFungible collection', async () => {
+  it('Burn item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -99,7 +103,9 @@
     });
   });
 
-  it('Burn owned portion of item in ReFungible collection', async () => {
+  it('Burn owned portion of item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
@@ -189,7 +195,9 @@
   });
 
   // TODO: burnFrom
-  it('Burn item in ReFungible collection', async () => {
+  it('Burn item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -33,6 +33,8 @@
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
   UNIQUE,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -124,7 +126,9 @@
     });
   });
 
-  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {
+  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
@@ -252,7 +256,9 @@
     });
   });
 
-  it('ReFungible: Sponsoring is rate limited', async () => {
+  it('ReFungible: Sponsoring is rate limited', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -16,7 +16,7 @@
 
 import {expect} from 'chai';
 import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
-import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess} from './util/helpers';
+import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess, requirePallets, Pallets} from './util/helpers';
 
 describe('integration test: ext. createCollection():', () => {
   it('Create new NFT collection', async () => {
@@ -34,7 +34,9 @@
   it('Create new Fungible collection', async () => {
     await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
   });
-  it('Create new ReFungible collection', async () => {
+  it('Create new ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
   });
 
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.test.ts
@@ -29,6 +29,8 @@
   itApi,
   normalizeAccountId,
   getCreateItemResult,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 const expect = chai.expect;
@@ -79,7 +81,9 @@
     }
 
   });
-  it('Create new item in ReFungible collection', async () => {
+  it('Create new item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await createItemExpectSuccess(alice, newCollectionID, createMode);
@@ -96,7 +100,9 @@
     await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
     await createItemExpectSuccess(bob, newCollectionID, createMode);
   });
-  it('Create new item in ReFungible collection with collection admin permissions', async () => {
+  it('Create new item in ReFungible collection with collection admin permissions', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address);
@@ -175,7 +181,9 @@
     });
   });
 
-  it('Check total pieces of ReFungible token', async () => {
+  it('Check total pieces of ReFungible token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const createMode = 'ReFungible';
       const createCollectionResult = await createCollection(api, alice, {mode: {type: createMode}});
@@ -219,7 +227,9 @@
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
     await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
   });
-  it('Regular user cannot create new item in ReFungible collection', async () => {
+  it('Regular user cannot create new item in ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const createMode = 'ReFungible';
     const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected;
@@ -296,7 +306,9 @@
     });
   });
 
-  it('Check total pieces for invalid Refungible token', async () => {
+  it('Check total pieces for invalid Refungible token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
       const collectionId  = createCollectionResult.collectionId;
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -33,6 +33,9 @@
   createCollectionWithPropsExpectSuccess,
   createMultipleItemsWithPropsExpectSuccess,
   getTokenProperties,
+  requirePallets,
+  Pallets,
+  checkPalletsPresence,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -91,7 +94,9 @@
     });
   });
 
-  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -272,7 +277,9 @@
     });
   });
 
-  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+  it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -335,7 +342,9 @@
     });
   });
 
-  it('Regular user cannot create items in active ReFungible collection', async () => {
+  it('Regular user cannot create items in active ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
@@ -358,9 +367,8 @@
     });
   });
 
-  it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {
+  it('Create NFTs that has reached the maximum data limit', async function() {
     await usingApi(async (api, privateKeyWrapper) => {
-      // NFT
       const collectionId = await createCollectionWithPropsExpectSuccess({
         propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}],
       });
@@ -372,8 +380,13 @@
       ];
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
+    });
+  });
 
-      // ReFungible
+  it('Create Refungible tokens that has reached the maximum data limit', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async api => {
       const collectionIdReFungible =
         await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       {
@@ -402,8 +415,15 @@
   it('Create tokens with different types', async () => {
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess();
+
+      const types = ['NFT', 'Fungible'];
+
+      if (await checkPalletsPresence([Pallets.ReFungible])) {
+        types.push('ReFungible');
+      }
+
       const createMultipleItemsTx = api.tx.unique
-        .createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'Fungible', 'ReFungible']);
+        .createMultipleItems(collectionId, normalizeAccountId(alice.address), types);
       await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/);
       // garbage collection :-D // lol
       await destroyCollectionExpectSuccess(collectionId);
modifiedtests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -16,7 +16,7 @@
 
 import {expect} from 'chai';
 import usingApi, {executeTransaction} from './substrate/substrate-api';
-import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties} from './util/helpers';
+import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties, requirePallets, Pallets} from './util/helpers';
 
 describe('Integration Test: createMultipleItemsEx', () => {
   it('can initialize multiple NFT with different owners', async () => {
@@ -146,7 +146,9 @@
     });
   });
 
-  it('can initialize an RFT with multiple owners', async () => {
+  it('can initialize an RFT with multiple owners', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const alice = privateKeyWrapper('//Alice');
       const bob = privateKeyWrapper('//Bob');
@@ -178,7 +180,9 @@
     });
   });
 
-  it('can initialize multiple RFTs with the same owner', async () => {
+  it('can initialize multiple RFTs with the same owner', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       const alice = privateKeyWrapper('//Alice');
       const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
@@ -389,7 +393,9 @@
     });
   });
 
-  it('fails when trying to set multiple owners when creating multiple refungibles', async () => {
+  it('fails when trying to set multiple owners when creating multiple refungibles', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
 
     await usingApi(async (api, privateKeyWrapper) => {
modifiedtests/src/destroyCollection.test.tsdiffbeforeafterboth
--- a/tests/src/destroyCollection.test.ts
+++ b/tests/src/destroyCollection.test.ts
@@ -25,6 +25,8 @@
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
   createItemExpectSuccess,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -38,7 +40,9 @@
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await destroyCollectionExpectSuccess(collectionId);
   });
-  it('ReFungible collection can be destroyed', async () => {
+  it('ReFungible collection can be destroyed', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(collectionId);
   });
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -16,7 +16,7 @@
 
 import {evmToAddress} from '@polkadot/util-crypto';
 import {expect} from 'chai';
-import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
+import {getCreatedCollectionCount, getDetailedCollectionInfo, requirePallets, Pallets} from '../util/helpers';
 import {
   evmCollectionHelpers,
   collectionIdToAddress,
@@ -28,6 +28,10 @@
 } from './util/helpers';
 
 describe('Create RFT collection from EVM', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Create collection', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
@@ -146,6 +150,10 @@
 });
 
 describe('(!negative tests!) Create RFT collection from EVM', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -228,4 +236,4 @@
       .setCollectionLimit('badLimit', 'true')
       .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');
   });
-});
\ No newline at end of file
+});
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -14,12 +14,16 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {createCollectionExpectSuccess, UNIQUE} from '../util/helpers';
+import {createCollectionExpectSuccess, UNIQUE, requirePallets, Pallets} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, tokenIdToAddress} from './util/helpers';
 import reFungibleTokenAbi from './reFungibleTokenAbi.json';
 import {expect} from 'chai';
 
 describe('Refungible: Information getting', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
     const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, caller);
@@ -120,6 +124,10 @@
 });
 
 describe('Refungible: Plain calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -399,6 +407,10 @@
 });
 
 describe('RFT: Fees', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
     const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, caller);
@@ -435,6 +447,10 @@
 });
 
 describe('Common metadata', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {
     const collection = await createCollectionExpectSuccess({
       name: 'token name',
@@ -462,4 +478,4 @@
 
     expect(symbol).to.equal('TOK');
   });
-});
\ No newline at end of file
+});
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';
+import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';
 import reFungibleTokenAbi from './reFungibleTokenAbi.json';
 
@@ -24,6 +24,10 @@
 const expect = chai.expect;
 
 describe('Refungible token: Information getting', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -75,6 +79,10 @@
 
 // FIXME: Need erc721 for ReFubgible.
 describe('Check ERC721 token URI for ReFungible', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const helper = evmCollectionHelpers(web3, owner);
@@ -216,6 +224,10 @@
 });
 
 describe('Refungible: Plain calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -477,6 +489,10 @@
 });
 
 describe('Refungible: Fees', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
@@ -532,6 +548,10 @@
 });
 
 describe('Refungible: Substrate calls', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+  });
+
   itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
     const alice = privateKeyWrapper('//Alice');
 
modifiedtests/src/eth/scheduling.test.tsdiffbeforeafterboth
--- a/tests/src/eth/scheduling.test.ts
+++ b/tests/src/eth/scheduling.test.ts
@@ -16,9 +16,13 @@
 
 import {expect} from 'chai';
 import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
-import {scheduleExpectSuccess, waitNewBlocks} from '../util/helpers';
+import {scheduleExpectSuccess, waitNewBlocks, requirePallets, Pallets} from '../util/helpers';
 
 describe('Scheduing EVM smart contracts', () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.Scheduler]);
+  });
+
   itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3, privateKeyWrapper}) => {
     const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const flipper = await deployFlipper(web3, deployer);
@@ -51,4 +55,4 @@
       expect(await flipper.methods.getValue().call()).to.be.equal(initialValue);
     }
   });
-});
\ No newline at end of file
+});
modifiedtests/src/limits.test.tsdiffbeforeafterboth
--- a/tests/src/limits.test.ts
+++ b/tests/src/limits.test.ts
@@ -27,6 +27,8 @@
   transferExpectSuccess,
   getFreeBalance,
   waitNewBlocks, burnItemExpectSuccess,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 import {expect} from 'chai';
 
@@ -67,7 +69,9 @@
 describe('Number of tokens per address (ReFungible)', () => {
   let alice: IKeyringPair;
 
-  before(async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
     });
@@ -367,7 +371,9 @@
   let bob: IKeyringPair;
   let charlie: IKeyringPair;
 
-  before(async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
       bob = privateKeyWrapper('//Bob');
modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -17,6 +17,8 @@
   transferExpectSuccess,
   transferFromExpectSuccess,
   setCollectionLimitsExpectSuccess,
+  requirePallets,
+  Pallets,
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -311,7 +313,9 @@
 
   // ---------- Re-Fungible ----------
 
-  it('ReFungible: allows an Owner to nest/unnest their token', async () => {
+  it('ReFungible: allows an Owner to nest/unnest their token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -333,7 +337,9 @@
     });
   });
 
-  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async () => {
+  it('ReFungible: allows an Owner to nest/unnest their token (Restricted nesting)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       const targetToken = await createItemExpectSuccess(alice, collectionNFT, 'NFT', {Substrate: alice.address});
@@ -715,7 +721,9 @@
 
   // ---------- Re-Fungible ----------
 
-  it('ReFungible: disallows to nest token if nesting is disabled', async () => {
+  it('ReFungible: disallows to nest token if nesting is disabled', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {}});
@@ -745,7 +753,9 @@
     });
   });
 
-  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async () => {
+  it('ReFungible: disallows a non-Owner to nest someone else\'s token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true}});
@@ -773,7 +783,9 @@
     });
   });
 
-  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async () => {
+  it('ReFungible: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await addToAllowListExpectSuccess(alice, collectionNFT, bob.address);
@@ -800,7 +812,9 @@
     });
   });
 
-  it('ReFungible: disallows to nest token to an unlisted collection', async () => {
+  it('ReFungible: disallows to nest token to an unlisted collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collectionNFT = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collectionNFT, {nesting: {tokenOwner: true, restricted:[]}});
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -8,6 +8,8 @@
   createItemExpectSuccess,
   getCreateCollectionResult,
   transferExpectSuccess,
+  requirePallets,
+  Pallets,
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 import {tokenIdToAddress} from '../eth/util/helpers';
@@ -64,7 +66,9 @@
     await testMakeSureSuppliesRequired({type: 'NFT'});
   });
 
-  it('Makes sure collectionById supplies required fields for ReFungible', async () => {
+  it('Makes sure collectionById supplies required fields for ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testMakeSureSuppliesRequired({type: 'ReFungible'});
   });
 });
@@ -120,7 +124,9 @@
   it('Sets properties for a NFT collection', async () => {
     await testSetsPropertiesForCollection('NFT');
   });
-  it('Sets properties for a ReFungible collection', async () => {
+  it('Sets properties for a ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testSetsPropertiesForCollection('ReFungible');
   });
 
@@ -178,7 +184,9 @@
   it('Check valid names for NFT collection properties keys', async () => {
     await testCheckValidNames('NFT');
   });
-  it('Check valid names for ReFungible collection properties keys', async () => {
+  it('Check valid names for ReFungible collection properties keys', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testCheckValidNames('ReFungible');
   });
 
@@ -209,7 +217,9 @@
   it('Changes properties of a NFT collection', async () => {
     await testChangesProperties({type: 'NFT'});
   });
-  it('Changes properties of a ReFungible collection', async () => {
+  it('Changes properties of a ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testChangesProperties({type: 'ReFungible'});
   });
 
@@ -238,7 +248,9 @@
   it('Deletes properties of a NFT collection', async () => {
     await testDeleteProperties({type: 'NFT'});
   });
-  it('Deletes properties of a ReFungible collection', async () => {
+  it('Deletes properties of a ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testDeleteProperties({type: 'ReFungible'});
   });
 });
@@ -269,7 +281,9 @@
   it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {
     await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});
   });
-  it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {
+  it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});
   });
   
@@ -307,7 +321,9 @@
   it('Fails to set properties that exceed the limits (NFT)', async () => {
     await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});
   });
-  it('Fails to set properties that exceed the limits (ReFungible)', async () => {
+  it('Fails to set properties that exceed the limits (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});
   });
   
@@ -337,7 +353,9 @@
   it('Fails to set more properties than it is allowed (NFT)', async () => {
     await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});
   });
-  it('Fails to set more properties than it is allowed (ReFungible)', async () => {
+  it('Fails to set more properties than it is allowed (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});
   });
   
@@ -392,7 +410,9 @@
   it('Fails to set properties with invalid names (NFT)', async () => {
     await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});
   });
-  it('Fails to set properties with invalid names (ReFungible)', async () => {
+  it('Fails to set properties with invalid names (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});
   });
 });
@@ -443,7 +463,9 @@
   it('Sets access rights to properties of a collection (NFT)', async () => {
     await testSetsAccessRightsToProperties({type: 'NFT'});
   });
-  it('Sets access rights to properties of a collection (ReFungible)', async () => {
+  it('Sets access rights to properties of a collection (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testSetsAccessRightsToProperties({type: 'ReFungible'});
   });
   
@@ -472,7 +494,9 @@
   it('Changes access rights to properties of a NFT collection', async () => {
     await testChangesAccessRightsToProperty({type: 'NFT'});
   });
-  it('Changes access rights to properties of a ReFungible collection', async () => {
+  it('Changes access rights to properties of a ReFungible collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testChangesAccessRightsToProperty({type: 'ReFungible'});
   });
 });
@@ -502,7 +526,9 @@
   it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {
     await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});
   });
-  it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {
+  it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});
   });
 
@@ -531,7 +557,9 @@
   it('Prevents from adding too many possible properties (NFT)', async () => {
     await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});
   });
-  it('Prevents from adding too many possible properties (ReFungible)', async () => {
+  it('Prevents from adding too many possible properties (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});
   });
 
@@ -560,7 +588,9 @@
   it('Prevents access rights to be modified if constant (NFT)', async () => {
     await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});
   });
-  it('Prevents access rights to be modified if constant (ReFungible)', async () => {
+  it('Prevents access rights to be modified if constant (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});
   });
 
@@ -608,7 +638,9 @@
   it('Prevents adding properties with invalid names (NFT)', async () => {
     await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});
   });
-  it('Prevents adding properties with invalid names (ReFungible)', async () => {
+  it('Prevents adding properties with invalid names (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});
   });
 });
@@ -651,7 +683,9 @@
   it('Reads yet empty properties of a token (NFT)', async () => {
     await testReadsYetEmptyProperties({type: 'NFT'});
   });
-  it('Reads yet empty properties of a token (ReFungible)', async () => {
+  it('Reads yet empty properties of a token (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testReadsYetEmptyProperties({type: 'ReFungible'});
   });
 
@@ -696,7 +730,9 @@
   it('Assigns properties to a token according to permissions (NFT)', async () => {
     await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);
   });
-  it('Assigns properties to a token according to permissions (ReFungible)', async () => {
+  it('Assigns properties to a token according to permissions (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);
   });
 
@@ -749,7 +785,9 @@
   it('Changes properties of a token according to permissions (NFT)', async () => {
     await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);
   });
-  it('Changes properties of a token according to permissions (ReFungible)', async () => {
+  it('Changes properties of a token according to permissions (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);
   });
 
@@ -802,7 +840,9 @@
   it('Deletes properties of a token according to permissions (NFT)', async () => {
     await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);
   });
-  it('Deletes properties of a token according to permissions (ReFungible)', async () => {
+  it('Deletes properties of a token according to permissions (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);
   });
 
@@ -1029,7 +1069,9 @@
   it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {
     await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);
   });
-  it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {
+  it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);
   });
 
@@ -1062,7 +1104,9 @@
   it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {
     await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);
   });
-  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {
+  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);
   });
 
@@ -1096,7 +1140,9 @@
   it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {
     await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);
   });
-  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {
+  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);
   });
 
@@ -1140,7 +1186,9 @@
   it('Forbids adding too many properties to a token (NFT)', async () => {
     await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);
   });
-  it('Forbids adding too many properties to a token (ReFungible)', async () => {
+  it('Forbids adding too many properties to a token (ReFungible)', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);
   });
 });
@@ -1149,7 +1197,9 @@
   let collection: number;
   let token: number;
 
-  before(async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
       bob = privateKeyWrapper('//Bob');
modifiedtests/src/nesting/rules-smoke.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/rules-smoke.test.ts
+++ b/tests/src/nesting/rules-smoke.test.ts
@@ -1,7 +1,7 @@
 import {expect} from 'chai';
 import {tokenIdToAddress} from '../eth/util/helpers';
 import usingApi, {executeTransaction} from '../substrate/substrate-api';
-import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult} from '../util/helpers';
+import {createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, CrossAccountId, getCreateCollectionResult, requirePallets, Pallets} from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
 describe('nesting check', () => {
@@ -47,7 +47,9 @@
     });
   });
 
-  it('called for refungible', async () => {
+  it('called for refungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {ReFungible: {}})))
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -10,6 +10,8 @@
   setCollectionPermissionsExpectSuccess,
   transferExpectSuccess,
   transferFromExpectSuccess,
+  requirePallets,
+  Pallets,
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -80,7 +82,9 @@
     });
   });
 
-  it('ReFungible: allows the owner to successfully unnest a token', async () => {
+  it('ReFungible: allows the owner to successfully unnest a token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
       await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
modifiedtests/src/nextSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/nextSponsoring.test.ts
+++ b/tests/src/nextSponsoring.test.ts
@@ -27,6 +27,8 @@
   transferExpectSuccess,
   normalizeAccountId,
   getNextSponsored,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -89,7 +91,9 @@
     });
   });
 
-  it('ReFungible', async () => {
+  it('ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
 
       const createMode = 'ReFungible';
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -49,8 +49,6 @@
   'inflation',
   'unique',
   'nonfungible',
-  'refungible',
-  'scheduler',
   'charging',
 ];
 
@@ -66,8 +64,16 @@
     await usingApi(async api => {
       const chain = await api.rpc.system.chain();
 
-      if (!chain.eq('UNIQUE')) {
-        requiredPallets.push(...['rmrkcore', 'rmrkequip']);
+      const refungible = 'refungible';
+      const scheduler = 'scheduler';
+      const rmrkPallets = ['rmrkcore', 'rmrkequip'];
+
+      if (chain.eq('OPAL by UNIQUE')) {
+        requiredPallets.push(refungible, scheduler, ...rmrkPallets);
+      } else if (chain.eq('QUARTZ by UNIQUE')) {
+        // Insert Quartz additional pallets here
+      } else if (chain.eq('UNIQUE')) {
+        // Insert Unique additional pallets here
       }
     });
   });
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -36,6 +36,9 @@
   CrossAccountId,
   getCreateItemsResult,
   getDestroyItemsResult,
+  getModuleNames,
+  Pallets,
+  requirePallets,
 } from './util/helpers';
 
 import chai from 'chai';
@@ -46,14 +49,20 @@
 let alice: IKeyringPair;
 let bob: IKeyringPair;
 
-describe('integration test: Refungible functionality:', () => {
-  before(async () => {
+
+
+describe('integration test: Refungible functionality:', async () => {
+  before(async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
       bob = privateKeyWrapper('//Bob');
+      if (!getModuleNames(api).includes(Pallets.ReFungible)) this.skip();
     });
+    
   });
-
+  
   it('Create refungible collection and token', async () => {
     await usingApi(async api => {
       const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
@@ -266,15 +275,6 @@
           amount: 50,
         },
       ]);
-    });
-  });
-});
-
-describe('Test Refungible properties:', () => {
-  before(async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      alice = privateKeyWrapper('//Alice');
-      bob = privateKeyWrapper('//Bob');
     });
   });
   
@@ -292,3 +292,4 @@
     });
   });
 });
+
modifiedtests/src/rmrk/acceptNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/acceptNft.test.ts
+++ b/tests/src/rmrk/acceptNft.test.ts
@@ -8,14 +8,19 @@
 } from './util/tx';
 import {NftIdTuple} from './util/fetch';
 import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
 
 describe('integration test: accept NFT', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
-
+  before(async function() {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
+  
+  
   const alice = '//Alice';
   const bob = '//Bob';
-
+  
   const createTestCollection = async (issuerUri: string) => {
     return await createCollection(
       api,
modifiedtests/src/rmrk/addResource.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/addResource.test.ts
+++ b/tests/src/rmrk/addResource.test.ts
@@ -12,6 +12,7 @@
   addNftComposableResource,
 } from './util/tx';
 import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup';
+import {requirePallets, Pallets} from '../util/helpers';
 
 describe('integration test: add NFT resource', () => {
   const Alice = '//Alice';
@@ -24,8 +25,9 @@
   const nonexistentId = 99999;
 
   let api: any;
-  before(async () => {
+  before(async function() {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('add resource', async () => {
modifiedtests/src/rmrk/addTheme.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/addTheme.test.ts
+++ b/tests/src/rmrk/addTheme.test.ts
@@ -3,10 +3,14 @@
 import {createBase, addTheme} from './util/tx';
 import {expectTxFailure} from './util/helpers';
 import {getThemeNames} from './util/fetch';
+import {requirePallets, Pallets} from '../util/helpers';
 
 describe('integration test: add Theme to Base', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function() {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkEquip]);
+  });
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/rmrk/burnNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/burnNft.test.ts
+++ b/tests/src/rmrk/burnNft.test.ts
@@ -5,6 +5,7 @@
 
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
+import {requirePallets, Pallets} from '../util/helpers';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -14,10 +15,12 @@
   const Bob = '//Bob';
 
   let api: any;
-  before(async () => {
+  before(async function() {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
+
   it('burn nft', async () => {
     await createCollection(
       api,
modifiedtests/src/rmrk/changeCollectionIssuer.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/changeCollectionIssuer.test.ts
+++ b/tests/src/rmrk/changeCollectionIssuer.test.ts
@@ -1,4 +1,5 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {
   changeIssuer,
@@ -10,10 +11,13 @@
   const Bob = '//Bob';
 
   let api: any;
-  before(async () => {
+  before(async function() {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
+
+
   it('change collection issuer', async () => {
     await createCollection(
       api,
modifiedtests/src/rmrk/createBase.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/createBase.test.ts
+++ b/tests/src/rmrk/createBase.test.ts
@@ -1,9 +1,13 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {createCollection, createBase} from './util/tx';
 
 describe('integration test: create new Base', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function() {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
+  });
 
   const alice = '//Alice';
 
modifiedtests/src/rmrk/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/createCollection.test.ts
+++ b/tests/src/rmrk/createCollection.test.ts
@@ -1,9 +1,15 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {createCollection} from './util/tx';
 
 describe('Integration test: create new collection', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
+
+
 
   const alice = '//Alice';
 
modifiedtests/src/rmrk/deleteCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/deleteCollection.test.ts
+++ b/tests/src/rmrk/deleteCollection.test.ts
@@ -1,11 +1,13 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, deleteCollection} from './util/tx';
 
 describe('integration test: delete collection', () => {
   let api: any;
-  before(async () => {
+  before(async function () {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const Alice = '//Alice';
modifiedtests/src/rmrk/equipNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/equipNft.test.ts
+++ b/tests/src/rmrk/equipNft.test.ts
@@ -1,6 +1,7 @@
 import {ApiPromise} from '@polkadot/api';
 import {expect} from 'chai';
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {getNft, getParts, NftIdTuple} from './util/fetch';
 import {expectTxFailure} from './util/helpers';
 import {
@@ -122,8 +123,10 @@
 describe.skip('integration test: Equip NFT', () => {
 
   let api: any;
-  before(async () => {
+  
+  before(async function () {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
   });
 
   it('equip nft', async () => {
modifiedtests/src/rmrk/getOwnedNfts.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/getOwnedNfts.test.ts
+++ b/tests/src/rmrk/getOwnedNfts.test.ts
@@ -1,11 +1,17 @@
 import {expect} from 'chai';
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {getOwnedNfts} from './util/fetch';
 import {mintNft, createCollection} from './util/tx';
 
 describe('integration test: get owned NFTs', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
+
 
   const alice = '//Alice';
 
modifiedtests/src/rmrk/lockCollection.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/lockCollection.test.ts
+++ b/tests/src/rmrk/lockCollection.test.ts
@@ -1,4 +1,5 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, lockCollection, mintNft} from './util/tx';
 
@@ -8,8 +9,9 @@
   const Max = 5;
 
   let api: any;
-  before(async () => {
+  before(async function () {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('lock collection', async () => {
modifiedtests/src/rmrk/mintNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/mintNft.test.ts
+++ b/tests/src/rmrk/mintNft.test.ts
@@ -1,12 +1,18 @@
 import {expect} from 'chai';
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {getNft} from './util/fetch';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, mintNft} from './util/tx';
 
 describe('integration test: mint new NFT', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+ 
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
+
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/rmrk/rejectNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/rejectNft.test.ts
+++ b/tests/src/rmrk/rejectNft.test.ts
@@ -8,10 +8,16 @@
 } from './util/tx';
 import {getChildren, NftIdTuple} from './util/fetch';
 import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
 
 describe('integration test: reject NFT', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
+
+
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/rmrk/removeResource.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/removeResource.test.ts
+++ b/tests/src/rmrk/removeResource.test.ts
@@ -1,6 +1,7 @@
 import {expect} from 'chai';
 import privateKey from '../substrate/privateKey';
 import {executeTransaction, getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {getNft, NftIdTuple} from './util/fetch';
 import {expectTxFailure} from './util/helpers';
 import {
@@ -16,9 +17,10 @@
 describe('Integration test: remove nft resource', () => {
   let api: any;
   let ss58Format: string;
-  before(async () => {
+  before(async function() {
     api = await getApiConnection();
     ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   const Alice = '//Alice';
modifiedtests/src/rmrk/rmrkIsolation.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/rmrkIsolation.test.ts
+++ b/tests/src/rmrk/rmrkIsolation.test.ts
@@ -6,7 +6,9 @@
   getCreateCollectionResult,
   getDetailedCollectionInfo,
   getGenericResult,
+  requirePallets,
   normalizeAccountId,
+  Pallets,
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 import {ApiPromise} from '@polkadot/api';
@@ -59,11 +61,10 @@
 describe('RMRK External Integration Test', async () => {
   const it_rmrk = (await isUnique() ? it : it.skip);
 
-  before(async () => {
+  before(async function() {
     await usingApi(async (api, privateKeyWrapper) => {
       alice = privateKeyWrapper('//Alice');
-
-      
+      await requirePallets(this, [Pallets.RmrkCore]);
     });
   });
 
modifiedtests/src/rmrk/sendNft.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/sendNft.test.ts
+++ b/tests/src/rmrk/sendNft.test.ts
@@ -3,10 +3,14 @@
 import {createCollection, mintNft, sendNft} from './util/tx';
 import {NftIdTuple} from './util/fetch';
 import {isNftChildOfAnother, expectTxFailure} from './util/helpers';
+import {requirePallets, Pallets} from '../util/helpers';
 
 describe('integration test: send NFT', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
 
   const maxNftId = 0xFFFFFFFF;
 
modifiedtests/src/rmrk/setCollectionProperty.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setCollectionProperty.test.ts
+++ b/tests/src/rmrk/setCollectionProperty.test.ts
@@ -1,4 +1,5 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, setPropertyCollection} from './util/tx';
 
@@ -7,8 +8,9 @@
   const Bob = '//Bob';
 
   let api: any;
-  before(async () => {
+  before(async function () {
     api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
   });
 
   it('set collection property', async () => {
modifiedtests/src/rmrk/setEquippableList.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setEquippableList.test.ts
+++ b/tests/src/rmrk/setEquippableList.test.ts
@@ -1,10 +1,14 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, createBase, setEquippableList} from './util/tx';
 
 describe("integration test: set slot's Equippable List", () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/rmrk/setNftProperty.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setNftProperty.test.ts
+++ b/tests/src/rmrk/setNftProperty.test.ts
@@ -1,11 +1,15 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {NftIdTuple} from './util/fetch';
 import {expectTxFailure} from './util/helpers';
 import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx';
 
 describe('integration test: set NFT property', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/rmrk/setResourcePriorities.test.tsdiffbeforeafterboth
--- a/tests/src/rmrk/setResourcePriorities.test.ts
+++ b/tests/src/rmrk/setResourcePriorities.test.ts
@@ -1,10 +1,14 @@
 import {getApiConnection} from '../substrate/substrate-api';
+import {requirePallets, Pallets} from '../util/helpers';
 import {expectTxFailure} from './util/helpers';
 import {mintNft, createCollection, setResourcePriorities} from './util/tx';
 
 describe('integration test: set NFT resource priorities', () => {
   let api: any;
-  before(async () => { api = await getApiConnection(); });
+  before(async function () {
+    api = await getApiConnection();
+    await requirePallets(this, [Pallets.RmrkCore]);
+  });
 
   const alice = '//Alice';
   const bob = '//Bob';
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionSponsor.test.ts
+++ b/tests/src/setCollectionSponsor.test.ts
@@ -23,6 +23,8 @@
   setCollectionSponsorExpectFailure,
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';
 
@@ -50,7 +52,9 @@
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
-  it('Set ReFungible collection sponsor', async () => {
+  it('Set ReFungible collection sponsor', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -35,11 +35,14 @@
   getBalance as getTokenBalance,
   transferFromExpectSuccess,
   transferFromExpectFail,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 import {
   subToEth,
   itWeb3, 
 } from './eth/util/helpers';
+import {request} from 'https';
 
 let alice: IKeyringPair;
 let bob: IKeyringPair;
@@ -89,56 +92,61 @@
     });
   });
 
-  it('User can transfer owned token', async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await transferExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        alice,
-        bob,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[nft] User can transfer owned token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 'NFT');
+  });
+
+  it('[fungible] User can transfer owned token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob, 1, 'Fungible');
+  });
+
+  it('[refungible] User can transfer owned token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await transferExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      alice,
+      bob,
+      100,
+      'ReFungible',
+    );
+  });
+
+  it('[nft] Collection admin can transfer owned token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
+    const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
+    await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
+  });
+
+  it('[fungible] Collection admin can transfer owned token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
+    await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
   });
 
-  it('Collection admin can transfer owned token', async () => {
-    await usingApi(async (api, privateKeyWrapper) => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-      const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT', bob.address);
-      await transferExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, 1, 'NFT');
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      await addCollectionAdminExpectSuccess(alice, fungibleCollectionId, bob.address);
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible', bob.address);
-      await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, 1, 'Fungible');
-      // reFungible
-      const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
-      const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
-      await transferExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[refungible] Collection admin can transfer owned token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    await addCollectionAdminExpectSuccess(alice, reFungibleCollectionId, bob.address);
+    const newReFungibleTokenId = await createItemExpectSuccess(bob, reFungibleCollectionId, 'ReFungible', bob.address);
+    await transferExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      100,
+      'ReFungible',
+    );
   });
 });
 
@@ -150,33 +158,49 @@
       charlie = privateKeyWrapper('//Charlie');
     });
   });
-  it('Transfer with not existed collection_id', async () => {
+
+  it('[nft] Transfer with not existed collection_id', async () => {
     await usingApi(async (api) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(nftCollectionCount + 1, 1, alice, bob, 1);
-      // fungible
+    });
+  });
+
+  it('[fungible] Transfer with not existed collection_id', async () => {
+    await usingApi(async (api) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(fungibleCollectionCount + 1, 0, alice, bob, 1);
-      // reFungible
+    });
+  });
+
+  it('[refungible] Transfer with not existed collection_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await transferExpectFailure(reFungibleCollectionCount + 1, 1, alice, bob, 1);
     });
   });
-  it('Transfer with deleted collection_id', async () => {
-    // nft
+
+  it('[nft] Transfer with deleted collection_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId);
     await destroyCollectionExpectSuccess(nftCollectionId);
     await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with deleted collection_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
     await destroyCollectionExpectSuccess(fungibleCollectionId);
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
-    // reFungible
+  });
+
+  it('[refungible] Transfer with deleted collection_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -190,16 +214,21 @@
       1,
     );
   });
-  it('Transfer with not existed item_id', async () => {
-    // nft
+
+  it('[nft] Transfer with not existed item_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     await transferExpectFailure(nftCollectionId, 2, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with not existed item_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     await transferExpectFailure(fungibleCollectionId, 2, alice, bob, 1);
-    // reFungible
-    const reFungibleCollectionId = await
-    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+  });
+
+  it('[refungible] Transfer with not existed item_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await transferExpectFailure(
       reFungibleCollectionId,
       2,
@@ -208,18 +237,24 @@
       1,
     );
   });
-  it('Transfer with deleted item_id', async () => {
-    // nft
+
+  it('[nft] Transfer with deleted item_id', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId, 1);
     await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with deleted item_id', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, alice, bob, 1);
-    // reFungible
+  });
+
+  it('[refungible] Transfer with deleted item_id', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -232,18 +267,23 @@
       1,
     );
   });
-  it('Transfer with recipient that is not owner', async () => {
-    // nft
+
+  it('[nft] Transfer with recipient that is not owner', async () => {
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
     await transferExpectFailure(nftCollectionId, newNftTokenId, charlie, bob, 1);
-    // fungible
+  });
+
+  it('[fungible] Transfer with recipient that is not owner', async () => {
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, charlie, bob, 1);
-    // reFungible
-    const reFungibleCollectionId = await
-    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+  });
+
+  it('[refungible] Transfer with recipient that is not owner', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
     await transferExpectFailure(
       reFungibleCollectionId,
@@ -276,7 +316,9 @@
     });
   });
 
-  it('RFT', async () => {
+  it('RFT', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -31,6 +31,8 @@
   burnItemExpectSuccess,
   setCollectionLimitsExpectSuccess,
   getCreatedCollectionCount,
+  requirePallets,
+  Pallets,
 } from './util/helpers';
 
 chai.use(chaiAsPromised);
@@ -49,36 +51,36 @@
     });
   });
 
-  it('Execute the extrinsic and check nftItemList - owner of token', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+  it('[nft] Execute the extrinsic and check nftItemList - owner of token', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
 
-      await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+    await transferFromExpectSuccess(nftCollectionId, newNftTokenId, bob, alice, charlie, 1, 'NFT');
+  });
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-      await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+  it('[fungible] Execute the extrinsic and check nftItemList - owner of token', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+    await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1, 'Fungible');
+  });
 
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
-      await transferFromExpectSuccess(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        100,
-        'ReFungible',
-      );
-    });
+  it('[refungible] Execute the extrinsic and check nftItemList - owner of token', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 100);
+    await transferFromExpectSuccess(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      100,
+      'ReFungible',
+    );
   });
 
   it('Should reduce allowance if value is big', async () => {
@@ -119,20 +121,28 @@
     });
   });
 
-  it('transferFrom for a collection that does not exist', async () => {
+  it('[nft] transferFrom for a collection that does not exist', async () => {
     await usingApi(async (api: ApiPromise) => {
-      // nft
       const nftCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(nftCollectionCount + 1, 1, alice, bob);
 
       await transferFromExpectFail(nftCollectionCount + 1, 1, bob, alice, charlie, 1);
+    });
+  });
 
-      // fungible
+  it('[fungible] transferFrom for a collection that does not exist', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const fungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob);
 
       await transferFromExpectFail(fungibleCollectionCount + 1, 0, bob, alice, charlie, 1);
-      // reFungible
+    });
+  });
+
+  it('[refungible] transferFrom for a collection that does not exist', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api: ApiPromise) => {
       const reFungibleCollectionCount = await getCreatedCollectionCount(api);
       await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob);
 
@@ -158,67 +168,70 @@
     });
   }); */
 
-  it('transferFrom for not approved address', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+  it('[nft] transferFrom for not approved address', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
 
-      await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+    await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 1);
+  });
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await transferFromExpectFail(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        1,
-      );
-    });
+  it('[fungible] transferFrom for not approved address', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 1);
+  });
+
+  it('[refungible] transferFrom for not approved address', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    const reFungibleCollectionId = await
+    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await transferFromExpectFail(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      1,
+    );
+  });
+
+  it('[nft] transferFrom incorrect token count', async () => {
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
+    await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+
+    await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
   });
 
-  it('transferFrom incorrect token count', async () => {
-    await usingApi(async () => {
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address);
+  it('[fungible] transferFrom incorrect token count', async () => {
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
+    await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
+    await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
+  });
 
-      await transferFromExpectFail(nftCollectionId, newNftTokenId, bob, alice, charlie, 2);
+  it('[refungible] transferFrom incorrect token count', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
 
-      // fungible
-      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-      const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-      await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
-      await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice, charlie, 2);
-      // reFungible
-      const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
-      await transferFromExpectFail(
-        reFungibleCollectionId,
-        newReFungibleTokenId,
-        bob,
-        alice,
-        charlie,
-        2,
-      );
-    });
+    const reFungibleCollectionId = await
+    createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+    const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
+    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address);
+    await transferFromExpectFail(
+      reFungibleCollectionId,
+      newReFungibleTokenId,
+      bob,
+      alice,
+      charlie,
+      2,
+    );
   });
 
-  it('execute transferFrom from account that is not owner of collection', async () => {
+  it('[nft] execute transferFrom from account that is not owner of collection', async () => {
     await usingApi(async (api, privateKeyWrapper) => {
       const dave = privateKeyWrapper('//Dave');
-      // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
       try {
@@ -230,8 +243,13 @@
       }
 
       // await transferFromExpectFail(nftCollectionId, newNftTokenId, Dave, Alice, Charlie, 1);
+    });
+  });
 
-      // fungible
+  it('[fungible] execute transferFrom from account that is not owner of collection', async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      const dave = privateKeyWrapper('//Dave');
+
       const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
       const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
       try {
@@ -241,7 +259,14 @@
         // tslint:disable-next-line:no-unused-expression
         expect(e).to.be.exist;
       }
-      // reFungible
+    });
+  });
+
+  it('[refungible] execute transferFrom from account that is not owner of collection', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
+    await usingApi(async (api, privateKeyWrapper) => {
+      const dave = privateKeyWrapper('//Dave');
       const reFungibleCollectionId = await
       createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
@@ -276,7 +301,9 @@
 
     });
   });
-  it('transferFrom burnt token before approve ReFungible', async () => {
+  it('transferFrom burnt token before approve ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async () => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await setCollectionLimitsExpectSuccess(alice, reFungibleCollectionId, {ownerCanTransfer: true});
@@ -308,7 +335,9 @@
 
     });
   });
-  it('transferFrom burnt token after approve ReFungible', async () => {
+  it('transferFrom burnt token after approve ReFungible', async function() {
+    await requirePallets(this, [Pallets.ReFungible]);
+
     await usingApi(async () => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -28,6 +28,7 @@
 import {hexToStr, strToUTF16, utf16ToStr} from './util';
 import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';
 import {UpDataStructsTokenChild} from '../interfaces';
+import {Context} from 'mocha';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -38,6 +39,66 @@
   Ethereum: string,
 };
 
+
+export enum Pallets {
+  Inflation = 'inflation',
+  RmrkCore = 'rmrkcore',
+  RmrkEquip = 'rmrkequip',
+  ReFungible = 'refungible',
+  Fungible = 'fungible',
+  NFT = 'nonfungible',
+  Scheduler = 'scheduler',
+}
+
+export async function isUnique(): Promise<boolean> {
+  return usingApi(async api => {
+    const chain = await api.rpc.system.chain();
+
+    return chain.eq('UNIQUE');
+  });
+}
+
+export async function isQuartz(): Promise<boolean> {
+  return usingApi(async api => {
+    const chain = await api.rpc.system.chain();
+    
+    return chain.eq('QUARTZ');
+  });
+}
+
+let modulesNames: any;
+export function getModuleNames(api: ApiPromise): string[] {
+  if (typeof modulesNames === 'undefined') 
+    modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
+  return modulesNames;
+}
+
+export async function missingRequiredPallets(requiredPallets: string[]): Promise<string[]> {
+  return await usingApi(async api => {
+    const pallets = getModuleNames(api);
+
+    return requiredPallets.filter(p => !pallets.includes(p));
+  });
+}
+
+export async function checkPalletsPresence(requiredPallets: string[]): Promise<boolean> {
+  return (await missingRequiredPallets(requiredPallets)).length == 0;
+}
+
+export async function requirePallets(mocha: Context, requiredPallets: string[]) {
+  const missingPallets = await missingRequiredPallets(requiredPallets);
+
+  if (missingPallets.length > 0) {
+    const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;
+    const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
+    const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;
+
+    console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);
+
+    mocha.skip();
+  }
+}
+
 export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {
   if (typeof input === 'string') {
     if (input.length >= 47) {