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

difftreelog

refactor drop rmrk compatibility layer

Yaroslav Bolyukin2023-02-05parent: #d110539.patch.diff
in: master

85 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5543,8 +5543,6 @@
  "pallet-nonfungible",
  "pallet-randomness-collective-flip",
  "pallet-refungible",
- "pallet-rmrk-core",
- "pallet-rmrk-equip",
  "pallet-session",
  "pallet-structure",
  "pallet-sudo",
@@ -5561,7 +5559,6 @@
  "parity-scale-codec",
  "polkadot-parachain",
  "precompile-utils-macro",
- "rmrk-rpc",
  "scale-info",
  "serde",
  "smallvec",
@@ -6772,43 +6769,6 @@
  "parity-scale-codec",
  "scale-info",
  "sp-core",
- "sp-runtime",
- "sp-std",
- "up-data-structs",
-]
-
-[[package]]
-name = "pallet-rmrk-core"
-version = "0.1.2"
-dependencies = [
- "frame-benchmarking",
- "frame-support",
- "frame-system",
- "pallet-common",
- "pallet-evm",
- "pallet-nonfungible",
- "pallet-structure",
- "parity-scale-codec",
- "rmrk-traits",
- "scale-info",
- "sp-runtime",
- "sp-std",
- "up-data-structs",
-]
-
-[[package]]
-name = "pallet-rmrk-equip"
-version = "0.1.2"
-dependencies = [
- "frame-benchmarking",
- "frame-support",
- "frame-system",
- "pallet-common",
- "pallet-evm",
- "pallet-nonfungible",
- "pallet-rmrk-core",
- "parity-scale-codec",
- "scale-info",
  "sp-runtime",
  "sp-std",
  "up-data-structs",
@@ -9009,8 +8969,6 @@
  "pallet-nonfungible",
  "pallet-randomness-collective-flip",
  "pallet-refungible",
- "pallet-rmrk-core",
- "pallet-rmrk-equip",
  "pallet-session",
  "pallet-structure",
  "pallet-sudo",
@@ -9026,7 +8984,6 @@
  "parity-scale-codec",
  "polkadot-parachain",
  "precompile-utils-macro",
- "rmrk-rpc",
  "scale-info",
  "serde",
  "smallvec",
@@ -9415,26 +9372,6 @@
 ]
 
 [[package]]
-name = "rmrk-rpc"
-version = "0.0.2"
-dependencies = [
- "parity-scale-codec",
- "rmrk-traits",
- "sp-api",
- "sp-runtime",
- "sp-std",
-]
-
-[[package]]
-name = "rmrk-traits"
-version = "0.1.0"
-dependencies = [
- "parity-scale-codec",
- "scale-info",
- "serde",
-]
-
-[[package]]
 name = "rocksdb"
 version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -13026,7 +12963,6 @@
  "pallet-evm",
  "parity-scale-codec",
  "quartz-runtime",
- "rmrk-rpc",
  "sc-client-api",
  "sc-executor",
  "sc-rpc-api",
@@ -13132,7 +13068,6 @@
  "polkadot-primitives",
  "polkadot-service",
  "quartz-runtime",
- "rmrk-rpc",
  "sc-basic-authorship",
  "sc-chain-spec",
  "sc-cli",
@@ -13186,7 +13121,6 @@
  "fp-storage",
  "jsonrpsee",
  "pallet-transaction-payment-rpc",
- "rmrk-rpc",
  "sc-client-api",
  "sc-finality-grandpa",
  "sc-network",
@@ -13265,8 +13199,6 @@
  "pallet-nonfungible",
  "pallet-randomness-collective-flip",
  "pallet-refungible",
- "pallet-rmrk-core",
- "pallet-rmrk-equip",
  "pallet-session",
  "pallet-structure",
  "pallet-sudo",
@@ -13282,7 +13214,6 @@
  "parity-scale-codec",
  "polkadot-parachain",
  "precompile-utils-macro",
- "rmrk-rpc",
  "scale-info",
  "serde",
  "smallvec",
@@ -13361,7 +13292,6 @@
  "frame-support",
  "pallet-evm",
  "parity-scale-codec",
- "rmrk-traits",
  "scale-info",
  "serde",
  "sp-core",
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -43,9 +43,6 @@
 pallet-inflation = { path = "pallets/inflation", default-features = false }
 pallet-maintenance = { default-features = false, path = "pallets/maintenance" }
 pallet-nonfungible = { default-features = false, path = "pallets/nonfungible" }
-pallet-proxy-rmrk-core = { default-features = false, path = "pallets/proxy-rmrk-core", package = "pallet-rmrk-core" }
-pallet-proxy-rmrk-equip = { default-features = false, path = "pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }
-rmrk-traits = { default-features = false, path = "primitives/rmrk-traits" }
 pallet-refungible = { default-features = false, path = "pallets/refungible" }
 pallet-structure = { default-features = false, path = "pallets/structure" }
 pallet-unique = { path = "pallets/unique", default-features = false }
@@ -53,7 +50,6 @@
 pallet-test-utils = { default-features = false, path = "test-pallets/utils" }
 pallet-app-promotion = { path = "pallets/app-promotion", default-features = false }
 app-promotion-rpc = { path = "primitives/app_promotion_rpc", default-features = false }
-rmrk-rpc = { path = "primitives/rmrk-rpc", default-features = false }
 
 # Unique: Runtimes
 unique-runtime = { path = "runtime/unique" }
modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -121,14 +121,6 @@
 bench-scheduler:
 	make _bench PALLET=unique-scheduler-v2 PALLET_DIR=scheduler-v2
 
-.PHONY: bench-rmrk-core
-bench-rmrk-core:
-	make _bench PALLET=proxy-rmrk-core
-
-.PHONY: bench-rmrk-equip
-bench-rmrk-equip:
-	make _bench PALLET=proxy-rmrk-equip
-
 .PHONY: bench-foreign-assets
 bench-foreign-assets:
 	make _bench PALLET=foreign-assets
@@ -146,7 +138,7 @@
 	make _bench PALLET=app-promotion PALLET_DIR=app-promotion
 
 .PHONY: bench
-# Disabled: bench-scheduler, bench-collator-selection, bench-identity, bench-rmrk-core, bench-rmrk-equip
+# Disabled: bench-scheduler, bench-collator-selection, bench-identity
 bench: bench-common bench-evm-migration bench-unique bench-structure bench-fungible bench-refungible bench-nonfungible bench-configuration bench-foreign-assets
 
 .PHONY: check
modifiedclient/rpc/Cargo.tomldiffbeforeafterboth
--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -14,7 +14,6 @@
 codec = { workspace = true, package = "parity-scale-codec" }
 
 app-promotion-rpc = { workspace = true }
-rmrk-rpc = { workspace = true }
 up-common = { workspace = true }
 up-data-structs = { workspace = true }
 up-pov-estimate-rpc = { workspace = true, optional = true }
modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -17,7 +17,7 @@
 // Original License
 use std::sync::Arc;
 
-use codec::{Decode, Encode};
+use codec::Decode;
 use jsonrpsee::{
 	core::{RpcResult as Result},
 	proc_macros::rpc,
@@ -32,15 +32,8 @@
 use sp_blockchain::HeaderBackend;
 use up_rpc::UniqueApi as UniqueRuntimeApi;
 use app_promotion_rpc::AppPromotionApi as AppPromotionRuntimeApi;
-
-// RMRK
-use rmrk_rpc::RmrkApi as RmrkRuntimeApi;
-use up_data_structs::{
-	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,
-};
 
 pub use app_promotion_unique_rpc::AppPromotionApiServer;
-pub use rmrk_unique_rpc::RmrkApiServer;
 
 #[cfg(feature = "pov-estimate")]
 pub mod pov_estimate;
@@ -300,129 +293,7 @@
 		) -> Result<Vec<(BlockNumber, String)>>;
 	}
 }
-
-mod rmrk_unique_rpc {
-	use super::*;
-
-	#[rpc(server)]
-	#[async_trait]
-	pub trait RmrkApi<
-		BlockHash,
-		AccountId,
-		CollectionInfo,
-		NftInfo,
-		ResourceInfo,
-		PropertyInfo,
-		BaseInfo,
-		PartType,
-		Theme,
-	>
-	{
-		/// Get the latest created collection ID.
-		#[method(name = "rmrk_lastCollectionIdx")]
-		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;
-
-		/// Get collection info by ID.
-		#[method(name = "rmrk_collectionById")]
-		fn collection_by_id(
-			&self,
-			id: RmrkCollectionId,
-			at: Option<BlockHash>,
-		) -> Result<Option<CollectionInfo>>;
-
-		/// Get NFT info by collection and NFT IDs.
-		#[method(name = "rmrk_nftById")]
-		fn nft_by_id(
-			&self,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			at: Option<BlockHash>,
-		) -> Result<Option<NftInfo>>;
-
-		/// Get tokens owned by an account in a collection.
-		#[method(name = "rmrk_accountTokens")]
-		fn account_tokens(
-			&self,
-			account_id: AccountId,
-			collection_id: RmrkCollectionId,
-			at: Option<BlockHash>,
-		) -> Result<Vec<RmrkNftId>>;
-
-		/// Get tokens nested in an NFT - its direct children (not the children's children).
-		#[method(name = "rmrk_nftChildren")]
-		fn nft_children(
-			&self,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			at: Option<BlockHash>,
-		) -> Result<Vec<RmrkNftChild>>;
-
-		/// Get collection properties, created by the user - not the proxy-specific properties.
-		#[method(name = "rmrk_collectionProperties")]
-		fn collection_properties(
-			&self,
-			collection_id: RmrkCollectionId,
-			filter_keys: Option<Vec<String>>,
-			at: Option<BlockHash>,
-		) -> Result<Vec<PropertyInfo>>;
-
-		/// Get NFT properties, created by the user - not the proxy-specific properties.
-		#[method(name = "rmrk_nftProperties")]
-		fn nft_properties(
-			&self,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			filter_keys: Option<Vec<String>>,
-			at: Option<BlockHash>,
-		) -> Result<Vec<PropertyInfo>>;
-
-		/// Get data of resources of an NFT.
-		#[method(name = "rmrk_nftResources")]
-		fn nft_resources(
-			&self,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			at: Option<BlockHash>,
-		) -> Result<Vec<ResourceInfo>>;
 
-		/// Get the priority of a resource in an NFT.
-		#[method(name = "rmrk_nftResourcePriority")]
-		fn nft_resource_priority(
-			&self,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-			at: Option<BlockHash>,
-		) -> Result<Option<u32>>;
-
-		/// Get base info by its ID.
-		#[method(name = "rmrk_base")]
-		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;
-
-		/// Get all parts of a base.
-		#[method(name = "rmrk_baseParts")]
-		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;
-
-		/// Get the theme names belonging to a base.
-		#[method(name = "rmrk_themeNames")]
-		fn theme_names(
-			&self,
-			base_id: RmrkBaseId,
-			at: Option<BlockHash>,
-		) -> Result<Vec<RmrkThemeName>>;
-
-		/// Get theme info, including properties, optionally limited to the provided keys.
-		#[method(name = "rmrk_themes")]
-		fn theme(
-			&self,
-			base_id: RmrkBaseId,
-			theme_name: String,
-			filter_keys: Option<Vec<String>>,
-			at: Option<BlockHash>,
-		) -> Result<Option<Theme>>;
-	}
-}
-
 #[macro_export]
 macro_rules! define_struct_for_server_api {
 	($name:ident { $($arg:ident: $arg_ty:ty),+ $(,)? }) => {
@@ -454,12 +325,6 @@
 	}
 }
 
-define_struct_for_server_api! {
-	Rmrk {
-		client: Arc<Client>
-	}
-}
-
 macro_rules! pass_method {
 	(
 		$method_name:ident(
@@ -508,12 +373,6 @@
 macro_rules! app_promotion_api {
 	() => {
 		dyn AppPromotionRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>
-	};
-}
-
-macro_rules! rmrk_api {
-	() => {
-		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>
 	};
 }
 
@@ -627,94 +486,6 @@
 		.into_iter()
 		.map(|(b, a)| (b, a.to_string()))
 		.collect::<Vec<_>>(), app_promotion_api);
-}
-
-#[allow(deprecated)]
-impl<
-		C,
-		Block,
-		AccountId,
-		CollectionInfo,
-		NftInfo,
-		ResourceInfo,
-		PropertyInfo,
-		BaseInfo,
-		PartType,
-		Theme,
-	>
-	rmrk_unique_rpc::RmrkApiServer<
-		<Block as BlockT>::Hash,
-		AccountId,
-		CollectionInfo,
-		NftInfo,
-		ResourceInfo,
-		PropertyInfo,
-		BaseInfo,
-		PartType,
-		Theme,
-	> for Rmrk<C, Block>
-where
-	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,
-	C::Api: RmrkRuntimeApi<
-		Block,
-		AccountId,
-		CollectionInfo,
-		NftInfo,
-		ResourceInfo,
-		PropertyInfo,
-		BaseInfo,
-		PartType,
-		Theme,
-	>,
-	AccountId: Decode + Encode,
-	CollectionInfo: Decode,
-	NftInfo: Decode,
-	ResourceInfo: Decode,
-	PropertyInfo: Decode,
-	BaseInfo: Decode,
-	PartType: Decode,
-	Theme: Decode,
-	Block: BlockT,
-{
-	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);
-	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);
-	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);
-	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);
-	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);
-	pass_method!(
-		collection_properties(
-			collection_id: RmrkCollectionId,
-
-			#[map(|keys| string_keys_to_bytes_keys(keys))]
-			filter_keys: Option<Vec<String>>
-		) -> Vec<PropertyInfo>,
-		rmrk_api
-	);
-	pass_method!(
-		nft_properties(
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-
-			#[map(|keys| string_keys_to_bytes_keys(keys))]
-			filter_keys: Option<Vec<String>>
-		) -> Vec<PropertyInfo>,
-		rmrk_api
-	);
-	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);
-	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);
-	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);
-	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);
-	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);
-	pass_method!(
-		theme(
-			base_id: RmrkBaseId,
-
-			#[map(|n| n.into_bytes())]
-			theme_name: String,
-
-			#[map(|keys| string_keys_to_bytes_keys(keys))]
-			filter_keys: Option<Vec<String>>
-		) -> Option<Theme>, rmrk_api);
 }
 
 fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -89,7 +89,6 @@
 fp-rpc = { workspace = true }
 
 app-promotion-rpc = { workspace = true }
-rmrk-rpc = { workspace = true }
 uc-rpc = { workspace = true }
 unique-rpc = { workspace = true }
 up-pov-estimate-rpc = { workspace = true }
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -71,12 +71,6 @@
 #[cfg(feature = "pov-estimate")]
 use crate::chain_spec::RuntimeIdentification;
 
-// RMRK
-use up_data_structs::{
-	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
-	RmrkPartType, RmrkTheme,
-};
-
 /// Unique native executor instance.
 #[cfg(feature = "unique-runtime")]
 pub struct UniqueRuntimeExecutor;
@@ -403,17 +397,7 @@
 		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
 		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
 		+ app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
-		+ rmrk_rpc::RmrkApi<
-			Block,
-			AccountId,
-			RmrkCollectionInfo<AccountId>,
-			RmrkInstanceInfo<AccountId>,
-			RmrkResourceInfo,
-			RmrkPropertyInfo,
-			RmrkBaseInfo<AccountId>,
-			RmrkPartType,
-			RmrkTheme,
-		> + up_pov_estimate_rpc::PovEstimateApi<Block>
+		+ up_pov_estimate_rpc::PovEstimateApi<Block>
 		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
 		+ sp_api::Metadata<Block>
 		+ sp_offchain::OffchainWorkerApi<Block>
@@ -732,17 +716,7 @@
 		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
 		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
 		+ app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
-		+ rmrk_rpc::RmrkApi<
-			Block,
-			AccountId,
-			RmrkCollectionInfo<AccountId>,
-			RmrkInstanceInfo<AccountId>,
-			RmrkResourceInfo,
-			RmrkPropertyInfo,
-			RmrkBaseInfo<AccountId>,
-			RmrkPartType,
-			RmrkTheme,
-		> + up_pov_estimate_rpc::PovEstimateApi<Block>
+		+ up_pov_estimate_rpc::PovEstimateApi<Block>
 		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
 		+ sp_api::Metadata<Block>
 		+ sp_offchain::OffchainWorkerApi<Block>
@@ -882,17 +856,7 @@
 		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
 		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
 		+ app_promotion_rpc::AppPromotionApi<Block, BlockNumber, Runtime::CrossAccountId, AccountId>
-		+ rmrk_rpc::RmrkApi<
-			Block,
-			AccountId,
-			RmrkCollectionInfo<AccountId>,
-			RmrkInstanceInfo<AccountId>,
-			RmrkResourceInfo,
-			RmrkPropertyInfo,
-			RmrkBaseInfo<AccountId>,
-			RmrkPartType,
-			RmrkTheme,
-		> + up_pov_estimate_rpc::PovEstimateApi<Block>
+		+ up_pov_estimate_rpc::PovEstimateApi<Block>
 		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
 		+ sp_api::Metadata<Block>
 		+ sp_offchain::OffchainWorkerApi<Block>
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -33,7 +33,6 @@
 fp-storage = { workspace = true }
 
 app-promotion-rpc = { workspace = true }
-rmrk-rpc = { workspace = true }
 serde = { workspace = true }
 uc-rpc = { workspace = true }
 up-common = { workspace = true }
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -42,12 +42,6 @@
 
 use up_common::types::opaque::*;
 
-// RMRK
-use up_data_structs::{
-	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
-	RmrkPartType, RmrkTheme,
-};
-
 #[cfg(feature = "pov-estimate")]
 type FullBackend = sc_service::TFullBackend<Block>;
 
@@ -164,17 +158,6 @@
 		<R as RuntimeInstance>::CrossAccountId,
 		AccountId,
 	>,
-	C::Api: rmrk_rpc::RmrkApi<
-		Block,
-		AccountId,
-		RmrkCollectionInfo<AccountId>,
-		RmrkInstanceInfo<AccountId>,
-		RmrkResourceInfo,
-		RmrkPropertyInfo,
-		RmrkBaseInfo<AccountId>,
-		RmrkPartType,
-		RmrkTheme,
-	>,
 	C::Api: up_pov_estimate_rpc::PovEstimateApi<Block>,
 	B: sc_client_api::Backend<Block> + Send + Sync + 'static,
 	B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
@@ -193,9 +176,6 @@
 	#[cfg(not(feature = "unique-runtime"))]
 	use uc_rpc::{AppPromotionApiServer, AppPromotion};
 
-	#[cfg(not(feature = "unique-runtime"))]
-	use uc_rpc::{RmrkApiServer, Rmrk};
-
 	#[cfg(feature = "pov-estimate")]
 	use uc_rpc::pov_estimate::{PovEstimateApiServer, PovEstimate};
 
@@ -267,9 +247,6 @@
 
 	#[cfg(not(feature = "unique-runtime"))]
 	io.merge(AppPromotion::new(client.clone()).into_rpc())?;
-
-	#[cfg(not(feature = "unique-runtime"))]
-	io.merge(Rmrk::new(client.clone()).into_rpc())?;
 
 	#[cfg(feature = "pov-estimate")]
 	io.merge(
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -33,7 +33,7 @@
 };
 
 use crate::{
-	Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf, eth, weights::WeightInfo,
+	Pallet, CollectionHandle, Config, CollectionProperties, eth, SelfWeightOf, weights::WeightInfo,
 };
 
 frontier_contract! {
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
before · pallets/common/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::{57	ops::{Deref, DerefMut},58	slice::from_ref,59};60use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};61use sp_std::vec::Vec;62use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};63use evm_coder::ToLog;64use frame_support::{65	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},66	ensure,67	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},68	dispatch::Pays,69	transactional, fail,70};71use pallet_evm::GasWeightMapping;72use up_data_structs::{73	AccessMode,74	COLLECTION_NUMBER_LIMIT,75	Collection,76	RpcCollection,77	CollectionFlags,78	RpcCollectionFlags,79	CollectionId,80	CreateItemData,81	MAX_TOKEN_PREFIX_LENGTH,82	COLLECTION_ADMINS_LIMIT,83	TokenId,84	TokenChild,85	CollectionStats,86	MAX_TOKEN_OWNERSHIP,87	CollectionMode,88	NFT_SPONSOR_TRANSFER_TIMEOUT,89	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,90	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,91	MAX_SPONSOR_TIMEOUT,92	CUSTOM_DATA_LIMIT,93	CollectionLimits,94	CreateCollectionData,95	SponsorshipState,96	CreateItemExData,97	SponsoringRateLimit,98	budget::Budget,99	PhantomType,100	Property,101	Properties,102	PropertiesPermissionMap,103	PropertyKey,104	PropertyValue,105	PropertyPermission,106	PropertiesError,107	TokenOwnerError,108	PropertyKeyPermission,109	TokenData,110	TrySetProperty,111	PropertyScope,112	// RMRK113	RmrkCollectionInfo,114	RmrkInstanceInfo,115	RmrkResourceInfo,116	RmrkPropertyInfo,117	RmrkBaseInfo,118	RmrkPartType,119	RmrkBoundedTheme,120	RmrkNftChild,121	CollectionPermissions,122};123use up_pov_estimate_rpc::PovInfo;124125pub use pallet::*;126use sp_core::H160;127use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};128129use crate::erc::CollectionHelpersEvents;130#[cfg(feature = "runtime-benchmarks")]131pub mod benchmarking;132pub mod dispatch;133pub mod erc;134pub mod eth;135pub mod weights;136137/// Weight info.138pub type SelfWeightOf<T> = <T as Config>::WeightInfo;139140/// Collection handle contains information about collection data and id.141/// Also provides functionality to count consumed gas.142///143/// CollectionHandle is used as a generic wrapper for collections of all types.144/// It allows to perform common operations and queries on any collection type,145/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].146#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]147pub struct CollectionHandle<T: Config> {148	/// Collection id149	pub id: CollectionId,150	collection: Collection<T::AccountId>,151	/// Substrate recorder for counting consumed gas152	pub recorder: SubstrateRecorder<T>,153}154155impl<T: Config> WithRecorder<T> for CollectionHandle<T> {156	fn recorder(&self) -> &SubstrateRecorder<T> {157		&self.recorder158	}159	fn into_recorder(self) -> SubstrateRecorder<T> {160		self.recorder161	}162}163164impl<T: Config> CollectionHandle<T> {165	/// Same as [CollectionHandle::new] but with an explicit gas limit.166	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {167		<CollectionById<T>>::get(id).map(|collection| Self {168			id,169			collection,170			recorder: SubstrateRecorder::new(gas_limit),171		})172	}173174	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].175	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {176		<CollectionById<T>>::get(id).map(|collection| Self {177			id,178			collection,179			recorder,180		})181	}182183	/// Retrives collection data from storage and creates collection handle with default parameters.184	/// If collection not found return `None`185	pub fn new(id: CollectionId) -> Option<Self> {186		Self::new_with_gas_limit(id, u64::MAX)187	}188189	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.190	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {191		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)192	}193194	/// Consume gas for reading.195	pub fn consume_store_reads(196		&self,197		reads: u64,198	) -> pallet_evm_coder_substrate::execution::Result<()> {199		self.recorder200			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(201				<T as frame_system::Config>::DbWeight::get()202					.read203					.saturating_mul(reads),204			)))205	}206207	/// Consume gas for writing.208	pub fn consume_store_writes(209		&self,210		writes: u64,211	) -> pallet_evm_coder_substrate::execution::Result<()> {212		self.recorder213			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(214				<T as frame_system::Config>::DbWeight::get()215					.write216					.saturating_mul(writes),217			)))218	}219220	/// Consume gas for reading and writing.221	pub fn consume_store_reads_and_writes(222		&self,223		reads: u64,224		writes: u64,225	) -> pallet_evm_coder_substrate::execution::Result<()> {226		let weight = <T as frame_system::Config>::DbWeight::get();227		let reads = weight.read.saturating_mul(reads);228		let writes = weight.read.saturating_mul(writes);229		self.recorder230			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(231				reads.saturating_add(writes),232			)))233	}234235	/// Save collection to storage.236	pub fn save(&self) -> DispatchResult {237		<CollectionById<T>>::insert(self.id, &self.collection);238		Ok(())239	}240241	/// Set collection sponsor.242	///243	/// Unique collections allows sponsoring for certain actions.244	/// This method allows you to set the sponsor of the collection.245	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].246	pub fn set_sponsor(247		&mut self,248		sender: &T::CrossAccountId,249		sponsor: T::AccountId,250	) -> DispatchResult {251		self.check_is_internal()?;252		self.check_is_owner_or_admin(sender)?;253254		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());255256		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));257		<PalletEvm<T>>::deposit_log(258			erc::CollectionHelpersEvents::CollectionChanged {259				collection_id: eth::collection_id_to_address(self.id),260			}261			.to_log(T::ContractAddress::get()),262		);263264		self.save()265	}266267	/// Force set `sponsor`.268	///269	/// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation270	/// from the `sponsor` is not required.271	///272	/// # Arguments273	///274	/// * `sender`: Caller's account.275	/// * `sponsor`: ID of the account of the sponsor-to-be.276	pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {277		self.check_is_internal()?;278279		self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());280281		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));282		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));283		<PalletEvm<T>>::deposit_log(284			erc::CollectionHelpersEvents::CollectionChanged {285				collection_id: eth::collection_id_to_address(self.id),286			}287			.to_log(T::ContractAddress::get()),288		);289290		self.save()291	}292293	/// Confirm sponsorship294	///295	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.296	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].297	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {298		self.check_is_internal()?;299		ensure!(300			self.collection.sponsorship.pending_sponsor() == Some(sender),301			Error::<T>::ConfirmSponsorshipFail302		);303304		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());305306		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));307		<PalletEvm<T>>::deposit_log(308			erc::CollectionHelpersEvents::CollectionChanged {309				collection_id: eth::collection_id_to_address(self.id),310			}311			.to_log(T::ContractAddress::get()),312		);313314		self.save()315	}316317	/// Remove collection sponsor.318	pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {319		self.check_is_internal()?;320		self.check_is_owner_or_admin(sender)?;321322		self.collection.sponsorship = SponsorshipState::Disabled;323324		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));325		<PalletEvm<T>>::deposit_log(326			erc::CollectionHelpersEvents::CollectionChanged {327				collection_id: eth::collection_id_to_address(self.id),328			}329			.to_log(T::ContractAddress::get()),330		);331		self.save()332	}333334	/// Force remove `sponsor`.335	///336	/// Differs from `remove_sponsor` in that337	/// it doesn't require consent from the `owner` of the collection.338	pub fn force_remove_sponsor(&mut self) -> DispatchResult {339		self.check_is_internal()?;340341		self.collection.sponsorship = SponsorshipState::Disabled;342343		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));344		<PalletEvm<T>>::deposit_log(345			erc::CollectionHelpersEvents::CollectionChanged {346				collection_id: eth::collection_id_to_address(self.id),347			}348			.to_log(T::ContractAddress::get()),349		);350		self.save()351	}352353	/// Checks that the collection was created with, and must be operated upon through **Unique API**.354	/// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.355	pub fn check_is_internal(&self) -> DispatchResult {356		if self.flags.external {357			return Err(<Error<T>>::CollectionIsExternal)?;358		}359360		Ok(())361	}362363	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.364	/// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.365	pub fn check_is_external(&self) -> DispatchResult {366		if !self.flags.external {367			return Err(<Error<T>>::CollectionIsInternal)?;368		}369370		Ok(())371	}372}373374impl<T: Config> Deref for CollectionHandle<T> {375	type Target = Collection<T::AccountId>;376377	fn deref(&self) -> &Self::Target {378		&self.collection379	}380}381382impl<T: Config> DerefMut for CollectionHandle<T> {383	fn deref_mut(&mut self) -> &mut Self::Target {384		&mut self.collection385	}386}387388impl<T: Config> CollectionHandle<T> {389	/// Checks if the `user` is the owner of the collection.390	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {391		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);392		Ok(())393	}394395	/// Returns **true** if the `user` is the owner or administrator of the collection.396	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {397		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))398	}399400	/// Checks if the `user` is the owner or administrator of the collection.401	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {402		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);403		Ok(())404	}405406	/// Returns **true** if407	/// * the `user`is a collection owner or admin408	/// * the collection limits allow the owner/admins to transfer/burn any collection token409	pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {410		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)411	}412413	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.414	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {415		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)416	}417418	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.419	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {420		ensure!(421			<Allowlist<T>>::get((self.id, user)),422			<Error<T>>::AddressNotInAllowlist423		);424		Ok(())425	}426427	/// Changes collection owner to another account428	/// #### Store read/writes429	/// 1 writes430	pub fn change_owner(431		&mut self,432		caller: T::CrossAccountId,433		new_owner: T::CrossAccountId,434	) -> DispatchResult {435		self.check_is_internal()?;436		self.check_is_owner(&caller)?;437		self.collection.owner = new_owner.as_sub().clone();438439		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(440			self.id,441			new_owner.as_sub().clone(),442		));443		<PalletEvm<T>>::deposit_log(444			erc::CollectionHelpersEvents::CollectionChanged {445				collection_id: eth::collection_id_to_address(self.id),446			}447			.to_log(T::ContractAddress::get()),448		);449450		self.save()451	}452}453454#[frame_support::pallet]455pub mod pallet {456	use super::*;457	use dispatch::CollectionDispatch;458	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};459	use frame_system::pallet_prelude::*;460	use frame_support::traits::Currency;461	use up_data_structs::{TokenId, mapping::TokenAddressMapping};462	use scale_info::TypeInfo;463	use weights::WeightInfo;464465	#[pallet::config]466	pub trait Config:467		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo468	{469		/// Weight information for functions of this pallet.470		type WeightInfo: WeightInfo;471472		/// Events compatible with [`frame_system::Config::Event`].473		type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;474475		/// Handler of accounts and payment.476		type Currency: Currency<Self::AccountId>;477478		/// Set price to create a collection.479		#[pallet::constant]480		type CollectionCreationPrice: Get<481			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,482		>;483484		/// Dispatcher of operations on collections.485		type CollectionDispatch: CollectionDispatch<Self>;486487		/// Account which holds the chain's treasury.488		type TreasuryAccountId: Get<Self::AccountId>;489490		/// Address under which the CollectionHelper contract would be available.491		#[pallet::constant]492		type ContractAddress: Get<H160>;493494		/// Mapper for token addresses to Ethereum addresses.495		type EvmTokenAddressMapping: TokenAddressMapping<H160>;496497		/// Mapper for token addresses to [`CrossAccountId`].498		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;499	}500501	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);502503	#[pallet::pallet]504	#[pallet::storage_version(STORAGE_VERSION)]505	#[pallet::generate_store(pub(super) trait Store)]506	pub struct Pallet<T>(_);507508	#[pallet::extra_constants]509	impl<T: Config> Pallet<T> {510		/// Maximum admins per collection.511		pub fn collection_admins_limit() -> u32 {512			COLLECTION_ADMINS_LIMIT513		}514	}515516	impl<T: Config> Pallet<T> {517		/// Helper function that handles deposit events518		pub fn deposit_event(event: Event<T>) {519			let event = <T as Config>::RuntimeEvent::from(event);520			let event = event.into();521			<frame_system::Pallet<T>>::deposit_event(event)522		}523	}524525	#[pallet::event]526	pub enum Event<T: Config> {527		/// New collection was created528		CollectionCreated(529			/// Globally unique identifier of newly created collection.530			CollectionId,531			/// [`CollectionMode`] converted into _u8_.532			u8,533			/// Collection owner.534			T::AccountId,535		),536537		/// New collection was destroyed538		CollectionDestroyed(539			/// Globally unique identifier of collection.540			CollectionId,541		),542543		/// New item was created.544		ItemCreated(545			/// Id of the collection where item was created.546			CollectionId,547			/// Id of an item. Unique within the collection.548			TokenId,549			/// Owner of newly created item550			T::CrossAccountId,551			/// Always 1 for NFT552			u128,553		),554555		/// Collection item was burned.556		ItemDestroyed(557			/// Id of the collection where item was destroyed.558			CollectionId,559			/// Identifier of burned NFT.560			TokenId,561			/// Which user has destroyed its tokens.562			T::CrossAccountId,563			/// Amount of token pieces destroed. Always 1 for NFT.564			u128,565		),566567		/// Item was transferred568		Transfer(569			/// Id of collection to which item is belong.570			CollectionId,571			/// Id of an item.572			TokenId,573			/// Original owner of item.574			T::CrossAccountId,575			/// New owner of item.576			T::CrossAccountId,577			/// Amount of token pieces transfered. Always 1 for NFT.578			u128,579		),580581		/// Amount pieces of token owned by `sender` was approved for `spender`.582		Approved(583			/// Id of collection to which item is belong.584			CollectionId,585			/// Id of an item.586			TokenId,587			/// Original owner of item.588			T::CrossAccountId,589			/// Id for which the approval was granted.590			T::CrossAccountId,591			/// Amount of token pieces transfered. Always 1 for NFT.592			u128,593		),594595		/// A `sender` approves operations on all owned tokens for `spender`.596		ApprovedForAll(597			/// Id of collection to which item is belong.598			CollectionId,599			/// Owner of a wallet.600			T::CrossAccountId,601			/// Id for which operator status was granted or rewoked.602			T::CrossAccountId,603			/// Is operator status granted or revoked?604			bool,605		),606607		/// The colletion property has been added or edited.608		CollectionPropertySet(609			/// Id of collection to which property has been set.610			CollectionId,611			/// The property that was set.612			PropertyKey,613		),614615		/// The property has been deleted.616		CollectionPropertyDeleted(617			/// Id of collection to which property has been deleted.618			CollectionId,619			/// The property that was deleted.620			PropertyKey,621		),622623		/// The token property has been added or edited.624		TokenPropertySet(625			/// Identifier of the collection whose token has the property set.626			CollectionId,627			/// The token for which the property was set.628			TokenId,629			/// The property that was set.630			PropertyKey,631		),632633		/// The token property has been deleted.634		TokenPropertyDeleted(635			/// Identifier of the collection whose token has the property deleted.636			CollectionId,637			/// The token for which the property was deleted.638			TokenId,639			/// The property that was deleted.640			PropertyKey,641		),642643		/// The token property permission of a collection has been set.644		PropertyPermissionSet(645			/// ID of collection to which property permission has been set.646			CollectionId,647			/// The property permission that was set.648			PropertyKey,649		),650651		/// Address was added to the allow list.652		AllowListAddressAdded(653			/// ID of the affected collection.654			CollectionId,655			/// Address of the added account.656			T::CrossAccountId,657		),658659		/// Address was removed from the allow list.660		AllowListAddressRemoved(661			/// ID of the affected collection.662			CollectionId,663			/// Address of the removed account.664			T::CrossAccountId,665		),666667		/// Collection admin was added.668		CollectionAdminAdded(669			/// ID of the affected collection.670			CollectionId,671			/// Admin address.672			T::CrossAccountId,673		),674675		/// Collection admin was removed.676		CollectionAdminRemoved(677			/// ID of the affected collection.678			CollectionId,679			/// Removed admin address.680			T::CrossAccountId,681		),682683		/// Collection limits were set.684		CollectionLimitSet(685			/// ID of the affected collection.686			CollectionId,687		),688689		/// Collection owned was changed.690		CollectionOwnerChanged(691			/// ID of the affected collection.692			CollectionId,693			/// New owner address.694			T::AccountId,695		),696697		/// Collection permissions were set.698		CollectionPermissionSet(699			/// ID of the affected collection.700			CollectionId,701		),702703		/// Collection sponsor was set.704		CollectionSponsorSet(705			/// ID of the affected collection.706			CollectionId,707			/// New sponsor address.708			T::AccountId,709		),710711		/// New sponsor was confirm.712		SponsorshipConfirmed(713			/// ID of the affected collection.714			CollectionId,715			/// New sponsor address.716			T::AccountId,717		),718719		/// Collection sponsor was removed.720		CollectionSponsorRemoved(721			/// ID of the affected collection.722			CollectionId,723		),724	}725726	#[pallet::error]727	pub enum Error<T> {728		/// This collection does not exist.729		CollectionNotFound,730		/// Sender parameter and item owner must be equal.731		MustBeTokenOwner,732		/// No permission to perform action733		NoPermission,734		/// Destroying only empty collections is allowed735		CantDestroyNotEmptyCollection,736		/// Collection is not in mint mode.737		PublicMintingNotAllowed,738		/// Address is not in allow list.739		AddressNotInAllowlist,740741		/// Collection name can not be longer than 63 char.742		CollectionNameLimitExceeded,743		/// Collection description can not be longer than 255 char.744		CollectionDescriptionLimitExceeded,745		/// Token prefix can not be longer than 15 char.746		CollectionTokenPrefixLimitExceeded,747		/// Total collections bound exceeded.748		TotalCollectionsLimitExceeded,749		/// Exceeded max admin count750		CollectionAdminCountExceeded,751		/// Collection limit bounds per collection exceeded752		CollectionLimitBoundsExceeded,753		/// Tried to enable permissions which are only permitted to be disabled754		OwnerPermissionsCantBeReverted,755		/// Collection settings not allowing items transferring756		TransferNotAllowed,757		/// Account token limit exceeded per collection758		AccountTokenLimitExceeded,759		/// Collection token limit exceeded760		CollectionTokenLimitExceeded,761		/// Metadata flag frozen762		MetadataFlagFrozen,763764		/// Item does not exist765		TokenNotFound,766		/// Item is balance not enough767		TokenValueTooLow,768		/// Requested value is more than the approved769		ApprovedValueTooLow,770		/// Tried to approve more than owned771		CantApproveMoreThanOwned,772		/// Only spending from eth mirror could be approved773		AddressIsNotEthMirror,774775		/// Can't transfer tokens to ethereum zero address776		AddressIsZero,777778		/// The operation is not supported779		UnsupportedOperation,780781		/// Insufficient funds to perform an action782		NotSufficientFounds,783784		/// User does not satisfy the nesting rule785		UserIsNotAllowedToNest,786		/// Only tokens from specific collections may nest tokens under this one787		SourceCollectionIsNotAllowedToNest,788789		/// Tried to store more data than allowed in collection field790		CollectionFieldSizeExceeded,791792		/// Tried to store more property data than allowed793		NoSpaceForProperty,794795		/// Tried to store more property keys than allowed796		PropertyLimitReached,797798		/// Property key is too long799		PropertyKeyIsTooLong,800801		/// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed802		InvalidCharacterInPropertyKey,803804		/// Empty property keys are forbidden805		EmptyPropertyKey,806807		/// Tried to access an external collection with an internal API808		CollectionIsExternal,809810		/// Tried to access an internal collection with an external API811		CollectionIsInternal,812813		/// This address is not set as sponsor, use setCollectionSponsor first.814		ConfirmSponsorshipFail,815816		/// The user is not an administrator.817		UserIsNotCollectionAdmin,818	}819820	/// Storage of the count of created collections. Essentially contains the last collection ID.821	#[pallet::storage]822	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;823824	/// Storage of the count of deleted collections.825	#[pallet::storage]826	pub type DestroyedCollectionCount<T> =827		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;828829	/// Storage of collection info.830	#[pallet::storage]831	pub type CollectionById<T> = StorageMap<832		Hasher = Blake2_128Concat,833		Key = CollectionId,834		Value = Collection<<T as frame_system::Config>::AccountId>,835		QueryKind = OptionQuery,836	>;837838	/// Storage of collection properties.839	#[pallet::storage]840	#[pallet::getter(fn collection_properties)]841	pub type CollectionProperties<T> = StorageMap<842		Hasher = Blake2_128Concat,843		Key = CollectionId,844		Value = Properties,845		QueryKind = ValueQuery,846		OnEmpty = up_data_structs::CollectionProperties,847	>;848849	/// Storage of token property permissions of a collection.850	#[pallet::storage]851	#[pallet::getter(fn property_permissions)]852	pub type CollectionPropertyPermissions<T> = StorageMap<853		Hasher = Blake2_128Concat,854		Key = CollectionId,855		Value = PropertiesPermissionMap,856		QueryKind = ValueQuery,857	>;858859	/// Storage of the amount of collection admins.860	#[pallet::storage]861	pub type AdminAmount<T> = StorageMap<862		Hasher = Blake2_128Concat,863		Key = CollectionId,864		Value = u32,865		QueryKind = ValueQuery,866	>;867868	/// List of collection admins.869	#[pallet::storage]870	pub type IsAdmin<T: Config> = StorageNMap<871		Key = (872			Key<Blake2_128Concat, CollectionId>,873			Key<Blake2_128Concat, T::CrossAccountId>,874		),875		Value = bool,876		QueryKind = ValueQuery,877	>;878879	/// Allowlisted collection users.880	#[pallet::storage]881	pub type Allowlist<T: Config> = StorageNMap<882		Key = (883			Key<Blake2_128Concat, CollectionId>,884			Key<Blake2_128Concat, T::CrossAccountId>,885		),886		Value = bool,887		QueryKind = ValueQuery,888	>;889890	/// Not used by code, exists only to provide some types to metadata.891	#[pallet::storage]892	pub type DummyStorageValue<T: Config> = StorageValue<893		Value = (894			CollectionStats,895			CollectionId,896			TokenId,897			TokenChild,898			PhantomType<(899				TokenData<T::CrossAccountId>,900				RpcCollection<T::AccountId>,901				// RMRK902				RmrkCollectionInfo<T::AccountId>,903				RmrkInstanceInfo<T::AccountId>,904				RmrkResourceInfo,905				RmrkPropertyInfo,906				RmrkBaseInfo<T::AccountId>,907				RmrkPartType,908				RmrkBoundedTheme,909				RmrkNftChild,910				// PoV Estimate Info911				PovInfo,912			)>,913		),914		QueryKind = OptionQuery,915	>;916917	#[pallet::hooks]918	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {919		fn on_runtime_upgrade() -> Weight {920			StorageVersion::new(1).put::<Pallet<T>>();921922			Weight::zero()923		}924	}925}926927impl<T: Config> Pallet<T> {928	/// Enshure that receiver address is correct.929	///930	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.931	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {932		ensure!(933			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,934			<Error<T>>::AddressIsZero935		);936		Ok(())937	}938939	/// Get a vector of collection admins.940	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {941		<IsAdmin<T>>::iter_prefix((collection,))942			.map(|(a, _)| a)943			.collect()944	}945946	/// Get a vector of users allowed to mint tokens.947	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {948		<Allowlist<T>>::iter_prefix((collection,))949			.map(|(a, _)| a)950			.collect()951	}952953	/// Is `user` allowed to mint token in `collection`.954	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {955		<Allowlist<T>>::get((collection, user))956	}957958	/// Get statistics of collections.959	pub fn collection_stats() -> CollectionStats {960		let created = <CreatedCollectionCount<T>>::get();961		let destroyed = <DestroyedCollectionCount<T>>::get();962		CollectionStats {963			created: created.0,964			destroyed: destroyed.0,965			alive: created.0 - destroyed.0,966		}967	}968969	/// Get the effective limits for the collection.970	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {971		let collection = <CollectionById<T>>::get(collection)?;972		let limits = collection.limits;973		let effective_limits = CollectionLimits {974			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),975			sponsored_data_size: Some(limits.sponsored_data_size()),976			sponsored_data_rate_limit: Some(977				limits978					.sponsored_data_rate_limit979					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),980			),981			token_limit: Some(limits.token_limit()),982			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(983				match collection.mode {984					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,985					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,986					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,987				},988			)),989			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),990			owner_can_transfer: Some(limits.owner_can_transfer()),991			owner_can_destroy: Some(limits.owner_can_destroy()),992			transfers_enabled: Some(limits.transfers_enabled()),993		};994995		Some(effective_limits)996	}997998	/// Returns information about the `collection` adapted for rpc.999	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {1000		let Collection {1001			name,1002			description,1003			owner,1004			mode,1005			token_prefix,1006			sponsorship,1007			limits,1008			permissions,1009			flags,1010		} = <CollectionById<T>>::get(collection)?;10111012		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)1013			.into_iter()1014			.map(|(key, permission)| PropertyKeyPermission { key, permission })1015			.collect();10161017		let properties = <CollectionProperties<T>>::get(collection)1018			.into_iter()1019			.map(|(key, value)| Property { key, value })1020			.collect();10211022		let permissions = CollectionPermissions {1023			access: Some(permissions.access()),1024			mint_mode: Some(permissions.mint_mode()),1025			nesting: Some(permissions.nesting().clone()),1026		};10271028		Some(RpcCollection {1029			name: name.into_inner(),1030			description: description.into_inner(),1031			owner,1032			mode,1033			token_prefix: token_prefix.into_inner(),1034			sponsorship,1035			limits,1036			permissions,1037			token_property_permissions,1038			properties,1039			read_only: flags.external,10401041			flags: RpcCollectionFlags {1042				foreign: flags.foreign,1043				erc721metadata: flags.erc721metadata,1044			},1045		})1046	}1047}10481049macro_rules! limit_default {1050	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1051		$(1052			if let Some($new) = $new.$field {1053				let $old = $old.$field($($arg)?);1054				let _ = $new;1055				let _ = $old;1056				$check1057			} else {1058				$new.$field = $old.$field1059			}1060		)*1061	}};1062}1063macro_rules! limit_default_clone {1064	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1065		$(1066			if let Some($new) = $new.$field.clone() {1067				let $old = $old.$field($($arg)?);1068				let _ = $new;1069				let _ = $old;1070				$check1071			} else {1072				$new.$field = $old.$field.clone()1073			}1074		)*1075	}};1076}10771078impl<T: Config> Pallet<T> {1079	/// Create new collection.1080	///1081	/// * `owner` - The owner of the collection.1082	/// * `data` - Description of the created collection.1083	/// * `flags` - Extra flags to store.1084	pub fn init_collection(1085		owner: T::CrossAccountId,1086		payer: T::CrossAccountId,1087		data: CreateCollectionData<T::AccountId>,1088		flags: CollectionFlags,1089	) -> Result<CollectionId, DispatchError> {1090		{1091			ensure!(1092				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1093				Error::<T>::CollectionTokenPrefixLimitExceeded1094			);1095		}10961097		let created_count = <CreatedCollectionCount<T>>::get()1098			.01099			.checked_add(1)1100			.ok_or(ArithmeticError::Overflow)?;1101		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1102		let id = CollectionId(created_count);11031104		// bound Total number of collections1105		ensure!(1106			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1107			<Error<T>>::TotalCollectionsLimitExceeded1108		);11091110		// =========11111112		let collection = Collection {1113			owner: owner.as_sub().clone(),1114			name: data.name,1115			mode: data.mode.clone(),1116			description: data.description,1117			token_prefix: data.token_prefix,1118			sponsorship: data1119				.pending_sponsor1120				.map(SponsorshipState::Unconfirmed)1121				.unwrap_or_default(),1122			limits: data1123				.limits1124				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1125				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,1126			permissions: data1127				.permissions1128				.map(|permissions| {1129					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1130				})1131				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1132			flags,1133		};11341135		let mut collection_properties = up_data_structs::CollectionProperties::get();1136		collection_properties1137			.try_set_from_iter(data.properties.into_iter())1138			.map_err(<Error<T>>::from)?;11391140		CollectionProperties::<T>::insert(id, collection_properties);11411142		let mut token_props_permissions = PropertiesPermissionMap::new();1143		token_props_permissions1144			.try_set_from_iter(data.token_property_permissions.into_iter())1145			.map_err(<Error<T>>::from)?;11461147		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11481149		// Take a (non-refundable) deposit of collection creation1150		{1151			let mut imbalance =1152				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1153			imbalance.subsume(1154				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1155					&T::TreasuryAccountId::get(),1156					T::CollectionCreationPrice::get(),1157				),1158			);1159			<T as Config>::Currency::settle(1160				payer.as_sub(),1161				imbalance,1162				WithdrawReasons::TRANSFER,1163				ExistenceRequirement::KeepAlive,1164			)1165			.map_err(|_| Error::<T>::NotSufficientFounds)?;1166		}11671168		<CreatedCollectionCount<T>>::put(created_count);1169		<Pallet<T>>::deposit_event(Event::CollectionCreated(1170			id,1171			data.mode.id(),1172			owner.as_sub().clone(),1173		));1174		<PalletEvm<T>>::deposit_log(1175			erc::CollectionHelpersEvents::CollectionCreated {1176				owner: *owner.as_eth(),1177				collection_id: eth::collection_id_to_address(id),1178			}1179			.to_log(T::ContractAddress::get()),1180		);1181		<CollectionById<T>>::insert(id, collection);1182		Ok(id)1183	}11841185	/// Destroy collection.1186	///1187	/// * `collection` - Collection handler.1188	/// * `sender` - The owner or administrator of the collection.1189	pub fn destroy_collection(1190		collection: CollectionHandle<T>,1191		sender: &T::CrossAccountId,1192	) -> DispatchResult {1193		ensure!(1194			collection.limits.owner_can_destroy(),1195			<Error<T>>::NoPermission,1196		);1197		collection.check_is_owner(sender)?;11981199		let destroyed_collections = <DestroyedCollectionCount<T>>::get()1200			.01201			.checked_add(1)1202			.ok_or(ArithmeticError::Overflow)?;12031204		// =========12051206		<DestroyedCollectionCount<T>>::put(destroyed_collections);1207		<CollectionById<T>>::remove(collection.id);1208		<AdminAmount<T>>::remove(collection.id);1209		let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1210		let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1211		<CollectionProperties<T>>::remove(collection.id);12121213		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));12141215		<PalletEvm<T>>::deposit_log(1216			erc::CollectionHelpersEvents::CollectionDestroyed {1217				collection_id: eth::collection_id_to_address(collection.id),1218			}1219			.to_log(T::ContractAddress::get()),1220		);1221		Ok(())1222	}12231224	/// This function sets or removes a collection properties according to1225	/// `properties_updates` contents:1226	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1227	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1228	///1229	/// This function fires an event for each property change.1230	/// In case of an error, all the changes (including the events) will be reverted1231	/// since the function is transactional.1232	#[transactional]1233	fn modify_collection_properties(1234		collection: &CollectionHandle<T>,1235		sender: &T::CrossAccountId,1236		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1237	) -> DispatchResult {1238		collection.check_is_owner_or_admin(sender)?;12391240		let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12411242		for (key, value) in properties_updates {1243			match value {1244				Some(value) => {1245					stored_properties1246						.try_set(key.clone(), value)1247						.map_err(<Error<T>>::from)?;12481249					Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1250					<PalletEvm<T>>::deposit_log(1251						erc::CollectionHelpersEvents::CollectionChanged {1252							collection_id: eth::collection_id_to_address(collection.id),1253						}1254						.to_log(T::ContractAddress::get()),1255					);1256				}1257				None => {1258					stored_properties.remove(&key).map_err(<Error<T>>::from)?;12591260					Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1261					<PalletEvm<T>>::deposit_log(1262						erc::CollectionHelpersEvents::CollectionChanged {1263							collection_id: eth::collection_id_to_address(collection.id),1264						}1265						.to_log(T::ContractAddress::get()),1266					);1267				}1268			}1269		}12701271		<CollectionProperties<T>>::set(collection.id, stored_properties);12721273		Ok(())1274	}12751276	/// A batch operation to add, edit or remove properties for a token.1277	/// It sets or removes a token's properties according to1278	/// `properties_updates` contents:1279	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1280	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1281	///1282	/// - `nesting_budget`: Limit for searching parents in-depth to check ownership.1283	/// - `is_token_create`: Indicates that method is called during token initialization.1284	///   Allows to bypass ownership check.1285	///1286	/// All affected properties should have `mutable` permission1287	/// to be **deleted** or to be **set more than once**,1288	/// and the sender should have permission to edit those properties.1289	///1290	/// This function fires an event for each property change.1291	/// In case of an error, all the changes (including the events) will be reverted1292	/// since the function is transactional.1293	pub fn modify_token_properties(1294		collection: &CollectionHandle<T>,1295		sender: &T::CrossAccountId,1296		token_id: TokenId,1297		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1298		is_token_create: bool,1299		mut stored_properties: Properties,1300		is_token_owner: impl Fn() -> Result<bool, DispatchError>,1301		set_token_properties: impl FnOnce(Properties),1302	) -> DispatchResult {1303		let is_collection_admin = collection.is_owner_or_admin(sender);1304		let permissions = Self::property_permissions(collection.id);13051306		let mut token_owner_result = None;1307		let mut is_token_owner = || -> Result<bool, DispatchError> {1308			*token_owner_result.get_or_insert_with(&is_token_owner)1309		};13101311		for (key, value) in properties_updates {1312			let permission = permissions1313				.get(&key)1314				.cloned()1315				.unwrap_or_else(PropertyPermission::none);13161317			let is_property_exists = stored_properties.get(&key).is_some();13181319			match permission {1320				PropertyPermission { mutable: false, .. } if is_property_exists => {1321					return Err(<Error<T>>::NoPermission.into());1322				}13231324				PropertyPermission {1325					collection_admin,1326					token_owner,1327					..1328				} => {1329					//TODO: investigate threats during public minting.1330					let is_token_create =1331						is_token_create && (collection_admin || token_owner) && value.is_some();1332					if !(is_token_create1333						|| (collection_admin && is_collection_admin)1334						|| (token_owner && is_token_owner()?))1335					{1336						fail!(<Error<T>>::NoPermission);1337					}1338				}1339			}13401341			match value {1342				Some(value) => {1343					stored_properties1344						.try_set(key.clone(), value)1345						.map_err(<Error<T>>::from)?;13461347					Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));1348				}1349				None => {1350					stored_properties.remove(&key).map_err(<Error<T>>::from)?;13511352					Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));1353				}1354			}13551356			<PalletEvm<T>>::deposit_log(1357				CollectionHelpersEvents::TokenChanged {1358					collection_id: eth::collection_id_to_address(collection.id),1359					token_id: token_id.into(),1360				}1361				.to_log(T::ContractAddress::get()),1362			);1363		}13641365		set_token_properties(stored_properties);13661367		Ok(())1368	}13691370	/// Sets or unsets the approval of a given operator.1371	///1372	/// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1373	/// - `owner`: Token owner1374	/// - `operator`: Operator1375	/// - `approve`: Should operator status be granted or revoked?1376	pub fn set_allowance_for_all(1377		collection: &CollectionHandle<T>,1378		owner: &T::CrossAccountId,1379		operator: &T::CrossAccountId,1380		approve: bool,1381		set_allowance: impl FnOnce(),1382		log: evm_coder::ethereum::Log,1383	) -> DispatchResult {1384		if collection.permissions.access() == AccessMode::AllowList {1385			collection.check_allowlist(owner)?;1386			collection.check_allowlist(operator)?;1387		}13881389		Self::ensure_correct_receiver(operator)?;13901391		set_allowance();13921393		<PalletEvm<T>>::deposit_log(log);1394		Self::deposit_event(Event::ApprovedForAll(1395			collection.id,1396			owner.clone(),1397			operator.clone(),1398			approve,1399		));1400		Ok(())1401	}14021403	/// Set collection property.1404	///1405	/// * `collection` - Collection handler.1406	/// * `sender` - The owner or administrator of the collection.1407	/// * `property` - The property to set.1408	pub fn set_collection_property(1409		collection: &CollectionHandle<T>,1410		sender: &T::CrossAccountId,1411		property: Property,1412	) -> DispatchResult {1413		Self::set_collection_properties(collection, sender, [property].into_iter())1414	}14151416	/// Set a scoped collection property, where the scope is a special prefix1417	/// prohibiting a user access to change the property directly.1418	///1419	/// * `collection_id` - ID of the collection for which the property is being set.1420	/// * `scope` - Property scope.1421	/// * `property` - The property to set.1422	pub fn set_scoped_collection_property(1423		collection_id: CollectionId,1424		scope: PropertyScope,1425		property: Property,1426	) -> DispatchResult {1427		CollectionProperties::<T>::try_mutate(collection_id, |properties| {1428			properties.try_scoped_set(scope, property.key, property.value)1429		})1430		.map_err(<Error<T>>::from)?;14311432		Ok(())1433	}14341435	/// Set scoped collection properties, where the scope is a special prefix1436	/// prohibiting a user access to change the properties directly.1437	///1438	/// * `collection_id` - ID of the collection for which the properties is being set.1439	/// * `scope` - Property scope.1440	/// * `properties` - The properties to set.1441	pub fn set_scoped_collection_properties(1442		collection_id: CollectionId,1443		scope: PropertyScope,1444		properties: impl Iterator<Item = Property>,1445	) -> DispatchResult {1446		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1447			stored_properties.try_scoped_set_from_iter(scope, properties)1448		})1449		.map_err(<Error<T>>::from)?;14501451		Ok(())1452	}14531454	/// Set collection properties.1455	///1456	/// * `collection` - Collection handler.1457	/// * `sender` - The owner or administrator of the collection.1458	/// * `properties` - The properties to set.1459	pub fn set_collection_properties(1460		collection: &CollectionHandle<T>,1461		sender: &T::CrossAccountId,1462		properties: impl Iterator<Item = Property>,1463	) -> DispatchResult {1464		Self::modify_collection_properties(1465			collection,1466			sender,1467			properties.map(|property| (property.key, Some(property.value))),1468		)1469	}14701471	/// Delete collection property.1472	///1473	/// * `collection` - Collection handler.1474	/// * `sender` - The owner or administrator of the collection.1475	/// * `property` - The property to delete.1476	pub fn delete_collection_property(1477		collection: &CollectionHandle<T>,1478		sender: &T::CrossAccountId,1479		property_key: PropertyKey,1480	) -> DispatchResult {1481		Self::delete_collection_properties(collection, sender, [property_key].into_iter())1482	}14831484	/// Delete collection properties.1485	///1486	/// * `collection` - Collection handler.1487	/// * `sender` - The owner or administrator of the collection.1488	/// * `properties` - The properties to delete.1489	pub fn delete_collection_properties(1490		collection: &CollectionHandle<T>,1491		sender: &T::CrossAccountId,1492		property_keys: impl Iterator<Item = PropertyKey>,1493	) -> DispatchResult {1494		Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1495	}14961497	/// Set collection propetry permission without any checks.1498	///1499	/// Used for migrations.1500	///1501	/// * `collection` - Collection handler.1502	/// * `property_permissions` - Property permissions.1503	pub fn set_property_permission_unchecked(1504		collection: CollectionId,1505		property_permission: PropertyKeyPermission,1506	) -> DispatchResult {1507		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1508			permissions.try_set(property_permission.key, property_permission.permission)1509		})1510		.map_err(<Error<T>>::from)?;1511		Ok(())1512	}15131514	/// Set collection property permission.1515	///1516	/// * `collection` - Collection handler.1517	/// * `sender` - The owner or administrator of the collection.1518	/// * `property_permission` - Property permission.1519	pub fn set_property_permission(1520		collection: &CollectionHandle<T>,1521		sender: &T::CrossAccountId,1522		property_permission: PropertyKeyPermission,1523	) -> DispatchResult {1524		Self::set_scoped_property_permission(1525			collection,1526			sender,1527			PropertyScope::None,1528			property_permission,1529		)1530	}15311532	/// Set collection property permission with scope.1533	///1534	/// * `collection` - Collection handler.1535	/// * `sender` - The owner or administrator of the collection.1536	/// * `scope` - Property scope.1537	/// * `property_permission` - Property permission.1538	pub fn set_scoped_property_permission(1539		collection: &CollectionHandle<T>,1540		sender: &T::CrossAccountId,1541		scope: PropertyScope,1542		property_permission: PropertyKeyPermission,1543	) -> DispatchResult {1544		collection.check_is_owner_or_admin(sender)?;15451546		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1547		let current_permission = all_permissions.get(&property_permission.key);1548		if matches![1549			current_permission,1550			Some(PropertyPermission { mutable: false, .. })1551		] {1552			return Err(<Error<T>>::NoPermission.into());1553		}15541555		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1556			let property_permission = property_permission.clone();1557			permissions.try_scoped_set(1558				scope,1559				property_permission.key,1560				property_permission.permission,1561			)1562		})1563		.map_err(<Error<T>>::from)?;15641565		Self::deposit_event(Event::PropertyPermissionSet(1566			collection.id,1567			property_permission.key,1568		));1569		<PalletEvm<T>>::deposit_log(1570			erc::CollectionHelpersEvents::CollectionChanged {1571				collection_id: eth::collection_id_to_address(collection.id),1572			}1573			.to_log(T::ContractAddress::get()),1574		);15751576		Ok(())1577	}15781579	/// Set token property permission.1580	///1581	/// * `collection` - Collection handler.1582	/// * `sender` - The owner or administrator of the collection.1583	/// * `property_permissions` - Property permissions.1584	#[transactional]1585	pub fn set_token_property_permissions(1586		collection: &CollectionHandle<T>,1587		sender: &T::CrossAccountId,1588		property_permissions: Vec<PropertyKeyPermission>,1589	) -> DispatchResult {1590		Self::set_scoped_token_property_permissions(1591			collection,1592			sender,1593			PropertyScope::None,1594			property_permissions,1595		)1596	}15971598	/// Set token property permission with scope.1599	///1600	/// * `collection` - Collection handler.1601	/// * `sender` - The owner or administrator of the collection.1602	/// * `scope` - Property scope.1603	/// * `property_permissions` - Property permissions.1604	#[transactional]1605	pub fn set_scoped_token_property_permissions(1606		collection: &CollectionHandle<T>,1607		sender: &T::CrossAccountId,1608		scope: PropertyScope,1609		property_permissions: Vec<PropertyKeyPermission>,1610	) -> DispatchResult {1611		for prop_pemission in property_permissions {1612			Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1613		}16141615		Ok(())1616	}16171618	/// Get collection property.1619	pub fn get_collection_property(1620		collection_id: CollectionId,1621		key: &PropertyKey,1622	) -> Option<PropertyValue> {1623		Self::collection_properties(collection_id).get(key).cloned()1624	}16251626	/// Convert byte vector to property key vector.1627	pub fn bytes_keys_to_property_keys(1628		keys: Vec<Vec<u8>>,1629	) -> Result<Vec<PropertyKey>, DispatchError> {1630		keys.into_iter()1631			.map(|key| -> Result<PropertyKey, DispatchError> {1632				key.try_into()1633					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1634			})1635			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1636	}16371638	/// Get properties according to given keys.1639	pub fn filter_collection_properties(1640		collection_id: CollectionId,1641		keys: Option<Vec<PropertyKey>>,1642	) -> Result<Vec<Property>, DispatchError> {1643		let properties = Self::collection_properties(collection_id);16441645		let properties = keys1646			.map(|keys| {1647				keys.into_iter()1648					.filter_map(|key| {1649						properties.get(&key).map(|value| Property {1650							key,1651							value: value.clone(),1652						})1653					})1654					.collect()1655			})1656			.unwrap_or_else(|| {1657				properties1658					.into_iter()1659					.map(|(key, value)| Property { key, value })1660					.collect()1661			});16621663		Ok(properties)1664	}16651666	/// Get property permissions according to given keys.1667	pub fn filter_property_permissions(1668		collection_id: CollectionId,1669		keys: Option<Vec<PropertyKey>>,1670	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1671		let permissions = Self::property_permissions(collection_id);16721673		let key_permissions = keys1674			.map(|keys| {1675				keys.into_iter()1676					.filter_map(|key| {1677						permissions1678							.get(&key)1679							.map(|permission| PropertyKeyPermission {1680								key,1681								permission: permission.clone(),1682							})1683					})1684					.collect()1685			})1686			.unwrap_or_else(|| {1687				permissions1688					.into_iter()1689					.map(|(key, permission)| PropertyKeyPermission { key, permission })1690					.collect()1691			});16921693		Ok(key_permissions)1694	}16951696	/// Toggle `user` participation in the `collection`'s allow list.1697	/// #### Store read/writes1698	/// 1 writes1699	pub fn toggle_allowlist(1700		collection: &CollectionHandle<T>,1701		sender: &T::CrossAccountId,1702		user: &T::CrossAccountId,1703		allowed: bool,1704	) -> DispatchResult {1705		collection.check_is_owner_or_admin(sender)?;17061707		// =========17081709		if allowed {1710			<Allowlist<T>>::insert((collection.id, user), true);1711			Self::deposit_event(Event::<T>::AllowListAddressAdded(1712				collection.id,1713				user.clone(),1714			));1715		} else {1716			<Allowlist<T>>::remove((collection.id, user));1717			Self::deposit_event(Event::<T>::AllowListAddressRemoved(1718				collection.id,1719				user.clone(),1720			));1721		}17221723		<PalletEvm<T>>::deposit_log(1724			erc::CollectionHelpersEvents::CollectionChanged {1725				collection_id: eth::collection_id_to_address(collection.id),1726			}1727			.to_log(T::ContractAddress::get()),1728		);17291730		Ok(())1731	}17321733	/// Toggle `user` participation in the `collection`'s admin list.1734	/// #### Store read/writes1735	/// 2 reads, 2 writes1736	pub fn toggle_admin(1737		collection: &CollectionHandle<T>,1738		sender: &T::CrossAccountId,1739		user: &T::CrossAccountId,1740		admin: bool,1741	) -> DispatchResult {1742		collection.check_is_internal()?;1743		collection.check_is_owner(sender)?;17441745		let is_admin = <IsAdmin<T>>::get((collection.id, user));1746		if is_admin == admin {1747			if admin {1748				return Ok(());1749			} else {1750				return Err(Error::<T>::UserIsNotCollectionAdmin.into());1751			}1752		}1753		let amount = <AdminAmount<T>>::get(collection.id);17541755		// =========17561757		if admin {1758			let amount = amount1759				.checked_add(1)1760				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1761			ensure!(1762				amount <= Self::collection_admins_limit(),1763				<Error<T>>::CollectionAdminCountExceeded,1764			);17651766			<AdminAmount<T>>::insert(collection.id, amount);1767			<IsAdmin<T>>::insert((collection.id, user), true);17681769			Self::deposit_event(Event::<T>::CollectionAdminAdded(1770				collection.id,1771				user.clone(),1772			));1773		} else {1774			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1775			<IsAdmin<T>>::remove((collection.id, user));17761777			Self::deposit_event(Event::<T>::CollectionAdminRemoved(1778				collection.id,1779				user.clone(),1780			));1781		}17821783		<PalletEvm<T>>::deposit_log(1784			erc::CollectionHelpersEvents::CollectionChanged {1785				collection_id: eth::collection_id_to_address(collection.id),1786			}1787			.to_log(T::ContractAddress::get()),1788		);17891790		Ok(())1791	}17921793	/// Update collection limits.1794	pub fn update_limits(1795		user: &T::CrossAccountId,1796		collection: &mut CollectionHandle<T>,1797		new_limit: CollectionLimits,1798	) -> DispatchResult {1799		collection.check_is_internal()?;1800		collection.check_is_owner_or_admin(user)?;18011802		collection.limits =1803			Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;18041805		Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1806		<PalletEvm<T>>::deposit_log(1807			erc::CollectionHelpersEvents::CollectionChanged {1808				collection_id: eth::collection_id_to_address(collection.id),1809			}1810			.to_log(T::ContractAddress::get()),1811		);18121813		collection.save()1814	}18151816	/// Merge set fields from `new_limit` to `old_limit`.1817	fn clamp_limits(1818		mode: CollectionMode,1819		old_limit: &CollectionLimits,1820		mut new_limit: CollectionLimits,1821	) -> Result<CollectionLimits, DispatchError> {1822		let limits = old_limit;1823		limit_default!(old_limit, new_limit,1824			account_token_ownership_limit => ensure!(1825				new_limit <= MAX_TOKEN_OWNERSHIP,1826				<Error<T>>::CollectionLimitBoundsExceeded,1827			),1828			sponsored_data_size => ensure!(1829				new_limit <= CUSTOM_DATA_LIMIT,1830				<Error<T>>::CollectionLimitBoundsExceeded,1831			),18321833			sponsored_data_rate_limit => {},1834			token_limit => ensure!(1835				old_limit >= new_limit && new_limit > 0,1836				<Error<T>>::CollectionTokenLimitExceeded1837			),18381839			sponsor_transfer_timeout(match mode {1840				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1841				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1842				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1843			}) => ensure!(1844				new_limit <= MAX_SPONSOR_TIMEOUT,1845				<Error<T>>::CollectionLimitBoundsExceeded,1846			),1847			sponsor_approve_timeout => {},1848			owner_can_transfer => ensure!(1849				!limits.owner_can_transfer_instaled() ||1850				old_limit || !new_limit,1851				<Error<T>>::OwnerPermissionsCantBeReverted,1852			),1853			owner_can_destroy => ensure!(1854				old_limit || !new_limit,1855				<Error<T>>::OwnerPermissionsCantBeReverted,1856			),1857			transfers_enabled => {},1858		);1859		Ok(new_limit)1860	}18611862	/// Update collection permissions.1863	pub fn update_permissions(1864		user: &T::CrossAccountId,1865		collection: &mut CollectionHandle<T>,1866		new_permission: CollectionPermissions,1867	) -> DispatchResult {1868		collection.check_is_internal()?;1869		collection.check_is_owner_or_admin(user)?;1870		collection.permissions = Self::clamp_permissions(1871			collection.mode.clone(),1872			&collection.permissions,1873			new_permission,1874		)?;18751876		Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1877		<PalletEvm<T>>::deposit_log(1878			erc::CollectionHelpersEvents::CollectionChanged {1879				collection_id: eth::collection_id_to_address(collection.id),1880			}1881			.to_log(T::ContractAddress::get()),1882		);18831884		collection.save()1885	}18861887	/// Merge set fields from `new_permission` to `old_permission`.1888	fn clamp_permissions(1889		_mode: CollectionMode,1890		old_permission: &CollectionPermissions,1891		mut new_permission: CollectionPermissions,1892	) -> Result<CollectionPermissions, DispatchError> {1893		limit_default_clone!(old_permission, new_permission,1894			access => {},1895			mint_mode => {},1896			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1897		);1898		Ok(new_permission)1899	}19001901	/// Repair possibly broken properties of a collection.1902	pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1903		CollectionProperties::<T>::mutate(collection_id, |properties| {1904			properties.recompute_consumed_space();1905		});19061907		Ok(())1908	}1909}19101911/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1912#[macro_export]1913macro_rules! unsupported {1914	($runtime:path) => {1915		Err($crate::Error::<$runtime>::UnsupportedOperation.into())1916	};1917}19181919/// Return weights for various worst-case operations.1920pub trait CommonWeightInfo<CrossAccountId> {1921	/// Weight of item creation.1922	fn create_item(data: &CreateItemData) -> Weight {1923		Self::create_multiple_items(from_ref(data))1924	}19251926	/// Weight of items creation.1927	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;19281929	/// Weight of items creation.1930	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;19311932	/// The weight of the burning item.1933	fn burn_item() -> Weight;19341935	/// Property setting weight.1936	///1937	/// * `amount`- The number of properties to set.1938	fn set_collection_properties(amount: u32) -> Weight;19391940	/// Collection property deletion weight.1941	///1942	/// * `amount`- The number of properties to set.1943	fn delete_collection_properties(amount: u32) -> Weight;19441945	/// Token property setting weight.1946	///1947	/// * `amount`- The number of properties to set.1948	fn set_token_properties(amount: u32) -> Weight;19491950	/// Token property deletion weight.1951	///1952	/// * `amount`- The number of properties to delete.1953	fn delete_token_properties(amount: u32) -> Weight;19541955	/// Token property permissions set weight.1956	///1957	/// * `amount`- The number of property permissions to set.1958	fn set_token_property_permissions(amount: u32) -> Weight;19591960	/// Transfer price of the token or its parts.1961	fn transfer() -> Weight;19621963	/// The price of setting the permission of the operation from another user.1964	fn approve() -> Weight;19651966	/// The price of setting the permission of the operation from another user for eth mirror.1967	fn approve_from() -> Weight;19681969	/// Transfer price from another user.1970	fn transfer_from() -> Weight;19711972	/// The price of burning a token from another user.1973	fn burn_from() -> Weight;19741975	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1976	/// whole users's balance.1977	///1978	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1979	fn burn_recursively_self_raw() -> Weight;19801981	/// Cost of iterating over `amount` children while burning, without counting child burning itself.1982	///1983	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1984	fn burn_recursively_breadth_raw(amount: u32) -> Weight;19851986	/// The price of recursive burning a token.1987	///1988	/// `max_selfs` - The maximum burning weight of the token itself.1989	/// `max_breadth` - The maximum number of nested tokens to burn.1990	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1991		Self::burn_recursively_self_raw()1992			.saturating_mul(max_selfs.max(1) as u64)1993			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1994	}19951996	/// The price of retrieving token owner1997	fn token_owner() -> Weight;19981999	/// The price of setting approval for all2000	fn set_allowance_for_all() -> Weight;20012002	/// The price of repairing an item.2003	fn force_repair_item() -> Weight;2004}20052006/// Weight info extension trait for refungible pallet.2007pub trait RefungibleExtensionsWeightInfo {2008	/// Weight of token repartition.2009	fn repartition() -> Weight;2010}20112012/// Common collection operations.2013///2014/// It wraps methods in Fungible, Nonfungible and Refungible pallets2015/// and adds weight info.2016pub trait CommonCollectionOperations<T: Config> {2017	/// Create token.2018	///2019	/// * `sender` - The user who mint the token and pays for the transaction.2020	/// * `to` - The user who will own the token.2021	/// * `data` - Token data.2022	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2023	fn create_item(2024		&self,2025		sender: T::CrossAccountId,2026		to: T::CrossAccountId,2027		data: CreateItemData,2028		nesting_budget: &dyn Budget,2029	) -> DispatchResultWithPostInfo;20302031	/// Create multiple tokens.2032	///2033	/// * `sender` - The user who mint the token and pays for the transaction.2034	/// * `to` - The user who will own the token.2035	/// * `data` - Token data.2036	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2037	fn create_multiple_items(2038		&self,2039		sender: T::CrossAccountId,2040		to: T::CrossAccountId,2041		data: Vec<CreateItemData>,2042		nesting_budget: &dyn Budget,2043	) -> DispatchResultWithPostInfo;20442045	/// Create multiple tokens.2046	///2047	/// * `sender` - The user who mint the token and pays for the transaction.2048	/// * `to` - The user who will own the token.2049	/// * `data` - Token data.2050	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2051	fn create_multiple_items_ex(2052		&self,2053		sender: T::CrossAccountId,2054		data: CreateItemExData<T::CrossAccountId>,2055		nesting_budget: &dyn Budget,2056	) -> DispatchResultWithPostInfo;20572058	/// Burn token.2059	///2060	/// * `sender` - The user who owns the token.2061	/// * `token` - Token id that will burned.2062	/// * `amount` - The number of parts of the token that will be burned.2063	fn burn_item(2064		&self,2065		sender: T::CrossAccountId,2066		token: TokenId,2067		amount: u128,2068	) -> DispatchResultWithPostInfo;20692070	/// Burn token and all nested tokens recursievly.2071	///2072	/// * `sender` - The user who owns the token.2073	/// * `token` - Token id that will burned.2074	/// * `self_budget` - The budget that can be spent on burning tokens.2075	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.2076	fn burn_item_recursively(2077		&self,2078		sender: T::CrossAccountId,2079		token: TokenId,2080		self_budget: &dyn Budget,2081		breadth_budget: &dyn Budget,2082	) -> DispatchResultWithPostInfo;20832084	/// Set collection properties.2085	///2086	/// * `sender` - Must be either the owner of the collection or its admin.2087	/// * `properties` - Properties to be set.2088	fn set_collection_properties(2089		&self,2090		sender: T::CrossAccountId,2091		properties: Vec<Property>,2092	) -> DispatchResultWithPostInfo;20932094	/// Delete collection properties.2095	///2096	/// * `sender` - Must be either the owner of the collection or its admin.2097	/// * `properties` - The properties to be removed.2098	fn delete_collection_properties(2099		&self,2100		sender: &T::CrossAccountId,2101		property_keys: Vec<PropertyKey>,2102	) -> DispatchResultWithPostInfo;21032104	/// Set token properties.2105	///2106	/// The appropriate [`PropertyPermission`] for the token property2107	/// must be set with [`Self::set_token_property_permissions`].2108	///2109	/// * `sender` - Must be either the owner of the token or its admin.2110	/// * `token_id` - The token for which the properties are being set.2111	/// * `properties` - Properties to be set.2112	/// * `budget` - Budget for setting properties.2113	fn set_token_properties(2114		&self,2115		sender: T::CrossAccountId,2116		token_id: TokenId,2117		properties: Vec<Property>,2118		budget: &dyn Budget,2119	) -> DispatchResultWithPostInfo;21202121	/// Remove token properties.2122	///2123	/// The appropriate [`PropertyPermission`] for the token property2124	/// must be set with [`Self::set_token_property_permissions`].2125	///2126	/// * `sender` - Must be either the owner of the token or its admin.2127	/// * `token_id` - The token for which the properties are being remove.2128	/// * `property_keys` - Keys to remove corresponding properties.2129	/// * `budget` - Budget for removing properties.2130	fn delete_token_properties(2131		&self,2132		sender: T::CrossAccountId,2133		token_id: TokenId,2134		property_keys: Vec<PropertyKey>,2135		budget: &dyn Budget,2136	) -> DispatchResultWithPostInfo;21372138	/// Set token property permissions.2139	///2140	/// * `sender` - Must be either the owner of the token or its admin.2141	/// * `token_id` - The token for which the properties are being set.2142	/// * `property_permissions` - Property permissions to be set.2143	/// * `budget` - Budget for setting properties.2144	fn set_token_property_permissions(2145		&self,2146		sender: &T::CrossAccountId,2147		property_permissions: Vec<PropertyKeyPermission>,2148	) -> DispatchResultWithPostInfo;21492150	/// Transfer amount of token pieces.2151	///2152	/// * `sender` - Donor user.2153	/// * `to` - Recepient user.2154	/// * `token` - The token of which parts are being sent.2155	/// * `amount` - The number of parts of the token that will be transferred.2156	/// * `budget` - The maximum budget that can be spent on the transfer.2157	fn transfer(2158		&self,2159		sender: T::CrossAccountId,2160		to: T::CrossAccountId,2161		token: TokenId,2162		amount: u128,2163		budget: &dyn Budget,2164	) -> DispatchResultWithPostInfo;21652166	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2167	///2168	/// * `sender` - The user who grants access to the token.2169	/// * `spender` - The user to whom the rights are granted.2170	/// * `token` - The token to which access is granted.2171	/// * `amount` - The amount of pieces that another user can dispose of.2172	fn approve(2173		&self,2174		sender: T::CrossAccountId,2175		spender: T::CrossAccountId,2176		token: TokenId,2177		amount: u128,2178	) -> DispatchResultWithPostInfo;21792180	/// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2181	///2182	/// * `sender` - The user who grants access to the token.2183	/// * `from` - Spender's eth mirror.2184	/// * `to` - The user to whom the rights are granted.2185	/// * `token` - The token to which access is granted.2186	/// * `amount` - The amount of pieces that another user can dispose of.2187	fn approve_from(2188		&self,2189		sender: T::CrossAccountId,2190		from: T::CrossAccountId,2191		to: T::CrossAccountId,2192		token: TokenId,2193		amount: u128,2194	) -> DispatchResultWithPostInfo;21952196	/// Send parts of a token owned by another user.2197	///2198	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2199	///2200	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2201	/// * `from` - The user who owns the token.2202	/// * `to` - Recepient user.2203	/// * `token` - The token of which parts are being sent.2204	/// * `amount` - The number of parts of the token that will be transferred.2205	/// * `budget` - The maximum budget that can be spent on the transfer.2206	fn transfer_from(2207		&self,2208		sender: T::CrossAccountId,2209		from: T::CrossAccountId,2210		to: T::CrossAccountId,2211		token: TokenId,2212		amount: u128,2213		budget: &dyn Budget,2214	) -> DispatchResultWithPostInfo;22152216	/// Burn parts of a token owned by another user.2217	///2218	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2219	///2220	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2221	/// * `from` - The user who owns the token.2222	/// * `token` - The token of which parts are being sent.2223	/// * `amount` - The number of parts of the token that will be transferred.2224	/// * `budget` - The maximum budget that can be spent on the burn.2225	fn burn_from(2226		&self,2227		sender: T::CrossAccountId,2228		from: T::CrossAccountId,2229		token: TokenId,2230		amount: u128,2231		budget: &dyn Budget,2232	) -> DispatchResultWithPostInfo;22332234	/// Check permission to nest token.2235	///2236	/// * `sender` - The user who initiated the check.2237	/// * `from` - The token that is checked for embedding.2238	/// * `under` - Token under which to check.2239	/// * `budget` - The maximum budget that can be spent on the check.2240	fn check_nesting(2241		&self,2242		sender: T::CrossAccountId,2243		from: (CollectionId, TokenId),2244		under: TokenId,2245		budget: &dyn Budget,2246	) -> DispatchResult;22472248	/// Nest one token into another.2249	///2250	/// * `under` - Token holder.2251	/// * `to_nest` - Nested token.2252	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22532254	/// Unnest token.2255	///2256	/// * `under` - Token holder.2257	/// * `to_nest` - Token to unnest.2258	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22592260	/// Get all user tokens.2261	///2262	/// * `account` - Account for which you need to get tokens.2263	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;22642265	/// Get all the tokens in the collection.2266	fn collection_tokens(&self) -> Vec<TokenId>;22672268	/// Check if the token exists.2269	///2270	/// * `token` - Id token to check.2271	fn token_exists(&self, token: TokenId) -> bool;22722273	/// Get the id of the last minted token.2274	fn last_token_id(&self) -> TokenId;22752276	/// Get the owner of the token.2277	///2278	/// * `token` - The token for which you need to find out the owner.2279	fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;22802281	/// Returns 10 tokens owners in no particular order.2282	///2283	/// * `token` - The token for which you need to find out the owners.2284	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;22852286	/// Get the value of the token property by key.2287	///2288	/// * `token` - Token with the property to get.2289	/// * `key` - Property name.2290	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;22912292	/// Get a set of token properties by key vector.2293	///2294	/// * `token` - Token with the property to get.2295	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2296	/// then all properties are returned.2297	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;22982299	/// Amount of unique collection tokens2300	fn total_supply(&self) -> u32;23012302	/// Amount of different tokens account has.2303	///2304	/// * `account` - The account for which need to get the balance.2305	fn account_balance(&self, account: T::CrossAccountId) -> u32;23062307	/// Amount of specific token account have.2308	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;23092310	/// Amount of token pieces2311	fn total_pieces(&self, token: TokenId) -> Option<u128>;23122313	/// Get the number of parts of the token that a trusted user can manage.2314	///2315	/// * `sender` - Trusted user.2316	/// * `spender` - Owner of the token.2317	/// * `token` - The token for which to get the value.2318	fn allowance(2319		&self,2320		sender: T::CrossAccountId,2321		spender: T::CrossAccountId,2322		token: TokenId,2323	) -> u128;23242325	/// Get extension for RFT collection.2326	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;23272328	/// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2329	/// * `owner` - Token owner2330	/// * `operator` - Operator2331	/// * `approve` - Should operator status be granted or revoked?2332	fn set_allowance_for_all(2333		&self,2334		owner: T::CrossAccountId,2335		operator: T::CrossAccountId,2336		approve: bool,2337	) -> DispatchResultWithPostInfo;23382339	/// Tells whether the given `owner` approves the `operator`.2340	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;23412342	/// Repairs a possibly broken item.2343	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2344}23452346/// Extension for RFT collection.2347pub trait RefungibleExtensions<T>2348where2349	T: Config,2350{2351	/// Change the number of parts of the token.2352	///2353	/// When the value changes down, this function is equivalent to burning parts of the token.2354	///2355	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.2356	/// * `token` - The token for which you want to change the number of parts.2357	/// * `amount` - The new value of the parts of the token.2358	fn repartition(2359		&self,2360		sender: &T::CrossAccountId,2361		token: TokenId,2362		amount: u128,2363	) -> DispatchResultWithPostInfo;2364}23652366/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2367///2368/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2369pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2370	let post_info = PostDispatchInfo {2371		actual_weight: Some(weight),2372		pays_fee: Pays::Yes,2373	};2374	match res {2375		Ok(()) => Ok(post_info),2376		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2377	}2378}23792380impl<T: Config> From<PropertiesError> for Error<T> {2381	fn from(error: PropertiesError) -> Self {2382		match error {2383			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2384			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2385			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2386			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2387			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2388		}2389	}2390}
after · pallets/common/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::{57	ops::{Deref, DerefMut},58	slice::from_ref,59};60use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};61use sp_std::vec::Vec;62use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};63use evm_coder::ToLog;64use frame_support::{65	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},66	ensure,67	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},68	dispatch::Pays,69	transactional, fail,70};71use pallet_evm::GasWeightMapping;72use up_data_structs::{73	AccessMode,74	COLLECTION_NUMBER_LIMIT,75	Collection,76	RpcCollection,77	CollectionFlags,78	RpcCollectionFlags,79	CollectionId,80	CreateItemData,81	MAX_TOKEN_PREFIX_LENGTH,82	COLLECTION_ADMINS_LIMIT,83	TokenId,84	TokenChild,85	CollectionStats,86	MAX_TOKEN_OWNERSHIP,87	CollectionMode,88	NFT_SPONSOR_TRANSFER_TIMEOUT,89	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,90	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,91	MAX_SPONSOR_TIMEOUT,92	CUSTOM_DATA_LIMIT,93	CollectionLimits,94	CreateCollectionData,95	SponsorshipState,96	CreateItemExData,97	SponsoringRateLimit,98	budget::Budget,99	PhantomType,100	Property,101	Properties,102	PropertiesPermissionMap,103	PropertyKey,104	PropertyValue,105	PropertyPermission,106	PropertiesError,107	TokenOwnerError,108	PropertyKeyPermission,109	TokenData,110	TrySetProperty,111	PropertyScope,112	CollectionPermissions,113};114use up_pov_estimate_rpc::PovInfo;115116pub use pallet::*;117use sp_core::H160;118use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};119120use crate::erc::CollectionHelpersEvents;121#[cfg(feature = "runtime-benchmarks")]122pub mod benchmarking;123pub mod dispatch;124pub mod erc;125pub mod eth;126pub mod weights;127128/// Weight info.129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]138pub struct CollectionHandle<T: Config> {139	/// Collection id140	pub id: CollectionId,141	collection: Collection<T::AccountId>,142	/// Substrate recorder for counting consumed gas143	pub recorder: SubstrateRecorder<T>,144}145146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {147	fn recorder(&self) -> &SubstrateRecorder<T> {148		&self.recorder149	}150	fn into_recorder(self) -> SubstrateRecorder<T> {151		self.recorder152	}153}154155impl<T: Config> CollectionHandle<T> {156	/// Same as [CollectionHandle::new] but with an explicit gas limit.157	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {158		<CollectionById<T>>::get(id).map(|collection| Self {159			id,160			collection,161			recorder: SubstrateRecorder::new(gas_limit),162		})163	}164165	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].166	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {167		<CollectionById<T>>::get(id).map(|collection| Self {168			id,169			collection,170			recorder,171		})172	}173174	/// Retrives collection data from storage and creates collection handle with default parameters.175	/// If collection not found return `None`176	pub fn new(id: CollectionId) -> Option<Self> {177		Self::new_with_gas_limit(id, u64::MAX)178	}179180	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.181	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {182		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)183	}184185	/// Consume gas for reading.186	pub fn consume_store_reads(187		&self,188		reads: u64,189	) -> pallet_evm_coder_substrate::execution::Result<()> {190		self.recorder191			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(192				<T as frame_system::Config>::DbWeight::get()193					.read194					.saturating_mul(reads),195			)))196	}197198	/// Consume gas for writing.199	pub fn consume_store_writes(200		&self,201		writes: u64,202	) -> pallet_evm_coder_substrate::execution::Result<()> {203		self.recorder204			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(205				<T as frame_system::Config>::DbWeight::get()206					.write207					.saturating_mul(writes),208			)))209	}210211	/// Consume gas for reading and writing.212	pub fn consume_store_reads_and_writes(213		&self,214		reads: u64,215		writes: u64,216	) -> pallet_evm_coder_substrate::execution::Result<()> {217		let weight = <T as frame_system::Config>::DbWeight::get();218		let reads = weight.read.saturating_mul(reads);219		let writes = weight.read.saturating_mul(writes);220		self.recorder221			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(222				reads.saturating_add(writes),223			)))224	}225226	/// Save collection to storage.227	pub fn save(&self) -> DispatchResult {228		<CollectionById<T>>::insert(self.id, &self.collection);229		Ok(())230	}231232	/// Set collection sponsor.233	///234	/// Unique collections allows sponsoring for certain actions.235	/// This method allows you to set the sponsor of the collection.236	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].237	pub fn set_sponsor(238		&mut self,239		sender: &T::CrossAccountId,240		sponsor: T::AccountId,241	) -> DispatchResult {242		self.check_is_internal()?;243		self.check_is_owner_or_admin(sender)?;244245		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());246247		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));248		<PalletEvm<T>>::deposit_log(249			erc::CollectionHelpersEvents::CollectionChanged {250				collection_id: eth::collection_id_to_address(self.id),251			}252			.to_log(T::ContractAddress::get()),253		);254255		self.save()256	}257258	/// Force set `sponsor`.259	///260	/// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation261	/// from the `sponsor` is not required.262	///263	/// # Arguments264	///265	/// * `sender`: Caller's account.266	/// * `sponsor`: ID of the account of the sponsor-to-be.267	pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {268		self.check_is_internal()?;269270		self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());271272		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));273		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));274		<PalletEvm<T>>::deposit_log(275			erc::CollectionHelpersEvents::CollectionChanged {276				collection_id: eth::collection_id_to_address(self.id),277			}278			.to_log(T::ContractAddress::get()),279		);280281		self.save()282	}283284	/// Confirm sponsorship285	///286	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.287	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].288	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {289		self.check_is_internal()?;290		ensure!(291			self.collection.sponsorship.pending_sponsor() == Some(sender),292			Error::<T>::ConfirmSponsorshipFail293		);294295		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());296297		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));298		<PalletEvm<T>>::deposit_log(299			erc::CollectionHelpersEvents::CollectionChanged {300				collection_id: eth::collection_id_to_address(self.id),301			}302			.to_log(T::ContractAddress::get()),303		);304305		self.save()306	}307308	/// Remove collection sponsor.309	pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {310		self.check_is_internal()?;311		self.check_is_owner_or_admin(sender)?;312313		self.collection.sponsorship = SponsorshipState::Disabled;314315		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));316		<PalletEvm<T>>::deposit_log(317			erc::CollectionHelpersEvents::CollectionChanged {318				collection_id: eth::collection_id_to_address(self.id),319			}320			.to_log(T::ContractAddress::get()),321		);322		self.save()323	}324325	/// Force remove `sponsor`.326	///327	/// Differs from `remove_sponsor` in that328	/// it doesn't require consent from the `owner` of the collection.329	pub fn force_remove_sponsor(&mut self) -> DispatchResult {330		self.check_is_internal()?;331332		self.collection.sponsorship = SponsorshipState::Disabled;333334		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));335		<PalletEvm<T>>::deposit_log(336			erc::CollectionHelpersEvents::CollectionChanged {337				collection_id: eth::collection_id_to_address(self.id),338			}339			.to_log(T::ContractAddress::get()),340		);341		self.save()342	}343344	/// Checks that the collection was created with, and must be operated upon through **Unique API**.345	/// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.346	pub fn check_is_internal(&self) -> DispatchResult {347		if self.flags.external {348			return Err(<Error<T>>::CollectionIsExternal)?;349		}350351		Ok(())352	}353354	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.355	/// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.356	pub fn check_is_external(&self) -> DispatchResult {357		if !self.flags.external {358			return Err(<Error<T>>::CollectionIsInternal)?;359		}360361		Ok(())362	}363}364365impl<T: Config> Deref for CollectionHandle<T> {366	type Target = Collection<T::AccountId>;367368	fn deref(&self) -> &Self::Target {369		&self.collection370	}371}372373impl<T: Config> DerefMut for CollectionHandle<T> {374	fn deref_mut(&mut self) -> &mut Self::Target {375		&mut self.collection376	}377}378379impl<T: Config> CollectionHandle<T> {380	/// Checks if the `user` is the owner of the collection.381	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {382		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);383		Ok(())384	}385386	/// Returns **true** if the `user` is the owner or administrator of the collection.387	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {388		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))389	}390391	/// Checks if the `user` is the owner or administrator of the collection.392	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {393		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);394		Ok(())395	}396397	/// Returns **true** if398	/// * the `user`is a collection owner or admin399	/// * the collection limits allow the owner/admins to transfer/burn any collection token400	pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {401		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)402	}403404	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.405	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {406		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)407	}408409	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.410	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {411		ensure!(412			<Allowlist<T>>::get((self.id, user)),413			<Error<T>>::AddressNotInAllowlist414		);415		Ok(())416	}417418	/// Changes collection owner to another account419	/// #### Store read/writes420	/// 1 writes421	pub fn change_owner(422		&mut self,423		caller: T::CrossAccountId,424		new_owner: T::CrossAccountId,425	) -> DispatchResult {426		self.check_is_internal()?;427		self.check_is_owner(&caller)?;428		self.collection.owner = new_owner.as_sub().clone();429430		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(431			self.id,432			new_owner.as_sub().clone(),433		));434		<PalletEvm<T>>::deposit_log(435			erc::CollectionHelpersEvents::CollectionChanged {436				collection_id: eth::collection_id_to_address(self.id),437			}438			.to_log(T::ContractAddress::get()),439		);440441		self.save()442	}443}444445#[frame_support::pallet]446pub mod pallet {447	use super::*;448	use dispatch::CollectionDispatch;449	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};450	use frame_system::pallet_prelude::*;451	use frame_support::traits::Currency;452	use up_data_structs::{TokenId, mapping::TokenAddressMapping};453	use scale_info::TypeInfo;454	use weights::WeightInfo;455456	#[pallet::config]457	pub trait Config:458		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo459	{460		/// Weight information for functions of this pallet.461		type WeightInfo: WeightInfo;462463		/// Events compatible with [`frame_system::Config::Event`].464		type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;465466		/// Handler of accounts and payment.467		type Currency: Currency<Self::AccountId>;468469		/// Set price to create a collection.470		#[pallet::constant]471		type CollectionCreationPrice: Get<472			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,473		>;474475		/// Dispatcher of operations on collections.476		type CollectionDispatch: CollectionDispatch<Self>;477478		/// Account which holds the chain's treasury.479		type TreasuryAccountId: Get<Self::AccountId>;480481		/// Address under which the CollectionHelper contract would be available.482		#[pallet::constant]483		type ContractAddress: Get<H160>;484485		/// Mapper for token addresses to Ethereum addresses.486		type EvmTokenAddressMapping: TokenAddressMapping<H160>;487488		/// Mapper for token addresses to [`CrossAccountId`].489		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;490	}491492	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);493494	#[pallet::pallet]495	#[pallet::storage_version(STORAGE_VERSION)]496	#[pallet::generate_store(pub(super) trait Store)]497	pub struct Pallet<T>(_);498499	#[pallet::extra_constants]500	impl<T: Config> Pallet<T> {501		/// Maximum admins per collection.502		pub fn collection_admins_limit() -> u32 {503			COLLECTION_ADMINS_LIMIT504		}505	}506507	impl<T: Config> Pallet<T> {508		/// Helper function that handles deposit events509		pub fn deposit_event(event: Event<T>) {510			let event = <T as Config>::RuntimeEvent::from(event);511			let event = event.into();512			<frame_system::Pallet<T>>::deposit_event(event)513		}514	}515516	#[pallet::event]517	pub enum Event<T: Config> {518		/// New collection was created519		CollectionCreated(520			/// Globally unique identifier of newly created collection.521			CollectionId,522			/// [`CollectionMode`] converted into _u8_.523			u8,524			/// Collection owner.525			T::AccountId,526		),527528		/// New collection was destroyed529		CollectionDestroyed(530			/// Globally unique identifier of collection.531			CollectionId,532		),533534		/// New item was created.535		ItemCreated(536			/// Id of the collection where item was created.537			CollectionId,538			/// Id of an item. Unique within the collection.539			TokenId,540			/// Owner of newly created item541			T::CrossAccountId,542			/// Always 1 for NFT543			u128,544		),545546		/// Collection item was burned.547		ItemDestroyed(548			/// Id of the collection where item was destroyed.549			CollectionId,550			/// Identifier of burned NFT.551			TokenId,552			/// Which user has destroyed its tokens.553			T::CrossAccountId,554			/// Amount of token pieces destroed. Always 1 for NFT.555			u128,556		),557558		/// Item was transferred559		Transfer(560			/// Id of collection to which item is belong.561			CollectionId,562			/// Id of an item.563			TokenId,564			/// Original owner of item.565			T::CrossAccountId,566			/// New owner of item.567			T::CrossAccountId,568			/// Amount of token pieces transfered. Always 1 for NFT.569			u128,570		),571572		/// Amount pieces of token owned by `sender` was approved for `spender`.573		Approved(574			/// Id of collection to which item is belong.575			CollectionId,576			/// Id of an item.577			TokenId,578			/// Original owner of item.579			T::CrossAccountId,580			/// Id for which the approval was granted.581			T::CrossAccountId,582			/// Amount of token pieces transfered. Always 1 for NFT.583			u128,584		),585586		/// A `sender` approves operations on all owned tokens for `spender`.587		ApprovedForAll(588			/// Id of collection to which item is belong.589			CollectionId,590			/// Owner of a wallet.591			T::CrossAccountId,592			/// Id for which operator status was granted or rewoked.593			T::CrossAccountId,594			/// Is operator status granted or revoked?595			bool,596		),597598		/// The colletion property has been added or edited.599		CollectionPropertySet(600			/// Id of collection to which property has been set.601			CollectionId,602			/// The property that was set.603			PropertyKey,604		),605606		/// The property has been deleted.607		CollectionPropertyDeleted(608			/// Id of collection to which property has been deleted.609			CollectionId,610			/// The property that was deleted.611			PropertyKey,612		),613614		/// The token property has been added or edited.615		TokenPropertySet(616			/// Identifier of the collection whose token has the property set.617			CollectionId,618			/// The token for which the property was set.619			TokenId,620			/// The property that was set.621			PropertyKey,622		),623624		/// The token property has been deleted.625		TokenPropertyDeleted(626			/// Identifier of the collection whose token has the property deleted.627			CollectionId,628			/// The token for which the property was deleted.629			TokenId,630			/// The property that was deleted.631			PropertyKey,632		),633634		/// The token property permission of a collection has been set.635		PropertyPermissionSet(636			/// ID of collection to which property permission has been set.637			CollectionId,638			/// The property permission that was set.639			PropertyKey,640		),641642		/// Address was added to the allow list.643		AllowListAddressAdded(644			/// ID of the affected collection.645			CollectionId,646			/// Address of the added account.647			T::CrossAccountId,648		),649650		/// Address was removed from the allow list.651		AllowListAddressRemoved(652			/// ID of the affected collection.653			CollectionId,654			/// Address of the removed account.655			T::CrossAccountId,656		),657658		/// Collection admin was added.659		CollectionAdminAdded(660			/// ID of the affected collection.661			CollectionId,662			/// Admin address.663			T::CrossAccountId,664		),665666		/// Collection admin was removed.667		CollectionAdminRemoved(668			/// ID of the affected collection.669			CollectionId,670			/// Removed admin address.671			T::CrossAccountId,672		),673674		/// Collection limits were set.675		CollectionLimitSet(676			/// ID of the affected collection.677			CollectionId,678		),679680		/// Collection owned was changed.681		CollectionOwnerChanged(682			/// ID of the affected collection.683			CollectionId,684			/// New owner address.685			T::AccountId,686		),687688		/// Collection permissions were set.689		CollectionPermissionSet(690			/// ID of the affected collection.691			CollectionId,692		),693694		/// Collection sponsor was set.695		CollectionSponsorSet(696			/// ID of the affected collection.697			CollectionId,698			/// New sponsor address.699			T::AccountId,700		),701702		/// New sponsor was confirm.703		SponsorshipConfirmed(704			/// ID of the affected collection.705			CollectionId,706			/// New sponsor address.707			T::AccountId,708		),709710		/// Collection sponsor was removed.711		CollectionSponsorRemoved(712			/// ID of the affected collection.713			CollectionId,714		),715	}716717	#[pallet::error]718	pub enum Error<T> {719		/// This collection does not exist.720		CollectionNotFound,721		/// Sender parameter and item owner must be equal.722		MustBeTokenOwner,723		/// No permission to perform action724		NoPermission,725		/// Destroying only empty collections is allowed726		CantDestroyNotEmptyCollection,727		/// Collection is not in mint mode.728		PublicMintingNotAllowed,729		/// Address is not in allow list.730		AddressNotInAllowlist,731732		/// Collection name can not be longer than 63 char.733		CollectionNameLimitExceeded,734		/// Collection description can not be longer than 255 char.735		CollectionDescriptionLimitExceeded,736		/// Token prefix can not be longer than 15 char.737		CollectionTokenPrefixLimitExceeded,738		/// Total collections bound exceeded.739		TotalCollectionsLimitExceeded,740		/// Exceeded max admin count741		CollectionAdminCountExceeded,742		/// Collection limit bounds per collection exceeded743		CollectionLimitBoundsExceeded,744		/// Tried to enable permissions which are only permitted to be disabled745		OwnerPermissionsCantBeReverted,746		/// Collection settings not allowing items transferring747		TransferNotAllowed,748		/// Account token limit exceeded per collection749		AccountTokenLimitExceeded,750		/// Collection token limit exceeded751		CollectionTokenLimitExceeded,752		/// Metadata flag frozen753		MetadataFlagFrozen,754755		/// Item does not exist756		TokenNotFound,757		/// Item is balance not enough758		TokenValueTooLow,759		/// Requested value is more than the approved760		ApprovedValueTooLow,761		/// Tried to approve more than owned762		CantApproveMoreThanOwned,763		/// Only spending from eth mirror could be approved764		AddressIsNotEthMirror,765766		/// Can't transfer tokens to ethereum zero address767		AddressIsZero,768769		/// The operation is not supported770		UnsupportedOperation,771772		/// Insufficient funds to perform an action773		NotSufficientFounds,774775		/// User does not satisfy the nesting rule776		UserIsNotAllowedToNest,777		/// Only tokens from specific collections may nest tokens under this one778		SourceCollectionIsNotAllowedToNest,779780		/// Tried to store more data than allowed in collection field781		CollectionFieldSizeExceeded,782783		/// Tried to store more property data than allowed784		NoSpaceForProperty,785786		/// Tried to store more property keys than allowed787		PropertyLimitReached,788789		/// Property key is too long790		PropertyKeyIsTooLong,791792		/// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed793		InvalidCharacterInPropertyKey,794795		/// Empty property keys are forbidden796		EmptyPropertyKey,797798		/// Tried to access an external collection with an internal API799		CollectionIsExternal,800801		/// Tried to access an internal collection with an external API802		CollectionIsInternal,803804		/// This address is not set as sponsor, use setCollectionSponsor first.805		ConfirmSponsorshipFail,806807		/// The user is not an administrator.808		UserIsNotCollectionAdmin,809	}810811	/// Storage of the count of created collections. Essentially contains the last collection ID.812	#[pallet::storage]813	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;814815	/// Storage of the count of deleted collections.816	#[pallet::storage]817	pub type DestroyedCollectionCount<T> =818		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;819820	/// Storage of collection info.821	#[pallet::storage]822	pub type CollectionById<T> = StorageMap<823		Hasher = Blake2_128Concat,824		Key = CollectionId,825		Value = Collection<<T as frame_system::Config>::AccountId>,826		QueryKind = OptionQuery,827	>;828829	/// Storage of collection properties.830	#[pallet::storage]831	#[pallet::getter(fn collection_properties)]832	pub type CollectionProperties<T> = StorageMap<833		Hasher = Blake2_128Concat,834		Key = CollectionId,835		Value = Properties,836		QueryKind = ValueQuery,837		OnEmpty = up_data_structs::CollectionProperties,838	>;839840	/// Storage of token property permissions of a collection.841	#[pallet::storage]842	#[pallet::getter(fn property_permissions)]843	pub type CollectionPropertyPermissions<T> = StorageMap<844		Hasher = Blake2_128Concat,845		Key = CollectionId,846		Value = PropertiesPermissionMap,847		QueryKind = ValueQuery,848	>;849850	/// Storage of the amount of collection admins.851	#[pallet::storage]852	pub type AdminAmount<T> = StorageMap<853		Hasher = Blake2_128Concat,854		Key = CollectionId,855		Value = u32,856		QueryKind = ValueQuery,857	>;858859	/// List of collection admins.860	#[pallet::storage]861	pub type IsAdmin<T: Config> = StorageNMap<862		Key = (863			Key<Blake2_128Concat, CollectionId>,864			Key<Blake2_128Concat, T::CrossAccountId>,865		),866		Value = bool,867		QueryKind = ValueQuery,868	>;869870	/// Allowlisted collection users.871	#[pallet::storage]872	pub type Allowlist<T: Config> = StorageNMap<873		Key = (874			Key<Blake2_128Concat, CollectionId>,875			Key<Blake2_128Concat, T::CrossAccountId>,876		),877		Value = bool,878		QueryKind = ValueQuery,879	>;880881	/// Not used by code, exists only to provide some types to metadata.882	#[pallet::storage]883	pub type DummyStorageValue<T: Config> = StorageValue<884		Value = (885			CollectionStats,886			CollectionId,887			TokenId,888			TokenChild,889			PhantomType<(890				TokenData<T::CrossAccountId>,891				RpcCollection<T::AccountId>,892				// PoV Estimate Info893				PovInfo,894			)>,895		),896		QueryKind = OptionQuery,897	>;898899	#[pallet::hooks]900	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {901		fn on_runtime_upgrade() -> Weight {902			StorageVersion::new(1).put::<Pallet<T>>();903904			Weight::zero()905		}906	}907}908909impl<T: Config> Pallet<T> {910	/// Enshure that receiver address is correct.911	///912	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.913	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {914		ensure!(915			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,916			<Error<T>>::AddressIsZero917		);918		Ok(())919	}920921	/// Get a vector of collection admins.922	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {923		<IsAdmin<T>>::iter_prefix((collection,))924			.map(|(a, _)| a)925			.collect()926	}927928	/// Get a vector of users allowed to mint tokens.929	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {930		<Allowlist<T>>::iter_prefix((collection,))931			.map(|(a, _)| a)932			.collect()933	}934935	/// Is `user` allowed to mint token in `collection`.936	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {937		<Allowlist<T>>::get((collection, user))938	}939940	/// Get statistics of collections.941	pub fn collection_stats() -> CollectionStats {942		let created = <CreatedCollectionCount<T>>::get();943		let destroyed = <DestroyedCollectionCount<T>>::get();944		CollectionStats {945			created: created.0,946			destroyed: destroyed.0,947			alive: created.0 - destroyed.0,948		}949	}950951	/// Get the effective limits for the collection.952	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {953		let collection = <CollectionById<T>>::get(collection)?;954		let limits = collection.limits;955		let effective_limits = CollectionLimits {956			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),957			sponsored_data_size: Some(limits.sponsored_data_size()),958			sponsored_data_rate_limit: Some(959				limits960					.sponsored_data_rate_limit961					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),962			),963			token_limit: Some(limits.token_limit()),964			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(965				match collection.mode {966					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,967					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,968					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,969				},970			)),971			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),972			owner_can_transfer: Some(limits.owner_can_transfer()),973			owner_can_destroy: Some(limits.owner_can_destroy()),974			transfers_enabled: Some(limits.transfers_enabled()),975		};976977		Some(effective_limits)978	}979980	/// Returns information about the `collection` adapted for rpc.981	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {982		let Collection {983			name,984			description,985			owner,986			mode,987			token_prefix,988			sponsorship,989			limits,990			permissions,991			flags,992		} = <CollectionById<T>>::get(collection)?;993994		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)995			.into_iter()996			.map(|(key, permission)| PropertyKeyPermission { key, permission })997			.collect();998999		let properties = <CollectionProperties<T>>::get(collection)1000			.into_iter()1001			.map(|(key, value)| Property { key, value })1002			.collect();10031004		let permissions = CollectionPermissions {1005			access: Some(permissions.access()),1006			mint_mode: Some(permissions.mint_mode()),1007			nesting: Some(permissions.nesting().clone()),1008		};10091010		Some(RpcCollection {1011			name: name.into_inner(),1012			description: description.into_inner(),1013			owner,1014			mode,1015			token_prefix: token_prefix.into_inner(),1016			sponsorship,1017			limits,1018			permissions,1019			token_property_permissions,1020			properties,1021			read_only: flags.external,10221023			flags: RpcCollectionFlags {1024				foreign: flags.foreign,1025				erc721metadata: flags.erc721metadata,1026			},1027		})1028	}1029}10301031macro_rules! limit_default {1032	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1033		$(1034			if let Some($new) = $new.$field {1035				let $old = $old.$field($($arg)?);1036				let _ = $new;1037				let _ = $old;1038				$check1039			} else {1040				$new.$field = $old.$field1041			}1042		)*1043	}};1044}1045macro_rules! limit_default_clone {1046	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1047		$(1048			if let Some($new) = $new.$field.clone() {1049				let $old = $old.$field($($arg)?);1050				let _ = $new;1051				let _ = $old;1052				$check1053			} else {1054				$new.$field = $old.$field.clone()1055			}1056		)*1057	}};1058}10591060impl<T: Config> Pallet<T> {1061	/// Create new collection.1062	///1063	/// * `owner` - The owner of the collection.1064	/// * `data` - Description of the created collection.1065	/// * `flags` - Extra flags to store.1066	pub fn init_collection(1067		owner: T::CrossAccountId,1068		payer: T::CrossAccountId,1069		data: CreateCollectionData<T::AccountId>,1070		flags: CollectionFlags,1071	) -> Result<CollectionId, DispatchError> {1072		{1073			ensure!(1074				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1075				Error::<T>::CollectionTokenPrefixLimitExceeded1076			);1077		}10781079		let created_count = <CreatedCollectionCount<T>>::get()1080			.01081			.checked_add(1)1082			.ok_or(ArithmeticError::Overflow)?;1083		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1084		let id = CollectionId(created_count);10851086		// bound Total number of collections1087		ensure!(1088			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1089			<Error<T>>::TotalCollectionsLimitExceeded1090		);10911092		// =========10931094		let collection = Collection {1095			owner: owner.as_sub().clone(),1096			name: data.name,1097			mode: data.mode.clone(),1098			description: data.description,1099			token_prefix: data.token_prefix,1100			sponsorship: data1101				.pending_sponsor1102				.map(SponsorshipState::Unconfirmed)1103				.unwrap_or_default(),1104			limits: data1105				.limits1106				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1107				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,1108			permissions: data1109				.permissions1110				.map(|permissions| {1111					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1112				})1113				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1114			flags,1115		};11161117		let mut collection_properties = up_data_structs::CollectionProperties::get();1118		collection_properties1119			.try_set_from_iter(data.properties.into_iter())1120			.map_err(<Error<T>>::from)?;11211122		CollectionProperties::<T>::insert(id, collection_properties);11231124		let mut token_props_permissions = PropertiesPermissionMap::new();1125		token_props_permissions1126			.try_set_from_iter(data.token_property_permissions.into_iter())1127			.map_err(<Error<T>>::from)?;11281129		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11301131		// Take a (non-refundable) deposit of collection creation1132		{1133			let mut imbalance =1134				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1135			imbalance.subsume(1136				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1137					&T::TreasuryAccountId::get(),1138					T::CollectionCreationPrice::get(),1139				),1140			);1141			<T as Config>::Currency::settle(1142				payer.as_sub(),1143				imbalance,1144				WithdrawReasons::TRANSFER,1145				ExistenceRequirement::KeepAlive,1146			)1147			.map_err(|_| Error::<T>::NotSufficientFounds)?;1148		}11491150		<CreatedCollectionCount<T>>::put(created_count);1151		<Pallet<T>>::deposit_event(Event::CollectionCreated(1152			id,1153			data.mode.id(),1154			owner.as_sub().clone(),1155		));1156		<PalletEvm<T>>::deposit_log(1157			erc::CollectionHelpersEvents::CollectionCreated {1158				owner: *owner.as_eth(),1159				collection_id: eth::collection_id_to_address(id),1160			}1161			.to_log(T::ContractAddress::get()),1162		);1163		<CollectionById<T>>::insert(id, collection);1164		Ok(id)1165	}11661167	/// Destroy collection.1168	///1169	/// * `collection` - Collection handler.1170	/// * `sender` - The owner or administrator of the collection.1171	pub fn destroy_collection(1172		collection: CollectionHandle<T>,1173		sender: &T::CrossAccountId,1174	) -> DispatchResult {1175		ensure!(1176			collection.limits.owner_can_destroy(),1177			<Error<T>>::NoPermission,1178		);1179		collection.check_is_owner(sender)?;11801181		let destroyed_collections = <DestroyedCollectionCount<T>>::get()1182			.01183			.checked_add(1)1184			.ok_or(ArithmeticError::Overflow)?;11851186		// =========11871188		<DestroyedCollectionCount<T>>::put(destroyed_collections);1189		<CollectionById<T>>::remove(collection.id);1190		<AdminAmount<T>>::remove(collection.id);1191		let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1192		let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1193		<CollectionProperties<T>>::remove(collection.id);11941195		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));11961197		<PalletEvm<T>>::deposit_log(1198			erc::CollectionHelpersEvents::CollectionDestroyed {1199				collection_id: eth::collection_id_to_address(collection.id),1200			}1201			.to_log(T::ContractAddress::get()),1202		);1203		Ok(())1204	}12051206	/// This function sets or removes a collection properties according to1207	/// `properties_updates` contents:1208	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1209	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1210	///1211	/// This function fires an event for each property change.1212	/// In case of an error, all the changes (including the events) will be reverted1213	/// since the function is transactional.1214	#[transactional]1215	fn modify_collection_properties(1216		collection: &CollectionHandle<T>,1217		sender: &T::CrossAccountId,1218		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1219	) -> DispatchResult {1220		collection.check_is_owner_or_admin(sender)?;12211222		let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12231224		for (key, value) in properties_updates {1225			match value {1226				Some(value) => {1227					stored_properties1228						.try_set(key.clone(), value)1229						.map_err(<Error<T>>::from)?;12301231					Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1232					<PalletEvm<T>>::deposit_log(1233						erc::CollectionHelpersEvents::CollectionChanged {1234							collection_id: eth::collection_id_to_address(collection.id),1235						}1236						.to_log(T::ContractAddress::get()),1237					);1238				}1239				None => {1240					stored_properties.remove(&key).map_err(<Error<T>>::from)?;12411242					Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1243					<PalletEvm<T>>::deposit_log(1244						erc::CollectionHelpersEvents::CollectionChanged {1245							collection_id: eth::collection_id_to_address(collection.id),1246						}1247						.to_log(T::ContractAddress::get()),1248					);1249				}1250			}1251		}12521253		<CollectionProperties<T>>::set(collection.id, stored_properties);12541255		Ok(())1256	}12571258	/// A batch operation to add, edit or remove properties for a token.1259	/// It sets or removes a token's properties according to1260	/// `properties_updates` contents:1261	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1262	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1263	///1264	/// - `nesting_budget`: Limit for searching parents in-depth to check ownership.1265	/// - `is_token_create`: Indicates that method is called during token initialization.1266	///   Allows to bypass ownership check.1267	///1268	/// All affected properties should have `mutable` permission1269	/// to be **deleted** or to be **set more than once**,1270	/// and the sender should have permission to edit those properties.1271	///1272	/// This function fires an event for each property change.1273	/// In case of an error, all the changes (including the events) will be reverted1274	/// since the function is transactional.1275	pub fn modify_token_properties(1276		collection: &CollectionHandle<T>,1277		sender: &T::CrossAccountId,1278		token_id: TokenId,1279		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1280		is_token_create: bool,1281		mut stored_properties: Properties,1282		is_token_owner: impl Fn() -> Result<bool, DispatchError>,1283		set_token_properties: impl FnOnce(Properties),1284	) -> DispatchResult {1285		let is_collection_admin = collection.is_owner_or_admin(sender);1286		let permissions = Self::property_permissions(collection.id);12871288		let mut token_owner_result = None;1289		let mut is_token_owner = || -> Result<bool, DispatchError> {1290			*token_owner_result.get_or_insert_with(&is_token_owner)1291		};12921293		for (key, value) in properties_updates {1294			let permission = permissions1295				.get(&key)1296				.cloned()1297				.unwrap_or_else(PropertyPermission::none);12981299			let is_property_exists = stored_properties.get(&key).is_some();13001301			match permission {1302				PropertyPermission { mutable: false, .. } if is_property_exists => {1303					return Err(<Error<T>>::NoPermission.into());1304				}13051306				PropertyPermission {1307					collection_admin,1308					token_owner,1309					..1310				} => {1311					//TODO: investigate threats during public minting.1312					let is_token_create =1313						is_token_create && (collection_admin || token_owner) && value.is_some();1314					if !(is_token_create1315						|| (collection_admin && is_collection_admin)1316						|| (token_owner && is_token_owner()?))1317					{1318						fail!(<Error<T>>::NoPermission);1319					}1320				}1321			}13221323			match value {1324				Some(value) => {1325					stored_properties1326						.try_set(key.clone(), value)1327						.map_err(<Error<T>>::from)?;13281329					Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));1330				}1331				None => {1332					stored_properties.remove(&key).map_err(<Error<T>>::from)?;13331334					Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));1335				}1336			}13371338			<PalletEvm<T>>::deposit_log(1339				CollectionHelpersEvents::TokenChanged {1340					collection_id: eth::collection_id_to_address(collection.id),1341					token_id: token_id.into(),1342				}1343				.to_log(T::ContractAddress::get()),1344			);1345		}13461347		set_token_properties(stored_properties);13481349		Ok(())1350	}13511352	/// Sets or unsets the approval of a given operator.1353	///1354	/// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.1355	/// - `owner`: Token owner1356	/// - `operator`: Operator1357	/// - `approve`: Should operator status be granted or revoked?1358	pub fn set_allowance_for_all(1359		collection: &CollectionHandle<T>,1360		owner: &T::CrossAccountId,1361		operator: &T::CrossAccountId,1362		approve: bool,1363		set_allowance: impl FnOnce(),1364		log: evm_coder::ethereum::Log,1365	) -> DispatchResult {1366		if collection.permissions.access() == AccessMode::AllowList {1367			collection.check_allowlist(owner)?;1368			collection.check_allowlist(operator)?;1369		}13701371		Self::ensure_correct_receiver(operator)?;13721373		set_allowance();13741375		<PalletEvm<T>>::deposit_log(log);1376		Self::deposit_event(Event::ApprovedForAll(1377			collection.id,1378			owner.clone(),1379			operator.clone(),1380			approve,1381		));1382		Ok(())1383	}13841385	/// Set collection property.1386	///1387	/// * `collection` - Collection handler.1388	/// * `sender` - The owner or administrator of the collection.1389	/// * `property` - The property to set.1390	pub fn set_collection_property(1391		collection: &CollectionHandle<T>,1392		sender: &T::CrossAccountId,1393		property: Property,1394	) -> DispatchResult {1395		Self::set_collection_properties(collection, sender, [property].into_iter())1396	}13971398	/// Set a scoped collection property, where the scope is a special prefix1399	/// prohibiting a user access to change the property directly.1400	///1401	/// * `collection_id` - ID of the collection for which the property is being set.1402	/// * `scope` - Property scope.1403	/// * `property` - The property to set.1404	pub fn set_scoped_collection_property(1405		collection_id: CollectionId,1406		scope: PropertyScope,1407		property: Property,1408	) -> DispatchResult {1409		CollectionProperties::<T>::try_mutate(collection_id, |properties| {1410			properties.try_scoped_set(scope, property.key, property.value)1411		})1412		.map_err(<Error<T>>::from)?;14131414		Ok(())1415	}14161417	/// Set scoped collection properties, where the scope is a special prefix1418	/// prohibiting a user access to change the properties directly.1419	///1420	/// * `collection_id` - ID of the collection for which the properties is being set.1421	/// * `scope` - Property scope.1422	/// * `properties` - The properties to set.1423	pub fn set_scoped_collection_properties(1424		collection_id: CollectionId,1425		scope: PropertyScope,1426		properties: impl Iterator<Item = Property>,1427	) -> DispatchResult {1428		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1429			stored_properties.try_scoped_set_from_iter(scope, properties)1430		})1431		.map_err(<Error<T>>::from)?;14321433		Ok(())1434	}14351436	/// Set collection properties.1437	///1438	/// * `collection` - Collection handler.1439	/// * `sender` - The owner or administrator of the collection.1440	/// * `properties` - The properties to set.1441	pub fn set_collection_properties(1442		collection: &CollectionHandle<T>,1443		sender: &T::CrossAccountId,1444		properties: impl Iterator<Item = Property>,1445	) -> DispatchResult {1446		Self::modify_collection_properties(1447			collection,1448			sender,1449			properties.map(|property| (property.key, Some(property.value))),1450		)1451	}14521453	/// Delete collection property.1454	///1455	/// * `collection` - Collection handler.1456	/// * `sender` - The owner or administrator of the collection.1457	/// * `property` - The property to delete.1458	pub fn delete_collection_property(1459		collection: &CollectionHandle<T>,1460		sender: &T::CrossAccountId,1461		property_key: PropertyKey,1462	) -> DispatchResult {1463		Self::delete_collection_properties(collection, sender, [property_key].into_iter())1464	}14651466	/// Delete collection properties.1467	///1468	/// * `collection` - Collection handler.1469	/// * `sender` - The owner or administrator of the collection.1470	/// * `properties` - The properties to delete.1471	pub fn delete_collection_properties(1472		collection: &CollectionHandle<T>,1473		sender: &T::CrossAccountId,1474		property_keys: impl Iterator<Item = PropertyKey>,1475	) -> DispatchResult {1476		Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1477	}14781479	/// Set collection propetry permission without any checks.1480	///1481	/// Used for migrations.1482	///1483	/// * `collection` - Collection handler.1484	/// * `property_permissions` - Property permissions.1485	pub fn set_property_permission_unchecked(1486		collection: CollectionId,1487		property_permission: PropertyKeyPermission,1488	) -> DispatchResult {1489		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1490			permissions.try_set(property_permission.key, property_permission.permission)1491		})1492		.map_err(<Error<T>>::from)?;1493		Ok(())1494	}14951496	/// Set collection property permission.1497	///1498	/// * `collection` - Collection handler.1499	/// * `sender` - The owner or administrator of the collection.1500	/// * `property_permission` - Property permission.1501	pub fn set_property_permission(1502		collection: &CollectionHandle<T>,1503		sender: &T::CrossAccountId,1504		property_permission: PropertyKeyPermission,1505	) -> DispatchResult {1506		Self::set_scoped_property_permission(1507			collection,1508			sender,1509			PropertyScope::None,1510			property_permission,1511		)1512	}15131514	/// Set collection property permission with scope.1515	///1516	/// * `collection` - Collection handler.1517	/// * `sender` - The owner or administrator of the collection.1518	/// * `scope` - Property scope.1519	/// * `property_permission` - Property permission.1520	pub fn set_scoped_property_permission(1521		collection: &CollectionHandle<T>,1522		sender: &T::CrossAccountId,1523		scope: PropertyScope,1524		property_permission: PropertyKeyPermission,1525	) -> DispatchResult {1526		collection.check_is_owner_or_admin(sender)?;15271528		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1529		let current_permission = all_permissions.get(&property_permission.key);1530		if matches![1531			current_permission,1532			Some(PropertyPermission { mutable: false, .. })1533		] {1534			return Err(<Error<T>>::NoPermission.into());1535		}15361537		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1538			let property_permission = property_permission.clone();1539			permissions.try_scoped_set(1540				scope,1541				property_permission.key,1542				property_permission.permission,1543			)1544		})1545		.map_err(<Error<T>>::from)?;15461547		Self::deposit_event(Event::PropertyPermissionSet(1548			collection.id,1549			property_permission.key,1550		));1551		<PalletEvm<T>>::deposit_log(1552			erc::CollectionHelpersEvents::CollectionChanged {1553				collection_id: eth::collection_id_to_address(collection.id),1554			}1555			.to_log(T::ContractAddress::get()),1556		);15571558		Ok(())1559	}15601561	/// Set token property permission.1562	///1563	/// * `collection` - Collection handler.1564	/// * `sender` - The owner or administrator of the collection.1565	/// * `property_permissions` - Property permissions.1566	#[transactional]1567	pub fn set_token_property_permissions(1568		collection: &CollectionHandle<T>,1569		sender: &T::CrossAccountId,1570		property_permissions: Vec<PropertyKeyPermission>,1571	) -> DispatchResult {1572		Self::set_scoped_token_property_permissions(1573			collection,1574			sender,1575			PropertyScope::None,1576			property_permissions,1577		)1578	}15791580	/// Set token property permission with scope.1581	///1582	/// * `collection` - Collection handler.1583	/// * `sender` - The owner or administrator of the collection.1584	/// * `scope` - Property scope.1585	/// * `property_permissions` - Property permissions.1586	#[transactional]1587	pub fn set_scoped_token_property_permissions(1588		collection: &CollectionHandle<T>,1589		sender: &T::CrossAccountId,1590		scope: PropertyScope,1591		property_permissions: Vec<PropertyKeyPermission>,1592	) -> DispatchResult {1593		for prop_pemission in property_permissions {1594			Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1595		}15961597		Ok(())1598	}15991600	/// Get collection property.1601	pub fn get_collection_property(1602		collection_id: CollectionId,1603		key: &PropertyKey,1604	) -> Option<PropertyValue> {1605		Self::collection_properties(collection_id).get(key).cloned()1606	}16071608	/// Convert byte vector to property key vector.1609	pub fn bytes_keys_to_property_keys(1610		keys: Vec<Vec<u8>>,1611	) -> Result<Vec<PropertyKey>, DispatchError> {1612		keys.into_iter()1613			.map(|key| -> Result<PropertyKey, DispatchError> {1614				key.try_into()1615					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1616			})1617			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1618	}16191620	/// Get properties according to given keys.1621	pub fn filter_collection_properties(1622		collection_id: CollectionId,1623		keys: Option<Vec<PropertyKey>>,1624	) -> Result<Vec<Property>, DispatchError> {1625		let properties = Self::collection_properties(collection_id);16261627		let properties = keys1628			.map(|keys| {1629				keys.into_iter()1630					.filter_map(|key| {1631						properties.get(&key).map(|value| Property {1632							key,1633							value: value.clone(),1634						})1635					})1636					.collect()1637			})1638			.unwrap_or_else(|| {1639				properties1640					.into_iter()1641					.map(|(key, value)| Property { key, value })1642					.collect()1643			});16441645		Ok(properties)1646	}16471648	/// Get property permissions according to given keys.1649	pub fn filter_property_permissions(1650		collection_id: CollectionId,1651		keys: Option<Vec<PropertyKey>>,1652	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1653		let permissions = Self::property_permissions(collection_id);16541655		let key_permissions = keys1656			.map(|keys| {1657				keys.into_iter()1658					.filter_map(|key| {1659						permissions1660							.get(&key)1661							.map(|permission| PropertyKeyPermission {1662								key,1663								permission: permission.clone(),1664							})1665					})1666					.collect()1667			})1668			.unwrap_or_else(|| {1669				permissions1670					.into_iter()1671					.map(|(key, permission)| PropertyKeyPermission { key, permission })1672					.collect()1673			});16741675		Ok(key_permissions)1676	}16771678	/// Toggle `user` participation in the `collection`'s allow list.1679	/// #### Store read/writes1680	/// 1 writes1681	pub fn toggle_allowlist(1682		collection: &CollectionHandle<T>,1683		sender: &T::CrossAccountId,1684		user: &T::CrossAccountId,1685		allowed: bool,1686	) -> DispatchResult {1687		collection.check_is_owner_or_admin(sender)?;16881689		// =========16901691		if allowed {1692			<Allowlist<T>>::insert((collection.id, user), true);1693			Self::deposit_event(Event::<T>::AllowListAddressAdded(1694				collection.id,1695				user.clone(),1696			));1697		} else {1698			<Allowlist<T>>::remove((collection.id, user));1699			Self::deposit_event(Event::<T>::AllowListAddressRemoved(1700				collection.id,1701				user.clone(),1702			));1703		}17041705		<PalletEvm<T>>::deposit_log(1706			erc::CollectionHelpersEvents::CollectionChanged {1707				collection_id: eth::collection_id_to_address(collection.id),1708			}1709			.to_log(T::ContractAddress::get()),1710		);17111712		Ok(())1713	}17141715	/// Toggle `user` participation in the `collection`'s admin list.1716	/// #### Store read/writes1717	/// 2 reads, 2 writes1718	pub fn toggle_admin(1719		collection: &CollectionHandle<T>,1720		sender: &T::CrossAccountId,1721		user: &T::CrossAccountId,1722		admin: bool,1723	) -> DispatchResult {1724		collection.check_is_internal()?;1725		collection.check_is_owner(sender)?;17261727		let is_admin = <IsAdmin<T>>::get((collection.id, user));1728		if is_admin == admin {1729			if admin {1730				return Ok(());1731			} else {1732				return Err(Error::<T>::UserIsNotCollectionAdmin.into());1733			}1734		}1735		let amount = <AdminAmount<T>>::get(collection.id);17361737		// =========17381739		if admin {1740			let amount = amount1741				.checked_add(1)1742				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1743			ensure!(1744				amount <= Self::collection_admins_limit(),1745				<Error<T>>::CollectionAdminCountExceeded,1746			);17471748			<AdminAmount<T>>::insert(collection.id, amount);1749			<IsAdmin<T>>::insert((collection.id, user), true);17501751			Self::deposit_event(Event::<T>::CollectionAdminAdded(1752				collection.id,1753				user.clone(),1754			));1755		} else {1756			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1757			<IsAdmin<T>>::remove((collection.id, user));17581759			Self::deposit_event(Event::<T>::CollectionAdminRemoved(1760				collection.id,1761				user.clone(),1762			));1763		}17641765		<PalletEvm<T>>::deposit_log(1766			erc::CollectionHelpersEvents::CollectionChanged {1767				collection_id: eth::collection_id_to_address(collection.id),1768			}1769			.to_log(T::ContractAddress::get()),1770		);17711772		Ok(())1773	}17741775	/// Update collection limits.1776	pub fn update_limits(1777		user: &T::CrossAccountId,1778		collection: &mut CollectionHandle<T>,1779		new_limit: CollectionLimits,1780	) -> DispatchResult {1781		collection.check_is_internal()?;1782		collection.check_is_owner_or_admin(user)?;17831784		collection.limits =1785			Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;17861787		Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1788		<PalletEvm<T>>::deposit_log(1789			erc::CollectionHelpersEvents::CollectionChanged {1790				collection_id: eth::collection_id_to_address(collection.id),1791			}1792			.to_log(T::ContractAddress::get()),1793		);17941795		collection.save()1796	}17971798	/// Merge set fields from `new_limit` to `old_limit`.1799	fn clamp_limits(1800		mode: CollectionMode,1801		old_limit: &CollectionLimits,1802		mut new_limit: CollectionLimits,1803	) -> Result<CollectionLimits, DispatchError> {1804		let limits = old_limit;1805		limit_default!(old_limit, new_limit,1806			account_token_ownership_limit => ensure!(1807				new_limit <= MAX_TOKEN_OWNERSHIP,1808				<Error<T>>::CollectionLimitBoundsExceeded,1809			),1810			sponsored_data_size => ensure!(1811				new_limit <= CUSTOM_DATA_LIMIT,1812				<Error<T>>::CollectionLimitBoundsExceeded,1813			),18141815			sponsored_data_rate_limit => {},1816			token_limit => ensure!(1817				old_limit >= new_limit && new_limit > 0,1818				<Error<T>>::CollectionTokenLimitExceeded1819			),18201821			sponsor_transfer_timeout(match mode {1822				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1823				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1824				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1825			}) => ensure!(1826				new_limit <= MAX_SPONSOR_TIMEOUT,1827				<Error<T>>::CollectionLimitBoundsExceeded,1828			),1829			sponsor_approve_timeout => {},1830			owner_can_transfer => ensure!(1831				!limits.owner_can_transfer_instaled() ||1832				old_limit || !new_limit,1833				<Error<T>>::OwnerPermissionsCantBeReverted,1834			),1835			owner_can_destroy => ensure!(1836				old_limit || !new_limit,1837				<Error<T>>::OwnerPermissionsCantBeReverted,1838			),1839			transfers_enabled => {},1840		);1841		Ok(new_limit)1842	}18431844	/// Update collection permissions.1845	pub fn update_permissions(1846		user: &T::CrossAccountId,1847		collection: &mut CollectionHandle<T>,1848		new_permission: CollectionPermissions,1849	) -> DispatchResult {1850		collection.check_is_internal()?;1851		collection.check_is_owner_or_admin(user)?;1852		collection.permissions = Self::clamp_permissions(1853			collection.mode.clone(),1854			&collection.permissions,1855			new_permission,1856		)?;18571858		Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1859		<PalletEvm<T>>::deposit_log(1860			erc::CollectionHelpersEvents::CollectionChanged {1861				collection_id: eth::collection_id_to_address(collection.id),1862			}1863			.to_log(T::ContractAddress::get()),1864		);18651866		collection.save()1867	}18681869	/// Merge set fields from `new_permission` to `old_permission`.1870	fn clamp_permissions(1871		_mode: CollectionMode,1872		old_permission: &CollectionPermissions,1873		mut new_permission: CollectionPermissions,1874	) -> Result<CollectionPermissions, DispatchError> {1875		limit_default_clone!(old_permission, new_permission,1876			access => {},1877			mint_mode => {},1878			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1879		);1880		Ok(new_permission)1881	}18821883	/// Repair possibly broken properties of a collection.1884	pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1885		CollectionProperties::<T>::mutate(collection_id, |properties| {1886			properties.recompute_consumed_space();1887		});18881889		Ok(())1890	}1891}18921893/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1894#[macro_export]1895macro_rules! unsupported {1896	($runtime:path) => {1897		Err($crate::Error::<$runtime>::UnsupportedOperation.into())1898	};1899}19001901/// Return weights for various worst-case operations.1902pub trait CommonWeightInfo<CrossAccountId> {1903	/// Weight of item creation.1904	fn create_item(data: &CreateItemData) -> Weight {1905		Self::create_multiple_items(from_ref(data))1906	}19071908	/// Weight of items creation.1909	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;19101911	/// Weight of items creation.1912	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;19131914	/// The weight of the burning item.1915	fn burn_item() -> Weight;19161917	/// Property setting weight.1918	///1919	/// * `amount`- The number of properties to set.1920	fn set_collection_properties(amount: u32) -> Weight;19211922	/// Collection property deletion weight.1923	///1924	/// * `amount`- The number of properties to set.1925	fn delete_collection_properties(amount: u32) -> Weight;19261927	/// Token property setting weight.1928	///1929	/// * `amount`- The number of properties to set.1930	fn set_token_properties(amount: u32) -> Weight;19311932	/// Token property deletion weight.1933	///1934	/// * `amount`- The number of properties to delete.1935	fn delete_token_properties(amount: u32) -> Weight;19361937	/// Token property permissions set weight.1938	///1939	/// * `amount`- The number of property permissions to set.1940	fn set_token_property_permissions(amount: u32) -> Weight;19411942	/// Transfer price of the token or its parts.1943	fn transfer() -> Weight;19441945	/// The price of setting the permission of the operation from another user.1946	fn approve() -> Weight;19471948	/// The price of setting the permission of the operation from another user for eth mirror.1949	fn approve_from() -> Weight;19501951	/// Transfer price from another user.1952	fn transfer_from() -> Weight;19531954	/// The price of burning a token from another user.1955	fn burn_from() -> Weight;19561957	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1958	/// whole users's balance.1959	///1960	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1961	fn burn_recursively_self_raw() -> Weight;19621963	/// Cost of iterating over `amount` children while burning, without counting child burning itself.1964	///1965	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1966	fn burn_recursively_breadth_raw(amount: u32) -> Weight;19671968	/// The price of recursive burning a token.1969	///1970	/// `max_selfs` - The maximum burning weight of the token itself.1971	/// `max_breadth` - The maximum number of nested tokens to burn.1972	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1973		Self::burn_recursively_self_raw()1974			.saturating_mul(max_selfs.max(1) as u64)1975			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1976	}19771978	/// The price of retrieving token owner1979	fn token_owner() -> Weight;19801981	/// The price of setting approval for all1982	fn set_allowance_for_all() -> Weight;19831984	/// The price of repairing an item.1985	fn force_repair_item() -> Weight;1986}19871988/// Weight info extension trait for refungible pallet.1989pub trait RefungibleExtensionsWeightInfo {1990	/// Weight of token repartition.1991	fn repartition() -> Weight;1992}19931994/// Common collection operations.1995///1996/// It wraps methods in Fungible, Nonfungible and Refungible pallets1997/// and adds weight info.1998pub trait CommonCollectionOperations<T: Config> {1999	/// Create token.2000	///2001	/// * `sender` - The user who mint the token and pays for the transaction.2002	/// * `to` - The user who will own the token.2003	/// * `data` - Token data.2004	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2005	fn create_item(2006		&self,2007		sender: T::CrossAccountId,2008		to: T::CrossAccountId,2009		data: CreateItemData,2010		nesting_budget: &dyn Budget,2011	) -> DispatchResultWithPostInfo;20122013	/// Create multiple tokens.2014	///2015	/// * `sender` - The user who mint the token and pays for the transaction.2016	/// * `to` - The user who will own the token.2017	/// * `data` - Token data.2018	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2019	fn create_multiple_items(2020		&self,2021		sender: T::CrossAccountId,2022		to: T::CrossAccountId,2023		data: Vec<CreateItemData>,2024		nesting_budget: &dyn Budget,2025	) -> DispatchResultWithPostInfo;20262027	/// Create multiple tokens.2028	///2029	/// * `sender` - The user who mint the token and pays for the transaction.2030	/// * `to` - The user who will own the token.2031	/// * `data` - Token data.2032	/// * `nesting_budget` - A budget that can be spent on nesting tokens.2033	fn create_multiple_items_ex(2034		&self,2035		sender: T::CrossAccountId,2036		data: CreateItemExData<T::CrossAccountId>,2037		nesting_budget: &dyn Budget,2038	) -> DispatchResultWithPostInfo;20392040	/// Burn token.2041	///2042	/// * `sender` - The user who owns the token.2043	/// * `token` - Token id that will burned.2044	/// * `amount` - The number of parts of the token that will be burned.2045	fn burn_item(2046		&self,2047		sender: T::CrossAccountId,2048		token: TokenId,2049		amount: u128,2050	) -> DispatchResultWithPostInfo;20512052	/// Burn token and all nested tokens recursievly.2053	///2054	/// * `sender` - The user who owns the token.2055	/// * `token` - Token id that will burned.2056	/// * `self_budget` - The budget that can be spent on burning tokens.2057	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.2058	fn burn_item_recursively(2059		&self,2060		sender: T::CrossAccountId,2061		token: TokenId,2062		self_budget: &dyn Budget,2063		breadth_budget: &dyn Budget,2064	) -> DispatchResultWithPostInfo;20652066	/// Set collection properties.2067	///2068	/// * `sender` - Must be either the owner of the collection or its admin.2069	/// * `properties` - Properties to be set.2070	fn set_collection_properties(2071		&self,2072		sender: T::CrossAccountId,2073		properties: Vec<Property>,2074	) -> DispatchResultWithPostInfo;20752076	/// Delete collection properties.2077	///2078	/// * `sender` - Must be either the owner of the collection or its admin.2079	/// * `properties` - The properties to be removed.2080	fn delete_collection_properties(2081		&self,2082		sender: &T::CrossAccountId,2083		property_keys: Vec<PropertyKey>,2084	) -> DispatchResultWithPostInfo;20852086	/// Set token properties.2087	///2088	/// The appropriate [`PropertyPermission`] for the token property2089	/// must be set with [`Self::set_token_property_permissions`].2090	///2091	/// * `sender` - Must be either the owner of the token or its admin.2092	/// * `token_id` - The token for which the properties are being set.2093	/// * `properties` - Properties to be set.2094	/// * `budget` - Budget for setting properties.2095	fn set_token_properties(2096		&self,2097		sender: T::CrossAccountId,2098		token_id: TokenId,2099		properties: Vec<Property>,2100		budget: &dyn Budget,2101	) -> DispatchResultWithPostInfo;21022103	/// Remove token properties.2104	///2105	/// The appropriate [`PropertyPermission`] for the token property2106	/// must be set with [`Self::set_token_property_permissions`].2107	///2108	/// * `sender` - Must be either the owner of the token or its admin.2109	/// * `token_id` - The token for which the properties are being remove.2110	/// * `property_keys` - Keys to remove corresponding properties.2111	/// * `budget` - Budget for removing properties.2112	fn delete_token_properties(2113		&self,2114		sender: T::CrossAccountId,2115		token_id: TokenId,2116		property_keys: Vec<PropertyKey>,2117		budget: &dyn Budget,2118	) -> DispatchResultWithPostInfo;21192120	/// Set token property permissions.2121	///2122	/// * `sender` - Must be either the owner of the token or its admin.2123	/// * `token_id` - The token for which the properties are being set.2124	/// * `property_permissions` - Property permissions to be set.2125	/// * `budget` - Budget for setting properties.2126	fn set_token_property_permissions(2127		&self,2128		sender: &T::CrossAccountId,2129		property_permissions: Vec<PropertyKeyPermission>,2130	) -> DispatchResultWithPostInfo;21312132	/// Transfer amount of token pieces.2133	///2134	/// * `sender` - Donor user.2135	/// * `to` - Recepient user.2136	/// * `token` - The token of which parts are being sent.2137	/// * `amount` - The number of parts of the token that will be transferred.2138	/// * `budget` - The maximum budget that can be spent on the transfer.2139	fn transfer(2140		&self,2141		sender: T::CrossAccountId,2142		to: T::CrossAccountId,2143		token: TokenId,2144		amount: u128,2145		budget: &dyn Budget,2146	) -> DispatchResultWithPostInfo;21472148	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2149	///2150	/// * `sender` - The user who grants access to the token.2151	/// * `spender` - The user to whom the rights are granted.2152	/// * `token` - The token to which access is granted.2153	/// * `amount` - The amount of pieces that another user can dispose of.2154	fn approve(2155		&self,2156		sender: T::CrossAccountId,2157		spender: T::CrossAccountId,2158		token: TokenId,2159		amount: u128,2160	) -> DispatchResultWithPostInfo;21612162	/// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2163	///2164	/// * `sender` - The user who grants access to the token.2165	/// * `from` - Spender's eth mirror.2166	/// * `to` - The user to whom the rights are granted.2167	/// * `token` - The token to which access is granted.2168	/// * `amount` - The amount of pieces that another user can dispose of.2169	fn approve_from(2170		&self,2171		sender: T::CrossAccountId,2172		from: T::CrossAccountId,2173		to: T::CrossAccountId,2174		token: TokenId,2175		amount: u128,2176	) -> DispatchResultWithPostInfo;21772178	/// Send parts of a token owned by another user.2179	///2180	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2181	///2182	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2183	/// * `from` - The user who owns the token.2184	/// * `to` - Recepient user.2185	/// * `token` - The token of which parts are being sent.2186	/// * `amount` - The number of parts of the token that will be transferred.2187	/// * `budget` - The maximum budget that can be spent on the transfer.2188	fn transfer_from(2189		&self,2190		sender: T::CrossAccountId,2191		from: T::CrossAccountId,2192		to: T::CrossAccountId,2193		token: TokenId,2194		amount: u128,2195		budget: &dyn Budget,2196	) -> DispatchResultWithPostInfo;21972198	/// Burn parts of a token owned by another user.2199	///2200	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2201	///2202	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2203	/// * `from` - The user who owns the token.2204	/// * `token` - The token of which parts are being sent.2205	/// * `amount` - The number of parts of the token that will be transferred.2206	/// * `budget` - The maximum budget that can be spent on the burn.2207	fn burn_from(2208		&self,2209		sender: T::CrossAccountId,2210		from: T::CrossAccountId,2211		token: TokenId,2212		amount: u128,2213		budget: &dyn Budget,2214	) -> DispatchResultWithPostInfo;22152216	/// Check permission to nest token.2217	///2218	/// * `sender` - The user who initiated the check.2219	/// * `from` - The token that is checked for embedding.2220	/// * `under` - Token under which to check.2221	/// * `budget` - The maximum budget that can be spent on the check.2222	fn check_nesting(2223		&self,2224		sender: T::CrossAccountId,2225		from: (CollectionId, TokenId),2226		under: TokenId,2227		budget: &dyn Budget,2228	) -> DispatchResult;22292230	/// Nest one token into another.2231	///2232	/// * `under` - Token holder.2233	/// * `to_nest` - Nested token.2234	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22352236	/// Unnest token.2237	///2238	/// * `under` - Token holder.2239	/// * `to_nest` - Token to unnest.2240	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));22412242	/// Get all user tokens.2243	///2244	/// * `account` - Account for which you need to get tokens.2245	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;22462247	/// Get all the tokens in the collection.2248	fn collection_tokens(&self) -> Vec<TokenId>;22492250	/// Check if the token exists.2251	///2252	/// * `token` - Id token to check.2253	fn token_exists(&self, token: TokenId) -> bool;22542255	/// Get the id of the last minted token.2256	fn last_token_id(&self) -> TokenId;22572258	/// Get the owner of the token.2259	///2260	/// * `token` - The token for which you need to find out the owner.2261	fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;22622263	/// Returns 10 tokens owners in no particular order.2264	///2265	/// * `token` - The token for which you need to find out the owners.2266	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;22672268	/// Get the value of the token property by key.2269	///2270	/// * `token` - Token with the property to get.2271	/// * `key` - Property name.2272	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;22732274	/// Get a set of token properties by key vector.2275	///2276	/// * `token` - Token with the property to get.2277	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2278	/// then all properties are returned.2279	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;22802281	/// Amount of unique collection tokens2282	fn total_supply(&self) -> u32;22832284	/// Amount of different tokens account has.2285	///2286	/// * `account` - The account for which need to get the balance.2287	fn account_balance(&self, account: T::CrossAccountId) -> u32;22882289	/// Amount of specific token account have.2290	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;22912292	/// Amount of token pieces2293	fn total_pieces(&self, token: TokenId) -> Option<u128>;22942295	/// Get the number of parts of the token that a trusted user can manage.2296	///2297	/// * `sender` - Trusted user.2298	/// * `spender` - Owner of the token.2299	/// * `token` - The token for which to get the value.2300	fn allowance(2301		&self,2302		sender: T::CrossAccountId,2303		spender: T::CrossAccountId,2304		token: TokenId,2305	) -> u128;23062307	/// Get extension for RFT collection.2308	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;23092310	/// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2311	/// * `owner` - Token owner2312	/// * `operator` - Operator2313	/// * `approve` - Should operator status be granted or revoked?2314	fn set_allowance_for_all(2315		&self,2316		owner: T::CrossAccountId,2317		operator: T::CrossAccountId,2318		approve: bool,2319	) -> DispatchResultWithPostInfo;23202321	/// Tells whether the given `owner` approves the `operator`.2322	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;23232324	/// Repairs a possibly broken item.2325	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2326}23272328/// Extension for RFT collection.2329pub trait RefungibleExtensions<T>2330where2331	T: Config,2332{2333	/// Change the number of parts of the token.2334	///2335	/// When the value changes down, this function is equivalent to burning parts of the token.2336	///2337	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.2338	/// * `token` - The token for which you want to change the number of parts.2339	/// * `amount` - The new value of the parts of the token.2340	fn repartition(2341		&self,2342		sender: &T::CrossAccountId,2343		token: TokenId,2344		amount: u128,2345	) -> DispatchResultWithPostInfo;2346}23472348/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2349///2350/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2351pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2352	let post_info = PostDispatchInfo {2353		actual_weight: Some(weight),2354		pays_fee: Pays::Yes,2355	};2356	match res {2357		Ok(()) => Ok(post_info),2358		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2359	}2360}23612362impl<T: Config> From<PropertiesError> for Error<T> {2363	fn from(error: PropertiesError) -> Self {2364		match error {2365			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2366			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2367			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2368			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2369			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2370		}2371	}2372}
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -38,8 +38,8 @@
 use sp_core::{U256, Get};
 
 use crate::{
-	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
-	weights::WeightInfo,
+	Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply,
+	SelfWeightOf, weights::WeightInfo,	
 };
 
 frontier_contract! {
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -47,7 +47,7 @@
 
 use crate::{
 	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
-	SelfWeightOf, weights::WeightInfo, TokenProperties,
+	TokenProperties, SelfWeightOf, weights::WeightInfo,
 };
 
 frontier_contract! {
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -214,7 +214,7 @@
 	/// usual [`TokenProperties`] due to an unlimited number
 	/// and separately stored and written-to key-value pairs.
 	///
-	/// Currently used to store RMRK data.
+	/// Currently unused.
 	#[pallet::storage]
 	#[pallet::getter(fn token_aux_property)]
 	pub type TokenAuxProperties<T: Config> = StorageNMap<
deletedpallets/proxy-rmrk-core/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/CHANGELOG.md
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- bureaucrate goes here -->
-## [v0.1.2] 2022-08-16
-
-### Other changes
-
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-
-- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
-
-Every extrinsic now runs in transaction implicitly, and
-`#[transactional]` on pallet dispatchable is now meaningless
-
-Upstream-Change: https://github.com/paritytech/substrate/issues/10806
-
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
\ No newline at end of file
deletedpallets/proxy-rmrk-core/Cargo.tomldiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/Cargo.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-[package]
-edition = "2021"
-license = "GPLv3"
-name = "pallet-rmrk-core"
-version = "0.1.2"
-
-[dependencies]
-# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
-codec = { workspace = true, package = "parity-scale-codec" }
-
-scale-info = { workspace = true }
-
-frame-benchmarking = { workspace = true, optional = true }
-frame-support = { workspace = true }
-frame-system = { workspace = true }
-pallet-common = { workspace = true }
-pallet-evm = { workspace = true }
-pallet-nonfungible = { workspace = true }
-pallet-structure = { workspace = true }
-rmrk-traits = { workspace = true }
-sp-runtime = { workspace = true }
-sp-std = { workspace = true }
-up-data-structs = { workspace = true }
-
-[features]
-default = ["std"]
-runtime-benchmarks = ['frame-benchmarking', 'frame-support/runtime-benchmarks', 'frame-system/runtime-benchmarks']
-std = [
-	"frame-support/std",
-	"frame-system/std",
-	"pallet-common/std",
-	"pallet-evm/std",
-	"pallet-nonfungible/std",
-	"pallet-structure/std",
-	"rmrk-traits/std",
-	"sp-runtime/std",
-	"sp-std/std",
-	"up-data-structs/std",
-	'frame-benchmarking/std',
-]
-try-runtime = ["frame-support/try-runtime"]
deletedpallets/proxy-rmrk-core/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/benchmarking.rs
+++ /dev/null
@@ -1,544 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_std::vec;
-
-use frame_benchmarking::{benchmarks, account};
-use frame_system::RawOrigin;
-use frame_support::{
-	traits::{Currency, Get},
-	BoundedVec,
-};
-use sp_runtime::Permill;
-
-use up_data_structs::*;
-
-use super::*;
-
-const SEED: u32 = 1;
-
-fn create_data<S: Get<u32>>() -> BoundedVec<u8, S> {
-	vec![b'A'; S::get() as usize].try_into().expect("size == S")
-}
-
-fn create_u32_array<S: Get<u32>>() -> BoundedVec<u32, S> {
-	vec![0; S::get() as usize].try_into().expect("size == S")
-}
-
-fn create_basic_resource() -> RmrkBasicResource {
-	RmrkBasicResource {
-		src: Some(create_data()),
-		metadata: Some(create_data()),
-		license: Some(create_data()),
-		thumb: Some(create_data()),
-	}
-}
-
-fn create_composable_resource() -> RmrkComposableResource {
-	RmrkComposableResource {
-		parts: create_u32_array(),
-		base: 100,
-		src: Some(create_data()),
-		metadata: Some(create_data()),
-		license: Some(create_data()),
-		thumb: Some(create_data()),
-	}
-}
-
-fn create_slot_resource() -> RmrkSlotResource {
-	RmrkSlotResource {
-		base: 100,
-		slot: 200,
-		src: Some(create_data()),
-		metadata: Some(create_data()),
-		license: Some(create_data()),
-		thumb: Some(create_data()),
-	}
-}
-
-fn create_max_resource_types_array<S: Get<u32>>(num: usize) -> BoundedVec<RmrkResourceTypes, S> {
-	vec![RmrkResourceTypes::Composable(create_composable_resource()); num]
-		.try_into()
-		.expect("num <= S")
-}
-
-fn create_max_collection<T: Config>(owner: &T::AccountId) -> DispatchResult {
-	<T as pallet_common::Config>::Currency::deposit_creating(
-		owner,
-		T::CollectionCreationPrice::get(),
-	);
-
-	let metadata = create_data();
-	let max = None;
-	let symbol = create_data();
-
-	<Pallet<T>>::create_collection(
-		RawOrigin::Signed(owner.clone()).into(),
-		metadata,
-		max,
-		symbol,
-	)
-}
-
-fn create_nft<T: Config>(owner: &T::AccountId, collection_id: RmrkCollectionId) -> DispatchResult {
-	let royalty_recipient = Some(owner.clone());
-	let royalty_amount = Some(Permill::from_percent(25));
-	let metadata = create_data();
-	let transferable = true;
-
-	<Pallet<T>>::mint_nft(
-		RawOrigin::Signed(owner.clone()).into(),
-		None,
-		collection_id,
-		royalty_recipient,
-		royalty_amount,
-		metadata,
-		transferable,
-		None,
-	)
-}
-
-struct NftBuilder {
-	collection_id: RmrkCollectionId,
-	current_nft_id: RmrkNftId,
-}
-
-impl NftBuilder {
-	fn new(collection_id: RmrkCollectionId) -> Self {
-		Self {
-			collection_id,
-			current_nft_id: 0,
-		}
-	}
-
-	fn build<T: Config>(&mut self, owner: &T::AccountId) -> Result<RmrkNftId, DispatchError> {
-		create_nft::<T>(owner, self.collection_id)?;
-		self.current_nft_id += 1;
-
-		Ok(self.current_nft_id)
-	}
-
-	fn build_tower<T: Config>(
-		&mut self,
-		owner: &T::AccountId,
-		height: u32,
-	) -> Result<(RmrkNftId, RmrkNftId), DispatchError> {
-		self.build::<T>(owner)?;
-
-		let root_nft_id = self.current_nft_id;
-		let mut prev_nft_id = root_nft_id;
-
-		for _ in 0..height {
-			self.build::<T>(owner)?;
-
-			let new_owner =
-				<RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(
-					self.collection_id,
-					prev_nft_id,
-				);
-
-			<Pallet<T>>::send(
-				RawOrigin::Signed(owner.clone()).into(),
-				self.collection_id,
-				self.current_nft_id,
-				new_owner,
-			)?;
-
-			prev_nft_id = self.current_nft_id;
-		}
-
-		let deepest_nft_id = self.current_nft_id;
-
-		Ok((root_nft_id, deepest_nft_id))
-	}
-
-	fn build_wide_tree<T: Config>(
-		&mut self,
-		owner: &T::AccountId,
-		width: u32,
-	) -> Result<RmrkNftId, DispatchError> {
-		self.build::<T>(owner)?;
-
-		let root_nft_id = self.current_nft_id;
-
-		let root_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(
-			self.collection_id,
-			root_nft_id,
-		);
-
-		for _ in 0..width {
-			self.build::<T>(owner)?;
-
-			<Pallet<T>>::send(
-				RawOrigin::Signed(owner.clone()).into(),
-				self.collection_id,
-				self.current_nft_id,
-				root_owner.clone(),
-			)?;
-		}
-
-		Ok(root_nft_id)
-	}
-}
-
-benchmarks! {
-	create_collection {
-		let caller = account("caller", 0, SEED);
-		<T as pallet_common::Config>::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get());
-		let metadata = create_data();
-		let max = None;
-		let symbol = create_data();
-	}: _(RawOrigin::Signed(caller), metadata, max, symbol)
-
-	destroy_collection {
-		let caller = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-	}: _(RawOrigin::Signed(caller), collection_id)
-
-	change_collection_issuer {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let new_owner: T::AccountId = account("new_owner", 0, SEED);
-
-		let new_owner_source = T::Lookup::unlookup(new_owner);
-	}: _(RawOrigin::Signed(caller), collection_id, new_owner_source)
-
-	lock_collection {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-	}: _(RawOrigin::Signed(caller), collection_id)
-
-	mint_nft {
-		let b in 0..100;
-
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-		let owner = caller.clone();
-
-		let royalty_recipient = Some(caller.clone());
-		let royalty_amount = Some(Permill::from_percent(25));
-		let metadata = create_data();
-		let transferable = true;
-	}:  _(
-		RawOrigin::Signed(caller),
-		None,
-		collection_id,
-		royalty_recipient,
-		royalty_amount,
-		metadata,
-		transferable,
-		Some(create_max_resource_types_array(b as usize))
-	)
-
-	burn_nft {
-		let b in 0..200;
-
-		let caller: T::AccountId = account("caller", 0, SEED);
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let root_nft_id  = nft_builder.build_wide_tree::<T>(&caller, b)?;
-		let max_burns = b + 1;
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		root_nft_id,
-		max_burns
-	)
-
-	send {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let src_nft_id = nft_builder.build::<T>(&caller)?;
-		let (_, target_nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 2)?;
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		src_nft_id,
-		<RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(collection_id, target_nft_id)
-	)
-
-	accept_nft {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let sender: T::AccountId = account("sender", 0, SEED);
-
-		create_max_collection::<T>(&sender)?;
-		let src_collection_id = 0;
-
-		create_max_collection::<T>(&caller)?;
-		let target_collection_id = 1;
-
-		let mut src_nft_builder = NftBuilder::new(src_collection_id);
-		let src_nft_id = src_nft_builder.build::<T>(&sender)?;
-
-		let mut target_nft_builder = NftBuilder::new(target_collection_id);
-		let fake_target_nft_id = target_nft_builder.build::<T>(&caller)?;
-		let (_, target_nft_id) = target_nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-
-		let new_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(
-			target_collection_id,
-			fake_target_nft_id
-		);
-
-		let actual_new_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(
-			target_collection_id,
-			target_nft_id
-		);
-
-		<Pallet<T>>::send(
-			RawOrigin::Signed(sender.clone()).into(),
-			src_collection_id,
-			src_nft_id,
-			new_owner,
-		)?;
-	}: _(
-		RawOrigin::Signed(caller),
-		src_collection_id,
-		src_nft_id,
-		actual_new_owner
-	)
-
-	reject_nft {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let sender: T::AccountId = account("sender", 0, SEED);
-
-		create_max_collection::<T>(&sender)?;
-		let src_collection_id = 0;
-
-		create_max_collection::<T>(&caller)?;
-		let target_collection_id = 1;
-
-		let mut src_nft_builder = NftBuilder::new(src_collection_id);
-		let (src_root_nft_id, _) = src_nft_builder.build_tower::<T>(&sender, NESTING_BUDGET - 1)?;
-
-		let mut target_nft_builder = NftBuilder::new(target_collection_id);
-		let target_nft_id = target_nft_builder.build::<T>(&caller)?;
-
-		let new_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::CollectionAndNftTuple(
-			target_collection_id,
-			target_nft_id
-		);
-
-		<Pallet<T>>::send(
-			RawOrigin::Signed(sender.clone()).into(),
-			src_collection_id,
-			src_root_nft_id,
-			new_owner,
-		)?;
-	}: _(
-		RawOrigin::Signed(caller),
-		src_collection_id,
-		src_root_nft_id
-	)
-
-	set_property {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-
-		let key = create_data();
-		let value = create_data();
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		Some(nft_id),
-		key,
-		value
-	)
-
-	set_priority {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-		let priorities = create_u32_array();
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nft_id,
-		priorities
-	)
-
-	add_basic_resource {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-		let resource = create_basic_resource();
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nft_id,
-		resource
-	)
-
-	add_composable_resource {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-		let resource = create_composable_resource();
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nft_id,
-		resource
-	)
-
-	add_slot_resource {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-		let resource = create_slot_resource();
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nft_id,
-		resource
-	)
-
-	remove_resource {
-		let caller: T::AccountId = account("caller", 0, SEED);
-
-		create_max_collection::<T>(&caller)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let (_, nft_id) = nft_builder.build_tower::<T>(&caller, NESTING_BUDGET - 1)?;
-		let resource = create_basic_resource();
-
-		<Pallet<T>>::add_basic_resource(
-			RawOrigin::Signed(caller.clone()).into(),
-			collection_id,
-			nft_id,
-			resource
-		)?;
-
-		let resource_id = 0;
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nft_id,
-		resource_id
-	)
-
-	accept_resource {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let admin: T::AccountId = account("admin", 0, SEED);
-
-		create_max_collection::<T>(&admin)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let root_nft_id = 1;
-		let (_, nested_nft_id) = nft_builder.build_tower::<T>(&admin, NESTING_BUDGET - 1)?;
-		let resource = create_basic_resource();
-
-		let new_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::AccountId(caller.clone());
-
-		<Pallet<T>>::send(
-			RawOrigin::Signed(admin.clone()).into(),
-			collection_id,
-			root_nft_id,
-			new_owner,
-		)?;
-
-		<Pallet<T>>::add_basic_resource(
-			RawOrigin::Signed(admin.clone()).into(),
-			collection_id,
-			nested_nft_id,
-			resource
-		)?;
-
-		let resource_id = 0;
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nested_nft_id,
-		resource_id
-	)
-
-	accept_resource_removal {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let admin: T::AccountId = account("admin", 0, SEED);
-
-		create_max_collection::<T>(&admin)?;
-		let collection_id = 0;
-
-		let mut nft_builder = NftBuilder::new(collection_id);
-		let root_nft_id = 1;
-		let (_, nested_nft_id) = nft_builder.build_tower::<T>(&admin, NESTING_BUDGET - 1)?;
-		let resource = create_basic_resource();
-
-		<Pallet<T>>::add_basic_resource(
-			RawOrigin::Signed(admin.clone()).into(),
-			collection_id,
-			nested_nft_id,
-			resource
-		)?;
-
-		let resource_id = 0;
-
-		let new_owner = <RmrkAccountIdOrCollectionNftTuple<T::AccountId>>::AccountId(caller.clone());
-
-		<Pallet<T>>::send(
-			RawOrigin::Signed(admin.clone()).into(),
-			collection_id,
-			root_nft_id,
-			new_owner,
-		)?;
-
-		<Pallet<T>>::remove_resource(
-			RawOrigin::Signed(admin).into(),
-			collection_id,
-			nested_nft_id,
-			resource_id
-		)?;
-	}: _(
-		RawOrigin::Signed(caller),
-		collection_id,
-		nested_nft_id,
-		resource_id
-	)
-}
deletedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ /dev/null
@@ -1,2119 +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/>.
-
-//! # RMRK Core Proxy Pallet
-//!
-//! A pallet used as proxy for RMRK Core (<https://rmrk-team.github.io/rmrk-substrate/#/pallets/rmrk-core>).
-//!
-//! - [`Config`]
-//! - [`Call`]
-//! - [`Pallet`]
-//!
-//! ## Overview
-//!
-//! The RMRK Core Proxy pallet mirrors the functionality of RMRK Core,
-//! binding its externalities to Unique's own underlying structure.
-//! It is purposed to mimic RMRK Core exactly, allowing seamless integrations
-//! of solutions based on RMRK.
-//!
-//! RMRK Core itself contains essential functionality for RMRK's nested and
-//! multi-resourced NFTs.
-//!
-//! *Note*, that while RMRK itself is subject to active development and restructuring,
-//! the proxy may be caught temporarily out of date.
-//!
-//! ### What is RMRK?
-//!
-//! RMRK is a set of NFT standards which compose several "NFT 2.0 lego" primitives.
-//! Putting these legos together allows a user to create NFT systems of arbitrary complexity.
-//!
-//! Meaning, RMRK NFTs are dynamic, able to nest into each other and form a hierarchy,
-//! make use of specific changeable and partially shared metadata in the form of resources,
-//! and more.
-//!
-//! Visit RMRK documentation and repositories to learn more:
-//! - Docs: <https://docs.rmrk.app/getting-started/>
-//! - FAQ: <https://coda.io/@rmrk/faq>
-//! - Substrate code repository: <https://github.com/rmrk-team/rmrk-substrate>
-//! - RMRK specification repository: <https://github.com/rmrk-team/rmrk-spec>
-//!
-//! ## Terminology
-//!
-//! For more information on RMRK, see RMRK's own documentation.
-//!
-//! ### Intro to RMRK
-//!
-//! - **Resource:** Additional piece of metadata of an NFT usually serving to add
-//! a piece of media on top of the root metadata (NFT's own), be it a different wing
-//! on the root template bird or something entirely unrelated.
-//!
-//! - **Base:** A list of possible "components" - Parts, a combination of which can
-//! be appended/equipped to/on an NFT.
-//!
-//! - **Part:** Something that, together with other Parts, can constitute an NFT.
-//! Parts are defined in the Base to which they belong. Parts can be either
-//! of the `slot` type or `fixed` type. Slots are intended for equippables.
-//! Note that "part of something" and "Part of a Base" can be easily confused,
-//! and so in this documentation these words are distinguished by the capital letter.
-//!
-//! - **Theme:** Named objects of variable => value pairs which get interpolated into
-//! the Base's `themable` Parts. Themes can hold any value, but are often represented
-//! in RMRK's examples as colors applied to visible Parts.
-//!
-//! ### Peculiarities in Unique
-//!
-//! - **Scoped properties:** Properties that are normally obscured from users.
-//! Their purpose is to contain structured metadata that was not included in the Unique standard
-//! for collections and tokens, meant to be operated on by proxies and other outliers.
-//! Scoped property keys are prefixed with `some-scope:`, where `some-scope` is
-//! an arbitrary keyword, like "rmrk". `:` is considered an unacceptable symbol in user-defined
-//! properties, which, along with other safeguards, makes scoped ones impossible to tamper with.
-//!
-//! - **Auxiliary properties:** A slightly different structure of properties,
-//! trading universality of use for more convenient storage, writes and access.
-//! Meant to be inaccessible to end users.
-//!
-//! ## Proxy Implementation
-//!
-//! An external user is supposed to be able to utilize this proxy as they would
-//! utilize RMRK, and get exactly the same results. Normally, Unique transactions
-//! are off-limits to RMRK collections and tokens, and vice versa. However,
-//! the information stored on chain can be freely interpreted by storage reads and Unique RPCs.
-//!
-//! ### ID Mapping
-//!
-//! RMRK's collections' IDs are counted independently of Unique's and start at 0.
-//! Note that tokens' IDs still start at 1.
-//! The collections themselves, as well as tokens, are stored as Unique collections,
-//! and thus RMRK IDs are mapped to Unique IDs (but not vice versa).
-//!
-//! ### External/Internal Collection Insulation
-//!
-//! A Unique transaction cannot target collections purposed for RMRK,
-//! and they are flagged as `external` to specify that. On the other hand,
-//! due to the mapping, RMRK transactions and RPCs simply cannot reach Unique collections.
-//!
-//! ### Native Properties
-//!
-//! Many of RMRK's native parameters are stored as scoped properties of a collection
-//! or an NFT on the chain. Scoped properties are prefixed with `rmrk:`, where `:`
-//! is an unacceptable symbol in user-defined properties, which, along with other safeguards,
-//! makes them impossible to tamper with.
-//!
-//! ### Collection and NFT Types, or Base, Parts and Themes Handling
-//!
-//! RMRK introduces the concept of a Base, which is a catalogue of Parts,
-//! possible components of an NFT. Due to its similarity with the functionality
-//! of a token collection, a Base is stored and handled as one, and the Base's Parts and Themes
-//! are this collection's NFTs. See [`CollectionType`] and [`NftType`].
-//!
-//! ## Interface
-//!
-//! ### Dispatchables
-//!
-//! - `create_collection` - Create a new collection of NFTs.
-//! - `destroy_collection` - Destroy a collection.
-//! - `change_collection_issuer` - Change the issuer of a collection.
-//! Analogous to Unique's collection's [`owner`](up_data_structs::Collection).
-//! - `lock_collection` - "Lock" the collection and prevent new token creation. **Cannot be undone.**
-//! - `mint_nft` - Mint an NFT in a specified collection.
-//! - `burn_nft` - Burn an NFT, destroying it and its nested tokens.
-//! - `send` - Transfer an NFT from an account/NFT A to another account/NFT B.
-//! - `accept_nft` - Accept an NFT sent from another account to self or an owned NFT.
-//! - `reject_nft` - Reject an NFT sent from another account to self or owned NFT and **burn it**.
-//! - `accept_resource` - Accept the addition of a newly created pending resource to an existing NFT.
-//! - `accept_resource_removal` - Accept the removal of a removal-pending resource from an NFT.
-//! - `set_property` - Add or edit a custom user property of a token or a collection.
-//! - `set_priority` - Set a different order of resource priorities for an NFT.
-//! - `add_basic_resource` - Create and set/propose a basic resource for an NFT.
-//! - `add_composable_resource` - Create and set/propose a composable resource for an NFT.
-//! - `add_slot_resource` - Create and set/propose a slot resource for an NFT.
-//! - `remove_resource` - Remove and erase a resource from an NFT.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use frame_support::{pallet_prelude::*, BoundedVec, dispatch::DispatchResult};
-use frame_system::{pallet_prelude::*, ensure_signed};
-use sp_runtime::{DispatchError, Permill, traits::StaticLookup};
-use sp_std::{
-	vec::Vec,
-	collections::{btree_set::BTreeSet, btree_map::BTreeMap},
-};
-use up_data_structs::{*, mapping::TokenAddressMapping};
-use pallet_common::{
-	Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations,
-};
-use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle, TokenData};
-use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
-use pallet_evm::account::CrossAccountId;
-use core::convert::AsRef;
-
-pub use pallet::*;
-
-#[cfg(feature = "runtime-benchmarks")]
-pub mod benchmarking;
-pub mod misc;
-pub mod property;
-pub mod rpc;
-pub mod weights;
-
-pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
-
-use weights::WeightInfo;
-use misc::*;
-pub use property::*;
-
-use RmrkProperty::*;
-
-/// A maximum number of levels of depth in the token nesting tree.
-pub const NESTING_BUDGET: u32 = 5;
-
-type PendingTarget = (CollectionId, TokenId);
-type PendingChild = (RmrkCollectionId, RmrkNftId);
-type PendingChildrenSet = BTreeSet<PendingChild>;
-
-type BasesMap = BTreeMap<RmrkBaseId, u32>;
-
-#[frame_support::pallet]
-pub mod pallet {
-	use super::*;
-
-	#[pallet::config]
-	pub trait Config:
-		frame_system::Config
-		+ pallet_common::Config
-		+ pallet_nonfungible::Config
-		+ pallet_evm::Config
-	{
-		/// Overarching event type.
-		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
-
-		/// The weight information of this pallet.
-		type WeightInfo: WeightInfo;
-	}
-
-	/// Latest yet-unused collection ID.
-	#[pallet::storage]
-	#[pallet::getter(fn collection_index)]
-	pub type CollectionIndex<T: Config> = StorageValue<_, RmrkCollectionId, ValueQuery>;
-
-	/// Mapping from RMRK collection ID to Unique's.
-	#[pallet::storage]
-	pub type UniqueCollectionId<T: Config> =
-		StorageMap<_, Twox64Concat, RmrkCollectionId, CollectionId, ValueQuery>;
-
-	#[pallet::pallet]
-	#[pallet::generate_store(pub(super) trait Store)]
-	pub struct Pallet<T>(_);
-
-	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
-	pub enum Event<T: Config> {
-		CollectionCreated {
-			issuer: T::AccountId,
-			collection_id: RmrkCollectionId,
-		},
-		CollectionDestroyed {
-			issuer: T::AccountId,
-			collection_id: RmrkCollectionId,
-		},
-		IssuerChanged {
-			old_issuer: T::AccountId,
-			new_issuer: T::AccountId,
-			collection_id: RmrkCollectionId,
-		},
-		CollectionLocked {
-			issuer: T::AccountId,
-			collection_id: RmrkCollectionId,
-		},
-		NftMinted {
-			owner: T::AccountId,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-		},
-		NFTBurned {
-			owner: T::AccountId,
-			nft_id: RmrkNftId,
-		},
-		NFTSent {
-			sender: T::AccountId,
-			recipient: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			approval_required: bool,
-		},
-		NFTAccepted {
-			sender: T::AccountId,
-			recipient: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-		},
-		NFTRejected {
-			sender: T::AccountId,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-		},
-		PropertySet {
-			collection_id: RmrkCollectionId,
-			maybe_nft_id: Option<RmrkNftId>,
-			key: RmrkKeyString,
-			value: RmrkValueString,
-		},
-		ResourceAdded {
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		},
-		ResourceRemoval {
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		},
-		ResourceAccepted {
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		},
-		ResourceRemovalAccepted {
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		},
-		PrioritySet {
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-		},
-	}
-
-	#[pallet::error]
-	pub enum Error<T> {
-		/* Unique proxy-specific events */
-		/// Property of the type of RMRK collection could not be read successfully.
-		CorruptedCollectionType,
-		// NftTypeEncodeError,
-		/// Too many symbols supplied as the property key. The maximum is [256](up_data_structs::MAX_PROPERTY_KEY_LENGTH).
-		RmrkPropertyKeyIsTooLong,
-		/// Too many bytes supplied as the property value. The maximum is [32768](up_data_structs::MAX_PROPERTY_VALUE_LENGTH).
-		RmrkPropertyValueIsTooLong,
-		/// Could not find a property by the supplied key.
-		RmrkPropertyIsNotFound,
-		/// Something went wrong when decoding encoded data from the storage.
-		/// Perhaps, there was a wrong key supplied for the type, or the data was improperly stored.
-		UnableToDecodeRmrkData,
-
-		/* RMRK compatible events */
-		/// Only destroying collections without tokens is allowed.
-		CollectionNotEmpty,
-		/// Could not find an ID for a collection. It is likely there were too many collections created on the chain, causing an overflow.
-		NoAvailableCollectionId,
-		/// Token does not exist, or there is no suitable ID for it, likely too many tokens were created in a collection, causing an overflow.
-		NoAvailableNftId,
-		/// Collection does not exist, has a wrong type, or does not map to a Unique ID.
-		CollectionUnknown,
-		/// No permission to perform action.
-		NoPermission,
-		/// Token is marked as non-transferable, and thus cannot be transferred.
-		NonTransferable,
-		/// Too many tokens created in the collection, no new ones are allowed.
-		CollectionFullOrLocked,
-		/// No such resource found.
-		ResourceDoesntExist,
-		/// If an NFT is sent to a descendant, that would form a nesting loop, an ouroboros.
-		/// Sending to self is redundant.
-		CannotSendToDescendentOrSelf,
-		/// Not the target owner of the sent NFT.
-		CannotAcceptNonOwnedNft,
-		/// Not the target owner of the sent NFT.
-		CannotRejectNonOwnedNft,
-		/// NFT was not sent and is not pending.
-		CannotRejectNonPendingNft,
-		/// Resource is not pending for the operation.
-		ResourceNotPending,
-		/// Could not find an ID for the resource. It is likely there were too many resources created on an NFT, causing an overflow.
-		NoAvailableResourceId,
-	}
-
-	#[pallet::call]
-	impl<T: Config> Pallet<T> {
-		// todo :refactor replace every collection_id with rmrk_collection_id (and nft_id) in arguments for uniformity?
-
-		/// Create a new collection of NFTs.
-		///
-		/// # Permissions:
-		/// * Anyone - will be assigned as the issuer of the collection.
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `metadata`: Metadata describing the collection, e.g. IPFS hash. Cannot be changed.
-		/// - `max`: Optional maximum number of tokens.
-		/// - `symbol`: UTF-8 string with token prefix, by which to represent the token in wallets and UIs.
-		/// Analogous to Unique's [`token_prefix`](up_data_structs::Collection). Cannot be changed.
-		#[pallet::call_index(0)]
-		#[pallet::weight(<SelfWeightOf<T>>::create_collection())]
-		pub fn create_collection(
-			origin: OriginFor<T>,
-			metadata: RmrkString,
-			max: Option<u32>,
-			symbol: RmrkCollectionSymbol,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-
-			let limits = CollectionLimits {
-				owner_can_transfer: Some(false),
-				token_limit: max,
-				..Default::default()
-			};
-
-			let data = CreateCollectionData {
-				limits: Some(limits),
-				token_prefix: symbol
-					.into_inner()
-					.try_into()
-					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
-				permissions: Some(CollectionPermissions {
-					nesting: Some(NestingPermissions {
-						token_owner: true,
-						collection_admin: false,
-						restricted: None,
-						#[cfg(feature = "runtime-benchmarks")]
-						permissive: false,
-					}),
-					..Default::default()
-				}),
-				..Default::default()
-			};
-
-			let unique_collection_id = Self::init_collection(
-				T::CrossAccountId::from_sub(sender.clone()),
-				data,
-				[
-					Self::encode_rmrk_property(Metadata, &metadata)?,
-					Self::encode_rmrk_property(CollectionType, &misc::CollectionType::Regular)?,
-				]
-				.into_iter(),
-			)?;
-			let rmrk_collection_id = <CollectionIndex<T>>::get();
-
-			<UniqueCollectionId<T>>::insert(rmrk_collection_id, unique_collection_id);
-
-			<PalletCommon<T>>::set_scoped_collection_property(
-				unique_collection_id,
-				RMRK_SCOPE,
-				Self::encode_rmrk_property(RmrkInternalCollectionId, &rmrk_collection_id)?,
-			)?;
-
-			<CollectionIndex<T>>::mutate(|n| *n += 1);
-
-			Self::deposit_event(Event::CollectionCreated {
-				issuer: sender,
-				collection_id: rmrk_collection_id,
-			});
-
-			Ok(())
-		}
-
-		/// Destroy a collection.
-		///
-		/// Only empty collections can be destroyed. If it has any tokens, they must be burned first.
-		///
-		/// # Permissions:
-		/// * Collection issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `collection_id`: RMRK ID of the collection to destroy.
-		#[pallet::call_index(1)]
-		#[pallet::weight(<SelfWeightOf<T>>::destroy_collection())]
-		pub fn destroy_collection(
-			origin: OriginFor<T>,
-			collection_id: RmrkCollectionId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection = Self::get_typed_nft_collection(
-				Self::unique_collection_id(collection_id)?,
-				misc::CollectionType::Regular,
-			)?;
-			collection.check_is_external()?;
-
-			<PalletNft<T>>::destroy_collection(collection, &cross_sender)
-				.map_err(Self::map_unique_err_to_proxy)?;
-
-			Self::deposit_event(Event::CollectionDestroyed {
-				issuer: sender,
-				collection_id,
-			});
-
-			Ok(())
-		}
-
-		/// Change the issuer of a collection. Analogous to Unique's collection's [`owner`](up_data_structs::Collection).
-		///
-		/// # Permissions:
-		/// * Collection issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `collection_id`: RMRK collection ID to change the issuer of.
-		/// - `new_issuer`: Collection's new issuer.
-		#[pallet::call_index(2)]
-		#[pallet::weight(<SelfWeightOf<T>>::change_collection_issuer())]
-		pub fn change_collection_issuer(
-			origin: OriginFor<T>,
-			collection_id: RmrkCollectionId,
-			new_issuer: <T::Lookup as StaticLookup>::Source,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-
-			let collection = Self::get_nft_collection(Self::unique_collection_id(collection_id)?)?;
-			collection.check_is_external()?;
-
-			let new_issuer = T::Lookup::lookup(new_issuer)?;
-
-			Self::change_collection_owner(
-				Self::unique_collection_id(collection_id)?,
-				misc::CollectionType::Regular,
-				sender.clone(),
-				new_issuer.clone(),
-			)?;
-
-			Self::deposit_event(Event::IssuerChanged {
-				old_issuer: sender,
-				new_issuer,
-				collection_id,
-			});
-
-			Ok(())
-		}
-
-		/// "Lock" the collection and prevent new token creation. Cannot be undone.
-		///
-		/// # Permissions:
-		/// * Collection issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `collection_id`: RMRK ID of the collection to lock.
-		#[pallet::call_index(3)]
-		#[pallet::weight(<SelfWeightOf<T>>::lock_collection())]
-		pub fn lock_collection(
-			origin: OriginFor<T>,
-			collection_id: RmrkCollectionId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection = Self::get_typed_nft_collection(
-				Self::unique_collection_id(collection_id)?,
-				misc::CollectionType::Regular,
-			)?;
-			collection.check_is_external()?;
-
-			Self::check_collection_owner(&collection, &cross_sender)?;
-
-			let token_count = collection.total_supply();
-
-			let mut collection = collection.into_inner();
-			collection.limits.token_limit = Some(token_count);
-			collection.save()?;
-
-			Self::deposit_event(Event::CollectionLocked {
-				issuer: sender,
-				collection_id,
-			});
-
-			Ok(())
-		}
-
-		/// Mint an NFT in a specified collection.
-		///
-		/// # Permissions:
-		/// * Collection issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `owner`: Owner account of the NFT. If set to None, defaults to the sender (collection issuer).
-		/// - `collection_id`: RMRK collection ID for the NFT to be minted within. Cannot be changed.
-		/// - `recipient`: Receiver account of the royalty. Has no effect if the `royalty_amount` is not set. Cannot be changed.
-		/// - `royalty_amount`: Optional permillage reward from each trade for the `recipient`. Cannot be changed.
-		/// - `metadata`: Arbitrary data about an NFT, e.g. IPFS hash. Cannot be changed.
-		/// - `transferable`: Can this NFT be transferred? Cannot be changed.
-		/// - `resources`: Resource data to be added to the NFT immediately after minting.
-		#[pallet::call_index(4)]
-		#[pallet::weight(<SelfWeightOf<T>>::mint_nft(resources.as_ref().map(|r| r.len() as u32).unwrap_or(0)))]
-		pub fn mint_nft(
-			origin: OriginFor<T>,
-			owner: Option<T::AccountId>,
-			collection_id: RmrkCollectionId,
-			recipient: Option<T::AccountId>,
-			royalty_amount: Option<Permill>,
-			metadata: RmrkString,
-			transferable: bool,
-			resources: Option<BoundedVec<RmrkResourceTypes, MaxResourcesOnMint>>,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let owner = owner.unwrap_or(sender.clone());
-			let cross_owner = T::CrossAccountId::from_sub(owner.clone());
-
-			let collection = Self::get_typed_nft_collection(
-				Self::unique_collection_id(collection_id)?,
-				misc::CollectionType::Regular,
-			)?;
-			collection.check_is_external()?;
-
-			let royalty_info = royalty_amount.map(|amount| rmrk_traits::RoyaltyInfo {
-				recipient: recipient.unwrap_or_else(|| owner.clone()),
-				amount,
-			});
-
-			let nft_id = Self::create_nft(
-				&cross_sender,
-				&cross_owner,
-				&collection,
-				[
-					Self::encode_rmrk_property(TokenType, &NftType::Regular)?,
-					Self::encode_rmrk_property(Transferable, &transferable)?,
-					Self::encode_rmrk_property(PendingNftAccept, &None::<PendingTarget>)?,
-					Self::encode_rmrk_property(RoyaltyInfo, &royalty_info)?,
-					Self::encode_rmrk_property(Metadata, &metadata)?,
-					Self::encode_rmrk_property(Equipped, &false)?,
-					Self::encode_rmrk_property(ResourcePriorities, &<Vec<u8>>::new())?,
-					Self::encode_rmrk_property(NextResourceId, &(0 as RmrkResourceId))?,
-					Self::encode_rmrk_property(PendingChildren, &PendingChildrenSet::new())?,
-					Self::encode_rmrk_property(AssociatedBases, &BasesMap::new())?,
-				]
-				.into_iter(),
-			)
-			.map_err(|err| match err {
-				DispatchError::Arithmetic(_) => <Error<T>>::NoAvailableNftId.into(),
-				err => Self::map_unique_err_to_proxy(err),
-			})?;
-
-			if let Some(resources) = resources {
-				for resource in resources {
-					Self::resource_add(sender.clone(), collection.id, nft_id, resource)?;
-				}
-			}
-
-			Self::deposit_event(Event::NftMinted {
-				owner,
-				collection_id,
-				nft_id: nft_id.0,
-			});
-
-			Ok(())
-		}
-
-		/// Burn an NFT, destroying it and its nested tokens up to the specified limit.
-		/// If the burning budget is exceeded, the transaction is reverted.
-		///
-		/// This is the way to burn a nested token as well.
-		///
-		/// For more information, see [`burn_recursively`](pallet_nonfungible::pallet::Pallet::burn_recursively).
-		///
-		/// # Permissions:
-		/// * Token owner
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `collection_id`: RMRK ID of the collection in which the NFT to burn belongs to.
-		/// - `nft_id`: ID of the NFT to be destroyed.
-		/// - `max_burns`: Maximum number of tokens to burn, assuming nesting. The transaction
-		/// is reverted if there are more tokens to burn in the nesting tree than this number.
-		/// This is primarily a mechanism of transaction weight control.
-		#[pallet::call_index(5)]
-		#[pallet::weight(<SelfWeightOf<T>>::burn_nft(*max_burns))]
-		pub fn burn_nft(
-			origin: OriginFor<T>,
-			collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			max_burns: u32,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection = Self::get_typed_nft_collection(
-				Self::unique_collection_id(collection_id)?,
-				misc::CollectionType::Regular,
-			)?;
-			collection.check_is_external()?;
-
-			Self::destroy_nft(
-				cross_sender,
-				Self::unique_collection_id(collection_id)?,
-				nft_id.into(),
-				max_burns,
-				<Error<T>>::NoPermission,
-			)
-			.map_err(|err| Self::map_unique_err_to_proxy(err.error))?;
-
-			Self::deposit_event(Event::NFTBurned {
-				owner: sender,
-				nft_id,
-			});
-
-			Ok(())
-		}
-
-		/// Transfer an NFT from an account/NFT A to another account/NFT B.
-		/// The token must be transferable. Nesting cannot occur deeper than the [`NESTING_BUDGET`].
-		///
-		/// If the target owner is an NFT owned by another account, then the NFT will enter
-		/// the pending state and will have to be accepted by the other account.
-		///
-		/// # Permissions:
-		/// - Token owner
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK ID of the collection of the NFT to be transferred.
-		/// - `rmrk_nft_id`: ID of the NFT to be transferred.
-		/// - `new_owner`: New owner of the nft which can be either an account or a NFT.
-		#[pallet::call_index(6)]
-		#[pallet::weight(<SelfWeightOf<T>>::send())]
-		pub fn send(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-			new_owner: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let nft_id = rmrk_nft_id.into();
-
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let token_data =
-				<TokenData<T>>::get((collection_id, nft_id)).ok_or(<Error<T>>::NoAvailableNftId)?;
-
-			let from = token_data.owner;
-
-			ensure!(
-				Self::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Transferable)?,
-				<Error<T>>::NonTransferable
-			);
-
-			ensure!(
-				Self::get_nft_property_decoded::<Option<PendingTarget>>(
-					collection_id,
-					nft_id,
-					RmrkProperty::PendingNftAccept
-				)?
-				.is_none(),
-				<Error<T>>::NoPermission
-			);
-
-			let target_owner;
-			let approval_required;
-
-			match new_owner {
-				RmrkAccountIdOrCollectionNftTuple::AccountId(ref account_id) => {
-					target_owner = T::CrossAccountId::from_sub(account_id.clone());
-					approval_required = false;
-				}
-				RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(
-					target_collection_id,
-					target_nft_id,
-				) => {
-					let target_collection_id = Self::unique_collection_id(target_collection_id)?;
-
-					let target_nft_budget = budget::Value::new(NESTING_BUDGET);
-
-					let target_nft_owner = <PalletStructure<T>>::get_checked_topmost_owner(
-						target_collection_id,
-						target_nft_id.into(),
-						Some((collection_id, nft_id)),
-						&target_nft_budget,
-					)
-					.map_err(Self::map_unique_err_to_proxy)?
-					.ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
-
-					approval_required = cross_sender != target_nft_owner;
-
-					if approval_required {
-						target_owner = target_nft_owner;
-
-						<PalletNft<T>>::set_scoped_token_property(
-							collection.id,
-							nft_id,
-							RMRK_SCOPE,
-							Self::encode_rmrk_property::<Option<PendingTarget>>(
-								PendingNftAccept,
-								&Some((target_collection_id, target_nft_id.into())),
-							)?,
-						)?;
-
-						Self::insert_pending_child(
-							(target_collection_id, target_nft_id.into()),
-							(rmrk_collection_id, rmrk_nft_id),
-						)?;
-					} else {
-						target_owner = T::CrossTokenAddressMapping::token_to_address(
-							target_collection_id,
-							target_nft_id.into(),
-						);
-					}
-				}
-			}
-
-			let src_nft_budget = budget::Value::new(NESTING_BUDGET);
-
-			<PalletNft<T>>::transfer_from(
-				&collection,
-				&cross_sender,
-				&from,
-				&target_owner,
-				nft_id,
-				&src_nft_budget,
-			)
-			.map_err(Self::map_unique_err_to_proxy)?;
-
-			Self::deposit_event(Event::NFTSent {
-				sender,
-				recipient: new_owner,
-				collection_id: rmrk_collection_id,
-				nft_id: rmrk_nft_id,
-				approval_required,
-			});
-
-			Ok(())
-		}
-
-		/// Accept an NFT sent from another account to self or an owned NFT.
-		///
-		/// The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first.
-		///
-		/// # Permissions:
-		/// - Token-owner-to-be
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT to be accepted.
-		/// - `rmrk_nft_id`: ID of the NFT to be accepted.
-		/// - `new_owner`: Either the sender's account ID or a sender-owned NFT,
-		/// whichever the accepted NFT was sent to.
-		#[pallet::call_index(7)]
-		#[pallet::weight(<SelfWeightOf<T>>::accept_nft())]
-		pub fn accept_nft(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-			new_owner: RmrkAccountIdOrCollectionNftTuple<T::AccountId>,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let nft_id = rmrk_nft_id.into();
-
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let new_cross_owner = match new_owner {
-				RmrkAccountIdOrCollectionNftTuple::AccountId(ref account_id) => {
-					T::CrossAccountId::from_sub(account_id.clone())
-				}
-				RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(
-					target_collection_id,
-					target_nft_id,
-				) => {
-					let target_collection_id = Self::unique_collection_id(target_collection_id)?;
-
-					T::CrossTokenAddressMapping::token_to_address(
-						target_collection_id,
-						TokenId(target_nft_id),
-					)
-				}
-			};
-
-			let budget = budget::Value::new(NESTING_BUDGET);
-
-			<PalletNft<T>>::transfer(
-				&collection,
-				&cross_sender,
-				&new_cross_owner,
-				nft_id,
-				&budget,
-			)
-			.map_err(|err| {
-				if err == <CommonError<T>>::UserIsNotAllowedToNest.into() {
-					<Error<T>>::CannotAcceptNonOwnedNft.into()
-				} else {
-					Self::map_unique_err_to_proxy(err)
-				}
-			})?;
-
-			let pending_target = Self::get_nft_property_decoded::<Option<PendingTarget>>(
-				collection_id,
-				nft_id,
-				RmrkProperty::PendingNftAccept,
-			)?;
-
-			if let Some(pending_target) = pending_target {
-				Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?;
-
-				<PalletNft<T>>::set_scoped_token_property(
-					collection.id,
-					nft_id,
-					RMRK_SCOPE,
-					Self::encode_rmrk_property(PendingNftAccept, &None::<PendingTarget>)?,
-				)?;
-			}
-
-			Self::deposit_event(Event::NFTAccepted {
-				sender,
-				recipient: new_owner,
-				collection_id: rmrk_collection_id,
-				nft_id: rmrk_nft_id,
-			});
-
-			Ok(())
-		}
-
-		/// Reject an NFT sent from another account to self or owned NFT.
-		/// The NFT in question will not be sent back and burnt instead.
-		///
-		/// The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first.
-		///
-		/// # Permissions:
-		/// - Token-owner-to-be-not
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK ID of the NFT to be rejected.
-		/// - `rmrk_nft_id`: ID of the NFT to be rejected.
-		#[pallet::call_index(8)]
-		#[pallet::weight(<SelfWeightOf<T>>::reject_nft())]
-		pub fn reject_nft(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let nft_id = rmrk_nft_id.into();
-
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			ensure!(
-				<TokenData<T>>::get((collection_id, nft_id)).is_some(),
-				<Error<T>>::NoAvailableNftId
-			);
-
-			let pending_target = Self::get_nft_property_decoded::<Option<PendingTarget>>(
-				collection_id,
-				nft_id,
-				RmrkProperty::PendingNftAccept,
-			)?;
-
-			match pending_target {
-				Some(pending_target) => {
-					Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?
-				}
-				None => return Err(<Error<T>>::CannotRejectNonPendingNft.into()),
-			}
-
-			Self::destroy_nft(
-				cross_sender,
-				collection_id,
-				nft_id,
-				NESTING_BUDGET,
-				<Error<T>>::CannotRejectNonOwnedNft,
-			)
-			.map_err(|err| Self::map_unique_err_to_proxy(err.error))?;
-
-			Self::deposit_event(Event::NFTRejected {
-				sender,
-				collection_id: rmrk_collection_id,
-				nft_id: rmrk_nft_id,
-			});
-
-			Ok(())
-		}
-
-		/// Accept the addition of a newly created pending resource to an existing NFT.
-		///
-		/// This transaction is needed when a resource is created and assigned to an NFT
-		/// by a non-owner, i.e. the collection issuer, with one of the
-		/// [`add_...` transactions](Pallet::add_basic_resource).
-		///
-		/// # Permissions:
-		/// - Token owner
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `rmrk_nft_id`: ID of the NFT with a pending resource to be accepted.
-		/// - `resource_id`: ID of the newly created pending resource.
-		/// accept the addition of a new resource to an existing NFT
-		#[pallet::call_index(9)]
-		#[pallet::weight(<SelfWeightOf<T>>::accept_resource())]
-		pub fn accept_resource(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender);
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)
-				.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let nft_id = rmrk_nft_id.into();
-
-			let budget = budget::Value::new(NESTING_BUDGET);
-
-			let nft_owner =
-				<PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
-					.map_err(|_| <Error<T>>::ResourceDoesntExist)?
-					.ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
-
-			Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
-				ensure!(res.pending, <Error<T>>::ResourceNotPending);
-				ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
-
-				res.pending = false;
-
-				Ok(())
-			})?;
-
-			Self::deposit_event(Event::<T>::ResourceAccepted {
-				nft_id: rmrk_nft_id,
-				resource_id,
-			});
-
-			Ok(())
-		}
-
-		/// Accept the removal of a removal-pending resource from an NFT.
-		///
-		/// This transaction is needed when a non-owner, i.e. the collection issuer,
-		/// requests a [removal](`Pallet::remove_resource`) of a resource from an NFT.
-		///
-		/// # Permissions:
-		/// - Token owner
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `rmrk_nft_id`: ID of the NFT with a resource to be removed.
-		/// - `resource_id`: ID of the removal-pending resource.
-		#[pallet::call_index(10)]
-		#[pallet::weight(<SelfWeightOf<T>>::accept_resource_removal())]
-		pub fn accept_resource_removal(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender);
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)
-				.map_err(|_| <Error<T>>::ResourceDoesntExist)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let nft_id = rmrk_nft_id.into();
-
-			let budget = budget::Value::new(NESTING_BUDGET);
-
-			let nft_owner =
-				<PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
-					.map_err(|_| <Error<T>>::ResourceDoesntExist)?
-					.ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
-
-			ensure!(cross_sender == nft_owner, <Error<T>>::NoPermission);
-
-			let resource_id_key = Self::get_scoped_property_key(ResourceId(resource_id))?;
-
-			let resource_info = <PalletNft<T>>::token_aux_property((
-				collection_id,
-				nft_id,
-				RMRK_SCOPE,
-				resource_id_key.clone(),
-			))
-			.ok_or(<Error<T>>::ResourceDoesntExist)?;
-
-			let resource_info: RmrkResourceInfo = Self::decode_property_value(&resource_info)?;
-
-			ensure!(
-				resource_info.pending_removal,
-				<Error<T>>::ResourceNotPending
-			);
-
-			<PalletNft<T>>::remove_token_aux_property(
-				collection_id,
-				nft_id,
-				RMRK_SCOPE,
-				resource_id_key,
-			);
-
-			if let RmrkResourceTypes::Composable(resource) = resource_info.resource {
-				let base_id = resource.base;
-
-				Self::remove_associated_base_id(collection_id, nft_id, base_id)?;
-			}
-
-			Self::deposit_event(Event::<T>::ResourceRemovalAccepted {
-				nft_id: rmrk_nft_id,
-				resource_id,
-			});
-
-			Ok(())
-		}
-
-		/// Add or edit a custom user property, a key-value pair, describing the metadata
-		/// of a token or a collection, on either one of these.
-		///
-		/// Note that in this proxy implementation many details regarding RMRK are stored
-		/// as scoped properties prefixed with "rmrk:", normally inaccessible
-		/// to external transactions and RPCs.
-		///
-		/// # Permissions:
-		/// - Collection issuer - in case of collection property
-		/// - Token owner - in case of NFT property
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID.
-		/// - `maybe_nft_id`: Optional ID of the NFT. If left empty, then the property is set for the collection.
-		/// - `key`: Key of the custom property to be referenced by.
-		/// - `value`: Value of the custom property to be stored.
-		#[pallet::call_index(11)]
-		#[pallet::weight(<SelfWeightOf<T>>::set_property())]
-		pub fn set_property(
-			origin: OriginFor<T>,
-			#[pallet::compact] rmrk_collection_id: RmrkCollectionId,
-			maybe_nft_id: Option<RmrkNftId>,
-			key: RmrkKeyString,
-			value: RmrkValueString,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let sender = T::CrossAccountId::from_sub(sender);
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let budget = budget::Value::new(NESTING_BUDGET);
-
-			match maybe_nft_id {
-				Some(nft_id) => {
-					let token_id: TokenId = nft_id.into();
-
-					Self::ensure_nft_type(collection_id, token_id, NftType::Regular)?;
-					Self::ensure_nft_owner(collection_id, token_id, &sender, &budget)?;
-
-					<PalletNft<T>>::set_scoped_token_property(
-						collection_id,
-						token_id,
-						RMRK_SCOPE,
-						Self::encode_rmrk_property(UserProperty(key.as_slice()), &value)?,
-					)?;
-				}
-				None => {
-					let collection = Self::get_typed_nft_collection(
-						collection_id,
-						misc::CollectionType::Regular,
-					)?;
-
-					Self::check_collection_owner(&collection, &sender)?;
-
-					<PalletCommon<T>>::set_scoped_collection_property(
-						collection_id,
-						RMRK_SCOPE,
-						Self::encode_rmrk_property(UserProperty(key.as_slice()), &value)?,
-					)?;
-				}
-			}
-
-			Self::deposit_event(Event::PropertySet {
-				collection_id: rmrk_collection_id,
-				maybe_nft_id,
-				key,
-				value,
-			});
-
-			Ok(())
-		}
-
-		/// Set a different order of resource priorities for an NFT. Priorities can be used,
-		/// for example, for order of rendering.
-		///
-		/// Note that the priorities are not updated automatically, and are an empty vector
-		/// by default. There is no pre-set definition for the order to be particular,
-		/// it can be interpreted arbitrarily use-case by use-case.
-		///
-		/// # Permissions:
-		/// - Token owner
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `rmrk_nft_id`: ID of the NFT to rearrange resource priorities for.
-		/// - `priorities`: Ordered vector of resource IDs.
-		#[pallet::call_index(12)]
-		#[pallet::weight(<SelfWeightOf<T>>::set_priority())]
-		pub fn set_priority(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			rmrk_nft_id: RmrkNftId,
-			priorities: BoundedVec<RmrkResourceId, RmrkMaxPriorities>,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let sender = T::CrossAccountId::from_sub(sender);
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let nft_id = rmrk_nft_id.into();
-
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let budget = budget::Value::new(NESTING_BUDGET);
-
-			Self::ensure_nft_type(collection_id, nft_id, NftType::Regular)?;
-			Self::ensure_nft_owner(collection_id, nft_id, &sender, &budget)?;
-
-			<PalletNft<T>>::set_scoped_token_property(
-				collection_id,
-				nft_id,
-				RMRK_SCOPE,
-				Self::encode_rmrk_property(ResourcePriorities, &priorities.into_inner())?,
-			)?;
-
-			Self::deposit_event(Event::<T>::PrioritySet {
-				collection_id: rmrk_collection_id,
-				nft_id: rmrk_nft_id,
-			});
-
-			Ok(())
-		}
-
-		/// Create and set/propose a basic resource for an NFT.
-		///
-		/// A basic resource is the simplest, lacking a Base and anything that comes with it.
-		/// See RMRK docs for more information and examples.
-		///
-		/// # Permissions:
-		/// - Collection issuer - if not the token owner, adding the resource will warrant
-		/// the owner's [acceptance](Pallet::accept_resource).
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `nft_id`: ID of the NFT to assign a resource to.
-		/// - `resource`: Data of the resource to be created.
-		#[pallet::call_index(13)]
-		#[pallet::weight(<SelfWeightOf<T>>::add_basic_resource())]
-		pub fn add_basic_resource(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			resource: RmrkBasicResource,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let resource_id = Self::resource_add(
-				sender,
-				collection_id,
-				nft_id.into(),
-				RmrkResourceTypes::Basic(resource),
-			)?;
-
-			Self::deposit_event(Event::ResourceAdded {
-				nft_id,
-				resource_id,
-			});
-			Ok(())
-		}
-
-		/// Create and set/propose a composable resource for an NFT.
-		///
-		/// A composable resource links to a Base and has a subset of its Parts it is composed of.
-		/// See RMRK docs for more information and examples.
-		///
-		/// # Permissions:
-		/// - Collection issuer - if not the token owner, adding the resource will warrant
-		/// the owner's [acceptance](Pallet::accept_resource).
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `nft_id`: ID of the NFT to assign a resource to.
-		/// - `resource`: Data of the resource to be created.
-		#[pallet::call_index(14)]
-		#[pallet::weight(<SelfWeightOf<T>>::add_composable_resource())]
-		pub fn add_composable_resource(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			resource: RmrkComposableResource,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let base_id = resource.base;
-
-			let resource_id = Self::resource_add(
-				sender,
-				collection_id,
-				nft_id.into(),
-				RmrkResourceTypes::Composable(resource),
-			)?;
-
-			<PalletNft<T>>::try_mutate_token_aux_property(
-				collection_id,
-				nft_id.into(),
-				RMRK_SCOPE,
-				Self::get_scoped_property_key(AssociatedBases)?,
-				|value| -> DispatchResult {
-					let mut bases: BasesMap = match value {
-						Some(value) => Self::decode_property_value(value)?,
-						None => BasesMap::new(),
-					};
-
-					*bases.entry(base_id).or_insert(0) += 1;
-
-					*value = Some(Self::encode_property_value(&bases)?);
-					Ok(())
-				},
-			)?;
-
-			Self::deposit_event(Event::ResourceAdded {
-				nft_id,
-				resource_id,
-			});
-			Ok(())
-		}
-
-		/// Create and set/propose a slot resource for an NFT.
-		///
-		/// A slot resource links to a Base and a slot ID in it which it can fit into.
-		/// See RMRK docs for more information and examples.
-		///
-		/// # Permissions:
-		/// - Collection issuer - if not the token owner, adding the resource will warrant
-		/// the owner's [acceptance](Pallet::accept_resource).
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK collection ID of the NFT.
-		/// - `nft_id`: ID of the NFT to assign a resource to.
-		/// - `resource`: Data of the resource to be created.
-		#[pallet::call_index(15)]
-		#[pallet::weight(<SelfWeightOf<T>>::add_slot_resource())]
-		pub fn add_slot_resource(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			resource: RmrkSlotResource,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			let resource_id = Self::resource_add(
-				sender,
-				collection_id,
-				nft_id.into(),
-				RmrkResourceTypes::Slot(resource),
-			)?;
-
-			Self::deposit_event(Event::ResourceAdded {
-				nft_id,
-				resource_id,
-			});
-			Ok(())
-		}
-
-		/// Remove and erase a resource from an NFT.
-		///
-		/// If the sender does not own the NFT, then it will be pending confirmation,
-		/// and will have to be [accepted](Pallet::accept_resource_removal) by the token owner.
-		///
-		/// # Permissions
-		/// - Collection issuer
-		///
-		/// # Arguments
-		/// - `origin`: sender of the transaction
-		/// - `rmrk_collection_id`: RMRK ID of a collection to which the NFT making use of the resource belongs to.
-		/// - `nft_id`: ID of the NFT with a resource to be removed.
-		/// - `resource_id`: ID of the resource to be removed.
-		#[pallet::call_index(16)]
-		#[pallet::weight(<SelfWeightOf<T>>::remove_resource())]
-		pub fn remove_resource(
-			origin: OriginFor<T>,
-			rmrk_collection_id: RmrkCollectionId,
-			nft_id: RmrkNftId,
-			resource_id: RmrkResourceId,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin.clone())?;
-
-			let collection_id = Self::unique_collection_id(rmrk_collection_id)?;
-			let collection =
-				Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-			collection.check_is_external()?;
-
-			Self::resource_remove(sender, collection_id, nft_id.into(), resource_id)?;
-
-			Self::deposit_event(Event::ResourceRemoval {
-				nft_id,
-				resource_id,
-			});
-			Ok(())
-		}
-	}
-}
-
-impl<T: Config> Pallet<T> {
-	/// Transform one of possible RMRK keys into a byte key with a RMRK scope.
-	pub fn get_scoped_property_key(rmrk_key: RmrkProperty) -> Result<PropertyKey, DispatchError> {
-		let key = rmrk_key.to_key::<T>()?;
-
-		let scoped_key = RMRK_SCOPE
-			.apply(key)
-			.map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)?;
-
-		Ok(scoped_key)
-	}
-
-	/// Form a Unique property, transforming a RMRK key into bytes (without assigning the scope yet)
-	/// and encoding the value from an arbitrary type into bytes.
-	pub fn encode_rmrk_property<E: Encode>(
-		rmrk_key: RmrkProperty,
-		value: &E,
-	) -> Result<Property, DispatchError> {
-		let key = rmrk_key.to_key::<T>()?;
-
-		let value = Self::encode_property_value(value)?;
-
-		let property = Property { key, value };
-
-		Ok(property)
-	}
-
-	/// Encode property value from an arbitrary type into bytes for storage.
-	pub fn encode_property_value<E: Encode, S: Get<u32>>(
-		value: &E,
-	) -> Result<BoundedBytes<S>, DispatchError> {
-		let value = value
-			.encode()
-			.try_into()
-			.map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong)?;
-
-		Ok(value)
-	}
-
-	/// Decode property value from bytes into an arbitrary type.
-	pub fn decode_property_value<D: Decode, S: Get<u32>>(
-		vec: &BoundedBytes<S>,
-	) -> Result<D, DispatchError> {
-		vec.decode()
-			.map_err(|_| <Error<T>>::UnableToDecodeRmrkData.into())
-	}
-
-	/// Change the limit of a property value byte vector.
-	pub fn rebind<L, S>(vec: &BoundedVec<u8, L>) -> Result<BoundedVec<u8, S>, DispatchError>
-	where
-		BoundedVec<u8, S>: TryFrom<Vec<u8>>,
-	{
-		vec.rebind()
-			.map_err(|_| <Error<T>>::RmrkPropertyValueIsTooLong.into())
-	}
-
-	/// Initialize a new NFT collection with certain RMRK-scoped properties.
-	///
-	/// See [`init_collection`](pallet_nonfungible::pallet::Pallet::init_collection) for more details.
-	fn init_collection(
-		sender: T::CrossAccountId,
-		data: CreateCollectionData<T::AccountId>,
-		properties: impl Iterator<Item = Property>,
-	) -> Result<CollectionId, DispatchError> {
-		let collection_id = <PalletNft<T>>::init_collection(
-			sender.clone(),
-			sender,
-			data,
-			up_data_structs::CollectionFlags {
-				external: true,
-				..Default::default()
-			},
-		);
-
-		if let Err(DispatchError::Arithmetic(_)) = &collection_id {
-			return Err(<Error<T>>::NoAvailableCollectionId.into());
-		}
-
-		<PalletCommon<T>>::set_scoped_collection_properties(
-			collection_id?,
-			RMRK_SCOPE,
-			properties,
-		)?;
-
-		collection_id
-	}
-
-	/// Mint a new NFT with certain RMRK-scoped properties. Sender must be the collection owner.
-	///
-	/// See [`create_item`](pallet_nonfungible::pallet::Pallet::create_item) for more details.
-	pub fn create_nft(
-		sender: &T::CrossAccountId,
-		owner: &T::CrossAccountId,
-		collection: &NonfungibleHandle<T>,
-		properties: impl Iterator<Item = Property>,
-	) -> Result<TokenId, DispatchError> {
-		let data = CreateNftExData {
-			properties: BoundedVec::default(),
-			owner: owner.clone(),
-		};
-
-		let budget = budget::Value::new(NESTING_BUDGET);
-
-		<PalletNft<T>>::create_item(collection, sender, data, &budget)?;
-
-		let nft_id = <PalletNft<T>>::current_token_id(collection.id);
-
-		<PalletNft<T>>::set_scoped_token_properties(collection.id, nft_id, RMRK_SCOPE, properties)?;
-
-		Ok(nft_id)
-	}
-
-	/// Burn an NFT, along with its nested children, limited by `max_burns`. The sender must be the token owner.
-	///
-	/// See [`burn_recursively`](pallet_nonfungible::pallet::Pallet::burn_recursively) for more details.
-	fn destroy_nft(
-		sender: T::CrossAccountId,
-		collection_id: CollectionId,
-		token_id: TokenId,
-		max_burns: u32,
-		error_if_not_owned: Error<T>,
-	) -> DispatchResultWithPostInfo {
-		let collection =
-			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-
-		let token_data =
-			<TokenData<T>>::get((collection_id, token_id)).ok_or(<Error<T>>::NoAvailableNftId)?;
-
-		let from = token_data.owner;
-
-		let owner_check_budget = budget::Value::new(NESTING_BUDGET);
-
-		ensure!(
-			<PalletStructure<T>>::check_indirectly_owned(
-				sender.clone(),
-				collection_id,
-				token_id,
-				None,
-				&owner_check_budget
-			)?,
-			error_if_not_owned,
-		);
-
-		let burns_budget = budget::Value::new(max_burns);
-		let breadth_budget = budget::Value::new(max_burns);
-
-		<PalletNft<T>>::burn_recursively(
-			&collection,
-			&from,
-			token_id,
-			&burns_budget,
-			&breadth_budget,
-		)
-	}
-
-	/// Add a sent token pending acceptance to the target owning token as a property.
-	fn insert_pending_child(
-		target: (CollectionId, TokenId),
-		child: (RmrkCollectionId, RmrkNftId),
-	) -> DispatchResult {
-		Self::mutate_pending_children(target, |pending_children| {
-			pending_children.insert(child);
-		})
-	}
-
-	/// Remove a sent token pending acceptance from the target token's properties.
-	fn remove_pending_child(
-		target: (CollectionId, TokenId),
-		child: (RmrkCollectionId, RmrkNftId),
-	) -> DispatchResult {
-		Self::mutate_pending_children(target, |pending_children| {
-			pending_children.remove(&child);
-		})
-	}
-
-	/// Apply a mutation to the property of a token containing sent tokens
-	/// that are currently pending acceptance.
-	fn mutate_pending_children(
-		(target_collection_id, target_nft_id): (CollectionId, TokenId),
-		f: impl FnOnce(&mut PendingChildrenSet),
-	) -> DispatchResult {
-		<PalletNft<T>>::try_mutate_token_aux_property(
-			target_collection_id,
-			target_nft_id,
-			RMRK_SCOPE,
-			Self::get_scoped_property_key(PendingChildren)?,
-			|pending_children| -> DispatchResult {
-				let mut map = match pending_children {
-					Some(map) => Self::decode_property_value(map)?,
-					None => PendingChildrenSet::new(),
-				};
-
-				f(&mut map);
-
-				*pending_children = Some(Self::encode_property_value(&map)?);
-
-				Ok(())
-			},
-		)
-	}
-
-	/// Get an iterator from a token's property containing tokens sent to it
-	/// that are currently pending acceptance.
-	fn iterate_pending_children(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-	) -> Result<impl Iterator<Item = PendingChild>, DispatchError> {
-		let property = <PalletNft<T>>::token_aux_property((
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			Self::get_scoped_property_key(PendingChildren)?,
-		));
-
-		let pending_children = match property {
-			Some(map) => Self::decode_property_value(&map)?,
-			None => PendingChildrenSet::new(),
-		};
-
-		Ok(pending_children.into_iter())
-	}
-
-	/// Get incremented resource ID from within an NFT's properties and store the new latest ID.
-	/// Thus, the returned resource ID should be used.
-	///
-	/// Resource IDs are unique only across an NFT.
-	fn acquire_next_resource_id(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-	) -> Result<RmrkResourceId, DispatchError> {
-		let resource_id: RmrkResourceId =
-			Self::get_nft_property_decoded(collection_id, nft_id, NextResourceId)?;
-
-		let next_id = resource_id
-			.checked_add(1)
-			.ok_or(<Error<T>>::NoAvailableResourceId)?;
-
-		<PalletNft<T>>::set_scoped_token_property(
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			Self::encode_rmrk_property(NextResourceId, &next_id)?,
-		)?;
-
-		Ok(resource_id)
-	}
-
-	/// Create and add a resource for a regular NFT, mark it as pending if the sender
-	/// is not the token owner. The sender must be the collection owner.
-	fn resource_add(
-		sender: T::AccountId,
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		resource: RmrkResourceTypes,
-	) -> Result<RmrkResourceId, DispatchError> {
-		let collection =
-			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-		ensure!(collection.owner == sender, Error::<T>::NoPermission);
-
-		let sender = T::CrossAccountId::from_sub(sender);
-		let budget = budget::Value::new(NESTING_BUDGET);
-
-		let nft_owner = <PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)
-			.map_err(Self::map_unique_err_to_proxy)?
-			.ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
-
-		let pending = sender != nft_owner;
-
-		let id = Self::acquire_next_resource_id(collection_id, nft_id)?;
-
-		let resource_info = RmrkResourceInfo {
-			id,
-			resource,
-			pending,
-			pending_removal: false,
-		};
-
-		<PalletNft<T>>::try_mutate_token_aux_property(
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			Self::get_scoped_property_key(ResourceId(id))?,
-			|value| -> DispatchResult {
-				*value = Some(Self::encode_property_value(&resource_info)?);
-
-				Ok(())
-			},
-		)?;
-
-		Ok(id)
-	}
-
-	/// Designate a resource for erasure from an NFT, and remove it if the sender is the token owner.
-	/// The sender must be the collection owner.
-	fn resource_remove(
-		sender: T::AccountId,
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		resource_id: RmrkResourceId,
-	) -> DispatchResult {
-		let collection =
-			Self::get_typed_nft_collection(collection_id, misc::CollectionType::Regular)?;
-		ensure!(collection.owner == sender, Error::<T>::NoPermission);
-
-		let resource_id_key = Self::get_scoped_property_key(ResourceId(resource_id))?;
-
-		let resource = <PalletNft<T>>::token_aux_property((
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			resource_id_key.clone(),
-		))
-		.ok_or(<Error<T>>::ResourceDoesntExist)?;
-
-		let resource_info: RmrkResourceInfo = Self::decode_property_value(&resource)?;
-
-		let budget = up_data_structs::budget::Value::new(NESTING_BUDGET);
-		let topmost_owner =
-			<PalletStructure<T>>::find_topmost_owner(collection_id, nft_id, &budget)?
-				.ok_or::<DispatchError>(<Error<T>>::NoPermission.into())?;
-
-		let sender = T::CrossAccountId::from_sub(sender);
-		if topmost_owner == sender {
-			<PalletNft<T>>::remove_token_aux_property(
-				collection_id,
-				nft_id,
-				RMRK_SCOPE,
-				Self::get_scoped_property_key(ResourceId(resource_id))?,
-			);
-
-			if let RmrkResourceTypes::Composable(resource) = resource_info.resource {
-				let base_id = resource.base;
-
-				Self::remove_associated_base_id(collection_id, nft_id, base_id)?;
-			}
-		} else {
-			Self::try_mutate_resource_info(collection_id, nft_id, resource_id, |res| {
-				res.pending_removal = true;
-
-				Ok(())
-			})?;
-		}
-
-		Ok(())
-	}
-
-	/// Remove a Base ID from an NFT if they are associated.
-	/// The Base itself is deleted if the number of associated NFTs reaches 0.
-	fn remove_associated_base_id(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		base_id: RmrkBaseId,
-	) -> DispatchResult {
-		<PalletNft<T>>::try_mutate_token_aux_property(
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			Self::get_scoped_property_key(AssociatedBases)?,
-			|value| -> DispatchResult {
-				let mut bases: BasesMap = match value {
-					Some(value) => Self::decode_property_value(value)?,
-					None => BasesMap::new(),
-				};
-
-				let remaining = bases.get(&base_id);
-
-				if let Some(remaining) = remaining {
-					if let Some(0) | None = remaining.checked_sub(1) {
-						bases.remove(&base_id);
-					}
-				}
-
-				*value = Some(Self::encode_property_value(&bases)?);
-				Ok(())
-			},
-		)
-	}
-
-	/// Apply a mutation to a resource stored in the token properties of an NFT.
-	fn try_mutate_resource_info(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		resource_id: RmrkResourceId,
-		f: impl FnOnce(&mut RmrkResourceInfo) -> DispatchResult,
-	) -> DispatchResult {
-		<PalletNft<T>>::try_mutate_token_aux_property(
-			collection_id,
-			nft_id,
-			RMRK_SCOPE,
-			Self::get_scoped_property_key(ResourceId(resource_id))?,
-			|value| match value {
-				Some(value) => {
-					let mut resource_info: RmrkResourceInfo = Self::decode_property_value(value)?;
-
-					f(&mut resource_info)?;
-
-					*value = Self::encode_property_value(&resource_info)?;
-
-					Ok(())
-				}
-				None => Err(<Error<T>>::ResourceDoesntExist.into()),
-			},
-		)
-	}
-
-	/// Change the owner of an NFT collection, ensuring that the sender is the current owner.
-	fn change_collection_owner(
-		collection_id: CollectionId,
-		collection_type: misc::CollectionType,
-		sender: T::AccountId,
-		new_owner: T::AccountId,
-	) -> DispatchResult {
-		let collection = Self::get_typed_nft_collection(collection_id, collection_type)?;
-		Self::check_collection_owner(&collection, &T::CrossAccountId::from_sub(sender))?;
-
-		let mut collection = collection.into_inner();
-
-		collection.owner = new_owner;
-		collection.save()
-	}
-
-	/// Ensure that an account is the collection owner/issuer, return an error if not.
-	pub fn check_collection_owner(
-		collection: &NonfungibleHandle<T>,
-		account: &T::CrossAccountId,
-	) -> DispatchResult {
-		collection
-			.check_is_owner(account)
-			.map_err(Self::map_unique_err_to_proxy)
-	}
-
-	/// Get the latest yet-unused RMRK collection index from the storage.
-	pub fn last_collection_idx() -> RmrkCollectionId {
-		<CollectionIndex<T>>::get()
-	}
-
-	/// Get a mapping from a RMRK collection ID to its corresponding Unique collection ID.
-	pub fn unique_collection_id(
-		rmrk_collection_id: RmrkCollectionId,
-	) -> Result<CollectionId, DispatchError> {
-		<UniqueCollectionId<T>>::try_get(rmrk_collection_id)
-			.map_err(|_| <Error<T>>::CollectionUnknown.into())
-	}
-
-	/// Get a mapping from a Unique collection ID to its RMRK collection ID counterpart, if it exists.
-	pub fn rmrk_collection_id(
-		unique_collection_id: CollectionId,
-	) -> Result<RmrkCollectionId, DispatchError> {
-		Self::get_collection_property_decoded(unique_collection_id, RmrkInternalCollectionId)
-	}
-
-	/// Fetch a Unique NFT collection.
-	pub fn get_nft_collection(
-		collection_id: CollectionId,
-	) -> Result<NonfungibleHandle<T>, DispatchError> {
-		let collection = <CollectionHandle<T>>::try_get(collection_id)
-			.map_err(|_| <Error<T>>::CollectionUnknown)?;
-
-		match collection.mode {
-			CollectionMode::NFT => Ok(NonfungibleHandle::cast(collection)),
-			_ => Err(<Error<T>>::CollectionUnknown.into()),
-		}
-	}
-
-	/// Check if an NFT collection with such an ID exists.
-	pub fn collection_exists(collection_id: CollectionId) -> bool {
-		<CollectionHandle<T>>::try_get(collection_id).is_ok()
-	}
-
-	/// Fetch and decode a RMRK-scoped collection property value in bytes.
-	pub fn get_collection_property(
-		collection_id: CollectionId,
-		key: RmrkProperty,
-	) -> Result<PropertyValue, DispatchError> {
-		let collection_property = <PalletCommon<T>>::collection_properties(collection_id)
-			.get(&Self::get_scoped_property_key(key)?)
-			.ok_or(<Error<T>>::CollectionUnknown)?
-			.clone();
-
-		Ok(collection_property)
-	}
-
-	/// Fetch a RMRK-scoped collection property and decode it from bytes into an appropriate type.
-	pub fn get_collection_property_decoded<V: Decode>(
-		collection_id: CollectionId,
-		key: RmrkProperty,
-	) -> Result<V, DispatchError> {
-		Self::decode_property_value(&Self::get_collection_property(collection_id, key)?)
-	}
-
-	/// Get the type of a collection stored as a scoped property.
-	///
-	/// RMRK Core proxy differentiates between regular collections as well as RMRK Bases as collections.
-	pub fn get_collection_type(
-		collection_id: CollectionId,
-	) -> Result<misc::CollectionType, DispatchError> {
-		Self::get_collection_property_decoded(collection_id, CollectionType).map_err(|err| {
-			if err != <Error<T>>::CollectionUnknown.into() {
-				<Error<T>>::CorruptedCollectionType.into()
-			} else {
-				err
-			}
-		})
-	}
-
-	/// Ensure that the type of the collection equals the provided type,
-	/// otherwise return an error.
-	pub fn ensure_collection_type(
-		collection_id: CollectionId,
-		collection_type: misc::CollectionType,
-	) -> DispatchResult {
-		let actual_type = Self::get_collection_type(collection_id)?;
-		ensure!(
-			actual_type == collection_type,
-			<CommonError<T>>::NoPermission
-		);
-
-		Ok(())
-	}
-
-	/// Fetch an NFT collection, but make sure it has the appropriate type.
-	pub fn get_typed_nft_collection(
-		collection_id: CollectionId,
-		collection_type: misc::CollectionType,
-	) -> Result<NonfungibleHandle<T>, DispatchError> {
-		Self::ensure_collection_type(collection_id, collection_type)?;
-
-		Self::get_nft_collection(collection_id)
-	}
-
-	/// Same as [`get_typed_nft_collection`](crate::pallet::Pallet::get_typed_nft_collection),
-	/// but also return the Unique collection ID.
-	pub fn get_typed_nft_collection_mapped(
-		rmrk_collection_id: RmrkCollectionId,
-		collection_type: misc::CollectionType,
-	) -> Result<(NonfungibleHandle<T>, CollectionId), DispatchError> {
-		let unique_collection_id = match collection_type {
-			misc::CollectionType::Regular => Self::unique_collection_id(rmrk_collection_id)?,
-			_ => rmrk_collection_id.into(),
-		};
-
-		let collection = Self::get_typed_nft_collection(unique_collection_id, collection_type)?;
-
-		Ok((collection, unique_collection_id))
-	}
-
-	/// Fetch and decode a RMRK-scoped NFT property value in bytes.
-	pub fn get_nft_property(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		key: RmrkProperty,
-	) -> Result<PropertyValue, DispatchError> {
-		let nft_property = <PalletNft<T>>::token_properties((collection_id, nft_id))
-			.get(&Self::get_scoped_property_key(key)?)
-			.ok_or(<Error<T>>::RmrkPropertyIsNotFound)?
-			.clone();
-
-		Ok(nft_property)
-	}
-
-	/// Fetch a RMRK-scoped NFT property and decode it from bytes into an appropriate type.
-	pub fn get_nft_property_decoded<V: Decode>(
-		collection_id: CollectionId,
-		nft_id: TokenId,
-		key: RmrkProperty,
-	) -> Result<V, DispatchError> {
-		Self::decode_property_value(&Self::get_nft_property(collection_id, nft_id, key)?)
-	}
-
-	/// Check that an NFT exists.
-	pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
-		<TokenData<T>>::contains_key((collection_id, nft_id))
-	}
-
-	/// Get the type of an NFT stored as a scoped property.
-	///
-	/// RMRK Core proxy differentiates between regular NFTs, and RMRK Parts and Themes.
-	pub fn get_nft_type(
-		collection_id: CollectionId,
-		token_id: TokenId,
-	) -> Result<NftType, DispatchError> {
-		Self::get_nft_property_decoded(collection_id, token_id, TokenType)
-			.map_err(|_| <Error<T>>::NoAvailableNftId.into())
-	}
-
-	/// Ensure that the type of the NFT equals the provided type, otherwise return an error.
-	pub fn ensure_nft_type(
-		collection_id: CollectionId,
-		token_id: TokenId,
-		nft_type: NftType,
-	) -> DispatchResult {
-		let actual_type = Self::get_nft_type(collection_id, token_id)?;
-		ensure!(actual_type == nft_type, <Error<T>>::NoPermission);
-
-		Ok(())
-	}
-
-	/// Ensure that an account is the owner of the token, either directly
-	/// or at the top of the nesting hierarchy; return an error if it is not.
-	pub fn ensure_nft_owner(
-		collection_id: CollectionId,
-		token_id: TokenId,
-		possible_owner: &T::CrossAccountId,
-		nesting_budget: &dyn budget::Budget,
-	) -> DispatchResult {
-		let is_owned = <PalletStructure<T>>::check_indirectly_owned(
-			possible_owner.clone(),
-			collection_id,
-			token_id,
-			None,
-			nesting_budget,
-		)
-		.map_err(Self::map_unique_err_to_proxy)?;
-
-		ensure!(is_owned, <Error<T>>::NoPermission);
-
-		Ok(())
-	}
-
-	/// Fetch non-scoped properties of a collection or a token that match the filter keys supplied,
-	/// or, if None are provided, return all non-scoped properties.
-	pub fn filter_user_properties<Key, Value, R, Mapper>(
-		collection_id: CollectionId,
-		token_id: Option<TokenId>,
-		filter_keys: Option<Vec<RmrkPropertyKey>>,
-		mapper: Mapper,
-	) -> Result<Vec<R>, DispatchError>
-	where
-		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
-		Value: Decode + Default,
-		Mapper: Fn(Key, Value) -> R,
-	{
-		filter_keys
-			.map(|keys| {
-				let properties = keys
-					.into_iter()
-					.filter_map(|key| {
-						let key: Key = key.try_into().ok()?;
-
-						let value = match token_id {
-							Some(token_id) => Self::get_nft_property_decoded(
-								collection_id,
-								token_id,
-								UserProperty(key.as_ref()),
-							),
-							None => Self::get_collection_property_decoded(
-								collection_id,
-								UserProperty(key.as_ref()),
-							),
-						}
-						.ok()?;
-
-						Some(mapper(key, value))
-					})
-					.collect();
-
-				Ok(properties)
-			})
-			.unwrap_or_else(|| {
-				let properties =
-					Self::iterate_user_properties(collection_id, token_id, mapper)?.collect();
-
-				Ok(properties)
-			})
-	}
-
-	/// Get all non-scoped properties from a collection or a token, and apply some transformation,
-	/// supplied by `mapper`, to each key-value pair.
-	pub fn iterate_user_properties<Key, Value, R, Mapper>(
-		collection_id: CollectionId,
-		token_id: Option<TokenId>,
-		mapper: Mapper,
-	) -> Result<impl Iterator<Item = R>, DispatchError>
-	where
-		Key: TryFrom<RmrkPropertyKey> + AsRef<[u8]>,
-		Value: Decode + Default,
-		Mapper: Fn(Key, Value) -> R,
-	{
-		let properties = match token_id {
-			Some(token_id) => <PalletNft<T>>::token_properties((collection_id, token_id)),
-			None => <PalletCommon<T>>::collection_properties(collection_id),
-		};
-
-		let properties = properties.into_iter().filter_map(move |(key, value)| {
-			let key = strip_key_prefix(&key, USER_PROPERTY_PREFIX)?;
-
-			let key: Key = key.to_vec().try_into().ok()?;
-			let value: Value = value.decode().ok()?;
-
-			Some(mapper(key, value))
-		});
-
-		Ok(properties)
-	}
-
-	/// Match Unique errors to RMRK's own and return the RMRK error if a match is successful.
-	fn map_unique_err_to_proxy(err: DispatchError) -> DispatchError {
-		map_unique_err_to_proxy! {
-			match err {
-				CommonError::NoPermission => NoPermission,
-				CommonError::CollectionTokenLimitExceeded => CollectionFullOrLocked,
-				CommonError::PublicMintingNotAllowed => NoPermission,
-				CommonError::TokenNotFound => NoAvailableNftId,
-				CommonError::ApprovedValueTooLow => NoPermission,
-				CommonError::CantDestroyNotEmptyCollection => CollectionNotEmpty,
-				StructureError::TokenNotFound => NoAvailableNftId,
-				StructureError::OuroborosDetected => CannotSendToDescendentOrSelf,
-			}
-		}
-	}
-}
deletedpallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/misc.rs
+++ /dev/null
@@ -1,84 +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/>.
-
-//! Miscellaneous helpers and utilities used by the proxy pallet.
-
-use super::*;
-use codec::{Encode, Decode, Error};
-
-/// Match an error to a provided pattern matcher and get
-/// the corresponding error of another type if a match is successful.
-#[macro_export]
-macro_rules! map_unique_err_to_proxy {
-    (match $err:ident { $($unique_err_ty:ident :: $unique_err:ident => $proxy_err:ident),+ $(,)? }) => {
-        $(
-            if $err == <$unique_err_ty<T>>::$unique_err.into() {
-                return <Error<T>>::$proxy_err.into()
-            } else
-        )+ {
-            $err
-        }
-    };
-}
-
-/// Interface to decode some serialized bytes into an arbitrary type `T`,
-/// preferably if these bytes were originally encoded from `T`.
-pub trait RmrkDecode<T: Decode, S> {
-	/// Try to decode self into an arbitrary type `T`.
-	fn decode(&self) -> Result<T, Error>;
-}
-
-impl<T: Decode, S> RmrkDecode<T, S> for BoundedVec<u8, S> {
-	fn decode(&self) -> Result<T, Error> {
-		let mut value = self.as_slice();
-
-		T::decode(&mut value)
-	}
-}
-
-/// Interface to "rebind" - change the limit of a bounded byte vector.
-pub trait RmrkRebind<T, S> {
-	/// Try to change the limit of a bounded byte vector.
-	fn rebind(&self) -> Result<BoundedVec<u8, S>, Error>;
-}
-
-impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T>
-where
-	BoundedVec<u8, S>: TryFrom<Vec<u8>>,
-{
-	fn rebind(&self) -> Result<BoundedVec<u8, S>, Error> {
-		BoundedVec::<u8, S>::try_from(self.clone().into_inner())
-			.map_err(|_| "BoundedVec exceeds its limit".into())
-	}
-}
-
-/// RMRK Base shares functionality with a regular collection, and is thus
-/// stored as one, but they are used for different purposes and need to be differentiated.
-#[derive(Encode, Decode, PartialEq, Eq)]
-pub enum CollectionType {
-	Regular,
-	Base,
-}
-
-/// RMRK Base, being stored as a collection, can have different kinds of tokens,
-/// all except the `Regular` type, which is attributed to `Regular` collection.
-#[derive(Encode, Decode, PartialEq, Eq)]
-pub enum NftType {
-	Regular,
-	FixedPart,
-	SlotPart,
-	Theme,
-}
deletedpallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/property.rs
+++ /dev/null
@@ -1,121 +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/>.
-
-//! Details of storing and handling RMRK properties.
-
-use super::*;
-use up_data_structs::PropertyScope;
-use core::convert::AsRef;
-
-/// Property prefix for storing resources.
-pub const RESOURCE_ID_PREFIX: &str = "rsid-";
-/// Property prefix for storing custom user-defined properties.
-pub const USER_PROPERTY_PREFIX: &str = "userprop-";
-/// Property scope for RMRK, used to signify that this property
-/// was created and is used by RMRK.
-pub const RMRK_SCOPE: PropertyScope = PropertyScope::Rmrk;
-
-/// Predefined RMRK property keys for storage of RMRK data format on the Unique chain.
-pub enum RmrkProperty<'r> {
-	Metadata,
-	CollectionType,
-	RmrkInternalCollectionId,
-	TokenType,
-	Transferable,
-	RoyaltyInfo,
-	Equipped,
-	ResourcePriorities,
-	NextResourceId,
-	ResourceId(RmrkResourceId),
-	PendingNftAccept,
-	PendingChildren,
-	AssociatedBases,
-	Parts,
-	Base,
-	Src,
-	EquippedNft,
-	BaseType,
-	ExternalPartId,
-	EquippableList,
-	ZIndex,
-	ThemeName,
-	ThemeInherit,
-	UserProperty(&'r [u8]),
-}
-
-impl<'r> RmrkProperty<'r> {
-	/// Convert a predefined RMRK property key enum into string bytes.
-	pub fn to_key<T: Config>(self) -> Result<PropertyKey, Error<T>> {
-		fn get_bytes<T: AsRef<[u8]>>(container: &T) -> &[u8] {
-			container.as_ref()
-		}
-
-		macro_rules! key {
-            ($($component:expr),+) => {
-                PropertyKey::try_from([$(key!(@ &$component)),+].concat())
-                    .map_err(|_| <Error<T>>::RmrkPropertyKeyIsTooLong)
-            };
-
-            (@ $key:expr) => {
-                get_bytes($key)
-            };
-        }
-
-		match self {
-			Self::Metadata => key!("metadata"),
-			Self::CollectionType => key!("collection-type"),
-			Self::RmrkInternalCollectionId => key!("internal-id"),
-			Self::TokenType => key!("token-type"),
-			Self::Transferable => key!("transferable"),
-			Self::RoyaltyInfo => key!("royalty-info"),
-			Self::Equipped => key!("equipped"),
-			Self::ResourcePriorities => key!("resource-priorities"),
-			Self::NextResourceId => key!("next-resource-id"),
-			Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()),
-			Self::PendingNftAccept => key!("pending-nft-accept"),
-			Self::PendingChildren => key!("pending-children"),
-			Self::AssociatedBases => key!("assoc-bases"),
-			Self::Parts => key!("parts"),
-			Self::Base => key!("base"),
-			Self::Src => key!("src"),
-			Self::EquippedNft => key!("equipped-nft"),
-			Self::BaseType => key!("base-type"),
-			Self::ExternalPartId => key!("ext-part-id"),
-			Self::EquippableList => key!("equippable-list"),
-			Self::ZIndex => key!("z-index"),
-			Self::ThemeName => key!("theme-name"),
-			Self::ThemeInherit => key!("theme-inherit"),
-			Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name),
-		}
-	}
-}
-
-/// Strip a property key of its prefix and RMRK scope.
-pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option<PropertyKey> {
-	let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?;
-	let key_prefix = RMRK_SCOPE.apply(key_prefix).ok()?;
-
-	key.as_slice()
-		.strip_prefix(key_prefix.as_slice())?
-		.to_vec()
-		.try_into()
-		.ok()
-}
-
-/// Check that the key has the prefix.
-pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool {
-	strip_key_prefix(key, prefix).is_some()
-}
deletedpallets/proxy-rmrk-core/src/rpc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/rpc.rs
+++ /dev/null
@@ -1,293 +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/>.
-
-//! Realizations of RMRK RPCs (remote procedure calls) related to the Core pallet.
-
-use super::*;
-
-/// Get the latest created collection ID.
-pub fn last_collection_idx<T: Config>() -> Result<RmrkCollectionId, DispatchError> {
-	Ok(<Pallet<T>>::last_collection_idx())
-}
-
-/// Get collection info by ID.
-pub fn collection_by_id<T: Config>(
-	collection_id: RmrkCollectionId,
-) -> Result<Option<RmrkCollectionInfo<T::AccountId>>, DispatchError> {
-	let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(
-		collection_id,
-		misc::CollectionType::Regular,
-	) {
-		Ok(c) => c,
-		Err(_) => return Ok(None),
-	};
-
-	let nfts_count = collection.total_supply();
-
-	Ok(Some(RmrkCollectionInfo {
-		issuer: collection.owner.clone(),
-		metadata: <Pallet<T>>::get_collection_property_decoded(
-			collection_id,
-			RmrkProperty::Metadata,
-		)?,
-		max: collection.limits.token_limit,
-		symbol: <Pallet<T>>::rebind(&collection.token_prefix)?,
-		nfts_count,
-	}))
-}
-
-/// Get NFT info by collection and NFT IDs.
-pub fn nft_by_id<T: Config>(
-	collection_id: RmrkCollectionId,
-	nft_by_id: RmrkNftId,
-) -> Result<Option<RmrkInstanceInfo<T::AccountId>>, DispatchError> {
-	let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(
-		collection_id,
-		misc::CollectionType::Regular,
-	) {
-		Ok(c) => c,
-		Err(_) => return Ok(None),
-	};
-
-	let nft_id = TokenId(nft_by_id);
-	if !<Pallet<T>>::nft_exists(collection_id, nft_id) {
-		return Ok(None);
-	}
-
-	let owner = match collection.token_owner(nft_id) {
-		Ok(owner) => match T::CrossTokenAddressMapping::address_to_token(&owner) {
-			Some((col, tok)) => {
-				let rmrk_collection = <Pallet<T>>::rmrk_collection_id(col)?;
-
-				RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0)
-			}
-			None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()),
-		},
-		_ => return Ok(None),
-	};
-
-	Ok(Some(RmrkInstanceInfo {
-		owner: owner,
-		royalty: <Pallet<T>>::get_nft_property_decoded(
-			collection_id,
-			nft_id,
-			RmrkProperty::RoyaltyInfo,
-		)?,
-		metadata: <Pallet<T>>::get_nft_property_decoded(
-			collection_id,
-			nft_id,
-			RmrkProperty::Metadata,
-		)?,
-		equipped: <Pallet<T>>::get_nft_property_decoded(
-			collection_id,
-			nft_id,
-			RmrkProperty::Equipped,
-		)?,
-		pending: <Pallet<T>>::get_nft_property_decoded(
-			collection_id,
-			nft_id,
-			RmrkProperty::PendingNftAccept,
-		)?,
-	}))
-}
-
-/// Get tokens owned by an account in a collection.
-pub fn account_tokens<T: Config>(
-	account_id: T::AccountId,
-	collection_id: RmrkCollectionId,
-) -> Result<Vec<RmrkNftId>, DispatchError> {
-	let cross_account_id = CrossAccountId::from_sub(account_id);
-
-	let (collection, collection_id) = match <Pallet<T>>::get_typed_nft_collection_mapped(
-		collection_id,
-		misc::CollectionType::Regular,
-	) {
-		Ok(c) => c,
-		Err(_) => return Ok(Vec::new()),
-	};
-
-	let tokens = collection
-		.account_tokens(cross_account_id)
-		.into_iter()
-		.filter(|token| {
-			let is_pending = <Pallet<T>>::get_nft_property_decoded(
-				collection_id,
-				*token,
-				RmrkProperty::PendingNftAccept,
-			)
-			.unwrap_or(true);
-
-			!is_pending
-		})
-		.map(|token| token.0)
-		.collect();
-
-	Ok(tokens)
-}
-
-/// Get tokens nested in an NFT - its direct children (not the children's children).
-pub fn nft_children<T: Config>(
-	collection_id: RmrkCollectionId,
-	nft_id: RmrkNftId,
-) -> Result<Vec<RmrkNftChild>, DispatchError> {
-	let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {
-		Ok(id) => id,
-		Err(_) => return Ok(Vec::new()),
-	};
-	let nft_id = TokenId(nft_id);
-	if !<Pallet<T>>::nft_exists(collection_id, nft_id) {
-		return Ok(Vec::new());
-	}
-
-	Ok(
-		pallet_nonfungible::TokenChildren::<T>::iter_prefix((collection_id, nft_id))
-			.filter_map(|((child_collection, child_token), _)| {
-				let rmrk_child_collection =
-					<Pallet<T>>::rmrk_collection_id(child_collection).ok()?;
-
-				Some(RmrkNftChild {
-					collection_id: rmrk_child_collection,
-					nft_id: child_token.0,
-				})
-			})
-			.chain(
-				<Pallet<T>>::iterate_pending_children(collection_id, nft_id)?.map(
-					|(child_collection, child_nft_id)| RmrkNftChild {
-						collection_id: child_collection,
-						nft_id: child_nft_id,
-					},
-				),
-			)
-			.collect(),
-	)
-}
-
-/// Get collection properties, created by the user - not the proxy-specific properties.
-pub fn collection_properties<T: Config>(
-	collection_id: RmrkCollectionId,
-	filter_keys: Option<Vec<RmrkPropertyKey>>,
-) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-	let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {
-		Ok(id) => id,
-		Err(_) => return Ok(Vec::new()),
-	};
-	if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {
-		return Ok(Vec::new());
-	}
-
-	let properties = <Pallet<T>>::filter_user_properties(
-		collection_id,
-		/* token_id = */ None,
-		filter_keys,
-		|key, value| RmrkPropertyInfo { key, value },
-	)?;
-
-	Ok(properties)
-}
-
-/// Get NFT properties, created by the user - not the proxy-specific properties.
-pub fn nft_properties<T: Config>(
-	collection_id: RmrkCollectionId,
-	nft_id: RmrkNftId,
-	filter_keys: Option<Vec<RmrkPropertyKey>>,
-) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-	let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {
-		Ok(id) => id,
-		Err(_) => return Ok(Vec::new()),
-	};
-	let token_id = TokenId(nft_id);
-
-	if <Pallet<T>>::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() {
-		return Ok(Vec::new());
-	}
-
-	let properties = <Pallet<T>>::filter_user_properties(
-		collection_id,
-		Some(token_id),
-		filter_keys,
-		|key, value| RmrkPropertyInfo { key, value },
-	)?;
-
-	Ok(properties)
-}
-
-/// Get full information on each resource of an NFT, including pending.
-pub fn nft_resources<T: Config>(
-	collection_id: RmrkCollectionId,
-	nft_id: RmrkNftId,
-) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-	let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {
-		Ok(id) => id,
-		Err(_) => return Ok(Vec::new()),
-	};
-	if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {
-		return Ok(Vec::new());
-	}
-
-	let nft_id = TokenId(nft_id);
-	if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {
-		return Ok(Vec::new());
-	}
-
-	let resources = <pallet_nonfungible::Pallet<T>>::iterate_token_aux_properties(
-		collection_id,
-		nft_id,
-		PropertyScope::Rmrk,
-	)
-	.filter_map(|(key, value)| {
-		if !is_valid_key_prefix(&key, RESOURCE_ID_PREFIX) {
-			return None;
-		}
-
-		let resource_info: RmrkResourceInfo = <Pallet<T>>::decode_property_value(&value).ok()?;
-
-		Some(resource_info)
-	})
-	.collect();
-
-	Ok(resources)
-}
-
-/// Get the priority of a resource in an NFT.
-pub fn nft_resource_priority<T: Config>(
-	collection_id: RmrkCollectionId,
-	nft_id: RmrkNftId,
-	resource_id: RmrkResourceId,
-) -> Result<Option<u32>, DispatchError> {
-	let collection_id = match <Pallet<T>>::unique_collection_id(collection_id) {
-		Ok(id) => id,
-		Err(_) => return Ok(None),
-	};
-	if <Pallet<T>>::ensure_collection_type(collection_id, misc::CollectionType::Regular).is_err() {
-		return Ok(None);
-	}
-
-	let nft_id = TokenId(nft_id);
-	if <Pallet<T>>::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() {
-		return Ok(None);
-	}
-
-	let priorities: Vec<_> = <Pallet<T>>::get_nft_property_decoded(
-		collection_id,
-		nft_id,
-		RmrkProperty::ResourcePriorities,
-	)?;
-	Ok(priorities
-		.into_iter()
-		.enumerate()
-		.find(|(_, id)| *id == resource_id)
-		.map(|(priority, _): (usize, RmrkResourceId)| priority as u32))
-}
deletedpallets/proxy-rmrk-core/src/weights.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/weights.rs
+++ /dev/null
@@ -1,480 +0,0 @@
-// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs
-
-//! Autogenerated weights for pallet_proxy_rmrk_core
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
-
-// Executed Command:
-// target/release/unique-collator
-// benchmark
-// pallet
-// --pallet
-// pallet-proxy-rmrk-core
-// --wasm-execution
-// compiled
-// --extrinsic
-// *
-// --template
-// .maintain/frame-weight-template.hbs
-// --steps=50
-// --repeat=80
-// --heap-pages=4096
-// --output=./pallets/proxy-rmrk-core/src/weights.rs
-
-#![cfg_attr(rustfmt, rustfmt_skip)]
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-#![allow(clippy::unnecessary_cast)]
-
-use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
-use sp_std::marker::PhantomData;
-
-/// Weight functions needed for pallet_proxy_rmrk_core.
-pub trait WeightInfo {
-	fn create_collection() -> Weight;
-	fn destroy_collection() -> Weight;
-	fn change_collection_issuer() -> Weight;
-	fn lock_collection() -> Weight;
-	fn mint_nft(b: u32, ) -> Weight;
-	fn burn_nft(b: u32, ) -> Weight;
-	fn send() -> Weight;
-	fn accept_nft() -> Weight;
-	fn reject_nft() -> Weight;
-	fn set_property() -> Weight;
-	fn set_priority() -> Weight;
-	fn add_basic_resource() -> Weight;
-	fn add_composable_resource() -> Weight;
-	fn add_slot_resource() -> Weight;
-	fn remove_resource() -> Weight;
-	fn accept_resource() -> Weight;
-	fn accept_resource_removal() -> Weight;
-}
-
-/// Weights for pallet_proxy_rmrk_core using the Substrate node and recommended hardware.
-pub struct SubstrateWeight<T>(PhantomData<T>);
-impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
-	// Storage: Common CreatedCollectionCount (r:1 w:1)
-	// Storage: Common DestroyedCollectionCount (r:1 w:0)
-	// Storage: System Account (r:2 w:2)
-	// Storage: RmrkCore CollectionIndex (r:1 w:1)
-	// Storage: Common CollectionPropertyPermissions (r:0 w:1)
-	// Storage: Common CollectionProperties (r:0 w:1)
-	// Storage: Common CollectionById (r:0 w:1)
-	// Storage: RmrkCore UniqueCollectionId (r:0 w:1)
-	fn create_collection() -> Weight {
-		Weight::from_ref_time(49_754_000)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(8 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:1)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:1 w:0)
-	// Storage: Common DestroyedCollectionCount (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:0 w:1)
-	// Storage: Nonfungible TokensBurnt (r:0 w:1)
-	// Storage: Common AdminAmount (r:0 w:1)
-	fn destroy_collection() -> Weight {
-		Weight::from_ref_time(48_588_000)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(6 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	fn change_collection_issuer() -> Weight {
-		Weight::from_ref_time(25_054_000)
-			.saturating_add(T::DbWeight::get().reads(3 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:1 w:0)
-	// Storage: Nonfungible TokensBurnt (r:1 w:0)
-	fn lock_collection() -> Weight {
-		Weight::from_ref_time(26_483_000)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:2 w:2)
-	fn mint_nft(b: u32, ) -> Weight {
-		Weight::from_ref_time(62_419_000)
-			// Standard Error: 7_000
-			.saturating_add(Weight::from_ref_time(12_325_000).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(6 as u64))
-			.saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64)))
-			.saturating_add(T::DbWeight::get().writes(5 as u64))
-			.saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:1 w:0)
-	// Storage: Nonfungible TokensBurnt (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	// Storage: Nonfungible TokenProperties (r:0 w:1)
-	fn burn_nft(b: u32, ) -> Weight {
-		(Weight::from_ref_time(0))
-			// Standard Error: 1_488_000
-			.saturating_add(Weight::from_ref_time(298_367_000).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(b as u64)))
-			.saturating_add(T::DbWeight::get().writes(6 as u64))
-			.saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:0)
-	// Storage: Nonfungible AccountBalance (r:2 w:2)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible TokenChildren (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:2)
-	fn send() -> Weight {
-		Weight::from_ref_time(81_942_000)
-			.saturating_add(T::DbWeight::get().reads(12 as u64))
-			.saturating_add(T::DbWeight::get().writes(6 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:2 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:2 w:0)
-	// Storage: Nonfungible TokenData (r:6 w:1)
-	// Storage: Nonfungible AccountBalance (r:2 w:2)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:2)
-	fn accept_nft() -> Weight {
-		Weight::from_ref_time(97_925_000)
-			.saturating_add(T::DbWeight::get().reads(16 as u64))
-			.saturating_add(T::DbWeight::get().writes(8 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:5)
-	// Storage: Nonfungible TokenProperties (r:1 w:5)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:9 w:4)
-	// Storage: Nonfungible TokensBurnt (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:5 w:5)
-	// Storage: Nonfungible Allowance (r:5 w:0)
-	// Storage: Nonfungible Owned (r:0 w:5)
-	fn reject_nft() -> Weight {
-		Weight::from_ref_time(277_794_000)
-			.saturating_add(T::DbWeight::get().reads(30 as u64))
-			.saturating_add(T::DbWeight::get().writes(26 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn set_property() -> Weight {
-		Weight::from_ref_time(54_657_000)
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn set_priority() -> Weight {
-		Weight::from_ref_time(55_056_000)
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn add_basic_resource() -> Weight {
-		Weight::from_ref_time(61_673_000)
-			.saturating_add(T::DbWeight::get().reads(10 as u64))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:2 w:2)
-	fn add_composable_resource() -> Weight {
-		Weight::from_ref_time(67_125_000)
-			.saturating_add(T::DbWeight::get().reads(11 as u64))
-			.saturating_add(T::DbWeight::get().writes(3 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn add_slot_resource() -> Weight {
-		Weight::from_ref_time(69_058_000)
-			.saturating_add(T::DbWeight::get().reads(10 as u64))
-			.saturating_add(T::DbWeight::get().writes(2 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn remove_resource() -> Weight {
-		Weight::from_ref_time(53_427_000)
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn accept_resource() -> Weight {
-		Weight::from_ref_time(50_623_000)
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn accept_resource_removal() -> Weight {
-		Weight::from_ref_time(50_917_000)
-			.saturating_add(T::DbWeight::get().reads(9 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-}
-
-// For backwards compatibility and tests
-impl WeightInfo for () {
-	// Storage: Common CreatedCollectionCount (r:1 w:1)
-	// Storage: Common DestroyedCollectionCount (r:1 w:0)
-	// Storage: System Account (r:2 w:2)
-	// Storage: RmrkCore CollectionIndex (r:1 w:1)
-	// Storage: Common CollectionPropertyPermissions (r:0 w:1)
-	// Storage: Common CollectionProperties (r:0 w:1)
-	// Storage: Common CollectionById (r:0 w:1)
-	// Storage: RmrkCore UniqueCollectionId (r:0 w:1)
-	fn create_collection() -> Weight {
-		Weight::from_ref_time(49_754_000)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(8 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:1)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:1 w:0)
-	// Storage: Common DestroyedCollectionCount (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:0 w:1)
-	// Storage: Nonfungible TokensBurnt (r:0 w:1)
-	// Storage: Common AdminAmount (r:0 w:1)
-	fn destroy_collection() -> Weight {
-		Weight::from_ref_time(48_588_000)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(6 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	fn change_collection_issuer() -> Weight {
-		Weight::from_ref_time(25_054_000)
-			.saturating_add(RocksDbWeight::get().reads(3 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:1 w:0)
-	// Storage: Nonfungible TokensBurnt (r:1 w:0)
-	fn lock_collection() -> Weight {
-		Weight::from_ref_time(26_483_000)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:2 w:2)
-	fn mint_nft(b: u32, ) -> Weight {
-		Weight::from_ref_time(62_419_000)
-			// Standard Error: 7_000
-			.saturating_add(Weight::from_ref_time(12_325_000).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(6 as u64))
-			.saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(b as u64)))
-			.saturating_add(RocksDbWeight::get().writes(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:1 w:0)
-	// Storage: Nonfungible TokensBurnt (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	// Storage: Nonfungible TokenProperties (r:0 w:1)
-	fn burn_nft(b: u32, ) -> Weight {
-		(Weight::from_ref_time(0))
-			// Standard Error: 1_488_000
-			.saturating_add(Weight::from_ref_time(298_367_000).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(b as u64)))
-			.saturating_add(RocksDbWeight::get().writes(6 as u64))
-			.saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:0)
-	// Storage: Nonfungible AccountBalance (r:2 w:2)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible TokenChildren (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:2)
-	fn send() -> Weight {
-		Weight::from_ref_time(81_942_000)
-			.saturating_add(RocksDbWeight::get().reads(12 as u64))
-			.saturating_add(RocksDbWeight::get().writes(6 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:2 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:2 w:0)
-	// Storage: Nonfungible TokenData (r:6 w:1)
-	// Storage: Nonfungible AccountBalance (r:2 w:2)
-	// Storage: Nonfungible Allowance (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:2)
-	fn accept_nft() -> Weight {
-		Weight::from_ref_time(97_925_000)
-			.saturating_add(RocksDbWeight::get().reads(16 as u64))
-			.saturating_add(RocksDbWeight::get().writes(8 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:5)
-	// Storage: Nonfungible TokenProperties (r:1 w:5)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenChildren (r:9 w:4)
-	// Storage: Nonfungible TokensBurnt (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:5 w:5)
-	// Storage: Nonfungible Allowance (r:5 w:0)
-	// Storage: Nonfungible Owned (r:0 w:5)
-	fn reject_nft() -> Weight {
-		Weight::from_ref_time(277_794_000)
-			.saturating_add(RocksDbWeight::get().reads(30 as u64))
-			.saturating_add(RocksDbWeight::get().writes(26 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn set_property() -> Weight {
-		Weight::from_ref_time(54_657_000)
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn set_priority() -> Weight {
-		Weight::from_ref_time(55_056_000)
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn add_basic_resource() -> Weight {
-		Weight::from_ref_time(61_673_000)
-			.saturating_add(RocksDbWeight::get().reads(10 as u64))
-			.saturating_add(RocksDbWeight::get().writes(2 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:2 w:2)
-	fn add_composable_resource() -> Weight {
-		Weight::from_ref_time(67_125_000)
-			.saturating_add(RocksDbWeight::get().reads(11 as u64))
-			.saturating_add(RocksDbWeight::get().writes(3 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn add_slot_resource() -> Weight {
-		Weight::from_ref_time(69_058_000)
-			.saturating_add(RocksDbWeight::get().reads(10 as u64))
-			.saturating_add(RocksDbWeight::get().writes(2 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	fn remove_resource() -> Weight {
-		Weight::from_ref_time(53_427_000)
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn accept_resource() -> Weight {
-		Weight::from_ref_time(50_623_000)
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	// Storage: RmrkCore UniqueCollectionId (r:1 w:0)
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:5 w:0)
-	// Storage: Nonfungible TokenAuxProperties (r:1 w:1)
-	fn accept_resource_removal() -> Weight {
-		Weight::from_ref_time(50_917_000)
-			.saturating_add(RocksDbWeight::get().reads(9 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-}
deletedpallets/proxy-rmrk-equip/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/CHANGELOG.md
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- bureaucrate goes here -->
-## [v0.1.2] 2022-08-16
-
-### Other changes
-
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-
-- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31
-
-Every extrinsic now runs in transaction implicitly, and
-`#[transactional]` on pallet dispatchable is now meaningless
-
-Upstream-Change: https://github.com/paritytech/substrate/issues/10806
-
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
\ No newline at end of file
deletedpallets/proxy-rmrk-equip/Cargo.tomldiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/Cargo.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-[package]
-edition = "2021"
-license = "GPLv3"
-name = "pallet-rmrk-equip"
-version = "0.1.2"
-
-[dependencies]
-# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
-codec = { workspace = true, package = "parity-scale-codec" }
-
-scale-info = { workspace = true }
-
-frame-benchmarking = {workspace = true, optional = true }
-frame-support = { workspace = true }
-frame-system = { workspace = true }
-pallet-common = { workspace = true }
-pallet-evm = { workspace = true }
-pallet-nonfungible = { workspace = true }
-pallet-proxy-rmrk-core = { workspace = true }
-sp-runtime = { workspace = true }
-sp-std = { workspace = true }
-up-data-structs = { workspace = true }
-
-[features]
-default = ["std"]
-runtime-benchmarks = ['frame-benchmarking', 'frame-support/runtime-benchmarks', 'frame-system/runtime-benchmarks']
-std = [
-	"frame-support/std",
-	"frame-system/std",
-	"pallet-common/std",
-	"pallet-evm/std",
-	"pallet-nonfungible/std",
-	"pallet-proxy-rmrk-core/std",
-	"sp-runtime/std",
-	"sp-std/std",
-	"up-data-structs/std",
-	'frame-benchmarking/std',
-]
-try-runtime = ["frame-support/try-runtime"]
deletedpallets/proxy-rmrk-equip/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/benchmarking.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-use sp_std::vec;
-
-use frame_benchmarking::{benchmarks, account};
-use frame_system::RawOrigin;
-use frame_support::{
-	traits::{Currency, Get},
-	BoundedVec,
-};
-
-use up_data_structs::*;
-
-use super::*;
-
-const SEED: u32 = 1;
-
-fn create_data<S: Get<u32>>() -> BoundedVec<u8, S> {
-	vec![b'A'; S::get() as usize].try_into().expect("size == S")
-}
-
-fn create_u32_array<S: Get<u32>>() -> BoundedVec<u32, S> {
-	vec![0; S::get() as usize].try_into().expect("size == S")
-}
-
-fn create_max_part(id: RmrkSlotId) -> RmrkPartType {
-	RmrkPartType::SlotPart(RmrkSlotPart {
-		id,
-		equippable: RmrkEquippableList::Custom(create_u32_array()),
-		src: create_data(),
-		z: 1,
-	})
-}
-
-fn create_parts_array<S: Get<u32>>(num: u32) -> BoundedVec<RmrkPartType, S> {
-	let mut parts: BoundedVec<RmrkPartType, S> = vec![].try_into().expect("0 <= S");
-
-	for i in 0..num {
-		parts.try_push(create_max_part(i)).expect("num <= S");
-	}
-
-	parts
-}
-
-fn create_max_theme_property() -> RmrkThemeProperty {
-	RmrkThemeProperty {
-		key: create_data(),
-		value: create_data(),
-	}
-}
-
-fn create_theme_properties_array<S: Get<u32>>(num: u32) -> BoundedVec<RmrkThemeProperty, S> {
-	vec![create_max_theme_property(); num as usize]
-		.try_into()
-		.expect("num <= S")
-}
-
-fn create_max_theme(name: RmrkString, props_num: u32) -> RmrkBoundedTheme {
-	RmrkBoundedTheme {
-		name,
-		properties: create_theme_properties_array(props_num),
-		inherit: false,
-	}
-}
-
-benchmarks! {
-	create_base {
-		let b in 0..RmrkPartsLimit::get();
-
-		let caller = account("caller", 0, SEED);
-		<T as pallet_common::Config>::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get());
-
-		let base_type = create_data();
-		let symbol = create_data();
-		let parts = create_parts_array(b);
-	}: _(RawOrigin::Signed(caller), base_type, symbol, parts)
-
-	theme_add {
-		let b in 0..MaxPropertiesPerTheme::get();
-
-		let caller = account("caller", 0, SEED);
-		<T as pallet_common::Config>::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get());
-
-		let base_type = create_data();
-		let symbol = create_data();
-		let parts = create_parts_array(0);
-
-		<Pallet<T>>::create_base(RawOrigin::Signed(caller.clone()).into(), base_type, symbol, parts)?;
-		let base_id = 1;
-
-
-		let default_theme_name = b"default".to_vec().try_into().expect("default is a valid name; qed");
-		let default_theme = create_max_theme(default_theme_name, 0);
-
-		<Pallet<T>>::theme_add(RawOrigin::Signed(caller.clone()).into(), base_id, default_theme)?;
-
-		let theme = create_max_theme(create_data(), b);
-	}: _(RawOrigin::Signed(caller), base_id, theme)
-
-	equippable {
-		let caller = account("caller", 0, SEED);
-		<T as pallet_common::Config>::Currency::deposit_creating(&caller, T::CollectionCreationPrice::get());
-
-		let base_id = 1;
-		let slot_id = 42;
-
-		let base_type = create_data();
-		let symbol = create_data();
-		let parts = vec! {
-			RmrkPartType::SlotPart(RmrkSlotPart {
-				id: slot_id,
-				equippable: RmrkEquippableList::All,
-				src: create_data(),
-				z: 1,
-			})
-		}.try_into().expect("1 <= RmrkPartsLimit");
-
-		<Pallet<T>>::create_base(RawOrigin::Signed(caller.clone()).into(), base_type, symbol, parts)?;
-
-		let equippables = RmrkEquippableList::Custom(create_u32_array());
-	}: _(RawOrigin::Signed(caller), base_id, slot_id, equippables)
-}
deletedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ /dev/null
@@ -1,508 +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/>.
-
-//! # RMRK Core Proxy Pallet
-//!
-//! A pallet used as proxy for RMRK Core (<https://rmrk-team.github.io/rmrk-substrate/#/pallets/rmrk-core>).
-//!
-//! - [`Config`]
-//! - [`Call`]
-//! - [`Pallet`]
-//!
-//! ## Overview
-//!
-//! The RMRK Equip Proxy pallet mirrors the functionality of RMRK Equip,
-//! binding its externalities to Unique's own underlying structure.
-//! It is purposed to mimic RMRK Equip exactly, allowing seamless integrations
-//! of solutions based on RMRK.
-//!
-//! RMRK Equip itself contains functionality to equip NFTs, and work with Bases,
-//! Parts, and Themes. See [Proxy Implementation](#proxy-implementation) for details.
-//!
-//! Equip Proxy is responsible for a more specific area of RMRK, and heavily relies on the Core.
-//! For a more foundational description of proxy implementation, please refer to [`pallet_rmrk_core`].
-//!
-//! *Note*, that while RMRK itself is subject to active development and restructuring,
-//! the proxy may be caught temporarily out of date.
-//!
-//! ### What is RMRK?
-//!
-//! RMRK is a set of NFT standards which compose several "NFT 2.0 lego" primitives.
-//! Putting these legos together allows a user to create NFT systems of arbitrary complexity.
-//!
-//! Meaning, RMRK NFTs are dynamic, able to nest into each other and form a hierarchy,
-//! make use of specific changeable and partially shared metadata in the form of resources,
-//! and more.
-//!
-//! Visit RMRK documentation and repositories to learn more:
-//! - Docs: <https://docs.rmrk.app/getting-started/>
-//! - FAQ: <https://coda.io/@rmrk/faq>
-//! - Substrate code repository: <https://github.com/rmrk-team/rmrk-substrate>
-//! - RMRK spec repository: <https://github.com/rmrk-team/rmrk-spec>
-//!
-//! ## Terminology
-//!
-//! For more information on RMRK, see RMRK's own documentation.
-//!
-//! ### Intro to RMRK
-//!
-//! - **Resource:** Additional piece of metadata of an NFT usually serving to add
-//! a piece of media on top of the root metadata (NFT's own), be it a different wing
-//! on the root template bird or something entirely unrelated.
-//!
-//! - **Base:** A list of possible "components" - Parts, a combination of which can
-//! be appended/equipped to/on an NFT.
-//!
-//! - **Part:** Something that, together with other Parts, can constitute an NFT.
-//! Parts are defined in the Base to which they belong. Parts can be either
-//! of the `slot` type or `fixed` type. Slots are intended for equippables.
-//! Note that "part of something" and "Part of a Base" can be easily confused,
-//! and so in this documentation these words are distinguished by the capital letter.
-//!
-//! - **Theme:** Named objects of variable => value pairs which get interpolated into
-//! the Base's `themable` Parts. Themes can hold any value, but are often represented
-//! in RMRK's examples as colors applied to visible Parts.
-//!
-//! ### Peculiarities in Unique
-//!
-//! - **Scoped properties:** Properties that are normally obscured from users.
-//! Their purpose is to contain structured metadata that was not included in the Unique standard
-//! for collections and tokens, meant to be operated on by proxies and other outliers.
-//! Scoped property keys are prefixed with `some-scope:`, where `some-scope` is
-//! an arbitrary keyword, like "rmrk". `:` is considered an unacceptable symbol in user-defined
-//! properties, which, along with other safeguards, makes scoped ones impossible to tamper with.
-//!
-//! - **Auxiliary properties:** A slightly different structure of properties,
-//! trading universality of use for more convenient storage, writes and access.
-//! Meant to be inaccessible to end users.
-//!
-//! ## Proxy Implementation
-//!
-//! An external user is supposed to be able to utilize this proxy as they would
-//! utilize RMRK, and get exactly the same results. Normally, Unique transactions
-//! are off-limits to RMRK collections and tokens, and vice versa. However,
-//! the information stored on chain can be freely interpreted by storage reads and Unique RPCs.
-//!
-//! ### ID Mapping
-//!
-//! RMRK's collections' IDs are counted independently of Unique's and start at 0.
-//! Note that tokens' IDs still start at 1.
-//! The collections themselves, as well as tokens, are stored as Unique collections,
-//! and thus RMRK IDs are mapped to Unique IDs (but not vice versa).
-//!
-//! ### External/Internal Collection Insulation
-//!
-//! A Unique transaction cannot target collections purposed for RMRK,
-//! and they are flagged as `external` to specify that. On the other hand,
-//! due to the mapping, RMRK transactions and RPCs simply cannot reach Unique collections.
-//!
-//! ### Native Properties
-//!
-//! Many of RMRK's native parameters are stored as scoped properties of a collection
-//! or an NFT on the chain. Scoped properties are prefixed with `rmrk:`, where `:`
-//! is an unacceptable symbol in user-defined properties, which, along with other safeguards,
-//! makes them impossible to tamper with.
-//!
-//! ### Collection and NFT Types, or Base, Parts and Themes Handling
-//!
-//! RMRK introduces the concept of a Base, which is a catalogue of Parts,
-//! possible components of an NFT. Due to its similarity with the functionality
-//! of a token collection, a Base is stored and handled as one, and the Base's Parts and Themes
-//! are this collection's NFTs. See [`CollectionType`] and [`NftType`].
-//!
-//! ## Interface
-//!
-//! ### Dispatchables
-//!
-//! - `create_base` - Create a new Base.
-//! - `theme_add` - Add a Theme to a Base.
-//! - `equippable` - Update the array of Collections allowed to be equipped to a Base's specified Slot Part.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use frame_support::{pallet_prelude::*, BoundedVec, dispatch::DispatchResult};
-use frame_system::{pallet_prelude::*, ensure_signed};
-use sp_runtime::DispatchError;
-use up_data_structs::*;
-use pallet_common::{Pallet as PalletCommon, Error as CommonError};
-use pallet_proxy_rmrk_core::{
-	Pallet as PalletCore, Error as CoreError,
-	misc::{self, *},
-	property::RmrkProperty::*,
-};
-use pallet_nonfungible::{Pallet as PalletNft, NonfungibleHandle};
-use pallet_evm::account::CrossAccountId;
-use weights::WeightInfo;
-
-pub use pallet::*;
-
-#[cfg(feature = "runtime-benchmarks")]
-pub mod benchmarking;
-pub mod rpc;
-pub mod weights;
-
-pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
-
-#[frame_support::pallet]
-pub mod pallet {
-	use super::*;
-
-	#[pallet::config]
-	pub trait Config: frame_system::Config + pallet_proxy_rmrk_core::Config {
-		/// Overarching event type.
-		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
-
-		/// The weight information of this pallet.
-		type WeightInfo: WeightInfo;
-	}
-
-	/// Map of a Base ID and a Part ID to an NFT in the Base collection serving as the Part.
-	#[pallet::storage]
-	#[pallet::getter(fn internal_part_id)]
-	pub type InernalPartId<T: Config> =
-		StorageDoubleMap<_, Twox64Concat, CollectionId, Twox64Concat, RmrkPartId, TokenId>;
-
-	/// Checkmark that a Base has a Theme NFT named "default".
-	#[pallet::storage]
-	#[pallet::getter(fn base_has_default_theme)]
-	pub type BaseHasDefaultTheme<T: Config> =
-		StorageMap<_, Twox64Concat, CollectionId, bool, ValueQuery>;
-
-	#[pallet::pallet]
-	#[pallet::generate_store(pub(super) trait Store)]
-	pub struct Pallet<T>(_);
-
-	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
-	pub enum Event<T: Config> {
-		BaseCreated {
-			issuer: T::AccountId,
-			base_id: RmrkBaseId,
-		},
-		EquippablesUpdated {
-			base_id: RmrkBaseId,
-			slot_id: RmrkSlotId,
-		},
-	}
-
-	#[pallet::error]
-	pub enum Error<T> {
-		/// No permission to perform action.
-		PermissionError,
-		/// Could not find an ID for a Base collection. It is likely there were too many collections created on the chain, causing an overflow.
-		NoAvailableBaseId,
-		/// Could not find a suitable ID for a Part, likely too many Part tokens were created in the Base, causing an overflow
-		NoAvailablePartId,
-		/// Base collection linked to this ID does not exist.
-		BaseDoesntExist,
-		/// No Theme named "default" is associated with the Base.
-		NeedsDefaultThemeFirst,
-		/// Part linked to this ID does not exist.
-		PartDoesntExist,
-		/// Cannot assign equippables to a fixed Part.
-		NoEquippableOnFixedPart,
-	}
-
-	#[pallet::call]
-	impl<T: Config> Pallet<T> {
-		/// Create a new Base.
-		///
-		/// Modeled after the [Base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md)
-		///
-		/// # Permissions
-		/// - Anyone - will be assigned as the issuer of the Base.
-		///
-		/// # Arguments:
-		/// - `origin`: Caller, will be assigned as the issuer of the Base
-		/// - `base_type`: Arbitrary media type, e.g. "svg".
-		/// - `symbol`: Arbitrary client-chosen symbol.
-		/// - `parts`: Array of Fixed and Slot Parts composing the Base,
-		/// confined in length by [`RmrkPartsLimit`](up_data_structs::RmrkPartsLimit).
-		#[pallet::call_index(0)]
-		#[pallet::weight(<SelfWeightOf<T>>::create_base(parts.len() as u32))]
-		pub fn create_base(
-			origin: OriginFor<T>,
-			base_type: RmrkString,
-			symbol: RmrkBaseSymbol,
-			parts: BoundedVec<RmrkPartType, RmrkPartsLimit>,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-			let cross_sender = T::CrossAccountId::from_sub(sender.clone());
-
-			let data = CreateCollectionData {
-				limits: None,
-				token_prefix: symbol
-					.into_inner()
-					.try_into()
-					.map_err(|_| <CommonError<T>>::CollectionTokenPrefixLimitExceeded)?,
-				..Default::default()
-			};
-
-			let collection_id_res = <PalletNft<T>>::init_collection(
-				cross_sender.clone(),
-				cross_sender.clone(),
-				data,
-				up_data_structs::CollectionFlags {
-					external: true,
-					..Default::default()
-				},
-			);
-
-			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
-				return Err(<Error<T>>::NoAvailableBaseId.into());
-			}
-
-			let collection_id = collection_id_res?;
-
-			<PalletCommon<T>>::set_scoped_collection_properties(
-				collection_id,
-				PropertyScope::Rmrk,
-				[
-					<PalletCore<T>>::encode_rmrk_property(
-						CollectionType,
-						&misc::CollectionType::Base,
-					)?,
-					<PalletCore<T>>::encode_rmrk_property(BaseType, &base_type)?,
-				]
-				.into_iter(),
-			)?;
-
-			let collection = <PalletCore<T>>::get_nft_collection(collection_id)?;
-
-			for part in parts {
-				Self::create_part(&cross_sender, &collection, part)?;
-			}
-
-			Self::deposit_event(Event::BaseCreated {
-				issuer: sender,
-				base_id: collection_id.0,
-			});
-
-			Ok(())
-		}
-
-		/// Add a Theme to a Base.
-		/// A Theme named "default" is required prior to adding other Themes.
-		///
-		/// Modeled after [Themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md).
-		///
-		/// # Permissions:
-		/// - Base issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `base_id`: Base ID containing the Theme to be updated.
-		/// - `theme`: Theme to add to the Base.  A Theme has a name and properties, which are an
-		///   array of [key, value, inherit].
-		///   - `key`: Arbitrary BoundedString, defined by client.
-		///   - `value`: Arbitrary BoundedString, defined by client.
-		///   - `inherit`: Optional bool.
-		#[pallet::call_index(1)]
-		#[pallet::weight(<SelfWeightOf<T>>::theme_add(theme.properties.len() as u32))]
-		pub fn theme_add(
-			origin: OriginFor<T>,
-			base_id: RmrkBaseId,
-			theme: RmrkBoundedTheme,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-
-			let sender = T::CrossAccountId::from_sub(sender);
-			let owner = &sender;
-
-			let collection_id: CollectionId = base_id.into();
-
-			let collection = Self::get_base(collection_id)?;
-
-			if theme.name.as_slice() == b"default" {
-				<BaseHasDefaultTheme<T>>::insert(collection_id, true);
-			} else if !Self::base_has_default_theme(collection_id) {
-				return Err(<Error<T>>::NeedsDefaultThemeFirst.into());
-			}
-
-			let token_id = <PalletCore<T>>::create_nft(
-				&sender,
-				owner,
-				&collection,
-				[
-					<PalletCore<T>>::encode_rmrk_property(TokenType, &NftType::Theme)?,
-					<PalletCore<T>>::encode_rmrk_property(ThemeName, &theme.name)?,
-					<PalletCore<T>>::encode_rmrk_property(ThemeInherit, &theme.inherit)?,
-				]
-				.into_iter(),
-			)
-			.map_err(|_| <Error<T>>::PermissionError)?;
-
-			for property in theme.properties {
-				<PalletNft<T>>::set_scoped_token_property(
-					collection_id,
-					token_id,
-					PropertyScope::Rmrk,
-					<PalletCore<T>>::encode_rmrk_property(
-						UserProperty(property.key.as_slice()),
-						&property.value,
-					)?,
-				)?;
-			}
-
-			Ok(())
-		}
-
-		/// Update the array of Collections allowed to be equipped to a Base's specified Slot Part.
-		///
-		/// Modeled after [equippable interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/equippable.md).
-		///
-		/// # Permissions:
-		/// - Base issuer
-		///
-		/// # Arguments:
-		/// - `origin`: sender of the transaction
-		/// - `base_id`: Base containing the Slot Part to be updated.
-		/// - `slot_id`: Slot Part whose Equippable List is being updated .
-		/// - `equippables`: List of equippables that will override the current Equippables list.
-		#[pallet::call_index(2)]
-		#[pallet::weight(<SelfWeightOf<T>>::equippable())]
-		pub fn equippable(
-			origin: OriginFor<T>,
-			base_id: RmrkBaseId,
-			slot_id: RmrkSlotId,
-			equippables: RmrkEquippableList,
-		) -> DispatchResult {
-			let sender = ensure_signed(origin)?;
-
-			let base_collection_id = base_id.into();
-			let collection = Self::get_base(base_collection_id)?;
-
-			<PalletCore<T>>::check_collection_owner(
-				&collection,
-				&T::CrossAccountId::from_sub(sender),
-			)
-			.map_err(|err| {
-				if err == <CoreError<T>>::NoPermission.into() {
-					<Error<T>>::PermissionError.into()
-				} else {
-					err
-				}
-			})?;
-
-			let part_id = Self::internal_part_id(base_collection_id, slot_id)
-				.ok_or(<Error<T>>::PartDoesntExist)?;
-
-			let nft_type = <PalletCore<T>>::get_nft_type(base_collection_id, part_id)
-				.map_err(|_| <Error<T>>::PartDoesntExist)?;
-
-			match nft_type {
-				NftType::Regular | NftType::Theme => return Err(<Error<T>>::PermissionError.into()),
-				NftType::FixedPart => return Err(<Error<T>>::NoEquippableOnFixedPart.into()),
-				NftType::SlotPart => {
-					<PalletNft<T>>::set_scoped_token_property(
-						base_collection_id,
-						part_id,
-						PropertyScope::Rmrk,
-						<PalletCore<T>>::encode_rmrk_property(EquippableList, &equippables)?,
-					)?;
-				}
-			}
-
-			Self::deposit_event(Event::EquippablesUpdated { base_id, slot_id });
-
-			Ok(())
-		}
-	}
-}
-
-impl<T: Config> Pallet<T> {
-	/// Create (or overwrite) a Part in a Base.
-	/// The Part and the Base are represented as an NFT and a Collection.
-	fn create_part(
-		sender: &T::CrossAccountId,
-		collection: &NonfungibleHandle<T>,
-		part: RmrkPartType,
-	) -> DispatchResult {
-		let owner = sender;
-
-		let part_id = part.id();
-		let src = part.src();
-		let z_index = part.z_index();
-
-		let nft_type = match part {
-			RmrkPartType::FixedPart(_) => NftType::FixedPart,
-			RmrkPartType::SlotPart(_) => NftType::SlotPart,
-		};
-
-		let token_id = match Self::internal_part_id(collection.id, part_id) {
-			Some(token_id) => token_id,
-			None => {
-				let token_id =
-					<PalletCore<T>>::create_nft(sender, owner, collection, [].into_iter())
-						.map_err(|err| match err {
-							DispatchError::Arithmetic(_) => <Error<T>>::NoAvailablePartId.into(),
-							err => err,
-						})?;
-
-				<InernalPartId<T>>::insert(collection.id, part_id, token_id);
-
-				<PalletNft<T>>::set_scoped_token_property(
-					collection.id,
-					token_id,
-					PropertyScope::Rmrk,
-					<PalletCore<T>>::encode_rmrk_property(ExternalPartId, &part_id)?,
-				)?;
-
-				token_id
-			}
-		};
-
-		<PalletNft<T>>::set_scoped_token_properties(
-			collection.id,
-			token_id,
-			PropertyScope::Rmrk,
-			[
-				<PalletCore<T>>::encode_rmrk_property(TokenType, &nft_type)?,
-				<PalletCore<T>>::encode_rmrk_property(Src, &src)?,
-				<PalletCore<T>>::encode_rmrk_property(ZIndex, &z_index)?,
-			]
-			.into_iter(),
-		)?;
-
-		if let RmrkPartType::SlotPart(part) = part {
-			<PalletNft<T>>::set_scoped_token_property(
-				collection.id,
-				token_id,
-				PropertyScope::Rmrk,
-				<PalletCore<T>>::encode_rmrk_property(EquippableList, &part.equippable)?,
-			)?;
-		}
-
-		Ok(())
-	}
-
-	/// Ensure that the collection under the Base ID is a Base collection,
-	/// and fetch it.
-	fn get_base(base_id: CollectionId) -> Result<NonfungibleHandle<T>, DispatchError> {
-		let collection =
-			<PalletCore<T>>::get_typed_nft_collection(base_id, misc::CollectionType::Base)
-				.map_err(|err| {
-					if err == <CoreError<T>>::CollectionUnknown.into() {
-						<Error<T>>::BaseDoesntExist.into()
-					} else {
-						err
-					}
-				})?;
-		collection.check_is_external()?;
-
-		Ok(collection)
-	}
-}
deletedpallets/proxy-rmrk-equip/src/rpc.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/rpc.rs
+++ /dev/null
@@ -1,208 +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/>.
-
-//! Realizations of RMRK RPCs (remote procedure calls) related to the Equip pallet.
-
-use super::*;
-use pallet_proxy_rmrk_core::{misc, property::*};
-use sp_std::vec::Vec;
-
-/// Get base info by its ID.
-pub fn base<T: Config>(
-	base_id: RmrkBaseId,
-) -> Result<Option<RmrkBaseInfo<T::AccountId>>, DispatchError> {
-	let (collection, collection_id) =
-		match <PalletCore<T>>::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base)
-		{
-			Ok(c) => c,
-			Err(_) => return Ok(None),
-		};
-
-	Ok(Some(RmrkBaseInfo {
-		issuer: collection.owner.clone(),
-		base_type: <PalletCore<T>>::get_collection_property_decoded(
-			collection_id,
-			RmrkProperty::BaseType,
-		)?,
-		symbol: <PalletCore<T>>::rebind(&collection.token_prefix)?,
-	}))
-}
-
-/// Get all parts of a base.
-pub fn base_parts<T: Config>(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
-	use pallet_common::CommonCollectionOperations;
-
-	let (collection, collection_id) =
-		match <PalletCore<T>>::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base)
-		{
-			Ok(c) => c,
-			Err(_) => return Ok(Vec::new()),
-		};
-
-	let parts = collection
-		.collection_tokens()
-		.into_iter()
-		.filter_map(|token_id| {
-			let nft_type = <PalletCore<T>>::get_nft_type(collection_id, token_id).ok()?;
-
-			match nft_type {
-				NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart {
-					id: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::ExternalPartId,
-					)
-					.ok()?,
-					src: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::Src,
-					)
-					.ok()?,
-					z: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::ZIndex,
-					)
-					.ok()?,
-				})),
-				NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart {
-					id: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::ExternalPartId,
-					)
-					.ok()?,
-					src: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::Src,
-					)
-					.ok()?,
-					z: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::ZIndex,
-					)
-					.ok()?,
-					equippable: <PalletCore<T>>::get_nft_property_decoded(
-						collection_id,
-						token_id,
-						RmrkProperty::EquippableList,
-					)
-					.ok()?,
-				})),
-				_ => None,
-			}
-		})
-		.collect();
-
-	Ok(parts)
-}
-
-/// Get the theme names belonging to a base.
-pub fn theme_names<T: Config>(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
-	use pallet_common::CommonCollectionOperations;
-
-	let (collection, collection_id) =
-		match <PalletCore<T>>::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base)
-		{
-			Ok(c) => c,
-			Err(_) => return Ok(Vec::new()),
-		};
-
-	let theme_names = collection
-		.collection_tokens()
-		.iter()
-		.filter_map(|token_id| {
-			let nft_type = <PalletCore<T>>::get_nft_type(collection_id, *token_id).ok()?;
-
-			match nft_type {
-				NftType::Theme => <PalletCore<T>>::get_nft_property_decoded(
-					collection_id,
-					*token_id,
-					RmrkProperty::ThemeName,
-				)
-				.ok(),
-				_ => None,
-			}
-		})
-		.collect();
-
-	Ok(theme_names)
-}
-
-/// Get theme info, including properties, optionally limited to the provided keys.
-pub fn theme<T: Config>(
-	base_id: RmrkBaseId,
-	theme_name: RmrkThemeName,
-	filter_keys: Option<Vec<RmrkPropertyKey>>,
-) -> Result<Option<RmrkTheme>, DispatchError> {
-	use pallet_common::CommonCollectionOperations;
-
-	let (collection, collection_id) =
-		match <PalletCore<T>>::get_typed_nft_collection_mapped(base_id, misc::CollectionType::Base)
-		{
-			Ok(c) => c,
-			Err(_) => return Ok(None),
-		};
-
-	let theme_info = collection
-		.collection_tokens()
-		.into_iter()
-		.find_map(|token_id| {
-			<PalletCore<T>>::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;
-
-			let name: RmrkString = <PalletCore<T>>::get_nft_property_decoded(
-				collection_id,
-				token_id,
-				RmrkProperty::ThemeName,
-			)
-			.ok()?;
-
-			if name == theme_name {
-				Some((name, token_id))
-			} else {
-				None
-			}
-		});
-
-	let (name, theme_id) = match theme_info {
-		Some((name, theme_id)) => (name, theme_id),
-		None => return Ok(None),
-	};
-
-	let properties = <PalletCore<T>>::filter_user_properties(
-		collection_id,
-		Some(theme_id),
-		filter_keys,
-		|key, value| RmrkThemeProperty { key, value },
-	)?;
-
-	let inherit = <PalletCore<T>>::get_nft_property_decoded(
-		collection_id,
-		theme_id,
-		RmrkProperty::ThemeInherit,
-	)?;
-
-	let theme = RmrkTheme {
-		name,
-		properties,
-		inherit,
-	};
-
-	Ok(Some(theme))
-}
deletedpallets/proxy-rmrk-equip/src/weights.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/weights.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs
-
-//! Autogenerated weights for pallet_proxy_rmrk_equip
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
-//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
-
-// Executed Command:
-// target/release/unique-collator
-// benchmark
-// pallet
-// --pallet
-// pallet-proxy-rmrk-equip
-// --wasm-execution
-// compiled
-// --extrinsic
-// *
-// --template
-// .maintain/frame-weight-template.hbs
-// --steps=50
-// --repeat=80
-// --heap-pages=4096
-// --output=./pallets/proxy-rmrk-equip/src/weights.rs
-
-#![cfg_attr(rustfmt, rustfmt_skip)]
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-#![allow(clippy::unnecessary_cast)]
-
-use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
-use sp_std::marker::PhantomData;
-
-/// Weight functions needed for pallet_proxy_rmrk_equip.
-pub trait WeightInfo {
-	fn create_base(b: u32, ) -> Weight;
-	fn theme_add(b: u32, ) -> Weight;
-	fn equippable() -> Weight;
-}
-
-/// Weights for pallet_proxy_rmrk_equip using the Substrate node and recommended hardware.
-pub struct SubstrateWeight<T>(PhantomData<T>);
-impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
-	// Storage: Common CreatedCollectionCount (r:1 w:1)
-	// Storage: Common DestroyedCollectionCount (r:1 w:0)
-	// Storage: System Account (r:2 w:2)
-	// Storage: Common CollectionPropertyPermissions (r:0 w:1)
-	// Storage: Common CollectionProperties (r:0 w:1)
-	// Storage: Common CollectionById (r:0 w:1)
-	// Storage: RmrkEquip InernalPartId (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	fn create_base(b: u32, ) -> Weight {
-		Weight::from_ref_time(58_417_000)
-			// Standard Error: 27_000
-			.saturating_add(Weight::from_ref_time(20_439_000).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(6 as u64))
-			.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(b as u64)))
-			.saturating_add(T::DbWeight::get().writes(8 as u64))
-			.saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: RmrkEquip BaseHasDefaultTheme (r:1 w:0)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	fn theme_add(b: u32, ) -> Weight {
-		Weight::from_ref_time(46_005_000)
-			// Standard Error: 42_000
-			.saturating_add(Weight::from_ref_time(2_922_000).saturating_mul(b as u64))
-			.saturating_add(T::DbWeight::get().reads(6 as u64))
-			.saturating_add(T::DbWeight::get().writes(5 as u64))
-	}
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: RmrkEquip InernalPartId (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	fn equippable() -> Weight {
-		Weight::from_ref_time(32_526_000)
-			.saturating_add(T::DbWeight::get().reads(4 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-}
-
-// For backwards compatibility and tests
-impl WeightInfo for () {
-	// Storage: Common CreatedCollectionCount (r:1 w:1)
-	// Storage: Common DestroyedCollectionCount (r:1 w:0)
-	// Storage: System Account (r:2 w:2)
-	// Storage: Common CollectionPropertyPermissions (r:0 w:1)
-	// Storage: Common CollectionProperties (r:0 w:1)
-	// Storage: Common CollectionById (r:0 w:1)
-	// Storage: RmrkEquip InernalPartId (r:1 w:1)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	fn create_base(b: u32, ) -> Weight {
-		Weight::from_ref_time(58_417_000)
-			// Standard Error: 27_000
-			.saturating_add(Weight::from_ref_time(20_439_000).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(6 as u64))
-			.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(b as u64)))
-			.saturating_add(RocksDbWeight::get().writes(8 as u64))
-			.saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(b as u64)))
-	}
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: RmrkEquip BaseHasDefaultTheme (r:1 w:0)
-	// Storage: Nonfungible TokensMinted (r:1 w:1)
-	// Storage: Nonfungible AccountBalance (r:1 w:1)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	// Storage: Nonfungible TokenData (r:0 w:1)
-	// Storage: Nonfungible Owned (r:0 w:1)
-	fn theme_add(b: u32, ) -> Weight {
-		Weight::from_ref_time(46_005_000)
-			// Standard Error: 42_000
-			.saturating_add(Weight::from_ref_time(2_922_000).saturating_mul(b as u64))
-			.saturating_add(RocksDbWeight::get().reads(6 as u64))
-			.saturating_add(RocksDbWeight::get().writes(5 as u64))
-	}
-	// Storage: Common CollectionProperties (r:1 w:0)
-	// Storage: Common CollectionById (r:1 w:0)
-	// Storage: RmrkEquip InernalPartId (r:1 w:0)
-	// Storage: Nonfungible TokenProperties (r:1 w:1)
-	fn equippable() -> Weight {
-		Weight::from_ref_time(32_526_000)
-			.saturating_add(RocksDbWeight::get().reads(4 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-}
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -48,8 +48,8 @@
 };
 
 use crate::{
-	AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, SelfWeightOf,
-	TokenProperties, TokensMinted, TotalSupply, weights::WeightInfo,
+	AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, 
+	TokenProperties, TokensMinted, TotalSupply, SelfWeightOf, weights::WeightInfo,
 };
 
 frontier_contract! {
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -28,6 +28,7 @@
 use pallet_common::{
 	erc::{CommonEvmHandler, PrecompileResult},
 	eth::{collection_id_to_address, CrossAddress},
+	CommonWeightInfo,
 };
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::{
@@ -39,7 +40,7 @@
 use sp_core::U256;
 use up_data_structs::TokenId;
 
-use crate::{Allowance, Balance, Config, Pallet, RefungibleHandle, TotalSupply};
+use crate::{Allowance, Balance, Config, Pallet, RefungibleHandle, TotalSupply, common::CommonWeights, SelfWeightOf, weights::WeightInfo};
 
 /// Refungible token handle contains information about token's collection and id
 ///
modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -15,7 +15,6 @@
 derivative = { workspace = true }
 frame-support = { workspace = true }
 pallet-evm = { workspace = true }
-rmrk-traits = { workspace = true }
 scale-info = { workspace = true }
 serde = { workspace = true, optional = true }
 sp-core = { workspace = true }
@@ -33,7 +32,6 @@
 	"codec/std",
 	"frame-support/std",
 	"pallet-evm/std",
-	"rmrk-traits/std",
 	"serde/std",
 	"serde1",
 	"sp-core/std",
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -27,33 +27,18 @@
 use frame_support::{
 	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},
 	traits::Get,
-	parameter_types,
 };
 
 #[cfg(feature = "serde")]
 use serde::{Serialize, Deserialize};
 
 use sp_core::U256;
-use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};
+use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};
 use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
 use bondrewd::Bitfields;
 use frame_support::{BoundedVec, traits::ConstU32};
 use derivative::Derivative;
 use scale_info::TypeInfo;
-
-// RMRK
-use rmrk_traits::{
-	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,
-	ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,
-};
-pub use rmrk_traits::{
-	primitives::{
-		CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,
-		SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,
-	},
-	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
-	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,
-};
 
 mod bondrewd_codec;
 mod bounded;
@@ -174,6 +159,12 @@
 impl EncodeLike<u32> for CollectionId {}
 impl EncodeLike<CollectionId> for u32 {}
 
+impl From<u32> for CollectionId {
+	fn from(value: u32) -> Self {
+		Self(value)
+	}
+}
+
 /// Token id.
 #[derive(
 	Encode,
@@ -1367,73 +1358,3 @@
 		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)
 	}
 }
-
-// RMRK
-// todo document?
-parameter_types! {
-	#[derive(PartialEq, TypeInfo)]
-	pub const RmrkStringLimit: u32 = 128;
-	#[derive(PartialEq)]
-	pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;
-	#[derive(PartialEq)]
-	pub const RmrkResourceSymbolLimit: u32 = 10;
-	#[derive(PartialEq)]
-	pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;
-	#[derive(PartialEq)]
-	pub const RmrkKeyLimit: u32 = 32;
-	#[derive(PartialEq)]
-	pub const RmrkValueLimit: u32 = 256;
-	#[derive(PartialEq)]
-	pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;
-	#[derive(PartialEq)]
-	pub const MaxPropertiesPerTheme: u32 = 5;
-	#[derive(PartialEq)]
-	pub const RmrkPartsLimit: u32 = 25;
-	#[derive(PartialEq)]
-	pub const RmrkMaxPriorities: u32 = 25;
-	#[derive(PartialEq)]
-	pub const MaxResourcesOnMint: u32 = 100;
-}
-
-impl From<RmrkCollectionId> for CollectionId {
-	fn from(id: RmrkCollectionId) -> Self {
-		Self(id)
-	}
-}
-
-impl From<RmrkNftId> for TokenId {
-	fn from(id: RmrkNftId) -> Self {
-		Self(id)
-	}
-}
-
-pub type RmrkCollectionInfo<AccountId> =
-	CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;
-pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
-pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;
-pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
-pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
-pub type BoundedEquippableCollectionIds =
-	BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;
-pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;
-pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;
-pub type RmrkThemeProperty = ThemeProperty<RmrkString>;
-pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
-pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;
-pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;
-
-pub type RmrkBasicResource = BasicResource<RmrkString>;
-pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;
-pub type RmrkSlotResource = SlotResource<RmrkString>;
-
-pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;
-pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
-pub type RmrkBaseSymbol = BoundedVec<u8, RmrkBaseSymbolLimit>;
-pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
-pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
-pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;
-pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed
-
-pub type RmrkRpcString = Vec<u8>;
-pub type RmrkThemeName = RmrkRpcString;
-pub type RmrkPropertyKey = RmrkRpcString;
deletedprimitives/rmrk-rpc/CHANGELOG.mddiffbeforeafterboth
--- a/primitives/rmrk-rpc/CHANGELOG.md
+++ /dev/null
@@ -1,10 +0,0 @@
-<!-- bureaucrate goes here -->
-## [v0.0.2] 2022-08-16
-
-### Other changes
-
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
-
-- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
-
-- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
\ No newline at end of file
deletedprimitives/rmrk-rpc/Cargo.tomldiffbeforeafterboth
--- a/primitives/rmrk-rpc/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-edition = "2021"
-license = ""
-name = "rmrk-rpc"
-version = "0.0.2"
-
-[dependencies]
-codec = { workspace = true }
-rmrk-traits = { workspace = true }
-sp-api = { workspace = true }
-sp-runtime = { workspace = true }
-sp-std = { workspace = true }
-
-[features]
-default = ["std"]
-std = ["codec/std", "rmrk-traits/std", "sp-api/std", "sp-runtime/std", "sp-std/std"]
deletedprimitives/rmrk-rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rmrk-rpc/src/lib.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use sp_api::{Encode, Decode};
-use sp_std::vec::Vec;
-use sp_runtime::DispatchError;
-use rmrk_traits::{primitives::*, NftChild};
-
-pub type Result<T> = core::result::Result<T, DispatchError>;
-
-pub type RpcString = Vec<u8>;
-
-pub type PropertyKey = RpcString;
-
-pub type ThemeName = RpcString;
-
-sp_api::decl_runtime_apis! {
-	pub trait RmrkApi<
-		AccountId,
-		CollectionInfo,
-		NftInfo,
-		ResourceInfo,
-		PropertyInfo,
-		BaseInfo,
-		PartType,
-		Theme
-	>
-	where
-		AccountId: Encode,
-		CollectionInfo: Decode,
-		NftInfo: Decode,
-		ResourceInfo: Decode,
-		PropertyInfo: Decode,
-		BaseInfo: Decode,
-		PartType: Decode,
-		Theme: Decode,
-	{
-		fn last_collection_idx() -> Result<CollectionId>;
-
-		fn collection_by_id(id: CollectionId) -> Result<Option<CollectionInfo>>;
-
-		fn nft_by_id(collection_id: CollectionId, nft_id: NftId) -> Result<Option<NftInfo>>;
-
-		fn account_tokens(account_id: AccountId, collection_id: CollectionId) -> Result<Vec<NftId>>;
-
-		fn nft_children(collection_id: CollectionId, nft_id: NftId) -> Result<Vec<NftChild>>;
-
-		fn collection_properties(collection_id: CollectionId, filter_keys: Option<Vec<PropertyKey>>) -> Result<Vec<PropertyInfo>>;
-
-		fn nft_properties(collection_id: CollectionId, nft_id: NftId, filter_keys: Option<Vec<PropertyKey>>) -> Result<Vec<PropertyInfo>>;
-
-		fn nft_resources(collection_id: CollectionId, nft_id: NftId) -> Result<Vec<ResourceInfo>>;
-
-		fn nft_resource_priority(collection_id: CollectionId, nft_id: NftId, resource_id: ResourceId) -> Result<Option<u32>>;
-
-		fn base(base_id: BaseId) -> Result<Option<BaseInfo>>;
-
-		fn base_parts(base_id: BaseId) -> Result<Vec<PartType>>;
-
-		fn theme_names(base_id: BaseId) -> Result<Vec<ThemeName>>;
-
-		fn theme(base_id: BaseId, theme_name: ThemeName, filter_keys: Option<Vec<PropertyKey>>) -> Result<Option<Theme>>;
-	}
-}
deletedprimitives/rmrk-traits/Cargo.tomldiffbeforeafterboth
--- a/primitives/rmrk-traits/Cargo.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[package]
-authors = ["RMRK Team", "Unique Network <support@uniquenetwork.io>"]
-description = "RMRK proxy data structs definitions"
-edition = "2021"
-homepage = "https://unique.network"
-license = 'GPLv3'
-name = "rmrk-traits"
-repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = "0.1.0"
-
-[dependencies]
-# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
-codec = { workspace = true, package = "parity-scale-codec" }
-
-scale-info = { workspace = true }
-serde = { workspace = true, optional = true }
-
-[features]
-default = ["std"]
-serde1 = ["serde/alloc"]
-std = ["codec/std", "serde/std", "serde1"]
deletedprimitives/rmrk-traits/src/base.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/base.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			AccountId: Serialize,
-			BoundedString: AsRef<[u8]>
-		"#)
-)]
-pub struct BaseInfo<AccountId, BoundedString> {
-	/// Original creator of the Base
-	pub issuer: AccountId,
-
-	/// Specifies how an NFT should be rendered, ie "svg"
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub base_type: BoundedString,
-
-	/// User provided symbol during Base creation
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub symbol: BoundedString,
-}
deletedprimitives/rmrk-traits/src/collection.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/collection.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			AccountId: Serialize,
-			BoundedString: AsRef<[u8]>,
-			BoundedSymbol: AsRef<[u8]>
-		"#)
-)]
-pub struct CollectionInfo<BoundedString, BoundedSymbol, AccountId> {
-	/// Current bidder and bid price.
-	pub issuer: AccountId,
-
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub metadata: BoundedString,
-	pub max: Option<u32>,
-
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub symbol: BoundedSymbol,
-	pub nfts_count: u32,
-}
deletedprimitives/rmrk-traits/src/lib.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/lib.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-pub mod base;
-pub mod collection;
-pub mod nft;
-pub mod part;
-pub mod property;
-pub mod resource;
-pub mod theme;
-
-#[cfg(feature = "std")]
-mod serialize;
-
-pub use base::BaseInfo;
-pub use part::{EquippableList, FixedPart, PartType, SlotPart};
-pub use theme::{Theme, ThemeProperty};
-pub use collection::CollectionInfo;
-pub use nft::{AccountIdOrCollectionNftTuple, NftInfo, RoyaltyInfo, NftChild};
-pub use property::PropertyInfo;
-pub use resource::{BasicResource, ComposableResource, ResourceInfo, ResourceTypes, SlotResource};
-pub mod primitives {
-	pub type CollectionId = u32;
-	pub type ResourceId = u32;
-	pub type NftId = u32;
-	pub type BaseId = u32;
-	pub type SlotId = u32;
-	pub type PartId = u32;
-	pub type ZIndex = u32;
-}
deletedprimitives/rmrk-traits/src/nft.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/nft.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-use crate::primitives::*;
-
-#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-pub enum AccountIdOrCollectionNftTuple<AccountId> {
-	AccountId(AccountId),
-	CollectionAndNftTuple(CollectionId, NftId),
-}
-
-/// Royalty information (recipient and amount)
-#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-pub struct RoyaltyInfo<AccountId, RoyaltyAmount> {
-	/// Recipient (AccountId) of the royalty
-	pub recipient: AccountId,
-	/// Amount (Permill) of the royalty
-	pub amount: RoyaltyAmount,
-}
-
-/// Nft info.
-#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			AccountId: Serialize,
-			RoyaltyAmount: Serialize,
-			BoundedString: AsRef<[u8]>
-		"#)
-)]
-pub struct NftInfo<AccountId, RoyaltyAmount, BoundedString> {
-	/// The owner of the NFT, can be either an Account or a tuple (CollectionId, NftId)
-	pub owner: AccountIdOrCollectionNftTuple<AccountId>,
-	/// Royalty (optional)
-	pub royalty: Option<RoyaltyInfo<AccountId, RoyaltyAmount>>,
-
-	/// Arbitrary data about an instance, e.g. IPFS hash
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub metadata: BoundedString,
-
-	/// Equipped state
-	pub equipped: bool,
-	/// Pending state (if sent to NFT)
-	pub pending: bool,
-}
-
-#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))]
-#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
-pub struct NftChild {
-	pub collection_id: CollectionId,
-	pub nft_id: NftId,
-}
deletedprimitives/rmrk-traits/src/part.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/part.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-use crate::primitives::*;
-
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
-#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
-pub struct FixedPart<BoundedString> {
-	pub id: PartId,
-	pub z: ZIndex,
-
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub src: BoundedString,
-}
-
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>")
-)]
-pub enum EquippableList<BoundedCollectionList> {
-	All,
-	Empty,
-	Custom(#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] BoundedCollectionList),
-}
-
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			BoundedCollectionList: AsRef<[CollectionId]>
-		"#)
-)]
-pub struct SlotPart<BoundedString, BoundedCollectionList> {
-	pub id: PartId,
-	pub equippable: EquippableList<BoundedCollectionList>,
-
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub src: BoundedString,
-
-	pub z: ZIndex,
-}
-
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			BoundedCollectionList: AsRef<[CollectionId]>
-		"#)
-)]
-pub enum PartType<BoundedString, BoundedCollectionList> {
-	FixedPart(FixedPart<BoundedString>),
-	SlotPart(SlotPart<BoundedString, BoundedCollectionList>),
-}
-
-impl<BoundedString, BoundedCollectionList> PartType<BoundedString, BoundedCollectionList> {
-	pub fn id(&self) -> PartId {
-		match self {
-			Self::FixedPart(part) => part.id,
-			Self::SlotPart(part) => part.id,
-		}
-	}
-
-	pub fn src(&self) -> &BoundedString {
-		match self {
-			Self::FixedPart(part) => &part.src,
-			Self::SlotPart(part) => &part.src,
-		}
-	}
-
-	pub fn z_index(&self) -> ZIndex {
-		match self {
-			Self::FixedPart(part) => part.z,
-			Self::SlotPart(part) => part.z,
-		}
-	}
-}
deletedprimitives/rmrk-traits/src/property.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/property.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[derive(Encode, Decode, PartialEq, TypeInfo)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedKey: AsRef<[u8]>,
-			BoundedValue: AsRef<[u8]>
-		"#)
-)]
-pub struct PropertyInfo<BoundedKey, BoundedValue> {
-	/// Key of the property
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub key: BoundedKey,
-
-	/// Value of the property
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub value: BoundedValue,
-}
deletedprimitives/rmrk-traits/src/resource.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/resource.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode, MaxEncodedLen};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-use crate::primitives::*;
-
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
-pub struct BasicResource<BoundedString> {
-	/// If the resource is Media, the base property is absent. Media src should be a URI like an
-	/// IPFS hash.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub src: Option<BoundedString>,
-
-	/// Reference to IPFS location of metadata
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub metadata: Option<BoundedString>,
-
-	/// Optional location or identier of license
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub license: Option<BoundedString>,
-
-	/// If the resource has the thumb property, this will be a URI to a thumbnail of the given
-	/// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is
-	/// complex and too detailed to show in a search-results page or a list. Also, if a bird owns
-	/// another bird, showing the full render of one bird inside the other's inventory might be a
-	/// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an
-	/// image that is lighter and faster to load but representative of this resource.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub thumb: Option<BoundedString>,
-}
-
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			BoundedParts: AsRef<[PartId]>
-		"#)
-)]
-pub struct ComposableResource<BoundedString, BoundedParts> {
-	/// If a resource is composed, it will have an array of parts that compose it
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub parts: BoundedParts,
-
-	/// A Base is uniquely identified by the combination of the word `base`, its minting block
-	/// number, and user provided symbol during Base creation, glued by dashes `-`, e.g.
-	/// base-4477293-kanaria_superbird.
-	pub base: BaseId,
-
-	/// If the resource is Media, the base property is absent. Media src should be a URI like an
-	/// IPFS hash.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub src: Option<BoundedString>,
-
-	/// Reference to IPFS location of metadata
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub metadata: Option<BoundedString>,
-
-	/// If the resource has the slot property, it was designed to fit into a specific Base's slot.
-	/// The baseslot will be composed of two dot-delimited values, like so:
-	/// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is
-	/// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird
-
-	/// Optional location or identier of license
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub license: Option<BoundedString>,
-
-	/// If the resource has the thumb property, this will be a URI to a thumbnail of the given
-	/// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is
-	/// complex and too detailed to show in a search-results page or a list. Also, if a bird owns
-	/// another bird, showing the full render of one bird inside the other's inventory might be a
-	/// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an
-	/// image that is lighter and faster to load but representative of this resource.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub thumb: Option<BoundedString>,
-}
-
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
-pub struct SlotResource<BoundedString> {
-	/// A Base is uniquely identified by the combination of the word `base`, its minting block
-	/// number, and user provided symbol during Base creation, glued by dashes `-`, e.g.
-	/// base-4477293-kanaria_superbird.
-	pub base: BaseId,
-
-	/// If the resource is Media, the base property is absent. Media src should be a URI like an
-	/// IPFS hash.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub src: Option<BoundedString>,
-
-	/// Reference to IPFS location of metadata
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub metadata: Option<BoundedString>,
-
-	/// If the resource has the slot property, it was designed to fit into a specific Base's slot.
-	/// The baseslot will be composed of two dot-delimited values, like so:
-	/// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is
-	/// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird
-	pub slot: SlotId,
-
-	/// The license field, if present, should contain a link to a license (IPFS or static HTTP
-	/// url), or an identifier, like RMRK_nocopy or ipfs://ipfs/someHashOfLicense.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub license: Option<BoundedString>,
-
-	/// If the resource has the thumb property, this will be a URI to a thumbnail of the given
-	/// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is
-	/// complex and too detailed to show in a search-results page or a list. Also, if a bird owns
-	/// another bird, showing the full render of one bird inside the other's inventory might be a
-	/// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an
-	/// image that is lighter and faster to load but representative of this resource.
-	#[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))]
-	pub thumb: Option<BoundedString>,
-}
-
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			BoundedParts: AsRef<[PartId]>
-		"#)
-)]
-pub enum ResourceTypes<BoundedString, BoundedParts> {
-	Basic(BasicResource<BoundedString>),
-	Composable(ComposableResource<BoundedString, BoundedParts>),
-	Slot(SlotResource<BoundedString>),
-}
-
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize))]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			BoundedParts: AsRef<[PartId]>
-		"#)
-)]
-pub struct ResourceInfo<BoundedString, BoundedParts> {
-	/// ID is a unique identifier for a resource across all those of a single NFT.
-	/// The combination of a collection ID, an NFT ID, and the resource ID must be
-	/// unique across the entire RMRK ecosystem.
-	//#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub id: ResourceId,
-
-	/// Resource type and the accordingly structured data stored
-	pub resource: ResourceTypes<BoundedString, BoundedParts>,
-
-	/// If resource is sent to non-rootowned NFT, pending will be false and need to be accepted
-	pub pending: bool,
-
-	/// If resource removal request is sent by non-rootowned NFT, pending will be true and need to be accepted
-	pub pending_removal: bool,
-}
deletedprimitives/rmrk-traits/src/serialize.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/serialize.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use core::convert::AsRef;
-use serde::ser::{self, Serialize};
-
-pub mod vec {
-	use super::*;
-
-	pub fn serialize<D, V, C>(value: &C, serializer: D) -> Result<D::Ok, D::Error>
-	where
-		D: ser::Serializer,
-		V: Serialize,
-		C: AsRef<[V]>,
-	{
-		value.as_ref().serialize(serializer)
-	}
-}
-
-pub mod opt_vec {
-	use super::*;
-
-	pub fn serialize<D, V, C>(value: &Option<C>, serializer: D) -> Result<D::Ok, D::Error>
-	where
-		D: ser::Serializer,
-		V: Serialize,
-		C: AsRef<[V]>,
-	{
-		match value {
-			Some(value) => super::vec::serialize(value, serializer),
-			None => serializer.serialize_none(),
-		}
-	}
-}
deletedprimitives/rmrk-traits/src/theme.rsdiffbeforeafterboth
--- a/primitives/rmrk-traits/src/theme.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2021-2022 RMRK
-// This file is part of rmrk-substrate.
-// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE
-
-use codec::{Decode, Encode};
-use scale_info::TypeInfo;
-
-#[cfg(feature = "std")]
-use serde::Serialize;
-
-#[cfg(feature = "std")]
-use crate::serialize;
-
-#[cfg_attr(feature = "std", derive(Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)]
-#[cfg_attr(
-	feature = "std",
-	serde(bound = r#"
-			BoundedString: AsRef<[u8]>,
-			PropertyList: AsRef<[ThemeProperty<BoundedString>]>,
-		"#)
-)]
-pub struct Theme<BoundedString, PropertyList> {
-	/// Name of the theme
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub name: BoundedString,
-
-	/// Theme properties
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub properties: PropertyList,
-	/// Inheritability
-	pub inherit: bool,
-}
-
-#[cfg_attr(feature = "std", derive(Eq, Serialize))]
-#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)]
-#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))]
-pub struct ThemeProperty<BoundedString> {
-	/// Key of the property
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub key: BoundedString,
-
-	/// Value of the property
-	#[cfg_attr(feature = "std", serde(with = "serialize::vec"))]
-	pub value: BoundedString,
-}
modifiedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/mod.rs
+++ b/runtime/common/config/pallets/mod.rs
@@ -35,9 +35,6 @@
 };
 use sp_arithmetic::Perbill;
 
-#[cfg(feature = "rmrk")]
-pub mod rmrk;
-
 #[cfg(feature = "scheduler")]
 pub mod scheduler;
 
deletedruntime/common/config/pallets/rmrk.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/rmrk.rs
+++ /dev/null
@@ -1,27 +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::{Runtime, RuntimeEvent};
-
-impl pallet_proxy_rmrk_core::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;
-	type RuntimeEvent = RuntimeEvent;
-}
-
-impl pallet_proxy_rmrk_equip::Config for Runtime {
-	type WeightInfo = pallet_proxy_rmrk_equip::weights::SubstrateWeight<Self>;
-	type RuntimeEvent = RuntimeEvent;
-}
modifiedruntime/common/construct_runtime.rsdiffbeforeafterboth
--- a/runtime/common/construct_runtime.rs
+++ b/runtime/common/construct_runtime.rs
@@ -82,11 +82,9 @@
                 Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,
                 Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,
 
-                #[cfg(feature = "rmrk")]
-                RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
+                // RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,
 
-                #[cfg(feature = "rmrk")]
-                RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
+                // RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,
 
                 #[cfg(feature = "app-promotion")]
                 AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event<T>} = 73,
modifiedruntime/common/maintenance.rsdiffbeforeafterboth
--- a/runtime/common/maintenance.rs
+++ b/runtime/common/maintenance.rs
@@ -70,11 +70,6 @@
 				#[cfg(feature = "scheduler")]
 				RuntimeCall::Scheduler(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
 
-				#[cfg(feature = "rmrk")]
-				RuntimeCall::RmrkCore(_) | RuntimeCall::RmrkEquip(_) => {
-					Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
-				}
-
 				#[cfg(feature = "app-promotion")]
 				RuntimeCall::AppPromotion(_) => {
 					Err(TransactionValidityError::Invalid(InvalidTransaction::Call))
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -231,149 +231,6 @@
                 }
             }
 
-            impl rmrk_rpc::RmrkApi<
-                Block,
-                AccountId,
-                RmrkCollectionInfo<AccountId>,
-                RmrkInstanceInfo<AccountId>,
-                RmrkResourceInfo,
-                RmrkPropertyInfo,
-                RmrkBaseInfo<AccountId>,
-                RmrkPartType,
-                RmrkTheme
-            > for Runtime {
-                fn last_collection_idx() -> Result<RmrkCollectionId, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::last_collection_idx::<Runtime>();
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::collection_by_id::<Runtime>(collection_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::nft_by_id::<Runtime>(collection_id, nft_by_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::account_tokens::<Runtime>(account_id, collection_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkNftChild>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::nft_children::<Runtime>(collection_id, nft_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn collection_properties(
-                    collection_id: RmrkCollectionId,
-                    filter_keys: Option<Vec<RmrkPropertyKey>>
-                ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::collection_properties::<Runtime>(collection_id, filter_keys);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn nft_properties(
-                    collection_id: RmrkCollectionId,
-                    nft_id: RmrkNftId,
-                    filter_keys: Option<Vec<RmrkPropertyKey>>
-                ) -> Result<Vec<RmrkPropertyInfo>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::nft_properties::<Runtime>(collection_id, nft_id, filter_keys);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn nft_resources(collection_id: RmrkCollectionId,nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::nft_resources::<Runtime>(collection_id, nft_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn nft_resource_priority(
-                    collection_id: RmrkCollectionId,
-                    nft_id: RmrkNftId,
-                    resource_id: RmrkResourceId
-                ) -> Result<Option<u32>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_core::rpc::nft_resource_priority::<Runtime>(collection_id, nft_id, resource_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_equip::rpc::base::<Runtime>(base_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_equip::rpc::base_parts::<Runtime>(base_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_equip::rpc::theme_names::<Runtime>(base_id);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-
-                #[allow(unused_variables)]
-                fn theme(
-                    base_id: RmrkBaseId,
-                    theme_name: RmrkThemeName,
-                    filter_keys: Option<Vec<RmrkPropertyKey>>
-                ) -> Result<Option<RmrkTheme>, DispatchError> {
-                    #[cfg(feature = "rmrk")]
-                    return pallet_proxy_rmrk_equip::rpc::theme::<Runtime>(base_id, theme_name, filter_keys);
-
-                    #[cfg(not(feature = "rmrk"))]
-                    return unsupported!();
-                }
-            }
-
             impl sp_api::Core<Block> for Runtime {
                 fn version() -> RuntimeVersion {
                     VERSION
@@ -701,13 +558,7 @@
 
                     #[cfg(feature = "scheduler")]
                     list_benchmark!(list, extra, pallet_unique_scheduler_v2, Scheduler);
-
-                    #[cfg(feature = "rmrk")]
-                    list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);
 
-                    #[cfg(feature = "rmrk")]
-                    list_benchmark!(list, extra, pallet_proxy_rmrk_equip, RmrkEquip);
-
                     #[cfg(feature = "collator-selection")]
                     list_benchmark!(list, extra, pallet_collator_selection, CollatorSelection);
 
@@ -771,12 +622,6 @@
 
                     #[cfg(feature = "scheduler")]
                     add_benchmark!(params, batches, pallet_unique_scheduler_v2, Scheduler);
-
-                    #[cfg(feature = "rmrk")]
-                    add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);
-
-                    #[cfg(feature = "rmrk")]
-                    add_benchmark!(params, batches, pallet_proxy_rmrk_equip, RmrkEquip);
 
                     #[cfg(feature = "collator-selection")]
                     add_benchmark!(params, batches, pallet_collator_selection, CollatorSelection);
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -41,8 +41,6 @@
 	'pallet-inflation/runtime-benchmarks',
 	'pallet-maintenance/runtime-benchmarks',
 	'pallet-nonfungible/runtime-benchmarks',
-	'pallet-proxy-rmrk-core/runtime-benchmarks',
-	'pallet-proxy-rmrk-equip/runtime-benchmarks',
 	'pallet-refungible/runtime-benchmarks',
 	'pallet-structure/runtime-benchmarks',
 	'pallet-timestamp/runtime-benchmarks',
@@ -95,8 +93,6 @@
 	'pallet-identity/std',
 	'pallet-inflation/std',
 	'pallet-nonfungible/std',
-	'pallet-proxy-rmrk-core/std',
-	'pallet-proxy-rmrk-equip/std',
 	'pallet-randomness-collective-flip/std',
 	'pallet-refungible/std',
 	'pallet-structure/std',
@@ -108,7 +104,6 @@
 	'pallet-unique-scheduler-v2/std',
 	'pallet-unique/std',
 	'parachain-info/std',
-	'rmrk-rpc/std',
 	'serde',
 	'sp-api/std',
 	'sp-block-builder/std',
@@ -176,8 +171,6 @@
 	'pallet-inflation/try-runtime',
 	'pallet-maintenance/try-runtime',
 	'pallet-nonfungible/try-runtime',
-	'pallet-proxy-rmrk-core/try-runtime',
-	'pallet-proxy-rmrk-equip/try-runtime',
 	'pallet-randomness-collective-flip/try-runtime',
 	'pallet-refungible/try-runtime',
 	'pallet-structure/try-runtime',
@@ -197,7 +190,6 @@
 foreign-assets = []
 pallet-test-utils = []
 refungible = []
-rmrk = []
 scheduler = []
 
 ################################################################################
@@ -282,14 +274,11 @@
 pallet-inflation = { workspace = true }
 pallet-maintenance = { workspace = true }
 pallet-nonfungible = { workspace = true }
-pallet-proxy-rmrk-core = { workspace = true }
-pallet-proxy-rmrk-equip = { workspace = true }
 pallet-refungible = { workspace = true }
 pallet-structure = { workspace = true }
 pallet-unique = { workspace = true }
 pallet-unique-scheduler-v2 = { workspace = true }
 precompile-utils-macro = { workspace = true }
-rmrk-rpc = { workspace = true }
 scale-info = { workspace = true }
 up-common = { workspace = true }
 up-data-structs = { workspace = true }
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -42,8 +42,6 @@
 	'pallet-inflation/runtime-benchmarks',
 	'pallet-maintenance/runtime-benchmarks',
 	'pallet-nonfungible/runtime-benchmarks',
-	'pallet-proxy-rmrk-core/runtime-benchmarks',
-	'pallet-proxy-rmrk-equip/runtime-benchmarks',
 	'pallet-refungible/runtime-benchmarks',
 	'pallet-structure/runtime-benchmarks',
 	'pallet-timestamp/runtime-benchmarks',
@@ -95,8 +93,6 @@
 	'pallet-fungible/std',
 	'pallet-inflation/std',
 	'pallet-nonfungible/std',
-	'pallet-proxy-rmrk-core/std',
-	'pallet-proxy-rmrk-equip/std',
 	'pallet-randomness-collective-flip/std',
 	'pallet-refungible/std',
 	'pallet-structure/std',
@@ -107,7 +103,6 @@
 	'pallet-treasury/std',
 	'pallet-unique/std',
 	'parachain-info/std',
-	'rmrk-rpc/std',
 	'serde',
 	'sp-api/std',
 	'sp-block-builder/std',
@@ -171,8 +166,6 @@
 	'pallet-inflation/try-runtime',
 	'pallet-maintenance/try-runtime',
 	'pallet-nonfungible/try-runtime',
-	'pallet-proxy-rmrk-core/try-runtime',
-	'pallet-proxy-rmrk-equip/try-runtime',
 	'pallet-randomness-collective-flip/try-runtime',
 	'pallet-refungible/try-runtime',
 	'pallet-structure/try-runtime',
@@ -189,7 +182,6 @@
 collator-selection = []
 foreign-assets = []
 refungible = []
-rmrk = []
 scheduler = []
 
 ################################################################################
@@ -228,7 +220,6 @@
 pallet-xcm = { workspace = true }
 parachain-info = { workspace = true }
 polkadot-parachain = { workspace = true }
-rmrk-rpc = { workspace = true }
 smallvec = { workspace = true }
 sp-api = { workspace = true }
 sp-arithmetic = { workspace = true }
@@ -260,8 +251,6 @@
 pallet-identity = { workspace = true }
 pallet-inflation = { workspace = true }
 pallet-nonfungible = { workspace = true }
-pallet-proxy-rmrk-core = { workspace = true }
-pallet-proxy-rmrk-equip = { workspace = true }
 pallet-refungible = { workspace = true }
 pallet-structure = { workspace = true }
 pallet-unique = { workspace = true }
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -39,8 +39,6 @@
 	'pallet-inflation/runtime-benchmarks',
 	'pallet-maintenance/runtime-benchmarks',
 	'pallet-nonfungible/runtime-benchmarks',
-	'pallet-proxy-rmrk-core/runtime-benchmarks',
-	'pallet-proxy-rmrk-equip/runtime-benchmarks',
 	'pallet-refungible/runtime-benchmarks',
 	'pallet-structure/runtime-benchmarks',
 	'pallet-timestamp/runtime-benchmarks',
@@ -93,8 +91,6 @@
 	'pallet-fungible/std',
 	'pallet-inflation/std',
 	'pallet-nonfungible/std',
-	'pallet-proxy-rmrk-core/std',
-	'pallet-proxy-rmrk-equip/std',
 	'pallet-randomness-collective-flip/std',
 	'pallet-refungible/std',
 	'pallet-structure/std',
@@ -105,7 +101,6 @@
 	'pallet-treasury/std',
 	'pallet-unique/std',
 	'parachain-info/std',
-	'rmrk-rpc/std',
 	'sp-api/std',
 	'sp-block-builder/std',
 	'sp-core/std',
@@ -169,8 +164,6 @@
 	'pallet-inflation/try-runtime',
 	'pallet-maintenance/try-runtime',
 	'pallet-nonfungible/try-runtime',
-	'pallet-proxy-rmrk-core/try-runtime',
-	'pallet-proxy-rmrk-equip/try-runtime',
 	'pallet-randomness-collective-flip/try-runtime',
 	'pallet-refungible/try-runtime',
 	'pallet-structure/try-runtime',
@@ -187,7 +180,6 @@
 collator-selection = []
 foreign-assets = []
 refungible = []
-rmrk = []
 scheduler = []
 
 ################################################################################
@@ -255,12 +247,9 @@
 pallet-identity = { workspace = true }
 pallet-inflation = { workspace = true }
 pallet-nonfungible = { workspace = true }
-pallet-proxy-rmrk-core = { workspace = true }
-pallet-proxy-rmrk-equip = { workspace = true }
 pallet-refungible = { workspace = true }
 pallet-structure = { workspace = true }
 pallet-unique = { workspace = true }
-rmrk-rpc = { workspace = true }
 scale-info = { workspace = true }
 up-common = { workspace = true }
 up-data-structs = { workspace = true }
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -43,7 +43,6 @@
     "testEthFractionalizer": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/fractionalizer/**/*.*test.ts'",
     "testEthMarketplace": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.*test.ts'",
     "testEvent": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.*test.ts",
-    "testRmrk": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./**/rmrk/*.*test.ts",
     "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'",
     "testEvmCoder": "mocha --timeout 9999999 -r ts-node/register './**/eth/evmCoder.test.ts'",
     "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",
deletedtests/src/.outdated/rmrk/acceptNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/acceptNft.seqtest.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {
-  createCollection,
-  mintNft,
-  sendNft,
-  acceptNft,
-} from './util/tx';
-import {NftIdTuple} from './util/fetch';
-import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers';
-
-describe('integration test: accept NFT', () => {
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-  
-  
-  const alice = '//Alice';
-  const bob = '//Bob';
-  
-  const createTestCollection = async (issuerUri: string) => {
-    return await createCollection(
-      api,
-      issuerUri,
-      'accept-metadata',
-      null,
-      'acpt',
-    );
-  };
-
-  it('accept NFT', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT);
-    await acceptNft(api, alice, bobCollectionId, childNftId, newOwnerNFT);
-
-    const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.true;
-  });
-
-  it('[negative] unable to accept NFT by a not-an-owner', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT);
-    const tx = acceptNft(api, bob, bobCollectionId, childNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative] unable to accept non-existing NFT', async () => {
-    const collectionId = 0;
-    const maxNftId = 0xFFFFFFFF;
-
-    const owner = alice;
-    const aliceCollectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, owner, aliceCollectionId, 'parent-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    const tx = acceptNft(api, alice, collectionId, maxNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] unable to accept NFT which is not sent', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    const tx = acceptNft(api, alice, bobCollectionId, childNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-
-    const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.false;
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/addResource.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/addResource.seqtest.ts
+++ /dev/null
@@ -1,435 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {NftIdTuple} from './util/fetch';
-import {expectTxFailure, getResourceById, requirePallets, Pallets} from './util/helpers';
-import {
-  addNftBasicResource,
-  acceptNftResource,
-  createCollection,
-  mintNft,
-  sendNft,
-  addNftSlotResource,
-  addNftComposableResource,
-} from './util/tx';
-import {RmrkTraitsResourceResourceInfo as ResourceInfo} from '@polkadot/types/lookup';
-
-describe('integration test: add NFT resource', () => {
-  const alice = '//Alice';
-  const bob = '//Bob';
-  const src = 'test-res-src';
-  const metadata = 'test-res-metadata';
-  const license = 'test-res-license';
-  const thumb = 'test-res-thumb';
-
-  const nonexistentId = 99999;
-
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  it('add resource', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-  });
-
-  it('add a resource to the nested NFT', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT);
-
-    await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      childNftId,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-  });
-
-  it('add multiple resources', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const baseId = 42;
-    const slotId = 10;
-    const parts = [0, 5, 2];
-
-    const resourcesInfo = [];
-    const resourceNum = 4;
-
-    const checkResource = (resource: ResourceInfo, resType: string, expectedId: number, expected: {
-      src: string,
-      metadata: string,
-      license: string,
-      thumb: string
-    }) => {
-
-      // FIXME A workaround. It seems it is a PolkadotJS bug.
-      // All of the following are `false`.
-      //
-      // console.log('>>> basic:', resource.resource.isBasic);
-      // console.log('>>> composable:', resource.resource.isComposable);
-      // console.log('>>> slot:', resource.resource.isSlot);
-      const resourceJson = (resource.resource.toHuman() as any)[resType];
-
-      expect(resource.id.toNumber(), 'Error: Invalid resource Id')
-        .to.be.eq(expectedId);
-
-      expect(resourceJson.src, 'Error: Invalid resource src')
-        .to.be.eq(expected.src);
-      expect(resourceJson.metadata, 'Error: Invalid resource metadata')
-        .to.be.eq(expected.metadata);
-      expect(resourceJson.license, 'Error: Invalid resource license')
-        .to.be.eq(expected.license);
-      expect(resourceJson.thumb, 'Error: Invalid resource thumb')
-        .to.be.eq(expected.thumb);
-    };
-
-    for (let i = 0; i < resourceNum; i++) {
-      resourcesInfo.push({
-        src: src + 'r-' + i,
-        metadata: metadata + 'r-' + i,
-        license: license + 'r-' + i,
-        thumb: thumb + 'r-' + i,
-      });
-    }
-
-    const firstBasicResourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      resourcesInfo[0].src,
-      resourcesInfo[0].metadata,
-      resourcesInfo[0].license,
-      resourcesInfo[0].thumb,
-    );
-
-    const secondBasicResourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      resourcesInfo[1].src,
-      resourcesInfo[1].metadata,
-      resourcesInfo[1].license,
-      resourcesInfo[1].thumb,
-    );
-
-    const composableResourceId = await addNftComposableResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      parts,
-      baseId,
-      resourcesInfo[2].src,
-      resourcesInfo[2].metadata,
-      resourcesInfo[2].license,
-      resourcesInfo[2].thumb,
-    );
-
-    const slotResourceId = await addNftSlotResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      baseId,
-      slotId,
-      resourcesInfo[3].src,
-      resourcesInfo[3].metadata,
-      resourcesInfo[3].license,
-      resourcesInfo[3].thumb,
-    );
-
-    const firstResource = await getResourceById(api, collectionIdAlice, nftAlice, firstBasicResourceId);
-    await checkResource(firstResource, 'Basic', firstBasicResourceId, resourcesInfo[0]);
-
-    const secondResource = await getResourceById(api, collectionIdAlice, nftAlice, secondBasicResourceId);
-    await checkResource(secondResource, 'Basic', secondBasicResourceId, resourcesInfo[1]);
-
-    const composableResource = await getResourceById(api, collectionIdAlice, nftAlice, composableResourceId);
-    await checkResource(composableResource, 'Composable', composableResourceId, resourcesInfo[2]);
-
-    const slotResource = await getResourceById(api, collectionIdAlice, nftAlice, slotResourceId);
-    await checkResource(slotResource, 'Slot', slotResourceId, resourcesInfo[3]);
-  });
-
-  it('[negative]: unable to add a resource to the non-existing NFT', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const tx = addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nonexistentId,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-  
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative]: unable to add a resource by a not-an-owner user', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const tx = addNftBasicResource(
-      api,
-      bob,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-  
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative]: unable to add a resource to the nested NFT if it isnt root owned by the caller', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT);
-
-    const tx = addNftBasicResource(
-      api,
-      bob,
-      'added',
-      collectionIdAlice,
-      childNftId,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-    
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('accept resource', async () => {
-    const collectionIdBob = await createCollection(
-      api,
-      bob,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      bob,
-      alice,
-      collectionIdBob,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      bob,
-      'pending',
-      collectionIdBob,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    await acceptNftResource(api, alice, collectionIdBob, nftAlice, resourceId);
-  });
-
-  it('[negative]: unable to accept a non-existing resource', async () => {
-    const collectionIdBob = await createCollection(
-      api,
-      bob,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      bob,
-      alice,
-      collectionIdBob,
-      'nft-metadata',
-    );
-
-    const tx = acceptNftResource(api, alice, collectionIdBob, nftAlice, nonexistentId);
-    await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx);
-  });
-
-  it('[negative]: unable to accept a resource by a not-an-NFT-owner user', async () => {
-    const collectionIdBob = await createCollection(
-      api,
-      bob,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      bob,
-      alice,
-      collectionIdBob,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      bob,
-      'pending',
-      collectionIdBob,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = acceptNftResource(api, bob, collectionIdBob, nftAlice, resourceId);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative]: unable to accept a resource to a non-target NFT', async () => {
-    const collectionIdBob = await createCollection(
-      api,
-      bob,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      bob,
-      alice,
-      collectionIdBob,
-      'nft-metadata',
-    );
-
-    const wrongNft = await mintNft(
-      api,
-      bob,
-      alice,
-      collectionIdBob,
-      'nft-metadata',
-    );
-    
-    const resourceId = await addNftBasicResource(
-      api,
-      bob,
-      'pending',
-      collectionIdBob,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = acceptNftResource(api, bob, collectionIdBob, wrongNft, resourceId);
-
-    await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx);
-  });
-
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/addTheme.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/addTheme.seqtest.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {createBase, addTheme} from './util/tx';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {getThemeNames} from './util/fetch';
-
-describe('integration test: add Theme to Base', () => {
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkEquip]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  it('add default theme', async () => {
-    const baseId = await createBase(api, alice, 'default-themed-base', 'DTBase', []);
-    await addTheme(api, alice, baseId, {
-      name: 'default',
-      properties: [
-        {
-          key: 'some-key',
-          value: 'some-key-value',
-        },
-        {
-          key: 'another-key',
-          value: 'another-key-value',
-        },
-      ],
-    });
-  });
-
-  it('add default theme and a custom one', async () => {
-    const baseId = await createBase(api, alice, '2-themed-base', '2TBase', []);
-    await addTheme(api, alice, baseId, {
-      name: 'default',
-      properties: [
-        {
-          key: 'default-key',
-          value: 'default-key-value',
-        },
-      ],
-    });
-    await addTheme(api, alice, baseId, {
-      name: 'custom-theme',
-      properties: [
-        {
-          key: 'custom-key-0',
-          value: 'custom-key-value-0',
-        },
-        {
-          key: 'custom-key-1',
-          value: 'custom-key-value-1',
-        },
-      ],
-    });
-  });
-
-  it('fetch filtered theme keys', async () => {
-    const baseId = await createBase(api, alice, '2-themed-base', '2TBase', []);
-    await addTheme(api, alice, baseId, {
-      name: 'default',
-      properties: [
-        {
-          key: 'first-key',
-          value: 'first-key-value',
-        },
-        {
-          key: 'second-key',
-          value: 'second-key-value',
-        },
-      ],
-    }, ['second-key']);
-  });
-
-  it('fetch theme names', async() => {
-    const baseId = await createBase(api, alice, '3-themed-base', '3TBase', []);
-    const names = [
-      'default',
-      'first-theme',
-      'second-theme',
-    ];
-
-    for (let i = 0; i < names.length; i++) {
-      await addTheme(api, alice, baseId, {name: names[i], properties: [{key: 'dummy', value: 'dummy'}]});
-    }
-
-    const fetchedNames = await getThemeNames(api, baseId);
-
-    for (let i = 0; i < names.length; i++) {
-      const isFound = fetchedNames.find((name) => name === names[i]) !== undefined;
-
-      expect(isFound, 'Error: invalid theme names').to.be.true;
-    }
-  });
-
-  it('[negative] unable to add theme to non-existing base', async () => {
-    const maxBaseId = 0xFFFFFFFF;
-    const tx = addTheme(api, alice, maxBaseId, {
-      name: 'default',
-      properties: [],
-    });
-
-    await expectTxFailure(/rmrkEquip\.BaseDoesntExist/, tx);
-  });
-
-  it('[negative] unable to add custom theme if no default theme', async () => {
-    const baseId = await createBase(api, alice, 'no-default-themed-base', 'NDTBase', []);
-    const tx = addTheme(api, alice, baseId, {
-      name: 'custom-theme',
-      properties: [],
-    });
-
-    await expectTxFailure(/rmrkEquip\.NeedsDefaultThemeFirst/, tx);
-  });
-
-  it('[negative] unable to add theme by a not-an-owner', async () => {
-    const baseId = await createBase(api, alice, 'no-default-themed-base', 'NDTBase', []);
-    const tx = addTheme(api, bob, baseId, {
-      name: 'default',
-      properties: [],
-    });
-
-    await expectTxFailure(/rmrkEquip\.PermissionError/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/burnNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/burnNft.seqtest.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {NftIdTuple, getChildren} from './util/fetch';
-import {burnNft, createCollection, sendNft, mintNft} from './util/tx';
-
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-describe('integration test: burn nft', () => {
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-  it('burn nft', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const nftId = await mintNft(
-        api,
-        alice,
-        alice,
-        collectionId,
-        'nft-metadata',
-      );
-      await burnNft(api, alice, collectionId, nftId);
-    });
-  });
-
-  it('burn nft with children', async () => {
-    const collectionId = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const childNftId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    const childrenBefore = await getChildren(api, collectionId, parentNftId);
-    expect(childrenBefore.length === 1, 'Error: parent NFT should have children')
-      .to.be.true;
-
-    const child = childrenBefore[0];
-    expect(child.collectionId.eq(collectionId), 'Error: invalid child collection Id')
-      .to.be.true;
-
-    expect(child.nftId.eq(childNftId), 'Error: invalid child NFT Id')
-      .to.be.true;
-
-    await burnNft(api, alice, collectionId, parentNftId);
-
-    const childrenAfter = await getChildren(api, collectionId, parentNftId);
-
-    expect(childrenAfter.length === 0, 'Error: children should be burned').to.be.true;
-  });
-
-  it('burn child nft', async () => {
-    const collectionId = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const childNftId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    const childrenBefore = await getChildren(api, collectionId, parentNftId);
-    expect(childrenBefore.length === 1, 'Error: parent NFT should have children')
-      .to.be.true;
-
-    const child = childrenBefore[0];
-    expect(child.collectionId.eq(collectionId), 'Error: invalid child collection Id')
-      .to.be.true;
-
-    expect(child.nftId.eq(childNftId), 'Error: invalid child NFT Id')
-      .to.be.true;
-
-    await burnNft(api, alice, collectionId, childNftId);
-
-    const childrenAfter = await getChildren(api, collectionId, parentNftId);
-
-    expect(childrenAfter.length === 0, 'Error: children should be burned').to.be.true;
-  });
-
-  it('[negative] burn non-existing NFT', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const tx = burnNft(api, alice, collectionId, 99999);
-      await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-    });
-  });
-
-  it('[negative] burn not an owner NFT user', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const nftId = await mintNft(
-        api,
-        alice,
-        alice,
-        collectionId,
-        'nft-metadata',
-      );
-      const tx = burnNft(api, bob, collectionId, nftId);
-      await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {
-  changeIssuer,
-  createCollection,
-} from './util/tx';
-
-describe('integration test: collection issuer', () => {
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-
-  it('change collection issuer', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      await changeIssuer(api, alice, collectionId, bob);
-    });
-  });
-
-  it('[negative] change not an owner NFT collection issuer', async () => {
-    await createCollection(api, bob, 'test-metadata', null, 'test-symbol').then(async (collectionId) => {
-      const tx = changeIssuer(api, alice, collectionId, bob);
-      await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-    });
-  });
-
-  it('[negative] change non-existigit NFT collection issuer', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async () => {
-      const tx = changeIssuer(api, alice, 99999, bob);
-      await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx);
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/createBase.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/createBase.seqtest.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {requirePallets, Pallets} from './util/helpers';
-import {createCollection, createBase} from './util/tx';
-
-describe('integration test: create new Base', () => {
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
-  });
-
-  const alice = '//Alice';
-
-  it('create empty Base', async () => {
-    await createBase(api, alice, 'empty-base-type', 'EBase', []);
-  });
-
-  it('create Base with fixed part', async () => {
-    await createBase(api, alice, 'fixedpart-base-type', 'FPBase', [
-      {
-        'FixedPart': {
-          id: 42,
-          z: 0,
-          src: 'some-fixed-url',
-        },
-      },
-    ]);
-  });
-
-  it('create Base with slot part (no collection)', async () => {
-    await createBase(api, alice, 'slotpart-base-type', 'SPBase', [
-      {
-        'SlotPart': {
-          id: 112,
-          equippable: 'Empty',
-          z: 0,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-  });
-
-  it('create Base with slot part (any collection)', async () => {
-    await createBase(api, alice, 'slotpartany-base-type', 'SPABase', [
-      {
-        'SlotPart': {
-          id: 222,
-          equippable: 'All',
-          z: 1,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-  });
-
-  it('create Base with slot part (custom collections)', async () => {
-    const firstCollectionId = await createCollection(
-      api,
-      alice,
-      'first-collection-meta',
-      null,
-      'first-collection',
-    );
-
-    const secondCollectionId = await createCollection(
-      api,
-      alice,
-      'first-collection-meta',
-      null,
-      'first-collection',
-    );
-
-    await createBase(api, alice, 'slotpartcustom-base-type', 'SPCBase', [
-      {
-        'SlotPart': {
-          id: 1024,
-          equippable: {
-            'Custom': [firstCollectionId, secondCollectionId],
-          },
-          z: 2,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/createCollection.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/createCollection.seqtest.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {requirePallets, Pallets} from './util/helpers';
-import {createCollection} from './util/tx';
-
-describe('Integration test: create new collection', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-
-  const alice = '//Alice';
-
-  it('create NFT collection', async () => {
-    await createCollection(api, alice, 'test-metadata', 42, 'test-symbol');
-  });
-
-  it('create NFT collection without token limit', async () => {
-    await createCollection(api, alice, 'no-limit-metadata', null, 'no-limit-symbol');
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/deleteCollection.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/deleteCollection.seqtest.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, deleteCollection} from './util/tx';
-
-describe('integration test: delete collection', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  it('delete NFT collection', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      await deleteCollection(api, alice, collectionId.toString());
-    });
-  });
-
-  it('[negative] delete non-existing NFT collection', async () => {
-    const tx = deleteCollection(api, alice, '99999');
-    await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx);
-  });
-
-  it('[negative] delete not an owner NFT collection', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const tx = deleteCollection(api, bob, collectionId.toString());
-      await expectTxFailure(/rmrkCore.NoPermission/, tx);
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/equipNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/equipNft.seqtest.ts
+++ /dev/null
@@ -1,340 +0,0 @@
-import {ApiPromise} from '@polkadot/api';
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {getNft, NftIdTuple} from './util/fetch';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {
-  addNftComposableResource,
-  addNftSlotResource,
-  createBase,
-  createCollection,
-  equipNft,
-  mintNft,
-  sendNft,
-  unequipNft,
-} from './util/tx';
-
-const alice = '//Alice';
-const bob = '//Bob';
-
-const composableParts: number[] = [5, 2, 7];
-const composableSrc = 'test-cmp-src';
-const composableMetadata = 'test-cmp-metadata';
-const composableLicense = 'test-comp-license';
-const composableThumb = 'test-comp-thumb';
-
-const slotSrc = 'test-slot-src';
-const slotLicense = 'test-slot-license';
-const slotMetadata = 'test-slot-metadata';
-const slotThumb = 'test-slot-thumb';
-
-const slotId = 1;
-
-function createTestCollection(api: ApiPromise): Promise<number> {
-  return createCollection(
-    api,
-    alice,
-    'test-metadata',
-    null,
-    'test-symbol',
-  );
-}
-
-async function mintTestNft(api: ApiPromise, collectionId: number): Promise<number> {
-  return await mintNft(
-    api,
-    alice,
-    alice,
-    collectionId,
-    'nft-metadata',
-  );
-}
-
-async function mintChildNft(api: ApiPromise, collectionId: number, parentNftId: number): Promise<number> {
-  const nftChildId = await mintTestNft(api, collectionId);
-
-  const parentNFT: NftIdTuple = [collectionId, parentNftId];
-
-  await sendNft(api, 'sent', alice, collectionId, nftChildId, parentNFT);
-
-  return nftChildId;
-}
-
-function createTestBase(api: ApiPromise): Promise<number> {
-  return createBase(api, alice, 'test-base', 'DTBase', [
-    {
-      SlotPart: {
-        id: slotId,
-        equippable: 'All',
-        z: 1,
-        src: slotSrc,
-      },
-    },
-  ]);
-}
-
-async function addTestComposable(api: ApiPromise, collectionId: number, nftId: number, baseId: number) {
-  await addNftComposableResource(
-    api,
-    alice,
-    'added',
-    collectionId,
-    nftId,
-    composableParts,
-    baseId,
-    composableSrc,
-    composableMetadata,
-    composableLicense,
-    composableThumb,
-  );
-}
-
-async function addTestSlot(api: ApiPromise, collectionId: number, nftId: number, baseId: number, slotId: number): Promise<number> {
-  return await addNftSlotResource(
-    api,
-    alice,
-    'added',
-    collectionId,
-    nftId,
-    baseId,
-    slotId,
-    slotSrc,
-    slotMetadata,
-    slotLicense,
-    slotThumb,
-  );
-}
-
-async function checkEquipStatus(
-  api: ApiPromise,
-  expectedStatus: 'equipped' | 'unequipped',
-  collectionId: number,
-  nftId: number,
-) {
-  const itemNftDataOpt = await getNft(api, collectionId, nftId);
-  expect(itemNftDataOpt.isSome, 'Error: unable to fetch item NFT data');
-
-  const itemNftData = itemNftDataOpt.unwrap();
-  expect(itemNftData.equipped.isTrue, `Error: item NFT should be ${expectedStatus}`)
-    .to.be.equal(expectedStatus === 'equipped');
-}
-
-describe.skip('integration test: Equip NFT', () => {
-
-  let api: any;
-  
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore, Pallets.RmrkEquip]);
-  });
-
-  it('equip nft', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    await equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-
-    await checkEquipStatus(api, 'equipped', collectionId, nftChildId);
-  });
-
-  it('unequip nft', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    await equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-
-    await checkEquipStatus(api, 'equipped', collectionId, nftChildId);
-
-    await unequipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-    await checkEquipStatus(api, 'unequipped', collectionId, nftChildId);
-  });
-
-  it('[negative] equip NFT onto non-existing NFT', async () => {
-    const collectionId = await createTestCollection(api);
-
-    const nftChildId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-    const invalidEquipperNFT: NftIdTuple = [collectionId, 9999999];
-
-    const baseId = 0;
-    const resourceId = 0;
-
-    const tx = equipNft(api, alice, itemNFT, invalidEquipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] equip non-existing NFT', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionId,
-      'nft-metadata',
-    );
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const invalidItemNFT: NftIdTuple = [collectionId, 99999999];
-
-    const resourceId = 0;
-
-    const tx = equipNft(api, alice, invalidItemNFT, equipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] equip NFT by a not-an-owner user', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const tx = equipNft(api, bob, itemNFT, equipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkEquip\.PermissionError/, tx);
-  });
-
-  it('[negative] unable to equip NFT onto indirect parent NFT', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-    const nftGrandchildId = await mintChildNft(api, collectionId, nftChildId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftGrandchildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftGrandchildId];
-
-    const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkEquip\.MustBeDirectParent/, tx);
-  });
-
-  it('[negative] unable to equip NFT onto parent NFT with another base', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    const invalidBaseId = 99999;
-
-    const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, invalidBaseId, slotId);
-    await expectTxFailure(/rmrkEquip\.NoResourceForThisBaseFoundOnNft/, tx);
-  });
-
-  it('[negative] unable to equip NFT into slot with another id', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createTestBase(api);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    const incorrectSlotId = slotId + 1;
-    const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, incorrectSlotId);
-    await expectTxFailure(/rmrkEquip\.ItemHasNoResourceToEquipThere/, tx);
-  });
-
-  it('[negative] unable to equip NFT with incorrect slot (fixed part)', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createBase(api, alice, 'test-base', 'DTBase', [
-      {
-        FixedPart: {
-          id: slotId,
-          equippable: 'All',
-          z: 1,
-          src: slotSrc,
-        },
-      },
-    ]);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkEquip\.CantEquipFixedPart/, tx);
-  });
-
-  it('[negative] unable to equip NFT from a collection that is not allowed by the slot', async () => {
-    const collectionId = await createTestCollection(api);
-    const nftParentId = await mintTestNft(api, collectionId);
-    const nftChildId = await mintChildNft(api, collectionId, nftParentId);
-
-    const baseId = await createBase(api, alice, 'test-base', 'DTBase', [
-      {
-        SlotPart: {
-          id: 1,
-          z: 1,
-          equippable: 'Empty',
-          src: slotSrc,
-        },
-      },
-    ]);
-
-    await addTestComposable(api, collectionId, nftParentId, baseId);
-    const resourceId = await addTestSlot(api, collectionId, nftChildId, baseId, slotId);
-
-    const equipperNFT: NftIdTuple = [collectionId, nftParentId];
-    const itemNFT: NftIdTuple = [collectionId, nftChildId];
-
-    const tx = equipNft(api, alice, itemNFT, equipperNFT, resourceId, baseId, slotId);
-    await expectTxFailure(/rmrkEquip\.CollectionNotEquippable/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/getOwnedNfts.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/getOwnedNfts.seqtest.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {requirePallets, Pallets} from './util/helpers';
-import {getOwnedNfts} from './util/fetch';
-import {mintNft, createCollection} from './util/tx';
-
-describe('integration test: get owned NFTs', () => {
-  let api: any;
-  
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-  const alice = '//Alice';
-
-  it('fetch all NFTs owned by a user', async () => {
-    const owner = alice;
-    const collectionMetadata = 'aliceCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'AliceSym';
-    const recipientUri = null;
-    const royalty = null;
-    const nftMetadata = 'alice-NFT-metadata';
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    const nftIds = [
-      await mintNft(
-        api,
-        alice,
-        owner,
-        collectionId,
-        nftMetadata + '-0',
-        recipientUri,
-        royalty,
-      ),
-      await mintNft(
-        api,
-        alice,
-        owner,
-        collectionId,
-        nftMetadata + '-1',
-        recipientUri,
-        royalty,
-      ),
-      await mintNft(
-        api,
-        alice,
-        owner,
-        collectionId,
-        nftMetadata + '-2',
-        recipientUri,
-        royalty,
-      ),
-    ];
-
-    const ownedNfts = await getOwnedNfts(api, alice, collectionId);
-
-    const isFound = (nftId: number) => {
-      return ownedNfts.find((ownedNftId) => {
-        return ownedNftId === nftId;
-      }) !== undefined;
-    };
-
-    nftIds.forEach((nftId) => {
-      expect(isFound(nftId), `NFT ${nftId} should be owned by ${alice}`)
-        .to.be.true;
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/lockCollection.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/lockCollection.seqtest.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, lockCollection, mintNft} from './util/tx';
-
-describe('integration test: lock collection', () => {
-  const alice = '//Alice';
-  const bob = '//Bob';
-  const max = 5;
-
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  it('lock collection', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      await lockCollection(api, alice, collectionId);
-    });
-  });
-
-  it('[negative] lock non-existing NFT collection', async () => {
-    const tx = lockCollection(api, alice, 99999);
-    await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx);
-  });
-
-  it('[negative] lock not an owner NFT collection issuer', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const tx = lockCollection(api, bob, collectionId);
-      await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-    });
-  });
-
-  it('lock collection with minting', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      max,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      for (let i = 0; i < 5; i++) {
-        await mintNft(
-          api,
-          alice,
-          alice,
-          collectionId,
-          'test-metadata',
-          null,
-          null,
-        );
-      }
-      await lockCollection(api, alice, collectionId, max);
-    });
-  });
-
-  it('[negative] unable to mint NFT inside a locked collection', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      max,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      await lockCollection(api, alice, collectionId);
-      const tx = mintNft(
-        api,
-        alice,
-        alice,
-        collectionId,
-        'test-metadata',
-        null,
-        null,
-      );
-      await expectTxFailure(/rmrkCore\.CollectionFullOrLocked/, tx);
-    });
-  });
-
-  it('[negative] unable to mint NFT inside a full collection', async () => {
-    await createCollection(api, alice, 'test-metadata', 1, 'test-symbol').then(async (collectionId) => {
-      await mintNft(
-        api,
-        alice,
-        alice,
-        collectionId,
-        'test-metadata',
-        null,
-        null,
-      );
-      const tx = mintNft(
-        api,
-        alice,
-        alice,
-        collectionId,
-        'test-metadata',
-        null,
-        null,
-      );
-      await expectTxFailure(/rmrkCore\.CollectionFullOrLocked/, tx);
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/mintNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/mintNft.seqtest.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {getNft} from './util/fetch';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, mintNft} from './util/tx';
-
-describe('integration test: mint new NFT', () => {
-  let api: any;
- 
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-  const maxCollectionId = 0xFFFFFFFF;
-  const maxNftId = 0xFFFFFFFF;
-
-  it('mint NFT', async () => {
-    const owner = null;
-    const collectionMetadata = 'mintingCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'MCS';
-    const recipientUri = null;
-    const royalty = null;
-    const nftMetadata = 'NFT-test-metadata';
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    await mintNft(
-      api,
-      alice,
-      owner,
-      collectionId,
-      nftMetadata,
-      recipientUri,
-      royalty,
-    );
-  });
-
-  it('mint NFT and set another owner', async () => {
-    const owner = bob;
-    const collectionMetadata = 'setOwnerCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'SOCS';
-    const recipientUri = null;
-    const royalty = null;
-    const nftMetadata = 'setOwner-NFT-metadata';
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    await mintNft(
-      api,
-      alice,
-      owner,
-      collectionId,
-      nftMetadata,
-      recipientUri,
-      royalty,
-    );
-  });
-
-  it('mint NFT with recipient and roalty', async () => {
-    const owner = alice;
-    const collectionMetadata = 'mintingCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'MCS';
-    const recipientUri = bob;
-    const royalty = 70000;
-    const nftMetadata = 'recipient-royalty-NFT-test-metadata';
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    await mintNft(
-      api,
-      alice,
-      owner,
-      collectionId,
-      nftMetadata,
-      recipientUri,
-      royalty,
-    );
-  });
-
-  it('mint NFT with resources', async () => {
-    const owner = alice;
-    const collectionMetadata = 'mintingCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'MCS';
-    const nftMetadata = 'NFT-with-resources-test-metadata';
-    const resources = [
-      {
-        basic: {
-          metadata: 'basic-resource-nft-minting',
-        },
-      }, {
-        slot: {
-          metadata: 'slot-resource-nft-minting',
-          slot: 9,
-        },
-      }, {
-        composable: {
-          metadata: 'composable-resource-nft-minting',
-          parts: [0, 5, 2],
-        },
-      }, {
-        slot: {
-          metadata: 'slot-resource-nft-minting-2',
-          thumb: 'srnm2',
-          base: 5,
-        },
-      },
-    ];
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    await mintNft(
-      api,
-      alice,
-      owner,
-      collectionId,
-      nftMetadata,
-      null,
-      null,
-      true,
-      resources,
-    );
-  });
-
-  it('[negative] unable to mint NFT within non-existing collection', async () => {
-    const owner = alice;
-    const recipientUri = null;
-    const royalty = null;
-    const nftMetadata = 'NFT-test-metadata';
-
-    const tx = mintNft(
-      api,
-      alice,
-      owner,
-      maxCollectionId,
-      nftMetadata,
-      recipientUri,
-      royalty,
-    );
-
-    await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx);
-  });
-
-  it("[negative] unable to mint NFT by a user that isn't the owner of the collection", async () => {
-    const owner = alice;
-    const collectionMetadata = 'mintingCollectionMetadata';
-    const collectionMax = null;
-    const collectionSymbol = 'MCS';
-    const recipientUri = null;
-    const royalty = null;
-    const nftMetadata = 'NFT-test-metadata';
-
-    const collectionId = await createCollection(
-      api,
-      alice,
-      collectionMetadata,
-      collectionMax,
-      collectionSymbol,
-    );
-
-    const tx = mintNft(
-      api,
-      bob,
-      owner,
-      collectionId,
-      nftMetadata,
-      recipientUri,
-      royalty,
-    );
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative] unable to fetch non-existing NFT', async () => {
-    const nft = await getNft(api, maxCollectionId, maxNftId);
-    expect(nft.isSome).to.be.false;
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/rejectNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/rejectNft.seqtest.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {
-  createCollection,
-  mintNft,
-  sendNft,
-  rejectNft,
-} from './util/tx';
-import {NftIdTuple} from './util/fetch';
-import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers';
-
-describe('integration test: reject NFT', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  const createTestCollection = async (issuerUri: string) => {
-    return await createCollection(
-      api,
-      issuerUri,
-      'reject-metadata',
-      null,
-      'rjct',
-    );
-  };
-
-  it('reject NFT', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT);
-    await rejectNft(api, alice, bobCollectionId, childNftId);
-
-    const isChild = await isNftChildOfAnother(api, bobCollectionId, childNftId, newOwnerNFT);
-    expect(isChild, 'Error: rejected NFT is still a child of the target NFT').to.be.false;
-  });
-
-  it('[negative] unable to reject NFT by a not-an-owner', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    await sendNft(api, 'pending', ownerBob, bobCollectionId, childNftId, newOwnerNFT);
-    const tx = rejectNft(api, bob, bobCollectionId, childNftId);
-
-    await expectTxFailure(/rmrkCore\.CannotRejectNonOwnedNft/, tx);
-  });
-
-  it('[negative] unable to reject non-existing NFT', async () => {
-    const maxNftId = 0xFFFFFFFF;
-
-    const collectionId = await createTestCollection(alice);
-
-    const tx = rejectNft(api, alice, collectionId, maxNftId);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] unable to reject NFT which is not sent', async () => {
-    const ownerAlice = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'parent-nft-metadata');
-
-    const tx = rejectNft(api, alice, collectionId, nftId);
-
-    await expectTxFailure(/rmrkCore\.CannotRejectNonPendingNft/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/removeResource.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/removeResource.seqtest.ts
+++ /dev/null
@@ -1,340 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {NftIdTuple} from './util/fetch';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {
-  acceptResourceRemoval, addNftBasicResource, createCollection, mintNft, removeNftResource, sendNft,
-} from './util/tx';
-
-
-
-
-describe('Integration test: remove nft resource', () => {
-  let api: any;
-  before(async function() {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-  const src = 'test-basic-src';
-  const metadata = 'test-basic-metadata';
-  const license = 'test-basic-license';
-  const thumb = 'test-basic-thumb';
-
-  it('deleting a resource directly by the NFT owner', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    await removeNftResource(api, 'removed', alice, collectionIdAlice, nftAlice, resourceId);
-  });
-
-  it('deleting resources indirectly by the NFT owner', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(api, alice, alice, collectionIdAlice, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, alice, collectionIdAlice, 'child-nft-metadata');
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      childNftId,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionIdAlice, childNftId, newOwnerNFT);
-
-    await removeNftResource(api, 'removed', alice, collectionIdAlice, childNftId, resourceId);
-  });
-
-  it('deleting a resource by the collection owner', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftBob = await mintNft(
-      api,
-      alice,
-      bob,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'pending',
-      collectionIdAlice,
-      nftBob,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    await removeNftResource(api, 'pending', alice, collectionIdAlice, nftBob, resourceId);
-    await acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, resourceId);
-  });
-
-  it('deleting a resource in a nested NFT by the collection owner', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const parentNftId = await mintNft(
-      api,
-      alice,
-      bob,
-      collectionIdAlice,
-      'parent-nft-metadata',
-    );
-    const childNftId = await mintNft(
-      api,
-      alice,
-      bob,
-      collectionIdAlice,
-      'child-nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'pending',
-      collectionIdAlice,
-      childNftId,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const newOwnerNFT: NftIdTuple = [collectionIdAlice, parentNftId];
-
-    await sendNft(api, 'sent', bob, collectionIdAlice, childNftId, newOwnerNFT);
-
-    await removeNftResource(api, 'pending', alice, collectionIdAlice, childNftId, resourceId);
-    await acceptResourceRemoval(api, bob, collectionIdAlice, childNftId, resourceId);
-  });
-
-  it('[negative]: can\'t delete a resource in a non-existing collection', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = removeNftResource(api, 'removed', alice, 0xFFFFFFFF, nftAlice, resourceId);
-    await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx); // FIXME: inappropriate error message (NoAvailableNftId)
-  });
-
-  it('[negative]: only collection owner can delete a resource', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = removeNftResource(api, 'removed', bob, collectionIdAlice, nftAlice, resourceId);
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative]: cannot delete a resource that does not exist', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const tx = removeNftResource(api, 'removed', alice, collectionIdAlice, nftAlice, 127);
-    await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx);
-  });
-
-  it('[negative]: Cannot accept deleting resource without owner attempt do delete it', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftBob = await mintNft(
-      api,
-      alice,
-      bob,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'pending',
-      collectionIdAlice,
-      nftBob,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, resourceId);
-    await expectTxFailure(/rmrkCore\.ResourceNotPending/, tx);
-  });
-
-  it('[negative]: cannot confirm the deletion of a non-existing resource', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftBob = await mintNft(
-      api,
-      alice,
-      bob,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftBob, 127);
-    await expectTxFailure(/rmrkCore\.ResourceDoesntExist/, tx);
-  });
-
-  it('[negative]: Non-owner user cannot confirm the deletion of resource', async () => {
-    const collectionIdAlice = await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    );
-
-    const nftAlice = await mintNft(
-      api,
-      alice,
-      alice,
-      collectionIdAlice,
-      'nft-metadata',
-    );
-
-    const resourceId = await addNftBasicResource(
-      api,
-      alice,
-      'added',
-      collectionIdAlice,
-      nftAlice,
-      src,
-      metadata,
-      license,
-      thumb,
-    );
-
-    const tx = acceptResourceRemoval(api, bob, collectionIdAlice, nftAlice, resourceId);
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/rmrkIsolation.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/rmrkIsolation.seqtest.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import {executeTransaction} from '../substrate/substrate-api';
-import {IKeyringPair} from '@polkadot/types/types';
-import {itSub, expect, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../../util';
-import {UniqueHelper} from '../../util/playgrounds/unique';
-
-let alice: IKeyringPair;
-let bob: IKeyringPair;
-
-async function createRmrkCollection(helper: UniqueHelper, sender: IKeyringPair): Promise<{uniqueId: number, rmrkId: number}> {
-  const result = await helper.executeExtrinsic(sender, 'api.tx.rmrkCore.createCollection', ['metadata', null, 'symbol'], true);
-
-  const uniqueId = helper.util.extractCollectionIdFromCreationResult(result);
-
-  let rmrkId = null;
-  result.result.events.forEach(({event: {data, method, section}}) => {
-    if ((section === 'rmrkCore') && (method === 'CollectionCreated')) {
-      rmrkId = parseInt(data[1].toString(), 10);
-    }
-  });
-
-  if (rmrkId === null) {
-    throw Error('No rmrkCore.CollectionCreated event was found!');
-  }
-
-  return {
-    uniqueId,
-    rmrkId,
-  };
-}
-
-async function createRmrkNft(helper: UniqueHelper, sender: IKeyringPair, collectionId: number): Promise<number> {
-  const result = await helper.executeExtrinsic(
-    sender,
-    'api.tx.rmrkCore.mintNft',
-    [
-      sender.address,
-      collectionId,
-      sender.address,
-      null,
-      'nft-metadata',
-      true,
-      null,
-    ],
-    true,
-  );
-
-  let rmrkNftId = null;
-  result.result.events.forEach(({event: {data, method, section}}) => {
-    if ((section === 'rmrkCore') && (method === 'NftMinted')) {
-      rmrkNftId = parseInt(data[2].toString(), 10);
-    }
-  });
-
-  if (rmrkNftId === null) {
-    throw Error('No rmrkCore.NftMinted event was found!');
-  }
-
-  return rmrkNftId;
-}
-
-describe('RMRK External Integration Test', () => {
-  before(async function() {
-    await usingPlaygrounds(async (_helper, privateKey) => {
-      alice = await privateKey('//Alice');
-    });
-  });
-
-  itSub.ifWithPallets('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', [Pallets.RmrkCore], async ({helper}) => {
-    // throw away collection to bump last Unique collection ID to test ID mapping
-    await helper.nft.mintCollection(alice, {tokenPrefix: 'unqt'});
-
-    const collectionIds = await createRmrkCollection(helper, alice);
-
-    expect(collectionIds.rmrkId).to.be.lessThan(collectionIds.uniqueId, 'collection ID mapping');
-
-    const collection = (await helper.nft.getCollectionObject(collectionIds.uniqueId).getData())!; // (await getDetailedCollectionInfo(api, collectionIds.uniqueId))!;
-    expect(collection.raw.readOnly, 'tagged external').to.be.true;
-  });
-});
-
-describe('Negative Integration Test: External Collections, Internal Ops', () => {
-  let uniqueCollectionId: number;
-  let rmrkCollectionId: number;
-  let rmrkNftId: number;
-  let normalizedAlice: {Substrate: string};
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      alice = await privateKey('//Alice');
-      bob = await privateKey('//Bob');
-      normalizedAlice = {Substrate: helper.address.normalizeSubstrateToChainFormat(alice.address)};
-
-      requirePalletsOrSkip(this, helper, [Pallets.RmrkCore]);
-
-      const collectionIds = await createRmrkCollection(helper, alice);
-      uniqueCollectionId = collectionIds.uniqueId;
-      rmrkCollectionId = collectionIds.rmrkId;
-
-      rmrkNftId = await createRmrkNft(helper, alice, rmrkCollectionId);
-    });
-  });
-
-  itSub.ifWithPallets('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', [Pallets.RmrkCore], async ({helper}) => {
-    // Collection item creation
-
-    await expect(helper.nft.mintToken(alice, {collectionId: uniqueCollectionId, owner: {Substrate: alice.address}}), 'creating item')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    const txCreateMultipleItems = helper.getApi().tx.unique.createMultipleItems(uniqueCollectionId, normalizedAlice, [{NFT: {}}, {NFT: {}}]);
-    await expect(executeTransaction(helper.getApi(), alice, txCreateMultipleItems), 'creating multiple')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-  
-    await expect(helper.nft.mintMultipleTokens(alice, uniqueCollectionId, [{owner: {Substrate: alice.address}}]), 'creating multiple ex')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    // Collection properties
-
-    await expect(helper.nft.setProperties(alice, uniqueCollectionId, [{key: 'a', value: '1'}, {key: 'b'}]), 'setting collection properties')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.deleteProperties(alice, uniqueCollectionId, ['a']), 'deleting collection properties')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.setTokenPropertyPermissions(alice, uniqueCollectionId, [{key: 'a', permission: {mutable: true}}]), 'setting property permissions')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    // NFT
-
-    await expect(helper.nft.burnToken(alice, uniqueCollectionId, rmrkNftId, 1n), 'burning')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.burnTokenFrom(alice, uniqueCollectionId, rmrkNftId, {Substrate: alice.address}, 1n), 'burning-from')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.transferToken(alice, uniqueCollectionId, rmrkNftId, {Substrate: bob.address}), 'transferring')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.approveToken(alice, uniqueCollectionId, rmrkNftId, {Substrate: bob.address}), 'approving')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.transferTokenFrom(alice, uniqueCollectionId, rmrkNftId, {Substrate: alice.address}, {Substrate: bob.address}), 'transferring-from')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    // NFT properties
-
-    await expect(helper.nft.setTokenProperties(alice, uniqueCollectionId, rmrkNftId, [{key: 'a', value: '2'}]), 'setting token properties')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.deleteTokenProperties(alice, uniqueCollectionId, rmrkNftId, ['a']))
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-  });
-
-  itSub.ifWithPallets('[Negative] Forbids Unique collection operations with an external collection', [Pallets.RmrkCore], async ({helper}) => {
-    await expect(helper.nft.burn(alice, uniqueCollectionId), 'destroying collection')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    // Allow list
-
-    await expect(helper.nft.addToAllowList(alice, uniqueCollectionId, {Substrate: bob.address}), 'adding to allow list')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.removeFromAllowList(alice, uniqueCollectionId, {Substrate: bob.address}), 'removing from allowlist')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    // Owner / Admin / Sponsor
-
-    await expect(helper.nft.changeOwner(alice, uniqueCollectionId, bob.address), 'changing owner')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.addAdmin(alice, uniqueCollectionId, {Substrate: bob.address}), 'adding admin')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.removeAdmin(alice, uniqueCollectionId, {Substrate: bob.address}), 'removing admin')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.setSponsor(alice, uniqueCollectionId, bob.address), 'setting sponsor')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.confirmSponsorship(alice, uniqueCollectionId), 'confirming sponsor')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.removeSponsor(alice, uniqueCollectionId), 'removing sponsor')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-    
-    // Limits / permissions / transfers
-
-    const txSetTransfers = helper.getApi().tx.unique.setTransfersEnabledFlag(uniqueCollectionId, true);
-    await expect(executeTransaction(helper.getApi(), alice, txSetTransfers), 'setting transfers enabled flag')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.setLimits(alice, uniqueCollectionId, {transfersEnabled: false}), 'setting collection limits')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-
-    await expect(helper.nft.setPermissions(alice, uniqueCollectionId, {access: 'AllowList'}), 'setting collection permissions')
-      .to.be.rejectedWith(/common\.CollectionIsExternal/);
-  });
-});
-
-describe('Negative Integration Test: Internal Collections, External Ops', () => {
-  let collectionId: number;
-  let nftId: number;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      alice = await privateKey('//Alice');
-      bob = await privateKey('//Bob');
-
-      const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'iceo'});
-      collectionId = collection.collectionId;
-      nftId = (await collection.mintToken(alice)).tokenId;
-    });
-  });
-
-  itSub.ifWithPallets('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', [Pallets.RmrkCore], async ({helper}) => {
-    const api = helper.getApi();
-
-    const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address);
-    await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer')
-      .to.be.rejectedWith(/rmrkCore\.CollectionUnknown/);
-
-    const maxBurns = 10;
-    const txBurnItem = api.tx.rmrkCore.burnNft(collectionId, nftId, maxBurns);
-    await expect(executeTransaction(api, alice, txBurnItem), 'burning NFT').to.be.rejectedWith(/rmrkCore\.CollectionUnknown/);
-  });
-});
deletedtests/src/.outdated/rmrk/sendNft.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/sendNft.seqtest.ts
+++ /dev/null
@@ -1,255 +0,0 @@
-import {expect} from 'chai';
-import {getApiConnection} from '../substrate/substrate-api';
-import {createCollection, mintNft, sendNft} from './util/tx';
-import {NftIdTuple} from './util/fetch';
-import {isNftChildOfAnother, expectTxFailure, requirePallets, Pallets} from './util/helpers';
-
-describe('integration test: send NFT', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const maxNftId = 0xFFFFFFFF;
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  const createTestCollection = async (issuerUri: string) => {
-    return await createCollection(
-      api,
-      issuerUri,
-      'nft-collection-metadata',
-      null,
-      'nft-collection',
-    );
-  };
-
-
-  it('send NFT to another user', async () => {
-    const originalOwnerUri = alice;
-    const newOwnerUri = bob;
-
-    const collectionId = await createTestCollection(alice);
-
-    const nftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'nft-metadata');
-
-    await sendNft(api, 'sent', originalOwnerUri, collectionId, nftId, newOwnerUri);
-  });
-
-  it('[negative] unable to send non-existing NFT', async () => {
-    const originalOwnerUri = alice;
-    const newOwnerUri = bob;
-
-    const collectionId = 0;
-    const tx = sendNft(api, 'sent', originalOwnerUri, collectionId, maxNftId, newOwnerUri);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] unable to send NFT by a not-an-owner', async () => {
-    const originalOwnerUri = alice;
-    const newOwnerUri = bob;
-
-    const collectionId = await createTestCollection(alice);
-
-    const nftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'nft-metadata');
-
-    const tx = sendNft(api, 'sent', newOwnerUri, collectionId, nftId, newOwnerUri);
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('send NFT to another NFT (same owner)', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.true;
-  });
-
-  it('[negative] send non-existing NFT to another NFT', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata');
-    const childNftId = maxNftId;
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    const tx = sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.false;
-  });
-
-  it('send NFT to another NFT (by not-an-owner)', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const author = alice;
-    const attacker = bob;
-
-    const parentNftId = await mintNft(api, author, originalOwnerUri, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, author, originalOwnerUri, collectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    const tx = sendNft(api, 'sent', attacker, collectionId, childNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.false;
-  });
-
-  it('[negative] send NFT to non-existing NFT', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = maxNftId;
-    const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    const tx = sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.false;
-  });
-
-  it('send NFT to another NFT owned by another user', async () => {
-    const ownerAlice = alice;
-    const ownerBob = bob;
-
-    const aliceCollectionId = await createTestCollection(alice);
-    const bobCollectionId = await createTestCollection(bob);
-
-    const parentNftId = await mintNft(api, alice, ownerAlice, aliceCollectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, bob, ownerBob, bobCollectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [aliceCollectionId, parentNftId];
-
-    await sendNft(api, 'pending', bob, bobCollectionId, childNftId, newOwnerNFT);
-  });
-
-  it('[negative] unable to send NFT to itself', async () => {
-    const nftOwner = alice;
-    const collectionId = await createTestCollection(alice);
-
-    const nftId = await mintNft(api, alice, nftOwner, collectionId, 'ouroboros-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionId, nftId];
-
-    const tx = sendNft(api, 'sent', alice, collectionId, nftId, newOwnerNFT);
-
-    await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, nftId, newOwnerNFT);
-    expect(isChild).to.be.false;
-  });
-
-  it('[negative] unable to send NFT to child NFT', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata');
-
-    const newOwnerNFT: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionId, childNftId, newOwnerNFT);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, newOwnerNFT);
-    expect(isChild).to.be.true;
-
-    const descendentOwner: NftIdTuple = [collectionId, childNftId];
-    const tx = sendNft(api, 'sent', alice, collectionId, parentNftId, descendentOwner);
-
-    await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx);
-    const isOuroboros = await isNftChildOfAnother(api, collectionId, parentNftId, descendentOwner);
-    expect(isOuroboros).to.be.false;
-  });
-
-  it('[negative] unable to send NFT to descendent NFT', async () => {
-    const originalOwnerUri = alice;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'child-nft-metadata');
-    const grandsonNftId = await mintNft(api, alice, originalOwnerUri, collectionId, 'grandson-nft-metadata');
-
-    const ownerParentNFT: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', alice, collectionId, childNftId, ownerParentNFT);
-
-    const isChild = await isNftChildOfAnother(api, collectionId, childNftId, ownerParentNFT);
-    expect(isChild).to.be.true;
-
-    const ownerChildNFT: NftIdTuple = [collectionId, childNftId];
-    await sendNft(api, 'sent', alice, collectionId, grandsonNftId, ownerChildNFT);
-
-    const isGrandson = await isNftChildOfAnother(api, collectionId, grandsonNftId, ownerChildNFT);
-    expect(isGrandson).to.be.true;
-
-    const ownerGrandsonNFT: NftIdTuple = [collectionId, grandsonNftId];
-    const tx = sendNft(api, 'sent', alice, collectionId, parentNftId, ownerGrandsonNFT);
-
-    await expectTxFailure(/rmrkCore\.CannotSendToDescendentOrSelf/, tx);
-    const isOuroboros = await isNftChildOfAnother(api, collectionId, parentNftId, ownerGrandsonNFT);
-    expect(isOuroboros).to.be.false;
-  });
-
-  it('send nested NFT to another user', async () => {
-    const originalOwner = alice;
-    const newOwner = bob;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwner, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, originalOwner, collectionId, 'child-nft-metadata');
-
-    const parentNftTuple: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', originalOwner, collectionId, childNftId, parentNftTuple);
-
-    await sendNft(api, 'sent', originalOwner, collectionId, childNftId, newOwner);
-  });
-
-  it('[negative] send nested NFT to another user (by a not-root-owner)', async () => {
-    const originalOwner = alice;
-    const newOwner = bob;
-
-    const collectionId = await createTestCollection(alice);
-
-    const parentNftId = await mintNft(api, alice, originalOwner, collectionId, 'parent-nft-metadata');
-    const childNftId = await mintNft(api, alice, originalOwner, collectionId, 'child-nft-metadata');
-
-    const parentNftTuple: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', originalOwner, collectionId, childNftId, parentNftTuple);
-
-    const tx = sendNft(api, 'sent', newOwner, collectionId, childNftId, newOwner);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/setCollectionProperty.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/setCollectionProperty.seqtest.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, setPropertyCollection} from './util/tx';
-
-describe('integration test: set collection property', () => {
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  it('set collection property', async () => {
-    await createCollection(
-      api,
-      alice,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      await setPropertyCollection(api, alice, collectionId, 'test_key', '42');
-      await setPropertyCollection(api, alice, collectionId, 'test_key', '10');
-      await setPropertyCollection(
-        api,
-        alice,
-        collectionId,
-        'second_test_key',
-        '111',
-      );
-    });
-  });
-
-  it('[negative] set non-existing collection property', async () => {
-    const tx = setPropertyCollection(
-      api,
-      alice,
-      9999,
-      'test_key',
-      '42',
-    );
-    await expectTxFailure(/rmrkCore\.CollectionUnknown/, tx);
-  });
-
-  it('[negative] set property not an owner NFT collection issuer', async () => {
-    await createCollection(
-      api,
-      bob,
-      'test-metadata',
-      null,
-      'test-symbol',
-    ).then(async (collectionId) => {
-      const tx = setPropertyCollection(
-        api,
-        alice,
-        collectionId,
-        'test_key',
-        '42',
-      );
-      await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-    });
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/setEquippableList.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/setEquippableList.seqtest.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, createBase, setEquippableList} from './util/tx';
-
-describe("integration test: set slot's Equippable List", () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  it("set Base's slot Equippable List", async () => {
-    const collectionIds = [
-      await createCollection(
-        api,
-        alice,
-        'equiplist-collection-metadata',
-        null,
-        'equiplist-0',
-      ),
-      await createCollection(
-        api,
-        alice,
-        'equiplist-collection-metadata',
-        null,
-        'equiplist-1',
-      ),
-    ];
-
-    const slotId = 202;
-
-    const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [
-      {
-        'SlotPart': {
-          id: slotId,
-          equippable: 'All',
-          z: 1,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-
-    await setEquippableList(api, alice, baseId, slotId, 'All');
-    await setEquippableList(api, alice, baseId, slotId, 'Empty');
-    await setEquippableList(api, alice, baseId, slotId, {'Custom': collectionIds});
-  });
-
-  it('[negative] unable to set equippable list of a slot of non-existing base', async () => {
-    const maxBaseId = 0xFFFFFFFF;
-    const slotId = 0;
-
-    const tx = setEquippableList(api, alice, maxBaseId, slotId, 'All');
-    await expectTxFailure(/rmrkEquip\.BaseDoesntExist/, tx);
-  });
-
-  it('[negative] unable to set equippable list by a not-an-owner', async () => {
-    const slotId = 42;
-
-    const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [
-      {
-        'SlotPart': {
-          id: slotId,
-          equippable: 'All',
-          z: 1,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-
-    const tx = setEquippableList(api, bob, baseId, slotId, 'All');
-    await expectTxFailure(/rmrkEquip\.PermissionError/, tx);
-  });
-
-  it('[negative] unable to set equippable list to a fixed part', async () => {
-    const fixedPartId = 42;
-
-    const baseId = await createBase(api, alice, 'fixedpart-base-type', 'fixedpart', [
-      {
-        'FixedPart': {
-          id: fixedPartId,
-          z: 0,
-          src: 'fixed-part-url',
-        },
-      },
-    ]);
-
-    const tx = setEquippableList(api, alice, baseId, fixedPartId, 'All');
-    await expectTxFailure(/rmrkEquip\.NoEquippableOnFixedPart/, tx);
-  });
-
-  it('[negative] unable to set equippable list to non-existing slot', async () => {
-    const slotId = 777;
-    const maxSlotId = 0xFFFFFFFF;
-
-    const baseId = await createBase(api, alice, 'slotpartany-base-type', 'slotpartany', [
-      {
-        'SlotPart': {
-          id: slotId,
-          equippable: 'All',
-          z: 1,
-          src: 'some-fallback-slot-url',
-        },
-      },
-    ]);
-
-    const tx = setEquippableList(api, alice, baseId, maxSlotId, 'All');
-    await expectTxFailure(/rmrkEquip\.PartDoesntExist/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/setNftProperty.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/setNftProperty.seqtest.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {NftIdTuple} from './util/fetch';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {createCollection, mintNft, sendNft, setNftProperty} from './util/tx';
-
-describe('integration test: set NFT property', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  const createTestCollection = async (issuerUri: string) => {
-    return await createCollection(
-      api,
-      issuerUri,
-      'setprop-nft-collection-metadata',
-      null,
-      'setprop',
-    );
-  };
-
-  it('set NFT property', async () => {
-    const ownerAlice = alice;
-
-    const collectionId = await createTestCollection(alice);
-    const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-nft');
-
-    await setNftProperty(api, alice, collectionId, nftId, 'test-key', 'test-key-value');
-    await setNftProperty(api, alice, collectionId, nftId, 'test-key', 'updated-key-value');
-    await setNftProperty(api, alice, collectionId, nftId, 'second-test-key', 'second-test-key-value');
-  });
-
-  it('[negative] unable to set a property of non-existing NFT', async () => {
-    const collectionId = 0;
-    const maxNftId = 0xFFFFFFFF;
-
-    const tx = setNftProperty(api, alice, collectionId, maxNftId, 'test-key', 'test-value');
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  it('[negative] unable to set a property by not-an-owner', async () => {
-    const ownerAlice = alice;
-
-    const collectionId = await createTestCollection(alice);
-    const nftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-nft');
-
-    const tx = setNftProperty(api, bob, collectionId, nftId, 'test-key', 'test-key-value');
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('set a property to nested NFT', async () => {
-    const ownerAlice = alice;
-
-    const collectionId = await createTestCollection(alice);
-    const parentNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-parent-nft');
-    const childNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-child-nft');
-
-    const ownerNft: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', ownerAlice, collectionId, childNftId, ownerNft);
-
-    await setNftProperty(api, alice, collectionId, childNftId, 'test-key', 'test-key-value');
-  });
-
-  it('[negative] set a property to nested NFT (by not-root-owner)', async () => {
-    const ownerAlice = alice;
-
-    const collectionId = await createTestCollection(alice);
-    const parentNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-parent-nft');
-    const childNftId = await mintNft(api, alice, ownerAlice, collectionId, 'prop-child-nft');
-
-    const ownerNft: NftIdTuple = [collectionId, parentNftId];
-
-    await sendNft(api, 'sent', ownerAlice, collectionId, childNftId, ownerNft);
-
-    const tx = setNftProperty(api, bob, collectionId, childNftId, 'test-key', 'test-key-value');
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/setResourcePriorities.seqtest.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/setResourcePriorities.seqtest.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import {getApiConnection} from '../substrate/substrate-api';
-import {expectTxFailure, requirePallets, Pallets} from './util/helpers';
-import {mintNft, createCollection, setResourcePriorities} from './util/tx';
-
-describe('integration test: set NFT resource priorities', () => {
-  let api: any;
-  before(async function () {
-    api = await getApiConnection();
-    await requirePallets(this, [Pallets.RmrkCore]);
-  });
-
-  const alice = '//Alice';
-  const bob = '//Bob';
-
-  const createTestCollection = (issuerUri: string) => {
-    return createCollection(
-      api,
-      issuerUri,
-      'resprio-collection-metadata',
-      null,
-      'resprio',
-    );
-  };
-
-  it('set NFT resource priorities', async () => {
-    const owner = alice;
-
-    const collectionId = await createTestCollection(alice);
-    const nftId = await mintNft(api, alice, owner, collectionId, 'resprio-nft-metadata');
-
-    await setResourcePriorities(api, alice, collectionId, nftId, [10, 42]);
-  });
-
-  it('[negative] set NFT resource priorities by a not-an-owner', async () => {
-    const owner = alice;
-    const attacker = bob;
-
-    const collectionId = await createTestCollection(alice);
-    const nftId = await mintNft(api, alice, owner, collectionId, 'resprio-nft-metadata');
-
-    const tx = setResourcePriorities(api, attacker, collectionId, nftId, [10, 42]);
-
-    await expectTxFailure(/rmrkCore\.NoPermission/, tx);
-  });
-
-  it('[negative] set NFT resource priorities to non-existing NFT', async () => {
-    const collectionId = 0;
-    const maxNftId = 0xFFFFFFFF;
-
-    const tx = setResourcePriorities(api, alice, collectionId, maxNftId, [10, 42]);
-
-    await expectTxFailure(/rmrkCore\.NoAvailableNftId/, tx);
-  });
-
-  after(async() => { await api.disconnect(); });
-});
deletedtests/src/.outdated/rmrk/util/fetch.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/util/fetch.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import {ApiPromise} from '@polkadot/api';
-import type {Option} from '@polkadot/types-codec';
-import type {
-  RmrkTraitsCollectionCollectionInfo as Collection,
-  RmrkTraitsNftNftInfo as Nft,
-  RmrkTraitsResourceResourceInfo as Resource,
-  RmrkTraitsBaseBaseInfo as Base,
-  RmrkTraitsPartPartType as PartType,
-  RmrkTraitsNftNftChild as NftChild,
-  RmrkTraitsTheme as Theme,
-  RmrkTraitsPropertyPropertyInfo as Property,
-} from '../../../interfaces/default/types'; // '@polkadot/types/lookup';
-import '../../../interfaces/augment-api';
-import '../../../interfaces/augment-api-query';
-import privateKey from '../../substrate/privateKey';
-
-export type NftIdTuple = [number, number];
-
-export async function getCollectionsCount(api: ApiPromise): Promise<number> {
-  return (await api.rpc.rmrk.lastCollectionIdx()).toNumber();
-}
-
-export function getCollection(api: ApiPromise, id: number): Promise<Option<Collection>> {
-  return api.rpc.rmrk.collectionById(id);
-}
-
-export async function getOwnedNfts(
-  api: ApiPromise,
-  ownerUri: string,
-  collectionId: number,
-): Promise<number[]> {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const owner = privateKey(ownerUri, Number(ss58Format));
-
-  return (await api.rpc.rmrk.accountTokens(owner.address, collectionId))
-    .map((value) => value.toNumber());
-}
-
-export function getNft(api: ApiPromise, collectionId: number, nftId: number): Promise<Option<Nft>> {
-  return api.rpc.rmrk.nftById(collectionId, nftId);
-}
-
-export async function getCollectionProperties(api: ApiPromise, collectionId: number): Promise<Property[]> {
-  return (await api.rpc.rmrk.collectionProperties(collectionId)).toArray();
-}
-
-export async function getNftProperties(api: ApiPromise, collectionId: number, nftId: number): Promise<Property[]> {
-  return (await api.rpc.rmrk.nftProperties(collectionId, nftId)).toArray();
-}
-
-export async function getChildren(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-): Promise<NftChild[]> {
-  return (await api.rpc.rmrk.nftChildren(collectionId, nftId)).toArray();
-}
-
-export function getBase(api: ApiPromise, baseId: number): Promise<Option<Base>> {
-  return api.rpc.rmrk.base(baseId);
-}
-
-export async function getParts(api: ApiPromise, baseId: number): Promise<PartType[]> {
-  return (await api.rpc.rmrk.baseParts(baseId)).toArray();
-}
-
-export async function getEquippableList(
-  api: ApiPromise,
-  baseId: number,
-  slotId: number,
-): Promise<'All' | 'Empty' | { 'Custom': number[] } | null> {
-  const parts = await getParts(api, baseId);
-
-  const part = parts.find((part) => {
-    if (part.isSlotPart) {
-      return part.asSlotPart.id.toNumber() === slotId;
-    } else {
-      return false;
-    }
-  });
-
-  if (part) {
-    const slot = part.asSlotPart;
-    if (slot.equippable.isCustom) {
-      return {
-        'Custom': slot.equippable.asCustom
-          .toArray()
-          .map((collectionId) => collectionId.toNumber()),
-      };
-    } else if (slot.equippable.isAll) {
-      return 'All';
-    } else {
-      return 'Empty';
-    }
-  } else {
-    return null;
-  }
-}
-
-export async function getResourcePriority(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-): Promise<number> {
-  return (await api.rpc.rmrk.nftResourcePriority(collectionId, nftId, resourceId))
-    .unwrap().toNumber();
-}
-
-export async function getThemeNames(api: ApiPromise, baseId: number): Promise<string[]> {
-  return (await api.rpc.rmrk.themeNames(baseId))
-    .map((name) => name.toUtf8());
-}
-
-export function getTheme(
-  api: ApiPromise,
-  baseId: number,
-  themeName: string,
-  keys: string[] | null = null,
-): Promise<Option<Theme>> {
-  return api.rpc.rmrk.themes(baseId, themeName, keys);
-}
-
-export async function getResources(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-): Promise<Resource[]> {
-  return (await api.rpc.rmrk.nftResources(collectionId, nftId)).toArray();
-}
deletedtests/src/.outdated/rmrk/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/util/helpers.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-import {ApiPromise} from '@polkadot/api';
-import {
-  RmrkTraitsNftAccountIdOrCollectionNftTuple as NftOwner,
-  RmrkTraitsPropertyPropertyInfo as Property,
-  RmrkTraitsResourceResourceInfo as ResourceInfo,
-} from '@polkadot/types/lookup';
-import type {EventRecord} from '@polkadot/types/interfaces';
-import type {GenericEventData} from '@polkadot/types';
-import privateKey from '../../substrate/privateKey';
-import {NftIdTuple, getChildren, getOwnedNfts, getCollectionProperties, getNftProperties, getResources} from './fetch';
-import chaiAsPromised from 'chai-as-promised';
-import chai from 'chai';
-import {getApiConnection} from '../../substrate/substrate-api';
-import {Context} from 'mocha';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-interface TxResult<T> {
-    success: boolean;
-    successData: T | null;
-}
-
-export enum Pallets {
-  Inflation = 'inflation',
-  RmrkCore = 'rmrkcore',
-  RmrkEquip = 'rmrkequip',
-  ReFungible = 'refungible',
-  Fungible = 'fungible',
-  NFT = 'nonfungible',
-  Scheduler = 'scheduler',
-  AppPromotion = 'apppromotion',
-}
-
-let modulesNames: any;
-export function getModuleNames(api: ApiPromise): string[] {
-  if (typeof modulesNames === 'undefined')
-    modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
-  return modulesNames;
-}
-
-export async function missingRequiredPallets(requiredPallets: string[]): Promise<string[]> {
-  const api = await getApiConnection();
-  const pallets = getModuleNames(api);
-  await api.disconnect();
-
-  return requiredPallets.filter(p => !pallets.includes(p));
-}
-
-export async function requirePallets(mocha: Context, requiredPallets: string[]) {
-  const missingPallets = await missingRequiredPallets(requiredPallets);
-
-  if (missingPallets.length > 0) {
-    const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;
-    const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
-    const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;
-
-    console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);
-
-    mocha.skip();
-  }
-}
-
-export function makeNftOwner(api: ApiPromise, owner: string | NftIdTuple): NftOwner {
-  const isNftSending = (typeof owner !== 'string');
-
-  if (isNftSending) {
-    return api.createType('RmrkTraitsNftAccountIdOrCollectionNftTuple', {
-      'CollectionAndNftTuple': owner,
-    });
-  } else {
-    const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-    return api.createType('RmrkTraitsNftAccountIdOrCollectionNftTuple', {
-      AccountId: privateKey(owner, Number(ss58Format)).address,
-    });
-  }
-}
-
-export async function isNftOwnedBy(
-  api: ApiPromise,
-  owner: string | NftIdTuple,
-  collectionId: number,
-  nftId: number,
-): Promise<boolean> {
-  if (typeof owner === 'string') {
-    return (await getOwnedNfts(api, owner, collectionId))
-      .find(ownedNftId => {
-        return ownedNftId === nftId;
-      }) !== undefined;
-  } else {
-    return (await getChildren(api, owner[0], owner[1]))
-      .find(child => {
-        return collectionId === child.collectionId.toNumber()
-                    && nftId === child.nftId.toNumber();
-      }) !== undefined;
-  }
-}
-
-export function isPropertyExists(
-  key: string,
-  value: string,
-  props: Property[],
-): boolean {
-  let isPropFound = false;
-  for (let i = 0; i < props.length && !isPropFound; i++) {
-    const fetchedProp = props[i];
-
-    isPropFound = fetchedProp.key.eq(key)
-                    && fetchedProp.value.eq(value);
-  }
-
-  return isPropFound;
-}
-
-export async function isCollectionPropertyExists(
-  api: ApiPromise,
-  collectionId: number,
-  key: string,
-  value: string,
-): Promise<boolean> {
-  const fetchedProps = await getCollectionProperties(api, collectionId);
-  return isPropertyExists(key, value, fetchedProps);
-}
-
-export async function isNftPropertyExists(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-  key: string,
-  value: string,
-): Promise<boolean> {
-  const fetchedProps = await getNftProperties(api, collectionId, nftId);
-  return isPropertyExists(key, value, fetchedProps);
-}
-
-export async function isNftChildOfAnother(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-  parentNft: NftIdTuple,
-): Promise<boolean> {
-  return (await getChildren(api, parentNft[0], parentNft[1]))
-    .find((childNft) => {
-      return childNft.collectionId.toNumber() === collectionId
-                && childNft.nftId.toNumber() === nftId;
-    }) !== undefined;
-}
-
-export function isTxResultSuccess(events: EventRecord[]): boolean {
-  let success = false;
-
-  events.forEach(({event: {method}}) => {
-    if (method == 'ExtrinsicSuccess') {
-      success = true;
-    }
-  });
-
-  return success;
-}
-
-export async function expectTxFailure(expectedError: RegExp, promise: Promise<any>) {
-  await expect(promise).to.be.rejectedWith(expectedError);
-}
-
-export function extractTxResult<T>(
-  events: EventRecord[],
-  expectSection: string,
-  expectMethod: string,
-  extractAction: (data: any) => T,
-): TxResult<T> {
-  let success = false;
-  let successData = null;
-  events.forEach(({event: {data, method, section}}) => {
-    if (method == 'ExtrinsicSuccess') {
-      success = true;
-    } else if ((expectSection == section) && (expectMethod == method)) {
-      successData = extractAction(data);
-    }
-  });
-  const result: TxResult<T> = {
-    success,
-    successData,
-  };
-  return result;
-}
-
-export function extractRmrkCoreTxResult<T>(
-  events: EventRecord[],
-  expectMethod: string,
-  extractAction: (data: GenericEventData) => T,
-): TxResult<T> {
-  return extractTxResult(events, 'rmrkCore', expectMethod, extractAction);
-}
-
-export function extractRmrkEquipTxResult<T>(
-  events: EventRecord[],
-  expectMethod: string,
-  extractAction: (data: GenericEventData) => T,
-): TxResult<T> {
-  return extractTxResult(events, 'rmrkEquip', expectMethod, extractAction);
-}
-
-export async function findResourceById(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-): Promise<ResourceInfo> {
-  const resources = await getResources(api, collectionId, nftId);
-
-  let resource = null;
-
-  for (let i = 0; i < resources.length; i++) {
-    const res = resources[i];
-
-    if (res.id.eq(resourceId)) {
-      resource = res;
-      break;
-    }
-  }
-
-  return resource!;
-}
-
-export async function getResourceById(
-  api: ApiPromise,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-): Promise<ResourceInfo> {
-  const resource = await findResourceById(
-    api,
-    collectionId,
-    nftId,
-    resourceId,
-  );
-
-  expect(resource !== null, 'Error: resource was not found').to.be.true;
-
-  return resource!;
-}
-
-export function checkResourceStatus(
-  resource: ResourceInfo,
-  expectedStatus: 'pending' | 'added',
-) {
-  expect(resource.pending.isTrue, `Error: added resource should be ${expectedStatus}`)
-    .to.be.equal(expectedStatus === 'pending');
-}
deletedtests/src/.outdated/rmrk/util/tx.tsdiffbeforeafterboth
--- a/tests/src/.outdated/rmrk/util/tx.ts
+++ /dev/null
@@ -1,1132 +0,0 @@
-import {ApiPromise} from '@polkadot/api';
-import {Bytes, Option, u32, Vec} from '@polkadot/types-codec';
-import {
-  RmrkTraitsNftAccountIdOrCollectionNftTuple as NftOwner, RmrkTraitsPartEquippableList as EquippableList,
-  RmrkTraitsPartPartType as PartType, RmrkTraitsResourceBasicResource as BasicResource,
-  RmrkTraitsResourceComposableResource as ComposableResource, RmrkTraitsResourceResourceInfo as ResourceInfo, RmrkTraitsResourceSlotResource as SlotResource, RmrkTraitsTheme as Theme,
-} from '@polkadot/types/lookup';
-import {IKeyringPair} from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import '../../../interfaces/augment-api';
-import privateKey from '../../substrate/privateKey';
-import {executeTransaction} from '../../substrate/substrate-api';
-import {
-  getBase,
-  getCollection,
-  getCollectionsCount,
-  getEquippableList,
-  getNft,
-  getParts,
-  getResources, 
-  getResourcePriority, 
-  getTheme,
-  NftIdTuple,
-} from './fetch';
-import {
-  extractRmrkCoreTxResult,
-  extractRmrkEquipTxResult, isCollectionPropertyExists, isNftOwnedBy, isNftPropertyExists, isTxResultSuccess, makeNftOwner,
-  findResourceById, getResourceById, checkResourceStatus,
-} from './helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-export async function createCollection(
-  api: ApiPromise,
-  issuerUri: string,
-  metadata: string,
-  max: number | null,
-  symbol: string,
-): Promise<number> {
-  let collectionId = 0;
-
-  const oldCollectionCount = await getCollectionsCount(api);
-  const maxOptional = max ? max.toString() : null;
-  const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkCore.createCollection(metadata, maxOptional, symbol);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const collectionResult = extractRmrkCoreTxResult(events, 'CollectionCreated', (data) => {
-    return parseInt(data[1].toString(), 10);
-  });
-  expect(collectionResult.success, 'Error: unable to create a collection').to.be.true;
-
-  collectionId = collectionResult.successData!;
-
-  const newCollectionCount = await getCollectionsCount(api);
-  const collectionOption = await getCollection(api, collectionId);
-
-  expect(newCollectionCount).to.be.equal(oldCollectionCount + 1, 'Error: NFT collection count should increase');
-  expect(collectionOption.isSome, 'Error: unable to fetch created NFT collection').to.be.true;
-
-  const collection = collectionOption.unwrap();
-
-  expect(collection.metadata.toUtf8()).to.be.equal(metadata, 'Error: Invalid NFT collection metadata');
-  expect(collection.max.isSome).to.be.equal(max !== null, 'Error: Invalid NFT collection max');
-
-  if (collection.max.isSome) {
-    expect(collection.max.unwrap().toNumber()).to.be.equal(max, 'Error: Invalid NFT collection max');
-  }
-  expect(collection.symbol.toUtf8()).to.be.equal(symbol, "Error: Invalid NFT collection's symbol");
-  expect(collection.nftsCount.toNumber()).to.be.equal(0, "Error: NFT collection shoudn't have any tokens");
-  expect(collection.issuer.toString()).to.be.equal(issuer.address, 'Error: Invalid NFT collection issuer');
-
-  return collectionId;
-}
-
-export async function changeIssuer(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  newIssuer: string,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const alice = privateKey(issuerUri, Number(ss58Format));
-  const bob = privateKey(newIssuer, Number(ss58Format));
-
-  // This is only needed when RMRK uses `uniques` pallet by Parity
-  // let tx = api.tx.uniques.setAcceptOwnership(
-  //     api.createType('Option<u32>', collectionId)
-  // );
-  // let events = await executeTransaction(api, bob, tx);
-  // expect(isTxResultSuccess(events), 'Error: Unable to accept ownership').to.be.true;
-
-  const tx = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address);
-  const events = await executeTransaction(api, alice, tx);
-  const changeIssuerResult = extractRmrkCoreTxResult(events, 'IssuerChanged', (data) => {
-    return parseInt(data[2].toString(), 10);
-  });
-  expect(changeIssuerResult.success, 'Error: Unable to change NFT collection issuer').to.be.true;
-  expect(changeIssuerResult.successData!, 'Error: Invalid collection id after changing the issuer')
-    .to.be.eq(collectionId);
-
-  await getCollection(api, collectionId).then((collectionOption) => {
-    const collection = collectionOption.unwrap();
-    expect(collection.issuer.toString())
-      .to.be.deep.eq(bob.address, 'Error: Invalid NFT collection issuer');
-  });
-}
-
-export async function deleteCollection(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: string,
-): Promise<number> {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkCore.destroyCollection(collectionId);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const collectionTxResult = extractRmrkCoreTxResult(
-    events,
-    'CollectionDestroy',
-    (data) => {
-      return parseInt(data[1].toString(), 10);
-    },
-  );
-  expect(collectionTxResult.success, 'Error: Unable to delete NFT collection').to.be.true;
-
-  const collection = await getCollection(
-    api,
-    parseInt(collectionId, 10),
-  );
-  expect(collection.isEmpty, 'Error: NFT collection should be deleted').to.be.true;
-
-  return 0;
-}
-
-export async function negativeDeleteCollection(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: string,
-): Promise<number> {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkCore.destroyCollection(collectionId);
-  await expect(executeTransaction(api, issuer, tx)).to.be.rejected;
-
-  return 0;
-}
-
-export async function setNftProperty(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  key: string,
-  value: string,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const nftIdOpt = api.createType('Option<u32>', nftId);
-  const tx = api.tx.rmrkCore.setProperty(
-    collectionId,
-    nftIdOpt,
-    key,
-    value,
-  );
-  const events = await executeTransaction(api, issuer, tx);
-
-  const propResult = extractRmrkCoreTxResult(events, 'PropertySet', (data) => {
-    return {
-      collectionId: parseInt(data[0].toString(), 10),
-      nftId: data[1] as Option<u32>,
-      key: data[2] as Bytes,
-      value: data[3] as Bytes,
-    };
-  });
-
-  expect(propResult.success, 'Error: Unable to set NFT property').to.be.true;
-  const eventData = propResult.successData!;
-  const eventDescription = 'from set NFT property event';
-
-  expect(eventData.collectionId, 'Error: Invalid collection ID ' + eventDescription)
-    .to.be.equal(collectionId);
-
-  expect(eventData.nftId.eq(nftIdOpt), 'Error: Invalid NFT ID ' + eventDescription)
-    .to.be.true;
-
-  expect(eventData.key.eq(key), 'Error: Invalid property key ' + eventDescription)
-    .to.be.true;
-
-  expect(eventData.value.eq(value), 'Error: Invalid property value ' + eventDescription)
-    .to.be.true;
-
-  expect(
-    await isNftPropertyExists(api, collectionId, nftId, key, value),
-    'Error: NFT property is not found',
-  ).to.be.true;
-}
-
-export async function mintNft(
-  api: ApiPromise,
-  issuerUri: string,
-  ownerUri: string | null,
-  collectionId: number,
-  metadata: string,
-  recipientUri: string | null = null,
-  royalty: number | null = null,
-  transferable = true,
-  resources: {basic?: any, composable?: any, slot?: any}[] | null = null,
-): Promise<number> {
-  let nftId = 0;
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const owner = ownerUri ? privateKey(ownerUri, Number(ss58Format)).address : null;
-  const recipient = recipientUri ? privateKey(recipientUri, Number(ss58Format)).address : null;
-  const royaltyOptional = royalty ? royalty.toString() : null;
-
-  const actualOwnerUri = ownerUri ? ownerUri : issuerUri;
-  const actualOwnerAddress = ownerUri ? owner : issuer.address;
-
-  const collectionOpt = await getCollection(api, collectionId);
-
-  const tx = api.tx.rmrkCore.mintNft(
-    owner,
-    collectionId,
-    recipient,
-    royaltyOptional,
-    metadata,
-    transferable,
-    resources as any,
-  );
-
-  const events = await executeTransaction(api, issuer, tx);
-  const nftResult = extractRmrkCoreTxResult(events, 'NftMinted', (data) => {
-    return parseInt(data[2].toString(), 10);
-  });
-
-  expect(nftResult.success, 'Error: Unable to mint NFT').to.be.true;
-
-  const newCollectionNftsCount = (await getCollection(api, collectionId))
-    .unwrap()
-    .nftsCount
-    .toNumber();
-
-  const oldCollectionNftsCount = collectionOpt
-    .unwrap()
-    .nftsCount.toNumber();
-
-  expect(newCollectionNftsCount, 'Error: NFTs count should increase')
-    .to.be.equal(oldCollectionNftsCount + 1);
-
-  nftId = nftResult.successData!;
-
-  const nftOption = await getNft(api, collectionId, nftId);
-
-  expect(nftOption.isSome, 'Error: Unable to fetch created NFT').to.be.true;
-
-  const nft = nftOption.unwrap();
-
-  expect(nft.owner.isAccountId, 'Error: NFT owner should be some user').to.be.true;
-  expect(nft.owner.asAccountId.toString()).to.be.equal(actualOwnerAddress, 'Error: Invalid NFT owner');
-
-  const isOwnedInUniques = await isNftOwnedBy(api, actualOwnerUri, collectionId, nftId);
-  expect(isOwnedInUniques, `Error: created NFT is not actually owned by ${ownerUri}`)
-    .to.be.true;
-
-  if (recipient === null && royalty === null) {
-    expect(nft.royalty.isNone, 'Error: Invalid NFT recipient')
-      .to.be.true;
-  } else {
-    expect(nft.royalty.isSome, 'Error: NFT royalty not found')
-      .to.be.true;
-
-    const nftRoyalty = nft.royalty.unwrap();
-    expect(nftRoyalty.recipient.eq(recipient), 'Error: Invalid NFT recipient')
-      .to.be.true;
-
-    expect(nftRoyalty.amount.eq(royalty), 'Error: Invalid NFT royalty')
-      .to.be.true;
-  }
-
-  expect(nft.metadata.toUtf8()).to.be.equal(metadata, 'Error: Invalid NFT metadata');
-    
-  const nftResources = await getResources(api, collectionId, nftId);
-  if (resources == null) {
-    expect(nftResources, 'Error: Invalid NFT resources').to.be.empty;
-  } else {
-    expect(nftResources.length).to.be.equal(resources.length);
-
-    for (let i = 0; i < resources.length; i++) {
-      let successFindingResource = false;
-      const resource = resources[i];
-      // try to find the matching resource from the query
-      for (let j = 0; j < nftResources.length && !successFindingResource; j++) {
-        const nftResourceData = nftResources[j].toHuman();
-        expect(
-          Object.prototype.hasOwnProperty.call(nftResourceData, 'resource'),
-          `Error: Corrupted resource data on resource #${i}`,
-        ).to.be.true;
-        const nftResource = nftResourceData.resource!;
-                type NftResourceKey = keyof typeof nftResource;
-
-                let typedResource = null;
-                let typedNftResource = null;
-
-                if (resource.basic && Object.prototype.hasOwnProperty.call(nftResource, 'Basic')) {
-                  typedResource = resource.basic!;
-                  typedNftResource = nftResource['Basic' as NftResourceKey]!;
-                } else if (resource.composable && Object.prototype.hasOwnProperty.call(nftResource, 'Composable')) {
-                  typedResource = resource.composable!;
-                  typedNftResource = nftResource['Composable' as NftResourceKey]! as any;
-                  if (typedResource.parts != undefined && typedResource.parts.toString() != typedNftResource.parts.toString()
-                        || typedResource.base != typedNftResource.base && typedResource.base != undefined) {
-                    continue;
-                  }
-                } else if (resource.slot && Object.prototype.hasOwnProperty.call(nftResource, 'Slot')) {
-                  typedResource = resource.slot!;
-                  typedNftResource = nftResource['Slot' as NftResourceKey]! as any;
-                  if (typedResource.slot != typedNftResource.slot && typedResource.slot != undefined 
-                        || typedResource.base != typedNftResource.base && typedResource.base != undefined) {
-                    continue;
-                  }
-                } else {
-                  continue;
-                }
-
-                if (typedResource.src != typedNftResource.src 
-                    || typedResource.metadata != typedNftResource.metadata 
-                    || typedResource.thumb != typedNftResource.thumb
-                    || typedResource.license != typedNftResource.license
-                ) {
-                  continue;
-                }
-
-                // do final checks since this is now established to be the resource we seek
-                expect(nftResourceData.pending, `Error: Resource #${i} is pending`).to.be.false;
-                expect(nftResourceData.pendingRemoval, `Error: Resource #${i} is pending removal`).to.be.false;
-
-                // remove the matching resource from the resources we check
-                nftResources.splice(j, 1);
-                successFindingResource = true;
-      }
-
-      expect(successFindingResource, `Error: Couldn't find resource #${i}'s counterpart among the returned`).to.be.true;
-    }
-  }
-
-  return nftId;
-}
-
-export async function sendNft(
-  api: ApiPromise,
-  expectedStatus: 'pending' | 'sent',
-  originalOwnerUri: string,
-  collectionId: number,
-  nftId: number,
-  newOwner: string | NftIdTuple,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const originalOwner = privateKey(originalOwnerUri, Number(ss58Format));
-  const newOwnerObj = makeNftOwner(api, newOwner);
-
-  const nftBeforeSendingOpt = await getNft(api, collectionId, nftId);
-
-  const tx = api.tx.rmrkCore.send(collectionId, nftId, newOwnerObj);
-  const events = await executeTransaction(api, originalOwner, tx);
-
-  const sendResult = extractRmrkCoreTxResult(events, 'NFTSent', (data) => {
-    return {
-      dstOwner: data[1] as NftOwner,
-      collectionId: parseInt(data[2].toString(), 10),
-      nftId: parseInt(data[3].toString(), 10),
-    };
-  });
-
-  expect(sendResult.success, 'Error: Unable to send NFT').to.be.true;
-  const sendData = sendResult.successData!;
-
-  expect(sendData.dstOwner.eq(newOwnerObj), 'Error: Invalid target user (from event data)')
-    .to.be.true;
-
-  expect(sendData.collectionId)
-    .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)');
-
-  expect(sendData.nftId).to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)');
-
-  expect(nftBeforeSendingOpt.isSome, 'Error: Unable to fetch NFT before sending').to.be.true;
-
-  const nftBeforeSending = nftBeforeSendingOpt.unwrap();
-
-  const nftAfterSendingOpt = await getNft(api, collectionId, nftId);
-
-  expect(nftAfterSendingOpt.isSome, 'Error: Unable to fetch NFT after sending').to.be.true;
-
-  const nftAfterSending = nftAfterSendingOpt.unwrap();
-
-  const isOwnedByNewOwner = await isNftOwnedBy(api, newOwner, collectionId, nftId);
-  const isPending = expectedStatus === 'pending';
-
-  expect(
-    isOwnedByNewOwner,
-    `Error: The NFT should be owned by ${newOwner.toString()}`,
-  ).to.be.true;
-
-  expect(nftAfterSending.royalty.eq(nftBeforeSending.royalty), 'Error: Invalid NFT royalty after sending')
-    .to.be.true;
-
-  expect(nftAfterSending.metadata.eq(nftBeforeSending.metadata), 'Error: Invalid NFT metadata after sending')
-    .to.be.true;
-
-  expect(nftAfterSending.equipped.eq(nftBeforeSending.equipped), 'Error: Invalid NFT equipped status after sending')
-    .to.be.true;
-
-  expect(nftAfterSending.pending.eq(isPending), 'Error: Invalid NFT pending state')
-    .to.be.true;
-}
-
-export async function acceptNft(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  newOwner: string | [number, number],
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const newOwnerObj = makeNftOwner(api, newOwner);
-
-  const nftBeforeOpt = await getNft(api, collectionId, nftId);
-
-  const tx = api.tx.rmrkCore.acceptNft(collectionId, nftId, newOwnerObj);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const acceptResult = extractRmrkCoreTxResult(events, 'NFTAccepted', (data) => {
-    return {
-      recipient: data[1] as NftOwner,
-      collectionId: parseInt(data[2].toString(), 10),
-      nftId: parseInt(data[3].toString(), 10),
-    };
-  });
-
-  expect(acceptResult.success, 'Error: Unable to accept NFT').to.be.true;
-  const acceptData = acceptResult.successData!;
-
-  expect(acceptData.recipient.eq(newOwnerObj), 'Error: Invalid NFT recipient (from event data)')
-    .to.be.true;
-
-  expect(acceptData.collectionId)
-    .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)');
-
-  expect(acceptData.nftId)
-    .to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)');
-
-  const nftBefore = nftBeforeOpt.unwrap();
-
-  const isPendingBeforeAccept = nftBefore.pending.isTrue;
-
-  const nftAfter = (await getNft(api, collectionId, nftId)).unwrap();
-  const isPendingAfterAccept = nftAfter.pending.isTrue;
-
-  expect(isPendingBeforeAccept, 'Error: NFT should be pending to be accepted')
-    .to.be.true;
-
-  expect(isPendingAfterAccept, 'Error: NFT should NOT be pending after accept')
-    .to.be.false;
-
-  const isOwnedInUniques = await isNftOwnedBy(api, newOwner, collectionId, nftId);
-  expect(isOwnedInUniques, `Error: created NFT is not actually owned by ${newOwner.toString()}`)
-    .to.be.true;
-}
-
-export async function rejectNft(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const nftBeforeOpt = await getNft(api, collectionId, nftId);
-
-  const tx = api.tx.rmrkCore.rejectNft(collectionId, nftId);
-  const events = await executeTransaction(api, issuer, tx);
-  const rejectResult = extractRmrkCoreTxResult(events, 'NFTRejected', (data) => {
-    return {
-      collectionId: parseInt(data[1].toString(), 10),
-      nftId: parseInt(data[2].toString(), 10),
-    };
-  });
-
-  const rejectData = rejectResult.successData!;
-
-  expect(rejectData.collectionId)
-    .to.be.equal(collectionId, 'Error: Invalid collection ID (from event data)');
-
-  expect(rejectData.nftId)
-    .to.be.equal(nftId, 'Error: Invalid NFT ID (from event data)');
-
-  const nftBefore = nftBeforeOpt.unwrap();
-
-  const isPendingBeforeReject = nftBefore.pending.isTrue;
-
-  const nftAfter = await getNft(api, collectionId, nftId);
-
-  expect(isPendingBeforeReject, 'Error: NFT should be pending to be rejected')
-    .to.be.true;
-
-  expect(nftAfter.isNone, 'Error: NFT should be burned after reject')
-    .to.be.true;
-}
-
-export async function createBase(
-  api: ApiPromise,
-  issuerUri: string,
-  baseType: string,
-  symbol: string,
-  parts: object[],
-): Promise<number> {
-  let baseId = 0;
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const partTypes = api.createType('Vec<RmrkTraitsPartPartType>', parts) as Vec<PartType>;
-
-  const tx = api.tx.rmrkEquip.createBase(baseType, symbol, partTypes);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const baseResult = extractRmrkEquipTxResult(events, 'BaseCreated', (data) => {
-    return parseInt(data[1].toString(), 10);
-  });
-
-  expect(baseResult.success, 'Error: Unable to create Base')
-    .to.be.true;
-
-  baseId = baseResult.successData!;
-  const baseOptional = await getBase(api, baseId);
-
-  expect(baseOptional.isSome, 'Error: Unable to fetch created Base')
-    .to.be.true;
-
-  const base = baseOptional.unwrap();
-  const baseParts = await getParts(api, baseId);
-
-  expect(base.issuer.toString()).to.be.equal(issuer.address, 'Error: Invalid Base issuer');
-  expect(base.baseType.toUtf8()).to.be.equal(baseType, 'Error: Invalid Base type');
-  expect(base.symbol.toUtf8()).to.be.equal(symbol, 'Error: Invalid Base symbol');
-  expect(partTypes.eq(baseParts), 'Error: Received invalid base parts').to.be.true;
-
-  return baseId;
-}
-
-export async function setResourcePriorities(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  priorities: number[],
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const prioritiesVec = api.createType('Vec<u32>', priorities);
-  const tx = api.tx.rmrkCore.setPriority(collectionId, nftId, prioritiesVec);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const prioResult = extractRmrkCoreTxResult(events, 'PrioritySet', (data) => {
-    return {
-      collectionId: parseInt(data[0].toString(), 10),
-      nftId: parseInt(data[1].toString(), 10),
-    };
-  });
-
-  expect(prioResult.success, 'Error: Unable to set resource priorities').to.be.true;
-  const eventData = prioResult.successData!;
-
-  expect(eventData.collectionId)
-    .to.be.equal(collectionId, 'Error: Invalid collection ID (set priorities event data)');
-
-  expect(eventData.nftId).to.be.equal(nftId, 'Error: Invalid NFT ID (set priorities event data');
-
-  for (let i = 0; i < priorities.length; i++) {
-    const resourceId = priorities[i];
-
-    const fetchedPrio = await getResourcePriority(api, collectionId, nftId, resourceId);
-    expect(fetchedPrio).to.be.equal(i, 'Error: Invalid priorities are set');
-  }
-
-}
-
-export async function setEquippableList(
-  api: ApiPromise,
-  issuerUri: string,
-  baseId: number,
-  slotId: number,
-  equippableList: 'All' | 'Empty' | { 'Custom': number[] },
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const equippable = api.createType('RmrkTraitsPartEquippableList', equippableList) as EquippableList;
-
-  const tx = api.tx.rmrkEquip.equippable(baseId, slotId, equippable);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const equipListResult = extractRmrkEquipTxResult(events, 'EquippablesUpdated', (data) => {
-    return {
-      baseId: parseInt(data[0].toString(), 10),
-      slotId: parseInt(data[1].toString(), 10),
-    };
-  });
-
-  expect(equipListResult.success, 'Error: unable to update equippable list').to.be.true;
-  const updateEvent = equipListResult.successData!;
-
-  expect(updateEvent.baseId)
-    .to.be.equal(baseId, 'Error: invalid base ID from update equippable event');
-
-  expect(updateEvent.slotId)
-    .to.be.equal(slotId, 'Error: invalid base ID from update equippable event');
-
-  const fetchedEquippableList = await getEquippableList(api, baseId, slotId);
-
-  expect(fetchedEquippableList, 'Error: unable to fetch equippable list').to.be.not.null;
-  if (fetchedEquippableList) {
-    expect(fetchedEquippableList)
-      .to.be.deep.equal(equippableList, 'Error: invalid equippable list was set');
-  }
-}
-
-export async function addTheme(
-  api: ApiPromise,
-  issuerUri: string,
-  baseId: number,
-  themeObj: object,
-  filterKeys: string[] | null = null,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const theme = api.createType('RmrkTraitsTheme', themeObj) as Theme;
-
-  const tx = api.tx.rmrkEquip.themeAdd(baseId, theme);
-  const events = await executeTransaction(api, issuer, tx);
-
-  expect(isTxResultSuccess(events), 'Error: Unable to add Theme').to.be.true;
-
-  const fetchedThemeOpt = await getTheme(api, baseId, theme.name.toUtf8(), null);
-
-  expect(fetchedThemeOpt.isSome, 'Error: Unable to fetch theme').to.be.true;
-
-  const fetchedTheme = fetchedThemeOpt.unwrap();
-
-  expect(theme.name.eq(fetchedTheme.name), 'Error: Invalid theme name').to.be.true;
-
-  for (let i = 0; i < theme.properties.length; i++) {
-    const property = theme.properties[i];
-    const propertyKey = property.key.toUtf8();
-
-    const propertyFoundCount = fetchedTheme.properties.filter((fetchedProp) => property.key.eq(fetchedProp.key)).length;
-
-    expect(propertyFoundCount > 1, `Error: Too many properties with key ${propertyKey} found`)
-      .to.be.false;
-
-    if (filterKeys) {
-      const isFiltered = fetchedTheme.properties.find((fetchedProp) => fetchedProp.key.eq(property.key)) === undefined;
-
-      if (isFiltered) {
-        expect(propertyFoundCount === 0, `Error: Unexpected filtered key ${propertyKey}`)
-          .to.be.true;
-        continue;
-      }
-    }
-
-    expect(propertyFoundCount === 1, `Error: The property with key ${propertyKey} is not found`)
-      .to.be.true;
-  }
-}
-
-export async function lockCollection(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  max = 0,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkCore.lockCollection(collectionId);
-  const events = await executeTransaction(api, issuer, tx);
-  const lockResult = extractRmrkCoreTxResult(events, 'CollectionLocked', (data) => {
-    return parseInt(data[1].toString(), 10);
-  });
-  expect(lockResult.success, 'Error: Unable to lock a collection').to.be.true;
-  expect(lockResult.successData!, 'Error: Invalid collection was locked')
-    .to.be.eq(collectionId);
-
-  await getCollection(api, collectionId).then((collectionOption) => {
-    const collection = collectionOption.unwrap();
-    expect(collection.max.unwrap().toNumber()).to.be.equal(max);
-  });
-}
-
-export async function setPropertyCollection(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  key: string,
-  value: string,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const alice = privateKey(issuerUri, Number(ss58Format));
-
-  const tx = api.tx.rmrkCore.setProperty(collectionId, null, key, value);
-  const events = await executeTransaction(api, alice, tx);
-  const propResult = extractRmrkCoreTxResult(events, 'PropertySet', (data) => {
-    return {
-      collectionId: parseInt(data[0].toString(), 10),
-      nftId: data[1] as Option<u32>,
-      key: data[2] as Bytes,
-      value: data[3] as Bytes,
-    };
-  });
-
-  expect(propResult.success, 'Error: Unable to set collection property').to.be.true;
-  const eventData = propResult.successData!;
-  const eventDescription = 'from set collection property event';
-
-  expect(eventData.collectionId, 'Error: Invalid collection ID ' + eventDescription)
-    .to.be.equal(collectionId);
-
-  expect(eventData.nftId.eq(null), 'Error: Unexpected NFT ID ' + eventDescription)
-    .to.be.true;
-
-  expect(eventData.key.eq(key), 'Error: Invalid property key ' + eventDescription)
-    .to.be.true;
-
-  expect(eventData.value.eq(value), 'Error: Invalid property value ' + eventDescription)
-    .to.be.true;
-
-  expect(await isCollectionPropertyExists(api, collectionId, key, value))
-    .to.be.true;
-}
-
-export async function burnNft(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const maxBurns = 10;
-  const tx = api.tx.rmrkCore.burnNft(collectionId, nftId, maxBurns);
-  const events = await executeTransaction(api, issuer, tx);
-  const burnResult = extractRmrkCoreTxResult(events, 'NFTBurned', (data) => {
-    return parseInt(data[1].toString(), 10);
-  });
-
-  expect(burnResult.success, 'Error: Unable to burn an NFT').to.be.true;
-  expect(burnResult.successData!, 'Error: Invalid NFT was burned')
-    .to.be.eq(nftId);
-
-  const nftBurned = await getNft(api, collectionId, nftId);
-  expect(nftBurned.isSome).to.be.false;
-}
-
-export async function acceptNftResource(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const tx = api.tx.rmrkCore.acceptResource(
-    collectionId,
-    nftId,
-    resourceId,
-  );
-
-  const events = await executeTransaction(api, issuer, tx);
-  const acceptResult = extractRmrkCoreTxResult(events, 'ResourceAccepted', (data) => {
-    return {
-      nftId: parseInt(data[0].toString(), 10),
-      resourceId: parseInt(data[1].toString(), 10),
-    };
-  });
-
-  expect(acceptResult.success, 'Error: Unable to accept a resource').to.be.true;
-  expect(acceptResult.successData!.nftId, 'Error: Invalid NFT ID while accepting a resource')
-    .to.be.eq(nftId);
-  expect(acceptResult.successData!.resourceId, 'Error: Invalid resource ID while accepting a resource')
-    .to.be.eq(resourceId);
-
-  const resource = await getResourceById(api, collectionId, nftId, resourceId);
-  checkResourceStatus(resource, 'added');
-}
-
-async function executeResourceCreation(
-  api: ApiPromise,
-  issuer: IKeyringPair,
-  tx: any,
-  collectionId: number,
-  nftId: number,
-  expectedStatus: 'pending' | 'added',
-): Promise<ResourceInfo> {
-  const events = await executeTransaction(api, issuer, tx);
-
-  const resourceResult = extractRmrkCoreTxResult(events, 'ResourceAdded', (data) => {
-    return parseInt(data[1].toString(), 10);
-  });
-  expect(resourceResult.success, 'Error: Unable to add resource').to.be.true;
-  const resourceId = resourceResult.successData!;
-
-  const resource = await getResourceById(api, collectionId, nftId, resourceId);
-  checkResourceStatus(resource, expectedStatus);
-
-  return resource;
-}
-
-export async function addNftBasicResource(
-  api: ApiPromise,
-  issuerUri: string,
-  expectedStatus: 'pending' | 'added',
-  collectionId: number,
-  nftId: number,
-  src: string | null,
-  metadata: string | null,
-  license: string | null,
-  thumb: string | null,
-): Promise<number> {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const basicResource = api.createType('RmrkTraitsResourceBasicResource', {
-    src: src,
-    metadata: metadata,
-    license: license,
-    thumb: thumb,
-  }) as BasicResource;
-
-  const tx = api.tx.rmrkCore.addBasicResource(
-    collectionId,
-    nftId,
-    basicResource,
-  );
-
-  const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus);
-
-  // FIXME A workaround. It seems it is a PolkadotJS bug.
-  // All of the following are `false`.
-  //
-  // console.log('>>> basic:', resource.resource.isBasic);
-  // console.log('>>> composable:', resource.resource.isComposable);
-  // console.log('>>> slot:', resource.resource.isSlot);
-  const resourceJson = resource.resource.toHuman() as any;
-
-  expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Basic'), 'Error: Expected basic resource type')
-    .to.be.true;
-
-  const recvBasicRes = resourceJson['Basic'];
-
-  expect(recvBasicRes.src, 'Error: Invalid basic resource src')
-    .to.be.eq(src);
-  expect(recvBasicRes.metadata, 'Error: basic first resource metadata')
-    .to.be.eq(metadata);
-  expect(recvBasicRes.license, 'Error: basic first resource license')
-    .to.be.eq(license);
-  expect(recvBasicRes.thumb, 'Error: basic first resource thumb')
-    .to.be.eq(thumb);
-
-  return resource.id.toNumber();
-}
-
-export async function addNftComposableResource(
-  api: ApiPromise,
-  issuerUri: string,
-  expectedStatus: 'pending' | 'added',
-  collectionId: number,
-  nftId: number,
-  parts: number[],
-  baseId: number,
-  src: string | null,
-  metadata: string | null,
-  license: string | null,
-  thumb: string | null,
-): Promise<number> {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const composableResource = api.createType('RmrkTraitsResourceComposableResource', {
-    parts: parts, // api.createType('Vec<u32>', parts),
-    base: baseId,
-    src: src,
-    metadata: metadata,
-    license: license,
-    thumb: thumb,
-  }) as ComposableResource;
-
-  const tx = api.tx.rmrkCore.addComposableResource(
-    collectionId,
-    nftId,
-    composableResource,
-  );
-
-  const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus);
-
-  // FIXME A workaround. It seems it is a PolkadotJS bug.
-  // All of the following are `false`.
-  //
-  // console.log('>>> basic:', resource.resource.isBasic);
-  // console.log('>>> composable:', resource.resource.isComposable);
-  // console.log('>>> slot:', resource.resource.isSlot);
-  const resourceJson = resource.resource.toHuman() as any;
-
-  expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Composable'), 'Error: Expected composable resource type')
-    .to.be.true;
-
-  const recvComposableRes = resourceJson['Composable'];
-
-  expect(recvComposableRes.parts.toString(), 'Error: Invalid composable resource parts')
-    .to.be.eq(parts.toString());
-  expect(recvComposableRes.base, 'Error: Invalid composable resource base id')
-    .to.be.eq(baseId.toString());
-  expect(recvComposableRes.src, 'Error: Invalid composable resource src')
-    .to.be.eq(src);
-  expect(recvComposableRes.metadata, 'Error: Invalid composable resource metadata')
-    .to.be.eq(metadata);
-  expect(recvComposableRes.license, 'Error: Invalid composable resource license')
-    .to.be.eq(license);
-  expect(recvComposableRes.thumb, 'Error: Invalid composable resource thumb')
-    .to.be.eq(thumb);
-
-  return resource.id.toNumber();
-}
-
-export async function addNftSlotResource(
-  api: ApiPromise,
-  issuerUri: string,
-  expectedStatus: 'pending' | 'added',
-  collectionId: number,
-  nftId: number,
-  baseId: number,
-  slotId: number,
-  src: string | null,
-  metadata: string | null,
-  license: string | null,
-  thumb: string | null,
-): Promise<number>  {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const slotResource = api.createType('RmrkTraitsResourceSlotResource', {
-    base: baseId,
-    src: src,
-    metadata,
-    slot: slotId,
-    license: license,
-    thumb: thumb,
-  }) as SlotResource;
-
-  const tx = api.tx.rmrkCore.addSlotResource(
-    collectionId,
-    nftId,
-    slotResource,
-  );
-
-  const resource = await executeResourceCreation(api, issuer, tx, collectionId, nftId, expectedStatus);
-
-  // FIXME A workaround. It seems it is a PolkadotJS bug.
-  // All of the following are `false`.
-  //
-  // console.log('>>> basic:', resource.resource.isBasic);
-  // console.log('>>> composable:', resource.resource.isComposable);
-  // console.log('>>> slot:', resource.resource.isSlot);
-  const resourceJson = resource.resource.toHuman() as any;
-
-  expect(Object.prototype.hasOwnProperty.call(resourceJson, 'Slot'), 'Error: Expected slot resource type')
-    .to.be.true;
-
-  const recvSlotRes = resourceJson['Slot'];
-
-  expect(recvSlotRes.base, 'Error: Invalid slot resource base id')
-    .to.be.eq(baseId.toString());
-  expect(recvSlotRes.slot, 'Error: Invalid slot resource slot id')
-    .to.be.eq(slotId.toString());
-  expect(recvSlotRes.src, 'Error: Invalid slot resource src')
-    .to.be.eq(src);
-  expect(recvSlotRes.metadata, 'Error: Invalid slot resource metadata')
-    .to.be.eq(metadata);
-  expect(recvSlotRes.license, 'Error: Invalid slot resource license')
-    .to.be.eq(license);
-  expect(recvSlotRes.thumb, 'Error: Invalid slot resource thumb')
-    .to.be.eq(thumb);
-
-  return resource.id.toNumber();
-}
-
-export async function equipNft(
-  api: ApiPromise,
-  issuerUri: string,
-  item: NftIdTuple,
-  equipper: NftIdTuple,
-  resource: number,
-  base: number,
-  slot: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkEquip.equip(item, equipper, resource, base, slot);
-  const events = await executeTransaction(api, issuer, tx);
-  const equipResult = extractRmrkEquipTxResult(events, 'SlotEquipped', (data) => {
-    return {
-      item_collection: parseInt(data[0].toString(), 10),
-      item_nft: parseInt(data[1].toString(), 10),
-      base_id: parseInt(data[2].toString(), 10),
-      slot_id: parseInt(data[3].toString(), 10),
-    };
-  });
-  expect(equipResult.success, 'Error: Unable to equip an item').to.be.true;
-  expect(equipResult.successData!.item_collection, 'Error: Invalid item collection id')
-    .to.be.eq(item[0]);
-  expect(equipResult.successData!.item_nft, 'Error: Invalid item NFT id')
-    .to.be.eq(item[1]);
-  expect(equipResult.successData!.base_id, 'Error: Invalid base id')
-    .to.be.eq(base);
-  expect(equipResult.successData!.slot_id, 'Error: Invalid slot id')
-    .to.be.eq(slot);
-}
-
-export async function unequipNft(
-  api: ApiPromise,
-  issuerUri: string,
-  item: any,
-  equipper: any,
-  resource: number,
-  base: number,
-  slot: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-  const tx = api.tx.rmrkEquip.equip(item, equipper, resource, base, slot);
-  const events = await executeTransaction(api, issuer, tx);
-
-  const unEquipResult = extractRmrkEquipTxResult(
-    events,
-    'SlotUnequipped',
-    (data) => {
-      return {
-        item_collection: parseInt(data[0].toString(), 10),
-        item_nft: parseInt(data[1].toString(), 10),
-        base_id: parseInt(data[2].toString(), 10),
-        slot_id: parseInt(data[3].toString(), 10),
-      };
-    },
-  );
-
-  expect(unEquipResult.success, 'Error: Unable to unequip an item').to.be.true;
-  expect(unEquipResult.successData!.item_collection, 'Error: Invalid item collection id')
-    .to.be.eq(item[0]);
-  expect(unEquipResult.successData!.item_nft, 'Error: Invalid item NFT id')
-    .to.be.eq(item[1]);
-  expect(unEquipResult.successData!.base_id, 'Error: Invalid base id')
-    .to.be.eq(base);
-  expect(unEquipResult.successData!.slot_id, 'Error: Invalid slot id')
-    .to.be.eq(slot);
-}
-
-export async function removeNftResource(
-  api: ApiPromise,
-  expectedStatus: 'pending' | 'removed',
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const tx = api.tx.rmrkCore.removeResource(collectionId, nftId, resourceId);
-  const events = await executeTransaction(api, issuer, tx);
-  const removeResult = extractRmrkCoreTxResult(events, 'ResourceRemoval', (data) => {
-    return {
-      nftId: parseInt(data[0].toString(), 10),
-      resourceId: parseInt(data[1].toString(), 10),
-    };
-  });
-  expect(removeResult.success, 'Error: Unable to remove a resource').to.be.true;
-  expect(removeResult.successData!.nftId, 'Error: Invalid NFT Id while removing a resource')
-    .to.be.eq(nftId);
-  expect(removeResult.successData!.resourceId, 'Error: Invalid resource Id while removing a resource')
-    .to.be.eq(resourceId);
-
-  const afterDeleting = await findResourceById(api, collectionId, nftId, resourceId);
-
-  if (expectedStatus === 'pending') {
-    expect(afterDeleting).not.to.be.null;
-    expect(afterDeleting?.pendingRemoval.isTrue).to.be.equal(true);
-  } else {
-    expect(afterDeleting).to.be.null;
-  }
-}
-
-export async function acceptResourceRemoval(
-  api: ApiPromise,
-  issuerUri: string,
-  collectionId: number,
-  nftId: number,
-  resourceId: number,
-) {
-  const ss58Format = api.registry.getChainProperties()!.toJSON().ss58Format;
-  const issuer = privateKey(issuerUri, Number(ss58Format));
-
-  const tx = api.tx.rmrkCore.acceptResourceRemoval(collectionId, nftId, resourceId);
-  const events = await executeTransaction(api, issuer, tx);
-  const acceptResult = extractRmrkCoreTxResult(events, 'ResourceRemovalAccepted', (data) => {
-    return {
-      nftId: parseInt(data[0].toString(), 10),
-      resourceId: parseInt(data[1].toString(), 10),
-    };
-  });
-  expect(acceptResult.success, 'Error: Unable to accept a resource').to.be.true;
-  expect(acceptResult.successData!.nftId, 'Error: Invalid NFT Id while accepting a resource')
-    .to.be.eq(nftId);
-  expect(acceptResult.successData!.resourceId, 'Error: Invalid resource Id while accepting a resource')
-    .to.be.eq(resourceId);
-
-  const afterDeleting = await findResourceById(api, collectionId, nftId, resourceId);
-  expect(afterDeleting, 'Error: resource deleting failed').to.be.null;
-}
modifiedtests/src/.outdated/substrate/substrate-api.tsdiffbeforeafterboth
--- a/tests/src/.outdated/substrate/substrate-api.ts
+++ b/tests/src/.outdated/substrate/substrate-api.ts
@@ -53,7 +53,6 @@
     rpc: {
       unique: defs.unique.rpc,
       appPromotion: defs.appPromotion.rpc,
-      rmrk: defs.rmrk.rpc,
       eth: {
         feeHistory: {
           description: 'Dummy',
modifiedtests/src/interfaces/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/definitions.ts
+++ b/tests/src/interfaces/definitions.ts
@@ -16,6 +16,5 @@
 
 export {default as unique} from './unique/definitions';
 export {default as appPromotion} from './appPromotion/definitions';
-export {default as rmrk} from './rmrk/definitions';
 export {default as povinfo} from './povinfo/definitions';
 export {default as default} from './default/definitions';
deletedtests/src/interfaces/rmrk/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/definitions.ts
+++ /dev/null
@@ -1,118 +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/>.
-
-type RpcParam = {
-  name: string;
-  type: string;
-  isOptional?: true;
-};
-
-const atParam = {name: 'at', type: 'Hash', isOptional: true};
-const fn = (description: string, params: RpcParam[], type: string) => ({
-  description,
-  params: [...params, atParam],
-  type,
-});
-
-export default {
-  types: {},
-  rpc: {
-    lastCollectionIdx: fn('Get the latest created collection id', [], 'u32'),
-    collectionById: fn('Get collection by id', [{name: 'id', type: 'u32'}], 'Option<RmrkTraitsCollectionCollectionInfo>'),
-    nftById: fn(
-      'Get NFT by collection id and NFT id',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'nftId', type: 'u32'},
-      ],
-      'Option<RmrkTraitsNftNftInfo>',
-    ),
-    accountTokens: fn(
-      'Get tokens owned by an account in a collection',
-      [
-        {name: 'accountId', type: 'AccountId32'},
-        {name: 'collectionId', type: 'u32'},
-      ],
-      'Vec<u32>',
-    ),
-    nftChildren: fn(
-      'Get NFT children',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'nftId', type: 'u32'},
-      ],
-      'Vec<RmrkTraitsNftNftChild>',
-    ),
-    collectionProperties: fn(
-      'Get collection properties',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'filterKeys', type: 'Vec<String>', isOptional: true},
-      ],
-      'Vec<RmrkTraitsPropertyPropertyInfo>',
-    ),
-    nftProperties: fn(
-      'Get NFT properties',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'nftId', type: 'u32'},
-        {name: 'filterKeys', type: 'Vec<String>', isOptional: true},
-      ],
-      'Vec<RmrkTraitsPropertyPropertyInfo>',
-    ),
-    nftResources: fn(
-      'Get NFT resources',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'nftId', type: 'u32'},
-      ],
-      'Vec<RmrkTraitsResourceResourceInfo>',
-    ),
-    nftResourcePriority: fn(
-      'Get NFT resource priorities',
-      [
-        {name: 'collectionId', type: 'u32'},
-        {name: 'nftId', type: 'u32'},
-        {name: 'resourceId', type: 'u32'},
-      ],
-      'Option<u32>',
-    ),
-    base: fn(
-      'Get base info',
-      [{name: 'baseId', type: 'u32'}],
-      'Option<RmrkTraitsBaseBaseInfo>',
-    ),
-    baseParts: fn(
-      'Get all Base\'s parts',
-      [{name: 'baseId', type: 'u32'}],
-      'Vec<RmrkTraitsPartPartType>',
-    ),
-    themeNames: fn(
-      'Get Base\'s theme names',
-      [{name: 'baseId', type: 'u32'}],
-      'Vec<Bytes>',
-    ),
-    themes: fn(
-      'Get Theme\'s keys values',
-      [
-        {name: 'baseId', type: 'u32'},
-        {name: 'themeName', type: 'String'},
-        {name: 'keys', type: 'Option<Vec<String>>'},
-      ],
-      'Option<RmrkTraitsTheme>',
-    ),
-  },
-};
deletedtests/src/interfaces/rmrk/index.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export * from './types';
deletedtests/src/interfaces/rmrk/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
-/* eslint-disable */
-
-export type PHANTOM_RMRK = 'rmrk';
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -64,7 +64,6 @@
 
       const refungible = 'refungible';
       const foreignAssets = 'foreignassets';
-      const _rmrkPallets = ['rmrkcore', 'rmrkequip'];
       const appPromotion = 'apppromotion';
       const collatorSelection = ['authorship', 'session', 'collatorselection', 'identity'];
       const testUtils = 'testutils';
modifiedtests/src/util/index.tsdiffbeforeafterboth
--- a/tests/src/util/index.ts
+++ b/tests/src/util/index.ts
@@ -106,8 +106,6 @@
 
 export enum Pallets {
   Inflation = 'inflation',
-  RmrkCore = 'rmrkcore',
-  RmrkEquip = 'rmrkequip',
   ReFungible = 'refungible',
   Fungible = 'fungible',
   NFT = 'nonfungible',
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -106,7 +106,6 @@
         unique: defs.unique.rpc,
         appPromotion: defs.appPromotion.rpc,
         povinfo: defs.povinfo.rpc,
-        rmrk: defs.rmrk.rpc,
         eth: {
           feeHistory: {
             description: 'Dummy',