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

difftreelog

test fix unit

Yaroslav Bolyukin2022-04-13parent: #f082ca5.patch.diff
in: master

19 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6829,37 +6829,18 @@
 name = "pallet-unique"
 version = "0.1.0"
 dependencies = [
- "ethereum",
- "evm-coder",
- "fp-evm",
- "fp-evm-mapping",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
- "hex-literal",
- "pallet-balances",
  "pallet-common",
- "pallet-ethereum",
  "pallet-evm",
- "pallet-evm-coder-substrate",
- "pallet-fungible",
- "pallet-nonfungible",
- "pallet-randomness-collective-flip",
- "pallet-refungible",
- "pallet-timestamp",
- "pallet-transaction-payment",
  "parity-scale-codec",
- "primitive-types",
- "rlp",
  "scale-info",
- "serde",
- "sp-api",
  "sp-core",
  "sp-io",
  "sp-runtime",
  "sp-std",
  "up-data-structs",
- "up-sponsorship",
 ]
 
 [[package]]
@@ -11918,6 +11899,35 @@
 ]
 
 [[package]]
+name = "tests"
+version = "0.1.0"
+dependencies = [
+ "fp-evm-mapping",
+ "frame-support",
+ "frame-system",
+ "pallet-balances",
+ "pallet-common",
+ "pallet-ethereum",
+ "pallet-evm",
+ "pallet-evm-coder-substrate",
+ "pallet-fungible",
+ "pallet-nonfungible",
+ "pallet-refungible",
+ "pallet-structure",
+ "pallet-timestamp",
+ "pallet-transaction-payment",
+ "pallet-unique",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+ "unique-runtime-common",
+ "up-data-structs",
+]
+
+[[package]]
 name = "textwrap"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -12677,6 +12687,7 @@
 name = "unique-runtime-common"
 version = "0.9.18"
 dependencies = [
+ "evm-coder",
  "fp-rpc",
  "frame-support",
  "frame-system",
@@ -12693,6 +12704,7 @@
  "sp-runtime",
  "sp-std",
  "up-data-structs",
+ "up-sponsorship",
 ]
 
 [[package]]
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,16 @@
 [workspace]
 resolver = "2"
-members = ['node/*', 'pallets/*', 'client/*', 'primitives/*', 'crates/*']
-exclude = ["runtime/unique", "runtime/quartz"]
+members = [
+    'node/*',
+    'pallets/*',
+    'client/*',
+    'primitives/*',
+    'crates/*',
+    'runtime/tests',
+]
+exclude = [
+    "runtime/unique",
+    "runtime/quartz"
+]
 [profile.release]
 panic = 'unwind'
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
19runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']19runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']
20std = [20std = [
21 'codec/std',21 'codec/std',
22 'serde/std',
23 'frame-support/std',22 'frame-support/std',
24 'frame-system/std',23 'frame-system/std',
25 'pallet-balances/std',
26 'pallet-evm/std',24 'pallet-evm/std',
27 'pallet-timestamp/std',
28 'pallet-randomness-collective-flip/std',
29 'pallet-transaction-payment/std',
30 'pallet-common/std',25 'pallet-common/std',
31 'pallet-fungible/std',
32 'pallet-nonfungible/std',
33 'pallet-refungible/std',
34 'fp-evm/std',
35 'up-data-structs/std',26 'up-data-structs/std',
36 'up-sponsorship/std',
37 'fp-evm-mapping/std',
38 'sp-std/std',27 'sp-std/std',
39 'sp-api/std',
40 'sp-runtime/std',28 'sp-runtime/std',
41 'frame-benchmarking/std',29 'frame-benchmarking/std',
42 'ethereum/std',
43 'rlp/std',
44
45 'primitive-types/std',
46 'evm-coder/std',
47 'pallet-evm-coder-substrate/std',
48]30]
49limit-testing = ["up-data-structs/limit-testing"]31limit-testing = ["up-data-structs/limit-testing"]
5032
73git = "https://github.com/paritytech/substrate"55git = "https://github.com/paritytech/substrate"
74branch = "polkadot-v0.9.20"56branch = "polkadot-v0.9.20"
75
76[dependencies.pallet-balances]
77default-features = false
78git = "https://github.com/paritytech/substrate"
79branch = "polkadot-v0.9.20"
80
81[dependencies.pallet-timestamp]
82default-features = false
83git = "https://github.com/paritytech/substrate"
84branch = "polkadot-v0.9.20"
85
86[dependencies.pallet-randomness-collective-flip]
87default-features = false
88git = "https://github.com/paritytech/substrate"
89branch = "polkadot-v0.9.20"
9057
91[dependencies.sp-std]58[dependencies.sp-std]
92default-features = false59default-features = false
93git = "https://github.com/paritytech/substrate"60git = "https://github.com/paritytech/substrate"
94branch = "polkadot-v0.9.20"61branch = "polkadot-v0.9.20"
95
96[dependencies.pallet-transaction-payment]
97default-features = false
98git = "https://github.com/paritytech/substrate"
99branch = "polkadot-v0.9.20"
100
101[dependencies.serde]
102default-features = false
103features = ['derive']
104version = '1.0.130'
10562
106[dependencies.sp-runtime]63[dependencies.sp-runtime]
107default-features = false64default-features = false
127scale-info = { version = "2.0.1", default-features = false, features = [83scale-info = { version = "2.0.1", default-features = false, features = [
128 "derive",84 "derive",
129] }85] }
130ethereum = { version = "0.12.0", default-features = false }
131rlp = { default-features = false, version = "0.5.0" }
132sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.20" }
133
134up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.20" }
135fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.20" }
136evm-coder = { default-features = false, path = "../../crates/evm-coder" }
137pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
138primitive-types = { version = "0.11.1", default-features = false, features = [
139 "serde_no_std",
140] }
141
142pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.20" }86pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.18-2" }
143pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.20" }
144fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.20" }
145hex-literal = "0.3.3"
146
147pallet-common = { default-features = false, path = "../common" }87pallet-common = { default-features = false, path = "../common" }
148pallet-fungible = { default-features = false, path = "../fungible" }
149pallet-nonfungible = { default-features = false, path = "../nonfungible" }
150pallet-refungible = { default-features = false, path = "../refungible" }
15188
deletedpallets/unique/src/common.rsdiffbeforeafterboth
--- a/pallets/unique/src/common.rs
+++ /dev/null
@@ -1,73 +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};
-
-use pallet_fungible::{common::CommonWeights as FungibleWeights};
-use pallet_nonfungible::{common::CommonWeights as NonfungibleWeights};
-use pallet_refungible::{common::CommonWeights as RefungibleWeights};
-use up_data_structs::CreateItemExData;
-
-use crate::Config;
-
-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: Config>(PhantomData<T>);
-impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
-	fn create_item() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(create_item())
-	}
-
-	fn create_multiple_items(amount: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(create_multiple_items(amount))
-	}
-
-	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 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 set_variable_metadata(bytes: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))
-	}
-
-	fn burn_from() -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(burn_from())
-	}
-}
deletedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ /dev/null
@@ -1,17 +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/>.
-
-pub mod sponsoring;
deletedpallets/unique/src/eth/sponsoring.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/sponsoring.rs
+++ /dev/null
@@ -1,102 +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 crate::{Config, sponsorship::*};
-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};
-
-use pallet_nonfungible::erc::{
-	UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call,
-};
-use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
-
-pub struct UniqueEthSponsorshipHandler<T: Config>(PhantomData<*const T>);
-impl<T: Config> 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 {
-			crate::CollectionMode::NFT => {
-				let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
-				match call {
-					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,
-				}
-			}
-			crate::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,
-		}?))
-	}
-}
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -22,10 +22,6 @@
 	clippy::unused_unit
 )]
 
-extern crate alloc;
-
-pub use serde::{Serialize, Deserialize};
-
 use frame_support::{
 	decl_module, decl_storage, decl_error, decl_event,
 	dispatch::DispatchResult,
@@ -50,20 +46,6 @@
 	CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,
 	dispatch::dispatch_call, dispatch::CollectionDispatch,
 };
-
-#[cfg(test)]
-mod mock;
-
-#[cfg(test)]
-mod tests;
-
-mod eth;
-mod sponsorship;
-pub use sponsorship::{UniqueSponsorshipHandler, UniqueSponsorshipPredict};
-pub use eth::sponsoring::UniqueEthSponsorshipHandler;
-
-pub mod common;
-use common::CommonWeights;
 
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
@@ -88,20 +70,12 @@
 	}
 }
 
-pub trait Config:
-	system::Config
-	+ pallet_evm_coder_substrate::Config
-	+ pallet_common::Config
-	+ pallet_nonfungible::Config
-	+ pallet_refungible::Config
-	+ pallet_fungible::Config
-	+ Sized
-	+ TypeInfo
-{
+pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {
 	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
 
 	/// Weight information for extrinsics in this pallet.
 	type WeightInfo: WeightInfo;
+	type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;
 }
 
 decl_event! {
@@ -689,7 +663,7 @@
 		/// * owner: Address, initial owner of the NFT.
 		///
 		/// * data: Token data to store on chain.
-		#[weight = <CommonWeights<T>>::create_item()]
+		#[weight = T::CommonWeightInfo::create_item()]
 		#[transactional]
 		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -716,7 +690,7 @@
 		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].
 		///
 		/// * owner: Address, initial owner of the NFT.
-		#[weight = <CommonWeights<T>>::create_multiple_items(items_data.len() as u32)]
+		#[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]
 		#[transactional]
 		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {
 			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);
@@ -726,7 +700,7 @@
 			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))
 		}
 
-		#[weight = <CommonWeights<T>>::create_multiple_items_ex(&data)]
+		#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]
 		#[transactional]
 		pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -774,7 +748,7 @@
 		/// * collection_id: ID of the collection.
 		///
 		/// * item_id: ID of NFT to burn.
-		#[weight = <CommonWeights<T>>::burn_item()]
+		#[weight = T::CommonWeightInfo::burn_item()]
 		#[transactional]
 		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -806,7 +780,7 @@
 		/// * item_id: ID of NFT to burn.
 		///
 		/// * from: owner of item
-		#[weight = <CommonWeights<T>>::burn_from()]
+		#[weight = T::CommonWeightInfo::burn_from()]
 		#[transactional]
 		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -838,7 +812,7 @@
 		///     * Non-Fungible Mode: Ignored
 		///     * Fungible Mode: Must specify transferred amount
 		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
-		#[weight = <CommonWeights<T>>::transfer()]
+		#[weight = T::CommonWeightInfo::transfer()]
 		#[transactional]
 		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -862,7 +836,7 @@
 		/// * collection_id.
 		///
 		/// * item_id: ID of the item.
-		#[weight = <CommonWeights<T>>::approve()]
+		#[weight = T::CommonWeightInfo::approve()]
 		#[transactional]
 		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -889,7 +863,7 @@
 		/// * item_id: ID of the item.
 		///
 		/// * value: Amount to transfer.
-		#[weight = <CommonWeights<T>>::transfer_from()]
+		#[weight = T::CommonWeightInfo::transfer_from()]
 		#[transactional]
 		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -910,7 +884,7 @@
 		/// * collection_id.
 		///
 		/// * schema: String representing the offchain data schema.
-		#[weight = <CommonWeights<T>>::set_variable_metadata(data.len() as u32)]
+		#[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]
 		#[transactional]
 		pub fn set_variable_meta_data (
 			origin,
deletedpallets/unique/src/mock.rsdiffbeforeafterboth
--- a/pallets/unique/src/mock.rs
+++ /dev/null
@@ -1,220 +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/>.
-
-#![allow(clippy::from_over_into)]
-
-use crate as pallet_template;
-use sp_core::{H160, H256};
-use frame_support::{parameter_types, traits::Everything, weights::IdentityFee};
-use sp_runtime::{
-	traits::{BlakeTwo256, IdentityLookup},
-	testing::Header,
-};
-use pallet_transaction_payment::{CurrencyAdapter};
-use frame_system as system;
-use pallet_evm::{AddressMapping, runner::stack::MaybeMirroredLog, account::CrossAccountId};
-use fp_evm_mapping::EvmBackwardsAddressMapping;
-use codec::{Encode, Decode, MaxEncodedLen};
-use scale_info::TypeInfo;
-use up_data_structs::ConstU32;
-
-type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
-type Block = frame_system::mocking::MockBlock<Test>;
-
-// Configure a mock runtime to test the pallet.
-frame_support::construct_runtime!(
-	pub enum Test where
-		Block = Block,
-		NodeBlock = Block,
-		UncheckedExtrinsic = UncheckedExtrinsic,
-	{
-		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
-		TemplateModule: pallet_template::{Pallet, Call, Storage},
-		Balances: pallet_balances::{Pallet, Call, Storage},
-		Common: pallet_common::{Pallet, Storage, Event<T>},
-		Fungible: pallet_fungible::{Pallet, Storage},
-		Refungible: pallet_refungible::{Pallet, Storage},
-		Nonfungible: pallet_nonfungible::{Pallet, Storage},
-	}
-);
-
-parameter_types! {
-	pub const BlockHashCount: u64 = 250;
-	pub const SS58Prefix: u8 = 42;
-}
-
-impl system::Config for Test {
-	type BaseCallFilter = Everything;
-	type BlockWeights = ();
-	type BlockLength = ();
-	type DbWeight = ();
-	type Origin = Origin;
-	type Call = Call;
-	type Index = u64;
-	type BlockNumber = u64;
-	type Hash = H256;
-	type Hashing = BlakeTwo256;
-	type AccountId = u64;
-	type Lookup = IdentityLookup<Self::AccountId>;
-	type Header = Header;
-	type Event = ();
-	type BlockHashCount = BlockHashCount;
-	type Version = ();
-	type PalletInfo = PalletInfo;
-	type AccountData = pallet_balances::AccountData<u64>;
-	type OnNewAccount = ();
-	type OnKilledAccount = ();
-	type SystemWeightInfo = ();
-	type SS58Prefix = SS58Prefix;
-	type OnSetCode = ();
-	type MaxConsumers = ConstU32<16>;
-}
-
-parameter_types! {
-	pub const ExistentialDeposit: u64 = 1;
-	pub const MaxLocks: u32 = 50;
-}
-//frame_system::Module<Test>;
-impl pallet_balances::Config for Test {
-	type AccountStore = System;
-	type Balance = u64;
-	type DustRemoval = ();
-	type Event = ();
-	type ExistentialDeposit = ExistentialDeposit;
-	type WeightInfo = ();
-	type MaxLocks = MaxLocks;
-	type MaxReserves = ();
-	type ReserveIdentifier = [u8; 8];
-}
-
-parameter_types! {
-	pub const OperationalFeeMultiplier: u8 = 5;
-}
-
-impl pallet_transaction_payment::Config for Test {
-	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Pallet<Test>, ()>;
-	type LengthToFee = IdentityFee<u64>;
-	type WeightToFee = IdentityFee<u64>;
-	type FeeMultiplierUpdate = ();
-	type OperationalFeeMultiplier = OperationalFeeMultiplier;
-}
-
-parameter_types! {
-	pub const MinimumPeriod: u64 = 1;
-}
-impl pallet_timestamp::Config for Test {
-	type Moment = u64;
-	type OnTimestampSet = ();
-	type MinimumPeriod = MinimumPeriod;
-	type WeightInfo = ();
-}
-
-parameter_types! {
-	pub const CollectionCreationPrice: u32 = 100;
-	pub TreasuryAccountId: u64 = 1234;
-	pub EthereumChainId: u32 = 1111;
-}
-
-pub struct TestEvmAddressMapping;
-impl AddressMapping<u64> for TestEvmAddressMapping {
-	fn into_account_id(_addr: sp_core::H160) -> u64 {
-		unimplemented!()
-	}
-}
-
-pub struct TestEvmBackwardsAddressMapping;
-impl EvmBackwardsAddressMapping<u64> for TestEvmBackwardsAddressMapping {
-	fn from_account_id(_account_id: u64) -> sp_core::H160 {
-		unimplemented!()
-	}
-}
-
-#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]
-pub struct TestCrossAccountId(u64, sp_core::H160);
-impl CrossAccountId<u64> for TestCrossAccountId {
-	fn as_sub(&self) -> &u64 {
-		&self.0
-	}
-	fn as_eth(&self) -> &sp_core::H160 {
-		&self.1
-	}
-	fn from_sub(sub: u64) -> Self {
-		let mut eth = [0; 20];
-		eth[12..20].copy_from_slice(&sub.to_be_bytes());
-		Self(sub, sp_core::H160(eth))
-	}
-	fn from_eth(eth: sp_core::H160) -> Self {
-		let mut sub_raw = [0; 8];
-		sub_raw.copy_from_slice(&eth.0[0..8]);
-		let sub = u64::from_be_bytes(sub_raw);
-		Self(sub, eth)
-	}
-	fn conv_eq(&self, other: &Self) -> bool {
-		self.as_sub() == other.as_sub()
-	}
-}
-
-impl Default for TestCrossAccountId {
-	fn default() -> Self {
-		Self::from_sub(0)
-	}
-}
-
-pub struct TestEtheremTransactionSender;
-impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {
-	fn submit_logs_transaction(_source: H160, _logs: Vec<MaybeMirroredLog>) {}
-}
-
-impl pallet_evm_coder_substrate::Config for Test {
-	type EthereumTransactionSender = TestEtheremTransactionSender;
-	type GasWeightMapping = ();
-}
-
-impl pallet_common::Config for Test {
-	type Event = ();
-	type Currency = Balances;
-	type CollectionCreationPrice = CollectionCreationPrice;
-	type TreasuryAccountId = TreasuryAccountId;
-}
-
-impl pallet_evm::account::Config for Test {
-	type CrossAccountId = TestCrossAccountId;
-	type EvmAddressMapping = TestEvmAddressMapping;
-	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
-}
-
-impl pallet_fungible::Config for Test {
-	type WeightInfo = ();
-}
-impl pallet_refungible::Config for Test {
-	type WeightInfo = ();
-}
-impl pallet_nonfungible::Config for Test {
-	type WeightInfo = ();
-}
-
-impl pallet_template::Config for Test {
-	type Event = ();
-	type WeightInfo = ();
-}
-
-// Build genesis storage according to the mock runtime.
-pub fn new_test_ext() -> sp_io::TestExternalities {
-	system::GenesisConfig::default()
-		.build_storage::<Test>()
-		.unwrap()
-		.into()
-}
deletedpallets/unique/src/sponsorship.rsdiffbeforeafterboth
--- a/pallets/unique/src/sponsorship.rs
+++ /dev/null
@@ -1,365 +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 crate::{
-	Config, Call, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket,
-	FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode, NftApproveBasket,
-	FungibleApproveBasket, RefungibleApproveBasket,
-};
-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, MetaUpdatePermission,
-	NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId,
-};
-use sp_runtime::traits::Saturating;
-use pallet_common::{CollectionHandle};
-use pallet_evm::account::CrossAccountId;
-
-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<()> {
-	if _properties.data_size() as u32 > collection.limits.sponsored_data_size() {
-		return None;
-	}
-
-	// 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_set_variable_meta_data<T: Config>(
-	who: &T::CrossAccountId,
-	collection: &CollectionHandle<T>,
-	item_id: &TokenId,
-	data: &[u8],
-) -> Option<()> {
-	// TODO: make it work for admins
-	if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {
-		return None;
-	}
-	// 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;
-			}
-		}
-	}
-
-	// Can't sponsor fungible collection, this tx will be rejected
-	// as invalid
-	if matches!(collection.mode, CollectionMode::Fungible(_)) {
-		return None;
-	}
-	if data.len() > 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) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	<VariableMetaDataBasket<T>>::insert(collection.id, item_id, 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: Config>(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<Call<T>>,
-{
-	fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
-		match IsSubType::<Call<T>>::is_sub_type(call)? {
-			Call::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)
-			}
-			Call::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)
-			}
-			Call::transfer_from {
-				collection_id,
-				item_id,
-				from,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)
-			}
-			Call::approve {
-				collection_id,
-				item_id,
-				..
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
-			}
-			Call::set_variable_meta_data {
-				collection_id,
-				item_id,
-				data,
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_set_variable_meta_data::<T>(
-					&T::CrossAccountId::from_sub(who.clone()),
-					&collection,
-					item_id,
-					data,
-				)
-				.map(|()| sponsor)
-			}
-			_ => None,
-		}
-	}
-}
-
-use crate::SponsorshipPredict;
-pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
-
-impl<T> SponsorshipPredict<T> for UniqueSponsorshipPredict<T>
-where
-	T: Config,
-{
-	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(_) => true,
-			CollectionMode::ReFungible => {
-				<pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
-			}
-		};
-
-		if token_exists {
-			Some(0)
-		} else {
-			None
-		}
-	}
-}
deletedpallets/unique/src/tests.rsdiffbeforeafterboth
--- a/pallets/unique/src/tests.rs
+++ /dev/null
@@ -1,2912 +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/>.
-
-// Tests to be written here
-use super::*;
-use crate::mock::*;
-use crate::{AccessMode, CollectionMode};
-use up_data_structs::{
-	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
-	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,
-	TokenId, MAX_TOKEN_OWNERSHIP,
-};
-use frame_support::{assert_noop, assert_ok, assert_err};
-use sp_std::convert::TryInto;
-use pallet_balances;
-
-fn add_balance(user: u64, value: u64) {
-	const DONOR_USER: u64 = 999;
-	assert_ok!(<pallet_balances::Pallet<Test>>::set_balance(
-		Origin::root(),
-		DONOR_USER,
-		value,
-		0
-	));
-	assert_ok!(<pallet_balances::Pallet<Test>>::force_transfer(
-		Origin::root(),
-		DONOR_USER,
-		user,
-		value
-	));
-}
-
-fn default_nft_data() -> CreateNftData {
-	CreateNftData {
-		const_data: vec![1, 2, 3].try_into().unwrap(),
-		variable_data: vec![3, 2, 1].try_into().unwrap(),
-	}
-}
-
-fn default_fungible_data() -> CreateFungibleData {
-	CreateFungibleData { value: 5 }
-}
-
-fn default_re_fungible_data() -> CreateReFungibleData {
-	CreateReFungibleData {
-		const_data: vec![1, 2, 3].try_into().unwrap(),
-		variable_data: vec![3, 2, 1].try_into().unwrap(),
-		pieces: 1023,
-	}
-}
-
-fn create_test_collection_for_owner(
-	mode: &CollectionMode,
-	owner: u64,
-	id: CollectionId,
-) -> CollectionId {
-	add_balance(owner, CollectionCreationPrice::get() as u64 + 1);
-
-	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-
-	let data: CreateCollectionData<u64> = CreateCollectionData {
-		name: col_name1.try_into().unwrap(),
-		description: col_desc1.try_into().unwrap(),
-		token_prefix: token_prefix1.try_into().unwrap(),
-		mode: mode.clone(),
-		..Default::default()
-	};
-
-	let origin1 = Origin::signed(owner);
-	assert_ok!(TemplateModule::create_collection_ex(origin1, data));
-
-	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
-	assert_eq!(
-		<pallet_common::CollectionById<Test>>::get(id)
-			.unwrap()
-			.owner,
-		owner
-	);
-	assert_eq!(
-		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,
-		saved_col_name
-	);
-	assert_eq!(
-		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,
-		*mode
-	);
-	assert_eq!(
-		<pallet_common::CollectionById<Test>>::get(id)
-			.unwrap()
-			.description,
-		saved_description
-	);
-	assert_eq!(
-		<pallet_common::CollectionById<Test>>::get(id)
-			.unwrap()
-			.token_prefix,
-		saved_prefix
-	);
-	id
-}
-
-fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {
-	create_test_collection_for_owner(&mode, 1, id)
-}
-
-fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {
-	let origin1 = Origin::signed(1);
-	assert_ok!(TemplateModule::create_item(
-		origin1,
-		collection_id,
-		account(1),
-		data.clone()
-	));
-}
-
-fn account(sub: u64) -> TestCrossAccountId {
-	TestCrossAccountId::from_sub(sub)
-}
-
-// Use cases tests region
-// #region
-
-#[test]
-fn set_version_schema() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		assert_ok!(TemplateModule::set_schema_version(
-			origin1,
-			collection_id,
-			SchemaVersion::Unique
-		));
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.schema_version,
-			SchemaVersion::Unique
-		);
-	});
-}
-
-#[test]
-fn check_not_sufficient_founds() {
-	new_test_ext().execute_with(|| {
-		let acc: u64 = 1;
-		<pallet_balances::Pallet<Test>>::set_balance(Origin::root(), acc, 0, 0).unwrap();
-
-		let name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-		let description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-		let token_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
-
-		let data: CreateCollectionData<<Test as system::Config>::AccountId> =
-			CreateCollectionData {
-				name: name.try_into().unwrap(),
-				description: description.try_into().unwrap(),
-				token_prefix: token_prefix.try_into().unwrap(),
-				mode: CollectionMode::NFT,
-				..Default::default()
-			};
-
-		let result = TemplateModule::create_collection_ex(Origin::signed(acc), data);
-		assert_err!(result, <CommonError<Test>>::NotSufficientFounds);
-	});
-}
-
-#[test]
-fn create_fungible_collection_fails_with_large_decimal_numbers() {
-	new_test_ext().execute_with(|| {
-		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-
-		let data: CreateCollectionData<u64> = CreateCollectionData {
-			name: col_name1.try_into().unwrap(),
-			description: col_desc1.try_into().unwrap(),
-			token_prefix: token_prefix1.try_into().unwrap(),
-			mode: CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1),
-			..Default::default()
-		};
-
-		let origin1 = Origin::signed(1);
-		assert_noop!(
-			TemplateModule::create_collection_ex(origin1, data),
-			Error::<Test>::CollectionDecimalPointLimitExceeded
-		);
-	});
-}
-
-#[test]
-fn create_nft_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.clone().into());
-
-		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();
-		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
-	});
-}
-
-// Use cases tests region
-// #region
-#[test]
-fn create_nft_multiple_items() {
-	new_test_ext().execute_with(|| {
-		create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];
-
-		assert_ok!(TemplateModule::create_multiple_items(
-			origin1,
-			CollectionId(1),
-			account(1),
-			items_data
-				.clone()
-				.into_iter()
-				.map(|d| { d.into() })
-				.collect()
-		));
-		for (index, data) in items_data.into_iter().enumerate() {
-			let item = <pallet_nonfungible::TokenData<Test>>::get((
-				CollectionId(1),
-				TokenId((index + 1) as u32),
-			))
-			.unwrap();
-			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
-			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
-		}
-	});
-}
-
-#[test]
-fn create_refungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.clone().into());
-		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
-		let balance =
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));
-		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
-		assert_eq!(balance, 1023);
-	});
-}
-
-#[test]
-fn create_multiple_refungible_items() {
-	new_test_ext().execute_with(|| {
-		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let items_data = vec![
-			default_re_fungible_data(),
-			default_re_fungible_data(),
-			default_re_fungible_data(),
-		];
-
-		assert_ok!(TemplateModule::create_multiple_items(
-			origin1,
-			CollectionId(1),
-			account(1),
-			items_data
-				.clone()
-				.into_iter()
-				.map(|d| { d.into() })
-				.collect()
-		));
-		for (index, data) in items_data.into_iter().enumerate() {
-			let item = <pallet_refungible::TokenData<Test>>::get((
-				CollectionId(1),
-				TokenId((index + 1) as u32),
-			));
-			let balance =
-				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));
-			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
-			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
-			assert_eq!(balance, 1023);
-		}
-	});
-}
-
-#[test]
-fn create_fungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
-			5
-		);
-	});
-}
-
-//#[test]
-// fn create_multiple_fungible_items() {
-//     new_test_ext().execute_with(|| {
-//         default_limits();
-
-//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-//         let origin1 = Origin::signed(1);
-
-//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];
-
-//         assert_ok!(TemplateModule::create_multiple_items(
-//             origin1.clone(),
-//             1,
-//             1,
-//             items_data.clone().into_iter().map(|d| { d.into() }).collect()
-//         ));
-
-//         for (index, _) in items_data.iter().enumerate() {
-//             assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);
-//         }
-//         assert_eq!(TemplateModule::balance_count(1, 1), 3000);
-//         assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);
-//     });
-// }
-
-#[test]
-fn transfer_fungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),
-			5
-		);
-
-		// change owner scenario
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(0),
-			5
-		));
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),
-			0
-		);
-
-		// split item scenario
-		assert_ok!(TemplateModule::transfer(
-			origin2.clone(),
-			account(3),
-			CollectionId(1),
-			TokenId(0),
-			3
-		));
-
-		// split item and new owner has account scenario
-		assert_ok!(TemplateModule::transfer(
-			origin2,
-			account(3),
-			CollectionId(1),
-			TokenId(0),
-			1
-		));
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),
-			1
-		);
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),
-			4
-		);
-	});
-}
-
-#[test]
-fn transfer_refungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		// Create RFT 1 in 1023 pieces for account 1
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.clone().into());
-		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
-		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
-			1023
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		// Account 1 transfers all 1023 pieces of RFT 1 to account 2
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1023
-		));
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
-			1023
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			false
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			true
-		);
-
-		// Account 2 transfers 500 pieces of RFT 1 to account 3
-		assert_ok!(TemplateModule::transfer(
-			origin2.clone(),
-			account(3),
-			CollectionId(1),
-			TokenId(1),
-			500
-		));
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
-			523
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
-			500
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),
-			true
-		);
-
-		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance
-		assert_ok!(TemplateModule::transfer(
-			origin2,
-			account(3),
-			CollectionId(1),
-			TokenId(1),
-			200
-		));
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
-			323
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
-			700
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),
-			true
-		);
-	});
-}
-
-#[test]
-fn transfer_nft_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		let origin1 = Origin::signed(1);
-		// default scenario
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			false
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			true
-		);
-	});
-}
-
-#[test]
-fn transfer_nft_item_wrong_value() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		let origin1 = Origin::signed(1);
-
-		assert_noop!(
-			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)
-				.map_err(|e| e.error),
-			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount
-		);
-	});
-}
-
-#[test]
-fn transfer_nft_item_zero_value() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		let origin1 = Origin::signed(1);
-
-		// Transferring 0 amount works on NFT...
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			0
-		));
-		// ... and results in no transfer
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-	});
-}
-
-#[test]
-fn nft_approve_and_transfer_from() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		// neg transfer_from
-		assert_noop!(
-			TemplateModule::transfer_from(
-				origin2.clone(),
-				account(1),
-				account(2),
-				CollectionId(1),
-				TokenId(1),
-				1
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::ApprovedValueTooLow
-		);
-
-		// do approve
-		assert_ok!(TemplateModule::approve(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(2)
-		);
-
-		assert_ok!(TemplateModule::transfer_from(
-			origin2,
-			account(1),
-			account(3),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()
-		);
-	});
-}
-
-#[test]
-fn nft_approve_and_transfer_from_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		// Create NFT 1 for account 1
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.clone().into());
-		assert_eq!(
-			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
-				.unwrap()
-				.const_data,
-			&data.const_data.into_inner()
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			CollectionId(1),
-			true
-		));
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			CollectionId(1),
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(3)
-		));
-
-		// Account 1 approves account 2 for NFT 1
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(2)
-		);
-
-		// Account 2 transfers NFT 1 from account 1 to account 3
-		assert_ok!(TemplateModule::transfer_from(
-			origin2,
-			account(1),
-			account(3),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()
-		);
-	});
-}
-
-#[test]
-fn refungible_approve_and_transfer_from() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		// Create RFT 1 in 1023 pieces for account 1
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
-			1023
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			CollectionId(1),
-			true
-		));
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			CollectionId(1),
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(3)
-		));
-
-		// Account 1 approves account 2 for 1023 pieces of RFT 1
-		assert_ok!(TemplateModule::approve(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1023
-		));
-		assert_eq!(
-			<pallet_refungible::Allowance<Test>>::get((
-				CollectionId(1),
-				TokenId(1),
-				account(1),
-				account(2)
-			)),
-			1023
-		);
-
-		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3
-		assert_ok!(TemplateModule::transfer_from(
-			origin2,
-			account(1),
-			account(3),
-			CollectionId(1),
-			TokenId(1),
-			100
-		));
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
-			923
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
-			100
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_refungible::Allowance<Test>>::get((
-				CollectionId(1),
-				TokenId(1),
-				account(1),
-				account(2)
-			)),
-			923
-		);
-	});
-}
-
-#[test]
-fn fungible_approve_and_transfer_from() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			CollectionId(1),
-			true
-		));
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			CollectionId(1),
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(3)
-		));
-
-		// do approve
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(2),
-			CollectionId(1),
-			TokenId(0),
-			5
-		));
-		assert_eq!(
-			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
-			5
-		);
-		assert_ok!(TemplateModule::approve(
-			origin1,
-			account(3),
-			CollectionId(1),
-			TokenId(0),
-			5
-		));
-		assert_eq!(
-			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
-			5
-		);
-		assert_eq!(
-			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),
-			5
-		);
-
-		assert_ok!(TemplateModule::transfer_from(
-			origin2.clone(),
-			account(1),
-			account(3),
-			CollectionId(1),
-			TokenId(0),
-			4
-		));
-
-		assert_eq!(
-			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
-			1
-		);
-
-		assert_noop!(
-			TemplateModule::transfer_from(
-				origin2,
-				account(1),
-				account(3),
-				CollectionId(1),
-				TokenId(0),
-				4
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::ApprovedValueTooLow
-		);
-	});
-}
-
-#[test]
-fn change_collection_owner() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::change_collection_owner(
-			origin1,
-			collection_id,
-			2
-		));
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.owner,
-			2
-		);
-	});
-}
-
-#[test]
-fn destroy_collection() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));
-	});
-}
-
-#[test]
-fn burn_nft_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-
-		// burn item
-		assert_ok!(TemplateModule::burn_item(
-			origin1.clone(),
-			collection_id,
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			0
-		);
-	});
-}
-
-#[test]
-fn burn_same_nft_item_twice() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-
-		// burn item
-		assert_ok!(TemplateModule::burn_item(
-			origin1.clone(),
-			collection_id,
-			TokenId(1),
-			1
-		));
-
-		// burn item again
-		assert_noop!(
-			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),
-			CommonError::<Test>::TokenNotFound
-		);
-
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			0
-		);
-	});
-}
-
-#[test]
-fn burn_fungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
-			5
-		);
-
-		// burn item
-		assert_ok!(TemplateModule::burn_item(
-			origin1.clone(),
-			CollectionId(1),
-			TokenId(0),
-			5
-		));
-		assert_noop!(
-			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),
-			CommonError::<Test>::TokenValueTooLow
-		);
-
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
-			0
-		);
-	});
-}
-
-#[test]
-fn burn_fungible_item_with_token_id() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
-			5
-		);
-
-		// Try to burn item using Token ID
-		assert_noop!(
-			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),
-			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId
-		);
-	});
-}
-#[test]
-fn burn_refungible_item() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		// check balance (collection with id = 1, user id = 2)
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
-			1023
-		);
-
-		// burn item
-		assert_ok!(TemplateModule::burn_item(
-			origin1.clone(),
-			collection_id,
-			TokenId(1),
-			1023
-		));
-		assert_noop!(
-			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1023)
-				.map_err(|e| e.error),
-			CommonError::<Test>::TokenValueTooLow
-		);
-
-		assert_eq!(
-			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
-			0
-		);
-	});
-}
-
-#[test]
-fn add_collection_admin() {
-	new_test_ext().execute_with(|| {
-		let collection1_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		// Add collection admins
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection1_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection1_id,
-			account(3)
-		));
-
-		// Owner is not an admin by default
-		assert_eq!(
-			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),
-			false
-		);
-		assert!(<pallet_common::IsAdmin<Test>>::get((
-			CollectionId(1),
-			account(2)
-		)));
-		assert!(<pallet_common::IsAdmin<Test>>::get((
-			CollectionId(1),
-			account(3)
-		)));
-	});
-}
-
-#[test]
-fn remove_collection_admin() {
-	new_test_ext().execute_with(|| {
-		let collection1_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		// Add collection admins 2 and 3
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection1_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection1_id,
-			account(3)
-		));
-
-		assert!(<pallet_common::IsAdmin<Test>>::get((
-			CollectionId(1),
-			account(2)
-		)));
-		assert!(<pallet_common::IsAdmin<Test>>::get((
-			CollectionId(1),
-			account(3)
-		)));
-
-		// remove admin 3
-		assert_ok!(TemplateModule::remove_collection_admin(
-			origin2,
-			CollectionId(1),
-			account(3)
-		));
-
-		// 2 is still admin, 3 is not an admin anymore
-		assert!(<pallet_common::IsAdmin<Test>>::get((
-			CollectionId(1),
-			account(2)
-		)));
-		assert_eq!(
-			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),
-			false
-		);
-	});
-}
-
-#[test]
-fn balance_of() {
-	new_test_ext().execute_with(|| {
-		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let fungible_collection_id =
-			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));
-		let re_fungible_collection_id =
-			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));
-
-		// check balance before
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),
-			0
-		);
-
-		let nft_data = default_nft_data();
-		create_test_item(nft_collection_id, &nft_data.into());
-
-		let fungible_data = default_fungible_data();
-		create_test_item(fungible_collection_id, &fungible_data.into());
-
-		let re_fungible_data = default_re_fungible_data();
-		create_test_item(re_fungible_collection_id, &re_fungible_data.into());
-
-		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),
-			5
-		);
-		assert_eq!(
-			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),
-			1
-		);
-
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_refungible::Owned<Test>>::get((
-				re_fungible_collection_id,
-				account(1),
-				TokenId(1)
-			)),
-			true
-		);
-	});
-}
-
-#[test]
-fn approve() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		let origin1 = Origin::signed(1);
-
-		// approve
-		assert_ok!(TemplateModule::approve(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(2)
-		);
-	});
-}
-
-#[test]
-fn transfer_from() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		// approve
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(2)
-		);
-
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			CollectionId(1),
-			true
-		));
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			CollectionId(1),
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			CollectionId(1),
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			CollectionId(1),
-			account(3)
-		));
-
-		assert_ok!(TemplateModule::transfer_from(
-			origin2,
-			account(1),
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-
-		// after transfer
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),
-			1
-		);
-	});
-}
-
-// #endregion
-
-// Coverage tests region
-// #region
-
-#[test]
-fn owner_can_add_address_to_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert!(<pallet_common::Allowlist<Test>>::get((
-			collection_id,
-			account(2)
-		)));
-	});
-}
-
-#[test]
-fn admin_can_add_address_to_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin2,
-			collection_id,
-			account(3)
-		));
-		assert!(<pallet_common::Allowlist<Test>>::get((
-			collection_id,
-			account(3)
-		)));
-	});
-}
-
-#[test]
-fn nonprivileged_user_cannot_add_address_to_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin2 = Origin::signed(2);
-		assert_noop!(
-			TemplateModule::add_to_allow_list(origin2, collection_id, account(3)),
-			CommonError::<Test>::NoPermission
-		);
-	});
-}
-
-#[test]
-fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-
-		assert_noop!(
-			TemplateModule::add_to_allow_list(origin1, CollectionId(1), account(2)),
-			CommonError::<Test>::CollectionNotFound
-		);
-	});
-}
-
-#[test]
-fn nobody_can_add_address_to_allow_list_of_deleted_collection() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::destroy_collection(
-			origin1.clone(),
-			collection_id
-		));
-		assert_noop!(
-			TemplateModule::add_to_allow_list(origin1, collection_id, account(2)),
-			CommonError::<Test>::CollectionNotFound
-		);
-	});
-}
-
-// If address is already added to allow list, nothing happens
-#[test]
-fn address_is_already_added_to_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert!(<pallet_common::Allowlist<Test>>::get((
-			collection_id,
-			account(2)
-		)));
-	});
-}
-
-#[test]
-fn owner_can_remove_address_from_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert_eq!(
-			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
-			false
-		);
-	});
-}
-
-#[test]
-fn admin_can_remove_address_from_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		// Owner adds admin
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		// Owner adds address 3 to allow list
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(3)
-		));
-
-		// Admin removes address 3 from allow list
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin2,
-			collection_id,
-			account(3)
-		));
-		assert_eq!(
-			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),
-			false
-		);
-	});
-}
-
-#[test]
-fn nonprivileged_user_cannot_remove_address_from_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert_noop!(
-			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),
-			CommonError::<Test>::NoPermission
-		);
-		assert!(<pallet_common::Allowlist<Test>>::get((
-			collection_id,
-			account(2)
-		)));
-	});
-}
-
-#[test]
-fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-
-		assert_noop!(
-			TemplateModule::remove_from_allow_list(origin1, CollectionId(1), account(2)),
-			CommonError::<Test>::CollectionNotFound
-		);
-	});
-}
-
-#[test]
-fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		// Add account 2 to allow list
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		// Account 2 is in collection allow-list
-		assert!(<pallet_common::Allowlist<Test>>::get((
-			collection_id,
-			account(2)
-		)));
-
-		// Destroy collection
-		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));
-
-		// Attempt to remove account 2 from collection allow-list => error
-		assert_noop!(
-			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),
-			CommonError::<Test>::CollectionNotFound
-		);
-
-		// Account 2 is not found in collection allow-list anyway
-		assert_eq!(
-			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
-			false
-		);
-	});
-}
-
-// If address is already removed from allow list, nothing happens
-#[test]
-fn address_is_already_removed_from_allow_list() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-		assert_eq!(
-			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
-			false
-		);
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-		assert_eq!(
-			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
-			false
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)
-#[test]
-fn allow_list_test_1() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		assert_noop!(
-			TemplateModule::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)
-				.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-#[test]
-fn allow_list_test_2() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		// do approve
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(1),
-			collection_id,
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(1)
-		);
-
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-
-		assert_noop!(
-			TemplateModule::transfer_from(
-				origin1,
-				account(1),
-				account(3),
-				CollectionId(1),
-				TokenId(1),
-				1
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)
-#[test]
-fn allow_list_test_3() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-
-		assert_noop!(
-			TemplateModule::transfer(origin1, account(3), collection_id, TokenId(1), 1)
-				.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-#[test]
-fn allow_list_test_4() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		// do approve
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(1),
-			collection_id,
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(1)
-		);
-
-		assert_ok!(TemplateModule::remove_from_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		assert_noop!(
-			TemplateModule::transfer_from(
-				origin1,
-				account(1),
-				account(3),
-				collection_id,
-				TokenId(1),
-				1
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)
-#[test]
-fn allow_list_test_5() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_noop!(
-			TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1)
-				.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).
-#[test]
-fn allow_list_test_6() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-
-		// do approve
-		assert_noop!(
-			TemplateModule::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)
-				.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and
-//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)
-#[test]
-fn allow_list_test_7() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-	});
-}
-
-#[test]
-fn allow_list_test_8() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		// Create NFT for account 1
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		let origin1 = Origin::signed(1);
-
-		// Toggle Allow List mode and add accounts 1 and 2
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(1)
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-
-		// Sself-approve account 1 for NFT 1
-		assert_ok!(TemplateModule::approve(
-			origin1.clone(),
-			account(1),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
-			account(1)
-		);
-
-		// Transfer from 1 to 2
-		assert_ok!(TemplateModule::transfer_from(
-			origin1,
-			account(1),
-			account(2),
-			CollectionId(1),
-			TokenId(1),
-			1
-		));
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.
-#[test]
-fn allow_list_test_9() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1,
-			collection_id,
-			false
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.
-#[test]
-fn allow_list_test_10() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			false
-		));
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection_id,
-			account(2)
-		));
-
-		assert_ok!(TemplateModule::create_item(
-			origin2,
-			collection_id,
-			account(2),
-			default_nft_data().into()
-		));
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.
-#[test]
-fn allow_list_test_11() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			false
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-
-		assert_noop!(
-			TemplateModule::create_item(
-				origin2,
-				CollectionId(1),
-				account(2),
-				default_nft_data().into()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::PublicMintingNotAllowed
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.
-#[test]
-fn allow_list_test_12() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1,
-			collection_id,
-			false
-		));
-
-		assert_noop!(
-			TemplateModule::create_item(
-				origin2,
-				CollectionId(1),
-				account(2),
-				default_nft_data().into()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::PublicMintingNotAllowed
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.
-#[test]
-fn allow_list_test_13() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1,
-			collection_id,
-			true
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.
-#[test]
-fn allow_list_test_14() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			true
-		));
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection_id,
-			account(2)
-		));
-
-		assert_ok!(TemplateModule::create_item(
-			origin2,
-			collection_id,
-			account(2),
-			default_nft_data().into()
-		));
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.
-#[test]
-fn allow_list_test_15() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1,
-			collection_id,
-			true
-		));
-
-		assert_noop!(
-			TemplateModule::create_item(
-				origin2,
-				collection_id,
-				account(2),
-				default_nft_data().into()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::AddressNotInAllowlist
-		);
-	});
-}
-
-// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.
-#[test]
-fn allow_list_test_16() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1,
-			collection_id,
-			account(2)
-		));
-
-		assert_ok!(TemplateModule::create_item(
-			origin2,
-			collection_id,
-			account(2),
-			default_nft_data().into()
-		));
-	});
-}
-
-// Total number of collections. Positive test
-#[test]
-fn total_number_collections_bound() {
-	new_test_ext().execute_with(|| {
-		create_test_collection(&CollectionMode::NFT, CollectionId(1));
-	});
-}
-
-#[test]
-fn create_max_collections() {
-	new_test_ext().execute_with(|| {
-		for i in 1..COLLECTION_NUMBER_LIMIT {
-			create_test_collection(&CollectionMode::NFT, CollectionId(i));
-		}
-	});
-}
-
-// Total number of collections. Negative test
-#[test]
-fn total_number_collections_bound_neg() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-
-		for i in 1..=COLLECTION_NUMBER_LIMIT {
-			create_test_collection(&CollectionMode::NFT, CollectionId(i));
-		}
-
-		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-
-		let data: CreateCollectionData<u64> = CreateCollectionData {
-			name: col_name1.try_into().unwrap(),
-			description: col_desc1.try_into().unwrap(),
-			token_prefix: token_prefix1.try_into().unwrap(),
-			mode: CollectionMode::NFT,
-			..Default::default()
-		};
-
-		// 11-th collection in chain. Expects error
-		assert_noop!(
-			TemplateModule::create_collection_ex(origin1, data),
-			CommonError::<Test>::TotalCollectionsLimitExceeded
-		);
-	});
-}
-
-// Owned tokens by a single address. Positive test
-#[test]
-fn owned_tokens_bound() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.clone().into());
-		create_test_item(collection_id, &data.into());
-	});
-}
-
-// Owned tokens by a single address. Negotive test
-#[test]
-fn owned_tokens_bound_neg() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		for _ in 1..=MAX_TOKEN_OWNERSHIP {
-			let data = default_nft_data();
-			create_test_item(collection_id, &data.clone().into());
-		}
-
-		let data = default_nft_data();
-		assert_noop!(
-			TemplateModule::create_item(origin1, CollectionId(1), account(1), data.into())
-				.map_err(|e| e.error),
-			CommonError::<Test>::AccountTokenLimitExceeded
-		);
-	});
-}
-
-// Number of collection admins. Positive test
-#[test]
-fn collection_admins_bound() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1.clone(),
-			collection_id,
-			account(2)
-		));
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin1,
-			collection_id,
-			account(3)
-		));
-	});
-}
-
-// Number of collection admins. Negotive test
-#[test]
-fn collection_admins_bound_neg() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		for i in 0..COLLECTION_ADMINS_LIMIT {
-			assert_ok!(TemplateModule::add_collection_admin(
-				origin1.clone(),
-				collection_id,
-				account((2 + i).into())
-			));
-		}
-		assert_noop!(
-			TemplateModule::add_collection_admin(
-				origin1,
-				collection_id,
-				account((3 + COLLECTION_ADMINS_LIMIT).into())
-			),
-			CommonError::<Test>::CollectionAdminCountExceeded
-		);
-	});
-}
-// #endregion
-
-#[test]
-fn set_const_on_chain_schema() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::set_const_on_chain_schema(
-			origin1,
-			collection_id,
-			b"test const on chain schema".to_vec().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.const_on_chain_schema,
-			b"test const on chain schema".to_vec()
-		);
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.variable_on_chain_schema,
-			b"".to_vec()
-		);
-	});
-}
-
-#[test]
-fn set_variable_on_chain_schema() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::set_variable_on_chain_schema(
-			origin1,
-			collection_id,
-			b"test variable on chain schema"
-				.to_vec()
-				.try_into()
-				.unwrap()
-		));
-
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.const_on_chain_schema,
-			b"".to_vec()
-		);
-		assert_eq!(
-			<pallet_common::CollectionById<Test>>::get(collection_id)
-				.unwrap()
-				.variable_on_chain_schema,
-			b"test variable on chain schema".to_vec()
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(CollectionId(1), &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_ok!(TemplateModule::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_ok!(TemplateModule::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_fungible_token_fails() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_noop!(
-			TemplateModule::set_variable_meta_data(
-				origin1,
-				collection_id,
-				TokenId(0),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {
-	new_test_ext().execute_with(|| {
-		//default_limits();
-
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_meta_update_permission_flag(
-			origin1.clone(),
-			collection_id,
-			MetaUpdatePermission::ItemOwner,
-		));
-
-		let variable_data = b"ten chars.".to_vec();
-		assert_ok!(TemplateModule::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn collection_transfer_flag_works() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		assert_ok!(TemplateModule::set_transfers_enabled_flag(
-			origin1,
-			collection_id,
-			true
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		let origin1 = Origin::signed(1);
-
-		// default scenario
-		assert_ok!(TemplateModule::transfer(
-			origin1,
-			account(2),
-			collection_id,
-			TokenId(1),
-			1
-		));
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			false
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			0
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			1
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_admin_flag() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin2.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		assert_ok!(TemplateModule::add_collection_admin(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::Admin,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_ok!(TemplateModule::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_admin_flag_neg() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin2.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::Admin,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_noop!(
-			TemplateModule::set_variable_meta_data(
-				origin1,
-				collection_id,
-				TokenId(1),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::NoPermission
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_flag_after_freeze() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(TemplateModule::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::None,
-		));
-		assert_noop!(
-			TemplateModule::set_meta_update_permission_flag(
-				origin2.clone(),
-				collection_id,
-				MetaUpdatePermission::Admin
-			),
-			CommonError::<Test>::MetadataFlagFrozen
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_none_flag_neg() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(TemplateModule::set_meta_update_permission_flag(
-			origin1.clone(),
-			collection_id,
-			MetaUpdatePermission::None,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_noop!(
-			TemplateModule::set_variable_meta_data(
-				origin1.clone(),
-				collection_id,
-				TokenId(1),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::NoPermission
-		);
-	});
-}
-
-#[test]
-fn collection_transfer_flag_works_neg() {
-	new_test_ext().execute_with(|| {
-		let origin1 = Origin::signed(1);
-
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-		assert_ok!(TemplateModule::set_transfers_enabled_flag(
-			origin1,
-			collection_id,
-			false
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-
-		let origin1 = Origin::signed(1);
-
-		// default scenario
-		assert_noop!(
-			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)
-				.map_err(|e| e.error),
-			CommonError::<Test>::TransferNotAllowed
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
-			1
-		);
-		assert_eq!(
-			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
-			0
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
-			true
-		);
-		assert_eq!(
-			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
-			false
-		);
-	});
-}
-
-#[test]
-fn collection_sponsoring() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-		let user1 = 1_u64;
-		let user2 = 777_u64;
-		let origin1 = Origin::signed(user1);
-		let origin2 = Origin::signed(user2);
-		let account2 = account(user2);
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));
-		assert_ok!(TemplateModule::set_collection_sponsor(
-			origin1.clone(),
-			collection_id,
-			user1
-		));
-		assert_ok!(TemplateModule::confirm_sponsorship(
-			origin1.clone(),
-			collection_id
-		));
-
-		// Expect error while have no permissions
-		assert!(TemplateModule::create_item(
-			origin2.clone(),
-			collection_id,
-			account2.clone(),
-			default_nft_data().into()
-		)
-		.is_err());
-
-		assert_ok!(TemplateModule::set_public_access_mode(
-			origin1.clone(),
-			collection_id,
-			AccessMode::AllowList
-		));
-		assert_ok!(TemplateModule::add_to_allow_list(
-			origin1.clone(),
-			collection_id,
-			account2.clone()
-		));
-		assert_ok!(TemplateModule::set_mint_permission(
-			origin1.clone(),
-			collection_id,
-			true
-		));
-
-		assert_ok!(TemplateModule::create_item(
-			origin2,
-			collection_id,
-			account2,
-			default_nft_data().into()
-		));
-	});
-}
modifiedruntime/common/Cargo.tomldiffbeforeafterboth
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -104,4 +104,6 @@
 branch = "unique-polkadot-v0.9.20"
 
 [dependencies]
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.20" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.18-2" }
+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.18' }
addedruntime/common/src/eth_sponsoring.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/src/eth_sponsoring.rs
@@ -0,0 +1,107 @@
+// 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,
+};
+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::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,
+		}?))
+	}
+}
modifiedruntime/common/src/lib.rsdiffbeforeafterboth
--- a/runtime/common/src/lib.rs
+++ b/runtime/common/src/lib.rs
@@ -2,5 +2,8 @@
 
 pub mod constants;
 pub mod dispatch;
+pub mod eth_sponsoring;
 pub mod runtime_apis;
+pub mod sponsoring;
 pub mod types;
+pub mod weights;
addedruntime/common/src/sponsoring.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/src/sponsoring.rs
@@ -0,0 +1,375 @@
+// 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, MetaUpdatePermission,
+	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, VariableMetaDataBasket, CreateItemBasket, ReFungibleTransferBasket,
+	FungibleTransferBasket, NftTransferBasket,
+};
+use pallet_fungible::Config as FungibleConfig;
+use pallet_nonfungible::Config as NonfungibleConfig;
+use pallet_refungible::Config as RefungibleConfig;
+
+pub fn withdraw_transfer<
+	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,
+>(
+	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: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,
+>(
+	collection: &CollectionHandle<T>,
+	who: &T::CrossAccountId,
+	_properties: &CreateItemData,
+) -> Option<()> {
+	if _properties.data_size() as u32 > collection.limits.sponsored_data_size() {
+		return None;
+	}
+
+	// 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_set_variable_meta_data<
+	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,
+>(
+	who: &T::CrossAccountId,
+	collection: &CollectionHandle<T>,
+	item_id: &TokenId,
+	data: &[u8],
+) -> Option<()> {
+	// TODO: make it work for admins
+	if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {
+		return None;
+	}
+	// 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;
+			}
+		}
+	}
+
+	// Can't sponsor fungible collection, this tx will be rejected
+	// as invalid
+	if matches!(collection.mode, CollectionMode::Fungible(_)) {
+		return None;
+	}
+	if data.len() > 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) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
+
+	<VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);
+
+	Some(())
+}
+
+pub fn withdraw_approve<T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig>(
+	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: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,
+	C: IsSubType<UniqueCall<T>>,
+{
+	fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
+		match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {
+			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)
+			}
+			UniqueCall::set_variable_meta_data {
+				collection_id,
+				item_id,
+				data,
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_set_variable_meta_data::<T>(
+					&T::CrossAccountId::from_sub(who.clone()),
+					&collection,
+					item_id,
+					data,
+				)
+				.map(|()| sponsor)
+			}
+			_ => None,
+		}
+	}
+}
+
+use crate::SponsorshipPredict;
+pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);
+
+impl<T> SponsorshipPredict<T> for UniqueSponsorshipPredict<T>
+where
+	T: Config,
+{
+	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(_) => true,
+			CollectionMode::ReFungible => {
+				<pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))
+			}
+		};
+
+		if token_exists {
+			Some(0)
+		} else {
+			None
+		}
+	}
+}
addedruntime/common/src/weights.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/src/weights.rs
@@ -0,0 +1,76 @@
+// 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};
+
+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, common::CommonWeights as RefungibleWeights};
+use up_data_structs::CreateItemExData;
+
+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(amount: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(create_multiple_items(amount))
+	}
+
+	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 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 set_variable_metadata(bytes: u32) -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))
+	}
+
+	fn burn_from() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(burn_from())
+	}
+}
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -120,6 +120,9 @@
 	types::*,
 	constants::*,
 	dispatch::{CollectionDispatchT, CollectionDispatch},
+	sponsoring::UniqueSponsorshipHandler,
+	eth_sponsoring::UniqueEthSponsorshipHandler,
+	weights::CommonWeights,
 };
 
 pub const RUNTIME_NAME: &str = "opal";
@@ -902,6 +905,7 @@
 impl pallet_unique::Config for Runtime {
 	type Event = Event;
 	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
+	type CommonWeightInfo = CommonWeights<Self>;
 }
 
 parameter_types! {
@@ -923,11 +927,11 @@
 // }
 
 type EvmSponsorshipHandler = (
-	pallet_unique::UniqueEthSponsorshipHandler<Runtime>,
+	UniqueEthSponsorshipHandler<Runtime>,
 	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,
 );
 type SponsorshipHandler = (
-	pallet_unique::UniqueSponsorshipHandler<Runtime>,
+	UniqueSponsorshipHandler<Runtime>,
 	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
 	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,
 );
addedruntime/tests/Cargo.tomldiffbeforeafterboth
--- /dev/null
+++ b/runtime/tests/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "tests"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+unique-runtime-common = { path = '../common' }
+up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
+
+sp-core = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+sp-std = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+sp-io = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+sp-runtime = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.18-2" }
+
+frame-support = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+frame-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+
+pallet-balances = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+pallet-transaction-payment = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+pallet-timestamp = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.18' }
+
+pallet-evm = { default-features = false, git = 'https://github.com/uniquenetwork/frontier.git', branch = 'unique-polkadot-v0.9.18-2' }
+pallet-ethereum = { default-features = false, git = 'https://github.com/uniquenetwork/frontier.git', branch = 'unique-polkadot-v0.9.18-2' }
+
+pallet-common = { path = '../../pallets/common' }
+pallet-structure = { path = '../../pallets/structure' }
+pallet-fungible = { path = '../../pallets/fungible' }
+pallet-nonfungible = { path = '../../pallets/nonfungible' }
+pallet-refungible = { path = '../../pallets/refungible' }
+pallet-unique = { path = '../../pallets/unique' }
+
+pallet-evm-coder-substrate = { path = '../../pallets/evm-coder-substrate' }
+
+parity-scale-codec = "*"
+scale-info = "*"
addedruntime/tests/src/lib.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/tests/src/lib.rs
@@ -0,0 +1,238 @@
+// 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/>.
+
+#![allow(clippy::from_over_into)]
+
+use sp_core::{H160, H256};
+use frame_support::{
+	parameter_types,
+	traits::{Everything, ConstU32},
+	weights::IdentityFee,
+};
+use sp_runtime::{
+	traits::{BlakeTwo256, IdentityLookup},
+	testing::Header,
+};
+use pallet_transaction_payment::{CurrencyAdapter};
+use frame_system as system;
+use pallet_evm::{AddressMapping, runner::stack::MaybeMirroredLog, account::CrossAccountId};
+use fp_evm_mapping::EvmBackwardsAddressMapping;
+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};
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
+type Block = frame_system::mocking::MockBlock<Test>;
+
+#[cfg(test)]
+mod tests;
+
+// Configure a mock runtime to test the pallet.
+frame_support::construct_runtime!(
+	pub enum Test where
+		Block = Block,
+		NodeBlock = Block,
+		UncheckedExtrinsic = UncheckedExtrinsic,
+	{
+		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+		Unique: pallet_unique::{Pallet, Call, Storage},
+		Balances: pallet_balances::{Pallet, Call, Storage},
+		Common: pallet_common::{Pallet, Storage, Event<T>},
+		Fungible: pallet_fungible::{Pallet, Storage},
+		Refungible: pallet_refungible::{Pallet, Storage},
+		Nonfungible: pallet_nonfungible::{Pallet, Storage},
+	}
+);
+
+parameter_types! {
+	pub const BlockHashCount: u64 = 250;
+	pub const SS58Prefix: u8 = 42;
+}
+
+impl system::Config for Test {
+	type BaseCallFilter = Everything;
+	type BlockWeights = ();
+	type BlockLength = ();
+	type DbWeight = ();
+	type Origin = Origin;
+	type Call = Call;
+	type Index = u64;
+	type BlockNumber = u64;
+	type Hash = H256;
+	type Hashing = BlakeTwo256;
+	type AccountId = u64;
+	type Lookup = IdentityLookup<Self::AccountId>;
+	type Header = Header;
+	type Event = ();
+	type BlockHashCount = BlockHashCount;
+	type Version = ();
+	type PalletInfo = PalletInfo;
+	type AccountData = pallet_balances::AccountData<u64>;
+	type OnNewAccount = ();
+	type OnKilledAccount = ();
+	type SystemWeightInfo = ();
+	type SS58Prefix = SS58Prefix;
+	type OnSetCode = ();
+	type MaxConsumers = ConstU32<16>;
+}
+
+parameter_types! {
+	pub const ExistentialDeposit: u64 = 1;
+	pub const MaxLocks: u32 = 50;
+}
+//frame_system::Module<Test>;
+impl pallet_balances::Config for Test {
+	type AccountStore = System;
+	type Balance = u64;
+	type DustRemoval = ();
+	type Event = ();
+	type ExistentialDeposit = ExistentialDeposit;
+	type WeightInfo = ();
+	type MaxLocks = MaxLocks;
+	type MaxReserves = ();
+	type ReserveIdentifier = [u8; 8];
+}
+
+parameter_types! {
+	pub const OperationalFeeMultiplier: u8 = 5;
+}
+
+impl pallet_transaction_payment::Config for Test {
+	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Pallet<Test>, ()>;
+	type LengthToFee = IdentityFee<u64>;
+	type WeightToFee = IdentityFee<u64>;
+	type FeeMultiplierUpdate = ();
+	type OperationalFeeMultiplier = OperationalFeeMultiplier;
+}
+
+parameter_types! {
+	pub const MinimumPeriod: u64 = 1;
+}
+impl pallet_timestamp::Config for Test {
+	type Moment = u64;
+	type OnTimestampSet = ();
+	type MinimumPeriod = MinimumPeriod;
+	type WeightInfo = ();
+}
+
+parameter_types! {
+	pub const CollectionCreationPrice: u32 = 100;
+	pub TreasuryAccountId: u64 = 1234;
+	pub EthereumChainId: u32 = 1111;
+}
+
+pub struct TestEvmAddressMapping;
+impl AddressMapping<u64> for TestEvmAddressMapping {
+	fn into_account_id(_addr: sp_core::H160) -> u64 {
+		unimplemented!()
+	}
+}
+
+pub struct TestEvmBackwardsAddressMapping;
+impl EvmBackwardsAddressMapping<u64> for TestEvmBackwardsAddressMapping {
+	fn from_account_id(_account_id: u64) -> sp_core::H160 {
+		unimplemented!()
+	}
+}
+
+#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]
+pub struct TestCrossAccountId(u64, sp_core::H160);
+impl CrossAccountId<u64> for TestCrossAccountId {
+	fn as_sub(&self) -> &u64 {
+		&self.0
+	}
+	fn as_eth(&self) -> &sp_core::H160 {
+		&self.1
+	}
+	fn from_sub(sub: u64) -> Self {
+		let mut eth = [0; 20];
+		eth[12..20].copy_from_slice(&sub.to_be_bytes());
+		Self(sub, sp_core::H160(eth))
+	}
+	fn from_eth(eth: sp_core::H160) -> Self {
+		let mut sub_raw = [0; 8];
+		sub_raw.copy_from_slice(&eth.0[0..8]);
+		let sub = u64::from_be_bytes(sub_raw);
+		Self(sub, eth)
+	}
+	fn conv_eq(&self, other: &Self) -> bool {
+		self.as_sub() == other.as_sub()
+	}
+}
+
+impl Default for TestCrossAccountId {
+	fn default() -> Self {
+		Self::from_sub(0)
+	}
+}
+
+pub struct TestEtheremTransactionSender;
+impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {
+	fn submit_logs_transaction(_source: H160, _logs: Vec<MaybeMirroredLog>) {}
+}
+
+impl pallet_evm_coder_substrate::Config for Test {
+	type EthereumTransactionSender = TestEtheremTransactionSender;
+	type GasWeightMapping = ();
+}
+
+impl pallet_common::Config for Test {
+	type Event = ();
+	type Currency = Balances;
+	type CollectionCreationPrice = CollectionCreationPrice;
+	type TreasuryAccountId = TreasuryAccountId;
+
+	type CollectionDispatch = CollectionDispatchT<Self>;
+	type EvmTokenAddressMapping = EvmTokenAddressMapping;
+	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+}
+
+impl pallet_evm::account::Config for Test {
+	type CrossAccountId = TestCrossAccountId;
+	type EvmAddressMapping = TestEvmAddressMapping;
+	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
+}
+
+impl pallet_structure::Config for Test {
+	type WeightInfo = ();
+	type Event = ();
+	type Call = Call;
+}
+impl pallet_fungible::Config for Test {
+	type WeightInfo = ();
+}
+impl pallet_refungible::Config for Test {
+	type WeightInfo = ();
+}
+impl pallet_nonfungible::Config for Test {
+	type WeightInfo = ();
+}
+
+impl pallet_unique::Config for Test {
+	type Event = ();
+	type WeightInfo = ();
+	type CommonWeightInfo = CommonWeights<Self>;
+}
+
+// Build genesis storage according to the mock runtime.
+pub fn new_test_ext() -> sp_io::TestExternalities {
+	system::GenesisConfig::default()
+		.build_storage::<Test>()
+		.unwrap()
+		.into()
+}
addedruntime/tests/src/tests.rsdiffbeforeafterboth
--- /dev/null
+++ b/runtime/tests/src/tests.rs
@@ -0,0 +1,2889 @@
+// 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/>.
+
+// Tests to be written here
+use crate::{Test, TestCrossAccountId, CollectionCreationPrice, Origin, Unique, new_test_ext};
+use up_data_structs::{
+	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
+	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,
+	TokenId, MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionField, SchemaVersion,
+	CollectionMode, AccessMode,
+};
+use frame_support::{assert_noop, assert_ok, assert_err};
+use sp_std::convert::TryInto;
+use pallet_evm::account::CrossAccountId;
+use pallet_common::Error as CommonError;
+use pallet_unique::Error as UniqueError;
+
+fn add_balance(user: u64, value: u64) {
+	const DONOR_USER: u64 = 999;
+	assert_ok!(<pallet_balances::Pallet<Test>>::set_balance(
+		Origin::root(),
+		DONOR_USER,
+		value,
+		0
+	));
+	assert_ok!(<pallet_balances::Pallet<Test>>::force_transfer(
+		Origin::root(),
+		DONOR_USER,
+		user,
+		value
+	));
+}
+
+fn default_nft_data() -> CreateNftData {
+	CreateNftData {
+		const_data: vec![1, 2, 3].try_into().unwrap(),
+		variable_data: vec![3, 2, 1].try_into().unwrap(),
+	}
+}
+
+fn default_fungible_data() -> CreateFungibleData {
+	CreateFungibleData { value: 5 }
+}
+
+fn default_re_fungible_data() -> CreateReFungibleData {
+	CreateReFungibleData {
+		const_data: vec![1, 2, 3].try_into().unwrap(),
+		variable_data: vec![3, 2, 1].try_into().unwrap(),
+		pieces: 1023,
+	}
+}
+
+fn create_test_collection_for_owner(
+	mode: &CollectionMode,
+	owner: u64,
+	id: CollectionId,
+) -> CollectionId {
+	add_balance(owner, CollectionCreationPrice::get() as u64 + 1);
+
+	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+
+	let data: CreateCollectionData<u64> = CreateCollectionData {
+		name: col_name1.try_into().unwrap(),
+		description: col_desc1.try_into().unwrap(),
+		token_prefix: token_prefix1.try_into().unwrap(),
+		mode: mode.clone(),
+		..Default::default()
+	};
+
+	let origin1 = Origin::signed(owner);
+	assert_ok!(Unique::create_collection_ex(origin1, data));
+
+	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
+	assert_eq!(
+		<pallet_common::CollectionById<Test>>::get(id)
+			.unwrap()
+			.owner,
+		owner
+	);
+	assert_eq!(
+		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,
+		saved_col_name
+	);
+	assert_eq!(
+		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,
+		*mode
+	);
+	assert_eq!(
+		<pallet_common::CollectionById<Test>>::get(id)
+			.unwrap()
+			.description,
+		saved_description
+	);
+	assert_eq!(
+		<pallet_common::CollectionById<Test>>::get(id)
+			.unwrap()
+			.token_prefix,
+		saved_prefix
+	);
+	id
+}
+
+fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {
+	create_test_collection_for_owner(&mode, 1, id)
+}
+
+fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {
+	let origin1 = Origin::signed(1);
+	assert_ok!(Unique::create_item(
+		origin1,
+		collection_id,
+		account(1),
+		data.clone()
+	));
+}
+
+fn account(sub: u64) -> TestCrossAccountId {
+	TestCrossAccountId::from_sub(sub)
+}
+
+// Use cases tests region
+// #region
+
+#[test]
+fn set_version_schema() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		assert_ok!(Unique::set_schema_version(
+			origin1,
+			collection_id,
+			SchemaVersion::Unique
+		));
+		assert_eq!(
+			<pallet_common::CollectionById<Test>>::get(collection_id)
+				.unwrap()
+				.schema_version,
+			SchemaVersion::Unique
+		);
+	});
+}
+
+#[test]
+fn check_not_sufficient_founds() {
+	new_test_ext().execute_with(|| {
+		let acc: u64 = 1;
+		<pallet_balances::Pallet<Test>>::set_balance(Origin::root(), acc, 0, 0).unwrap();
+
+		let name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+		let description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+		let token_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
+
+		let data: CreateCollectionData<<Test as frame_system::Config>::AccountId> =
+			CreateCollectionData {
+				name: name.try_into().unwrap(),
+				description: description.try_into().unwrap(),
+				token_prefix: token_prefix.try_into().unwrap(),
+				mode: CollectionMode::NFT,
+				..Default::default()
+			};
+
+		let result = Unique::create_collection_ex(Origin::signed(acc), data);
+		assert_err!(result, <CommonError<Test>>::NotSufficientFounds);
+	});
+}
+
+#[test]
+fn create_fungible_collection_fails_with_large_decimal_numbers() {
+	new_test_ext().execute_with(|| {
+		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+
+		let data: CreateCollectionData<u64> = CreateCollectionData {
+			name: col_name1.try_into().unwrap(),
+			description: col_desc1.try_into().unwrap(),
+			token_prefix: token_prefix1.try_into().unwrap(),
+			mode: CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1),
+			..Default::default()
+		};
+
+		let origin1 = Origin::signed(1);
+		assert_noop!(
+			Unique::create_collection_ex(origin1, data),
+			UniqueError::<Test>::CollectionDecimalPointLimitExceeded
+		);
+	});
+}
+
+#[test]
+fn create_nft_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.clone().into());
+
+		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();
+		assert_eq!(item.const_data, data.const_data.into_inner());
+		assert_eq!(item.variable_data, data.variable_data.into_inner());
+	});
+}
+
+// Use cases tests region
+// #region
+#[test]
+fn create_nft_multiple_items() {
+	new_test_ext().execute_with(|| {
+		create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];
+
+		assert_ok!(Unique::create_multiple_items(
+			origin1,
+			CollectionId(1),
+			account(1),
+			items_data
+				.clone()
+				.into_iter()
+				.map(|d| { d.into() })
+				.collect()
+		));
+		for (index, data) in items_data.into_iter().enumerate() {
+			let item = <pallet_nonfungible::TokenData<Test>>::get((
+				CollectionId(1),
+				TokenId((index + 1) as u32),
+			))
+			.unwrap();
+			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
+			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
+		}
+	});
+}
+
+#[test]
+fn create_refungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+
+		let data = default_re_fungible_data();
+		create_test_item(collection_id, &data.clone().into());
+		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
+		let balance =
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));
+		assert_eq!(item.const_data, data.const_data.into_inner());
+		assert_eq!(item.variable_data, data.variable_data.into_inner());
+		assert_eq!(balance, 1023);
+	});
+}
+
+#[test]
+fn create_multiple_refungible_items() {
+	new_test_ext().execute_with(|| {
+		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let items_data = vec![
+			default_re_fungible_data(),
+			default_re_fungible_data(),
+			default_re_fungible_data(),
+		];
+
+		assert_ok!(Unique::create_multiple_items(
+			origin1,
+			CollectionId(1),
+			account(1),
+			items_data
+				.clone()
+				.into_iter()
+				.map(|d| { d.into() })
+				.collect()
+		));
+		for (index, data) in items_data.into_iter().enumerate() {
+			let item = <pallet_refungible::TokenData<Test>>::get((
+				CollectionId(1),
+				TokenId((index + 1) as u32),
+			));
+			let balance =
+				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));
+			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
+			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
+			assert_eq!(balance, 1023);
+		}
+	});
+}
+
+#[test]
+fn create_fungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
+			5
+		);
+	});
+}
+
+//#[test]
+// fn create_multiple_fungible_items() {
+//     new_test_ext().execute_with(|| {
+//         default_limits();
+
+//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+//         let origin1 = Origin::signed(1);
+
+//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];
+
+//         assert_ok!(Unique::create_multiple_items(
+//             origin1.clone(),
+//             1,
+//             1,
+//             items_data.clone().into_iter().map(|d| { d.into() }).collect()
+//         ));
+
+//         for (index, _) in items_data.iter().enumerate() {
+//             assert_eq!(Unique::fungible_item_id(1, (index + 1) as TokenId).value, 5);
+//         }
+//         assert_eq!(Unique::balance_count(1, 1), 3000);
+//         assert_eq!(Unique::address_tokens(1, 1), [1, 2, 3]);
+//     });
+// }
+
+#[test]
+fn transfer_fungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),
+			5
+		);
+
+		// change owner scenario
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(0),
+			5
+		));
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),
+			0
+		);
+
+		// split item scenario
+		assert_ok!(Unique::transfer(
+			origin2.clone(),
+			account(3),
+			CollectionId(1),
+			TokenId(0),
+			3
+		));
+
+		// split item and new owner has account scenario
+		assert_ok!(Unique::transfer(
+			origin2,
+			account(3),
+			CollectionId(1),
+			TokenId(0),
+			1
+		));
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),
+			1
+		);
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),
+			4
+		);
+	});
+}
+
+#[test]
+fn transfer_refungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+
+		// Create RFT 1 in 1023 pieces for account 1
+		let data = default_re_fungible_data();
+		create_test_item(collection_id, &data.clone().into());
+		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
+		assert_eq!(item.const_data, data.const_data.into_inner());
+		assert_eq!(item.variable_data, data.variable_data.into_inner());
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
+			1023
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		// Account 1 transfers all 1023 pieces of RFT 1 to account 2
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1023
+		));
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
+			1023
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			false
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			true
+		);
+
+		// Account 2 transfers 500 pieces of RFT 1 to account 3
+		assert_ok!(Unique::transfer(
+			origin2.clone(),
+			account(3),
+			CollectionId(1),
+			TokenId(1),
+			500
+		));
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
+			523
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
+			500
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),
+			true
+		);
+
+		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance
+		assert_ok!(Unique::transfer(
+			origin2,
+			account(3),
+			CollectionId(1),
+			TokenId(1),
+			200
+		));
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),
+			323
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
+			700
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),
+			true
+		);
+	});
+}
+
+#[test]
+fn transfer_nft_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		let origin1 = Origin::signed(1);
+		// default scenario
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			false
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			true
+		);
+	});
+}
+
+#[test]
+fn transfer_nft_item_wrong_value() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		let origin1 = Origin::signed(1);
+
+		assert_noop!(
+			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)
+				.map_err(|e| e.error),
+			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount
+		);
+	});
+}
+
+#[test]
+fn transfer_nft_item_zero_value() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		let origin1 = Origin::signed(1);
+
+		// Transferring 0 amount works on NFT...
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			0
+		));
+		// ... and results in no transfer
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+	});
+}
+
+#[test]
+fn nft_approve_and_transfer_from() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		// neg transfer_from
+		assert_noop!(
+			Unique::transfer_from(
+				origin2.clone(),
+				account(1),
+				account(2),
+				CollectionId(1),
+				TokenId(1),
+				1
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::ApprovedValueTooLow
+		);
+
+		// do approve
+		assert_ok!(Unique::approve(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(2)
+		);
+
+		assert_ok!(Unique::transfer_from(
+			origin2,
+			account(1),
+			account(3),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()
+		);
+	});
+}
+
+#[test]
+fn nft_approve_and_transfer_from_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		// Create NFT 1 for account 1
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.clone().into());
+		assert_eq!(
+			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
+				.unwrap()
+				.const_data,
+			&data.const_data.into_inner()
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			CollectionId(1),
+			true
+		));
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			CollectionId(1),
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(3)
+		));
+
+		// Account 1 approves account 2 for NFT 1
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(2)
+		);
+
+		// Account 2 transfers NFT 1 from account 1 to account 3
+		assert_ok!(Unique::transfer_from(
+			origin2,
+			account(1),
+			account(3),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()
+		);
+	});
+}
+
+#[test]
+fn refungible_approve_and_transfer_from() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		// Create RFT 1 in 1023 pieces for account 1
+		let data = default_re_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
+			1023
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			CollectionId(1),
+			true
+		));
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			CollectionId(1),
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(3)
+		));
+
+		// Account 1 approves account 2 for 1023 pieces of RFT 1
+		assert_ok!(Unique::approve(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1023
+		));
+		assert_eq!(
+			<pallet_refungible::Allowance<Test>>::get((
+				CollectionId(1),
+				TokenId(1),
+				account(1),
+				account(2)
+			)),
+			1023
+		);
+
+		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3
+		assert_ok!(Unique::transfer_from(
+			origin2,
+			account(1),
+			account(3),
+			CollectionId(1),
+			TokenId(1),
+			100
+		));
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
+			923
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),
+			100
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_refungible::Allowance<Test>>::get((
+				CollectionId(1),
+				TokenId(1),
+				account(1),
+				account(2)
+			)),
+			923
+		);
+	});
+}
+
+#[test]
+fn fungible_approve_and_transfer_from() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			CollectionId(1),
+			true
+		));
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			CollectionId(1),
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(3)
+		));
+
+		// do approve
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(2),
+			CollectionId(1),
+			TokenId(0),
+			5
+		));
+		assert_eq!(
+			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
+			5
+		);
+		assert_ok!(Unique::approve(
+			origin1,
+			account(3),
+			CollectionId(1),
+			TokenId(0),
+			5
+		));
+		assert_eq!(
+			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
+			5
+		);
+		assert_eq!(
+			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),
+			5
+		);
+
+		assert_ok!(Unique::transfer_from(
+			origin2.clone(),
+			account(1),
+			account(3),
+			CollectionId(1),
+			TokenId(0),
+			4
+		));
+
+		assert_eq!(
+			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),
+			1
+		);
+
+		assert_noop!(
+			Unique::transfer_from(
+				origin2,
+				account(1),
+				account(3),
+				CollectionId(1),
+				TokenId(0),
+				4
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::ApprovedValueTooLow
+		);
+	});
+}
+
+#[test]
+fn change_collection_owner() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::change_collection_owner(origin1, collection_id, 2));
+		assert_eq!(
+			<pallet_common::CollectionById<Test>>::get(collection_id)
+				.unwrap()
+				.owner,
+			2
+		);
+	});
+}
+
+#[test]
+fn destroy_collection() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::destroy_collection(origin1, collection_id));
+	});
+}
+
+#[test]
+fn burn_nft_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+
+		// burn item
+		assert_ok!(Unique::burn_item(
+			origin1.clone(),
+			collection_id,
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			0
+		);
+	});
+}
+
+#[test]
+fn burn_same_nft_item_twice() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+
+		// burn item
+		assert_ok!(Unique::burn_item(
+			origin1.clone(),
+			collection_id,
+			TokenId(1),
+			1
+		));
+
+		// burn item again
+		assert_noop!(
+			Unique::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),
+			CommonError::<Test>::TokenNotFound
+		);
+
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			0
+		);
+	});
+}
+
+#[test]
+fn burn_fungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
+			5
+		);
+
+		// burn item
+		assert_ok!(Unique::burn_item(
+			origin1.clone(),
+			CollectionId(1),
+			TokenId(0),
+			5
+		));
+		assert_noop!(
+			Unique::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueTooLow
+		);
+
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
+			0
+		);
+	});
+}
+
+#[test]
+fn burn_fungible_item_with_token_id() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),
+			5
+		);
+
+		// Try to burn item using Token ID
+		assert_noop!(
+			Unique::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),
+			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId
+		);
+	});
+}
+#[test]
+fn burn_refungible_item() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			true
+		));
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		let data = default_re_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 2)
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
+			1023
+		);
+
+		// burn item
+		assert_ok!(Unique::burn_item(
+			origin1.clone(),
+			collection_id,
+			TokenId(1),
+			1023
+		));
+		assert_noop!(
+			Unique::burn_item(origin1, collection_id, TokenId(1), 1023).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueTooLow
+		);
+
+		assert_eq!(
+			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),
+			0
+		);
+	});
+}
+
+#[test]
+fn add_collection_admin() {
+	new_test_ext().execute_with(|| {
+		let collection1_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		// Add collection admins
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection1_id,
+			account(2)
+		));
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection1_id,
+			account(3)
+		));
+
+		// Owner is not an admin by default
+		assert_eq!(
+			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),
+			false
+		);
+		assert!(<pallet_common::IsAdmin<Test>>::get((
+			CollectionId(1),
+			account(2)
+		)));
+		assert!(<pallet_common::IsAdmin<Test>>::get((
+			CollectionId(1),
+			account(3)
+		)));
+	});
+}
+
+#[test]
+fn remove_collection_admin() {
+	new_test_ext().execute_with(|| {
+		let collection1_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		// Add collection admins 2 and 3
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection1_id,
+			account(2)
+		));
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection1_id,
+			account(3)
+		));
+
+		assert!(<pallet_common::IsAdmin<Test>>::get((
+			CollectionId(1),
+			account(2)
+		)));
+		assert!(<pallet_common::IsAdmin<Test>>::get((
+			CollectionId(1),
+			account(3)
+		)));
+
+		// remove admin 3
+		assert_ok!(Unique::remove_collection_admin(
+			origin2,
+			CollectionId(1),
+			account(3)
+		));
+
+		// 2 is still admin, 3 is not an admin anymore
+		assert!(<pallet_common::IsAdmin<Test>>::get((
+			CollectionId(1),
+			account(2)
+		)));
+		assert_eq!(
+			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),
+			false
+		);
+	});
+}
+
+#[test]
+fn balance_of() {
+	new_test_ext().execute_with(|| {
+		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let fungible_collection_id =
+			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));
+		let re_fungible_collection_id =
+			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));
+
+		// check balance before
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),
+			0
+		);
+
+		let nft_data = default_nft_data();
+		create_test_item(nft_collection_id, &nft_data.into());
+
+		let fungible_data = default_fungible_data();
+		create_test_item(fungible_collection_id, &fungible_data.into());
+
+		let re_fungible_data = default_re_fungible_data();
+		create_test_item(re_fungible_collection_id, &re_fungible_data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),
+			5
+		);
+		assert_eq!(
+			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),
+			1
+		);
+
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_refungible::Owned<Test>>::get((
+				re_fungible_collection_id,
+				account(1),
+				TokenId(1)
+			)),
+			true
+		);
+	});
+}
+
+#[test]
+fn approve() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		let origin1 = Origin::signed(1);
+
+		// approve
+		assert_ok!(Unique::approve(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(2)
+		);
+	});
+}
+
+#[test]
+fn transfer_from() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		// approve
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(2)
+		);
+
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			CollectionId(1),
+			true
+		));
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			CollectionId(1),
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			CollectionId(1),
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			CollectionId(1),
+			account(3)
+		));
+
+		assert_ok!(Unique::transfer_from(
+			origin2,
+			account(1),
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+
+		// after transfer
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),
+			1
+		);
+	});
+}
+
+// #endregion
+
+// Coverage tests region
+// #region
+
+#[test]
+fn owner_can_add_address_to_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert!(<pallet_common::Allowlist<Test>>::get((
+			collection_id,
+			account(2)
+		)));
+	});
+}
+
+#[test]
+fn admin_can_add_address_to_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin2,
+			collection_id,
+			account(3)
+		));
+		assert!(<pallet_common::Allowlist<Test>>::get((
+			collection_id,
+			account(3)
+		)));
+	});
+}
+
+#[test]
+fn nonprivileged_user_cannot_add_address_to_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin2 = Origin::signed(2);
+		assert_noop!(
+			Unique::add_to_allow_list(origin2, collection_id, account(3)),
+			CommonError::<Test>::NoPermission
+		);
+	});
+}
+
+#[test]
+fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+
+		assert_noop!(
+			Unique::add_to_allow_list(origin1, CollectionId(1), account(2)),
+			CommonError::<Test>::CollectionNotFound
+		);
+	});
+}
+
+#[test]
+fn nobody_can_add_address_to_allow_list_of_deleted_collection() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::destroy_collection(origin1.clone(), collection_id));
+		assert_noop!(
+			Unique::add_to_allow_list(origin1, collection_id, account(2)),
+			CommonError::<Test>::CollectionNotFound
+		);
+	});
+}
+
+// If address is already added to allow list, nothing happens
+#[test]
+fn address_is_already_added_to_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert!(<pallet_common::Allowlist<Test>>::get((
+			collection_id,
+			account(2)
+		)));
+	});
+}
+
+#[test]
+fn owner_can_remove_address_from_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+		assert_ok!(Unique::remove_from_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert_eq!(
+			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
+			false
+		);
+	});
+}
+
+#[test]
+fn admin_can_remove_address_from_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		// Owner adds admin
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		// Owner adds address 3 to allow list
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(3)
+		));
+
+		// Admin removes address 3 from allow list
+		assert_ok!(Unique::remove_from_allow_list(
+			origin2,
+			collection_id,
+			account(3)
+		));
+		assert_eq!(
+			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),
+			false
+		);
+	});
+}
+
+#[test]
+fn nonprivileged_user_cannot_remove_address_from_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert_noop!(
+			Unique::remove_from_allow_list(origin2, collection_id, account(2)),
+			CommonError::<Test>::NoPermission
+		);
+		assert!(<pallet_common::Allowlist<Test>>::get((
+			collection_id,
+			account(2)
+		)));
+	});
+}
+
+#[test]
+fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+
+		assert_noop!(
+			Unique::remove_from_allow_list(origin1, CollectionId(1), account(2)),
+			CommonError::<Test>::CollectionNotFound
+		);
+	});
+}
+
+#[test]
+fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		// Add account 2 to allow list
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		// Account 2 is in collection allow-list
+		assert!(<pallet_common::Allowlist<Test>>::get((
+			collection_id,
+			account(2)
+		)));
+
+		// Destroy collection
+		assert_ok!(Unique::destroy_collection(origin1, collection_id));
+
+		// Attempt to remove account 2 from collection allow-list => error
+		assert_noop!(
+			Unique::remove_from_allow_list(origin2, collection_id, account(2)),
+			CommonError::<Test>::CollectionNotFound
+		);
+
+		// Account 2 is not found in collection allow-list anyway
+		assert_eq!(
+			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
+			false
+		);
+	});
+}
+
+// If address is already removed from allow list, nothing happens
+#[test]
+fn address_is_already_removed_from_allow_list() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+		assert_ok!(Unique::remove_from_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+		assert_eq!(
+			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
+			false
+		);
+		assert_ok!(Unique::remove_from_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+		assert_eq!(
+			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),
+			false
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)
+#[test]
+fn allow_list_test_1() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		assert_noop!(
+			Unique::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)
+				.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+#[test]
+fn allow_list_test_2() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		// do approve
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(1),
+			collection_id,
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(1)
+		);
+
+		assert_ok!(Unique::remove_from_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+
+		assert_noop!(
+			Unique::transfer_from(
+				origin1,
+				account(1),
+				account(3),
+				CollectionId(1),
+				TokenId(1),
+				1
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)
+#[test]
+fn allow_list_test_3() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+
+		assert_noop!(
+			Unique::transfer(origin1, account(3), collection_id, TokenId(1), 1)
+				.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+#[test]
+fn allow_list_test_4() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		// do approve
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(1),
+			collection_id,
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(1)
+		);
+
+		assert_ok!(Unique::remove_from_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		assert_noop!(
+			Unique::transfer_from(
+				origin1,
+				account(1),
+				account(3),
+				collection_id,
+				TokenId(1),
+				1
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)
+#[test]
+fn allow_list_test_5() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_noop!(
+			Unique::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).
+#[test]
+fn allow_list_test_6() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+
+		// do approve
+		assert_noop!(
+			Unique::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)
+				.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and
+//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)
+#[test]
+fn allow_list_test_7() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+	});
+}
+
+#[test]
+fn allow_list_test_8() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		// Create NFT for account 1
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		let origin1 = Origin::signed(1);
+
+		// Toggle Allow List mode and add accounts 1 and 2
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(1)
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		// Sself-approve account 1 for NFT 1
+		assert_ok!(Unique::approve(
+			origin1.clone(),
+			account(1),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),
+			account(1)
+		);
+
+		// Transfer from 1 to 2
+		assert_ok!(Unique::transfer_from(
+			origin1,
+			account(1),
+			account(2),
+			CollectionId(1),
+			TokenId(1),
+			1
+		));
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.
+#[test]
+fn allow_list_test_9() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.
+#[test]
+fn allow_list_test_10() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			false
+		));
+
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection_id,
+			account(2)
+		));
+
+		assert_ok!(Unique::create_item(
+			origin2,
+			collection_id,
+			account(2),
+			default_nft_data().into()
+		));
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.
+#[test]
+fn allow_list_test_11() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			false
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+
+		assert_noop!(
+			Unique::create_item(
+				origin2,
+				CollectionId(1),
+				account(2),
+				default_nft_data().into()
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::PublicMintingNotAllowed
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.
+#[test]
+fn allow_list_test_12() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));
+
+		assert_noop!(
+			Unique::create_item(
+				origin2,
+				CollectionId(1),
+				account(2),
+				default_nft_data().into()
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::PublicMintingNotAllowed
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.
+#[test]
+fn allow_list_test_13() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.
+#[test]
+fn allow_list_test_14() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			true
+		));
+
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection_id,
+			account(2)
+		));
+
+		assert_ok!(Unique::create_item(
+			origin2,
+			collection_id,
+			account(2),
+			default_nft_data().into()
+		));
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.
+#[test]
+fn allow_list_test_15() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));
+
+		assert_noop!(
+			Unique::create_item(
+				origin2,
+				collection_id,
+				account(2),
+				default_nft_data().into()
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::AddressNotInAllowlist
+		);
+	});
+}
+
+// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.
+#[test]
+fn allow_list_test_16() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			true
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1,
+			collection_id,
+			account(2)
+		));
+
+		assert_ok!(Unique::create_item(
+			origin2,
+			collection_id,
+			account(2),
+			default_nft_data().into()
+		));
+	});
+}
+
+// Total number of collections. Positive test
+#[test]
+fn total_number_collections_bound() {
+	new_test_ext().execute_with(|| {
+		create_test_collection(&CollectionMode::NFT, CollectionId(1));
+	});
+}
+
+#[test]
+fn create_max_collections() {
+	new_test_ext().execute_with(|| {
+		for i in 1..COLLECTION_NUMBER_LIMIT {
+			create_test_collection(&CollectionMode::NFT, CollectionId(i));
+		}
+	});
+}
+
+// Total number of collections. Negative test
+#[test]
+fn total_number_collections_bound_neg() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+
+		for i in 1..=COLLECTION_NUMBER_LIMIT {
+			create_test_collection(&CollectionMode::NFT, CollectionId(i));
+		}
+
+		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+
+		let data: CreateCollectionData<u64> = CreateCollectionData {
+			name: col_name1.try_into().unwrap(),
+			description: col_desc1.try_into().unwrap(),
+			token_prefix: token_prefix1.try_into().unwrap(),
+			mode: CollectionMode::NFT,
+			..Default::default()
+		};
+
+		// 11-th collection in chain. Expects error
+		assert_noop!(
+			Unique::create_collection_ex(origin1, data),
+			CommonError::<Test>::TotalCollectionsLimitExceeded
+		);
+	});
+}
+
+// Owned tokens by a single address. Positive test
+#[test]
+fn owned_tokens_bound() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.clone().into());
+		create_test_item(collection_id, &data.into());
+	});
+}
+
+// Owned tokens by a single address. Negotive test
+#[test]
+fn owned_tokens_bound_neg() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		for _ in 1..=MAX_TOKEN_OWNERSHIP {
+			let data = default_nft_data();
+			create_test_item(collection_id, &data.clone().into());
+		}
+
+		let data = default_nft_data();
+		assert_noop!(
+			Unique::create_item(origin1, CollectionId(1), account(1), data.into())
+				.map_err(|e| e.error),
+			CommonError::<Test>::AccountTokenLimitExceeded
+		);
+	});
+}
+
+// Number of collection admins. Positive test
+#[test]
+fn collection_admins_bound() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		assert_ok!(Unique::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+		assert_ok!(Unique::add_collection_admin(
+			origin1,
+			collection_id,
+			account(3)
+		));
+	});
+}
+
+// Number of collection admins. Negotive test
+#[test]
+fn collection_admins_bound_neg() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		for i in 0..COLLECTION_ADMINS_LIMIT {
+			assert_ok!(Unique::add_collection_admin(
+				origin1.clone(),
+				collection_id,
+				account((2 + i).into())
+			));
+		}
+		assert_noop!(
+			Unique::add_collection_admin(
+				origin1,
+				collection_id,
+				account((3 + COLLECTION_ADMINS_LIMIT).into())
+			),
+			CommonError::<Test>::CollectionAdminCountExceeded
+		);
+	});
+}
+// #endregion
+
+#[test]
+fn set_const_on_chain_schema() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::set_const_on_chain_schema(
+			origin1,
+			collection_id,
+			b"test const on chain schema".to_vec().try_into().unwrap()
+		));
+
+		assert_eq!(
+			<pallet_common::CollectionData<Test>>::get((
+				collection_id,
+				CollectionField::ConstOnChainSchema
+			)),
+			b"test const on chain schema".to_vec()
+		);
+		assert_eq!(
+			<pallet_common::CollectionData<Test>>::get((
+				collection_id,
+				CollectionField::VariableOnChainSchema
+			)),
+			b"".to_vec()
+		);
+	});
+}
+
+#[test]
+fn set_variable_on_chain_schema() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(Unique::set_variable_on_chain_schema(
+			origin1,
+			collection_id,
+			b"test variable on chain schema"
+				.to_vec()
+				.try_into()
+				.unwrap()
+		));
+
+		assert_eq!(
+			<pallet_common::CollectionData<Test>>::get((
+				collection_id,
+				CollectionField::ConstOnChainSchema
+			)),
+			b"".to_vec()
+		);
+		assert_eq!(
+			<pallet_common::CollectionData<Test>>::get((
+				collection_id,
+				CollectionField::VariableOnChainSchema
+			)),
+			b"test variable on chain schema".to_vec()
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(CollectionId(1), &data.into());
+
+		let variable_data = b"test data".to_vec();
+		assert_ok!(Unique::set_variable_meta_data(
+			origin1,
+			collection_id,
+			TokenId(1),
+			variable_data.clone().try_into().unwrap()
+		));
+
+		assert_eq!(
+			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
+				.unwrap()
+				.variable_data,
+			variable_data
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_re_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		let variable_data = b"test data".to_vec();
+		assert_ok!(Unique::set_variable_meta_data(
+			origin1,
+			collection_id,
+			TokenId(1),
+			variable_data.clone().try_into().unwrap()
+		));
+
+		assert_eq!(
+			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,
+			variable_data
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_fungible_token_fails() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		let variable_data = b"test data".to_vec();
+		assert_noop!(
+			Unique::set_variable_meta_data(
+				origin1,
+				collection_id,
+				TokenId(0),
+				variable_data.try_into().unwrap()
+			)
+			.map_err(|e| e.error),
+			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {
+	new_test_ext().execute_with(|| {
+		//default_limits();
+
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_meta_update_permission_flag(
+			origin1.clone(),
+			collection_id,
+			MetaUpdatePermission::ItemOwner,
+		));
+
+		let variable_data = b"ten chars.".to_vec();
+		assert_ok!(Unique::set_variable_meta_data(
+			origin1,
+			collection_id,
+			TokenId(1),
+			variable_data.clone().try_into().unwrap()
+		));
+
+		assert_eq!(
+			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
+				.unwrap()
+				.variable_data,
+			variable_data
+		);
+	});
+}
+
+#[test]
+fn collection_transfer_flag_works() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		assert_ok!(Unique::set_transfers_enabled_flag(
+			origin1,
+			collection_id,
+			true
+		));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		let origin1 = Origin::signed(1);
+
+		// default scenario
+		assert_ok!(Unique::transfer(
+			origin1,
+			account(2),
+			collection_id,
+			TokenId(1),
+			1
+		));
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			false
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			0
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			1
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_nft_with_admin_flag() {
+	new_test_ext().execute_with(|| {
+		// default_limits();
+
+		let collection_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_mint_permission(
+			origin2.clone(),
+			collection_id,
+			true
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin2.clone(),
+			collection_id,
+			account(1)
+		));
+
+		assert_ok!(Unique::add_collection_admin(
+			origin2.clone(),
+			collection_id,
+			account(1)
+		));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_meta_update_permission_flag(
+			origin2.clone(),
+			collection_id,
+			MetaUpdatePermission::Admin,
+		));
+
+		let variable_data = b"test.".to_vec();
+		assert_ok!(Unique::set_variable_meta_data(
+			origin1,
+			collection_id,
+			TokenId(1),
+			variable_data.clone().try_into().unwrap()
+		));
+
+		assert_eq!(
+			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
+				.unwrap()
+				.variable_data,
+			variable_data
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_nft_with_admin_flag_neg() {
+	new_test_ext().execute_with(|| {
+		// default_limits();
+
+		let collection_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_mint_permission(
+			origin2.clone(),
+			collection_id,
+			true
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin2.clone(),
+			collection_id,
+			account(1)
+		));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_meta_update_permission_flag(
+			origin2.clone(),
+			collection_id,
+			MetaUpdatePermission::Admin,
+		));
+
+		let variable_data = b"test.".to_vec();
+		assert_noop!(
+			Unique::set_variable_meta_data(
+				origin1,
+				collection_id,
+				TokenId(1),
+				variable_data.try_into().unwrap()
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::NoPermission
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_flag_after_freeze() {
+	new_test_ext().execute_with(|| {
+		// default_limits();
+
+		let collection_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
+
+		let origin2 = Origin::signed(2);
+
+		assert_ok!(Unique::set_meta_update_permission_flag(
+			origin2.clone(),
+			collection_id,
+			MetaUpdatePermission::None,
+		));
+		assert_noop!(
+			Unique::set_meta_update_permission_flag(
+				origin2.clone(),
+				collection_id,
+				MetaUpdatePermission::Admin
+			),
+			CommonError::<Test>::MetadataFlagFrozen
+		);
+	});
+}
+
+#[test]
+fn set_variable_meta_data_on_nft_with_none_flag_neg() {
+	new_test_ext().execute_with(|| {
+		// default_limits();
+
+		let collection_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
+		let origin1 = Origin::signed(1);
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		assert_ok!(Unique::set_meta_update_permission_flag(
+			origin1.clone(),
+			collection_id,
+			MetaUpdatePermission::None,
+		));
+
+		let variable_data = b"test.".to_vec();
+		assert_noop!(
+			Unique::set_variable_meta_data(
+				origin1.clone(),
+				collection_id,
+				TokenId(1),
+				variable_data.try_into().unwrap()
+			)
+			.map_err(|e| e.error),
+			CommonError::<Test>::NoPermission
+		);
+	});
+}
+
+#[test]
+fn collection_transfer_flag_works_neg() {
+	new_test_ext().execute_with(|| {
+		let origin1 = Origin::signed(1);
+
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+		assert_ok!(Unique::set_transfers_enabled_flag(
+			origin1,
+			collection_id,
+			false
+		));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+
+		let origin1 = Origin::signed(1);
+
+		// default scenario
+		assert_noop!(
+			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)
+				.map_err(|e| e.error),
+			CommonError::<Test>::TransferNotAllowed
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),
+			1
+		);
+		assert_eq!(
+			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
+			0
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),
+			true
+		);
+		assert_eq!(
+			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),
+			false
+		);
+	});
+}
+
+#[test]
+fn collection_sponsoring() {
+	new_test_ext().execute_with(|| {
+		// default_limits();
+		let user1 = 1_u64;
+		let user2 = 777_u64;
+		let origin1 = Origin::signed(user1);
+		let origin2 = Origin::signed(user2);
+		let account2 = account(user2);
+
+		let collection_id =
+			create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));
+		assert_ok!(Unique::set_collection_sponsor(
+			origin1.clone(),
+			collection_id,
+			user1
+		));
+		assert_ok!(Unique::confirm_sponsorship(origin1.clone(), collection_id));
+
+		// Expect error while have no permissions
+		assert!(Unique::create_item(
+			origin2.clone(),
+			collection_id,
+			account2.clone(),
+			default_nft_data().into()
+		)
+		.is_err());
+
+		assert_ok!(Unique::set_public_access_mode(
+			origin1.clone(),
+			collection_id,
+			AccessMode::AllowList
+		));
+		assert_ok!(Unique::add_to_allow_list(
+			origin1.clone(),
+			collection_id,
+			account2.clone()
+		));
+		assert_ok!(Unique::set_mint_permission(
+			origin1.clone(),
+			collection_id,
+			true
+		));
+
+		assert_ok!(Unique::create_item(
+			origin2,
+			collection_id,
+			account2,
+			default_nft_data().into()
+		));
+	});
+}