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

difftreelog

Merge branch 'develop' into doc/architectural-changes

Farhad Hakimov2022-07-22parents: #5b3cd06 #26e74f7.patch.diff
in: master

80 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5731,7 +5731,7 @@
 
 [[package]]
 name = "pallet-common"
-version = "0.1.0"
+version = "0.1.2"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -5953,7 +5953,7 @@
 
 [[package]]
 name = "pallet-fungible"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -6198,7 +6198,7 @@
 
 [[package]]
 name = "pallet-nonfungible"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -6320,13 +6320,16 @@
 
 [[package]]
 name = "pallet-refungible"
-version = "0.1.0"
+version = "0.1.2"
 dependencies = [
+ "ethereum",
+ "evm-coder",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
  "pallet-common",
  "pallet-evm",
+ "pallet-evm-coder-substrate",
  "pallet-structure",
  "parity-scale-codec 3.1.5",
  "scale-info",
@@ -12374,7 +12377,7 @@
 
 [[package]]
 name = "uc-rpc"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "anyhow",
  "jsonrpsee",
@@ -12733,7 +12736,7 @@
 
 [[package]]
 name = "up-data-structs"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "derivative",
  "frame-support",
@@ -12751,7 +12754,7 @@
 
 [[package]]
 name = "up-rpc"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "pallet-common",
  "pallet-evm",
modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,10 @@
 NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs
 NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json
 
+REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs
+RENFUNGIBLE_EVM_ABI=./tests/src/eth/reFungibleAbi.json
+RENFUNGIBLE_TOKEN_EVM_ABI=./tests/src/eth/reFungibleTokenAbi.json
+
 CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/
 CONTRACT_HELPERS_ABI=./tests/src/eth/util/contractHelpersAbi.json
 
@@ -21,7 +25,7 @@
 TESTS_API=./tests/src/eth/api/
 
 .PHONY: regenerate_solidity
-regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol CollectionHelpers.sol
+regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol
 
 UniqueFungible.sol:
 	PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
@@ -30,6 +34,10 @@
 UniqueNFT.sol:
 	PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
 	PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
+	
+UniqueRefungibleToken.sol:
+	PACKAGE=pallet-refungible NAME=erc_token::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
+	PACKAGE=pallet-refungible NAME=erc_token::gen_impl OUTPUT=$(REFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
 
 ContractHelpers.sol:
 	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
@@ -47,6 +55,10 @@
 	INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw ./.maintain/scripts/compile_stub.sh
 	INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh
 
+UniqueRefungibleToken: UniqueRefungibleToken.sol
+	INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungibleToken.raw ./.maintain/scripts/compile_stub.sh
+	INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(RENFUNGIBLE_TOKEN_EVM_ABI) ./.maintain/scripts/generate_abi.sh
+
 ContractHelpers: ContractHelpers.sol
 	INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw ./.maintain/scripts/compile_stub.sh
 	INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_ABI) ./.maintain/scripts/generate_abi.sh
@@ -55,7 +67,7 @@
 	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelpers.raw ./.maintain/scripts/compile_stub.sh
 	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh
 
-evm_stubs: UniqueFungible UniqueNFT ContractHelpers CollectionHelpers
+evm_stubs: UniqueFungible UniqueNFT UniqueRefungibleToken ContractHelpers CollectionHelpers
 
 .PHONY: _bench
 _bench:
addedclient/rpc/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/client/rpc/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+    This was an internal request to improve the web interface and support fractionalization event. 
+ 
\ No newline at end of file
modifiedclient/rpc/Cargo.tomldiffbeforeafterboth
--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "uc-rpc"
-version = "0.1.0"
+version = "0.1.1"
 license = "GPLv3"
 edition = "2021"
 
modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -77,6 +77,15 @@
 		at: Option<BlockHash>,
 	) -> Result<Option<CrossAccountId>>;
 
+	/// Returns 10 tokens owners in no particular order.
+	#[method(name = "unique_tokenOwners")]
+	fn token_owners(
+		&self,
+		collection: CollectionId,
+		token: TokenId,
+		at: Option<BlockHash>,
+	) -> Result<Vec<CrossAccountId>>;
+
 	/// Get the topmost token owner in the hierarchy of a possibly nested token.
 	#[method(name = "unique_topmostTokenOwner")]
 	fn topmost_token_owner(
@@ -510,6 +519,7 @@
 	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);
 	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);
 	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128>, unique_api);
+	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);
 }
 
 #[allow(deprecated)]
addedpallets/common/CHANGELOG.MDdiffbeforeafterboth
--- /dev/null
+++ b/pallets/common/CHANGELOG.MD
@@ -0,0 +1,10 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.2] - 2022-07-20
+
+### Fixed
+
+-   Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid
+    mutability modifiers, causing invalid stub/abi generation.
addedpallets/common/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/common/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+    This was an internal request to improve the web interface and support fractionalization event. 
+
+ 
\ No newline at end of file
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-common"
-version = "0.1.0"
+version = "0.1.2"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -1,3 +1,5 @@
+//! Module with interfaces for dispatching collections.
+
 use frame_support::{
 	dispatch::{
 		DispatchResultWithPostInfo, PostDispatchInfo, Weight, DispatchErrorWithPostInfo,
@@ -20,7 +22,10 @@
 	// submit_logs is measured as part of collection pallets
 }
 
-/// Helper function to implement substrate calls for common collection methods
+/// Helper function to implement substrate calls for common collection methods.
+///
+/// * `collection` - The collection on which to call the method.
+/// * `call` - The function in which to call the corresponding method from [`CommonCollectionOperations`].
 pub fn dispatch_tx<
 	T: Config,
 	C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,
@@ -64,15 +69,31 @@
 	result
 }
 
+/// Interface for working with different collections through the dispatcher.
 pub trait CollectionDispatch<T: Config> {
+	/// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).
+	///
+	/// * `sender` - The user who will become the owner of the collection.
+	/// * `data` - Description of the created collection.
 	fn create(
 		sender: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> DispatchResult;
+
+	/// Delete the collection.
+	///
+	/// * `sender` - The owner of the collection.
+	/// * `handle` - Collection handle.
 	fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;
 
+	/// Get a specialized collection from the handle.
+	///
+	/// * `handle` - Collection handle.
 	fn dispatch(handle: CollectionHandle<T>) -> Self;
+
+	/// Get the collection handle for the corresponding implementation.
 	fn into_inner(self) -> CollectionHandle<T>;
 
+	/// Get the implementation of [`CommonCollectionOperations`].
 	fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;
 }
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! This module contains the implementation of pallet methods for evm.
+
 use evm_coder::{
 	solidity_interface, solidity, ToLog,
 	types::*,
@@ -29,29 +31,40 @@
 
 use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
 
+/// Events for ethereum collection helper.
 #[derive(ToLog)]
 pub enum CollectionHelpersEvents {
+	/// The collection has been created.
 	CollectionCreated {
+		/// Collection owner.
 		#[indexed]
 		owner: address,
+
+		/// Collection ID.
 		#[indexed]
 		collection_id: address,
 	},
 }
 
 /// Does not always represent a full collection, for RFT it is either
-/// collection (Implementing ERC721), or specific collection token (Implementing ERC20)
+/// collection (Implementing ERC721), or specific collection token (Implementing ERC20).
 pub trait CommonEvmHandler {
 	const CODE: &'static [u8];
 
+	/// Call precompiled handle.
 	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;
 }
 
+/// @title A contract that allows you to work with collections.
 #[solidity_interface(name = "Collection")]
 impl<T: Config> CollectionHandle<T>
 where
 	T::AccountId: From<[u8; 32]>,
 {
+	/// Set collection property.
+	///
+	/// @param key Property key.
+	/// @param value Propery value.
 	fn set_collection_property(
 		&mut self,
 		caller: caller,
@@ -68,6 +81,9 @@
 			.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// Delete collection property.
+	///
+	/// @param key Property key.
 	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let key = <Vec<u8>>::from(key)
@@ -77,7 +93,12 @@
 		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)
 	}
 
-	/// Throws error if key not found
+	/// Get collection property.
+	///
+	/// @dev Throws error if key not found.
+	///
+	/// @param key Property key.
+	/// @return bytes The property corresponding to the key.
 	fn collection_property(&self, key: string) -> Result<bytes> {
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -89,6 +110,11 @@
 		Ok(prop.to_vec())
 	}
 
+	/// Set the sponsor of the collection.
+	///
+	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	///
+	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
 	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 
@@ -98,6 +124,9 @@
 		save(self)
 	}
 
+	/// Collection sponsorship confirmation.
+	///
+	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
 	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		if !self
@@ -109,6 +138,16 @@
 		save(self)
 	}
 
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Name of the limit. Valid names:
+	/// 	"accountTokenOwnershipLimit",
+	/// 	"sponsoredDataSize",
+	/// 	"sponsoredDataRateLimit",
+	/// 	"tokenLimit",
+	/// 	"sponsorTransferTimeout",
+	/// 	"sponsorApproveTimeout"
+	/// @param value Value of the limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
 	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -145,6 +184,13 @@
 		save(self)
 	}
 
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Name of the limit. Valid names:
+	/// 	"ownerCanTransfer",
+	/// 	"ownerCanDestroy",
+	/// 	"transfersEnabled"
+	/// @param value Value of the limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
 	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -172,11 +218,18 @@
 		save(self)
 	}
 
+	/// Get contract address.
 	fn contract_address(&self, _caller: caller) -> Result<address> {
 		Ok(crate::eth::collection_id_to_address(self.id))
 	}
 
-	fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {
+	/// Add collection admin by substrate address.
+	/// @param new_admin Substrate administrator address.
+	fn add_collection_admin_substrate(
+		&mut self,
+		caller: caller,
+		new_admin: uint256,
+	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let mut new_admin_arr: [u8; 32] = Default::default();
 		new_admin.to_big_endian(&mut new_admin_arr);
@@ -186,35 +239,44 @@
 		Ok(())
 	}
 
+	/// Remove collection admin by substrate address.
+	/// @param admin Substrate administrator address.
 	fn remove_collection_admin_substrate(
-		&self,
+		&mut self,
 		caller: caller,
-		new_admin: uint256,
+		admin: uint256,
 	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		let mut new_admin_arr: [u8; 32] = Default::default();
-		new_admin.to_big_endian(&mut new_admin_arr);
-		let account_id = T::AccountId::from(new_admin_arr);
-		let new_admin = T::CrossAccountId::from_sub(account_id);
-		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)
-			.map_err(dispatch_to_evm::<T>)?;
+		let mut admin_arr: [u8; 32] = Default::default();
+		admin.to_big_endian(&mut admin_arr);
+		let account_id = T::AccountId::from(admin_arr);
+		let admin = T::CrossAccountId::from_sub(account_id);
+		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
-	fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {
+	/// Add collection admin.
+	/// @param new_admin Address of the added administrator.
+	fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let new_admin = T::CrossAccountId::from_eth(new_admin);
 		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
-	fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {
+	/// Remove collection admin.
+	///
+	/// @param new_admin Address of the removed administrator.
+	fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let admin = T::CrossAccountId::from_eth(admin);
 		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
+	/// Toggle accessibility of collection nesting.
+	///
+	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
 	#[solidity(rename_selector = "setCollectionNesting")]
 	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -235,6 +297,10 @@
 		save(self)
 	}
 
+	/// Toggle accessibility of collection nesting.
+	///
+	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	/// @param collections Addresses of collections that will be available for nesting.
 	#[solidity(rename_selector = "setCollectionNesting")]
 	fn set_nesting(
 		&mut self,
@@ -280,6 +346,10 @@
 		save(self)
 	}
 
+	/// Set the collection access method.
+	/// @param mode Access mode
+	/// 	0 for Normal
+	/// 	1 for AllowList
 	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 		let permissions = CollectionPermissions {
@@ -300,20 +370,29 @@
 		save(self)
 	}
 
-	fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {
+	/// Add the user to the allowed list.
+	///
+	/// @param user Address of a trusted user.
+	fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let user = T::CrossAccountId::from_eth(user);
 		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
-	fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {
+	/// Remove the user from the allowed list.
+	///
+	/// @param user Address of a removed user.
+	fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let user = T::CrossAccountId::from_eth(user);
 		<Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
+	/// Switch permission for minting.
+	///
+	/// @param mode Enable if "true".
 	fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 		let permissions = CollectionPermissions {
@@ -351,6 +430,7 @@
 	Ok(())
 }
 
+/// Get the "tokenURI" key as [PropertyKey](up_data_structs::PropertyKey).
 pub fn token_uri_key() -> up_data_structs::PropertyKey {
 	b"tokenURI"
 		.to_vec()
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! The module contains a number of functions for converting and checking ethereum identifiers.
+
 use up_data_structs::CollectionId;
 use sp_core::H160;
 
@@ -23,6 +25,7 @@
 	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,
 ];
 
+/// Maps the ethereum address of the collection in substrate.
 pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {
 	if eth[0..16] != ETH_COLLECTION_PREFIX {
 		return None;
@@ -31,6 +34,8 @@
 	id_bytes.copy_from_slice(&eth[16..20]);
 	Some(CollectionId(u32::from_be_bytes(id_bytes)))
 }
+
+/// Maps the substrate collection id in ethereum.
 pub fn collection_id_to_address(id: CollectionId) -> H160 {
 	let mut out = [0; 20];
 	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);
@@ -38,6 +43,7 @@
 	H160(out)
 }
 
+/// Check if the ethereum address is a collection.
 pub fn is_collection(address: &H160) -> bool {
 	address[0..16] == ETH_COLLECTION_PREFIX
 }
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -14,8 +14,43 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Common pallet
+//!
+//! The Common pallet provides functionality for handling collections.
+//!
+//! ## Overview
+//!
+//! The Common pallet provides an interface for common collection operations for different collection types
+//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.
+//! It also provides this functionality to EVM, see [erc] and [eth] modules.
+//!
+//! The Common pallet provides functions for:
+//!
+//! - Setting and approving collection sponsor.
+//! - Get\set\delete allow list.
+//! - Get\set\delete collection properties.
+//! - Get\set\delete collection property permissions.
+//! - Get\set\delete token property permissions.
+//! - Get\set\delete collection administrators.
+//! - Checking access permissions.
+//!
+//! ### Terminology
+//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will
+//! be possible to mint tokens.
+//!
+//! **Allow list** - List of users who have the right to minting tokens.
+//!
+//! **Collection properties** - Collection properties are simply key-value stores where various
+//! metadata can be placed.
+//!
+//! **Permissions on token properties** - For each property in the token can be set permission
+//! to change, see [`PropertyPermission`].
+//!
+//! **Collection administrator** - For a collection, you can set administrators who have the right
+//! to most actions on the collection.
+
+#![warn(missing_docs)]
 #![cfg_attr(not(feature = "std"), no_std)]
-
 extern crate alloc;
 
 use core::ops::{Deref, DerefMut};
@@ -90,14 +125,24 @@
 pub mod eth;
 pub mod weights;
 
+/// Weight info.
 pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
+/// Collection handle contains information about collection data and id.
+/// Also provides functionality to count consumed gas.
+///
+/// CollectionHandle is used as a generic wrapper for collections of all types.
+/// It allows to perform common operations and queries on any collection type,
+/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].
 #[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]
 pub struct CollectionHandle<T: Config> {
+	/// Collection id
 	pub id: CollectionId,
 	collection: Collection<T::AccountId>,
+	/// Substrate recorder for counting consumed gas
 	pub recorder: SubstrateRecorder<T>,
 }
+
 impl<T: Config> WithRecorder<T> for CollectionHandle<T> {
 	fn recorder(&self) -> &SubstrateRecorder<T> {
 		&self.recorder
@@ -106,7 +151,9 @@
 		self.recorder
 	}
 }
+
 impl<T: Config> CollectionHandle<T> {
+	/// Same as [CollectionHandle::new] but with an explicit gas limit.
 	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
 		<CollectionById<T>>::get(id).map(|collection| Self {
 			id,
@@ -115,6 +162,7 @@
 		})
 	}
 
+	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].
 	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {
 		<CollectionById<T>>::get(id).map(|collection| Self {
 			id,
@@ -123,14 +171,18 @@
 		})
 	}
 
+	/// Retrives collection data from storage and creates collection handle with default parameters.
+	/// If collection not found return `None`
 	pub fn new(id: CollectionId) -> Option<Self> {
 		Self::new_with_gas_limit(id, u64::MAX)
 	}
 
+	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.
 	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {
 		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)
 	}
 
+	/// Consume gas for reading.
 	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {
 		self.recorder
 			.consume_gas(T::GasWeightMapping::weight_to_gas(
@@ -140,6 +192,7 @@
 			))
 	}
 
+	/// Consume gas for writing.
 	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {
 		self.recorder
 			.consume_gas(T::GasWeightMapping::weight_to_gas(
@@ -148,16 +201,27 @@
 					.saturating_mul(writes),
 			))
 	}
+
+	/// Save collection to storage.
 	pub fn save(self) -> DispatchResult {
 		<CollectionById<T>>::insert(self.id, self.collection);
 		Ok(())
 	}
 
+	/// Set collection sponsor.
+	///
+	/// Unique collections allows sponsoring for certain actions.
+	/// This method allows you to set the sponsor of the collection.
+	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].
 	pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {
 		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
 		Ok(())
 	}
 
+	/// Confirm sponsorship
+	///
+	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.
+	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].
 	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {
 		if self.collection.sponsorship.pending_sponsor() != Some(sender) {
 			return Ok(false);
@@ -168,7 +232,7 @@
 	}
 
 	/// Checks that the collection was created with, and must be operated upon through **Unique API**.
-	/// Now check only the `external_collection` flag and if it's **true**, then return `CollectionIsExternal` error.
+	/// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.
 	pub fn check_is_internal(&self) -> DispatchResult {
 		if self.external_collection {
 			return Err(<Error<T>>::CollectionIsExternal)?;
@@ -178,7 +242,7 @@
 	}
 
 	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.
-	/// Now check only the `external_collection` flag and if it's **false**, then return `CollectionIsInternal` error.
+	/// Now check only the `external_collection` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.
 	pub fn check_is_external(&self) -> DispatchResult {
 		if !self.external_collection {
 			return Err(<Error<T>>::CollectionIsInternal)?;
@@ -203,23 +267,34 @@
 }
 
 impl<T: Config> CollectionHandle<T> {
-	pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {
-		ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);
+	/// Checks if the `user` is the owner of the collection.
+	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {
+		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);
 		Ok(())
 	}
-	pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {
-		*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))
+
+	/// Returns **true** if the `user` is the owner or administrator of the collection.
+	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {
+		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))
 	}
-	pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {
-		ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);
+
+	/// Checks if the `user` is the owner or administrator of the collection.
+	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {
+		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);
 		Ok(())
 	}
+
+	/// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.
 	pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {
 		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
 	}
+
+	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.
 	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {
 		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
 	}
+
+	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.
 	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {
 		ensure!(
 			<Allowlist<T>>::get((self.id, user)),
@@ -249,21 +324,34 @@
 		+ TypeInfo
 		+ account::Config
 	{
+		/// Weight information for functions of this pallet.
 		type WeightInfo: WeightInfo;
+
+		/// Events compatible with [`frame_system::Config::Event`].
 		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
 
+		/// Handler of accounts and payment.
 		type Currency: Currency<Self::AccountId>;
 
+		/// Set price to create a collection.
 		#[pallet::constant]
 		type CollectionCreationPrice: Get<
 			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,
 		>;
+
+		/// Dispatcher of operations on collections.
 		type CollectionDispatch: CollectionDispatch<Self>;
 
+		/// Account which holds the chain's treasury.
 		type TreasuryAccountId: Get<Self::AccountId>;
+
+		/// Address under which the CollectionHelper contract would be available.
 		type ContractAddress: Get<H160>;
 
+		/// Mapper for token addresses to Ethereum addresses.
 		type EvmTokenAddressMapping: TokenAddressMapping<H160>;
+
+		/// Mapper for token addresses to [`CrossAccountId`].
 		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;
 	}
 
@@ -276,6 +364,7 @@
 
 	#[pallet::extra_constants]
 	impl<T: Config> Pallet<T> {
+		/// Maximum admins per collection.
 		pub fn collection_admins_limit() -> u32 {
 			COLLECTION_ADMINS_LIMIT
 		}
@@ -285,116 +374,116 @@
 	#[pallet::generate_deposit(pub fn deposit_event)]
 	pub enum Event<T: Config> {
 		/// New collection was created
-		///
-		/// # Arguments
-		///
-		/// * collection_id - Globally unique identifier of newly created collection.
-		/// * mode - [CollectionMode] converted into u8.
-		/// * account_id - Collection owner.
-		CollectionCreated(CollectionId, u8, T::AccountId),
+		CollectionCreated(
+			/// Globally unique identifier of newly created collection.
+			CollectionId,
+			/// [`CollectionMode`] converted into _u8_.
+			u8,
+			/// Collection owner.
+			T::AccountId,
+		),
 
 		/// New collection was destroyed
-		///
-		/// # Arguments
-		///
-		/// * collection_id - Globally unique identifier of collection that has been destroyed.
-		CollectionDestroyed(CollectionId),
+		CollectionDestroyed(
+			/// Globally unique identifier of collection.
+			CollectionId,
+		),
 
 		/// New item was created.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection where the item was created.
-		/// * item_id - ID of the item. Unique within the collection.
-		/// * recipient - Owner of the newly created item.
-		/// * amount - The amount of tokens that were created (always 1 for NFT).
-		ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),
+		ItemCreated(
+			/// Id of the collection where item was created.
+			CollectionId,
+			/// Id of an item. Unique within the collection.
+			TokenId,
+			/// Owner of newly created item
+			T::CrossAccountId,
+			/// Always 1 for NFT
+			u128,
+		),
 
 		/// Collection item was burned.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - Identifier of the collection to which the burned NFT belonged.
-		/// * item_id - Identifier of burned NFT.
-		/// * owner - Which user has destroyed their tokens.
-		/// * amount - Amount of tokens that were destroyed (always 1 for NFT).
-		ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),
+		ItemDestroyed(
+			/// Id of the collection where item was destroyed.
+			CollectionId,
+			/// Identifier of burned NFT.
+			TokenId,
+			/// Which user has destroyed its tokens.
+			T::CrossAccountId,
+			/// Amount of token pieces destroed. Always 1 for NFT.
+			u128,
+		),
 
-		/// Item was transferred.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection to which the item belongs.
-		/// * item_id - ID of the item transferred.
-		/// * sender - Original owner of the item.
-		/// * recipient - New owner of the item.
-		/// * amount - Amount of tokens that were transferred (always 1 for NFT).
+		/// Item was transferred
 		Transfer(
+			/// Id of collection to which item is belong.
 			CollectionId,
+			/// Id of an item.
 			TokenId,
+			/// Original owner of item.
 			T::CrossAccountId,
+			/// New owner of item.
 			T::CrossAccountId,
+			/// Amount of token pieces transfered. Always 1 for NFT.
 			u128,
 		),
 
-		/// Sponsoring allowance was approved.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - todo:doc flesh out
-		/// * item_id
-		/// * sender
-		/// * spender
-		/// * amount
+		/// Amount pieces of token owned by `sender` was approved for `spender`.
 		Approved(
+			/// Id of collection to which item is belong.
 			CollectionId,
+			/// Id of an item.
 			TokenId,
+			/// Original owner of item.
 			T::CrossAccountId,
+			/// Id for which the approval was granted.
 			T::CrossAccountId,
+			/// Amount of token pieces transfered. Always 1 for NFT.
 			u128,
 		),
 
-		/// Collection property was added or edited.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection, whose property was just set.
-		/// * property_key - Key of the property that was just set.
-		CollectionPropertySet(CollectionId, PropertyKey),
+		/// The colletion property has been added or edited.
+		CollectionPropertySet(
+			/// Id of collection to which property has been set.
+			CollectionId,
+			/// The property that was set.
+			PropertyKey,
+		),
 
-		/// Collection property was deleted.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection, whose property was just deleted.
-		/// * property_key - Key of the property that was just deleted.
-		CollectionPropertyDeleted(CollectionId, PropertyKey),
+		/// The property has been deleted.
+		CollectionPropertyDeleted(
+			/// Id of collection to which property has been deleted.
+			CollectionId,
+			/// The property that was deleted.
+			PropertyKey,
+		),
 
-		/// Item property was added or edited.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection, whose token's property was just set.
-		/// * item_id - ID of the item, whose property was just set.
-		/// * property_key - Key of the property that was just set.
-		TokenPropertySet(CollectionId, TokenId, PropertyKey),
+		/// The token property has been added or edited.
+		TokenPropertySet(
+			/// Identifier of the collection whose token has the property set.
+			CollectionId,
+			/// The token for which the property was set.
+			TokenId,
+			/// The property that was set.
+			PropertyKey,
+		),
 
-		/// Item property was deleted.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection, whose token's property was just deleted.
-		/// * item_id - ID of the item, whose property was just deleted.
-		/// * property_key - Key of the property that was just deleted.
-		TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),
+		/// The token property has been deleted.
+		TokenPropertyDeleted(
+			/// Identifier of the collection whose token has the property deleted.
+			CollectionId,
+			/// The token for which the property was deleted.
+			TokenId,
+			/// The property that was deleted.
+			PropertyKey,
+		),
 
-		/// Token property permission was added or updated for a collection.
-		///
-		/// # Arguments
-		///
-		/// * collection_id - ID of the collection, whose permissions were just set/updated.
-		/// * property_key - Key of the property of the set/updated permission.
-		PropertyPermissionSet(CollectionId, PropertyKey),
+		/// The token property permission of a collection has been set.
+		PropertyPermissionSet(
+			/// ID of collection to which property permission has been set.
+			CollectionId,
+			/// The property permission that was set.
+			PropertyKey,
+		),
 	}
 
 	#[pallet::error]
@@ -482,16 +571,16 @@
 		CollectionIsInternal,
 	}
 
-	/// The number of created collections. Essentially contains the last collection ID.
+	/// Storage of the count of created collections. Essentially contains the last collection ID.
 	#[pallet::storage]
 	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
 
-	/// The number of destroyed collections
+	/// Storage of the count of deleted collections.
 	#[pallet::storage]
 	pub type DestroyedCollectionCount<T> =
 		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
 
-	/// Collection info
+	/// Storage of collection info.
 	#[pallet::storage]
 	pub type CollectionById<T> = StorageMap<
 		Hasher = Blake2_128Concat,
@@ -500,7 +589,7 @@
 		QueryKind = OptionQuery,
 	>;
 
-	/// Collection properties
+	/// Storage of collection properties.
 	#[pallet::storage]
 	#[pallet::getter(fn collection_properties)]
 	pub type CollectionProperties<T> = StorageMap<
@@ -511,7 +600,7 @@
 		OnEmpty = up_data_structs::CollectionProperties,
 	>;
 
-	/// Token permissions of a collection
+	/// Storage of token property permissions of a collection.
 	#[pallet::storage]
 	#[pallet::getter(fn property_permissions)]
 	pub type CollectionPropertyPermissions<T> = StorageMap<
@@ -521,7 +610,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Amount of collection admins
+	/// Storage of the amount of collection admins.
 	#[pallet::storage]
 	pub type AdminAmount<T> = StorageMap<
 		Hasher = Blake2_128Concat,
@@ -530,7 +619,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// List of collection admins
+	/// List of collection admins.
 	#[pallet::storage]
 	pub type IsAdmin<T: Config> = StorageNMap<
 		Key = (
@@ -541,7 +630,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Allowlisted collection users
+	/// Allowlisted collection users.
 	#[pallet::storage]
 	pub type Allowlist<T: Config> = StorageNMap<
 		Key = (
@@ -552,7 +641,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Not used by code, exists only to provide some types to metadata
+	/// Not used by code, exists only to provide some types to metadata.
 	#[pallet::storage]
 	pub type DummyStorageValue<T: Config> = StorageValue<
 		Value = (
@@ -646,7 +735,9 @@
 }
 
 impl<T: Config> Pallet<T> {
-	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens
+	/// Enshure that receiver address is correct.
+	///
+	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.
 	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {
 		ensure!(
 			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,
@@ -654,19 +745,27 @@
 		);
 		Ok(())
 	}
+
+	/// Get a vector of collection admins.
 	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {
 		<IsAdmin<T>>::iter_prefix((collection,))
 			.map(|(a, _)| a)
 			.collect()
 	}
+
+	/// Get a vector of users allowed to mint tokens.
 	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {
 		<Allowlist<T>>::iter_prefix((collection,))
 			.map(|(a, _)| a)
 			.collect()
 	}
+
+	/// Is `user` allowed to mint token in `collection`.
 	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {
 		<Allowlist<T>>::get((collection, user))
 	}
+
+	/// Get statistics of collections.
 	pub fn collection_stats() -> CollectionStats {
 		let created = <CreatedCollectionCount<T>>::get();
 		let destroyed = <DestroyedCollectionCount<T>>::get();
@@ -677,6 +776,7 @@
 		}
 	}
 
+	/// Get the effective limits for the collection.
 	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {
 		let collection = <CollectionById<T>>::get(collection);
 		if collection.is_none() {
@@ -710,6 +810,7 @@
 		Some(effective_limits)
 	}
 
+	/// Returns information about the `collection` adapted for rpc.
 	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {
 		let Collection {
 			name,
@@ -785,6 +886,11 @@
 }
 
 impl<T: Config> Pallet<T> {
+	/// Create new collection.
+	///
+	/// * `owner` - The owner of the collection.
+	/// * `data` - Description of the created collection.
+	/// * `is_external` - Marks that collection managet by not "Unique network".
 	pub fn init_collection(
 		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
@@ -860,7 +966,7 @@
 				),
 			);
 			<T as Config>::Currency::settle(
-				&owner.as_sub(),
+				owner.as_sub(),
 				imbalance,
 				WithdrawReasons::TRANSFER,
 				ExistenceRequirement::KeepAlive,
@@ -885,6 +991,10 @@
 		Ok(id)
 	}
 
+	/// Destroy collection.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
 	pub fn destroy_collection(
 		collection: CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -913,6 +1023,11 @@
 		Ok(())
 	}
 
+	/// Set collection property.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `property` - The property to set.
 	pub fn set_collection_property(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -931,6 +1046,11 @@
 		Ok(())
 	}
 
+	/// Set scouped collection property.
+	///
+	/// * `collection_id` - ID of the collection for which the property is being set.
+	/// * `scope` - Property scope.
+	/// * `property` - The property to set.
 	pub fn set_scoped_collection_property(
 		collection_id: CollectionId,
 		scope: PropertyScope,
@@ -944,6 +1064,11 @@
 		Ok(())
 	}
 
+	/// Set scouped collection properties.
+	///
+	/// * `collection_id` - ID of the collection for which the properties is being set.
+	/// * `scope` - Property scope.
+	/// * `properties` - The properties to set.
 	pub fn set_scoped_collection_properties(
 		collection_id: CollectionId,
 		scope: PropertyScope,
@@ -957,6 +1082,11 @@
 		Ok(())
 	}
 
+	/// Set collection properties.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `properties` - The properties to set.
 	#[transactional]
 	pub fn set_collection_properties(
 		collection: &CollectionHandle<T>,
@@ -970,6 +1100,11 @@
 		Ok(())
 	}
 
+	/// Delete collection property.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `property` - The property to delete.
 	pub fn delete_collection_property(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -990,6 +1125,11 @@
 		Ok(())
 	}
 
+	/// Delete collection properties.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `properties` - The properties to delete.
 	#[transactional]
 	pub fn delete_collection_properties(
 		collection: &CollectionHandle<T>,
@@ -1003,7 +1143,12 @@
 		Ok(())
 	}
 
-	// For migrations
+	/// Set collection propetry permission without any checks.
+	///
+	/// Used for migrations.
+	///
+	/// * `collection` - Collection handler.
+	/// * `property_permissions` - Property permissions.
 	pub fn set_property_permission_unchecked(
 		collection: CollectionId,
 		property_permission: PropertyKeyPermission,
@@ -1015,6 +1160,11 @@
 		Ok(())
 	}
 
+	/// Set collection property permission.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `property_permission` - Property permission.
 	pub fn set_property_permission(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -1045,6 +1195,11 @@
 		Ok(())
 	}
 
+	/// Set token property permission.
+	///
+	/// * `collection` - Collection handler.
+	/// * `sender` - The owner or administrator of the collection.
+	/// * `property_permissions` - Property permissions.
 	#[transactional]
 	pub fn set_token_property_permissions(
 		collection: &CollectionHandle<T>,
@@ -1058,6 +1213,7 @@
 		Ok(())
 	}
 
+	/// Get collection property.
 	pub fn get_collection_property(
 		collection_id: CollectionId,
 		key: &PropertyKey,
@@ -1065,6 +1221,7 @@
 		Self::collection_properties(collection_id).get(key).cloned()
 	}
 
+	/// Convert byte vector to property key vector.
 	pub fn bytes_keys_to_property_keys(
 		keys: Vec<Vec<u8>>,
 	) -> Result<Vec<PropertyKey>, DispatchError> {
@@ -1076,6 +1233,7 @@
 			.collect::<Result<Vec<PropertyKey>, DispatchError>>()
 	}
 
+	/// Get properties according to given keys.
 	pub fn filter_collection_properties(
 		collection_id: CollectionId,
 		keys: Option<Vec<PropertyKey>>,
@@ -1103,6 +1261,7 @@
 		Ok(properties)
 	}
 
+	/// Get property permissions according to given keys.
 	pub fn filter_property_permissions(
 		collection_id: CollectionId,
 		keys: Option<Vec<PropertyKey>>,
@@ -1132,6 +1291,7 @@
 		Ok(key_permissions)
 	}
 
+	/// Toggle `user` participation in the `collection`'s allow list.
 	pub fn toggle_allowlist(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -1151,6 +1311,7 @@
 		Ok(())
 	}
 
+	/// Toggle `user` participation in the `collection`'s admin list.
 	pub fn toggle_admin(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -1186,6 +1347,7 @@
 		Ok(())
 	}
 
+	/// Merge set fields from `new_limit` to `old_limit`.
 	pub fn clamp_limits(
 		mode: CollectionMode,
 		old_limit: &CollectionLimits,
@@ -1231,20 +1393,22 @@
 		Ok(new_limit)
 	}
 
+	/// Merge set fields from `new_permission` to `old_permission`.
 	pub fn clamp_permissions(
 		_mode: CollectionMode,
-		old_limit: &CollectionPermissions,
-		mut new_limit: CollectionPermissions,
+		old_permission: &CollectionPermissions,
+		mut new_permission: CollectionPermissions,
 	) -> Result<CollectionPermissions, DispatchError> {
-		limit_default_clone!(old_limit, new_limit,
+		limit_default_clone!(old_permission, new_permission,
 			access => {},
 			mint_mode => {},
 			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },
 		);
-		Ok(new_limit)
+		Ok(new_permission)
 	}
 }
 
+/// Indicates unsupported methods by returning [Error::UnsupportedOperation].
 #[macro_export]
 macro_rules! unsupported {
 	() => {
@@ -1252,32 +1416,72 @@
 	};
 }
 
-/// Worst cases
+/// Return weights for various worst-case operations.
 pub trait CommonWeightInfo<CrossAccountId> {
+	/// Weight of item creation.
 	fn create_item() -> Weight;
+
+	/// Weight of items creation.
 	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;
+
+	/// Weight of items creation.
 	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;
+
+	/// The weight of the burning item.
 	fn burn_item() -> Weight;
+
+	/// Property setting weight.
+	///
+	/// * `amount`- The number of properties to set.
 	fn set_collection_properties(amount: u32) -> Weight;
+
+	/// Collection property deletion weight.
+	///
+	/// * `amount`- The number of properties to set.
 	fn delete_collection_properties(amount: u32) -> Weight;
+
+	/// Token property setting weight.
+	///
+	/// * `amount`- The number of properties to set.
 	fn set_token_properties(amount: u32) -> Weight;
+
+	/// Token property deletion weight.
+	///
+	/// * `amount`- The number of properties to delete.
 	fn delete_token_properties(amount: u32) -> Weight;
+
+	/// Token property permissions set weight.
+	///
+	/// * `amount`- The number of property permissions to set.
 	fn set_token_property_permissions(amount: u32) -> Weight;
+
+	/// Transfer price of the token or its parts.
 	fn transfer() -> Weight;
+
+	/// The price of setting the permission of the operation from another user.
 	fn approve() -> Weight;
+
+	/// Transfer price from another user.
 	fn transfer_from() -> Weight;
+
+	/// The price of burning a token from another user.
 	fn burn_from() -> Weight;
 
 	/// Differs from burn_item in case of Fungible and Refungible, as it should burn
-	/// whole users's balance
+	/// whole users's balance.
 	///
-	/// This method shouldn't be used directly, as it doesn't count breadth price, use `burn_recursively` instead
+	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
 	fn burn_recursively_self_raw() -> Weight;
-	/// Cost of iterating over `amount` children while burning, without counting child burning itself
+
+	/// Cost of iterating over `amount` children while burning, without counting child burning itself.
 	///
-	/// This method shouldn't be used directly, as it doesn't count depth price, use `burn_recursively` instead
+	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
 	fn burn_recursively_breadth_raw(amount: u32) -> Weight;
 
+	/// The price of recursive burning a token.
+	///
+	/// `max_selfs` - The maximum burning weight of the token itself.
+	/// `max_breadth` - The maximum number of nested tokens to burn.
 	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {
 		Self::burn_recursively_self_raw()
 			.saturating_mul(max_selfs.max(1) as u64)
@@ -1285,11 +1489,23 @@
 	}
 }
 
+/// Weight info extension trait for refungible pallet.
 pub trait RefungibleExtensionsWeightInfo {
+	/// Weight of token repartition.
 	fn repartition() -> Weight;
 }
 
+/// Common collection operations.
+///
+/// It wraps methods in Fungible, Nonfungible and Refungible pallets
+/// and adds weight info.
 pub trait CommonCollectionOperations<T: Config> {
+	/// Create token.
+	///
+	/// * `sender` - The user who mint the token and pays for the transaction.
+	/// * `to` - The user who will own the token.
+	/// * `data` - Token data.
+	/// * `nesting_budget` - A budget that can be spent on nesting tokens.
 	fn create_item(
 		&self,
 		sender: T::CrossAccountId,
@@ -1297,6 +1513,13 @@
 		data: CreateItemData,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Create multiple tokens.
+	///
+	/// * `sender` - The user who mint the token and pays for the transaction.
+	/// * `to` - The user who will own the token.
+	/// * `data` - Token data.
+	/// * `nesting_budget` - A budget that can be spent on nesting tokens.
 	fn create_multiple_items(
 		&self,
 		sender: T::CrossAccountId,
@@ -1304,18 +1527,38 @@
 		data: Vec<CreateItemData>,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Create multiple tokens.
+	///
+	/// * `sender` - The user who mint the token and pays for the transaction.
+	/// * `to` - The user who will own the token.
+	/// * `data` - Token data.
+	/// * `nesting_budget` - A budget that can be spent on nesting tokens.
 	fn create_multiple_items_ex(
 		&self,
 		sender: T::CrossAccountId,
 		data: CreateItemExData<T::CrossAccountId>,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Burn token.
+	///
+	/// * `sender` - The user who owns the token.
+	/// * `token` - Token id that will burned.
+	/// * `amount` - The number of parts of the token that will be burned.
 	fn burn_item(
 		&self,
 		sender: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResultWithPostInfo;
+
+	/// Burn token and all nested tokens recursievly.
+	///
+	/// * `sender` - The user who owns the token.
+	/// * `token` - Token id that will burned.
+	/// * `self_budget` - The budget that can be spent on burning tokens.
+	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.
 	fn burn_item_recursively(
 		&self,
 		sender: T::CrossAccountId,
@@ -1323,43 +1566,95 @@
 		self_budget: &dyn Budget,
 		breadth_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Set collection properties.
+	///
+	/// * `sender` - Must be either the owner of the collection or its admin.
+	/// * `properties` - Properties to be set.
 	fn set_collection_properties(
 		&self,
 		sender: T::CrossAccountId,
 		properties: Vec<Property>,
 	) -> DispatchResultWithPostInfo;
+
+	/// Delete collection properties.
+	///
+	/// * `sender` - Must be either the owner of the collection or its admin.
+	/// * `properties` - The properties to be removed.
 	fn delete_collection_properties(
 		&self,
 		sender: &T::CrossAccountId,
 		property_keys: Vec<PropertyKey>,
 	) -> DispatchResultWithPostInfo;
+
+	/// Set token properties.
+	///
+	/// The appropriate [`PropertyPermission`] for the token property
+	/// must be set with [`Self::set_token_property_permissions`].
+	///
+	/// * `sender` - Must be either the owner of the token or its admin.
+	/// * `token_id` - The token for which the properties are being set.
+	/// * `properties` - Properties to be set.
+	/// * `budget` - Budget for setting properties.
 	fn set_token_properties(
 		&self,
 		sender: T::CrossAccountId,
 		token_id: TokenId,
-		property: Vec<Property>,
-		nesting_budget: &dyn Budget,
+		properties: Vec<Property>,
+		budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Remove token properties.
+	///
+	/// The appropriate [`PropertyPermission`] for the token property
+	/// must be set with [`Self::set_token_property_permissions`].
+	///
+	/// * `sender` - Must be either the owner of the token or its admin.
+	/// * `token_id` - The token for which the properties are being remove.
+	/// * `property_keys` - Keys to remove corresponding properties.
+	/// * `budget` - Budget for removing properties.
 	fn delete_token_properties(
 		&self,
 		sender: T::CrossAccountId,
 		token_id: TokenId,
 		property_keys: Vec<PropertyKey>,
-		nesting_budget: &dyn Budget,
+		budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Set token property permissions.
+	///
+	/// * `sender` - Must be either the owner of the token or its admin.
+	/// * `token_id` - The token for which the properties are being set.
+	/// * `properties` - Properties to be set.
+	/// * `budget` - Budget for setting properties.
 	fn set_token_property_permissions(
 		&self,
 		sender: &T::CrossAccountId,
 		property_permissions: Vec<PropertyKeyPermission>,
 	) -> DispatchResultWithPostInfo;
+
+	/// Transfer amount of token pieces.
+	///
+	/// * `sender` - Donor user.
+	/// * `to` - Recepient user.
+	/// * `token` - The token of which parts are being sent.
+	/// * `amount` - The number of parts of the token that will be transferred.
+	/// * `budget` - The maximum budget that can be spent on the transfer.
 	fn transfer(
 		&self,
 		sender: T::CrossAccountId,
 		to: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
-		nesting_budget: &dyn Budget,
+		budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].
+	///
+	/// * `sender` - The user who grants access to the token.
+	/// * `spender` - The user to whom the rights are granted.
+	/// * `token` - The token to which access is granted.
+	/// * `amount` - The amount of pieces that another user can dispose of.
 	fn approve(
 		&self,
 		sender: T::CrossAccountId,
@@ -1367,6 +1662,17 @@
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResultWithPostInfo;
+
+	/// Send parts of a token owned by another user.
+	///
+	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].
+	///
+	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).
+	/// * `from` - The user who owns the token.
+	/// * `to` - Recepient user.
+	/// * `token` - The token of which parts are being sent.
+	/// * `amount` - The number of parts of the token that will be transferred.
+	/// * `budget` - The maximum budget that can be spent on the transfer.
 	fn transfer_from(
 		&self,
 		sender: T::CrossAccountId,
@@ -1374,67 +1680,145 @@
 		to: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
-		nesting_budget: &dyn Budget,
+		budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
+
+	/// Burn parts of a token owned by another user.
+	///
+	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].
+	///
+	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).
+	/// * `from` - The user who owns the token.
+	/// * `token` - The token of which parts are being sent.
+	/// * `amount` - The number of parts of the token that will be transferred.
+	/// * `budget` - The maximum budget that can be spent on the burn.
 	fn burn_from(
 		&self,
 		sender: T::CrossAccountId,
 		from: T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
-		nesting_budget: &dyn Budget,
+		budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
 
+	/// Check permission to nest token.
+	///
+	/// * `sender` - The user who initiated the check.
+	/// * `from` - The token that is checked for embedding.
+	/// * `under` - Token under which to check.
+	/// * `budget` - The maximum budget that can be spent on the check.
 	fn check_nesting(
 		&self,
 		sender: T::CrossAccountId,
 		from: (CollectionId, TokenId),
 		under: TokenId,
-		nesting_budget: &dyn Budget,
+		budget: &dyn Budget,
 	) -> DispatchResult;
 
+	/// Nest one token into another.
+	///
+	/// * `under` - Token holder.
+	/// * `to_nest` - Nested token.
 	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));
 
+	/// Unnest token.
+	///
+	/// * `under` - Token holder.
+	/// * `to_nest` - Token to unnest.
 	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));
 
+	/// Get all user tokens.
+	///
+	/// * `account` - Account for which you need to get tokens.
 	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;
+
+	/// Get all the tokens in the collection.
 	fn collection_tokens(&self) -> Vec<TokenId>;
+
+	/// Check if the token exists.
+	///
+	/// * `token` - Id token to check.
 	fn token_exists(&self, token: TokenId) -> bool;
+
+	/// Get the id of the last minted token.
 	fn last_token_id(&self) -> TokenId;
 
+	/// Get the owner of the token.
+	///
+	/// * `token` - The token for which you need to find out the owner.
 	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;
+
+	/// Returns 10 tokens owners in no particular order.
+	///
+	/// * `token` - The token for which you need to find out the owners.
+	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;
+
+	/// Get the value of the token property by key.
+	///
+	/// * `token` - Token with the property to get.
+	/// * `key` - Property name.
 	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;
-	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;
+
+	/// Get a set of token properties by key vector.
+	///
+	/// * `token` - Token with the property to get.
+	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),
+	/// then all properties are returned.
+	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;
+
 	/// Amount of unique collection tokens
 	fn total_supply(&self) -> u32;
-	/// Amount of different tokens account has (Applicable to nonfungible/refungible)
+
+	/// Amount of different tokens account has.
+	///
+	/// * `account` - The account for which need to get the balance.
 	fn account_balance(&self, account: T::CrossAccountId) -> u32;
-	/// Amount of specific token account have (Applicable to fungible/refungible)
+
+	/// Amount of specific token account have.
 	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;
+
 	/// Amount of token pieces
 	fn total_pieces(&self, token: TokenId) -> Option<u128>;
+
+	/// Get the number of parts of the token that a trusted user can manage.
+	///
+	/// * `sender` - Trusted user.
+	/// * `spender` - Owner of the token.
+	/// * `token` - The token for which to get the value.
 	fn allowance(
 		&self,
 		sender: T::CrossAccountId,
 		spender: T::CrossAccountId,
 		token: TokenId,
 	) -> u128;
+
+	/// Get extension for RFT collection.
 	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;
 }
 
+/// Extension for RFT collection.
 pub trait RefungibleExtensions<T>
 where
 	T: Config,
 {
+	/// Change the number of parts of the token.
+	///
+	/// When the value changes down, this function is equivalent to burning parts of the token.
+	///
+	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.
+	/// * `token` - The token for which you want to change the number of parts.
+	/// * `amount` - The new value of the parts of the token.
 	fn repartition(
 		&self,
-		owner: &T::CrossAccountId,
+		sender: &T::CrossAccountId,
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResultWithPostInfo;
 }
 
-// Flexible enough for implementing CommonCollectionOperations
+/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].
+///
+/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.
 pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {
 	let post_info = PostDispatchInfo {
 		actual_weight: Some(weight),
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/fungible/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/fungible/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+    This was an internal request to improve the web interface and support fractionalization event. 
+    
+ 
+ 
\ No newline at end of file
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/fungible/Cargo.toml
+++ b/pallets/fungible/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-fungible"
-version = "0.1.0"
+version = "0.1.1"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -105,6 +105,8 @@
 	}
 }
 
+/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
+/// methods and adds weight info.
 impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {
 	fn create_item(
 		&self,
@@ -360,6 +362,11 @@
 		None
 	}
 
+	/// Returns 10 tokens owners in no particular order.
+	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+		<Pallet<T>>::token_owners(self.id, token).unwrap_or_default()
+	}
+
 	fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
 		None
 	}
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! ERC-20 standart support implementation.
+
 use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
 use core::convert::TryInto;
 use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -14,6 +14,68 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Fungible Pallet
+//!
+//! The Fungible pallet provides functionality for dealing with fungible assets.
+//!
+//! - [`CreateItemData`]
+//! - [`Config`]
+//! - [`FungibleHandle`]
+//! - [`Pallet`]
+//! - [`TotalSupply`]
+//! - [`Balance`]
+//! - [`Allowance`]
+//! - [`Error`]
+//!
+//! ## Fungible tokens
+//!
+//! Fungible tokens or assets are divisible and non-unique. For instance,
+//! fiat currencies like the dollar are fungible: A $1 bill
+//! in New York City has the same value as a $1 bill in Miami.
+//! A fungible token can also be a cryptocurrency like Bitcoin: 1 BTC is worth 1 BTC,
+//! no matter where it is issued. Thus, the fungibility refers to a specific currency’s
+//! ability to maintain one standard value. As well, it needs to have uniform acceptance.
+//! This means that a currency’s history should not be able to affect its value,
+//! and this is due to the fact that each piece that is a part of the currency is equal
+//! in value when compared to every other piece of that exact same currency.
+//! In the world of cryptocurrencies, this is essentially a coin or a token
+//! that can be replaced by another identical coin or token, and they are
+//! both mutually interchangeable. A popular implementation of fungible tokens is
+//! the ERC-20 token standard.
+//!
+//! ### ERC-20
+//!
+//! The [ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) (Ethereum Request for Comments 20), proposed by Fabian Vogelsteller in November 2015,
+//! is a Token Standard that implements an API for tokens within Smart Contracts.
+//!
+//! Example functionalities ERC-20 provides:
+//!
+//! * transfer tokens from one account to another
+//! * get the current token balance of an account
+//! * get the total supply of the token available on the network
+//! * approve whether an amount of token from an account can be spent by a third-party account
+//!
+//! ## Overview
+//!
+//! The module provides functionality for asset management of fungible asset, supports ERC-20 standart, includes:
+//!
+//! * Asset Issuance
+//! * Asset Transferal
+//! * Asset Destruction
+//! * Delegated Asset Transfers
+//!
+//! **NOTE:** The created fungible asset always has `token_id` = 0.
+//! So `tokenA` and `tokenB` will have different `collection_id`.
+//!
+//! ### Implementations
+//!
+//! The Fungible pallet provides implementations for the following traits.
+//!
+//! - [`WithRecorder`](pallet_evm_coder_substrate::WithRecorder): Trait for EVM support
+//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing with collections
+//!	- [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight
+//! - [`CommonEvmHandler`](pallet_common::erc::CommonEvmHandler): Function for handling EVM runtime calls
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use core::ops::Deref;
@@ -33,7 +95,7 @@
 use pallet_evm_coder_substrate::WithRecorder;
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
-use sp_std::{collections::btree_map::BTreeMap};
+use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
 
 pub use pallet::*;
 
@@ -44,7 +106,6 @@
 pub mod erc;
 pub mod weights;
 
-/// todo:doc?
 pub type CreateItemData<T> = (<T as pallet_evm::account::Config>::CrossAccountId, u128);
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
@@ -58,7 +119,7 @@
 	pub enum Error<T> {
 		/// Not Fungible item data used to mint in Fungible collection.
 		NotFungibleDataUsedToMintFungibleCollectionToken,
-		/// Not default id passed as TokenId argument.
+		/// Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.
 		FungibleItemsHaveNoId,
 		/// Tried to set data for fungible item.
 		FungibleItemsDontHaveData,
@@ -95,7 +156,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// todo:doc
+	/// Storage for assets delegated to a limited extent to other users.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (
@@ -108,14 +169,22 @@
 	>;
 }
 
+/// Wrapper around untyped collection handle, asserting inner collection is of fungible type.
+/// Required for interaction with Fungible collections, type safety and implementation [`solidity_interface`][`evm_coder::solidity_interface`].
 pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
+
+/// Implementation of methods required for dispatching during runtime.
 impl<T: Config> FungibleHandle<T> {
+	/// Casts [`CollectionHandle`][`pallet_common::CollectionHandle`] into [`FungibleHandle`].
 	pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {
 		Self(inner)
 	}
+
+	/// Casts [`FungibleHandle`] into [`CollectionHandle`][`pallet_common::CollectionHandle`].
 	pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {
 		self.0
 	}
+	/// Returns a mutable reference to the internal [`CollectionHandle`][`pallet_common::CollectionHandle`].
 	pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {
 		&mut self.0
 	}
@@ -136,13 +205,17 @@
 	}
 }
 
+/// Pallet implementation for fungible assets
 impl<T: Config> Pallet<T> {
+	/// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.
 	pub fn init_collection(
 		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data, false)
 	}
+
+	/// Destroys a collection.
 	pub fn destroy_collection(
 		collection: FungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -163,10 +236,14 @@
 		Ok(())
 	}
 
+	///Checks if collection has tokens. Return `true` if it has.
 	fn collection_has_tokens(collection_id: CollectionId) -> bool {
 		<TotalSupply<T>>::get(collection_id) != 0
 	}
 
+	/// Burns the specified amount of the token. If the token balance
+	/// or total supply is less than the given value,
+	/// it will return [DispatchError].
 	pub fn burn(
 		collection: &FungibleHandle<T>,
 		owner: &T::CrossAccountId,
@@ -211,6 +288,13 @@
 		Ok(())
 	}
 
+	/// Transfers the specified amount of tokens. Will check that
+	/// the transfer is allowed for the token.
+	///
+	/// - `from`: Owner of tokens to transfer.
+	/// - `to`: Recepient of transfered tokens.
+	/// - `amount`: Amount of tokens to transfer.
+	/// - `collection`: Collection that contains the token
 	pub fn transfer(
 		collection: &FungibleHandle<T>,
 		from: &T::CrossAccountId,
@@ -281,6 +365,8 @@
 		Ok(())
 	}
 
+	/// Minting tokens for multiple IDs.
+	/// See [`create_item`][`Pallet::create_item`] for more details.
 	pub fn create_multiple_items(
 		collection: &FungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -382,6 +468,12 @@
 		));
 	}
 
+	/// Set allowance for the spender to `transfer` or `burn` owner's tokens.
+	///
+	/// - `collection`: Collection that contains the token
+	/// - `owner`: Owner of tokens that sets the allowance.
+	/// - `spender`: Recipient of the allowance rights.
+	/// - `amount`: Amount of tokens the spender is allowed to `transfer` or `burn`.
 	pub fn set_allowance(
 		collection: &FungibleHandle<T>,
 		owner: &T::CrossAccountId,
@@ -406,6 +498,13 @@
 		Ok(())
 	}
 
+	/// Checks if a non-owner has (enough) allowance from the owner to perform operations on the tokens.
+	/// Returns the expected remaining allowance - it should be set manually if the transaction proceeds.
+	///
+	/// - `collection`: Collection that contains the token.
+	/// - `spender`: CrossAccountId who has the allowance rights.
+	/// - `from`: The owner of the tokens who sets the allowance.
+	/// - `amount`: Amount of tokens by which the allowance sholud be reduced.
 	fn check_allowed(
 		collection: &FungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -445,6 +544,11 @@
 		Ok(allowance)
 	}
 
+	/// Transfer fungible tokens from one account to another.
+	/// Same as the [`transfer`][`Pallet::transfer`] but spender doesn't needs to be an owner of the token pieces.
+	/// The owner should set allowance for the spender to transfer pieces.
+	///	See [`set_allowance`][`Pallet::set_allowance`] for more details.
+
 	pub fn transfer_from(
 		collection: &FungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -464,6 +568,11 @@
 		Ok(())
 	}
 
+	/// Burn fungible tokens from the account.
+	///
+	/// Same as the [`burn`][`Pallet::burn`] but spender doesn't need to be an owner of the tokens. The `from` should
+	/// set allowance for the spender to burn tokens.
+	/// See [`set_allowance`][`Pallet::set_allowance`] for more details.
 	pub fn burn_from(
 		collection: &FungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -482,7 +591,13 @@
 		Ok(())
 	}
 
-	/// Delegated to `create_multiple_items`
+	///	Creates fungible token.
+	///
+	/// The sender should be the owner/admin of the collection or collection should be configured
+	/// to allow public minting.
+	///
+	/// - `data`: Contains user who will become the owners of the tokens and amount
+	///   of tokens he will receive.
 	pub fn create_item(
 		collection: &FungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -496,4 +611,26 @@
 			nesting_budget,
 		)
 	}
+
+	/// Returns 10 tokens owners in no particular order
+	///
+	/// There is no direct way to get token holders in ascending order,
+	/// since `iter_prefix` returns values in no particular order.
+	/// Therefore, getting the 10 largest holders with a large value of holders
+	/// can lead to impact memory allocation + sorting with  `n * log (n)`.
+	pub fn token_owners(
+		collection: CollectionId,
+		_token: TokenId,
+	) -> Option<Vec<T::CrossAccountId>> {
+		let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection,))
+			.map(|(owner, _amount)| owner)
+			.take(10)
+			.collect();
+
+		if res.is_empty() {
+			None
+		} else {
+			Some(res)
+		}
+	}
 }
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -43,6 +43,233 @@
 	}
 }
 
+// Selector: 7d9262e6
+contract Collection is Dummy, ERC165 {
+	// Set collection property.
+	//
+	// @param key Property key.
+	// @param value Propery value.
+	//
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		public
+	{
+		require(false, stub_error);
+		key;
+		value;
+		dummy = 0;
+	}
+
+	// Delete collection property.
+	//
+	// @param key Property key.
+	//
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) public {
+		require(false, stub_error);
+		key;
+		dummy = 0;
+	}
+
+	// Get collection property.
+	//
+	// @dev Throws error if key not found.
+	//
+	// @param key Property key.
+	// @return bytes The property corresponding to the key.
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		public
+		view
+		returns (bytes memory)
+	{
+		require(false, stub_error);
+		key;
+		dummy;
+		return hex"";
+	}
+
+	// Set the sponsor of the collection.
+	//
+	// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	//
+	// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	//
+	// Selector: setCollectionSponsor(address) 7623402e
+	function setCollectionSponsor(address sponsor) public {
+		require(false, stub_error);
+		sponsor;
+		dummy = 0;
+	}
+
+	// Collection sponsorship confirmation.
+	//
+	// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	//
+	// Selector: confirmCollectionSponsorship() 3c50e97a
+	function confirmCollectionSponsorship() public {
+		require(false, stub_error);
+		dummy = 0;
+	}
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"accountTokenOwnershipLimit",
+	// 	"sponsoredDataSize",
+	// 	"sponsoredDataRateLimit",
+	// 	"tokenLimit",
+	// 	"sponsorTransferTimeout",
+	// 	"sponsorApproveTimeout"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,uint32) 6a3841db
+	function setCollectionLimit(string memory limit, uint32 value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"ownerCanTransfer",
+	// 	"ownerCanDestroy",
+	// 	"transfersEnabled"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,bool) 993b7fba
+	function setCollectionLimit(string memory limit, bool value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Get contract address.
+	//
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+
+	// Add collection admin by substrate address.
+	// @param new_admin Substrate administrator address.
+	//
+	// Selector: addCollectionAdminSubstrate(uint256) 5730062b
+	function addCollectionAdminSubstrate(uint256 newAdmin) public {
+		require(false, stub_error);
+		newAdmin;
+		dummy = 0;
+	}
+
+	// Remove collection admin by substrate address.
+	// @param admin Substrate administrator address.
+	//
+	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
+	function removeCollectionAdminSubstrate(uint256 admin) public {
+		require(false, stub_error);
+		admin;
+		dummy = 0;
+	}
+
+	// Add collection admin.
+	// @param new_admin Address of the added administrator.
+	//
+	// Selector: addCollectionAdmin(address) 92e462c7
+	function addCollectionAdmin(address newAdmin) public {
+		require(false, stub_error);
+		newAdmin;
+		dummy = 0;
+	}
+
+	// Remove collection admin.
+	//
+	// @param new_admin Address of the removed administrator.
+	//
+	// Selector: removeCollectionAdmin(address) fafd7b42
+	function removeCollectionAdmin(address admin) public {
+		require(false, stub_error);
+		admin;
+		dummy = 0;
+	}
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	//
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) public {
+		require(false, stub_error);
+		enable;
+		dummy = 0;
+	}
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// @param collections Addresses of collections that will be available for nesting.
+	//
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		public
+	{
+		require(false, stub_error);
+		enable;
+		collections;
+		dummy = 0;
+	}
+
+	// Set the collection access method.
+	// @param mode Access mode
+	// 	0 for Normal
+	// 	1 for AllowList
+	//
+	// Selector: setCollectionAccess(uint8) 41835d4c
+	function setCollectionAccess(uint8 mode) public {
+		require(false, stub_error);
+		mode;
+		dummy = 0;
+	}
+
+	// Add the user to the allowed list.
+	//
+	// @param user Address of a trusted user.
+	//
+	// Selector: addToCollectionAllowList(address) 67844fe6
+	function addToCollectionAllowList(address user) public {
+		require(false, stub_error);
+		user;
+		dummy = 0;
+	}
+
+	// Remove the user from the allowed list.
+	//
+	// @param user Address of a removed user.
+	//
+	// Selector: removeFromCollectionAllowList(address) 85c51acb
+	function removeFromCollectionAllowList(address user) public {
+		require(false, stub_error);
+		user;
+		dummy = 0;
+	}
+
+	// Switch permission for minting.
+	//
+	// @param mode Enable if "true".
+	//
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) public {
+		require(false, stub_error);
+		mode;
+		dummy = 0;
+	}
+}
+
 // Selector: 942e8b22
 contract ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
@@ -124,76 +351,6 @@
 		spender;
 		dummy;
 		return 0;
-	}
-}
-
-// Selector: c894dc35
-contract Collection is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		public
-	{
-		require(false, stub_error);
-		key;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) public {
-		require(false, stub_error);
-		key;
-		dummy = 0;
-	}
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		public
-		view
-		returns (bytes memory)
-	{
-		require(false, stub_error);
-		key;
-		dummy;
-		return hex"";
-	}
-
-	// Selector: ethSetSponsor(address) 8f9af356
-	function ethSetSponsor(address sponsor) public {
-		require(false, stub_error);
-		sponsor;
-		dummy = 0;
-	}
-
-	// Selector: ethConfirmSponsorship() a8580d1a
-	function ethConfirmSponsorship() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	// Selector: setLimit(string,uint32) 68db30ca
-	function setLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: setLimit(string,bool) ea67e4c2
-	function setLimit(string memory limit, bool value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: contractAddress() f6b4dfb4
-	function contractAddress() public view returns (address) {
-		require(false, stub_error);
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
 	}
 }
 
modifiedpallets/inflation/src/lib.rsdiffbeforeafterboth
--- a/pallets/inflation/src/lib.rs
+++ b/pallets/inflation/src/lib.rs
@@ -14,6 +14,20 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Inflation
+//!
+//! The inflation pallet is designed to increase the number of tokens at certain intervals.
+//! With each iteration, increases the `total_issuance` value for the native token.
+//! Executing an `on_initialize` hook at the beginning of each block, causing inflation to begin.
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+//! * `start_inflation` - This method sets the inflation start date. Can be only called once.
+//! Inflation start block can be backdated and will catch up. The method will create Treasury
+//!	account if it does not exist and perform the first inflation deposit.
+
 // #![recursion_limit = "1024"]
 #![cfg_attr(not(feature = "std"), no_std)]
 
addedpallets/nonfungible/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/nonfungible/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+- Implementation of RPC method `token_owners`.
+   For reasons of compatibility with this pallet, returns only one owner if token exists.
+   This was an internal request to improve the web interface and support fractionalization event. 
\ No newline at end of file
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-nonfungible"
-version = "0.1.0"
+version = "0.1.1"
 license = "GPLv3"
 edition = "2021"
 
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -183,7 +183,7 @@
 			value: property_value(),
 		}).collect::<Vec<_>>();
 		let item = create_max_item(&collection, &owner, owner.clone())?;
-	}: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?}
+	}: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}
 
 	delete_token_properties {
 		let b in 0..MAX_PROPERTIES_PER_ITEM;
@@ -205,7 +205,7 @@
 			value: property_value(),
 		}).collect::<Vec<_>>();
 		let item = create_max_item(&collection, &owner, owner.clone())?;
-		<Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?;
+		<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;
 		let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
-	}: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete, &Unlimited)?}
+	}: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}
 }
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -26,7 +26,7 @@
 	weights::WeightInfo as _,
 };
 use sp_runtime::DispatchError;
-use sp_std::vec::Vec;
+use sp_std::{vec::Vec, vec};
 
 use crate::{
 	AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,
@@ -133,6 +133,8 @@
 	}
 }
 
+/// Implementation of `CommonCollectionOperations` for `NonfungibleHandle`. It wraps Nonfungible Pallete
+/// methods and adds weight info.
 impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {
 	fn create_item(
 		&self,
@@ -420,6 +422,11 @@
 		<TokenData<T>>::get((self.id, token)).map(|t| t.owner)
 	}
 
+	/// Returns token owners.
+	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+		self.token_owner(token).map_or_else(|| vec![], |t| vec![t])
+	}
+
 	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {
 		<Pallet<T>>::token_properties((self.id, token_id))
 			.get(key)
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -14,6 +14,11 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Nonfungible Pallet EVM API
+//!
+//! Provides ERC-721 standart support implementation and EVM API for unique extensions for Nonfungible Pallet.
+//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.
+
 extern crate alloc;
 use core::{
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
@@ -40,8 +45,15 @@
 	SelfWeightOf, weights::WeightInfo, TokenProperties,
 };
 
+/// @title A contract that allows to set and delete token properties and change token property permissions.
 #[solidity_interface(name = "TokenProperties")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Set permissions for token property.
+	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	/// @param key Property key.
+	/// @param is_mutable Permission to mutate property.
+	/// @param collection_admin Permission to mutate property by collection admin if property is mutable.
+	/// @param token_owner Permission to mutate property by token owner if property is mutable.
 	fn set_token_property_permission(
 		&mut self,
 		caller: caller,
@@ -68,6 +80,11 @@
 		.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Set token property value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @param value Property value.
 	fn set_property(
 		&mut self,
 		caller: caller,
@@ -96,6 +113,10 @@
 		.map_err(dispatch_to_evm::<T>)
 	}
 
+	/// @notice Delete token property value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
 	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -111,7 +132,11 @@
 			.map_err(dispatch_to_evm::<T>)
 	}
 
-	/// Throws error if key not found
+	/// @notice Get token property value.
+	/// @dev Throws error if key not found
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @return Property value bytes
 	fn property(&self, token_id: uint256, key: string) -> Result<bytes> {
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
@@ -127,6 +152,11 @@
 
 #[derive(ToLog)]
 pub enum ERC721Events {
+	/// @dev This emits when ownership of any NFT changes by any mechanism.
+	///  This event emits when NFTs are created (`from` == 0) and destroyed
+	///  (`to` == 0). Exception: during contract creation, any number of NFTs
+	///  may be created and assigned without emitting Transfer. At the time of
+	///  any transfer, the approved address for that NFT (if any) is reset to none.
 	Transfer {
 		#[indexed]
 		from: address,
@@ -135,6 +165,10 @@
 		#[indexed]
 		token_id: uint256,
 	},
+	/// @dev This emits when the approved address for an NFT is changed or
+	///  reaffirmed. The zero address indicates there is no approved address.
+	///  When a Transfer event emits, this also indicates that the approved
+	///  address for that NFT (if any) is reset to none.
 	Approval {
 		#[indexed]
 		owner: address,
@@ -143,6 +177,8 @@
 		#[indexed]
 		token_id: uint256,
 	},
+	/// @dev This emits when an operator is enabled or disabled for an owner.
+	///  The operator can manage all NFTs of the owner.
 	#[allow(dead_code)]
 	ApprovalForAll {
 		#[indexed]
@@ -159,19 +195,27 @@
 	MintingFinished {},
 }
 
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
 #[solidity_interface(name = "ERC721Metadata")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice A descriptive name for a collection of NFTs in this contract
 	fn name(&self) -> Result<string> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
 			.collect::<string>())
 	}
 
+	/// @notice An abbreviated name for NFTs in this contract
 	fn symbol(&self) -> Result<string> {
 		Ok(string::from_utf8_lossy(&self.token_prefix).into())
 	}
 
-	/// Returns token's const_metadata
+	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	/// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC
+	///  3986. The URI may point to a JSON file that conforms to the "ERC721
+	///  Metadata JSON Schema".
+	/// @return token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
 	fn token_uri(&self, token_id: uint256) -> Result<string> {
 		let key = token_uri_key();
@@ -192,32 +236,53 @@
 	}
 }
 
+/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
 #[solidity_interface(name = "ERC721Enumerable")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Enumerate valid NFTs
+	/// @param index A counter less than `totalSupply()`
+	/// @return The token identifier for the `index`th NFT,
+	///  (sort order not specified)
 	fn token_by_index(&self, index: uint256) -> Result<uint256> {
 		Ok(index)
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
+	/// @notice Count NFTs tracked by this contract
+	/// @return A count of valid NFTs tracked by this contract, where each one of
+	///  them has an assigned and queryable owner not equal to the zero address
 	fn total_supply(&self) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		Ok(<Pallet<T>>::total_supply(self).into())
 	}
 }
 
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 #[solidity_interface(name = "ERC721", events(ERC721Events))]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Count all NFTs assigned to an owner
+	/// @dev NFTs assigned to the zero address are considered invalid, and this
+	///  function throws for queries about the zero address.
+	/// @param owner An address for whom to query the balance
+	/// @return The number of NFTs owned by `owner`, possibly zero
 	fn balance_of(&self, owner: address) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <AccountBalance<T>>::get((self.id, owner));
 		Ok(balance.into())
 	}
+	/// @notice Find the owner of an NFT
+	/// @dev NFTs assigned to zero address are considered invalid, and queries
+	///  about them do throw.
+	/// @param tokenId The identifier for an NFT
+	/// @return The address of the owner of the NFT
 	fn owner_of(&self, token_id: uint256) -> Result<address> {
 		self.consume_store_reads(1)?;
 		let token: TokenId = token_id.try_into()?;
@@ -226,7 +291,7 @@
 			.owner
 			.as_eth())
 	}
-	/// Not implemented
+	/// @dev Not implemented
 	fn safe_transfer_from_with_data(
 		&mut self,
 		_from: address,
@@ -238,7 +303,7 @@
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
-	/// Not implemented
+	/// @dev Not implemented
 	fn safe_transfer_from(
 		&mut self,
 		_from: address,
@@ -250,6 +315,16 @@
 		Err("not implemented".into())
 	}
 
+	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	///  THEY MAY BE PERMANENTLY LOST
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
@@ -272,6 +347,12 @@
 		Ok(())
 	}
 
+	/// @notice Set or reaffirm the approved address for an NFT
+	/// @dev The zero address indicates there is no approved address.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param approved The new approved NFT controller
+	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve(
 		&mut self,
@@ -289,7 +370,7 @@
 		Ok(())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn set_approval_for_all(
 		&mut self,
 		_caller: caller,
@@ -300,21 +381,26 @@
 		Err("not implemented".into())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn get_approved(&self, _token_id: uint256) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 }
 
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
 #[solidity_interface(name = "ERC721Burnable")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::burn_item())]
 	fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -325,14 +411,18 @@
 	}
 }
 
+/// @title ERC721 minting logic.
 #[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]
 impl<T: Config> NonfungibleHandle<T> {
 	fn minting_finished(&self) -> Result<bool> {
 		Ok(false)
 	}
 
-	/// `token_id` should be obtained with `next_token_id` method,
-	/// unlike standard, you can't specify it manually
+	/// @notice Function to mint token.
+	/// @dev `tokenId` should be obtained with `nextTokenId` method,
+	///  unlike standard, you can't specify it manually
+	/// @param to The new owner
+	/// @param tokenId ID of the minted NFT
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -364,8 +454,12 @@
 		Ok(true)
 	}
 
-	/// `token_id` should be obtained with `next_token_id` method,
-	/// unlike standard, you can't specify it manually
+	/// @notice Function to mint token with the given tokenUri.
+	/// @dev `tokenId` should be obtained with `nextTokenId` method,
+	///  unlike standard, you can't specify it manually
+	/// @param to The new owner
+	/// @param tokenId ID of the minted NFT
+	/// @param tokenUri Token URI that would be stored in the NFT properties
 	#[solidity(rename_selector = "mintWithTokenURI")]
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri(
@@ -420,7 +514,7 @@
 		Ok(true)
 	}
 
-	/// Not implemented
+	/// @dev Not implemented
 	fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
 		Err("not implementable".into())
 	}
@@ -449,8 +543,15 @@
 	false
 }
 
+/// @title Unique extensions for ERC721.
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
+	/// @notice Transfer ownership of an NFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer(
 		&mut self,
@@ -470,6 +571,13 @@
 		Ok(())
 	}
 
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param tokenId The NFT to transfer
+	/// @param _value Not used for an NFT
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from(
 		&mut self,
@@ -490,6 +598,7 @@
 		Ok(())
 	}
 
+	/// @notice Returns next free NFT ID.
 	fn next_token_id(&self) -> Result<uint256> {
 		self.consume_store_reads(1)?;
 		Ok(<TokensMinted<T>>::get(self.id)
@@ -498,6 +607,11 @@
 			.into())
 	}
 
+	/// @notice Function to mint multiple tokens.
+	/// @dev `tokenIds` should be an array of consecutive numbers and first number
+	///  should be obtained with `nextTokenId` method
+	/// @param to The new owner
+	/// @param tokenIds IDs of the minted NFTs
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
 	fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -529,6 +643,11 @@
 		Ok(true)
 	}
 
+	/// @notice Function to mint multiple tokens with the given tokenUris.
+	/// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	///  numbers and first number should be obtained with `nextTokenId` method
+	/// @param to The new owner
+	/// @param tokens array of pairs of token ID and token URI for minted tokens
 	#[solidity(rename_selector = "mintBulkWithTokenURI")]
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
 	fn mint_bulk_with_token_uri(
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -14,6 +14,80 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Nonfungible Pallet
+//!
+//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.
+//!
+//! - [`Config`]
+//! - [`NonfungibleHandle`]
+//! - [`Pallet`]
+//! - [`CommonWeights`](common::CommonWeights)
+//!
+//! ## Overview
+//!
+//! The Nonfungible pallet provides functions for:
+//!
+//! - NFT collection creation and removal
+//! - Minting and burning of NFT tokens
+//! - Retrieving account balances
+//! - Transfering NFT tokens
+//! - Setting and checking allowance for NFT tokens
+//! - Setting properties and permissions for NFT collections and tokens
+//! - Nesting and unnesting tokens
+//!
+//! ### Terminology
+//!
+//! - **NFT token:** Non fungible token.
+//!
+//! - **NFT Collection:** A collection of NFT tokens. All NFT tokens are part of a collection.
+//!   Each collection can define it's own properties, properties for it's tokens and set of permissions.
+//!
+//! - **Balance:** Number of NFT tokens owned by an account
+//!
+//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on
+//!
+//! - **Burning:** The process of “deleting” a token from a collection and from
+//!   an account balance of the owner.
+//!
+//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting
+//!   owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in
+//!   it's child token i.e. parent-child relationship graph shouldn't have cycles.
+//!
+//! - **Properties:** Key-Values pairs. Token properties are attached to a token. Collection properties are
+//!   attached to a collection. Set of permissions could be defined for each property.
+//!
+//! ### Implementations
+//!
+//! The Nonfungible pallet provides implementations for the following traits. If these traits provide
+//! the functionality that you need, then you can avoid coupling with the Nonfungible pallet.
+//!
+//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight
+//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing
+//!   with collections
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for
+//!   some accounts.
+//! - `destroy_collection` - Destroy exising NFT collection. There should be no tokens in the collection.
+//! - `burn` - Burn NFT token owned by account.
+//! - `transfer` - Transfer NFT token. Transfers should be enabled for NFT collection.
+//!   Nests the NFT token if it is sent to another token.
+//! - `create_item` - Mint NFT token in collection. Sender should have permission to mint tokens.
+//! - `set_allowance` - Set allowance for another account.
+//! - `set_token_property` - Set token property value.
+//! - `delete_token_property` - Remove property from the token.
+//! - `set_collection_properties` - Set collection properties.
+//! - `delete_collection_properties` - Remove properties from the collection.
+//! - `set_property_permission` - Set collection property permission.
+//! - `set_token_property_permissions` - Set token property permissions.
+//!
+//! ## Assumptions
+//!
+//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use erc::ERC721Events;
@@ -56,8 +130,8 @@
 pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
-/// Token data, stored independently from other data used to describe it.
-/// Notably contains the owner account address.
+/// Token data, stored independently from other data used to describe it
+/// for the convenience of database access. Notably contains the owner account address.
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
 pub struct ItemData<CrossAccountId> {
@@ -122,7 +196,7 @@
 		QueryKind = OptionQuery,
 	>;
 
-	/// Key-value pairs, describing the metadata of a token.
+	/// Map of key-value pairs, describing the metadata of a token.
 	#[pallet::storage]
 	#[pallet::getter(fn token_properties)]
 	pub type TokenProperties<T: Config> = StorageNMap<
@@ -132,7 +206,15 @@
 		OnEmpty = up_data_structs::TokenProperties,
 	>;
 
-	/// Scoped, auxiliary properties of a token, primarily used for on-chain operations.
+	/// Custom data of a token that is serialized to bytes, 
+	/// primarily reserved for on-chain operations, 
+	/// normally obscured from the external users.
+	/// 
+	/// Auxiliary properties are slightly different from 
+	/// usual [`TokenProperties`] due to an unlimited number 
+	/// and separately stored and written-to key-value pairs.
+	/// 
+	/// Currently used to store RMRK data.
 	#[pallet::storage]
 	#[pallet::getter(fn token_aux_property)]
 	pub type TokenAuxProperties<T: Config> = StorageNMap<
@@ -171,7 +253,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Amount of tokens owned in a collection.
+	/// Amount of tokens owned by an account in a collection.
 	#[pallet::storage]
 	pub type AccountBalance<T: Config> = StorageNMap<
 		Key = (
@@ -182,7 +264,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// todo:doc
+	/// Allowance set by a token owner for another user to perform one of certain transactions on a token.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -284,13 +366,21 @@
 }
 
 impl<T: Config> Pallet<T> {
+	/// Get number of NFT tokens in collection.
 	pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {
 		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)
 	}
+
+	/// Check that NFT token exists.
+	///
+	/// - `token`: Token ID.
 	pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {
 		<TokenData<T>>::contains_key((collection.id, token))
 	}
 
+	/// Set the token property with the scope.
+	///
+	/// - `property`: Contains key-value pair.
 	pub fn set_scoped_token_property(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -305,6 +395,7 @@
 		Ok(())
 	}
 
+	/// Batch operation to set multiple properties with the same scope.
 	pub fn set_scoped_token_properties(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -319,6 +410,9 @@
 		Ok(())
 	}
 
+	/// Add or edit auxiliary data for the property.
+	///
+	/// - `f`: function that adds or edits auxiliary data.
 	pub fn try_mutate_token_aux_property<R, E>(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -329,6 +423,7 @@
 		<TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)
 	}
 
+	/// Remove auxiliary data for the property.
 	pub fn remove_token_aux_property(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -338,6 +433,9 @@
 		<TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));
 	}
 
+	/// Get all auxiliary data in a given scope.
+	///
+	/// Returns iterator over Property Key - Data pairs.
 	pub fn iterate_token_aux_properties(
 		collection_id: CollectionId,
 		token_id: TokenId,
@@ -346,6 +444,7 @@
 		<TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))
 	}
 
+	/// Get ID of the last minted token
 	pub fn current_token_id(collection_id: CollectionId) -> TokenId {
 		TokenId(<TokensMinted<T>>::get(collection_id))
 	}
@@ -353,6 +452,11 @@
 
 // unchecked calls skips any permission checks
 impl<T: Config> Pallet<T> {
+	/// Create NFT collection
+	///
+	/// `init_collection` will take non-refundable deposit for collection creation.
+	///
+	/// - `data`: Contains settings for collection limits and permissions.
 	pub fn init_collection(
 		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
@@ -360,6 +464,11 @@
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data, is_external)
 	}
+
+	/// Destroy NFT collection
+	///
+	/// `destroy_collection` will throw error if collection contains any tokens.
+	/// Only owner can destroy collection.
 	pub fn destroy_collection(
 		collection: NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -384,6 +493,15 @@
 		Ok(())
 	}
 
+	/// Burn NFT token
+	///
+	/// `burn` removes `token` from the `collection`, from it's owner and from the parent token
+	/// if the token is nested.
+	/// Only the owner can `burn` the token. The `token` shouldn't have any nested tokens.
+	/// Also removes all corresponding properties and auxiliary properties.
+	///
+	/// - `token`: Token that should be burned
+	/// - `collection`: Collection that contains the token
 	pub fn burn(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -453,6 +571,12 @@
 		Ok(())
 	}
 
+	/// Same as [`burn`] but burns all the tokens that are nested in the token first
+	///
+	/// - `self_budget`: Limit for searching children in depth.
+	/// - `breadth_budget`: Limit of breadth of searching children.
+	///
+	/// [`burn`]: struct.Pallet.html#method.burn
 	#[transactional]
 	pub fn burn_recursively(
 		collection: &NonfungibleHandle<T>,
@@ -492,6 +616,14 @@
 		})
 	}
 
+	/// Batch operation to add, edit or remove properties for the token
+	///
+	/// All affected properties should have mutable permission and sender should have
+	/// permission to edit those properties.
+	///
+	/// - `nesting_budget`: Limit for searching parents in depth to check ownership.
+	/// - `is_token_create`: Indicates that method is called during token initialization.
+	///   Allows to bypass ownership check.
 	#[transactional]
 	fn modify_token_properties(
 		collection: &NonfungibleHandle<T>,
@@ -585,6 +717,11 @@
 		Ok(())
 	}
 
+	/// Batch operation to add or edit properties for the token
+	///
+	/// Same as [`modify_token_properties`] but doesn't allow to remove properties
+	///
+	/// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
 	pub fn set_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -603,6 +740,11 @@
 		)
 	}
 
+	/// Add or edit single property for the token
+	///
+	/// Calls [`set_token_properties`] internally
+	///
+	/// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties
 	pub fn set_token_property(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -622,6 +764,11 @@
 		)
 	}
 
+	/// Batch operation to remove properties from the token
+	///
+	/// Same as [`modify_token_properties`] but doesn't allow to add or edit properties
+	///
+	/// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
 	pub fn delete_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -641,6 +788,11 @@
 		)
 	}
 
+	/// Remove single property from the token
+	///
+	/// Calls [`delete_token_properties`] internally
+	///
+	/// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties
 	pub fn delete_token_property(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -657,6 +809,7 @@
 		)
 	}
 
+	/// Add or edit properties for the collection
 	pub fn set_collection_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -665,6 +818,7 @@
 		<PalletCommon<T>>::set_collection_properties(collection, sender, properties)
 	}
 
+	/// Remove properties from the collection
 	pub fn delete_collection_properties(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -673,6 +827,9 @@
 		<PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)
 	}
 
+	/// Set property permissions for the token.
+	///
+	/// Sender should be the owner or admin of token's collection.
 	pub fn set_token_property_permissions(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -681,6 +838,9 @@
 		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)
 	}
 
+	/// Set property permissions for the collection.
+	///
+	/// Sender should be the owner or admin of the collection.
 	pub fn set_property_permission(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -689,6 +849,15 @@
 		<PalletCommon<T>>::set_property_permission(collection, sender, permission)
 	}
 
+	/// Transfer NFT token from one account to another.
+	///
+	/// `from` account stops being the owner and `to` account becomes the owner of the token.
+	/// If `to` is token than `to` becomes owner of the token and the token become nested.
+	/// Unnests token from previous parent if it was nested before.
+	/// Removes allowance for the token if there was any.
+	/// Throws if transfers aren't allowed for collection or if receiver reached token ownership limit.
+	///
+	/// - `nesting_budget`: Limit for token nesting depth
 	pub fn transfer(
 		collection: &NonfungibleHandle<T>,
 		from: &T::CrossAccountId,
@@ -780,6 +949,16 @@
 		Ok(())
 	}
 
+	/// Batch operation to mint multiple NFT tokens.
+	///
+	/// The sender should be the owner/admin of the collection or collection should be configured
+	/// to allow public minting.
+	/// Throws if amount of tokens reached it's limit for the collection or if caller reached
+	/// token ownership limit.
+	///
+	/// - `data`: Contains list of token properties and users who will become the owners of the
+	///   corresponging tokens.
+	/// - `nesting_budget`: Limit for token nesting depth
 	pub fn create_multiple_items(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -964,6 +1143,9 @@
 		}
 	}
 
+	/// Set allowance for the spender to `transfer` or `burn` sender's token.
+	///
+	/// - `token`: Token the spender is allowed to `transfer` or `burn`.
 	pub fn set_allowance(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -996,6 +1178,7 @@
 		Ok(())
 	}
 
+	/// Checks allowance for the spender to use the token.
 	fn check_allowed(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1038,6 +1221,12 @@
 		Ok(())
 	}
 
+	/// Transfer NFT token from one account to another.
+	///
+	/// Same as the [`transfer`] but spender doesn't needs to be the owner of the token.
+	/// The owner should set allowance for the spender to transfer token.
+	///
+	/// [`transfer`]: struct.Pallet.html#method.transfer
 	pub fn transfer_from(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1054,6 +1243,12 @@
 		Self::transfer(collection, from, to, token, nesting_budget)
 	}
 
+	/// Burn NFT token for `from` account.
+	///
+	/// Same as the [`burn`] but spender doesn't need to be an owner of the token. The owner should
+	/// set allowance for the spender to burn token.
+	///
+	/// [`burn`]: struct.Pallet.html#method.burn
 	pub fn burn_from(
 		collection: &NonfungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -1068,6 +1263,8 @@
 		Self::burn(collection, from, token)
 	}
 
+	/// Check that `from` token could be nested in `under` token.
+	///
 	pub fn check_nesting(
 		handle: &NonfungibleHandle<T>,
 		sender: T::CrossAccountId,
@@ -1137,7 +1334,11 @@
 			.collect()
 	}
 
-	/// Delegated to `create_multiple_items`
+	/// Mint single NFT token.
+	///
+	/// Delegated to [`create_multiple_items`]
+	///
+	/// [`create_multiple_items`]: struct.Pallet.html#method.create_multiple_items
 	pub fn create_item(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -53,6 +53,13 @@
 
 // Selector: 41369377
 contract TokenProperties is Dummy, ERC165 {
+	// @notice Set permissions for token property.
+	// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	// @param key Property key.
+	// @param is_mutable Permission to mutate property.
+	// @param collection_admin Permission to mutate property by collection admin if property is mutable.
+	// @param token_owner Permission to mutate property by token owner if property is mutable.
+	//
 	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
 	function setTokenPropertyPermission(
 		string memory key,
@@ -68,6 +75,12 @@
 		dummy = 0;
 	}
 
+	// @notice Set token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	// @param value Property value.
+	//
 	// Selector: setProperty(uint256,string,bytes) 1752d67b
 	function setProperty(
 		uint256 tokenId,
@@ -81,6 +94,11 @@
 		dummy = 0;
 	}
 
+	// @notice Delete token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	//
 	// Selector: deleteProperty(uint256,string) 066111d1
 	function deleteProperty(uint256 tokenId, string memory key) public {
 		require(false, stub_error);
@@ -89,7 +107,11 @@
 		dummy = 0;
 	}
 
-	// Throws error if key not found
+	// @notice Get token property value.
+	// @dev Throws error if key not found
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	// @return Property value bytes
 	//
 	// Selector: property(uint256,string) 7228c327
 	function property(uint256 tokenId, string memory key)
@@ -107,6 +129,11 @@
 
 // Selector: 42966c68
 contract ERC721Burnable is Dummy, ERC165 {
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param tokenId The NFT to approve
+	//
 	// Selector: burn(uint256) 42966c68
 	function burn(uint256 tokenId) public {
 		require(false, stub_error);
@@ -117,6 +144,12 @@
 
 // Selector: 58800161
 contract ERC721 is Dummy, ERC165, ERC721Events {
+	// @notice Count all NFTs assigned to an owner
+	// @dev NFTs assigned to the zero address are considered invalid, and this
+	//  function throws for queries about the zero address.
+	// @param owner An address for whom to query the balance
+	// @return The number of NFTs owned by `owner`, possibly zero
+	//
 	// Selector: balanceOf(address) 70a08231
 	function balanceOf(address owner) public view returns (uint256) {
 		require(false, stub_error);
@@ -125,6 +158,12 @@
 		return 0;
 	}
 
+	// @notice Find the owner of an NFT
+	// @dev NFTs assigned to zero address are considered invalid, and queries
+	//  about them do throw.
+	// @param tokenId The identifier for an NFT
+	// @return The address of the owner of the NFT
+	//
 	// Selector: ownerOf(uint256) 6352211e
 	function ownerOf(uint256 tokenId) public view returns (address) {
 		require(false, stub_error);
@@ -133,7 +172,7 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
 	function safeTransferFromWithData(
@@ -150,7 +189,7 @@
 		dummy = 0;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFrom(address,address,uint256) 42842e0e
 	function safeTransferFrom(
@@ -165,6 +204,17 @@
 		dummy = 0;
 	}
 
+	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	//  THEY MAY BE PERMANENTLY LOST
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transferFrom(address,address,uint256) 23b872dd
 	function transferFrom(
 		address from,
@@ -178,6 +228,13 @@
 		dummy = 0;
 	}
 
+	// @notice Set or reaffirm the approved address for an NFT
+	// @dev The zero address indicates there is no approved address.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param approved The new approved NFT controller
+	// @param tokenId The NFT to approve
+	//
 	// Selector: approve(address,uint256) 095ea7b3
 	function approve(address approved, uint256 tokenId) public {
 		require(false, stub_error);
@@ -186,7 +243,7 @@
 		dummy = 0;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: setApprovalForAll(address,bool) a22cb465
 	function setApprovalForAll(address operator, bool approved) public {
@@ -196,7 +253,7 @@
 		dummy = 0;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: getApproved(uint256) 081812fc
 	function getApproved(uint256 tokenId) public view returns (address) {
@@ -206,7 +263,7 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: isApprovedForAll(address,address) e985e9c5
 	function isApprovedForAll(address owner, address operator)
@@ -224,6 +281,8 @@
 
 // Selector: 5b5e139f
 contract ERC721Metadata is Dummy, ERC165 {
+	// @notice A descriptive name for a collection of NFTs in this contract
+	//
 	// Selector: name() 06fdde03
 	function name() public view returns (string memory) {
 		require(false, stub_error);
@@ -231,6 +290,8 @@
 		return "";
 	}
 
+	// @notice An abbreviated name for NFTs in this contract
+	//
 	// Selector: symbol() 95d89b41
 	function symbol() public view returns (string memory) {
 		require(false, stub_error);
@@ -238,7 +299,11 @@
 		return "";
 	}
 
-	// Returns token's const_metadata
+	// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC
+	//  3986. The URI may point to a JSON file that conforms to the "ERC721
+	//  Metadata JSON Schema".
+	// @return token's const_metadata
 	//
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) public view returns (string memory) {
@@ -258,8 +323,11 @@
 		return false;
 	}
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
 	//
 	// Selector: mint(address,uint256) 40c10f19
 	function mint(address to, uint256 tokenId) public returns (bool) {
@@ -270,8 +338,12 @@
 		return false;
 	}
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token with the given tokenUri.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
+	// @param tokenUri Token URI that would be stored in the NFT properties
 	//
 	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
 	function mintWithTokenURI(
@@ -287,7 +359,7 @@
 		return false;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: finishMinting() 7d64bcb4
 	function finishMinting() public returns (bool) {
@@ -299,6 +371,11 @@
 
 // Selector: 780e9d63
 contract ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid NFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
 	// Selector: tokenByIndex(uint256) 4f6ccce7
 	function tokenByIndex(uint256 index) public view returns (uint256) {
 		require(false, stub_error);
@@ -307,7 +384,7 @@
 		return 0;
 	}
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
 	function tokenOfOwnerByIndex(address owner, uint256 index)
@@ -322,6 +399,10 @@
 		return 0;
 	}
 
+	// @notice Count NFTs tracked by this contract
+	// @return A count of valid NFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
 	// Selector: totalSupply() 18160ddd
 	function totalSupply() public view returns (uint256) {
 		require(false, stub_error);
@@ -332,6 +413,11 @@
 
 // Selector: 7d9262e6
 contract Collection is Dummy, ERC165 {
+	// Set collection property.
+	//
+	// @param key Property key.
+	// @param value Propery value.
+	//
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
 		public
@@ -342,6 +428,10 @@
 		dummy = 0;
 	}
 
+	// Delete collection property.
+	//
+	// @param key Property key.
+	//
 	// Selector: deleteCollectionProperty(string) 7b7debce
 	function deleteCollectionProperty(string memory key) public {
 		require(false, stub_error);
@@ -349,8 +439,13 @@
 		dummy = 0;
 	}
 
-	// Throws error if key not found
+	// Get collection property.
+	//
+	// @dev Throws error if key not found.
 	//
+	// @param key Property key.
+	// @return bytes The property corresponding to the key.
+	//
 	// Selector: collectionProperty(string) cf24fd6d
 	function collectionProperty(string memory key)
 		public
@@ -363,6 +458,12 @@
 		return hex"";
 	}
 
+	// Set the sponsor of the collection.
+	//
+	// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	//
+	// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	//
 	// Selector: setCollectionSponsor(address) 7623402e
 	function setCollectionSponsor(address sponsor) public {
 		require(false, stub_error);
@@ -370,12 +471,27 @@
 		dummy = 0;
 	}
 
+	// Collection sponsorship confirmation.
+	//
+	// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	//
 	// Selector: confirmCollectionSponsorship() 3c50e97a
 	function confirmCollectionSponsorship() public {
 		require(false, stub_error);
 		dummy = 0;
 	}
 
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"accountTokenOwnershipLimit",
+	// 	"sponsoredDataSize",
+	// 	"sponsoredDataRateLimit",
+	// 	"tokenLimit",
+	// 	"sponsorTransferTimeout",
+	// 	"sponsorApproveTimeout"
+	// @param value Value of the limit.
+	//
 	// Selector: setCollectionLimit(string,uint32) 6a3841db
 	function setCollectionLimit(string memory limit, uint32 value) public {
 		require(false, stub_error);
@@ -384,6 +500,14 @@
 		dummy = 0;
 	}
 
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"ownerCanTransfer",
+	// 	"ownerCanDestroy",
+	// 	"transfersEnabled"
+	// @param value Value of the limit.
+	//
 	// Selector: setCollectionLimit(string,bool) 993b7fba
 	function setCollectionLimit(string memory limit, bool value) public {
 		require(false, stub_error);
@@ -392,6 +516,8 @@
 		dummy = 0;
 	}
 
+	// Get contract address.
+	//
 	// Selector: contractAddress() f6b4dfb4
 	function contractAddress() public view returns (address) {
 		require(false, stub_error);
@@ -399,34 +525,51 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
+	// Add collection admin by substrate address.
+	// @param new_admin Substrate administrator address.
+	//
 	// Selector: addCollectionAdminSubstrate(uint256) 5730062b
-	function addCollectionAdminSubstrate(uint256 newAdmin) public view {
+	function addCollectionAdminSubstrate(uint256 newAdmin) public {
 		require(false, stub_error);
 		newAdmin;
-		dummy;
+		dummy = 0;
 	}
 
+	// Remove collection admin by substrate address.
+	// @param admin Substrate administrator address.
+	//
 	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
-	function removeCollectionAdminSubstrate(uint256 newAdmin) public view {
+	function removeCollectionAdminSubstrate(uint256 admin) public {
 		require(false, stub_error);
-		newAdmin;
-		dummy;
+		admin;
+		dummy = 0;
 	}
 
+	// Add collection admin.
+	// @param new_admin Address of the added administrator.
+	//
 	// Selector: addCollectionAdmin(address) 92e462c7
-	function addCollectionAdmin(address newAdmin) public view {
+	function addCollectionAdmin(address newAdmin) public {
 		require(false, stub_error);
 		newAdmin;
-		dummy;
+		dummy = 0;
 	}
 
+	// Remove collection admin.
+	//
+	// @param new_admin Address of the removed administrator.
+	//
 	// Selector: removeCollectionAdmin(address) fafd7b42
-	function removeCollectionAdmin(address admin) public view {
+	function removeCollectionAdmin(address admin) public {
 		require(false, stub_error);
 		admin;
-		dummy;
+		dummy = 0;
 	}
 
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	//
 	// Selector: setCollectionNesting(bool) 112d4586
 	function setCollectionNesting(bool enable) public {
 		require(false, stub_error);
@@ -434,6 +577,11 @@
 		dummy = 0;
 	}
 
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// @param collections Addresses of collections that will be available for nesting.
+	//
 	// Selector: setCollectionNesting(bool,address[]) 64872396
 	function setCollectionNesting(bool enable, address[] memory collections)
 		public
@@ -444,6 +592,11 @@
 		dummy = 0;
 	}
 
+	// Set the collection access method.
+	// @param mode Access mode
+	// 	0 for Normal
+	// 	1 for AllowList
+	//
 	// Selector: setCollectionAccess(uint8) 41835d4c
 	function setCollectionAccess(uint8 mode) public {
 		require(false, stub_error);
@@ -451,20 +604,32 @@
 		dummy = 0;
 	}
 
+	// Add the user to the allowed list.
+	//
+	// @param user Address of a trusted user.
+	//
 	// Selector: addToCollectionAllowList(address) 67844fe6
-	function addToCollectionAllowList(address user) public view {
+	function addToCollectionAllowList(address user) public {
 		require(false, stub_error);
 		user;
-		dummy;
+		dummy = 0;
 	}
 
+	// Remove the user from the allowed list.
+	//
+	// @param user Address of a removed user.
+	//
 	// Selector: removeFromCollectionAllowList(address) 85c51acb
-	function removeFromCollectionAllowList(address user) public view {
+	function removeFromCollectionAllowList(address user) public {
 		require(false, stub_error);
 		user;
-		dummy;
+		dummy = 0;
 	}
 
+	// Switch permission for minting.
+	//
+	// @param mode Enable if "true".
+	//
 	// Selector: setCollectionMintMode(bool) 00018e84
 	function setCollectionMintMode(bool mode) public {
 		require(false, stub_error);
@@ -475,6 +640,13 @@
 
 // Selector: d74d154f
 contract ERC721UniqueExtensions is Dummy, ERC165 {
+	// @notice Transfer ownership of an NFT
+	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	//  is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) public {
 		require(false, stub_error);
@@ -483,6 +655,14 @@
 		dummy = 0;
 	}
 
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: burnFrom(address,uint256) 79cc6790
 	function burnFrom(address from, uint256 tokenId) public {
 		require(false, stub_error);
@@ -491,6 +671,8 @@
 		dummy = 0;
 	}
 
+	// @notice Returns next free NFT ID.
+	//
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() public view returns (uint256) {
 		require(false, stub_error);
@@ -498,6 +680,12 @@
 		return 0;
 	}
 
+	// @notice Function to mint multiple tokens.
+	// @dev `tokenIds` should be an array of consecutive numbers and first number
+	//  should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokenIds IDs of the minted NFTs
+	//
 	// Selector: mintBulk(address,uint256[]) 44a9945e
 	function mintBulk(address to, uint256[] memory tokenIds)
 		public
@@ -510,6 +698,12 @@
 		return false;
 	}
 
+	// @notice Function to mint multiple tokens with the given tokenUris.
+	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	//  numbers and first number should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokens array of pairs of token ID and token URI for minted tokens
+	//
 	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
 	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
 		public
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -3,7 +3,7 @@
 //! Autogenerated weights for pallet_nonfungible
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-06-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
 
 // Executed Command:
@@ -56,7 +56,7 @@
 	// Storage: Nonfungible TokenData (r:0 w:1)
 	// Storage: Nonfungible Owned (r:0 w:1)
 	fn create_item() -> Weight {
-		(24_135_000 as Weight)
+		(20_328_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(4 as Weight))
 	}
@@ -65,9 +65,9 @@
 	// Storage: Nonfungible TokenData (r:0 w:4)
 	// Storage: Nonfungible Owned (r:0 w:4)
 	fn create_multiple_items(b: u32, ) -> Weight {
-		(21_952_000 as Weight)
-			// Standard Error: 5_000
-			.saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))
+		(10_134_000 as Weight)
+			// Standard Error: 3_000
+			.saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))
@@ -77,9 +77,9 @@
 	// Storage: Nonfungible TokenData (r:0 w:4)
 	// Storage: Nonfungible Owned (r:0 w:4)
 	fn create_multiple_items_ex(b: u32, ) -> Weight {
-		(10_432_000 as Weight)
-			// Standard Error: 6_000
-			.saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))
+		(5_710_000 as Weight)
+			// Standard Error: 4_000
+			.saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
@@ -93,7 +93,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_item() -> Weight {
-		(29_798_000 as Weight)
+		(28_433_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
@@ -105,7 +105,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_recursively_self_raw() -> Weight {
-		(37_955_000 as Weight)
+		(34_435_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
@@ -119,8 +119,8 @@
 	// Storage: Common CollectionById (r:1 w:0)
 	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 1_349_000
-			.saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))
+			// Standard Error: 1_539_000
+			.saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(7 as Weight))
 			.saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
@@ -131,14 +131,14 @@
 	// Storage: Nonfungible Allowance (r:1 w:0)
 	// Storage: Nonfungible Owned (r:0 w:2)
 	fn transfer() -> Weight {
-		(27_867_000 as Weight)
+		(24_376_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
 	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible Allowance (r:1 w:1)
 	fn approve() -> Weight {
-		(18_824_000 as Weight)
+		(15_890_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
@@ -147,7 +147,7 @@
 	// Storage: Nonfungible AccountBalance (r:2 w:2)
 	// Storage: Nonfungible Owned (r:0 w:2)
 	fn transfer_from() -> Weight {
-		(32_879_000 as Weight)
+		(28_634_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
 	}
@@ -159,7 +159,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_from() -> Weight {
-		(37_061_000 as Weight)
+		(32_201_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
 	}
@@ -167,28 +167,26 @@
 	fn set_token_property_permissions(b: u32, ) -> Weight {
 		(0 as Weight)
 			// Standard Error: 57_000
-			.saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible TokenProperties (r:1 w:1)
 	fn set_token_properties(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 2_278_000
-			.saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))
-			.saturating_add(T::DbWeight::get().reads(3 as Weight))
+			// Standard Error: 1_648_000
+			.saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible TokenProperties (r:1 w:1)
 	fn delete_token_properties(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 2_234_000
-			.saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))
-			.saturating_add(T::DbWeight::get().reads(3 as Weight))
+			// Standard Error: 1_632_000
+			.saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 }
@@ -200,7 +198,7 @@
 	// Storage: Nonfungible TokenData (r:0 w:1)
 	// Storage: Nonfungible Owned (r:0 w:1)
 	fn create_item() -> Weight {
-		(24_135_000 as Weight)
+		(20_328_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
 	}
@@ -209,9 +207,9 @@
 	// Storage: Nonfungible TokenData (r:0 w:4)
 	// Storage: Nonfungible Owned (r:0 w:4)
 	fn create_multiple_items(b: u32, ) -> Weight {
-		(21_952_000 as Weight)
-			// Standard Error: 5_000
-			.saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))
+		(10_134_000 as Weight)
+			// Standard Error: 3_000
+			.saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))
@@ -221,9 +219,9 @@
 	// Storage: Nonfungible TokenData (r:0 w:4)
 	// Storage: Nonfungible Owned (r:0 w:4)
 	fn create_multiple_items_ex(b: u32, ) -> Weight {
-		(10_432_000 as Weight)
-			// Standard Error: 6_000
-			.saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))
+		(5_710_000 as Weight)
+			// Standard Error: 4_000
+			.saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
@@ -237,7 +235,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_item() -> Weight {
-		(29_798_000 as Weight)
+		(28_433_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
@@ -249,7 +247,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_recursively_self_raw() -> Weight {
-		(37_955_000 as Weight)
+		(34_435_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
@@ -263,8 +261,8 @@
 	// Storage: Common CollectionById (r:1 w:0)
 	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 1_349_000
-			.saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))
+			// Standard Error: 1_539_000
+			.saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(7 as Weight))
 			.saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
@@ -275,14 +273,14 @@
 	// Storage: Nonfungible Allowance (r:1 w:0)
 	// Storage: Nonfungible Owned (r:0 w:2)
 	fn transfer() -> Weight {
-		(27_867_000 as Weight)
+		(24_376_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
 	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible Allowance (r:1 w:1)
 	fn approve() -> Weight {
-		(18_824_000 as Weight)
+		(15_890_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
@@ -291,7 +289,7 @@
 	// Storage: Nonfungible AccountBalance (r:2 w:2)
 	// Storage: Nonfungible Owned (r:0 w:2)
 	fn transfer_from() -> Weight {
-		(32_879_000 as Weight)
+		(28_634_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
 	}
@@ -303,7 +301,7 @@
 	// Storage: Nonfungible Owned (r:0 w:1)
 	// Storage: Nonfungible TokenProperties (r:0 w:1)
 	fn burn_from() -> Weight {
-		(37_061_000 as Weight)
+		(32_201_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
 	}
@@ -311,28 +309,26 @@
 	fn set_token_property_permissions(b: u32, ) -> Weight {
 		(0 as Weight)
 			// Standard Error: 57_000
-			.saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible TokenProperties (r:1 w:1)
 	fn set_token_properties(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 2_278_000
-			.saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))
-			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
+			// Standard Error: 1_648_000
+			.saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
-	// Storage: Nonfungible TokenData (r:1 w:0)
 	// Storage: Nonfungible TokenProperties (r:1 w:1)
 	fn delete_token_properties(b: u32, ) -> Weight {
 		(0 as Weight)
-			// Standard Error: 2_234_000
-			.saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))
-			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
+			// Standard Error: 1_632_000
+			.saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 }
addedpallets/refungible/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/refungible/CHANGELOG.md
@@ -0,0 +1,18 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [v0.1.2] - 2022-07-14
+
+### Other changes
+
+feat(refungible-pallet): add ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))
+test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))
+
+## [v0.1.1] - 2022-07-14
+
+### Other changes
+
+- feat: RPC method `token_owners` returning 10 owners in no particular order.
+
+This was an internal request to improve the web interface and support fractionalization event. 
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-refungible"
-version = "0.1.0"
+version = "0.1.2"
 license = "GPLv3"
 edition = "2021"
 
@@ -11,36 +11,43 @@
 version = '3.1.2'
 
 [dependencies]
-frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
 pallet-common = { default-features = false, path = '../common' }
 pallet-structure = { default-features = false, path = '../structure' }
+struct-versioning = { path = "../../crates/struct-versioning" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
+
+ethereum = { version = "0.12.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive",] }
+
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
-scale-info = { version = "2.0.1", default-features = false, features = [
-    "derive",
-] }
-struct-versioning = { path = "../../crates/struct-versioning" }
+frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
+frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.24" }
+sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
+sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
+sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.24" }
 
 [features]
 default = ["std"]
 std = [
+    "ethereum/std",
+    "evm-coder/std",
+    'frame-benchmarking/std',
     "frame-support/std",
     "frame-system/std",
+    "pallet-common/std",
+    "pallet-evm/std",
+    "pallet-evm-coder-substrate/std",
+    "pallet-structure/std",
     "sp-runtime/std",
     "sp-std/std",
     "up-data-structs/std",
-    "pallet-common/std",
-    "pallet-structure/std",
-    'frame-benchmarking/std',
-    "pallet-evm/std",
 ]
 runtime-benchmarks = [
     'frame-benchmarking',
     'frame-support/runtime-benchmarks',
     'frame-system/runtime-benchmarks',
+    'up-data-structs/runtime-benchmarks',
 ]
addedpallets/refungible/Changelog.mddiffbeforeafterboth
--- /dev/null
+++ b/pallets/refungible/Changelog.md
@@ -0,0 +1,3 @@
+### 0.1.1
+---
+* Added support for properties for RFT collections and tokens.
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -18,9 +18,12 @@
 use crate::{Pallet, Config, RefungibleHandle};
 
 use sp_std::prelude::*;
-use pallet_common::benchmarking::{create_collection_raw, create_data};
+use pallet_common::benchmarking::{create_collection_raw, property_key, property_value, create_data};
 use frame_benchmarking::{benchmarks, account};
-use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, CUSTOM_DATA_LIMIT, budget::Unlimited};
+use up_data_structs::{
+	CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT,
+	budget::Unlimited,
+};
 use pallet_common::bench_init;
 use core::convert::TryInto;
 use core::iter::IntoIterator;
@@ -38,6 +41,7 @@
 			.collect::<BTreeMap<_, _>>()
 			.try_into()
 			.unwrap(),
+		properties: Default::default(),
 	}
 }
 fn create_max_item<T: Config>(
@@ -204,6 +208,68 @@
 		<Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;
 	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}
 
+	set_token_property_permissions {
+		let b in 0..MAX_PROPERTIES_PER_ITEM;
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub;
+		};
+		let perms = (0..b).map(|k| PropertyKeyPermission {
+			key: property_key(k as usize),
+			permission: PropertyPermission {
+				mutable: false,
+				collection_admin: false,
+				token_owner: false,
+			},
+		}).collect::<Vec<_>>();
+	}: {<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?}
+
+	set_token_properties {
+		let b in 0..MAX_PROPERTIES_PER_ITEM;
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub;
+		};
+		let perms = (0..b).map(|k| PropertyKeyPermission {
+			key: property_key(k as usize),
+			permission: PropertyPermission {
+				mutable: false,
+				collection_admin: true,
+				token_owner: true,
+			},
+		}).collect::<Vec<_>>();
+		<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
+		let props = (0..b).map(|k| Property {
+			key: property_key(k as usize),
+			value: property_value(),
+		}).collect::<Vec<_>>();
+		let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
+	}: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}
+
+	delete_token_properties {
+		let b in 0..MAX_PROPERTIES_PER_ITEM;
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub;
+		};
+		let perms = (0..b).map(|k| PropertyKeyPermission {
+			key: property_key(k as usize),
+			permission: PropertyPermission {
+				mutable: true,
+				collection_admin: true,
+				token_owner: true,
+			},
+		}).collect::<Vec<_>>();
+		<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
+		let props = (0..b).map(|k| Property {
+			key: property_key(k as usize),
+			value: property_value(),
+		}).collect::<Vec<_>>();
+		let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
+		<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;
+		let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
+	}: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}
+
 	repartition_item {
 		bench_init!{
 			owner: sub; collection: collection(owner);
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -20,9 +20,12 @@
 use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};
 use up_data_structs::{
 	CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,
-	PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData,
+	PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData, CollectionPropertiesVec,
+};
+use pallet_common::{
+	CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
+	weights::WeightInfo as _,
 };
-use pallet_common::{CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight};
 use pallet_structure::Error as StructureError;
 use sp_runtime::{DispatchError};
 use sp_std::{vec::Vec, vec};
@@ -41,6 +44,14 @@
 	};
 }
 
+fn properties_weight<T: Config>(properties: &CollectionPropertiesVec) -> u64 {
+	if properties.len() > 0 {
+		<CommonWeights<T>>::set_token_properties(properties.len() as u32)
+	} else {
+		0
+	}
+}
+
 pub struct CommonWeights<T: Config>(PhantomData<T>);
 impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
 	fn create_item() -> Weight {
@@ -48,16 +59,31 @@
 	}
 
 	fn create_multiple_items(data: &[CreateItemData]) -> Weight {
-		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32)
+		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
+			data.iter()
+				.map(|data| match data {
+					CreateItemData::ReFungible(rft_data) => {
+						properties_weight::<T>(&rft_data.properties)
+					}
+					_ => 0,
+				})
+				.fold(0, |a, b| a.saturating_add(b)),
+		)
 	}
 
 	fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {
 		match call {
 			CreateItemExData::RefungibleMultipleOwners(i) => {
 				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)
+					.saturating_add(properties_weight::<T>(&i.properties))
 			}
 			CreateItemExData::RefungibleMultipleItems(i) => {
 				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)
+					.saturating_add(
+						i.iter()
+							.map(|d| properties_weight::<T>(&d.properties))
+							.fold(0, |a, b| a.saturating_add(b)),
+					)
 			}
 			_ => 0,
 		}
@@ -67,29 +93,24 @@
 		max_weight_of!(burn_item_partial(), burn_item_fully())
 	}
 
-	fn set_collection_properties(_amount: u32) -> Weight {
-		// Error
-		0
+	fn set_collection_properties(amount: u32) -> Weight {
+		<pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)
 	}
 
-	fn delete_collection_properties(_amount: u32) -> Weight {
-		// Error
-		0
+	fn delete_collection_properties(amount: u32) -> Weight {
+		<pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)
 	}
 
-	fn set_token_properties(_amount: u32) -> Weight {
-		// Error
-		0
+	fn set_token_properties(amount: u32) -> Weight {
+		<SelfWeightOf<T>>::set_token_properties(amount)
 	}
 
-	fn delete_token_properties(_amount: u32) -> Weight {
-		// Error
-		0
+	fn delete_token_properties(amount: u32) -> Weight {
+		<SelfWeightOf<T>>::delete_token_properties(amount)
 	}
 
-	fn set_token_property_permissions(_amount: u32) -> Weight {
-		// Error
-		0
+	fn set_token_property_permissions(amount: u32) -> Weight {
+		<SelfWeightOf<T>>::set_token_property_permissions(amount)
 	}
 
 	fn transfer() -> Weight {
@@ -140,11 +161,14 @@
 				out.insert(to.clone(), data.pieces);
 				out.try_into().expect("limit > 0")
 			},
+			properties: data.properties,
 		}),
 		_ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),
 	}
 }
 
+/// Implementation of `CommonCollectionOperations` for `RefungibleHandle`. It wraps Refungible Pallete
+/// methods and adds weight info.
 impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {
 	fn create_item(
 		&self,
@@ -295,46 +319,85 @@
 
 	fn set_collection_properties(
 		&self,
-		_sender: T::CrossAccountId,
-		_property: Vec<Property>,
+		sender: T::CrossAccountId,
+		properties: Vec<Property>,
 	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::SettingPropertiesNotAllowed)
+		let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);
+
+		with_weight(
+			<Pallet<T>>::set_collection_properties(self, &sender, properties),
+			weight,
+		)
 	}
 
 	fn delete_collection_properties(
 		&self,
-		_sender: &T::CrossAccountId,
-		_property_keys: Vec<PropertyKey>,
+		sender: &T::CrossAccountId,
+		property_keys: Vec<PropertyKey>,
 	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::SettingPropertiesNotAllowed)
+		let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);
+
+		with_weight(
+			<Pallet<T>>::delete_collection_properties(self, sender, property_keys),
+			weight,
+		)
 	}
 
 	fn set_token_properties(
 		&self,
-		_sender: T::CrossAccountId,
-		_token_id: TokenId,
-		_property: Vec<Property>,
-		_nesting_budget: &dyn Budget,
+		sender: T::CrossAccountId,
+		token_id: TokenId,
+		properties: Vec<Property>,
+		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::SettingPropertiesNotAllowed)
+		let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);
+
+		with_weight(
+			<Pallet<T>>::set_token_properties(
+				self,
+				&sender,
+				token_id,
+				properties.into_iter(),
+				false,
+				nesting_budget,
+			),
+			weight,
+		)
 	}
 
 	fn set_token_property_permissions(
 		&self,
-		_sender: &T::CrossAccountId,
-		_property_permissions: Vec<PropertyKeyPermission>,
+		sender: &T::CrossAccountId,
+		property_permissions: Vec<PropertyKeyPermission>,
 	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::SettingPropertiesNotAllowed)
+		let weight =
+			<CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);
+
+		with_weight(
+			<Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),
+			weight,
+		)
 	}
 
 	fn delete_token_properties(
 		&self,
-		_sender: T::CrossAccountId,
-		_token_id: TokenId,
-		_property_keys: Vec<PropertyKey>,
-		_nesting_budget: &dyn Budget,
+		sender: T::CrossAccountId,
+		token_id: TokenId,
+		property_keys: Vec<PropertyKey>,
+		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::SettingPropertiesNotAllowed)
+		let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);
+
+		with_weight(
+			<Pallet<T>>::delete_token_properties(
+				self,
+				&sender,
+				token_id,
+				property_keys.into_iter(),
+				nesting_budget,
+			),
+			weight,
+		)
 	}
 
 	fn check_nesting(
@@ -371,8 +434,13 @@
 		TokenId(<TokensMinted<T>>::get(self.id))
 	}
 
-	fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {
-		None
+	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {
+		<Pallet<T>>::token_owner(self.id, token)
+	}
+
+	/// Returns 10 token in no particular order.
+	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
+		<Pallet<T>>::token_owners(self.id, token).unwrap_or_default()
 	}
 
 	fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -14,34 +14,35 @@
 // 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 up_data_structs::TokenId;
-use pallet_common::erc::CommonEvmHandler;
-use pallet_evm::PrecompileHandle;
+extern crate alloc;
+use evm_coder::{generate_stubgen, solidity_interface, types::*};
 
-use crate::{Config, RefungibleHandle};
+use pallet_common::{CollectionHandle, erc::CollectionCall, erc::CommonEvmHandler};
 
-impl<T: Config> CommonEvmHandler for RefungibleHandle<T> {
-	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");
+use pallet_evm::PrecompileHandle;
+use pallet_evm_coder_substrate::call;
 
-	fn call(
-		self,
-		_handle: &mut impl PrecompileHandle,
-	) -> Option<pallet_common::erc::PrecompileResult> {
-		// TODO: Implement RFT variant of ERC721
-		None
-	}
-}
+use crate::{Config, RefungibleHandle};
 
-pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
+#[solidity_interface(
+	name = "UniqueRFT",
+	is(via("CollectionHandle<T>", common_mut, Collection),)
+)]
+impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> {}
 
-impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T> {
-	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");
+// Not a tests, but code generators
+generate_stubgen!(gen_impl, UniqueRFTCall<()>, true);
+generate_stubgen!(gen_iface, UniqueRFTCall<()>, false);
 
+impl<T: Config> CommonEvmHandler for RefungibleHandle<T>
+where
+	T::AccountId: From<[u8; 32]>,
+{
+	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");
 	fn call(
 		self,
-		_handle: &mut impl PrecompileHandle,
+		handle: &mut impl PrecompileHandle,
 	) -> Option<pallet_common::erc::PrecompileResult> {
-		// TODO: Implement RFT variant of ERC20
-		None
+		call::<T, UniqueRFTCall<T>, _, _>(handle, self)
 	}
 }
addedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/refungible/src/erc_token.rs
@@ -0,0 +1,257 @@
+// 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/>.
+
+//! # Refungible Pallet EVM API for token pieces
+//!
+//! Provides ERC-20 standart support implementation and EVM API for unique extensions for Refungible Pallet.
+//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.
+
+extern crate alloc;
+use core::{
+	char::{REPLACEMENT_CHARACTER, decode_utf16},
+	convert::TryInto,
+	ops::Deref,
+};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
+use pallet_common::{
+	CommonWeightInfo,
+	erc::{CommonEvmHandler, PrecompileResult},
+};
+use pallet_evm::{account::CrossAccountId, PrecompileHandle};
+use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};
+use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
+use sp_std::vec::Vec;
+use up_data_structs::TokenId;
+
+use crate::{
+	Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,
+	weights::WeightInfo, TotalSupply,
+};
+
+pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
+
+#[derive(ToLog)]
+pub enum ERC20Events {
+	/// @dev This event is emitted when the amount of tokens (value) is sent
+	/// from the from address to the to address. In the case of minting new
+	/// tokens, the transfer is usually from the 0 address while in the case
+	/// of burning tokens the transfer is to 0.
+	Transfer {
+		#[indexed]
+		from: address,
+		#[indexed]
+		to: address,
+		value: uint256,
+	},
+	/// @dev This event is emitted when the amount of tokens (value) is approved
+	/// by the owner to be used by the spender.
+	Approval {
+		#[indexed]
+		owner: address,
+		#[indexed]
+		spender: address,
+		value: uint256,
+	},
+}
+
+/// @title Standard ERC20 token
+///
+/// @dev Implementation of the basic standard token.
+/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
+#[solidity_interface(name = "ERC20", events(ERC20Events))]
+impl<T: Config> RefungibleTokenHandle<T> {
+	/// @return the name of the token.
+	fn name(&self) -> Result<string> {
+		Ok(decode_utf16(self.name.iter().copied())
+			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
+			.collect::<string>())
+	}
+
+	/// @return the symbol of the token.
+	fn symbol(&self) -> Result<string> {
+		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	}
+
+	/// @dev Total number of tokens in existence
+	fn total_supply(&self) -> Result<uint256> {
+		self.consume_store_reads(1)?;
+		Ok(<TotalSupply<T>>::get((self.id, self.1)).into())
+	}
+
+	/// @dev Not supported
+	fn decimals(&self) -> Result<uint8> {
+		// Decimals aren't supported for refungible tokens
+		Ok(0)
+	}
+
+	/// @dev Gets the balance of the specified address.
+	/// @param owner The address to query the balance of.
+	/// @return An uint256 representing the amount owned by the passed address.
+	fn balance_of(&self, owner: address) -> Result<uint256> {
+		self.consume_store_reads(1)?;
+		let owner = T::CrossAccountId::from_eth(owner);
+		let balance = <Balance<T>>::get((self.id, self.1, owner));
+		Ok(balance.into())
+	}
+
+	/// @dev Transfer token for a specified address
+	/// @param to The address to transfer to.
+	/// @param amount The amount to be transferred.
+	#[weight(<CommonWeights<T>>::transfer())]
+	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let to = T::CrossAccountId::from_eth(to);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+		let budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::transfer(self, &caller, &to, self.1, amount, &budget)
+			.map_err(|_| "transfer error")?;
+		Ok(true)
+	}
+
+	/// @dev Transfer tokens from one address to another
+	/// @param from address The address which you want to send tokens from
+	/// @param to address The address which you want to transfer to
+	/// @param amount uint256 the amount of tokens to be transferred
+	#[weight(<CommonWeights<T>>::transfer_from())]
+	fn transfer_from(
+		&mut self,
+		caller: caller,
+		from: address,
+		to: address,
+		amount: uint256,
+	) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let to = T::CrossAccountId::from_eth(to);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+		let budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
+
+	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
+	/// Beware that changing an allowance with this method brings the risk that someone may use both the old
+	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
+	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
+	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+	/// @param spender The address which will spend the funds.
+	/// @param amount The amount of tokens to be spent.
+	#[weight(<SelfWeightOf<T>>::approve())]
+	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let spender = T::CrossAccountId::from_eth(spender);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Pallet<T>>::set_allowance(self, &caller, &spender, self.1, amount)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
+
+	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
+	/// @param owner address The address which owns the funds.
+	/// @param spender address The address which will spend the funds.
+	/// @return A uint256 specifying the amount of tokens still available for the spender.
+	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+		self.consume_store_reads(1)?;
+		let owner = T::CrossAccountId::from_eth(owner);
+		let spender = T::CrossAccountId::from_eth(spender);
+
+		Ok(<Allowance<T>>::get((self.id, self.1, owner, spender)).into())
+	}
+}
+
+#[solidity_interface(name = "ERC20UniqueExtensions")]
+impl<T: Config> RefungibleTokenHandle<T> {
+	/// @dev Function that burns an amount of the token of a given account,
+	/// deducting from the sender's allowance for said account.
+	/// @param from The account whose tokens will be burnt.
+	/// @param amount The amount that will be burnt.
+	#[weight(<SelfWeightOf<T>>::burn_from())]
+	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+		let budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::burn_from(self, &caller, &from, self.1, amount, &budget)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
+
+	/// @dev Function that changes total amount of the tokens.
+	///  Throws if `msg.sender` doesn't owns all of the tokens.
+	/// @param amount New total amount of the tokens.
+	#[weight(<SelfWeightOf<T>>::repartition_item())]
+	fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Pallet<T>>::repartition(self, &caller, self.1, amount).map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
+}
+
+impl<T: Config> RefungibleTokenHandle<T> {
+	pub fn into_inner(self) -> RefungibleHandle<T> {
+		self.0
+	}
+	pub fn common_mut(&mut self) -> &mut RefungibleHandle<T> {
+		&mut self.0
+	}
+}
+
+impl<T: Config> WithRecorder<T> for RefungibleTokenHandle<T> {
+	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.recorder()
+	}
+	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.into_recorder()
+	}
+}
+
+impl<T: Config> Deref for RefungibleTokenHandle<T> {
+	type Target = RefungibleHandle<T>;
+
+	fn deref(&self) -> &Self::Target {
+		&self.0
+	}
+}
+
+#[solidity_interface(name = "UniqueRefungibleToken", is(ERC20, ERC20UniqueExtensions,))]
+impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}
+
+generate_stubgen!(gen_impl, UniqueRefungibleTokenCall<()>, true);
+generate_stubgen!(gen_iface, UniqueRefungibleTokenCall<()>, false);
+
+impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T>
+where
+	T::AccountId: From<[u8; 32]>,
+{
+	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");
+
+	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
+		call::<T, UniqueRefungibleTokenCall<T>, _, _>(handle, self)
+	}
+}
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -14,32 +14,113 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Refungible Pallet
+//!
+//! The Refungible pallet provides functionality for handling refungible collections and tokens.
+//!
+//! - [`Config`]
+//! - [`RefungibleHandle`]
+//! - [`Pallet`]
+//! - [`CommonWeights`](common::CommonWeights)
+//!
+//! ## Overview
+//!
+//! The Refungible pallet provides functions for:
+//!
+//! - RFT collection creation and removal
+//! - Minting and burning of RFT tokens
+//! - Partition and repartition of RFT tokens
+//! - Retrieving number of pieces of RFT token
+//! - Retrieving account balances
+//! - Transfering RFT token pieces
+//! - Burning RFT token pieces
+//! - Setting and checking allowance for RFT tokens
+//!
+//! ### Terminology
+//!
+//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all
+//!   of the RFT token pieces than it owns the RFT token and can repartition it.
+//!
+//! - **RFT Collection:** A collection of RFT tokens. All RFT tokens are part of a collection.
+//!   Each collection has its own settings and set of permissions.
+//!
+//! - **RFT token piece:** A fungible part of an RFT token.
+//!
+//! - **Balance:** RFT token pieces owned by an account
+//!
+//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to
+//!   transfer from the balance of another account
+//!
+//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from
+//!   an account balance.
+//!
+//! ### Implementations
+//!
+//! The Refungible pallet provides implementations for the following traits. If these traits provide
+//! the functionality that you need, then you can avoid coupling with the Refungible pallet.
+//!
+//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight
+//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing
+//!   with collections
+//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible
+//!   collection
+//!
+//! ## Interface
+//!
+//! ### Dispatchable Functions
+//!
+//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for
+//!   some accounts.
+//! - `destroy_collection` - Destroy exising RFT collection. There should be no tokens in the collection.
+//! - `burn` - Burn some amount of RFT token pieces owned by account. Burns the RFT token if no pieces left.
+//! - `transfer` - Transfer some amount of RFT token pieces. Transfers should be enabled for RFT collection.
+//!   Nests the RFT token if RFT token pieces are sent to another token.
+//! - `create_item` - Mint RFT token in collection. Sender should have permission to mint tokens.
+//! - `set_allowance` - Set allowance for another account to transfer balance from sender's account.
+//! - `repartition` - Repartition token to selected number of pieces. Sender should own all existing pieces.
+//!
+//! ## Assumptions
+//!
+//! * Total number of pieces for one token shouldn't exceed `up_data_structs::MAX_REFUNGIBLE_PIECES`.
+//! * Total number of tokens of all types shouldn't be greater than `up_data_structs::MAX_TOKEN_PREFIX_LENGTH`.
+//! * Sender should be in collection's allow list to perform operations on tokens.
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
-use frame_support::{ensure, BoundedVec};
-use up_data_structs::{
-	AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,
-	CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,
+use crate::erc_token::ERC20Events;
+
+use codec::{Encode, Decode, MaxEncodedLen};
+use core::ops::Deref;
+use evm_coder::ToLog;
+use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};
+use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
+use pallet_evm_coder_substrate::WithRecorder;
+use pallet_common::{
+	CommonCollectionOperations, Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,
 };
-use pallet_evm::account::CrossAccountId;
-use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};
 use pallet_structure::Pallet as PalletStructure;
-use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
+use scale_info::TypeInfo;
+use sp_core::H160;
+use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
-use core::ops::Deref;
-use codec::{Encode, Decode, MaxEncodedLen};
-use scale_info::TypeInfo;
+use up_data_structs::{
+	AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData,
+	CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId, Property,
+	PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,
+	TrySetProperty,
+};
 
 pub use pallet::*;
 #[cfg(feature = "runtime-benchmarks")]
 pub mod benchmarking;
 pub mod common;
 pub mod erc;
+pub mod erc_token;
 pub mod weights;
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
-/// Token data, stored independently from other data used to describe it.
-/// Notably contains the token metadata.
+/// Token data, stored independently from other data used to describe it
+/// for the convenience of database access. Notably contains the token metadata.
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]
 pub struct ItemData {
@@ -108,6 +189,16 @@
 
 	/// Amount of pieces a refungible token is split into.
 	#[pallet::storage]
+	#[pallet::getter(fn token_properties)]
+	pub type TokenProperties<T: Config> = StorageNMap<
+		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
+		Value = up_data_structs::Properties,
+		QueryKind = ValueQuery,
+		OnEmpty = up_data_structs::TokenProperties,
+	>;
+
+	/// Total amount of pieces for token
+	#[pallet::storage]
 	pub type TotalSupply<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
 		Value = u128,
@@ -138,7 +229,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Amount of pieces of a token owned by an account.
+	/// Amount of token pieces owned by account.
 	#[pallet::storage]
 	pub type Balance<T: Config> = StorageNMap<
 		Key = (
@@ -151,7 +242,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// todo:doc
+	/// Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (
@@ -188,7 +279,11 @@
 	pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {
 		self.0
 	}
+	pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {
+		&mut self.0
+	}
 }
+
 impl<T: Config> Deref for RefungibleHandle<T> {
 	type Target = pallet_common::CollectionHandle<T>;
 
@@ -197,23 +292,75 @@
 	}
 }
 
+impl<T: Config> WithRecorder<T> for RefungibleHandle<T> {
+	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.recorder()
+	}
+	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.into_recorder()
+	}
+}
+
 impl<T: Config> Pallet<T> {
+	/// Get number of RFT tokens in collection
 	pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {
 		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)
 	}
+
+	/// Check that RFT token exists
+	///
+	/// - `token`: Token ID.
 	pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {
 		<TotalSupply<T>>::contains_key((collection.id, token))
 	}
+
+	pub fn set_scoped_token_property(
+		collection_id: CollectionId,
+		token_id: TokenId,
+		scope: PropertyScope,
+		property: Property,
+	) -> DispatchResult {
+		TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {
+			properties.try_scoped_set(scope, property.key, property.value)
+		})
+		.map_err(<CommonError<T>>::from)?;
+
+		Ok(())
+	}
+
+	pub fn set_scoped_token_properties(
+		collection_id: CollectionId,
+		token_id: TokenId,
+		scope: PropertyScope,
+		properties: impl Iterator<Item = Property>,
+	) -> DispatchResult {
+		TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {
+			stored_properties.try_scoped_set_from_iter(scope, properties)
+		})
+		.map_err(<CommonError<T>>::from)?;
+
+		Ok(())
+	}
 }
 
 // unchecked calls skips any permission checks
 impl<T: Config> Pallet<T> {
+	/// Create RFT collection
+	///
+	/// `init_collection` will take non-refundable deposit for collection creation.
+	///
+	/// - `data`: Contains settings for collection limits and permissions.
 	pub fn init_collection(
 		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data, false)
 	}
+
+	/// Destroy RFT collection
+	///
+	/// `destroy_collection` will throw error if collection contains any tokens.
+	/// Only owner can destroy collection.
 	pub fn destroy_collection(
 		collection: RefungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -245,13 +392,17 @@
 			.is_some()
 	}
 
-	pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {
+	pub fn burn_token_unchecked(
+		collection: &RefungibleHandle<T>,
+		token_id: TokenId,
+	) -> DispatchResult {
 		let burnt = <TokensBurnt<T>>::get(collection.id)
 			.checked_add(1)
 			.ok_or(ArithmeticError::Overflow)?;
 
 		<TokensBurnt<T>>::insert(collection.id, burnt);
 		<TokenData<T>>::remove((collection.id, token_id));
+		<TokenProperties<T>>::remove((collection.id, token_id));
 		<TotalSupply<T>>::remove((collection.id, token_id));
 		<Balance<T>>::remove_prefix((collection.id, token_id), None);
 		<Allowance<T>>::remove_prefix((collection.id, token_id), None);
@@ -259,6 +410,17 @@
 		Ok(())
 	}
 
+	/// Burn RFT token pieces
+	///
+	/// `burn` will decrease total amount of token pieces and amount owned by sender.
+	/// `burn` can be called even if there are multiple owners of the RFT token.
+	/// If sender wouldn't have any pieces left after `burn` than she will stop being
+	/// one of the owners of the token. If there is no account that owns any pieces of
+	/// the token than token will be burned too.
+	///
+	/// - `amount`: Amount of token pieces to burn.
+	/// - `token`: Token who's pieces should be burned
+	/// - `collection`: Collection that contains the token
 	pub fn burn(
 		collection: &RefungibleHandle<T>,
 		owner: &T::CrossAccountId,
@@ -286,7 +448,7 @@
 			<Owned<T>>::remove((collection.id, owner, token));
 			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);
 			<AccountBalance<T>>::insert((collection.id, owner), account_balance);
-			Self::burn_token(collection, token)?;
+			Self::burn_token_unchecked(collection, token)?;
 			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
 				collection.id,
 				token,
@@ -319,7 +481,18 @@
 			<Balance<T>>::insert((collection.id, token, owner), balance);
 		}
 		<TotalSupply<T>>::insert((collection.id, token), total_supply);
-		// TODO: ERC20 transfer event
+
+		<PalletEvm<T>>::deposit_log(
+			ERC20Events::Transfer {
+				from: *owner.as_eth(),
+				to: H160::default(),
+				value: amount.into(),
+			}
+			.to_log(T::EvmTokenAddressMapping::token_to_address(
+				collection.id,
+				token,
+			)),
+		);
 		<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
 			collection.id,
 			token,
@@ -329,6 +502,179 @@
 		Ok(())
 	}
 
+	#[transactional]
+	fn modify_token_properties(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		token_id: TokenId,
+		properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
+		is_token_create: bool,
+		nesting_budget: &dyn Budget,
+	) -> DispatchResult {
+		let is_collection_admin = || collection.is_owner_or_admin(sender);
+		let is_token_owner = || -> Result<bool, DispatchError> {
+			let balance = collection.balance(sender.clone(), token_id);
+			let total_pieces: u128 =
+				Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);
+			if balance != total_pieces {
+				return Ok(false);
+			}
+
+			let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(
+				sender.clone(),
+				collection.id,
+				token_id,
+				None,
+				nesting_budget,
+			)?;
+
+			Ok(is_bundle_owner)
+		};
+
+		for (key, value) in properties {
+			let permission = <PalletCommon<T>>::property_permissions(collection.id)
+				.get(&key)
+				.cloned()
+				.unwrap_or_else(PropertyPermission::none);
+
+			let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))
+				.get(&key)
+				.is_some();
+
+			match permission {
+				PropertyPermission { mutable: false, .. } if is_property_exists => {
+					return Err(<CommonError<T>>::NoPermission.into());
+				}
+
+				PropertyPermission {
+					collection_admin,
+					token_owner,
+					..
+				} => {
+					//TODO: investigate threats during public minting.
+					let is_token_create =
+						is_token_create && (collection_admin || token_owner) && value.is_some();
+					if !(is_token_create
+						|| (collection_admin && is_collection_admin())
+						|| (token_owner && is_token_owner()?))
+					{
+						fail!(<CommonError<T>>::NoPermission);
+					}
+				}
+			}
+
+			match value {
+				Some(value) => {
+					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
+						properties.try_set(key.clone(), value)
+					})
+					.map_err(<CommonError<T>>::from)?;
+
+					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(
+						collection.id,
+						token_id,
+						key,
+					));
+				}
+				None => {
+					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
+						properties.remove(&key)
+					})
+					.map_err(<CommonError<T>>::from)?;
+
+					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
+						collection.id,
+						token_id,
+						key,
+					));
+				}
+			}
+		}
+
+		Ok(())
+	}
+
+	pub fn set_token_properties(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		token_id: TokenId,
+		properties: impl Iterator<Item = Property>,
+		is_token_create: bool,
+		nesting_budget: &dyn Budget,
+	) -> DispatchResult {
+		Self::modify_token_properties(
+			collection,
+			sender,
+			token_id,
+			properties.map(|p| (p.key, Some(p.value))),
+			is_token_create,
+			nesting_budget,
+		)
+	}
+
+	pub fn set_token_property(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		token_id: TokenId,
+		property: Property,
+		nesting_budget: &dyn Budget,
+	) -> DispatchResult {
+		let is_token_create = false;
+
+		Self::set_token_properties(
+			collection,
+			sender,
+			token_id,
+			[property].into_iter(),
+			is_token_create,
+			nesting_budget,
+		)
+	}
+
+	pub fn delete_token_properties(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		token_id: TokenId,
+		property_keys: impl Iterator<Item = PropertyKey>,
+		nesting_budget: &dyn Budget,
+	) -> DispatchResult {
+		let is_token_create = false;
+
+		Self::modify_token_properties(
+			collection,
+			sender,
+			token_id,
+			property_keys.into_iter().map(|key| (key, None)),
+			is_token_create,
+			nesting_budget,
+		)
+	}
+
+	pub fn delete_token_property(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		token_id: TokenId,
+		property_key: PropertyKey,
+		nesting_budget: &dyn Budget,
+	) -> DispatchResult {
+		Self::delete_token_properties(
+			collection,
+			sender,
+			token_id,
+			[property_key].into_iter(),
+			nesting_budget,
+		)
+	}
+
+	/// Transfer RFT token pieces from one account to another.
+	///
+	/// If the sender is no longer owns any pieces after the `transfer` than she stops being an owner of the token.
+	///
+	/// - `from`: Owner of token pieces to transfer.
+	/// - `to`: Recepient of transfered token pieces.
+	/// - `amount`: Amount of token pieces to transfer.
+	/// - `token`: Token whos pieces should be transfered
+	/// - `collection`: Collection that contains the token
 	pub fn transfer(
 		collection: &RefungibleHandle<T>,
 		from: &T::CrossAccountId,
@@ -422,7 +768,17 @@
 			}
 		}
 
-		// TODO: ERC20 transfer event
+		<PalletEvm<T>>::deposit_log(
+			ERC20Events::Transfer {
+				from: *from.as_eth(),
+				to: *to.as_eth(),
+				value: amount.into(),
+			}
+			.to_log(T::EvmTokenAddressMapping::token_to_address(
+				collection.id,
+				token,
+			)),
+		);
 		<PalletCommon<T>>::deposit_event(CommonEvent::Transfer(
 			collection.id,
 			token,
@@ -433,6 +789,11 @@
 		Ok(())
 	}
 
+	/// Batched operation to create multiple RFT tokens.
+	///
+	/// Same as `create_item` but creates multiple tokens.
+	///
+	/// - `data`: Same as 'data` in `create_item` but contains data for multiple tokens.
 	pub fn create_multiple_items(
 		collection: &RefungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -517,34 +878,70 @@
 
 		// =========
 
+		with_transaction(|| {
+			for (i, data) in data.iter().enumerate() {
+				let token_id = first_token_id + i as u32 + 1;
+				<TotalSupply<T>>::insert((collection.id, token_id), totals[i]);
+
+				<TokenData<T>>::insert(
+					(collection.id, token_id),
+					ItemData {
+						const_data: data.const_data.clone(),
+					},
+				);
+
+				for (user, amount) in data.users.iter() {
+					if *amount == 0 {
+						continue;
+					}
+					<Balance<T>>::insert((collection.id, token_id, &user), amount);
+					<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);
+					<PalletStructure<T>>::nest_if_sent_to_token_unchecked(
+						user,
+						collection.id,
+						TokenId(token_id),
+					);
+				}
+
+				if let Err(e) = Self::set_token_properties(
+					collection,
+					sender,
+					TokenId(token_id),
+					data.properties.clone().into_iter(),
+					true,
+					nesting_budget,
+				) {
+					return TransactionOutcome::Rollback(Err(e));
+				}
+			}
+			TransactionOutcome::Commit(Ok(()))
+		})?;
+
 		<TokensMinted<T>>::insert(collection.id, tokens_minted);
+
 		for (account, balance) in balances {
 			<AccountBalance<T>>::insert((collection.id, account), balance);
 		}
+
 		for (i, token) in data.into_iter().enumerate() {
 			let token_id = first_token_id + i as u32 + 1;
-			<TotalSupply<T>>::insert((collection.id, token_id), totals[i]);
-
-			<TokenData<T>>::insert(
-				(collection.id, token_id),
-				ItemData {
-					const_data: token.const_data,
-				},
-			);
 
 			for (user, amount) in token.users.into_iter() {
 				if amount == 0 {
 					continue;
 				}
-				<Balance<T>>::insert((collection.id, token_id, &user), amount);
-				<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);
-				<PalletStructure<T>>::nest_if_sent_to_token_unchecked(
-					&user,
-					collection.id,
-					TokenId(token_id),
+
+				<PalletEvm<T>>::deposit_log(
+					ERC20Events::Transfer {
+						from: H160::default(),
+						to: *user.as_eth(),
+						value: amount.into(),
+					}
+					.to_log(T::EvmTokenAddressMapping::token_to_address(
+						collection.id,
+						TokenId(token_id),
+					)),
 				);
-
-				// TODO: ERC20 transfer event
 				<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
 					collection.id,
 					TokenId(token_id),
@@ -568,7 +965,18 @@
 		} else {
 			<Allowance<T>>::insert((collection.id, token, sender, spender), amount);
 		}
-		// TODO: ERC20 approval event
+
+		<PalletEvm<T>>::deposit_log(
+			ERC20Events::Approval {
+				owner: *sender.as_eth(),
+				spender: *spender.as_eth(),
+				value: amount.into(),
+			}
+			.to_log(T::EvmTokenAddressMapping::token_to_address(
+				collection.id,
+				token,
+			)),
+		);
 		<PalletCommon<T>>::deposit_event(CommonEvent::Approved(
 			collection.id,
 			token,
@@ -578,6 +986,9 @@
 		))
 	}
 
+	/// Set allowance for the spender to `transfer` or `burn` sender's token pieces.
+	///
+	/// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.
 	pub fn set_allowance(
 		collection: &RefungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -646,6 +1057,12 @@
 		Ok(allowance)
 	}
 
+	/// Transfer RFT token pieces from one account to another.
+	///
+	/// Same as the [`transfer`] but spender doesn't needs to be an owner of the token pieces.
+	/// The owner should set allowance for the spender to transfer pieces.
+	///
+	/// [`transfer`]: struct.Pallet.html#method.transfer
 	pub fn transfer_from(
 		collection: &RefungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -667,6 +1084,12 @@
 		Ok(())
 	}
 
+	/// Burn RFT token pieces from the account.
+	///
+	/// Same as the [`burn`] but spender doesn't need to be an owner of the token pieces. The owner should
+	/// set allowance for the spender to burn pieces
+	///
+	/// [`burn`]: struct.Pallet.html#method.burn
 	pub fn burn_from(
 		collection: &RefungibleHandle<T>,
 		spender: &T::CrossAccountId,
@@ -687,7 +1110,13 @@
 		Ok(())
 	}
 
-	/// Delegated to `create_multiple_items`
+	/// Create RFT token.
+	///
+	/// The sender should be the owner/admin of the collection or collection should be configured
+	/// to allow public minting.
+	///
+	/// - `data`: Contains list of users who will become the owners of the token pieces and amount
+	///   of token pieces they will receive.
 	pub fn create_item(
 		collection: &RefungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -697,6 +1126,13 @@
 		Self::create_multiple_items(collection, sender, vec![data], nesting_budget)
 	}
 
+	/// Repartition RFT token.
+	///
+	/// `repartition` will set token balance of the sender and total amount of token pieces.
+	/// Sender should own all of the token pieces. `repartition' could be done even if some
+	/// token pieces were burned before.
+	///
+	/// - `amount`: Total amount of token pieces that the token will have after `repartition`.
 	pub fn repartition(
 		collection: &RefungibleHandle<T>,
 		owner: &T::CrossAccountId,
@@ -709,19 +1145,119 @@
 		);
 		ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);
 		// Ensure user owns all pieces
-		let total_supply = <TotalSupply<T>>::get((collection.id, token));
+		let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);
 		let balance = <Balance<T>>::get((collection.id, token, owner));
 		ensure!(
-			total_supply == balance,
+			total_pieces == balance,
 			<Error<T>>::RepartitionWhileNotOwningAllPieces
 		);
 
 		<Balance<T>>::insert((collection.id, token, owner), amount);
 		<TotalSupply<T>>::insert((collection.id, token), amount);
+
+		if amount > total_pieces {
+			let mint_amount = amount - total_pieces;
+			<PalletEvm<T>>::deposit_log(
+				ERC20Events::Transfer {
+					from: H160::default(),
+					to: *owner.as_eth(),
+					value: mint_amount.into(),
+				}
+				.to_log(T::EvmTokenAddressMapping::token_to_address(
+					collection.id,
+					token,
+				)),
+			);
+			<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
+				collection.id,
+				token,
+				owner.clone(),
+				mint_amount,
+			));
+		} else if total_pieces > amount {
+			let burn_amount = total_pieces - amount;
+			<PalletEvm<T>>::deposit_log(
+				ERC20Events::Transfer {
+					from: *owner.as_eth(),
+					to: H160::default(),
+					value: burn_amount.into(),
+				}
+				.to_log(T::EvmTokenAddressMapping::token_to_address(
+					collection.id,
+					token,
+				)),
+			);
+			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
+				collection.id,
+				token,
+				owner.clone(),
+				burn_amount,
+			));
+		}
+
 		Ok(())
 	}
 
+	fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {
+		let mut owner = None;
+		let mut count = 0;
+		for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {
+			count += 1;
+			if count > 1 {
+				return None;
+			}
+			owner = Some(key);
+		}
+		owner
+	}
+
 	fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {
 		<TotalSupply<T>>::try_get((collection_id, token_id)).ok()
 	}
+
+	pub fn set_collection_properties(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		properties: Vec<Property>,
+	) -> DispatchResult {
+		<PalletCommon<T>>::set_collection_properties(collection, sender, properties)
+	}
+
+	pub fn delete_collection_properties(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		property_keys: Vec<PropertyKey>,
+	) -> DispatchResult {
+		<PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)
+	}
+
+	pub fn set_token_property_permissions(
+		collection: &RefungibleHandle<T>,
+		sender: &T::CrossAccountId,
+		property_permissions: Vec<PropertyKeyPermission>,
+	) -> DispatchResult {
+		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)
+	}
+
+	/// Returns 10 token in no particular order.
+	///
+	/// There is no direct way to get token holders in ascending order,
+	/// since `iter_prefix` returns values in no particular order.
+	/// Therefore, getting the 10 largest holders with a large value of holders
+	/// can lead to impact memory allocation + sorting with  `n * log (n)`.
+	pub fn token_owners(
+		collection_id: CollectionId,
+		token: TokenId,
+	) -> Option<Vec<T::CrossAccountId>> {
+		let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection_id, token))
+			.map(|(owner, _amount)| owner)
+			.take(10)
+			.collect();
+
+		if res.is_empty() {
+			None
+		} else {
+			Some(res)
+		}
+	}
 }
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
--- /dev/null
+++ b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Common stubs holder
+contract Dummy {
+	uint8 dummy;
+	string stub_error = "this contract is implemented in native";
+}
+
+contract ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		interfaceID;
+		return true;
+	}
+}
+
+// Inline
+contract ERC20Events {
+	event Transfer(address indexed from, address indexed to, uint256 value);
+	event Approval(
+		address indexed owner,
+		address indexed spender,
+		uint256 value
+	);
+}
+
+// Selector: 942e8b22
+contract ERC20 is Dummy, ERC165, ERC20Events {
+	// Selector: name() 06fdde03
+	function name() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
+	// Selector: symbol() 95d89b41
+	function symbol() public view returns (string memory) {
+		require(false, stub_error);
+		dummy;
+		return "";
+	}
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// Selector: decimals() 313ce567
+	function decimals() public view returns (uint8) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// Selector: balanceOf(address) 70a08231
+	function balanceOf(address owner) public view returns (uint256) {
+		require(false, stub_error);
+		owner;
+		dummy;
+		return 0;
+	}
+
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		to;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: transferFrom(address,address,uint256) 23b872dd
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) public returns (bool) {
+		require(false, stub_error);
+		from;
+		to;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: approve(address,uint256) 095ea7b3
+	function approve(address spender, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		spender;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: allowance(address,address) dd62ed3e
+	function allowance(address owner, address spender)
+		public
+		view
+		returns (uint256)
+	{
+		require(false, stub_error);
+		owner;
+		spender;
+		dummy;
+		return 0;
+	}
+}
+
+// Selector: ab8deb37
+contract ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		from;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: repartition(uint256) d2418ca7
+	function repartition(uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		amount;
+		dummy = 0;
+		return false;
+	}
+}
+
+contract UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -3,7 +3,7 @@
 //! Autogenerated weights for pallet_refungible
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-06-27, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
 
 // Executed Command:
@@ -49,6 +49,9 @@
 	fn transfer_from_removing() -> Weight;
 	fn transfer_from_creating_removing() -> Weight;
 	fn burn_from() -> Weight;
+	fn set_token_property_permissions(b: u32, ) -> Weight;
+	fn set_token_properties(b: u32, ) -> Weight;
+	fn delete_token_properties(b: u32, ) -> Weight;
 	fn repartition_item() -> Weight;
 }
 
@@ -62,7 +65,7 @@
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn create_item() -> Weight {
-		(17_553_000 as Weight)
+		(21_310_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
 	}
@@ -73,9 +76,9 @@
 	// Storage: Refungible TokenData (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items(b: u32, ) -> Weight {
-		(10_654_000 as Weight)
-			// Standard Error: 1_000
-			.saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))
+		(9_552_000 as Weight)
+			// Standard Error: 2_000
+			.saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))
@@ -87,9 +90,9 @@
 	// Storage: Refungible TokenData (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {
-		(3_587_000 as Weight)
+		(4_857_000 as Weight)
 			// Standard Error: 2_000
-			.saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
@@ -102,9 +105,9 @@
 	// Storage: Refungible Balance (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {
-		(1_980_000 as Weight)
+		(11_335_000 as Weight)
 			// Standard Error: 2_000
-			.saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(T::DbWeight::get().writes(3 as Weight))
@@ -115,7 +118,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn burn_item_partial() -> Weight {
-		(21_010_000 as Weight)
+		(21_239_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(3 as Weight))
 			.saturating_add(T::DbWeight::get().writes(4 as Weight))
 	}
@@ -125,14 +128,15 @@
 	// Storage: Refungible TokensBurnt (r:1 w:1)
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
+	// Storage: Refungible TokenProperties (r:0 w:1)
 	fn burn_item_fully() -> Weight {
-		(28_413_000 as Weight)
+		(29_426_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
-			.saturating_add(T::DbWeight::get().writes(6 as Weight))
+			.saturating_add(T::DbWeight::get().writes(7 as Weight))
 	}
 	// Storage: Refungible Balance (r:2 w:2)
 	fn transfer_normal() -> Weight {
-		(17_513_000 as Weight)
+		(17_743_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(2 as Weight))
 	}
@@ -140,7 +144,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_creating() -> Weight {
-		(20_469_000 as Weight)
+		(20_699_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(3 as Weight))
 			.saturating_add(T::DbWeight::get().writes(4 as Weight))
 	}
@@ -148,7 +152,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_removing() -> Weight {
-		(22_472_000 as Weight)
+		(22_833_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(3 as Weight))
 			.saturating_add(T::DbWeight::get().writes(4 as Weight))
 	}
@@ -156,21 +160,21 @@
 	// Storage: Refungible AccountBalance (r:2 w:2)
 	// Storage: Refungible Owned (r:0 w:2)
 	fn transfer_creating_removing() -> Weight {
-		(24_866_000 as Weight)
+		(24_936_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
 	}
 	// Storage: Refungible Balance (r:1 w:0)
 	// Storage: Refungible Allowance (r:0 w:1)
 	fn approve() -> Weight {
-		(13_475_000 as Weight)
+		(13_446_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Refungible Allowance (r:1 w:1)
 	// Storage: Refungible Balance (r:2 w:2)
 	fn transfer_from_normal() -> Weight {
-		(24_707_000 as Weight)
+		(24_777_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(3 as Weight))
 			.saturating_add(T::DbWeight::get().writes(3 as Weight))
 	}
@@ -179,7 +183,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_from_creating() -> Weight {
-		(27_812_000 as Weight)
+		(28_483_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
@@ -188,7 +192,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_from_removing() -> Weight {
-		(29_966_000 as Weight)
+		(29_896_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(5 as Weight))
 	}
@@ -197,7 +201,7 @@
 	// Storage: Refungible AccountBalance (r:2 w:2)
 	// Storage: Refungible Owned (r:0 w:2)
 	fn transfer_from_creating_removing() -> Weight {
-		(31_660_000 as Weight)
+		(32_070_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(7 as Weight))
 	}
@@ -208,15 +212,42 @@
 	// Storage: Refungible TokensBurnt (r:1 w:1)
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
+	// Storage: Refungible TokenProperties (r:0 w:1)
 	fn burn_from() -> Weight {
-		(36_248_000 as Weight)
+		(36_789_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
-			.saturating_add(T::DbWeight::get().writes(7 as Weight))
+			.saturating_add(T::DbWeight::get().writes(8 as Weight))
+	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:1)
+	fn set_token_property_permissions(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 62_000
+			.saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(T::DbWeight::get().reads(1 as Weight))
+			.saturating_add(T::DbWeight::get().writes(1 as Weight))
+	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn set_token_properties(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 1_668_000
+			.saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(T::DbWeight::get().reads(2 as Weight))
+			.saturating_add(T::DbWeight::get().writes(1 as Weight))
+	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn delete_token_properties(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 1_619_000
+			.saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(T::DbWeight::get().reads(2 as Weight))
+			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Refungible TotalSupply (r:1 w:1)
 	// Storage: Refungible Balance (r:1 w:1)
 	fn repartition_item() -> Weight {
-		(8_226_000 as Weight)
+		(8_325_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(2 as Weight))
 			.saturating_add(T::DbWeight::get().writes(2 as Weight))
 	}
@@ -231,7 +262,7 @@
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn create_item() -> Weight {
-		(17_553_000 as Weight)
+		(21_310_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
 	}
@@ -242,9 +273,9 @@
 	// Storage: Refungible TokenData (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items(b: u32, ) -> Weight {
-		(10_654_000 as Weight)
-			// Standard Error: 1_000
-			.saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))
+		(9_552_000 as Weight)
+			// Standard Error: 2_000
+			.saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))
@@ -256,9 +287,9 @@
 	// Storage: Refungible TokenData (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {
-		(3_587_000 as Weight)
+		(4_857_000 as Weight)
 			// Standard Error: 2_000
-			.saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
@@ -271,9 +302,9 @@
 	// Storage: Refungible Balance (r:0 w:4)
 	// Storage: Refungible Owned (r:0 w:4)
 	fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {
-		(1_980_000 as Weight)
+		(11_335_000 as Weight)
 			// Standard Error: 2_000
-			.saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))
 			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
@@ -284,7 +315,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn burn_item_partial() -> Weight {
-		(21_010_000 as Weight)
+		(21_239_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
 	}
@@ -294,14 +325,15 @@
 	// Storage: Refungible TokensBurnt (r:1 w:1)
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
+	// Storage: Refungible TokenProperties (r:0 w:1)
 	fn burn_item_fully() -> Weight {
-		(28_413_000 as Weight)
+		(29_426_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
 	}
 	// Storage: Refungible Balance (r:2 w:2)
 	fn transfer_normal() -> Weight {
-		(17_513_000 as Weight)
+		(17_743_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(2 as Weight))
 	}
@@ -309,7 +341,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_creating() -> Weight {
-		(20_469_000 as Weight)
+		(20_699_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
 	}
@@ -317,7 +349,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_removing() -> Weight {
-		(22_472_000 as Weight)
+		(22_833_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
 	}
@@ -325,21 +357,21 @@
 	// Storage: Refungible AccountBalance (r:2 w:2)
 	// Storage: Refungible Owned (r:0 w:2)
 	fn transfer_creating_removing() -> Weight {
-		(24_866_000 as Weight)
+		(24_936_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
 	}
 	// Storage: Refungible Balance (r:1 w:0)
 	// Storage: Refungible Allowance (r:0 w:1)
 	fn approve() -> Weight {
-		(13_475_000 as Weight)
+		(13_446_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 	// Storage: Refungible Allowance (r:1 w:1)
 	// Storage: Refungible Balance (r:2 w:2)
 	fn transfer_from_normal() -> Weight {
-		(24_707_000 as Weight)
+		(24_777_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
 	}
@@ -348,7 +380,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_from_creating() -> Weight {
-		(27_812_000 as Weight)
+		(28_483_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
@@ -357,7 +389,7 @@
 	// Storage: Refungible AccountBalance (r:1 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
 	fn transfer_from_removing() -> Weight {
-		(29_966_000 as Weight)
+		(29_896_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(5 as Weight))
 	}
@@ -366,7 +398,7 @@
 	// Storage: Refungible AccountBalance (r:2 w:2)
 	// Storage: Refungible Owned (r:0 w:2)
 	fn transfer_from_creating_removing() -> Weight {
-		(31_660_000 as Weight)
+		(32_070_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
 	}
@@ -377,15 +409,42 @@
 	// Storage: Refungible TokensBurnt (r:1 w:1)
 	// Storage: Refungible TokenData (r:0 w:1)
 	// Storage: Refungible Owned (r:0 w:1)
+	// Storage: Refungible TokenProperties (r:0 w:1)
 	fn burn_from() -> Weight {
-		(36_248_000 as Weight)
+		(36_789_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(8 as Weight))
+	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:1)
+	fn set_token_property_permissions(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 62_000
+			.saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
+	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn set_token_properties(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 1_668_000
+			.saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
+	// Storage: Common CollectionPropertyPermissions (r:1 w:0)
+	// Storage: Refungible TokenProperties (r:1 w:1)
+	fn delete_token_properties(b: u32, ) -> Weight {
+		(0 as Weight)
+			// Standard Error: 1_619_000
+			.saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))
+			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
+	}
 	// Storage: Refungible TotalSupply (r:1 w:1)
 	// Storage: Refungible Balance (r:1 w:1)
 	fn repartition_item() -> Weight {
-		(8_226_000 as Weight)
+		(8_325_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(2 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(2 as Weight))
 	}
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
--- a/pallets/scheduler/src/lib.rs
+++ b/pallets/scheduler/src/lib.rs
@@ -24,7 +24,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-// 	http://www.apache.org/licenses/LICENSE-2.0
+// 	<http://www.apache.org/licenses/LICENSE-2.0>
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,27 +32,36 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! # Schedulerdo_reschedule
+//! # Unique scheduler
+//! A Pallet for scheduling dispatches.
+//!
+//! - [`Config`]
+//! - [`Call`]
+//! - [`Pallet`]
+//!
+//! ## Overview
 //!
 //! This Pallet exposes capabilities for scheduling dispatches to occur at a
 //! specified block number or at a specified period. These scheduled dispatches
-//! may be named or anonymous and may be canceled.
+//! should be named and may be canceled.
 //!
-//! **NOTE:** The scheduled calls will be dispatched with the default filter
-//! for the origin: namely `frame_system::Config::BaseCallFilter` for all origin
-//! except root which will get no filter. And not the filter contained in origin
-//! use to call `fn schedule`.
+//! **NOTE:** The unique scheduler is designed for deferred transaction calls by block number.
+//! Any user can book a call of a certain transaction to a specific block number.
+//! Also possible to book a call with a certain frequency.
 //!
-//! If a call is scheduled using proxy or whatever mecanism which adds filter,
-//! then those filter will not be used when dispatching the schedule call.
+//! Key differences from the original pallet:
+//! <https://crates.io/crates/pallet-scheduler>
+//! Schedule Id restricted by 16 bytes. Identificator for booked call.
+//! Priority limited by HARD DEADLINE (<= 63). Calls over maximum weight don't include to block.
+//! The maximum weight that may be scheduled per block for any dispatchables of less priority than `schedule::HARD_DEADLINE`.
+//! Maybe_periodic limit is 100 calls. Reserved for future sponsored transaction support.
+//! At 100 calls reserved amount is not so much and this is avoid potential problems with balance locks.
+//! Any account allowed to schedule any calls. Account withdraw implemented through default transaction logic.
 //!
 //! ## Interface
 //!
 //! ### Dispatchable Functions
 //!
-//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a specified block and
-//!   with a specified priority.
-//! * `cancel` - cancel a scheduled dispatch, specified by block number and index.
 //! * `schedule_named` - augments the `schedule` interface with an additional `Vec<u8>` parameter
 //!   that can be used for identification.
 //! * `cancel_named` - the named complement to the cancel function.
@@ -258,7 +267,7 @@
 
 	/// A Scheduler-Runtime interface for finer payment handling.
 	pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {
-		/// Reserve the maximum spendings on a call.
+		/// Reserve (lock) the maximum spendings on a call, calculated from its weight and the repetition count.
 		fn reserve_balance(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -266,7 +275,7 @@
 			count: u32,
 		) -> Result<(), DispatchError>;
 
-		/// Pay for call dispatch (un-reserve) from the reserved funds, returning the change.
+		/// Unreserve (unlock) a certain amount from the payer's reserved funds, returning the change.
 		fn pay_for_call(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -282,7 +291,7 @@
 			TransactionValidityError,
 		>;
 
-		/// Release reserved funds.
+		/// Release unspent reserved funds in case of a schedule cancel.
 		fn cancel_reserve(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -441,6 +450,8 @@
 				// 	);
 				// }
 
+				// Execute transaction via chain default pipeline
+				// That means dispatch will be processed like any user's extrinsic e.g. transaction fees will be taken
 				let r = T::CallExecutor::dispatch_call(sender, call.clone());
 
 				let mut actual_call_weight: Weight = item_weight;
@@ -485,8 +496,8 @@
 					Agenda::<T>::append(wake, Some(s));
 				}
 			}
+			// Total weight should be 0, because the transaction is already paid for
 			0
-			//total_weight
 		}
 	}
 
modifiedpallets/structure/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/structure/src/benchmarking.rs
+++ b/pallets/structure/src/benchmarking.rs
@@ -1,3 +1,19 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
 use super::*;
 
 use frame_benchmarking::{benchmarks, account};
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -1,3 +1,56 @@
+// 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/>.
+
+//! # Structure Pallet
+//!
+//! The Structure pallet provides functionality for handling tokens nesting an unnesting.
+//!
+//! - [`Config`]
+//! - [`Pallet`]
+//!
+//! ## Overview
+//!
+//! The Structure pallet provides functions for:
+//!
+//! - Searching for token parents, children and owners. Actual implementation of searching for
+//!   parent/child is done by pallets corresponding to token's collection type.
+//! - Nesting and unnesting tokens. Actual implementation of nesting is done by pallets corresponding
+//!   to token's collection type.
+//!
+//! ### Terminology
+//!
+//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting
+//!   owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in
+//!   it's child token i.e. parent-child relationship graph shouldn't have
+//!
+//! - **Parent:** Token that current token is nested in.
+//!
+//! - **Owner:** Account that owns the token and all nested tokens.
+//!
+//! ## Interface
+//!
+//! ### Available Functions
+//!
+//! - `find_parent` - Find parent of the token. It could be an account or another token.
+//! - `parent_chain` - Find chain of parents of the token.
+//! - `find_topmost_owner` - Find account or token in the end of the chain of parents.
+//! - `check_nesting` - Check if the token could be nested in the other token
+//! - `nest_if_sent_to_token` - Nest the token in the other token
+//! - `unnest_if_nested` - Unnest the token from the other token
+
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use pallet_common::CommonCollectionOperations;
@@ -82,6 +135,12 @@
 }
 
 impl<T: Config> Pallet<T> {
+	/// Find account owning the `token` or a token that the `token` is nested in.
+	///
+	/// Returns the enum that have three variants:
+	/// - [`User`](crate::Parent<T>::User): Contains account.
+	/// - [`Token`](crate::Parent<T>::Token): Contains token id and collection id.
+	/// - [`TokenNotFound`](crate::Parent<T>::TokenNotFound): Indicates that parent was not found
 	pub fn find_parent(
 		collection: CollectionId,
 		token: TokenId,
@@ -103,6 +162,11 @@
 		})
 	}
 
+	/// Get the chain of parents of a token in the nesting hierarchy
+	///
+	/// Returns an iterator of addresses of the owning tokens and the owning account,
+	/// starting from the immediate parent token, ending with the account.
+	/// Returns error if cycle is detected.
 	pub fn parent_chain(
 		mut collection: CollectionId,
 		mut token: TokenId,
@@ -133,6 +197,8 @@
 	/// Try to dereference address, until finding top level owner
 	///
 	/// May return token address if parent token not yet exists
+	///
+	/// - `budget`: Limit for searching parents in depth.
 	pub fn find_topmost_owner(
 		collection: CollectionId,
 		token: TokenId,
@@ -149,6 +215,10 @@
 		})
 	}
 
+	/// Find the topmost parent and check that assigning `for_nest` token as a child for
+	/// `token` wouldn't create a cycle.
+	///
+	/// - `budget`: Limit for searching parents in depth.
 	pub fn get_checked_topmost_owner(
 		collection: CollectionId,
 		token: TokenId,
@@ -177,6 +247,10 @@
 		Err(<Error<T>>::DepthLimit.into())
 	}
 
+	/// Burn token and all of it's nested tokens
+	///
+	/// - `self_budget`: Limit for searching children in depth.
+	/// - `breadth_budget`: Limit of breadth of searching children.
 	pub fn burn_item_recursively(
 		from: T::CrossAccountId,
 		collection: CollectionId,
@@ -190,7 +264,13 @@
 		dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)
 	}
 
-	/// Check if token indirectly owned by specified user
+	/// Check if `token` indirectly owned by `user`
+	///
+	/// Returns `true` if `user` is `token`'s owner. Or If token is provided as `user` then
+	/// check that `user` and `token` have same owner.
+	/// Checks that assigning `for_nest` token as a child for `token` wouldn't create a cycle.
+	///
+	/// - `budget`: Limit for searching parents in depth.
 	pub fn check_indirectly_owned(
 		user: T::CrossAccountId,
 		collection: CollectionId,
@@ -207,6 +287,12 @@
 			.map(|indirect_owner| indirect_owner == target_parent)
 	}
 
+	/// Checks that `under` is valid token and that `token_id` could be nested under it
+	/// and that `from` is `under`'s owner
+	///
+	/// Returns OK if `under` is not a token
+	///
+	/// - `nesting_budget`: Limit for searching parents in depth.
 	pub fn check_nesting(
 		from: T::CrossAccountId,
 		under: &T::CrossAccountId,
@@ -219,6 +305,11 @@
 		})
 	}
 
+	/// Nests `token_id` under `under` token
+	///
+	/// Returns OK if `under` is not a token. Checks that nesting is possible.
+	///
+	/// - `nesting_budget`: Limit for searching parents in depth.
 	pub fn nest_if_sent_to_token(
 		from: T::CrossAccountId,
 		under: &T::CrossAccountId,
@@ -235,6 +326,9 @@
 		})
 	}
 
+	/// Nests `token_id` under `owner` token
+	///
+	/// Caller should check that nesting wouldn't cause recursion in nesting
 	pub fn nest_if_sent_to_token_unchecked(
 		owner: &T::CrossAccountId,
 		collection_id: CollectionId,
@@ -245,6 +339,7 @@
 		});
 	}
 
+	/// Unnests `token_id` from `owner`.
 	pub fn unnest_if_nested(
 		owner: &T::CrossAccountId,
 		collection_id: CollectionId,
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -6,7 +6,7 @@
 license = 'GPLv3'
 homepage = "https://unique.network"
 repository = 'https://github.com/UniqueNetwork/unique-chain'
-version = '0.1.0'
+version = '0.1.1'
 
 [dependencies]
 scale-info = { version = "2.0.1", default-features = false, features = [
addedprimitives/data-structs/Changelog.mddiffbeforeafterboth
--- /dev/null
+++ b/primitives/data-structs/Changelog.md
@@ -0,0 +1,3 @@
+### 0.1.1
+---
+* Added fields with properties to `CreateReFungibleData` and `CreateRefungibleExData`.
\ No newline at end of file
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -563,8 +563,14 @@
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
+
 	/// Number of pieces the RFT is split into
 	pub pieces: u128,
+
+	/// Key-value pairs used to describe the token as metadata
+	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
+	#[derivative(Debug(format_with = "bounded::vec_debug"))]
+	pub properties: CollectionPropertiesVec,
 }
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
@@ -601,6 +607,8 @@
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
 	#[derivative(Debug(format_with = "bounded::map_debug"))]
 	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
+	#[derivative(Debug(format_with = "bounded::vec_debug"))]
+	pub properties: CollectionPropertiesVec,
 }
 
 /// Explicit item creation data with meta parameters, namely the owner.
addedprimitives/rpc/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/primitives/rpc/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.1.1] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+   This was an internal request to improve the web interface and support fractionalization event. 
\ No newline at end of file
modifiedprimitives/rpc/Cargo.tomldiffbeforeafterboth
--- a/primitives/rpc/Cargo.toml
+++ b/primitives/rpc/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "up-rpc"
-version = "0.1.0"
+version = "0.1.1"
 license = "GPLv3"
 edition = "2021"
 
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -81,5 +81,6 @@
 		fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>>;
 		fn effective_collection_limits(collection_id: CollectionId) -> Result<Option<CollectionLimits>>;
 		fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result<Option<u128>>;
+		fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
 	}
 }
addedruntime/common/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/runtime/common/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## [0.9.25] - 2022-07-14
+
+### Added
+
+ - Implementation of RPC method `token_owners` returning 10 owners in no particular order.
+    This was an internal request to improve the web interface and support fractionalization event. 
+
+
+ 
\ No newline at end of file
modifiedruntime/common/src/dispatch.rsdiffbeforeafterboth
--- a/runtime/common/src/dispatch.rs
+++ b/runtime/common/src/dispatch.rs
@@ -25,7 +25,9 @@
 pub use pallet_common::dispatch::CollectionDispatch;
 use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};
 use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};
-use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle, erc::RefungibleTokenHandle};
+use pallet_refungible::{
+	Pallet as PalletRefungible, RefungibleHandle, erc_token::RefungibleTokenHandle,
+};
 use up_data_structs::{
 	CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,
 };
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -40,6 +40,11 @@
                 fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
                     dispatch_unique_runtime!(collection.token_owner(token))
                 }
+
+                fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec::<CrossAccountId>, DispatchError>  {
+                   dispatch_unique_runtime!(collection.token_owners(token))
+                }
+
                 fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>, DispatchError> {
                     let budget = up_data_structs::budget::Value::new(10);
 
modifiedruntime/tests/src/tests.rsdiffbeforeafterboth
--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -64,6 +64,12 @@
 	CreateReFungibleData {
 		const_data: vec![1, 2, 3].try_into().unwrap(),
 		pieces: 1023,
+		properties: vec![Property {
+			key: b"test-prop".to_vec().try_into().unwrap(),
+			value: b"test-nft-prop".to_vec().try_into().unwrap(),
+		}]
+		.try_into()
+		.unwrap(),
 	}
 }
 
addedtests/CHANGELOG.mddiffbeforeafterboth
--- /dev/null
+++ b/tests/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+## 2022-07-14
+
+### Added
+ - Integrintegration tests of RPC method `token_owners`.
+ - Integrintegration tests of Fungible Pallet.
+  
+ 
\ No newline at end of file
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -80,6 +80,8 @@
     "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
     "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",
     "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",
+    "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",
+    "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",
     "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
     "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",
     "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -376,14 +376,26 @@
       // ReFungible
       const collectionIdReFungible =
         await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      const argsReFungible = [
-        {ReFungible: ['1'.repeat(2049), 10]},
-        {ReFungible: ['2'.repeat(2049), 10]},
-        {ReFungible: ['3'.repeat(2049), 10]},
-      ];
-      const createMultipleItemsTxFungible = api.tx.unique
-        .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);
-      await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;
+      {
+        const argsReFungible = [
+          {ReFungible: ['1'.repeat(2049), 10, []]},
+          {ReFungible: ['2'.repeat(2049), 10, []]},
+          {ReFungible: ['3'.repeat(2049), 10, []]},
+        ];
+        const createMultipleItemsTxFungible = api.tx.unique
+          .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);
+        await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;
+      }
+      {
+        const argsReFungible = [
+          {ReFungible: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}},
+          {ReFungible: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}},
+          {ReFungible: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}},
+        ];
+        const createMultipleItemsTxFungible = api.tx.unique
+          .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);
+        await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;
+      }
     });
   });
 
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -28,6 +28,154 @@
 	function burnFrom(address from, uint256 amount) external returns (bool);
 }
 
+// Selector: 7d9262e6
+interface Collection is Dummy, ERC165 {
+	// Set collection property.
+	//
+	// @param key Property key.
+	// @param value Propery value.
+	//
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		external;
+
+	// Delete collection property.
+	//
+	// @param key Property key.
+	//
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) external;
+
+	// Get collection property.
+	//
+	// @dev Throws error if key not found.
+	//
+	// @param key Property key.
+	// @return bytes The property corresponding to the key.
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		external
+		view
+		returns (bytes memory);
+
+	// Set the sponsor of the collection.
+	//
+	// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	//
+	// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	//
+	// Selector: setCollectionSponsor(address) 7623402e
+	function setCollectionSponsor(address sponsor) external;
+
+	// Collection sponsorship confirmation.
+	//
+	// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	//
+	// Selector: confirmCollectionSponsorship() 3c50e97a
+	function confirmCollectionSponsorship() external;
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"accountTokenOwnershipLimit",
+	// 	"sponsoredDataSize",
+	// 	"sponsoredDataRateLimit",
+	// 	"tokenLimit",
+	// 	"sponsorTransferTimeout",
+	// 	"sponsorApproveTimeout"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,uint32) 6a3841db
+	function setCollectionLimit(string memory limit, uint32 value) external;
+
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"ownerCanTransfer",
+	// 	"ownerCanDestroy",
+	// 	"transfersEnabled"
+	// @param value Value of the limit.
+	//
+	// Selector: setCollectionLimit(string,bool) 993b7fba
+	function setCollectionLimit(string memory limit, bool value) external;
+
+	// Get contract address.
+	//
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() external view returns (address);
+
+	// Add collection admin by substrate address.
+	// @param new_admin Substrate administrator address.
+	//
+	// Selector: addCollectionAdminSubstrate(uint256) 5730062b
+	function addCollectionAdminSubstrate(uint256 newAdmin) external;
+
+	// Remove collection admin by substrate address.
+	// @param admin Substrate administrator address.
+	//
+	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
+	function removeCollectionAdminSubstrate(uint256 admin) external;
+
+	// Add collection admin.
+	// @param new_admin Address of the added administrator.
+	//
+	// Selector: addCollectionAdmin(address) 92e462c7
+	function addCollectionAdmin(address newAdmin) external;
+
+	// Remove collection admin.
+	//
+	// @param new_admin Address of the removed administrator.
+	//
+	// Selector: removeCollectionAdmin(address) fafd7b42
+	function removeCollectionAdmin(address admin) external;
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	//
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) external;
+
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// @param collections Addresses of collections that will be available for nesting.
+	//
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		external;
+
+	// Set the collection access method.
+	// @param mode Access mode
+	// 	0 for Normal
+	// 	1 for AllowList
+	//
+	// Selector: setCollectionAccess(uint8) 41835d4c
+	function setCollectionAccess(uint8 mode) external;
+
+	// Add the user to the allowed list.
+	//
+	// @param user Address of a trusted user.
+	//
+	// Selector: addToCollectionAllowList(address) 67844fe6
+	function addToCollectionAllowList(address user) external;
+
+	// Remove the user from the allowed list.
+	//
+	// @param user Address of a removed user.
+	//
+	// Selector: removeFromCollectionAllowList(address) 85c51acb
+	function removeFromCollectionAllowList(address user) external;
+
+	// Switch permission for minting.
+	//
+	// @param mode Enable if "true".
+	//
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) external;
+}
+
 // Selector: 942e8b22
 interface ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
@@ -63,39 +211,6 @@
 		external
 		view
 		returns (uint256);
-}
-
-// Selector: c894dc35
-interface Collection is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		external;
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) external;
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		external
-		view
-		returns (bytes memory);
-
-	// Selector: ethSetSponsor(address) 8f9af356
-	function ethSetSponsor(address sponsor) external;
-
-	// Selector: ethConfirmSponsorship() a8580d1a
-	function ethConfirmSponsorship() external;
-
-	// Selector: setLimit(string,uint32) 68db30ca
-	function setLimit(string memory limit, uint32 value) external;
-
-	// Selector: setLimit(string,bool) ea67e4c2
-	function setLimit(string memory limit, bool value) external;
-
-	// Selector: contractAddress() f6b4dfb4
-	function contractAddress() external view returns (address);
 }
 
 interface UniqueFungible is
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -44,6 +44,13 @@
 
 // Selector: 41369377
 interface TokenProperties is Dummy, ERC165 {
+	// @notice Set permissions for token property.
+	// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	// @param key Property key.
+	// @param is_mutable Permission to mutate property.
+	// @param collection_admin Permission to mutate property by collection admin if property is mutable.
+	// @param token_owner Permission to mutate property by token owner if property is mutable.
+	//
 	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
 	function setTokenPropertyPermission(
 		string memory key,
@@ -52,6 +59,12 @@
 		bool tokenOwner
 	) external;
 
+	// @notice Set token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	// @param value Property value.
+	//
 	// Selector: setProperty(uint256,string,bytes) 1752d67b
 	function setProperty(
 		uint256 tokenId,
@@ -59,10 +72,19 @@
 		bytes memory value
 	) external;
 
+	// @notice Delete token property value.
+	// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	//
 	// Selector: deleteProperty(uint256,string) 066111d1
 	function deleteProperty(uint256 tokenId, string memory key) external;
 
-	// Throws error if key not found
+	// @notice Get token property value.
+	// @dev Throws error if key not found
+	// @param tokenId ID of the token.
+	// @param key Property key.
+	// @return Property value bytes
 	//
 	// Selector: property(uint256,string) 7228c327
 	function property(uint256 tokenId, string memory key)
@@ -73,19 +95,36 @@
 
 // Selector: 42966c68
 interface ERC721Burnable is Dummy, ERC165 {
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param tokenId The NFT to approve
+	//
 	// Selector: burn(uint256) 42966c68
 	function burn(uint256 tokenId) external;
 }
 
 // Selector: 58800161
 interface ERC721 is Dummy, ERC165, ERC721Events {
+	// @notice Count all NFTs assigned to an owner
+	// @dev NFTs assigned to the zero address are considered invalid, and this
+	//  function throws for queries about the zero address.
+	// @param owner An address for whom to query the balance
+	// @return The number of NFTs owned by `owner`, possibly zero
+	//
 	// Selector: balanceOf(address) 70a08231
 	function balanceOf(address owner) external view returns (uint256);
 
+	// @notice Find the owner of an NFT
+	// @dev NFTs assigned to zero address are considered invalid, and queries
+	//  about them do throw.
+	// @param tokenId The identifier for an NFT
+	// @return The address of the owner of the NFT
+	//
 	// Selector: ownerOf(uint256) 6352211e
 	function ownerOf(uint256 tokenId) external view returns (address);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
 	function safeTransferFromWithData(
@@ -95,7 +134,7 @@
 		bytes memory data
 	) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: safeTransferFrom(address,address,uint256) 42842e0e
 	function safeTransferFrom(
@@ -104,6 +143,17 @@
 		uint256 tokenId
 	) external;
 
+	// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	//  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	//  THEY MAY BE PERMANENTLY LOST
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transferFrom(address,address,uint256) 23b872dd
 	function transferFrom(
 		address from,
@@ -111,20 +161,27 @@
 		uint256 tokenId
 	) external;
 
+	// @notice Set or reaffirm the approved address for an NFT
+	// @dev The zero address indicates there is no approved address.
+	// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	//  operator of the current owner.
+	// @param approved The new approved NFT controller
+	// @param tokenId The NFT to approve
+	//
 	// Selector: approve(address,uint256) 095ea7b3
 	function approve(address approved, uint256 tokenId) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: setApprovalForAll(address,bool) a22cb465
 	function setApprovalForAll(address operator, bool approved) external;
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: getApproved(uint256) 081812fc
 	function getApproved(uint256 tokenId) external view returns (address);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: isApprovedForAll(address,address) e985e9c5
 	function isApprovedForAll(address owner, address operator)
@@ -135,13 +192,21 @@
 
 // Selector: 5b5e139f
 interface ERC721Metadata is Dummy, ERC165 {
+	// @notice A descriptive name for a collection of NFTs in this contract
+	//
 	// Selector: name() 06fdde03
 	function name() external view returns (string memory);
 
+	// @notice An abbreviated name for NFTs in this contract
+	//
 	// Selector: symbol() 95d89b41
 	function symbol() external view returns (string memory);
 
-	// Returns token's const_metadata
+	// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC
+	//  3986. The URI may point to a JSON file that conforms to the "ERC721
+	//  Metadata JSON Schema".
+	// @return token's const_metadata
 	//
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) external view returns (string memory);
@@ -152,14 +217,21 @@
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() external view returns (bool);
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
 	//
 	// Selector: mint(address,uint256) 40c10f19
 	function mint(address to, uint256 tokenId) external returns (bool);
 
-	// `token_id` should be obtained with `next_token_id` method,
-	// unlike standard, you can't specify it manually
+	// @notice Function to mint token with the given tokenUri.
+	// @dev `tokenId` should be obtained with `nextTokenId` method,
+	//  unlike standard, you can't specify it manually
+	// @param to The new owner
+	// @param tokenId ID of the minted NFT
+	// @param tokenUri Token URI that would be stored in the NFT properties
 	//
 	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
 	function mintWithTokenURI(
@@ -168,7 +240,7 @@
 		string memory tokenUri
 	) external returns (bool);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: finishMinting() 7d64bcb4
 	function finishMinting() external returns (bool);
@@ -176,10 +248,15 @@
 
 // Selector: 780e9d63
 interface ERC721Enumerable is Dummy, ERC165 {
+	// @notice Enumerate valid NFTs
+	// @param index A counter less than `totalSupply()`
+	// @return The token identifier for the `index`th NFT,
+	//  (sort order not specified)
+	//
 	// Selector: tokenByIndex(uint256) 4f6ccce7
 	function tokenByIndex(uint256 index) external view returns (uint256);
 
-	// Not implemented
+	// @dev Not implemented
 	//
 	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
 	function tokenOfOwnerByIndex(address owner, uint256 index)
@@ -187,20 +264,38 @@
 		view
 		returns (uint256);
 
+	// @notice Count NFTs tracked by this contract
+	// @return A count of valid NFTs tracked by this contract, where each one of
+	//  them has an assigned and queryable owner not equal to the zero address
+	//
 	// Selector: totalSupply() 18160ddd
 	function totalSupply() external view returns (uint256);
 }
 
 // Selector: 7d9262e6
 interface Collection is Dummy, ERC165 {
+	// Set collection property.
+	//
+	// @param key Property key.
+	// @param value Propery value.
+	//
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
 		external;
 
+	// Delete collection property.
+	//
+	// @param key Property key.
+	//
 	// Selector: deleteCollectionProperty(string) 7b7debce
 	function deleteCollectionProperty(string memory key) external;
 
-	// Throws error if key not found
+	// Get collection property.
+	//
+	// @dev Throws error if key not found.
+	//
+	// @param key Property key.
+	// @return bytes The property corresponding to the key.
 	//
 	// Selector: collectionProperty(string) cf24fd6d
 	function collectionProperty(string memory key)
@@ -208,69 +303,168 @@
 		view
 		returns (bytes memory);
 
+	// Set the sponsor of the collection.
+	//
+	// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	//
+	// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	//
 	// Selector: setCollectionSponsor(address) 7623402e
 	function setCollectionSponsor(address sponsor) external;
 
+	// Collection sponsorship confirmation.
+	//
+	// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	//
 	// Selector: confirmCollectionSponsorship() 3c50e97a
 	function confirmCollectionSponsorship() external;
 
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"accountTokenOwnershipLimit",
+	// 	"sponsoredDataSize",
+	// 	"sponsoredDataRateLimit",
+	// 	"tokenLimit",
+	// 	"sponsorTransferTimeout",
+	// 	"sponsorApproveTimeout"
+	// @param value Value of the limit.
+	//
 	// Selector: setCollectionLimit(string,uint32) 6a3841db
 	function setCollectionLimit(string memory limit, uint32 value) external;
 
+	// Set limits for the collection.
+	// @dev Throws error if limit not found.
+	// @param limit Name of the limit. Valid names:
+	// 	"ownerCanTransfer",
+	// 	"ownerCanDestroy",
+	// 	"transfersEnabled"
+	// @param value Value of the limit.
+	//
 	// Selector: setCollectionLimit(string,bool) 993b7fba
 	function setCollectionLimit(string memory limit, bool value) external;
 
+	// Get contract address.
+	//
 	// Selector: contractAddress() f6b4dfb4
 	function contractAddress() external view returns (address);
 
+	// Add collection admin by substrate address.
+	// @param new_admin Substrate administrator address.
+	//
 	// Selector: addCollectionAdminSubstrate(uint256) 5730062b
-	function addCollectionAdminSubstrate(uint256 newAdmin) external view;
+	function addCollectionAdminSubstrate(uint256 newAdmin) external;
 
+	// Remove collection admin by substrate address.
+	// @param admin Substrate administrator address.
+	//
 	// Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
-	function removeCollectionAdminSubstrate(uint256 newAdmin) external view;
+	function removeCollectionAdminSubstrate(uint256 admin) external;
 
+	// Add collection admin.
+	// @param new_admin Address of the added administrator.
+	//
 	// Selector: addCollectionAdmin(address) 92e462c7
-	function addCollectionAdmin(address newAdmin) external view;
+	function addCollectionAdmin(address newAdmin) external;
 
+	// Remove collection admin.
+	//
+	// @param new_admin Address of the removed administrator.
+	//
 	// Selector: removeCollectionAdmin(address) fafd7b42
-	function removeCollectionAdmin(address admin) external view;
+	function removeCollectionAdmin(address admin) external;
 
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	//
 	// Selector: setCollectionNesting(bool) 112d4586
 	function setCollectionNesting(bool enable) external;
 
+	// Toggle accessibility of collection nesting.
+	//
+	// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// @param collections Addresses of collections that will be available for nesting.
+	//
 	// Selector: setCollectionNesting(bool,address[]) 64872396
 	function setCollectionNesting(bool enable, address[] memory collections)
 		external;
 
+	// Set the collection access method.
+	// @param mode Access mode
+	// 	0 for Normal
+	// 	1 for AllowList
+	//
 	// Selector: setCollectionAccess(uint8) 41835d4c
 	function setCollectionAccess(uint8 mode) external;
 
+	// Add the user to the allowed list.
+	//
+	// @param user Address of a trusted user.
+	//
 	// Selector: addToCollectionAllowList(address) 67844fe6
-	function addToCollectionAllowList(address user) external view;
+	function addToCollectionAllowList(address user) external;
 
+	// Remove the user from the allowed list.
+	//
+	// @param user Address of a removed user.
+	//
 	// Selector: removeFromCollectionAllowList(address) 85c51acb
-	function removeFromCollectionAllowList(address user) external view;
+	function removeFromCollectionAllowList(address user) external;
 
+	// Switch permission for minting.
+	//
+	// @param mode Enable if "true".
+	//
 	// Selector: setCollectionMintMode(bool) 00018e84
 	function setCollectionMintMode(bool mode) external;
 }
 
 // Selector: d74d154f
 interface ERC721UniqueExtensions is Dummy, ERC165 {
+	// @notice Transfer ownership of an NFT
+	// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	//  is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param to The new owner
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) external;
 
+	// @notice Burns a specific ERC721 token.
+	// @dev Throws unless `msg.sender` is the current owner or an authorized
+	//  operator for this NFT. Throws if `from` is not the current owner. Throws
+	//  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// @param from The current owner of the NFT
+	// @param tokenId The NFT to transfer
+	// @param _value Not used for an NFT
+	//
 	// Selector: burnFrom(address,uint256) 79cc6790
 	function burnFrom(address from, uint256 tokenId) external;
 
+	// @notice Returns next free NFT ID.
+	//
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() external view returns (uint256);
 
+	// @notice Function to mint multiple tokens.
+	// @dev `tokenIds` should be an array of consecutive numbers and first number
+	//  should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokenIds IDs of the minted NFTs
+	//
 	// Selector: mintBulk(address,uint256[]) 44a9945e
 	function mintBulk(address to, uint256[] memory tokenIds)
 		external
 		returns (bool);
 
+	// @notice Function to mint multiple tokens with the given tokenUris.
+	// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	//  numbers and first number should be obtained with `nextTokenId` method
+	// @param to The new owner
+	// @param tokens array of pairs of token ID and token URI for minted tokens
+	//
 	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
 	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
 		external
addedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/api/UniqueRefungibleToken.sol
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+// Inline
+interface ERC20Events {
+	event Transfer(address indexed from, address indexed to, uint256 value);
+	event Approval(
+		address indexed owner,
+		address indexed spender,
+		uint256 value
+	);
+}
+
+// Selector: 942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+	// Selector: name() 06fdde03
+	function name() external view returns (string memory);
+
+	// Selector: symbol() 95d89b41
+	function symbol() external view returns (string memory);
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
+
+	// Selector: decimals() 313ce567
+	function decimals() external view returns (uint8);
+
+	// Selector: balanceOf(address) 70a08231
+	function balanceOf(address owner) external view returns (uint256);
+
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 amount) external returns (bool);
+
+	// Selector: transferFrom(address,address,uint256) 23b872dd
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) external returns (bool);
+
+	// Selector: approve(address,uint256) 095ea7b3
+	function approve(address spender, uint256 amount) external returns (bool);
+
+	// Selector: allowance(address,address) dd62ed3e
+	function allowance(address owner, address spender)
+		external
+		view
+		returns (uint256);
+}
+
+// Selector: ab8deb37
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) external returns (bool);
+
+	// Selector: repartition(uint256) d2418ca7
+	function repartition(uint256 amount) external returns (bool);
+}
+
+interface UniqueRefungibleToken is
+	Dummy,
+	ERC165,
+	ERC20,
+	ERC20UniqueExtensions
+{}
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/fungibleAbi.json
+++ b/tests/src/eth/fungibleAbi.json
@@ -51,6 +51,33 @@
   },
   {
     "inputs": [
+      { "internalType": "address", "name": "newAdmin", "type": "address" }
+    ],
+    "name": "addCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }
+    ],
+    "name": "addCollectionAdminSubstrate",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "addToCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
       { "internalType": "address", "name": "owner", "type": "address" },
       { "internalType": "address", "name": "spender", "type": "address" }
     ],
@@ -97,6 +124,13 @@
   },
   {
     "inputs": [],
+    "name": "confirmCollectionSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "contractAddress",
     "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
     "stateMutability": "view",
@@ -118,43 +152,51 @@
   },
   {
     "inputs": [],
-    "name": "ethConfirmSponsorship",
-    "outputs": [],
-    "stateMutability": "nonpayable",
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
     "type": "function"
   },
   {
     "inputs": [
-      { "internalType": "address", "name": "sponsor", "type": "address" }
+      { "internalType": "address", "name": "admin", "type": "address" }
     ],
-    "name": "ethSetSponsor",
+    "name": "removeCollectionAdmin",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
   },
   {
-    "inputs": [],
-    "name": "name",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
+    "inputs": [
+      { "internalType": "uint256", "name": "admin", "type": "uint256" }
+    ],
+    "name": "removeCollectionAdminSubstrate",
+    "outputs": [],
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
     "inputs": [
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
+      { "internalType": "address", "name": "user", "type": "address" }
     ],
-    "name": "setCollectionProperty",
+    "name": "removeFromCollectionAllowList",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
   },
   {
+    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],
+    "name": "setCollectionAccess",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
       { "internalType": "uint32", "name": "value", "type": "uint32" }
     ],
-    "name": "setLimit",
+    "name": "setCollectionLimit",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
@@ -164,7 +206,54 @@
       { "internalType": "string", "name": "limit", "type": "string" },
       { "internalType": "bool", "name": "value", "type": "bool" }
     ],
-    "name": "setLimit",
+    "name": "setCollectionLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+    "name": "setCollectionMintMode",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bool", "name": "enable", "type": "bool" },
+      {
+        "internalType": "address[]",
+        "name": "collections",
+        "type": "address[]"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setCollectionSponsor",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -86,7 +86,7 @@
     ],
     "name": "addCollectionAdmin",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -95,7 +95,7 @@
     ],
     "name": "addCollectionAdminSubstrate",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -104,7 +104,7 @@
     ],
     "name": "addToCollectionAllowList",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -304,16 +304,16 @@
     ],
     "name": "removeCollectionAdmin",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
     "inputs": [
-      { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }
+      { "internalType": "uint256", "name": "admin", "type": "uint256" }
     ],
     "name": "removeCollectionAdminSubstrate",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -322,7 +322,7 @@
     ],
     "name": "removeFromCollectionAllowList",
     "outputs": [],
-    "stateMutability": "view",
+    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
addedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -0,0 +1,458 @@
+// 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/>.
+
+import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';
+import {createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';
+import reFungibleTokenAbi from './reFungibleTokenAbi.json';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+describe('Refungible token: Information getting', () => {
+  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});
+    const totalSupply = await contract.methods.totalSupply().call();
+
+    expect(totalSupply).to.equal('200');
+  });
+
+  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});
+    const balance = await contract.methods.balanceOf(caller).call();
+
+    expect(balance).to.equal('200');
+  });
+
+  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});
+    const decimals = await contract.methods.decimals().call();
+
+    expect(decimals).to.equal('0');
+  });
+});
+
+describe('Refungible: Plain calls', () => {
+  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+
+    const spender = createEthAccount(web3);
+
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    {
+      const result = await contract.methods.approve(spender, 100).send({from: owner});
+      const events = normalizeEvents(result.events);
+
+      expect(events).to.be.deep.equal([
+        {
+          address,
+          event: 'Approval',
+          args: {
+            owner,
+            spender,
+            value: '100',
+          },
+        },
+      ]);
+    }
+
+    {
+      const allowance = await contract.methods.allowance(owner, spender).call();
+      expect(+allowance).to.equal(100);
+    }
+  });
+
+  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, owner);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const spender = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, spender);
+
+    const receiver = createEthAccount(web3);
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    await contract.methods.approve(spender, 100).send();
+
+    {
+      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});
+      const events = normalizeEvents(result.events);
+      expect(events).to.be.deep.equal([
+        {
+          address,
+          event: 'Transfer',
+          args: {
+            from: owner,
+            to: receiver,
+            value: '49',
+          },
+        },
+        {
+          address,
+          event: 'Approval',
+          args: {
+            owner,
+            spender,
+            value: '51',
+          },
+        },
+      ]);
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(receiver).call();
+      expect(+balance).to.equal(49);
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(owner).call();
+      expect(+balance).to.equal(151);
+    }
+  });
+
+  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, owner);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const receiver = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, receiver);
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    {
+      const result = await contract.methods.transfer(receiver, 50).send({from: owner});
+      const events = normalizeEvents(result.events);
+      expect(events).to.be.deep.equal([
+        {
+          address,
+          event: 'Transfer',
+          args: {
+            from: owner,
+            to: receiver,
+            value: '50',
+          },
+        },
+      ]);
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(owner).call();
+      expect(+balance).to.equal(150);
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(receiver).call();
+      expect(+balance).to.equal(50);
+    }
+  });
+
+  itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, owner);
+
+    const receiver = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, receiver);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    await contract.methods.repartition(200).send({from: owner});
+    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);
+    await contract.methods.transfer(receiver, 110).send({from: owner});
+    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);
+    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);
+    
+    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;
+
+    await contract.methods.transfer(receiver, 90).send({from: owner});
+    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);
+    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);
+
+    await contract.methods.repartition(150).send({from: receiver});
+    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;
+    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);
+  });
+
+  itWeb3('Can repartition with increased amount', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, owner);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    const result = await contract.methods.repartition(200).send();
+    const events = normalizeEvents(result.events);
+
+    expect(events).to.deep.equal([
+      {
+        address,
+        event: 'Transfer',
+        args: {
+          from: '0x0000000000000000000000000000000000000000',
+          to: owner,
+          value: '100',
+        },
+      },
+    ]);
+  });
+
+  itWeb3('Can repartition with decreased amount', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = createEthAccount(web3);
+    await transferBalanceToEth(api, alice, owner);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    const result = await contract.methods.repartition(50).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.deep.equal([
+      {
+        address,
+        event: 'Transfer',
+        args: {
+          from: owner,
+          to: '0x0000000000000000000000000000000000000000',
+          value: '50',
+        },
+      },
+    ]);
+  });
+});
+
+describe('Refungible: Fees', () => {
+  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const spender = createEthAccount(web3);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    await contract.methods.approve(spender, 100).send({from: owner});
+
+    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+
+  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const receiver = createEthAccount(web3);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});
+
+    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));
+    expect(cost < BigInt(0.2 * Number(UNIQUE)));
+  });
+});
+
+describe('Refungible: Substrate calls', () => {
+  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+
+    const receiver = createEthAccount(web3);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);
+
+    const events = await recordEvents(contract, async () => {
+      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;
+    });
+
+    expect(events).to.be.deep.equal([
+      {
+        address,
+        event: 'Approval',
+        args: {
+          owner: subToEth(alice.address),
+          spender: receiver,
+          value: '100',
+        },
+      },
+    ]);
+  });
+
+  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+    const bob = privateKeyWrapper('//Bob');
+
+    const receiver = createEthAccount(web3);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);
+
+    const events = await recordEvents(contract, async () => {
+      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;
+    });
+
+    expect(events).to.be.deep.equal([
+      {
+        address,
+        event: 'Transfer',
+        args: {
+          from: subToEth(alice.address),
+          to: receiver,
+          value: '51',
+        },
+      },
+      {
+        address,
+        event: 'Approval',
+        args: {
+          owner: subToEth(alice.address),
+          spender: subToEth(bob.address),
+          value: '49',
+        },
+      },
+    ]);
+  });
+
+  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {
+    const alice = privateKeyWrapper('//Alice');
+
+    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+
+    const receiver = createEthAccount(web3);
+
+    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;
+
+    const address = tokenIdToAddress(collectionId, tokenId);
+    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);
+
+    const events = await recordEvents(contract, async () => {
+      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;
+    });
+
+    expect(events).to.be.deep.equal([
+      {
+        address,
+        event: 'Transfer',
+        args: {
+          from: subToEth(alice.address),
+          to: receiver,
+          value: '51',
+        },
+      },
+    ]);
+  });
+});
addedtests/src/eth/reFungibleTokenAbi.jsondiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/reFungibleTokenAbi.json
@@ -0,0 +1,158 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "spender",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "spender", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "spender", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "repartition",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedtests/src/fungible.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/fungible.test.ts
@@ -0,0 +1,184 @@
+// 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/>.
+
+import {default as usingApi} from './substrate/substrate-api';
+import {IKeyringPair} from '@polkadot/types/types';
+import {
+  getBalance,
+  createMultipleItemsExpectSuccess,
+  isTokenExists,
+  getLastTokenId,
+  getAllowance,
+  approve,
+  transferFrom,
+  createCollection,
+  transfer,
+  burnItem,
+  normalizeAccountId,
+  CrossAccountId,
+  createFungibleItemExpectSuccess,
+  U128_MAX,
+  burnFromExpectSuccess,
+} from './util/helpers';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
+
+describe('integration test: Fungible functionality:', () => {
+  before(async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      alice = privateKeyWrapper('//Alice');
+      bob = privateKeyWrapper('//Bob');
+    });
+  });
+
+  it('Create fungible collection and token', async () => {
+    await usingApi(async api => {
+      const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+      expect(createCollectionResult.success).to.be.true;
+      const collectionId  = createCollectionResult.collectionId;
+      const defaultTokenId = await getLastTokenId(api, collectionId);
+      const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+      const aliceBalance = await getBalance(api, collectionId, alice, aliceTokenId); 
+      const itemCountAfter = await getLastTokenId(api, collectionId);
+      
+      // What to expect
+      // tslint:disable-next-line:no-unused-expression
+      expect(itemCountAfter).to.be.equal(defaultTokenId);
+      expect(aliceBalance).to.be.equal(U128_MAX);
+    });
+  });
+  
+  it('RPC method tokenOnewrs for fungible collection and token', async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+      const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+      
+      const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+      const collectionId = createCollectionResult.collectionId;
+      const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+     
+      await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+      await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+            
+      for (let i = 0; i < 7; i++) {
+        await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 1);
+      } 
+      
+      const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+      const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+      const aliceID = normalizeAccountId(alice);
+      const bobId = normalizeAccountId(bob);
+
+      // What to expect
+      // tslint:disable-next-line:no-unused-expression
+      expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+      expect(owners.length == 10).to.be.true;
+      
+      const eleven = privateKeyWrapper('11');
+      expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+      expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+    });
+  });
+  
+  it('Transfer token', async () => {
+    await usingApi(async api => {
+      const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+      const tokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address);
+
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(500n);
+      expect(await transfer(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;
+      expect(await transfer(api, collectionId, tokenId, alice, ethAcc, 140n)).to.be.true;
+
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(300n);
+      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(60n);
+      expect(await getBalance(api, collectionId, ethAcc, tokenId)).to.be.equal(140n);
+      await expect(transfer(api, collectionId, tokenId, alice, bob, 350n)).to.eventually.be.rejected;
+    });
+  });
+
+  it('Tokens multiple creation', async () => {
+    await usingApi(async api => {
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+      
+      const args = [
+        {Fungible: {Value: 500n}},
+        {Fungible: {Value: 400n}},
+        {Fungible: {Value: 300n}},
+      ];
+      
+      await createMultipleItemsExpectSuccess(alice, collectionId, args);
+      expect(await getBalance(api, collectionId, alice, 0)).to.be.equal(1200n);
+    });   
+  });
+
+  it('Burn some tokens ', async () => {
+    await usingApi(async api => {   
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+      const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address));
+      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(500n);
+      expect(await burnItem(api, alice, collectionId, tokenId, 499n)).to.be.true;
+      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(1n);
+    });
+  });
+  
+  it('Burn all tokens ', async () => {
+    await usingApi(async api => {   
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+      const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 500n}, alice.address));
+      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+      expect(await burnItem(api, alice, collectionId, tokenId, 500n)).to.be.true;
+      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;
+      
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(0n);
+      expect((await api.rpc.unique.totalPieces(collectionId, tokenId)).value.toBigInt()).to.be.equal(0n);
+    });
+  });
+
+  it('Set allowance for token', async () => {
+    await usingApi(async api => {
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}})).collectionId;
+      const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+      
+      const tokenId = (await createFungibleItemExpectSuccess(alice, collectionId, {Value: 100n}, alice.address));
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);
+
+      expect(await approve(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;
+      expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(60n);
+      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(0n);
+      
+      expect(await transferFrom(api, collectionId, tokenId, bob, alice, bob,  20n)).to.be.true;
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(80n);
+      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(20n);
+      expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(40n);
+      
+      await burnFromExpectSuccess(bob, alice, collectionId, tokenId, 10n);
+     
+      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(70n);
+      expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(30n);
+      expect(await transferFrom(api, collectionId, tokenId, bob, alice, ethAcc,  10n)).to.be.true;
+      expect(await getBalance(api, collectionId, ethAcc, tokenId)).to.be.equal(10n);
+    });
+  });
+});
modifiedtests/src/interfaces/augment-api-consts.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-consts.ts
+++ b/tests/src/interfaces/augment-api-consts.ts
@@ -29,7 +29,13 @@
       [key: string]: Codec;
     };
     common: {
+      /**
+       * Maximum admins per collection.
+       **/
       collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
+      /**
+       * Set price to create a collection.
+       **/
       collectionCreationPrice: u128 & AugmentedConst<ApiType>;
       /**
        * Generic const
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -285,7 +285,7 @@
        **/
       FungibleItemsDontHaveData: AugmentedError<ApiType>;
       /**
-       * Not default id passed as TokenId argument.
+       * Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.
        **/
       FungibleItemsHaveNoId: AugmentedError<ApiType>;
       /**
@@ -596,7 +596,7 @@
     };
     unique: {
       /**
-       * Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.
+       * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
        **/
       CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
       /**
@@ -608,7 +608,7 @@
        **/
       EmptyArgument: AugmentedError<ApiType>;
       /**
-       * Repertition is only supported by refungible collection
+       * Repertition is only supported by refungible collection.
        **/
       RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;
       /**
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -59,114 +59,47 @@
     };
     common: {
       /**
-       * Sponsoring allowance was approved.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - todo:doc flesh out
-       * * item_id
-       * * sender
-       * * spender
-       * * amount
+       * Amount pieces of token owned by `sender` was approved for `spender`.
        **/
       Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
        * New collection was created
-       * 
-       * # Arguments
-       * 
-       * * collection_id - Globally unique identifier of newly created collection.
-       * * mode - [CollectionMode] converted into u8.
-       * * account_id - Collection owner.
        **/
       CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;
       /**
        * New collection was destroyed
-       * 
-       * # Arguments
-       * 
-       * * collection_id - Globally unique identifier of collection that has been destroyed.
        **/
       CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;
       /**
-       * Collection property was deleted.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection, whose property was just deleted.
-       * * property_key - Key of the property that was just deleted.
+       * The property has been deleted.
        **/
       CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
-       * Collection property was added or edited.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection, whose property was just set.
-       * * property_key - Key of the property that was just set.
+       * The colletion property has been added or edited.
        **/
       CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
        * New item was created.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection where the item was created.
-       * * item_id - ID of the item. Unique within the collection.
-       * * recipient - Owner of the newly created item.
-       * * amount - The amount of tokens that were created (always 1 for NFT).
        **/
       ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
        * Collection item was burned.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - Identifier of the collection to which the burned NFT belonged.
-       * * item_id - Identifier of burned NFT.
-       * * owner - Which user has destroyed their tokens.
-       * * amount - Amount of tokens that were destroyed (always 1 for NFT).
        **/
       ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
-       * Token property permission was added or updated for a collection.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection, whose permissions were just set/updated.
-       * * property_key - Key of the property of the set/updated permission.
+       * The token property permission of a collection has been set.
        **/
       PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
-       * Item property was deleted.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection, whose token's property was just deleted.
-       * * item_id - ID of the item, whose property was just deleted.
-       * * property_key - Key of the property that was just deleted.
+       * The token property has been deleted.
        **/
       TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
       /**
-       * Item property was added or edited.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection, whose token's property was just set.
-       * * item_id - ID of the item, whose property was just set.
-       * * property_key - Key of the property that was just set.
+       * The token property has been added or edited.
        **/
       TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
       /**
-       * Item was transferred.
-       * 
-       * # Arguments
-       * 
-       * * collection_id - ID of the collection to which the item belongs.
-       * * item_id - ID of the item transferred.
-       * * sender - Original owner of the item.
-       * * recipient - New owner of the item.
-       * * amount - Amount of tokens that were transferred (always 1 for NFT).
+       * Item was transferred
        **/
       Transfer: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
@@ -569,94 +502,77 @@
        * Address was added to the allow list
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * user:  Address.
+       * * collection_id: ID of the affected collection.
+       * * user: Address of the added account.
        **/
       AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Address was removed from the allow list
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * user:  Address.
+       * * collection_id: ID of the affected collection.
+       * * user: Address of the removed account.
        **/
       AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Collection admin was added
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * admin:  Admin address.
+       * * collection_id: ID of the affected collection.
+       * * admin: Admin address.
        **/
       CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Collection admin was removed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * admin:  Admin address.
+       * * collection_id: ID of the affected collection.
+       * * admin: Removed admin address.
        **/
       CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Collection limits were set
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
+       * * collection_id: ID of the affected collection.
        **/
       CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
       /**
        * Collection owned was changed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * owner:  New owner address.
+       * * collection_id: ID of the affected collection.
+       * * owner: New owner address.
        **/
       CollectionOwnedChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
        * Collection permissions were set
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
+       * * collection_id: ID of the affected collection.
        **/
       CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
       /**
        * Collection sponsor was removed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
+       * * collection_id: ID of the affected collection.
        **/
       CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
       /**
        * Collection sponsor was set
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * owner:  New sponsor address.
+       * * collection_id: ID of the affected collection.
+       * * owner: New sponsor address.
        **/
       CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
        * New sponsor was confirm
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * sponsor:  New sponsor address.
+       * * collection_id: ID of the affected collection.
+       * * sponsor: New sponsor address.
        **/
       SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -70,39 +70,39 @@
     };
     common: {
       /**
-       * Amount of collection admins
+       * Storage of the amount of collection admins.
        **/
       adminAmount: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Allowlisted collection users
+       * Allowlisted collection users.
        **/
       allowlist: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Collection info
+       * Storage of collection info.
        **/
       collectionById: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Option<UpDataStructsCollection>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Collection properties
+       * Storage of collection properties.
        **/
       collectionProperties: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Token permissions of a collection
+       * Storage of token property permissions of a collection.
        **/
       collectionPropertyPermissions: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<BTreeMap<Bytes, UpDataStructsPropertyPermission>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * The number of created collections. Essentially contains the last collection ID.
+       * Storage of the count of created collections. Essentially contains the last collection ID.
        **/
       createdCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
       /**
-       * The number of destroyed collections
+       * Storage of the count of deleted collections.
        **/
       destroyedCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
       /**
-       * Not used by code, exists only to provide some types to metadata
+       * Not used by code, exists only to provide some types to metadata.
        **/
       dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
       /**
-       * List of collection admins
+       * List of collection admins.
        **/
       isAdmin: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -200,7 +200,7 @@
     };
     fungible: {
       /**
-       * todo:doc
+       * Storage for assets delegated to a limited extent to other users.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -244,11 +244,11 @@
     };
     nonfungible: {
       /**
-       * Amount of tokens owned in a collection.
+       * Amount of tokens owned by an account in a collection.
        **/
       accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * todo:doc
+       * Allowance set by a token owner for another user to perform one of certain transactions on a token.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
@@ -256,7 +256,15 @@
        **/
       owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
       /**
-       * Scoped, auxiliary properties of a token, primarily used for on-chain operations.
+       * Custom data of a token that is serialized to bytes,
+       * primarily reserved for on-chain operations,
+       * normally obscured from the external users.
+       * 
+       * Auxiliary properties are slightly different from
+       * usual [`TokenProperties`] due to an unlimited number
+       * and separately stored and written-to key-value pairs.
+       * 
+       * Currently used to store RMRK data.
        **/
       tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
       /**
@@ -268,7 +276,7 @@
        **/
       tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletNonfungibleItemData>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
-       * Key-value pairs, describing the metadata of a token.
+       * Map of key-value pairs, describing the metadata of a token.
        **/
       tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
@@ -447,11 +455,11 @@
        **/
       accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * todo:doc
+       * Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Amount of pieces of a token owned by an account.
+       * Amount of token pieces owned by account.
        **/
       balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -463,6 +471,10 @@
        **/
       tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
+       * Amount of pieces a refungible token is split into.
+       **/
+      tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+      /**
        * Amount of tokens burnt in a collection.
        **/
       tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
@@ -471,7 +483,7 @@
        **/
       tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Amount of pieces a refungible token is split into.
+       * Total amount of pieces for token
        **/
       totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -673,6 +673,10 @@
        **/
       collectionTokens: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
       /**
+       * Get token constant metadata
+       **/
+      constMetadata: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Bytes>>;
+      /**
        * Get effective collection limits
        **/
       effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;
@@ -705,6 +709,10 @@
        **/
       tokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
+       * Returns 10 tokens owners in no particular order
+       **/
+      tokenOwners: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
+      /**
        * Get token properties, optionally limited to the provided keys
        **/
       tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
@@ -720,6 +728,10 @@
        * Get the amount of distinctive tokens present in a collection
        **/
       totalSupply: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
+      /**
+       * Get token variable metadata
+       **/
+      variableMetadata: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Bytes>>;
     };
     web3: {
       /**
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -730,18 +730,22 @@
     };
     unique: {
       /**
-       * Adds an admin of the collection.
-       * NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.
+       * Add an admin to a collection.
+       * 
+       * NFT Collection can be controlled by multiple admin addresses
+       * (some which can also be servers, for example). Admins can issue
+       * and burn NFTs, as well as add and remove other admins,
+       * but cannot change NFT or Collection ownership.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the Collection to add admin for.
-       * * new_admin - Address of new admin to add.
+       * * `collection_id`: ID of the Collection to add an admin for.
+       * * `new_admin`: Address of new admin to add.
        **/
       addCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newAdmin: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -749,61 +753,76 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * address.
+       * * `collection_id`: ID of the modified collection.
+       * * `address`: ID of the address to be added to the allowlist.
        **/
       addToAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Set, change, or remove approved address to transfer the ownership of the NFT.
+       * Allow a non-permissioned address to transfer or burn an item.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT owner
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
        * 
        * # Arguments
        * 
-       * * approved - Address that is approved to transfer this NFT or zero (if needed to remove approval).
-       * * collection_id.
-       * * item_id - ID of the item.
+       * * `spender`: Account to be approved to make specific transactions on non-owned tokens.
+       * * `collection_id`: ID of the collection the item belongs to.
+       * * `item_id`: ID of the item transactions on which are now approved.
+       * * `amount`: Number of pieces of the item approved for a transaction (maximum of 1 for NFTs).
+       * Set to 0 to revoke the approval.
        **/
       approve: AugmentedSubmittable<(spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
-       * Destroy a concrete instance of NFT on behalf of the owner.
-       * See also: [`approve`]
+       * Destroy a token on behalf of the owner as a non-owner account.
+       * 
+       * See also: [`approve`][`Pallet::approve`].
+       * 
+       * After this method executes, one approval is removed from the total so that
+       * the approved address will not be able to transfer this item again from this owner.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
-       * * Collection Admin.
-       * * Current NFT Owner.
+       * * Collection owner
+       * * Collection admin
+       * * Current token owner
+       * * Address approved by current item owner
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * item_id - ID of NFT to burn.
-       * * from - The owner of the item from whom it is taken away.
+       * * `from`: The owner of the burning item.
+       * * `collection_id`: ID of the collection to which the item belongs.
+       * * `item_id`: ID of item to burn.
+       * * `value`: Number of pieces to burn.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to burn.
+       * * Re-Fungible Mode: The desired number of pieces to burn.
        **/
       burnFrom: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32, u128]>;
       /**
-       * Destroy a concrete instance of NFT.
+       * Destroy an item.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT Owner
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * item_id - ID of NFT to burn.
+       * * `collection_id`: ID of the collection to which the item belongs.
+       * * `item_id`: ID of item to burn.
+       * * `value`: Number of pieces of the item to destroy.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to burn.
+       * * Re-Fungible Mode: The desired number of pieces to burn.
        **/
       burnItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
       /**
@@ -811,108 +830,126 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * new_owner.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_owner`: ID of the account that will become the owner.
        **/
       changeCollectionOwner: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newOwner: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
       /**
-       * Confirm own sponsorship of a collection.
+       * Confirm own sponsorship of a collection, becoming the sponsor.
        * 
+       * An invitation must be pending, see [`set_collection_sponsor`][`Pallet::set_collection_sponsor`].
+       * Sponsor can pay the fees of a transaction instead of the sender,
+       * but only within specified limits.
+       * 
        * # Permissions
        * 
        * * Sponsor-to-be
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the collection with the pending sponsor.
        **/
       confirmSponsorship: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
-       * This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.
+       * Create a collection of tokens.
+       * 
+       * Each Token may have multiple properties encoded as an array of bytes
+       * of certain length. The initial owner of the collection is set
+       * to the address that signed the transaction and can be changed later.
        * 
+       * Prefer the more advanced [`create_collection_ex`][`Pallet::create_collection_ex`] instead.
+       * 
        * # Permissions
        * 
-       * * Anyone.
+       * * Anyone - becomes the owner of the new collection.
        * 
        * # Arguments
        * 
-       * * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.
-       * * collection_description - UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.
-       * * token_prefix - UTF-8 string with token prefix.
-       * * mode - [CollectionMode] collection type and type dependent data.
+       * * `collection_name`: Wide-character string with collection name
+       * (limit [`MAX_COLLECTION_NAME_LENGTH`]).
+       * * `collection_description`: Wide-character string with collection description
+       * (limit [`MAX_COLLECTION_DESCRIPTION_LENGTH`]).
+       * * `token_prefix`: Byte string containing the token prefix to mark a collection
+       * to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).
+       * * `mode`: Type of items stored in the collection and type dependent data.
        **/
       createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
       /**
        * Create a collection with explicit parameters.
-       * Prefer it to the deprecated [`created_collection`] method.
        * 
+       * Prefer it to the deprecated [`create_collection`][`Pallet::create_collection`] method.
+       * 
        * # Permissions
        * 
-       * * Anyone.
+       * * Anyone - becomes the owner of the new collection.
        * 
        * # Arguments
        * 
-       * * data: explicit create-collection data.
+       * * `data`: Explicit data of a collection used for its creation.
        **/
       createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; pendingSponsor?: any; limits?: any; permissions?: any; tokenPropertyPermissions?: any; properties?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
       /**
-       * Create a concrete instance of NFT Collection created with CreateCollection method.
+       * Mint an item within a collection.
+       * 
+       * A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * * Anyone if
        * * Allow List is enabled, and
        * * Address is added to allow list, and
-       * * MintPermission is enabled (see SetMintPermission method)
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * owner - Address, initial owner of the NFT.
-       * * data - Token data to store on chain.
+       * * `collection_id`: ID of the collection to which an item would belong.
+       * * `owner`: Address of the initial owner of the item.
+       * * `data`: Token data describing the item to store on chain.
        **/
       createItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, data: UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCreateItemData]>;
       /**
-       * Create multiple items in a collection created with CreateCollection method.
+       * Create multiple items within a collection.
+       * 
+       * A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * * Anyone if
        * * Allow List is enabled, and
-       * * Address is added to allow list, and
-       * * MintPermission is enabled (see SetMintPermission method)
+       * * Address is added to the allow list, and
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * owner - Address, initial owner of the NFT.
-       * * items_data - Array items properties. Each property is an array of bytes itself, see [`create_item`].
+       * * `collection_id`: ID of the collection to which the tokens would belong.
+       * * `owner`: Address of the initial owner of the tokens.
+       * * `items_data`: Vector of data describing each item to be created.
        **/
       createMultipleItems: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemsData: Vec<UpDataStructsCreateItemData> | (UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, Vec<UpDataStructsCreateItemData>]>;
       /**
-       * Create multiple items inside a collection with explicitly specified initial parameters.
+       * Create multiple items within a collection with explicitly specified initial parameters.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * * Anyone if
        * * Allow List is enabled, and
        * * Address is added to allow list, and
-       * * MintPermission is enabled (see SetMintPermission method)
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * data - Explicit item creation data.
+       * * `collection_id`: ID of the collection to which the tokens would belong.
+       * * `data`: Explicit item creation data.
        **/
       createMultipleItemsEx: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, data: UpDataStructsCreateItemExData | { NFT: any } | { Fungible: any } | { RefungibleMultipleItems: any } | { RefungibleMultipleOwners: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCreateItemExData]>;
       /**
@@ -925,63 +962,68 @@
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * property_keys - Vector of keys of the properties to be deleted.
+       * * `collection_id`: ID of the modified collection.
+       * * `property_keys`: Vector of keys of the properties to be deleted.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
       deleteCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<Bytes>]>;
       /**
-       * Delete specified token properties.
+       * Delete specified token properties. Currently properties only work with NFTs.
        * 
        * # Permissions
        * 
        * * Depends on collection's token property permissions and specified property mutability:
-       * * Collection Owner
-       * * Collection Admin
-       * * Token Owner
+       * * Collection owner
+       * * Collection admin
+       * * Token owner
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * token_id.
-       * * property_keys - Vector of keys of the properties to be deleted.
+       * * `collection_id`: ID of the collection to which the token belongs.
+       * * `token_id`: ID of the modified token.
+       * * `property_keys`: Vector of keys of the properties to be deleted.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
       deleteTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<Bytes>]>;
       /**
-       * Destroy the collection if no tokens exist within.
+       * Destroy a collection if no tokens exist within.
        * 
        * # Permissions
        * 
-       * * Collection Owner
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id - collection to destroy.
+       * * `collection_id`: Collection to destroy.
        **/
       destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
-       * Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.
+       * Remove admin of a collection.
+       * 
+       * An admin address can remove itself. List of admins may become empty,
+       * in which case only Collection Owner will be able to add an Admin.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the Collection to remove admin for.
-       * * account_id - Address of admin to remove.
+       * * `collection_id`: ID of the collection to remove the admin for.
+       * * `account_id`: Address of the admin to remove.
        **/
       removeCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, accountId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Switch back to pay-per-own-transaction model.
+       * Remove a collection's a sponsor, making everyone pay for their own transactions.
        * 
        * # Permissions
        * 
-       * * Collection Owner
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the collection with the sponsor to remove.
        **/
       removeCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
@@ -989,27 +1031,27 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * address.
+       * * `collection_id`: ID of the modified collection.
+       * * `address`: ID of the address to be removed from the allowlist.
        **/
       removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Re-partition a refungible token, while owning all of its parts.
+       * Re-partition a refungible token, while owning all of its parts/pieces.
        * 
        * # Permissions
        * 
-       * * Token Owner (must own every part)
+       * * Token owner (must own every part)
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * token_id - ID of the RFT.
-       * * amount - New number of parts into which the token shall be partitioned.
+       * * `collection_id`: ID of the collection the RFT belongs to.
+       * * `token_id`: ID of the RFT.
+       * * `amount`: New number of parts/pieces into which the token shall be partitioned.
        **/
       repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
       /**
@@ -1017,13 +1059,14 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * new_limit - New limits of the collection. They will overwrite the current ones.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_limit`: New limits of the collection. Fields that are not set (None)
+       * will not overwrite the old ones.
        **/
       setCollectionLimits: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newLimit: UpDataStructsCollectionLimits | { accountTokenOwnershipLimit?: any; sponsoredDataSize?: any; sponsoredDataRateLimit?: any; tokenLimit?: any; sponsorTransferTimeout?: any; sponsorApproveTimeout?: any; ownerCanTransfer?: any; ownerCanDestroy?: any; transfersEnabled?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionLimits]>;
       /**
@@ -1031,13 +1074,14 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * new_permission - New permissions of the collection. They will overwrite the current ones.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_permission`: New permissions of the collection. Fields that are not set (None)
+       * will not overwrite the old ones.
        **/
       setCollectionPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newPermission: UpDataStructsCollectionPermissions | { access?: any; mintMode?: any; nesting?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionPermissions]>;
       /**
@@ -1045,71 +1089,82 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * properties - Vector of key-value pairs stored as the collection's metadata. Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       * * `collection_id`: ID of the modified collection.
+       * * `properties`: Vector of key-value pairs stored as the collection's metadata.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
       setCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsProperty>]>;
       /**
-       * Set (invite) a new collection sponsor. If successful, confirmation from the sponsor-to-be will be pending.
+       * Set (invite) a new collection sponsor.
+       * 
+       * If successful, confirmation from the sponsor-to-be will be pending.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * new_sponsor.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_sponsor`: ID of the account of the sponsor-to-be.
        **/
       setCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newSponsor: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
       /**
        * Add or change token properties according to collection's permissions.
+       * Currently properties only work with NFTs.
        * 
        * # Permissions
        * 
        * * Depends on collection's token property permissions and specified property mutability:
-       * * Collection Owner
-       * * Collection Admin
-       * * Token Owner
+       * * Collection owner
+       * * Collection admin
+       * * Token owner
+       * 
+       * See [`set_token_property_permissions`][`Pallet::set_token_property_permissions`].
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * token_id.
-       * * properties - Vector of key-value pairs stored as the token's metadata. Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       * * `collection_id: ID of the collection to which the token belongs.
+       * * `token_id`: ID of the modified token.
+       * * `properties`: Vector of key-value pairs stored as the token's metadata.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
       setTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<UpDataStructsProperty>]>;
       /**
        * Add or change token property permissions of a collection.
        * 
+       * Without a permission for a particular key, a property with that key
+       * cannot be created in a token.
+       * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * * property_permissions - Vector of permissions for property keys. Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       * * `collection_id`: ID of the modified collection.
+       * * `property_permissions`: Vector of permissions for property keys.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
       setTokenPropertyPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyPermissions: Vec<UpDataStructsPropertyKeyPermission> | (UpDataStructsPropertyKeyPermission | { key?: any; permission?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsPropertyKeyPermission>]>;
       /**
-       * Set transfers_enabled value for particular collection.
+       * Completely allow or disallow transfers for a particular collection.
        * 
        * # Permissions
        * 
-       * * Collection Owner
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id - ID of the collection.
-       * * value - New flag value.
+       * * `collection_id`: ID of the collection.
+       * * `value`: New value of the flag, are transfers allowed?
        **/
       setTransfersEnabledFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
       /**
@@ -1117,44 +1172,50 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT owner
+       * * Collection owner
+       * * Collection admin
+       * * Current token owner
        * 
        * # Arguments
        * 
-       * * recipient - Address of token recipient.
-       * 
-       * * collection_id.
-       * 
-       * * item_id - ID of the item
+       * * `recipient`: Address of token recipient.
+       * * `collection_id`: ID of the collection the item belongs to.
+       * * `item_id`: ID of the item.
        * * Non-Fungible Mode: Required.
        * * Fungible Mode: Ignored.
        * * Re-Fungible Mode: Required.
        * 
-       * * value - Amount to transfer.
-       * * Non-Fungible Mode: Ignored
-       * * Fungible Mode: Must specify transferred amount
-       * * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
+       * * `value`: Amount to transfer.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to transfer.
+       * * Re-Fungible Mode: The desired number of pieces to transfer.
        **/
       transfer: AugmentedSubmittable<(recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
-       * Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.
+       * Change ownership of an item on behalf of the owner as a non-owner account.
+       * 
+       * See the [`approve`][`Pallet::approve`] method for additional information.
+       * 
+       * After this method executes, one approval is removed from the total so that
+       * the approved address will not be able to transfer this item again from this owner.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT owner
-       * * Address approved by current NFT owner
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
+       * * Address approved by current item owner
        * 
        * # Arguments
        * 
-       * * from - Address that currently owns the token.
-       * * recipient - Address of the new token-owner-to-be.
-       * * collection_id.
-       * * item_id - ID of the item to be transferred.
-       * * value - Amount to transfer.
+       * * `from`: Address that currently owns the token.
+       * * `recipient`: Address of the new token-owner-to-be.
+       * * `collection_id`: ID of the collection the item.
+       * * `item_id`: ID of the item to be transferred.
+       * * `value`: Amount to transfer.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to transfer.
+       * * Re-Fungible Mode: The desired number of pieces to transfer.
        **/
       transferFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -2461,12 +2461,14 @@
 export interface UpDataStructsCreateReFungibleData extends Struct {
   readonly constData: Bytes;
   readonly pieces: u128;
+  readonly properties: Vec<UpDataStructsProperty>;
 }
 
 /** @name UpDataStructsCreateRefungibleExData */
 export interface UpDataStructsCreateRefungibleExData extends Struct {
   readonly constData: Bytes;
   readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
+  readonly properties: Vec<UpDataStructsProperty>;
 }
 
 /** @name UpDataStructsNestingPermissions */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
before · tests/src/interfaces/lookup.ts
1// Auto-generated via `yarn polkadot-types-from-defs`, do not edit2/* eslint-disable */34/* eslint-disable sort-keys */56export default {7  /**8   * Lookup2: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>9   **/10  PolkadotPrimitivesV2PersistedValidationData: {11    parentHead: 'Bytes',12    relayParentNumber: 'u32',13    relayParentStorageRoot: 'H256',14    maxPovSize: 'u32'15  },16  /**17   * Lookup9: polkadot_primitives::v2::UpgradeRestriction18   **/19  PolkadotPrimitivesV2UpgradeRestriction: {20    _enum: ['Present']21  },22  /**23   * Lookup10: sp_trie::storage_proof::StorageProof24   **/25  SpTrieStorageProof: {26    trieNodes: 'BTreeSet<Bytes>'27  },28  /**29   * Lookup13: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot30   **/31  CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {32    dmqMqcHead: 'H256',33    relayDispatchQueueSize: '(u32,u32)',34    ingressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>',35    egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>'36  },37  /**38   * Lookup18: polkadot_primitives::v2::AbridgedHrmpChannel39   **/40  PolkadotPrimitivesV2AbridgedHrmpChannel: {41    maxCapacity: 'u32',42    maxTotalSize: 'u32',43    maxMessageSize: 'u32',44    msgCount: 'u32',45    totalSize: 'u32',46    mqcHead: 'Option<H256>'47  },48  /**49   * Lookup20: polkadot_primitives::v2::AbridgedHostConfiguration50   **/51  PolkadotPrimitivesV2AbridgedHostConfiguration: {52    maxCodeSize: 'u32',53    maxHeadDataSize: 'u32',54    maxUpwardQueueCount: 'u32',55    maxUpwardQueueSize: 'u32',56    maxUpwardMessageSize: 'u32',57    maxUpwardMessageNumPerCandidate: 'u32',58    hrmpMaxMessageNumPerCandidate: 'u32',59    validationUpgradeCooldown: 'u32',60    validationUpgradeDelay: 'u32'61  },62  /**63   * Lookup26: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>64   **/65  PolkadotCorePrimitivesOutboundHrmpMessage: {66    recipient: 'u32',67    data: 'Bytes'68  },69  /**70   * Lookup28: cumulus_pallet_parachain_system::pallet::Call<T>71   **/72  CumulusPalletParachainSystemCall: {73    _enum: {74      set_validation_data: {75        data: 'CumulusPrimitivesParachainInherentParachainInherentData',76      },77      sudo_send_upward_message: {78        message: 'Bytes',79      },80      authorize_upgrade: {81        codeHash: 'H256',82      },83      enact_authorized_upgrade: {84        code: 'Bytes'85      }86    }87  },88  /**89   * Lookup29: cumulus_primitives_parachain_inherent::ParachainInherentData90   **/91  CumulusPrimitivesParachainInherentParachainInherentData: {92    validationData: 'PolkadotPrimitivesV2PersistedValidationData',93    relayChainState: 'SpTrieStorageProof',94    downwardMessages: 'Vec<PolkadotCorePrimitivesInboundDownwardMessage>',95    horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'96  },97  /**98   * Lookup31: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>99   **/100  PolkadotCorePrimitivesInboundDownwardMessage: {101    sentAt: 'u32',102    msg: 'Bytes'103  },104  /**105   * Lookup34: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>106   **/107  PolkadotCorePrimitivesInboundHrmpMessage: {108    sentAt: 'u32',109    data: 'Bytes'110  },111  /**112   * Lookup37: cumulus_pallet_parachain_system::pallet::Event<T>113   **/114  CumulusPalletParachainSystemEvent: {115    _enum: {116      ValidationFunctionStored: 'Null',117      ValidationFunctionApplied: {118        relayChainBlockNum: 'u32',119      },120      ValidationFunctionDiscarded: 'Null',121      UpgradeAuthorized: {122        codeHash: 'H256',123      },124      DownwardMessagesReceived: {125        count: 'u32',126      },127      DownwardMessagesProcessed: {128        weightUsed: 'u64',129        dmqHead: 'H256'130      }131    }132  },133  /**134   * Lookup38: cumulus_pallet_parachain_system::pallet::Error<T>135   **/136  CumulusPalletParachainSystemError: {137    _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']138  },139  /**140   * Lookup41: pallet_balances::AccountData<Balance>141   **/142  PalletBalancesAccountData: {143    free: 'u128',144    reserved: 'u128',145    miscFrozen: 'u128',146    feeFrozen: 'u128'147  },148  /**149   * Lookup43: pallet_balances::BalanceLock<Balance>150   **/151  PalletBalancesBalanceLock: {152    id: '[u8;8]',153    amount: 'u128',154    reasons: 'PalletBalancesReasons'155  },156  /**157   * Lookup45: pallet_balances::Reasons158   **/159  PalletBalancesReasons: {160    _enum: ['Fee', 'Misc', 'All']161  },162  /**163   * Lookup48: pallet_balances::ReserveData<ReserveIdentifier, Balance>164   **/165  PalletBalancesReserveData: {166    id: '[u8;16]',167    amount: 'u128'168  },169  /**170   * Lookup51: pallet_balances::Releases171   **/172  PalletBalancesReleases: {173    _enum: ['V1_0_0', 'V2_0_0']174  },175  /**176   * Lookup52: pallet_balances::pallet::Call<T, I>177   **/178  PalletBalancesCall: {179    _enum: {180      transfer: {181        dest: 'MultiAddress',182        value: 'Compact<u128>',183      },184      set_balance: {185        who: 'MultiAddress',186        newFree: 'Compact<u128>',187        newReserved: 'Compact<u128>',188      },189      force_transfer: {190        source: 'MultiAddress',191        dest: 'MultiAddress',192        value: 'Compact<u128>',193      },194      transfer_keep_alive: {195        dest: 'MultiAddress',196        value: 'Compact<u128>',197      },198      transfer_all: {199        dest: 'MultiAddress',200        keepAlive: 'bool',201      },202      force_unreserve: {203        who: 'MultiAddress',204        amount: 'u128'205      }206    }207  },208  /**209   * Lookup58: pallet_balances::pallet::Event<T, I>210   **/211  PalletBalancesEvent: {212    _enum: {213      Endowed: {214        account: 'AccountId32',215        freeBalance: 'u128',216      },217      DustLost: {218        account: 'AccountId32',219        amount: 'u128',220      },221      Transfer: {222        from: 'AccountId32',223        to: 'AccountId32',224        amount: 'u128',225      },226      BalanceSet: {227        who: 'AccountId32',228        free: 'u128',229        reserved: 'u128',230      },231      Reserved: {232        who: 'AccountId32',233        amount: 'u128',234      },235      Unreserved: {236        who: 'AccountId32',237        amount: 'u128',238      },239      ReserveRepatriated: {240        from: 'AccountId32',241        to: 'AccountId32',242        amount: 'u128',243        destinationStatus: 'FrameSupportTokensMiscBalanceStatus',244      },245      Deposit: {246        who: 'AccountId32',247        amount: 'u128',248      },249      Withdraw: {250        who: 'AccountId32',251        amount: 'u128',252      },253      Slashed: {254        who: 'AccountId32',255        amount: 'u128'256      }257    }258  },259  /**260   * Lookup59: frame_support::traits::tokens::misc::BalanceStatus261   **/262  FrameSupportTokensMiscBalanceStatus: {263    _enum: ['Free', 'Reserved']264  },265  /**266   * Lookup60: pallet_balances::pallet::Error<T, I>267   **/268  PalletBalancesError: {269    _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves']270  },271  /**272   * Lookup63: pallet_timestamp::pallet::Call<T>273   **/274  PalletTimestampCall: {275    _enum: {276      set: {277        now: 'Compact<u64>'278      }279    }280  },281  /**282   * Lookup66: pallet_transaction_payment::Releases283   **/284  PalletTransactionPaymentReleases: {285    _enum: ['V1Ancient', 'V2']286  },287  /**288   * Lookup67: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>289   **/290  PalletTreasuryProposal: {291    proposer: 'AccountId32',292    value: 'u128',293    beneficiary: 'AccountId32',294    bond: 'u128'295  },296  /**297   * Lookup70: pallet_treasury::pallet::Call<T, I>298   **/299  PalletTreasuryCall: {300    _enum: {301      propose_spend: {302        value: 'Compact<u128>',303        beneficiary: 'MultiAddress',304      },305      reject_proposal: {306        proposalId: 'Compact<u32>',307      },308      approve_proposal: {309        proposalId: 'Compact<u32>',310      },311      remove_approval: {312        proposalId: 'Compact<u32>'313      }314    }315  },316  /**317   * Lookup72: pallet_treasury::pallet::Event<T, I>318   **/319  PalletTreasuryEvent: {320    _enum: {321      Proposed: {322        proposalIndex: 'u32',323      },324      Spending: {325        budgetRemaining: 'u128',326      },327      Awarded: {328        proposalIndex: 'u32',329        award: 'u128',330        account: 'AccountId32',331      },332      Rejected: {333        proposalIndex: 'u32',334        slashed: 'u128',335      },336      Burnt: {337        burntFunds: 'u128',338      },339      Rollover: {340        rolloverBalance: 'u128',341      },342      Deposit: {343        value: 'u128'344      }345    }346  },347  /**348   * Lookup75: frame_support::PalletId349   **/350  FrameSupportPalletId: '[u8;8]',351  /**352   * Lookup76: pallet_treasury::pallet::Error<T, I>353   **/354  PalletTreasuryError: {355    _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'ProposalNotApproved']356  },357  /**358   * Lookup77: pallet_sudo::pallet::Call<T>359   **/360  PalletSudoCall: {361    _enum: {362      sudo: {363        call: 'Call',364      },365      sudo_unchecked_weight: {366        call: 'Call',367        weight: 'u64',368      },369      set_key: {370        _alias: {371          new_: 'new',372        },373        new_: 'MultiAddress',374      },375      sudo_as: {376        who: 'MultiAddress',377        call: 'Call'378      }379    }380  },381  /**382   * Lookup79: frame_system::pallet::Call<T>383   **/384  FrameSystemCall: {385    _enum: {386      fill_block: {387        ratio: 'Perbill',388      },389      remark: {390        remark: 'Bytes',391      },392      set_heap_pages: {393        pages: 'u64',394      },395      set_code: {396        code: 'Bytes',397      },398      set_code_without_checks: {399        code: 'Bytes',400      },401      set_storage: {402        items: 'Vec<(Bytes,Bytes)>',403      },404      kill_storage: {405        _alias: {406          keys_: 'keys',407        },408        keys_: 'Vec<Bytes>',409      },410      kill_prefix: {411        prefix: 'Bytes',412        subkeys: 'u32',413      },414      remark_with_event: {415        remark: 'Bytes'416      }417    }418  },419  /**420   * Lookup83: orml_vesting::module::Call<T>421   **/422  OrmlVestingModuleCall: {423    _enum: {424      claim: 'Null',425      vested_transfer: {426        dest: 'MultiAddress',427        schedule: 'OrmlVestingVestingSchedule',428      },429      update_vesting_schedules: {430        who: 'MultiAddress',431        vestingSchedules: 'Vec<OrmlVestingVestingSchedule>',432      },433      claim_for: {434        dest: 'MultiAddress'435      }436    }437  },438  /**439   * Lookup84: orml_vesting::VestingSchedule<BlockNumber, Balance>440   **/441  OrmlVestingVestingSchedule: {442    start: 'u32',443    period: 'u32',444    periodCount: 'u32',445    perPeriod: 'Compact<u128>'446  },447  /**448   * Lookup86: cumulus_pallet_xcmp_queue::pallet::Call<T>449   **/450  CumulusPalletXcmpQueueCall: {451    _enum: {452      service_overweight: {453        index: 'u64',454        weightLimit: 'u64',455      },456      suspend_xcm_execution: 'Null',457      resume_xcm_execution: 'Null',458      update_suspend_threshold: {459        _alias: {460          new_: 'new',461        },462        new_: 'u32',463      },464      update_drop_threshold: {465        _alias: {466          new_: 'new',467        },468        new_: 'u32',469      },470      update_resume_threshold: {471        _alias: {472          new_: 'new',473        },474        new_: 'u32',475      },476      update_threshold_weight: {477        _alias: {478          new_: 'new',479        },480        new_: 'u64',481      },482      update_weight_restrict_decay: {483        _alias: {484          new_: 'new',485        },486        new_: 'u64',487      },488      update_xcmp_max_individual_weight: {489        _alias: {490          new_: 'new',491        },492        new_: 'u64'493      }494    }495  },496  /**497   * Lookup87: pallet_xcm::pallet::Call<T>498   **/499  PalletXcmCall: {500    _enum: {501      send: {502        dest: 'XcmVersionedMultiLocation',503        message: 'XcmVersionedXcm',504      },505      teleport_assets: {506        dest: 'XcmVersionedMultiLocation',507        beneficiary: 'XcmVersionedMultiLocation',508        assets: 'XcmVersionedMultiAssets',509        feeAssetItem: 'u32',510      },511      reserve_transfer_assets: {512        dest: 'XcmVersionedMultiLocation',513        beneficiary: 'XcmVersionedMultiLocation',514        assets: 'XcmVersionedMultiAssets',515        feeAssetItem: 'u32',516      },517      execute: {518        message: 'XcmVersionedXcm',519        maxWeight: 'u64',520      },521      force_xcm_version: {522        location: 'XcmV1MultiLocation',523        xcmVersion: 'u32',524      },525      force_default_xcm_version: {526        maybeXcmVersion: 'Option<u32>',527      },528      force_subscribe_version_notify: {529        location: 'XcmVersionedMultiLocation',530      },531      force_unsubscribe_version_notify: {532        location: 'XcmVersionedMultiLocation',533      },534      limited_reserve_transfer_assets: {535        dest: 'XcmVersionedMultiLocation',536        beneficiary: 'XcmVersionedMultiLocation',537        assets: 'XcmVersionedMultiAssets',538        feeAssetItem: 'u32',539        weightLimit: 'XcmV2WeightLimit',540      },541      limited_teleport_assets: {542        dest: 'XcmVersionedMultiLocation',543        beneficiary: 'XcmVersionedMultiLocation',544        assets: 'XcmVersionedMultiAssets',545        feeAssetItem: 'u32',546        weightLimit: 'XcmV2WeightLimit'547      }548    }549  },550  /**551   * Lookup88: xcm::VersionedMultiLocation552   **/553  XcmVersionedMultiLocation: {554    _enum: {555      V0: 'XcmV0MultiLocation',556      V1: 'XcmV1MultiLocation'557    }558  },559  /**560   * Lookup89: xcm::v0::multi_location::MultiLocation561   **/562  XcmV0MultiLocation: {563    _enum: {564      Null: 'Null',565      X1: 'XcmV0Junction',566      X2: '(XcmV0Junction,XcmV0Junction)',567      X3: '(XcmV0Junction,XcmV0Junction,XcmV0Junction)',568      X4: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',569      X5: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',570      X6: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',571      X7: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',572      X8: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)'573    }574  },575  /**576   * Lookup90: xcm::v0::junction::Junction577   **/578  XcmV0Junction: {579    _enum: {580      Parent: 'Null',581      Parachain: 'Compact<u32>',582      AccountId32: {583        network: 'XcmV0JunctionNetworkId',584        id: '[u8;32]',585      },586      AccountIndex64: {587        network: 'XcmV0JunctionNetworkId',588        index: 'Compact<u64>',589      },590      AccountKey20: {591        network: 'XcmV0JunctionNetworkId',592        key: '[u8;20]',593      },594      PalletInstance: 'u8',595      GeneralIndex: 'Compact<u128>',596      GeneralKey: 'Bytes',597      OnlyChild: 'Null',598      Plurality: {599        id: 'XcmV0JunctionBodyId',600        part: 'XcmV0JunctionBodyPart'601      }602    }603  },604  /**605   * Lookup91: xcm::v0::junction::NetworkId606   **/607  XcmV0JunctionNetworkId: {608    _enum: {609      Any: 'Null',610      Named: 'Bytes',611      Polkadot: 'Null',612      Kusama: 'Null'613    }614  },615  /**616   * Lookup92: xcm::v0::junction::BodyId617   **/618  XcmV0JunctionBodyId: {619    _enum: {620      Unit: 'Null',621      Named: 'Bytes',622      Index: 'Compact<u32>',623      Executive: 'Null',624      Technical: 'Null',625      Legislative: 'Null',626      Judicial: 'Null'627    }628  },629  /**630   * Lookup93: xcm::v0::junction::BodyPart631   **/632  XcmV0JunctionBodyPart: {633    _enum: {634      Voice: 'Null',635      Members: {636        count: 'Compact<u32>',637      },638      Fraction: {639        nom: 'Compact<u32>',640        denom: 'Compact<u32>',641      },642      AtLeastProportion: {643        nom: 'Compact<u32>',644        denom: 'Compact<u32>',645      },646      MoreThanProportion: {647        nom: 'Compact<u32>',648        denom: 'Compact<u32>'649      }650    }651  },652  /**653   * Lookup94: xcm::v1::multilocation::MultiLocation654   **/655  XcmV1MultiLocation: {656    parents: 'u8',657    interior: 'XcmV1MultilocationJunctions'658  },659  /**660   * Lookup95: xcm::v1::multilocation::Junctions661   **/662  XcmV1MultilocationJunctions: {663    _enum: {664      Here: 'Null',665      X1: 'XcmV1Junction',666      X2: '(XcmV1Junction,XcmV1Junction)',667      X3: '(XcmV1Junction,XcmV1Junction,XcmV1Junction)',668      X4: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',669      X5: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',670      X6: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',671      X7: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',672      X8: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)'673    }674  },675  /**676   * Lookup96: xcm::v1::junction::Junction677   **/678  XcmV1Junction: {679    _enum: {680      Parachain: 'Compact<u32>',681      AccountId32: {682        network: 'XcmV0JunctionNetworkId',683        id: '[u8;32]',684      },685      AccountIndex64: {686        network: 'XcmV0JunctionNetworkId',687        index: 'Compact<u64>',688      },689      AccountKey20: {690        network: 'XcmV0JunctionNetworkId',691        key: '[u8;20]',692      },693      PalletInstance: 'u8',694      GeneralIndex: 'Compact<u128>',695      GeneralKey: 'Bytes',696      OnlyChild: 'Null',697      Plurality: {698        id: 'XcmV0JunctionBodyId',699        part: 'XcmV0JunctionBodyPart'700      }701    }702  },703  /**704   * Lookup97: xcm::VersionedXcm<Call>705   **/706  XcmVersionedXcm: {707    _enum: {708      V0: 'XcmV0Xcm',709      V1: 'XcmV1Xcm',710      V2: 'XcmV2Xcm'711    }712  },713  /**714   * Lookup98: xcm::v0::Xcm<Call>715   **/716  XcmV0Xcm: {717    _enum: {718      WithdrawAsset: {719        assets: 'Vec<XcmV0MultiAsset>',720        effects: 'Vec<XcmV0Order>',721      },722      ReserveAssetDeposit: {723        assets: 'Vec<XcmV0MultiAsset>',724        effects: 'Vec<XcmV0Order>',725      },726      TeleportAsset: {727        assets: 'Vec<XcmV0MultiAsset>',728        effects: 'Vec<XcmV0Order>',729      },730      QueryResponse: {731        queryId: 'Compact<u64>',732        response: 'XcmV0Response',733      },734      TransferAsset: {735        assets: 'Vec<XcmV0MultiAsset>',736        dest: 'XcmV0MultiLocation',737      },738      TransferReserveAsset: {739        assets: 'Vec<XcmV0MultiAsset>',740        dest: 'XcmV0MultiLocation',741        effects: 'Vec<XcmV0Order>',742      },743      Transact: {744        originType: 'XcmV0OriginKind',745        requireWeightAtMost: 'u64',746        call: 'XcmDoubleEncoded',747      },748      HrmpNewChannelOpenRequest: {749        sender: 'Compact<u32>',750        maxMessageSize: 'Compact<u32>',751        maxCapacity: 'Compact<u32>',752      },753      HrmpChannelAccepted: {754        recipient: 'Compact<u32>',755      },756      HrmpChannelClosing: {757        initiator: 'Compact<u32>',758        sender: 'Compact<u32>',759        recipient: 'Compact<u32>',760      },761      RelayedFrom: {762        who: 'XcmV0MultiLocation',763        message: 'XcmV0Xcm'764      }765    }766  },767  /**768   * Lookup100: xcm::v0::multi_asset::MultiAsset769   **/770  XcmV0MultiAsset: {771    _enum: {772      None: 'Null',773      All: 'Null',774      AllFungible: 'Null',775      AllNonFungible: 'Null',776      AllAbstractFungible: {777        id: 'Bytes',778      },779      AllAbstractNonFungible: {780        class: 'Bytes',781      },782      AllConcreteFungible: {783        id: 'XcmV0MultiLocation',784      },785      AllConcreteNonFungible: {786        class: 'XcmV0MultiLocation',787      },788      AbstractFungible: {789        id: 'Bytes',790        amount: 'Compact<u128>',791      },792      AbstractNonFungible: {793        class: 'Bytes',794        instance: 'XcmV1MultiassetAssetInstance',795      },796      ConcreteFungible: {797        id: 'XcmV0MultiLocation',798        amount: 'Compact<u128>',799      },800      ConcreteNonFungible: {801        class: 'XcmV0MultiLocation',802        instance: 'XcmV1MultiassetAssetInstance'803      }804    }805  },806  /**807   * Lookup101: xcm::v1::multiasset::AssetInstance808   **/809  XcmV1MultiassetAssetInstance: {810    _enum: {811      Undefined: 'Null',812      Index: 'Compact<u128>',813      Array4: '[u8;4]',814      Array8: '[u8;8]',815      Array16: '[u8;16]',816      Array32: '[u8;32]',817      Blob: 'Bytes'818    }819  },820  /**821   * Lookup104: xcm::v0::order::Order<Call>822   **/823  XcmV0Order: {824    _enum: {825      Null: 'Null',826      DepositAsset: {827        assets: 'Vec<XcmV0MultiAsset>',828        dest: 'XcmV0MultiLocation',829      },830      DepositReserveAsset: {831        assets: 'Vec<XcmV0MultiAsset>',832        dest: 'XcmV0MultiLocation',833        effects: 'Vec<XcmV0Order>',834      },835      ExchangeAsset: {836        give: 'Vec<XcmV0MultiAsset>',837        receive: 'Vec<XcmV0MultiAsset>',838      },839      InitiateReserveWithdraw: {840        assets: 'Vec<XcmV0MultiAsset>',841        reserve: 'XcmV0MultiLocation',842        effects: 'Vec<XcmV0Order>',843      },844      InitiateTeleport: {845        assets: 'Vec<XcmV0MultiAsset>',846        dest: 'XcmV0MultiLocation',847        effects: 'Vec<XcmV0Order>',848      },849      QueryHolding: {850        queryId: 'Compact<u64>',851        dest: 'XcmV0MultiLocation',852        assets: 'Vec<XcmV0MultiAsset>',853      },854      BuyExecution: {855        fees: 'XcmV0MultiAsset',856        weight: 'u64',857        debt: 'u64',858        haltOnError: 'bool',859        xcm: 'Vec<XcmV0Xcm>'860      }861    }862  },863  /**864   * Lookup106: xcm::v0::Response865   **/866  XcmV0Response: {867    _enum: {868      Assets: 'Vec<XcmV0MultiAsset>'869    }870  },871  /**872   * Lookup107: xcm::v0::OriginKind873   **/874  XcmV0OriginKind: {875    _enum: ['Native', 'SovereignAccount', 'Superuser', 'Xcm']876  },877  /**878   * Lookup108: xcm::double_encoded::DoubleEncoded<T>879   **/880  XcmDoubleEncoded: {881    encoded: 'Bytes'882  },883  /**884   * Lookup109: xcm::v1::Xcm<Call>885   **/886  XcmV1Xcm: {887    _enum: {888      WithdrawAsset: {889        assets: 'XcmV1MultiassetMultiAssets',890        effects: 'Vec<XcmV1Order>',891      },892      ReserveAssetDeposited: {893        assets: 'XcmV1MultiassetMultiAssets',894        effects: 'Vec<XcmV1Order>',895      },896      ReceiveTeleportedAsset: {897        assets: 'XcmV1MultiassetMultiAssets',898        effects: 'Vec<XcmV1Order>',899      },900      QueryResponse: {901        queryId: 'Compact<u64>',902        response: 'XcmV1Response',903      },904      TransferAsset: {905        assets: 'XcmV1MultiassetMultiAssets',906        beneficiary: 'XcmV1MultiLocation',907      },908      TransferReserveAsset: {909        assets: 'XcmV1MultiassetMultiAssets',910        dest: 'XcmV1MultiLocation',911        effects: 'Vec<XcmV1Order>',912      },913      Transact: {914        originType: 'XcmV0OriginKind',915        requireWeightAtMost: 'u64',916        call: 'XcmDoubleEncoded',917      },918      HrmpNewChannelOpenRequest: {919        sender: 'Compact<u32>',920        maxMessageSize: 'Compact<u32>',921        maxCapacity: 'Compact<u32>',922      },923      HrmpChannelAccepted: {924        recipient: 'Compact<u32>',925      },926      HrmpChannelClosing: {927        initiator: 'Compact<u32>',928        sender: 'Compact<u32>',929        recipient: 'Compact<u32>',930      },931      RelayedFrom: {932        who: 'XcmV1MultilocationJunctions',933        message: 'XcmV1Xcm',934      },935      SubscribeVersion: {936        queryId: 'Compact<u64>',937        maxResponseWeight: 'Compact<u64>',938      },939      UnsubscribeVersion: 'Null'940    }941  },942  /**943   * Lookup110: xcm::v1::multiasset::MultiAssets944   **/945  XcmV1MultiassetMultiAssets: 'Vec<XcmV1MultiAsset>',946  /**947   * Lookup112: xcm::v1::multiasset::MultiAsset948   **/949  XcmV1MultiAsset: {950    id: 'XcmV1MultiassetAssetId',951    fun: 'XcmV1MultiassetFungibility'952  },953  /**954   * Lookup113: xcm::v1::multiasset::AssetId955   **/956  XcmV1MultiassetAssetId: {957    _enum: {958      Concrete: 'XcmV1MultiLocation',959      Abstract: 'Bytes'960    }961  },962  /**963   * Lookup114: xcm::v1::multiasset::Fungibility964   **/965  XcmV1MultiassetFungibility: {966    _enum: {967      Fungible: 'Compact<u128>',968      NonFungible: 'XcmV1MultiassetAssetInstance'969    }970  },971  /**972   * Lookup116: xcm::v1::order::Order<Call>973   **/974  XcmV1Order: {975    _enum: {976      Noop: 'Null',977      DepositAsset: {978        assets: 'XcmV1MultiassetMultiAssetFilter',979        maxAssets: 'u32',980        beneficiary: 'XcmV1MultiLocation',981      },982      DepositReserveAsset: {983        assets: 'XcmV1MultiassetMultiAssetFilter',984        maxAssets: 'u32',985        dest: 'XcmV1MultiLocation',986        effects: 'Vec<XcmV1Order>',987      },988      ExchangeAsset: {989        give: 'XcmV1MultiassetMultiAssetFilter',990        receive: 'XcmV1MultiassetMultiAssets',991      },992      InitiateReserveWithdraw: {993        assets: 'XcmV1MultiassetMultiAssetFilter',994        reserve: 'XcmV1MultiLocation',995        effects: 'Vec<XcmV1Order>',996      },997      InitiateTeleport: {998        assets: 'XcmV1MultiassetMultiAssetFilter',999        dest: 'XcmV1MultiLocation',1000        effects: 'Vec<XcmV1Order>',1001      },1002      QueryHolding: {1003        queryId: 'Compact<u64>',1004        dest: 'XcmV1MultiLocation',1005        assets: 'XcmV1MultiassetMultiAssetFilter',1006      },1007      BuyExecution: {1008        fees: 'XcmV1MultiAsset',1009        weight: 'u64',1010        debt: 'u64',1011        haltOnError: 'bool',1012        instructions: 'Vec<XcmV1Xcm>'1013      }1014    }1015  },1016  /**1017   * Lookup117: xcm::v1::multiasset::MultiAssetFilter1018   **/1019  XcmV1MultiassetMultiAssetFilter: {1020    _enum: {1021      Definite: 'XcmV1MultiassetMultiAssets',1022      Wild: 'XcmV1MultiassetWildMultiAsset'1023    }1024  },1025  /**1026   * Lookup118: xcm::v1::multiasset::WildMultiAsset1027   **/1028  XcmV1MultiassetWildMultiAsset: {1029    _enum: {1030      All: 'Null',1031      AllOf: {1032        id: 'XcmV1MultiassetAssetId',1033        fun: 'XcmV1MultiassetWildFungibility'1034      }1035    }1036  },1037  /**1038   * Lookup119: xcm::v1::multiasset::WildFungibility1039   **/1040  XcmV1MultiassetWildFungibility: {1041    _enum: ['Fungible', 'NonFungible']1042  },1043  /**1044   * Lookup121: xcm::v1::Response1045   **/1046  XcmV1Response: {1047    _enum: {1048      Assets: 'XcmV1MultiassetMultiAssets',1049      Version: 'u32'1050    }1051  },1052  /**1053   * Lookup122: xcm::v2::Xcm<Call>1054   **/1055  XcmV2Xcm: 'Vec<XcmV2Instruction>',1056  /**1057   * Lookup124: xcm::v2::Instruction<Call>1058   **/1059  XcmV2Instruction: {1060    _enum: {1061      WithdrawAsset: 'XcmV1MultiassetMultiAssets',1062      ReserveAssetDeposited: 'XcmV1MultiassetMultiAssets',1063      ReceiveTeleportedAsset: 'XcmV1MultiassetMultiAssets',1064      QueryResponse: {1065        queryId: 'Compact<u64>',1066        response: 'XcmV2Response',1067        maxWeight: 'Compact<u64>',1068      },1069      TransferAsset: {1070        assets: 'XcmV1MultiassetMultiAssets',1071        beneficiary: 'XcmV1MultiLocation',1072      },1073      TransferReserveAsset: {1074        assets: 'XcmV1MultiassetMultiAssets',1075        dest: 'XcmV1MultiLocation',1076        xcm: 'XcmV2Xcm',1077      },1078      Transact: {1079        originType: 'XcmV0OriginKind',1080        requireWeightAtMost: 'Compact<u64>',1081        call: 'XcmDoubleEncoded',1082      },1083      HrmpNewChannelOpenRequest: {1084        sender: 'Compact<u32>',1085        maxMessageSize: 'Compact<u32>',1086        maxCapacity: 'Compact<u32>',1087      },1088      HrmpChannelAccepted: {1089        recipient: 'Compact<u32>',1090      },1091      HrmpChannelClosing: {1092        initiator: 'Compact<u32>',1093        sender: 'Compact<u32>',1094        recipient: 'Compact<u32>',1095      },1096      ClearOrigin: 'Null',1097      DescendOrigin: 'XcmV1MultilocationJunctions',1098      ReportError: {1099        queryId: 'Compact<u64>',1100        dest: 'XcmV1MultiLocation',1101        maxResponseWeight: 'Compact<u64>',1102      },1103      DepositAsset: {1104        assets: 'XcmV1MultiassetMultiAssetFilter',1105        maxAssets: 'Compact<u32>',1106        beneficiary: 'XcmV1MultiLocation',1107      },1108      DepositReserveAsset: {1109        assets: 'XcmV1MultiassetMultiAssetFilter',1110        maxAssets: 'Compact<u32>',1111        dest: 'XcmV1MultiLocation',1112        xcm: 'XcmV2Xcm',1113      },1114      ExchangeAsset: {1115        give: 'XcmV1MultiassetMultiAssetFilter',1116        receive: 'XcmV1MultiassetMultiAssets',1117      },1118      InitiateReserveWithdraw: {1119        assets: 'XcmV1MultiassetMultiAssetFilter',1120        reserve: 'XcmV1MultiLocation',1121        xcm: 'XcmV2Xcm',1122      },1123      InitiateTeleport: {1124        assets: 'XcmV1MultiassetMultiAssetFilter',1125        dest: 'XcmV1MultiLocation',1126        xcm: 'XcmV2Xcm',1127      },1128      QueryHolding: {1129        queryId: 'Compact<u64>',1130        dest: 'XcmV1MultiLocation',1131        assets: 'XcmV1MultiassetMultiAssetFilter',1132        maxResponseWeight: 'Compact<u64>',1133      },1134      BuyExecution: {1135        fees: 'XcmV1MultiAsset',1136        weightLimit: 'XcmV2WeightLimit',1137      },1138      RefundSurplus: 'Null',1139      SetErrorHandler: 'XcmV2Xcm',1140      SetAppendix: 'XcmV2Xcm',1141      ClearError: 'Null',1142      ClaimAsset: {1143        assets: 'XcmV1MultiassetMultiAssets',1144        ticket: 'XcmV1MultiLocation',1145      },1146      Trap: 'Compact<u64>',1147      SubscribeVersion: {1148        queryId: 'Compact<u64>',1149        maxResponseWeight: 'Compact<u64>',1150      },1151      UnsubscribeVersion: 'Null'1152    }1153  },1154  /**1155   * Lookup125: xcm::v2::Response1156   **/1157  XcmV2Response: {1158    _enum: {1159      Null: 'Null',1160      Assets: 'XcmV1MultiassetMultiAssets',1161      ExecutionResult: 'Option<(u32,XcmV2TraitsError)>',1162      Version: 'u32'1163    }1164  },1165  /**1166   * Lookup128: xcm::v2::traits::Error1167   **/1168  XcmV2TraitsError: {1169    _enum: {1170      Overflow: 'Null',1171      Unimplemented: 'Null',1172      UntrustedReserveLocation: 'Null',1173      UntrustedTeleportLocation: 'Null',1174      MultiLocationFull: 'Null',1175      MultiLocationNotInvertible: 'Null',1176      BadOrigin: 'Null',1177      InvalidLocation: 'Null',1178      AssetNotFound: 'Null',1179      FailedToTransactAsset: 'Null',1180      NotWithdrawable: 'Null',1181      LocationCannotHold: 'Null',1182      ExceedsMaxMessageSize: 'Null',1183      DestinationUnsupported: 'Null',1184      Transport: 'Null',1185      Unroutable: 'Null',1186      UnknownClaim: 'Null',1187      FailedToDecode: 'Null',1188      MaxWeightInvalid: 'Null',1189      NotHoldingFees: 'Null',1190      TooExpensive: 'Null',1191      Trap: 'u64',1192      UnhandledXcmVersion: 'Null',1193      WeightLimitReached: 'u64',1194      Barrier: 'Null',1195      WeightNotComputable: 'Null'1196    }1197  },1198  /**1199   * Lookup129: xcm::v2::WeightLimit1200   **/1201  XcmV2WeightLimit: {1202    _enum: {1203      Unlimited: 'Null',1204      Limited: 'Compact<u64>'1205    }1206  },1207  /**1208   * Lookup130: xcm::VersionedMultiAssets1209   **/1210  XcmVersionedMultiAssets: {1211    _enum: {1212      V0: 'Vec<XcmV0MultiAsset>',1213      V1: 'XcmV1MultiassetMultiAssets'1214    }1215  },1216  /**1217   * Lookup145: cumulus_pallet_xcm::pallet::Call<T>1218   **/1219  CumulusPalletXcmCall: 'Null',1220  /**1221   * Lookup146: cumulus_pallet_dmp_queue::pallet::Call<T>1222   **/1223  CumulusPalletDmpQueueCall: {1224    _enum: {1225      service_overweight: {1226        index: 'u64',1227        weightLimit: 'u64'1228      }1229    }1230  },1231  /**1232   * Lookup147: pallet_inflation::pallet::Call<T>1233   **/1234  PalletInflationCall: {1235    _enum: {1236      start_inflation: {1237        inflationStartRelayBlock: 'u32'1238      }1239    }1240  },1241  /**1242   * Lookup148: pallet_unique::Call<T>1243   **/1244  PalletUniqueCall: {1245    _enum: {1246      create_collection: {1247        collectionName: 'Vec<u16>',1248        collectionDescription: 'Vec<u16>',1249        tokenPrefix: 'Bytes',1250        mode: 'UpDataStructsCollectionMode',1251      },1252      create_collection_ex: {1253        data: 'UpDataStructsCreateCollectionData',1254      },1255      destroy_collection: {1256        collectionId: 'u32',1257      },1258      add_to_allow_list: {1259        collectionId: 'u32',1260        address: 'PalletEvmAccountBasicCrossAccountIdRepr',1261      },1262      remove_from_allow_list: {1263        collectionId: 'u32',1264        address: 'PalletEvmAccountBasicCrossAccountIdRepr',1265      },1266      change_collection_owner: {1267        collectionId: 'u32',1268        newOwner: 'AccountId32',1269      },1270      add_collection_admin: {1271        collectionId: 'u32',1272        newAdmin: 'PalletEvmAccountBasicCrossAccountIdRepr',1273      },1274      remove_collection_admin: {1275        collectionId: 'u32',1276        accountId: 'PalletEvmAccountBasicCrossAccountIdRepr',1277      },1278      set_collection_sponsor: {1279        collectionId: 'u32',1280        newSponsor: 'AccountId32',1281      },1282      confirm_sponsorship: {1283        collectionId: 'u32',1284      },1285      remove_collection_sponsor: {1286        collectionId: 'u32',1287      },1288      create_item: {1289        collectionId: 'u32',1290        owner: 'PalletEvmAccountBasicCrossAccountIdRepr',1291        data: 'UpDataStructsCreateItemData',1292      },1293      create_multiple_items: {1294        collectionId: 'u32',1295        owner: 'PalletEvmAccountBasicCrossAccountIdRepr',1296        itemsData: 'Vec<UpDataStructsCreateItemData>',1297      },1298      set_collection_properties: {1299        collectionId: 'u32',1300        properties: 'Vec<UpDataStructsProperty>',1301      },1302      delete_collection_properties: {1303        collectionId: 'u32',1304        propertyKeys: 'Vec<Bytes>',1305      },1306      set_token_properties: {1307        collectionId: 'u32',1308        tokenId: 'u32',1309        properties: 'Vec<UpDataStructsProperty>',1310      },1311      delete_token_properties: {1312        collectionId: 'u32',1313        tokenId: 'u32',1314        propertyKeys: 'Vec<Bytes>',1315      },1316      set_token_property_permissions: {1317        collectionId: 'u32',1318        propertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',1319      },1320      create_multiple_items_ex: {1321        collectionId: 'u32',1322        data: 'UpDataStructsCreateItemExData',1323      },1324      set_transfers_enabled_flag: {1325        collectionId: 'u32',1326        value: 'bool',1327      },1328      burn_item: {1329        collectionId: 'u32',1330        itemId: 'u32',1331        value: 'u128',1332      },1333      burn_from: {1334        collectionId: 'u32',1335        from: 'PalletEvmAccountBasicCrossAccountIdRepr',1336        itemId: 'u32',1337        value: 'u128',1338      },1339      transfer: {1340        recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',1341        collectionId: 'u32',1342        itemId: 'u32',1343        value: 'u128',1344      },1345      approve: {1346        spender: 'PalletEvmAccountBasicCrossAccountIdRepr',1347        collectionId: 'u32',1348        itemId: 'u32',1349        amount: 'u128',1350      },1351      transfer_from: {1352        from: 'PalletEvmAccountBasicCrossAccountIdRepr',1353        recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',1354        collectionId: 'u32',1355        itemId: 'u32',1356        value: 'u128',1357      },1358      set_collection_limits: {1359        collectionId: 'u32',1360        newLimit: 'UpDataStructsCollectionLimits',1361      },1362      set_collection_permissions: {1363        collectionId: 'u32',1364        newPermission: 'UpDataStructsCollectionPermissions',1365      },1366      repartition: {1367        collectionId: 'u32',1368        tokenId: 'u32',1369        amount: 'u128'1370      }1371    }1372  },1373  /**1374   * Lookup154: up_data_structs::CollectionMode1375   **/1376  UpDataStructsCollectionMode: {1377    _enum: {1378      NFT: 'Null',1379      Fungible: 'u8',1380      ReFungible: 'Null'1381    }1382  },1383  /**1384   * Lookup155: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>1385   **/1386  UpDataStructsCreateCollectionData: {1387    mode: 'UpDataStructsCollectionMode',1388    access: 'Option<UpDataStructsAccessMode>',1389    name: 'Vec<u16>',1390    description: 'Vec<u16>',1391    tokenPrefix: 'Bytes',1392    pendingSponsor: 'Option<AccountId32>',1393    limits: 'Option<UpDataStructsCollectionLimits>',1394    permissions: 'Option<UpDataStructsCollectionPermissions>',1395    tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',1396    properties: 'Vec<UpDataStructsProperty>'1397  },1398  /**1399   * Lookup157: up_data_structs::AccessMode1400   **/1401  UpDataStructsAccessMode: {1402    _enum: ['Normal', 'AllowList']1403  },1404  /**1405   * Lookup160: up_data_structs::CollectionLimits1406   **/1407  UpDataStructsCollectionLimits: {1408    accountTokenOwnershipLimit: 'Option<u32>',1409    sponsoredDataSize: 'Option<u32>',1410    sponsoredDataRateLimit: 'Option<UpDataStructsSponsoringRateLimit>',1411    tokenLimit: 'Option<u32>',1412    sponsorTransferTimeout: 'Option<u32>',1413    sponsorApproveTimeout: 'Option<u32>',1414    ownerCanTransfer: 'Option<bool>',1415    ownerCanDestroy: 'Option<bool>',1416    transfersEnabled: 'Option<bool>'1417  },1418  /**1419   * Lookup162: up_data_structs::SponsoringRateLimit1420   **/1421  UpDataStructsSponsoringRateLimit: {1422    _enum: {1423      SponsoringDisabled: 'Null',1424      Blocks: 'u32'1425    }1426  },1427  /**1428   * Lookup165: up_data_structs::CollectionPermissions1429   **/1430  UpDataStructsCollectionPermissions: {1431    access: 'Option<UpDataStructsAccessMode>',1432    mintMode: 'Option<bool>',1433    nesting: 'Option<UpDataStructsNestingPermissions>'1434  },1435  /**1436   * Lookup167: up_data_structs::NestingPermissions1437   **/1438  UpDataStructsNestingPermissions: {1439    tokenOwner: 'bool',1440    collectionAdmin: 'bool',1441    restricted: 'Option<UpDataStructsOwnerRestrictedSet>'1442  },1443  /**1444   * Lookup169: up_data_structs::OwnerRestrictedSet1445   **/1446  UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',1447  /**1448   * Lookup175: up_data_structs::PropertyKeyPermission1449   **/1450  UpDataStructsPropertyKeyPermission: {1451    key: 'Bytes',1452    permission: 'UpDataStructsPropertyPermission'1453  },1454  /**1455   * Lookup177: up_data_structs::PropertyPermission1456   **/1457  UpDataStructsPropertyPermission: {1458    mutable: 'bool',1459    collectionAdmin: 'bool',1460    tokenOwner: 'bool'1461  },1462  /**1463   * Lookup180: up_data_structs::Property1464   **/1465  UpDataStructsProperty: {1466    key: 'Bytes',1467    value: 'Bytes'1468  },1469  /**1470   * Lookup183: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>1471   **/1472  PalletEvmAccountBasicCrossAccountIdRepr: {1473    _enum: {1474      Substrate: 'AccountId32',1475      Ethereum: 'H160'1476    }1477  },1478  /**1479   * Lookup185: up_data_structs::CreateItemData1480   **/1481  UpDataStructsCreateItemData: {1482    _enum: {1483      NFT: 'UpDataStructsCreateNftData',1484      Fungible: 'UpDataStructsCreateFungibleData',1485      ReFungible: 'UpDataStructsCreateReFungibleData'1486    }1487  },1488  /**1489   * Lookup186: up_data_structs::CreateNftData1490   **/1491  UpDataStructsCreateNftData: {1492    properties: 'Vec<UpDataStructsProperty>'1493  },1494  /**1495   * Lookup187: up_data_structs::CreateFungibleData1496   **/1497  UpDataStructsCreateFungibleData: {1498    value: 'u128'1499  },1500  /**1501   * Lookup188: up_data_structs::CreateReFungibleData1502   **/1503  UpDataStructsCreateReFungibleData: {1504    constData: 'Bytes',1505    pieces: 'u128'1506  },1507  /**1508   * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1509   **/1510  UpDataStructsCreateItemExData: {1511    _enum: {1512      NFT: 'Vec<UpDataStructsCreateNftExData>',1513      Fungible: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',1514      RefungibleMultipleItems: 'Vec<UpDataStructsCreateRefungibleExData>',1515      RefungibleMultipleOwners: 'UpDataStructsCreateRefungibleExData'1516    }1517  },1518  /**1519   * Lookup195: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1520   **/1521  UpDataStructsCreateNftExData: {1522    properties: 'Vec<UpDataStructsProperty>',1523    owner: 'PalletEvmAccountBasicCrossAccountIdRepr'1524  },1525  /**1526   * Lookup202: up_data_structs::CreateRefungibleExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1527   **/1528  UpDataStructsCreateRefungibleExData: {1529    constData: 'Bytes',1530    users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>'1531  },1532  /**1533   * Lookup204: pallet_unique_scheduler::pallet::Call<T>1534   **/1535  PalletUniqueSchedulerCall: {1536    _enum: {1537      schedule_named: {1538        id: '[u8;16]',1539        when: 'u32',1540        maybePeriodic: 'Option<(u32,u32)>',1541        priority: 'u8',1542        call: 'FrameSupportScheduleMaybeHashed',1543      },1544      cancel_named: {1545        id: '[u8;16]',1546      },1547      schedule_named_after: {1548        id: '[u8;16]',1549        after: 'u32',1550        maybePeriodic: 'Option<(u32,u32)>',1551        priority: 'u8',1552        call: 'FrameSupportScheduleMaybeHashed'1553      }1554    }1555  },1556  /**1557   * Lookup206: frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>1558   **/1559  FrameSupportScheduleMaybeHashed: {1560    _enum: {1561      Value: 'Call',1562      Hash: 'H256'1563    }1564  },1565  /**1566   * Lookup207: pallet_template_transaction_payment::Call<T>1567   **/1568  PalletTemplateTransactionPaymentCall: 'Null',1569  /**1570   * Lookup208: pallet_structure::pallet::Call<T>1571   **/1572  PalletStructureCall: 'Null',1573  /**1574   * Lookup209: pallet_rmrk_core::pallet::Call<T>1575   **/1576  PalletRmrkCoreCall: {1577    _enum: {1578      create_collection: {1579        metadata: 'Bytes',1580        max: 'Option<u32>',1581        symbol: 'Bytes',1582      },1583      destroy_collection: {1584        collectionId: 'u32',1585      },1586      change_collection_issuer: {1587        collectionId: 'u32',1588        newIssuer: 'MultiAddress',1589      },1590      lock_collection: {1591        collectionId: 'u32',1592      },1593      mint_nft: {1594        owner: 'Option<AccountId32>',1595        collectionId: 'u32',1596        recipient: 'Option<AccountId32>',1597        royaltyAmount: 'Option<Permill>',1598        metadata: 'Bytes',1599        transferable: 'bool',1600        resources: 'Option<Vec<RmrkTraitsResourceResourceTypes>>',1601      },1602      burn_nft: {1603        collectionId: 'u32',1604        nftId: 'u32',1605        maxBurns: 'u32',1606      },1607      send: {1608        rmrkCollectionId: 'u32',1609        rmrkNftId: 'u32',1610        newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',1611      },1612      accept_nft: {1613        rmrkCollectionId: 'u32',1614        rmrkNftId: 'u32',1615        newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',1616      },1617      reject_nft: {1618        rmrkCollectionId: 'u32',1619        rmrkNftId: 'u32',1620      },1621      accept_resource: {1622        rmrkCollectionId: 'u32',1623        rmrkNftId: 'u32',1624        resourceId: 'u32',1625      },1626      accept_resource_removal: {1627        rmrkCollectionId: 'u32',1628        rmrkNftId: 'u32',1629        resourceId: 'u32',1630      },1631      set_property: {1632        rmrkCollectionId: 'Compact<u32>',1633        maybeNftId: 'Option<u32>',1634        key: 'Bytes',1635        value: 'Bytes',1636      },1637      set_priority: {1638        rmrkCollectionId: 'u32',1639        rmrkNftId: 'u32',1640        priorities: 'Vec<u32>',1641      },1642      add_basic_resource: {1643        rmrkCollectionId: 'u32',1644        nftId: 'u32',1645        resource: 'RmrkTraitsResourceBasicResource',1646      },1647      add_composable_resource: {1648        rmrkCollectionId: 'u32',1649        nftId: 'u32',1650        resource: 'RmrkTraitsResourceComposableResource',1651      },1652      add_slot_resource: {1653        rmrkCollectionId: 'u32',1654        nftId: 'u32',1655        resource: 'RmrkTraitsResourceSlotResource',1656      },1657      remove_resource: {1658        rmrkCollectionId: 'u32',1659        nftId: 'u32',1660        resourceId: 'u32'1661      }1662    }1663  },1664  /**1665   * Lookup215: rmrk_traits::resource::ResourceTypes<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1666   **/1667  RmrkTraitsResourceResourceTypes: {1668    _enum: {1669      Basic: 'RmrkTraitsResourceBasicResource',1670      Composable: 'RmrkTraitsResourceComposableResource',1671      Slot: 'RmrkTraitsResourceSlotResource'1672    }1673  },1674  /**1675   * Lookup217: rmrk_traits::resource::BasicResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>1676   **/1677  RmrkTraitsResourceBasicResource: {1678    src: 'Option<Bytes>',1679    metadata: 'Option<Bytes>',1680    license: 'Option<Bytes>',1681    thumb: 'Option<Bytes>'1682  },1683  /**1684   * Lookup219: rmrk_traits::resource::ComposableResource<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1685   **/1686  RmrkTraitsResourceComposableResource: {1687    parts: 'Vec<u32>',1688    base: 'u32',1689    src: 'Option<Bytes>',1690    metadata: 'Option<Bytes>',1691    license: 'Option<Bytes>',1692    thumb: 'Option<Bytes>'1693  },1694  /**1695   * Lookup220: rmrk_traits::resource::SlotResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>1696   **/1697  RmrkTraitsResourceSlotResource: {1698    base: 'u32',1699    src: 'Option<Bytes>',1700    metadata: 'Option<Bytes>',1701    slot: 'u32',1702    license: 'Option<Bytes>',1703    thumb: 'Option<Bytes>'1704  },1705  /**1706   * Lookup222: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>1707   **/1708  RmrkTraitsNftAccountIdOrCollectionNftTuple: {1709    _enum: {1710      AccountId: 'AccountId32',1711      CollectionAndNftTuple: '(u32,u32)'1712    }1713  },1714  /**1715   * Lookup226: pallet_rmrk_equip::pallet::Call<T>1716   **/1717  PalletRmrkEquipCall: {1718    _enum: {1719      create_base: {1720        baseType: 'Bytes',1721        symbol: 'Bytes',1722        parts: 'Vec<RmrkTraitsPartPartType>',1723      },1724      theme_add: {1725        baseId: 'u32',1726        theme: 'RmrkTraitsTheme',1727      },1728      equippable: {1729        baseId: 'u32',1730        slotId: 'u32',1731        equippables: 'RmrkTraitsPartEquippableList'1732      }1733    }1734  },1735  /**1736   * Lookup229: rmrk_traits::part::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1737   **/1738  RmrkTraitsPartPartType: {1739    _enum: {1740      FixedPart: 'RmrkTraitsPartFixedPart',1741      SlotPart: 'RmrkTraitsPartSlotPart'1742    }1743  },1744  /**1745   * Lookup231: rmrk_traits::part::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>1746   **/1747  RmrkTraitsPartFixedPart: {1748    id: 'u32',1749    z: 'u32',1750    src: 'Bytes'1751  },1752  /**1753   * Lookup232: rmrk_traits::part::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1754   **/1755  RmrkTraitsPartSlotPart: {1756    id: 'u32',1757    equippable: 'RmrkTraitsPartEquippableList',1758    src: 'Bytes',1759    z: 'u32'1760  },1761  /**1762   * Lookup233: rmrk_traits::part::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>1763   **/1764  RmrkTraitsPartEquippableList: {1765    _enum: {1766      All: 'Null',1767      Empty: 'Null',1768      Custom: 'Vec<u32>'1769    }1770  },1771  /**1772   * Lookup235: rmrk_traits::theme::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>, S>>1773   **/1774  RmrkTraitsTheme: {1775    name: 'Bytes',1776    properties: 'Vec<RmrkTraitsThemeThemeProperty>',1777    inherit: 'bool'1778  },1779  /**1780   * Lookup237: rmrk_traits::theme::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>1781   **/1782  RmrkTraitsThemeThemeProperty: {1783    key: 'Bytes',1784    value: 'Bytes'1785  },1786  /**1787   * Lookup239: pallet_evm::pallet::Call<T>1788   **/1789  PalletEvmCall: {1790    _enum: {1791      withdraw: {1792        address: 'H160',1793        value: 'u128',1794      },1795      call: {1796        source: 'H160',1797        target: 'H160',1798        input: 'Bytes',1799        value: 'U256',1800        gasLimit: 'u64',1801        maxFeePerGas: 'U256',1802        maxPriorityFeePerGas: 'Option<U256>',1803        nonce: 'Option<U256>',1804        accessList: 'Vec<(H160,Vec<H256>)>',1805      },1806      create: {1807        source: 'H160',1808        init: 'Bytes',1809        value: 'U256',1810        gasLimit: 'u64',1811        maxFeePerGas: 'U256',1812        maxPriorityFeePerGas: 'Option<U256>',1813        nonce: 'Option<U256>',1814        accessList: 'Vec<(H160,Vec<H256>)>',1815      },1816      create2: {1817        source: 'H160',1818        init: 'Bytes',1819        salt: 'H256',1820        value: 'U256',1821        gasLimit: 'u64',1822        maxFeePerGas: 'U256',1823        maxPriorityFeePerGas: 'Option<U256>',1824        nonce: 'Option<U256>',1825        accessList: 'Vec<(H160,Vec<H256>)>'1826      }1827    }1828  },1829  /**1830   * Lookup245: pallet_ethereum::pallet::Call<T>1831   **/1832  PalletEthereumCall: {1833    _enum: {1834      transact: {1835        transaction: 'EthereumTransactionTransactionV2'1836      }1837    }1838  },1839  /**1840   * Lookup246: ethereum::transaction::TransactionV21841   **/1842  EthereumTransactionTransactionV2: {1843    _enum: {1844      Legacy: 'EthereumTransactionLegacyTransaction',1845      EIP2930: 'EthereumTransactionEip2930Transaction',1846      EIP1559: 'EthereumTransactionEip1559Transaction'1847    }1848  },1849  /**1850   * Lookup247: ethereum::transaction::LegacyTransaction1851   **/1852  EthereumTransactionLegacyTransaction: {1853    nonce: 'U256',1854    gasPrice: 'U256',1855    gasLimit: 'U256',1856    action: 'EthereumTransactionTransactionAction',1857    value: 'U256',1858    input: 'Bytes',1859    signature: 'EthereumTransactionTransactionSignature'1860  },1861  /**1862   * Lookup248: ethereum::transaction::TransactionAction1863   **/1864  EthereumTransactionTransactionAction: {1865    _enum: {1866      Call: 'H160',1867      Create: 'Null'1868    }1869  },1870  /**1871   * Lookup249: ethereum::transaction::TransactionSignature1872   **/1873  EthereumTransactionTransactionSignature: {1874    v: 'u64',1875    r: 'H256',1876    s: 'H256'1877  },1878  /**1879   * Lookup251: ethereum::transaction::EIP2930Transaction1880   **/1881  EthereumTransactionEip2930Transaction: {1882    chainId: 'u64',1883    nonce: 'U256',1884    gasPrice: 'U256',1885    gasLimit: 'U256',1886    action: 'EthereumTransactionTransactionAction',1887    value: 'U256',1888    input: 'Bytes',1889    accessList: 'Vec<EthereumTransactionAccessListItem>',1890    oddYParity: 'bool',1891    r: 'H256',1892    s: 'H256'1893  },1894  /**1895   * Lookup253: ethereum::transaction::AccessListItem1896   **/1897  EthereumTransactionAccessListItem: {1898    address: 'H160',1899    storageKeys: 'Vec<H256>'1900  },1901  /**1902   * Lookup254: ethereum::transaction::EIP1559Transaction1903   **/1904  EthereumTransactionEip1559Transaction: {1905    chainId: 'u64',1906    nonce: 'U256',1907    maxPriorityFeePerGas: 'U256',1908    maxFeePerGas: 'U256',1909    gasLimit: 'U256',1910    action: 'EthereumTransactionTransactionAction',1911    value: 'U256',1912    input: 'Bytes',1913    accessList: 'Vec<EthereumTransactionAccessListItem>',1914    oddYParity: 'bool',1915    r: 'H256',1916    s: 'H256'1917  },1918  /**1919   * Lookup255: pallet_evm_migration::pallet::Call<T>1920   **/1921  PalletEvmMigrationCall: {1922    _enum: {1923      begin: {1924        address: 'H160',1925      },1926      set_data: {1927        address: 'H160',1928        data: 'Vec<(H256,H256)>',1929      },1930      finish: {1931        address: 'H160',1932        code: 'Bytes'1933      }1934    }1935  },1936  /**1937   * Lookup258: pallet_sudo::pallet::Event<T>1938   **/1939  PalletSudoEvent: {1940    _enum: {1941      Sudid: {1942        sudoResult: 'Result<Null, SpRuntimeDispatchError>',1943      },1944      KeyChanged: {1945        oldSudoer: 'Option<AccountId32>',1946      },1947      SudoAsDone: {1948        sudoResult: 'Result<Null, SpRuntimeDispatchError>'1949      }1950    }1951  },1952  /**1953   * Lookup260: sp_runtime::DispatchError1954   **/1955  SpRuntimeDispatchError: {1956    _enum: {1957      Other: 'Null',1958      CannotLookup: 'Null',1959      BadOrigin: 'Null',1960      Module: 'SpRuntimeModuleError',1961      ConsumerRemaining: 'Null',1962      NoProviders: 'Null',1963      TooManyConsumers: 'Null',1964      Token: 'SpRuntimeTokenError',1965      Arithmetic: 'SpRuntimeArithmeticError',1966      Transactional: 'SpRuntimeTransactionalError'1967    }1968  },1969  /**1970   * Lookup261: sp_runtime::ModuleError1971   **/1972  SpRuntimeModuleError: {1973    index: 'u8',1974    error: '[u8;4]'1975  },1976  /**1977   * Lookup262: sp_runtime::TokenError1978   **/1979  SpRuntimeTokenError: {1980    _enum: ['NoFunds', 'WouldDie', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported']1981  },1982  /**1983   * Lookup263: sp_runtime::ArithmeticError1984   **/1985  SpRuntimeArithmeticError: {1986    _enum: ['Underflow', 'Overflow', 'DivisionByZero']1987  },1988  /**1989   * Lookup264: sp_runtime::TransactionalError1990   **/1991  SpRuntimeTransactionalError: {1992    _enum: ['LimitReached', 'NoLayer']1993  },1994  /**1995   * Lookup265: pallet_sudo::pallet::Error<T>1996   **/1997  PalletSudoError: {1998    _enum: ['RequireSudo']1999  },2000  /**2001   * Lookup266: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>2002   **/2003  FrameSystemAccountInfo: {2004    nonce: 'u32',2005    consumers: 'u32',2006    providers: 'u32',2007    sufficients: 'u32',2008    data: 'PalletBalancesAccountData'2009  },2010  /**2011   * Lookup267: frame_support::weights::PerDispatchClass<T>2012   **/2013  FrameSupportWeightsPerDispatchClassU64: {2014    normal: 'u64',2015    operational: 'u64',2016    mandatory: 'u64'2017  },2018  /**2019   * Lookup268: sp_runtime::generic::digest::Digest2020   **/2021  SpRuntimeDigest: {2022    logs: 'Vec<SpRuntimeDigestDigestItem>'2023  },2024  /**2025   * Lookup270: sp_runtime::generic::digest::DigestItem2026   **/2027  SpRuntimeDigestDigestItem: {2028    _enum: {2029      Other: 'Bytes',2030      __Unused1: 'Null',2031      __Unused2: 'Null',2032      __Unused3: 'Null',2033      Consensus: '([u8;4],Bytes)',2034      Seal: '([u8;4],Bytes)',2035      PreRuntime: '([u8;4],Bytes)',2036      __Unused7: 'Null',2037      RuntimeEnvironmentUpdated: 'Null'2038    }2039  },2040  /**2041   * Lookup272: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>2042   **/2043  FrameSystemEventRecord: {2044    phase: 'FrameSystemPhase',2045    event: 'Event',2046    topics: 'Vec<H256>'2047  },2048  /**2049   * Lookup274: frame_system::pallet::Event<T>2050   **/2051  FrameSystemEvent: {2052    _enum: {2053      ExtrinsicSuccess: {2054        dispatchInfo: 'FrameSupportWeightsDispatchInfo',2055      },2056      ExtrinsicFailed: {2057        dispatchError: 'SpRuntimeDispatchError',2058        dispatchInfo: 'FrameSupportWeightsDispatchInfo',2059      },2060      CodeUpdated: 'Null',2061      NewAccount: {2062        account: 'AccountId32',2063      },2064      KilledAccount: {2065        account: 'AccountId32',2066      },2067      Remarked: {2068        _alias: {2069          hash_: 'hash',2070        },2071        sender: 'AccountId32',2072        hash_: 'H256'2073      }2074    }2075  },2076  /**2077   * Lookup275: frame_support::weights::DispatchInfo2078   **/2079  FrameSupportWeightsDispatchInfo: {2080    weight: 'u64',2081    class: 'FrameSupportWeightsDispatchClass',2082    paysFee: 'FrameSupportWeightsPays'2083  },2084  /**2085   * Lookup276: frame_support::weights::DispatchClass2086   **/2087  FrameSupportWeightsDispatchClass: {2088    _enum: ['Normal', 'Operational', 'Mandatory']2089  },2090  /**2091   * Lookup277: frame_support::weights::Pays2092   **/2093  FrameSupportWeightsPays: {2094    _enum: ['Yes', 'No']2095  },2096  /**2097   * Lookup278: orml_vesting::module::Event<T>2098   **/2099  OrmlVestingModuleEvent: {2100    _enum: {2101      VestingScheduleAdded: {2102        from: 'AccountId32',2103        to: 'AccountId32',2104        vestingSchedule: 'OrmlVestingVestingSchedule',2105      },2106      Claimed: {2107        who: 'AccountId32',2108        amount: 'u128',2109      },2110      VestingSchedulesUpdated: {2111        who: 'AccountId32'2112      }2113    }2114  },2115  /**2116   * Lookup279: cumulus_pallet_xcmp_queue::pallet::Event<T>2117   **/2118  CumulusPalletXcmpQueueEvent: {2119    _enum: {2120      Success: 'Option<H256>',2121      Fail: '(Option<H256>,XcmV2TraitsError)',2122      BadVersion: 'Option<H256>',2123      BadFormat: 'Option<H256>',2124      UpwardMessageSent: 'Option<H256>',2125      XcmpMessageSent: 'Option<H256>',2126      OverweightEnqueued: '(u32,u32,u64,u64)',2127      OverweightServiced: '(u64,u64)'2128    }2129  },2130  /**2131   * Lookup280: pallet_xcm::pallet::Event<T>2132   **/2133  PalletXcmEvent: {2134    _enum: {2135      Attempted: 'XcmV2TraitsOutcome',2136      Sent: '(XcmV1MultiLocation,XcmV1MultiLocation,XcmV2Xcm)',2137      UnexpectedResponse: '(XcmV1MultiLocation,u64)',2138      ResponseReady: '(u64,XcmV2Response)',2139      Notified: '(u64,u8,u8)',2140      NotifyOverweight: '(u64,u8,u8,u64,u64)',2141      NotifyDispatchError: '(u64,u8,u8)',2142      NotifyDecodeFailed: '(u64,u8,u8)',2143      InvalidResponder: '(XcmV1MultiLocation,u64,Option<XcmV1MultiLocation>)',2144      InvalidResponderVersion: '(XcmV1MultiLocation,u64)',2145      ResponseTaken: 'u64',2146      AssetsTrapped: '(H256,XcmV1MultiLocation,XcmVersionedMultiAssets)',2147      VersionChangeNotified: '(XcmV1MultiLocation,u32)',2148      SupportedVersionChanged: '(XcmV1MultiLocation,u32)',2149      NotifyTargetSendFail: '(XcmV1MultiLocation,u64,XcmV2TraitsError)',2150      NotifyTargetMigrationFail: '(XcmVersionedMultiLocation,u64)'2151    }2152  },2153  /**2154   * Lookup281: xcm::v2::traits::Outcome2155   **/2156  XcmV2TraitsOutcome: {2157    _enum: {2158      Complete: 'u64',2159      Incomplete: '(u64,XcmV2TraitsError)',2160      Error: 'XcmV2TraitsError'2161    }2162  },2163  /**2164   * Lookup283: cumulus_pallet_xcm::pallet::Event<T>2165   **/2166  CumulusPalletXcmEvent: {2167    _enum: {2168      InvalidFormat: '[u8;8]',2169      UnsupportedVersion: '[u8;8]',2170      ExecutedDownward: '([u8;8],XcmV2TraitsOutcome)'2171    }2172  },2173  /**2174   * Lookup284: cumulus_pallet_dmp_queue::pallet::Event<T>2175   **/2176  CumulusPalletDmpQueueEvent: {2177    _enum: {2178      InvalidFormat: {2179        messageId: '[u8;32]',2180      },2181      UnsupportedVersion: {2182        messageId: '[u8;32]',2183      },2184      ExecutedDownward: {2185        messageId: '[u8;32]',2186        outcome: 'XcmV2TraitsOutcome',2187      },2188      WeightExhausted: {2189        messageId: '[u8;32]',2190        remainingWeight: 'u64',2191        requiredWeight: 'u64',2192      },2193      OverweightEnqueued: {2194        messageId: '[u8;32]',2195        overweightIndex: 'u64',2196        requiredWeight: 'u64',2197      },2198      OverweightServiced: {2199        overweightIndex: 'u64',2200        weightUsed: 'u64'2201      }2202    }2203  },2204  /**2205   * Lookup285: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2206   **/2207  PalletUniqueRawEvent: {2208    _enum: {2209      CollectionSponsorRemoved: 'u32',2210      CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2211      CollectionOwnedChanged: '(u32,AccountId32)',2212      CollectionSponsorSet: '(u32,AccountId32)',2213      SponsorshipConfirmed: '(u32,AccountId32)',2214      CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2215      AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2216      AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2217      CollectionLimitSet: 'u32',2218      CollectionPermissionSet: 'u32'2219    }2220  },2221  /**2222   * Lookup286: pallet_unique_scheduler::pallet::Event<T>2223   **/2224  PalletUniqueSchedulerEvent: {2225    _enum: {2226      Scheduled: {2227        when: 'u32',2228        index: 'u32',2229      },2230      Canceled: {2231        when: 'u32',2232        index: 'u32',2233      },2234      Dispatched: {2235        task: '(u32,u32)',2236        id: 'Option<[u8;16]>',2237        result: 'Result<Null, SpRuntimeDispatchError>',2238      },2239      CallLookupFailed: {2240        task: '(u32,u32)',2241        id: 'Option<[u8;16]>',2242        error: 'FrameSupportScheduleLookupError'2243      }2244    }2245  },2246  /**2247   * Lookup288: frame_support::traits::schedule::LookupError2248   **/2249  FrameSupportScheduleLookupError: {2250    _enum: ['Unknown', 'BadFormat']2251  },2252  /**2253   * Lookup289: pallet_common::pallet::Event<T>2254   **/2255  PalletCommonEvent: {2256    _enum: {2257      CollectionCreated: '(u32,u8,AccountId32)',2258      CollectionDestroyed: 'u32',2259      ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2260      ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2261      Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2262      Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2263      CollectionPropertySet: '(u32,Bytes)',2264      CollectionPropertyDeleted: '(u32,Bytes)',2265      TokenPropertySet: '(u32,u32,Bytes)',2266      TokenPropertyDeleted: '(u32,u32,Bytes)',2267      PropertyPermissionSet: '(u32,Bytes)'2268    }2269  },2270  /**2271   * Lookup290: pallet_structure::pallet::Event<T>2272   **/2273  PalletStructureEvent: {2274    _enum: {2275      Executed: 'Result<Null, SpRuntimeDispatchError>'2276    }2277  },2278  /**2279   * Lookup291: pallet_rmrk_core::pallet::Event<T>2280   **/2281  PalletRmrkCoreEvent: {2282    _enum: {2283      CollectionCreated: {2284        issuer: 'AccountId32',2285        collectionId: 'u32',2286      },2287      CollectionDestroyed: {2288        issuer: 'AccountId32',2289        collectionId: 'u32',2290      },2291      IssuerChanged: {2292        oldIssuer: 'AccountId32',2293        newIssuer: 'AccountId32',2294        collectionId: 'u32',2295      },2296      CollectionLocked: {2297        issuer: 'AccountId32',2298        collectionId: 'u32',2299      },2300      NftMinted: {2301        owner: 'AccountId32',2302        collectionId: 'u32',2303        nftId: 'u32',2304      },2305      NFTBurned: {2306        owner: 'AccountId32',2307        nftId: 'u32',2308      },2309      NFTSent: {2310        sender: 'AccountId32',2311        recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2312        collectionId: 'u32',2313        nftId: 'u32',2314        approvalRequired: 'bool',2315      },2316      NFTAccepted: {2317        sender: 'AccountId32',2318        recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2319        collectionId: 'u32',2320        nftId: 'u32',2321      },2322      NFTRejected: {2323        sender: 'AccountId32',2324        collectionId: 'u32',2325        nftId: 'u32',2326      },2327      PropertySet: {2328        collectionId: 'u32',2329        maybeNftId: 'Option<u32>',2330        key: 'Bytes',2331        value: 'Bytes',2332      },2333      ResourceAdded: {2334        nftId: 'u32',2335        resourceId: 'u32',2336      },2337      ResourceRemoval: {2338        nftId: 'u32',2339        resourceId: 'u32',2340      },2341      ResourceAccepted: {2342        nftId: 'u32',2343        resourceId: 'u32',2344      },2345      ResourceRemovalAccepted: {2346        nftId: 'u32',2347        resourceId: 'u32',2348      },2349      PrioritySet: {2350        collectionId: 'u32',2351        nftId: 'u32'2352      }2353    }2354  },2355  /**2356   * Lookup292: pallet_rmrk_equip::pallet::Event<T>2357   **/2358  PalletRmrkEquipEvent: {2359    _enum: {2360      BaseCreated: {2361        issuer: 'AccountId32',2362        baseId: 'u32',2363      },2364      EquippablesUpdated: {2365        baseId: 'u32',2366        slotId: 'u32'2367      }2368    }2369  },2370  /**2371   * Lookup293: pallet_evm::pallet::Event<T>2372   **/2373  PalletEvmEvent: {2374    _enum: {2375      Log: 'EthereumLog',2376      Created: 'H160',2377      CreatedFailed: 'H160',2378      Executed: 'H160',2379      ExecutedFailed: 'H160',2380      BalanceDeposit: '(AccountId32,H160,U256)',2381      BalanceWithdraw: '(AccountId32,H160,U256)'2382    }2383  },2384  /**2385   * Lookup294: ethereum::log::Log2386   **/2387  EthereumLog: {2388    address: 'H160',2389    topics: 'Vec<H256>',2390    data: 'Bytes'2391  },2392  /**2393   * Lookup295: pallet_ethereum::pallet::Event2394   **/2395  PalletEthereumEvent: {2396    _enum: {2397      Executed: '(H160,H160,H256,EvmCoreErrorExitReason)'2398    }2399  },2400  /**2401   * Lookup296: evm_core::error::ExitReason2402   **/2403  EvmCoreErrorExitReason: {2404    _enum: {2405      Succeed: 'EvmCoreErrorExitSucceed',2406      Error: 'EvmCoreErrorExitError',2407      Revert: 'EvmCoreErrorExitRevert',2408      Fatal: 'EvmCoreErrorExitFatal'2409    }2410  },2411  /**2412   * Lookup297: evm_core::error::ExitSucceed2413   **/2414  EvmCoreErrorExitSucceed: {2415    _enum: ['Stopped', 'Returned', 'Suicided']2416  },2417  /**2418   * Lookup298: evm_core::error::ExitError2419   **/2420  EvmCoreErrorExitError: {2421    _enum: {2422      StackUnderflow: 'Null',2423      StackOverflow: 'Null',2424      InvalidJump: 'Null',2425      InvalidRange: 'Null',2426      DesignatedInvalid: 'Null',2427      CallTooDeep: 'Null',2428      CreateCollision: 'Null',2429      CreateContractLimit: 'Null',2430      OutOfOffset: 'Null',2431      OutOfGas: 'Null',2432      OutOfFund: 'Null',2433      PCUnderflow: 'Null',2434      CreateEmpty: 'Null',2435      Other: 'Text',2436      InvalidCode: 'Null'2437    }2438  },2439  /**2440   * Lookup301: evm_core::error::ExitRevert2441   **/2442  EvmCoreErrorExitRevert: {2443    _enum: ['Reverted']2444  },2445  /**2446   * Lookup302: evm_core::error::ExitFatal2447   **/2448  EvmCoreErrorExitFatal: {2449    _enum: {2450      NotSupported: 'Null',2451      UnhandledInterrupt: 'Null',2452      CallErrorAsFatal: 'EvmCoreErrorExitError',2453      Other: 'Text'2454    }2455  },2456  /**2457   * Lookup303: frame_system::Phase2458   **/2459  FrameSystemPhase: {2460    _enum: {2461      ApplyExtrinsic: 'u32',2462      Finalization: 'Null',2463      Initialization: 'Null'2464    }2465  },2466  /**2467   * Lookup305: frame_system::LastRuntimeUpgradeInfo2468   **/2469  FrameSystemLastRuntimeUpgradeInfo: {2470    specVersion: 'Compact<u32>',2471    specName: 'Text'2472  },2473  /**2474   * Lookup306: frame_system::limits::BlockWeights2475   **/2476  FrameSystemLimitsBlockWeights: {2477    baseBlock: 'u64',2478    maxBlock: 'u64',2479    perClass: 'FrameSupportWeightsPerDispatchClassWeightsPerClass'2480  },2481  /**2482   * Lookup307: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>2483   **/2484  FrameSupportWeightsPerDispatchClassWeightsPerClass: {2485    normal: 'FrameSystemLimitsWeightsPerClass',2486    operational: 'FrameSystemLimitsWeightsPerClass',2487    mandatory: 'FrameSystemLimitsWeightsPerClass'2488  },2489  /**2490   * Lookup308: frame_system::limits::WeightsPerClass2491   **/2492  FrameSystemLimitsWeightsPerClass: {2493    baseExtrinsic: 'u64',2494    maxExtrinsic: 'Option<u64>',2495    maxTotal: 'Option<u64>',2496    reserved: 'Option<u64>'2497  },2498  /**2499   * Lookup310: frame_system::limits::BlockLength2500   **/2501  FrameSystemLimitsBlockLength: {2502    max: 'FrameSupportWeightsPerDispatchClassU32'2503  },2504  /**2505   * Lookup311: frame_support::weights::PerDispatchClass<T>2506   **/2507  FrameSupportWeightsPerDispatchClassU32: {2508    normal: 'u32',2509    operational: 'u32',2510    mandatory: 'u32'2511  },2512  /**2513   * Lookup312: frame_support::weights::RuntimeDbWeight2514   **/2515  FrameSupportWeightsRuntimeDbWeight: {2516    read: 'u64',2517    write: 'u64'2518  },2519  /**2520   * Lookup313: sp_version::RuntimeVersion2521   **/2522  SpVersionRuntimeVersion: {2523    specName: 'Text',2524    implName: 'Text',2525    authoringVersion: 'u32',2526    specVersion: 'u32',2527    implVersion: 'u32',2528    apis: 'Vec<([u8;8],u32)>',2529    transactionVersion: 'u32',2530    stateVersion: 'u8'2531  },2532  /**2533   * Lookup317: frame_system::pallet::Error<T>2534   **/2535  FrameSystemError: {2536    _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']2537  },2538  /**2539   * Lookup319: orml_vesting::module::Error<T>2540   **/2541  OrmlVestingModuleError: {2542    _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']2543  },2544  /**2545   * Lookup321: cumulus_pallet_xcmp_queue::InboundChannelDetails2546   **/2547  CumulusPalletXcmpQueueInboundChannelDetails: {2548    sender: 'u32',2549    state: 'CumulusPalletXcmpQueueInboundState',2550    messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'2551  },2552  /**2553   * Lookup322: cumulus_pallet_xcmp_queue::InboundState2554   **/2555  CumulusPalletXcmpQueueInboundState: {2556    _enum: ['Ok', 'Suspended']2557  },2558  /**2559   * Lookup325: polkadot_parachain::primitives::XcmpMessageFormat2560   **/2561  PolkadotParachainPrimitivesXcmpMessageFormat: {2562    _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']2563  },2564  /**2565   * Lookup328: cumulus_pallet_xcmp_queue::OutboundChannelDetails2566   **/2567  CumulusPalletXcmpQueueOutboundChannelDetails: {2568    recipient: 'u32',2569    state: 'CumulusPalletXcmpQueueOutboundState',2570    signalsExist: 'bool',2571    firstIndex: 'u16',2572    lastIndex: 'u16'2573  },2574  /**2575   * Lookup329: cumulus_pallet_xcmp_queue::OutboundState2576   **/2577  CumulusPalletXcmpQueueOutboundState: {2578    _enum: ['Ok', 'Suspended']2579  },2580  /**2581   * Lookup331: cumulus_pallet_xcmp_queue::QueueConfigData2582   **/2583  CumulusPalletXcmpQueueQueueConfigData: {2584    suspendThreshold: 'u32',2585    dropThreshold: 'u32',2586    resumeThreshold: 'u32',2587    thresholdWeight: 'u64',2588    weightRestrictDecay: 'u64',2589    xcmpMaxIndividualWeight: 'u64'2590  },2591  /**2592   * Lookup333: cumulus_pallet_xcmp_queue::pallet::Error<T>2593   **/2594  CumulusPalletXcmpQueueError: {2595    _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']2596  },2597  /**2598   * Lookup334: pallet_xcm::pallet::Error<T>2599   **/2600  PalletXcmError: {2601    _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']2602  },2603  /**2604   * Lookup335: cumulus_pallet_xcm::pallet::Error<T>2605   **/2606  CumulusPalletXcmError: 'Null',2607  /**2608   * Lookup336: cumulus_pallet_dmp_queue::ConfigData2609   **/2610  CumulusPalletDmpQueueConfigData: {2611    maxIndividual: 'u64'2612  },2613  /**2614   * Lookup337: cumulus_pallet_dmp_queue::PageIndexData2615   **/2616  CumulusPalletDmpQueuePageIndexData: {2617    beginUsed: 'u32',2618    endUsed: 'u32',2619    overweightCount: 'u64'2620  },2621  /**2622   * Lookup340: cumulus_pallet_dmp_queue::pallet::Error<T>2623   **/2624  CumulusPalletDmpQueueError: {2625    _enum: ['Unknown', 'OverLimit']2626  },2627  /**2628   * Lookup344: pallet_unique::Error<T>2629   **/2630  PalletUniqueError: {2631    _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']2632  },2633  /**2634   * Lookup347: pallet_unique_scheduler::ScheduledV3<frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>2635   **/2636  PalletUniqueSchedulerScheduledV3: {2637    maybeId: 'Option<[u8;16]>',2638    priority: 'u8',2639    call: 'FrameSupportScheduleMaybeHashed',2640    maybePeriodic: 'Option<(u32,u32)>',2641    origin: 'OpalRuntimeOriginCaller'2642  },2643  /**2644   * Lookup348: opal_runtime::OriginCaller2645   **/2646  OpalRuntimeOriginCaller: {2647    _enum: {2648      __Unused0: 'Null',2649      __Unused1: 'Null',2650      __Unused2: 'Null',2651      __Unused3: 'Null',2652      Void: 'SpCoreVoid',2653      __Unused5: 'Null',2654      __Unused6: 'Null',2655      __Unused7: 'Null',2656      __Unused8: 'Null',2657      __Unused9: 'Null',2658      __Unused10: 'Null',2659      __Unused11: 'Null',2660      __Unused12: 'Null',2661      __Unused13: 'Null',2662      __Unused14: 'Null',2663      __Unused15: 'Null',2664      __Unused16: 'Null',2665      __Unused17: 'Null',2666      __Unused18: 'Null',2667      __Unused19: 'Null',2668      __Unused20: 'Null',2669      __Unused21: 'Null',2670      __Unused22: 'Null',2671      __Unused23: 'Null',2672      __Unused24: 'Null',2673      __Unused25: 'Null',2674      __Unused26: 'Null',2675      __Unused27: 'Null',2676      __Unused28: 'Null',2677      __Unused29: 'Null',2678      __Unused30: 'Null',2679      __Unused31: 'Null',2680      __Unused32: 'Null',2681      __Unused33: 'Null',2682      __Unused34: 'Null',2683      __Unused35: 'Null',2684      system: 'FrameSupportDispatchRawOrigin',2685      __Unused37: 'Null',2686      __Unused38: 'Null',2687      __Unused39: 'Null',2688      __Unused40: 'Null',2689      __Unused41: 'Null',2690      __Unused42: 'Null',2691      __Unused43: 'Null',2692      __Unused44: 'Null',2693      __Unused45: 'Null',2694      __Unused46: 'Null',2695      __Unused47: 'Null',2696      __Unused48: 'Null',2697      __Unused49: 'Null',2698      __Unused50: 'Null',2699      PolkadotXcm: 'PalletXcmOrigin',2700      CumulusXcm: 'CumulusPalletXcmOrigin',2701      __Unused53: 'Null',2702      __Unused54: 'Null',2703      __Unused55: 'Null',2704      __Unused56: 'Null',2705      __Unused57: 'Null',2706      __Unused58: 'Null',2707      __Unused59: 'Null',2708      __Unused60: 'Null',2709      __Unused61: 'Null',2710      __Unused62: 'Null',2711      __Unused63: 'Null',2712      __Unused64: 'Null',2713      __Unused65: 'Null',2714      __Unused66: 'Null',2715      __Unused67: 'Null',2716      __Unused68: 'Null',2717      __Unused69: 'Null',2718      __Unused70: 'Null',2719      __Unused71: 'Null',2720      __Unused72: 'Null',2721      __Unused73: 'Null',2722      __Unused74: 'Null',2723      __Unused75: 'Null',2724      __Unused76: 'Null',2725      __Unused77: 'Null',2726      __Unused78: 'Null',2727      __Unused79: 'Null',2728      __Unused80: 'Null',2729      __Unused81: 'Null',2730      __Unused82: 'Null',2731      __Unused83: 'Null',2732      __Unused84: 'Null',2733      __Unused85: 'Null',2734      __Unused86: 'Null',2735      __Unused87: 'Null',2736      __Unused88: 'Null',2737      __Unused89: 'Null',2738      __Unused90: 'Null',2739      __Unused91: 'Null',2740      __Unused92: 'Null',2741      __Unused93: 'Null',2742      __Unused94: 'Null',2743      __Unused95: 'Null',2744      __Unused96: 'Null',2745      __Unused97: 'Null',2746      __Unused98: 'Null',2747      __Unused99: 'Null',2748      __Unused100: 'Null',2749      Ethereum: 'PalletEthereumRawOrigin'2750    }2751  },2752  /**2753   * Lookup349: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>2754   **/2755  FrameSupportDispatchRawOrigin: {2756    _enum: {2757      Root: 'Null',2758      Signed: 'AccountId32',2759      None: 'Null'2760    }2761  },2762  /**2763   * Lookup350: pallet_xcm::pallet::Origin2764   **/2765  PalletXcmOrigin: {2766    _enum: {2767      Xcm: 'XcmV1MultiLocation',2768      Response: 'XcmV1MultiLocation'2769    }2770  },2771  /**2772   * Lookup351: cumulus_pallet_xcm::pallet::Origin2773   **/2774  CumulusPalletXcmOrigin: {2775    _enum: {2776      Relay: 'Null',2777      SiblingParachain: 'u32'2778    }2779  },2780  /**2781   * Lookup352: pallet_ethereum::RawOrigin2782   **/2783  PalletEthereumRawOrigin: {2784    _enum: {2785      EthereumTransaction: 'H160'2786    }2787  },2788  /**2789   * Lookup353: sp_core::Void2790   **/2791  SpCoreVoid: 'Null',2792  /**2793   * Lookup354: pallet_unique_scheduler::pallet::Error<T>2794   **/2795  PalletUniqueSchedulerError: {2796    _enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange']2797  },2798  /**2799   * Lookup355: up_data_structs::Collection<sp_core::crypto::AccountId32>2800   **/2801  UpDataStructsCollection: {2802    owner: 'AccountId32',2803    mode: 'UpDataStructsCollectionMode',2804    name: 'Vec<u16>',2805    description: 'Vec<u16>',2806    tokenPrefix: 'Bytes',2807    sponsorship: 'UpDataStructsSponsorshipState',2808    limits: 'UpDataStructsCollectionLimits',2809    permissions: 'UpDataStructsCollectionPermissions',2810    externalCollection: 'bool'2811  },2812  /**2813   * Lookup356: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>2814   **/2815  UpDataStructsSponsorshipState: {2816    _enum: {2817      Disabled: 'Null',2818      Unconfirmed: 'AccountId32',2819      Confirmed: 'AccountId32'2820    }2821  },2822  /**2823   * Lookup357: up_data_structs::Properties2824   **/2825  UpDataStructsProperties: {2826    map: 'UpDataStructsPropertiesMapBoundedVec',2827    consumedSpace: 'u32',2828    spaceLimit: 'u32'2829  },2830  /**2831   * Lookup358: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>2832   **/2833  UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',2834  /**2835   * Lookup363: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>2836   **/2837  UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',2838  /**2839   * Lookup370: up_data_structs::CollectionStats2840   **/2841  UpDataStructsCollectionStats: {2842    created: 'u32',2843    destroyed: 'u32',2844    alive: 'u32'2845  },2846  /**2847   * Lookup371: up_data_structs::TokenChild2848   **/2849  UpDataStructsTokenChild: {2850    token: 'u32',2851    collection: 'u32'2852  },2853  /**2854   * Lookup372: PhantomType::up_data_structs<T>2855   **/2856  PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',2857  /**2858   * Lookup374: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2859   **/2860  UpDataStructsTokenData: {2861    properties: 'Vec<UpDataStructsProperty>',2862    owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',2863    pieces: 'u128'2864  },2865  /**2866   * Lookup376: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>2867   **/2868  UpDataStructsRpcCollection: {2869    owner: 'AccountId32',2870    mode: 'UpDataStructsCollectionMode',2871    name: 'Vec<u16>',2872    description: 'Vec<u16>',2873    tokenPrefix: 'Bytes',2874    sponsorship: 'UpDataStructsSponsorshipState',2875    limits: 'UpDataStructsCollectionLimits',2876    permissions: 'UpDataStructsCollectionPermissions',2877    tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',2878    properties: 'Vec<UpDataStructsProperty>',2879    readOnly: 'bool'2880  },2881  /**2882   * Lookup377: rmrk_traits::collection::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>2883   **/2884  RmrkTraitsCollectionCollectionInfo: {2885    issuer: 'AccountId32',2886    metadata: 'Bytes',2887    max: 'Option<u32>',2888    symbol: 'Bytes',2889    nftsCount: 'u32'2890  },2891  /**2892   * Lookup378: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>2893   **/2894  RmrkTraitsNftNftInfo: {2895    owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2896    royalty: 'Option<RmrkTraitsNftRoyaltyInfo>',2897    metadata: 'Bytes',2898    equipped: 'bool',2899    pending: 'bool'2900  },2901  /**2902   * Lookup380: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>2903   **/2904  RmrkTraitsNftRoyaltyInfo: {2905    recipient: 'AccountId32',2906    amount: 'Permill'2907  },2908  /**2909   * Lookup381: rmrk_traits::resource::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>2910   **/2911  RmrkTraitsResourceResourceInfo: {2912    id: 'u32',2913    resource: 'RmrkTraitsResourceResourceTypes',2914    pending: 'bool',2915    pendingRemoval: 'bool'2916  },2917  /**2918   * Lookup382: rmrk_traits::property::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>2919   **/2920  RmrkTraitsPropertyPropertyInfo: {2921    key: 'Bytes',2922    value: 'Bytes'2923  },2924  /**2925   * Lookup383: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>2926   **/2927  RmrkTraitsBaseBaseInfo: {2928    issuer: 'AccountId32',2929    baseType: 'Bytes',2930    symbol: 'Bytes'2931  },2932  /**2933   * Lookup384: rmrk_traits::nft::NftChild2934   **/2935  RmrkTraitsNftNftChild: {2936    collectionId: 'u32',2937    nftId: 'u32'2938  },2939  /**2940   * Lookup386: pallet_common::pallet::Error<T>2941   **/2942  PalletCommonError: {2943    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal']2944  },2945  /**2946   * Lookup388: pallet_fungible::pallet::Error<T>2947   **/2948  PalletFungibleError: {2949    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']2950  },2951  /**2952   * Lookup389: pallet_refungible::ItemData2953   **/2954  PalletRefungibleItemData: {2955    constData: 'Bytes'2956  },2957  /**2958   * Lookup393: pallet_refungible::pallet::Error<T>2959   **/2960  PalletRefungibleError: {2961    _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']2962  },2963  /**2964   * Lookup394: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2965   **/2966  PalletNonfungibleItemData: {2967    owner: 'PalletEvmAccountBasicCrossAccountIdRepr'2968  },2969  /**2970   * Lookup396: up_data_structs::PropertyScope2971   **/2972  UpDataStructsPropertyScope: {2973    _enum: ['None', 'Rmrk']2974  },2975  /**2976   * Lookup398: pallet_nonfungible::pallet::Error<T>2977   **/2978  PalletNonfungibleError: {2979    _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']2980  },2981  /**2982   * Lookup399: pallet_structure::pallet::Error<T>2983   **/2984  PalletStructureError: {2985    _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']2986  },2987  /**2988   * Lookup400: pallet_rmrk_core::pallet::Error<T>2989   **/2990  PalletRmrkCoreError: {2991    _enum: ['CorruptedCollectionType', 'NftTypeEncodeError', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId']2992  },2993  /**2994   * Lookup402: pallet_rmrk_equip::pallet::Error<T>2995   **/2996  PalletRmrkEquipError: {2997    _enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']2998  },2999  /**3000   * Lookup405: pallet_evm::pallet::Error<T>3001   **/3002  PalletEvmError: {3003    _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']3004  },3005  /**3006   * Lookup408: fp_rpc::TransactionStatus3007   **/3008  FpRpcTransactionStatus: {3009    transactionHash: 'H256',3010    transactionIndex: 'u32',3011    from: 'H160',3012    to: 'Option<H160>',3013    contractAddress: 'Option<H160>',3014    logs: 'Vec<EthereumLog>',3015    logsBloom: 'EthbloomBloom'3016  },3017  /**3018   * Lookup410: ethbloom::Bloom3019   **/3020  EthbloomBloom: '[u8;256]',3021  /**3022   * Lookup412: ethereum::receipt::ReceiptV33023   **/3024  EthereumReceiptReceiptV3: {3025    _enum: {3026      Legacy: 'EthereumReceiptEip658ReceiptData',3027      EIP2930: 'EthereumReceiptEip658ReceiptData',3028      EIP1559: 'EthereumReceiptEip658ReceiptData'3029    }3030  },3031  /**3032   * Lookup413: ethereum::receipt::EIP658ReceiptData3033   **/3034  EthereumReceiptEip658ReceiptData: {3035    statusCode: 'u8',3036    usedGas: 'U256',3037    logsBloom: 'EthbloomBloom',3038    logs: 'Vec<EthereumLog>'3039  },3040  /**3041   * Lookup414: ethereum::block::Block<ethereum::transaction::TransactionV2>3042   **/3043  EthereumBlock: {3044    header: 'EthereumHeader',3045    transactions: 'Vec<EthereumTransactionTransactionV2>',3046    ommers: 'Vec<EthereumHeader>'3047  },3048  /**3049   * Lookup415: ethereum::header::Header3050   **/3051  EthereumHeader: {3052    parentHash: 'H256',3053    ommersHash: 'H256',3054    beneficiary: 'H160',3055    stateRoot: 'H256',3056    transactionsRoot: 'H256',3057    receiptsRoot: 'H256',3058    logsBloom: 'EthbloomBloom',3059    difficulty: 'U256',3060    number: 'U256',3061    gasLimit: 'U256',3062    gasUsed: 'U256',3063    timestamp: 'u64',3064    extraData: 'Bytes',3065    mixHash: 'H256',3066    nonce: 'EthereumTypesHashH64'3067  },3068  /**3069   * Lookup416: ethereum_types::hash::H643070   **/3071  EthereumTypesHashH64: '[u8;8]',3072  /**3073   * Lookup421: pallet_ethereum::pallet::Error<T>3074   **/3075  PalletEthereumError: {3076    _enum: ['InvalidSignature', 'PreLogExists']3077  },3078  /**3079   * Lookup422: pallet_evm_coder_substrate::pallet::Error<T>3080   **/3081  PalletEvmCoderSubstrateError: {3082    _enum: ['OutOfGas', 'OutOfFund']3083  },3084  /**3085   * Lookup423: pallet_evm_contract_helpers::SponsoringModeT3086   **/3087  PalletEvmContractHelpersSponsoringModeT: {3088    _enum: ['Disabled', 'Allowlisted', 'Generous']3089  },3090  /**3091   * Lookup425: pallet_evm_contract_helpers::pallet::Error<T>3092   **/3093  PalletEvmContractHelpersError: {3094    _enum: ['NoPermission']3095  },3096  /**3097   * Lookup426: pallet_evm_migration::pallet::Error<T>3098   **/3099  PalletEvmMigrationError: {3100    _enum: ['AccountNotEmpty', 'AccountIsNotMigrating']3101  },3102  /**3103   * Lookup428: sp_runtime::MultiSignature3104   **/3105  SpRuntimeMultiSignature: {3106    _enum: {3107      Ed25519: 'SpCoreEd25519Signature',3108      Sr25519: 'SpCoreSr25519Signature',3109      Ecdsa: 'SpCoreEcdsaSignature'3110    }3111  },3112  /**3113   * Lookup429: sp_core::ed25519::Signature3114   **/3115  SpCoreEd25519Signature: '[u8;64]',3116  /**3117   * Lookup431: sp_core::sr25519::Signature3118   **/3119  SpCoreSr25519Signature: '[u8;64]',3120  /**3121   * Lookup432: sp_core::ecdsa::Signature3122   **/3123  SpCoreEcdsaSignature: '[u8;65]',3124  /**3125   * Lookup435: frame_system::extensions::check_spec_version::CheckSpecVersion<T>3126   **/3127  FrameSystemExtensionsCheckSpecVersion: 'Null',3128  /**3129   * Lookup436: frame_system::extensions::check_genesis::CheckGenesis<T>3130   **/3131  FrameSystemExtensionsCheckGenesis: 'Null',3132  /**3133   * Lookup439: frame_system::extensions::check_nonce::CheckNonce<T>3134   **/3135  FrameSystemExtensionsCheckNonce: 'Compact<u32>',3136  /**3137   * Lookup440: frame_system::extensions::check_weight::CheckWeight<T>3138   **/3139  FrameSystemExtensionsCheckWeight: 'Null',3140  /**3141   * Lookup441: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>3142   **/3143  PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',3144  /**3145   * Lookup442: opal_runtime::Runtime3146   **/3147  OpalRuntimeRuntime: 'Null',3148  /**3149   * Lookup443: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>3150   **/3151  PalletEthereumFakeTransactionFinalizer: 'Null'3152};
after · tests/src/interfaces/lookup.ts
1// Auto-generated via `yarn polkadot-types-from-defs`, do not edit2/* eslint-disable */34/* eslint-disable sort-keys */56export default {7  /**8   * Lookup2: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>9   **/10  PolkadotPrimitivesV2PersistedValidationData: {11    parentHead: 'Bytes',12    relayParentNumber: 'u32',13    relayParentStorageRoot: 'H256',14    maxPovSize: 'u32'15  },16  /**17   * Lookup9: polkadot_primitives::v2::UpgradeRestriction18   **/19  PolkadotPrimitivesV2UpgradeRestriction: {20    _enum: ['Present']21  },22  /**23   * Lookup10: sp_trie::storage_proof::StorageProof24   **/25  SpTrieStorageProof: {26    trieNodes: 'BTreeSet<Bytes>'27  },28  /**29   * Lookup13: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot30   **/31  CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {32    dmqMqcHead: 'H256',33    relayDispatchQueueSize: '(u32,u32)',34    ingressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>',35    egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>'36  },37  /**38   * Lookup18: polkadot_primitives::v2::AbridgedHrmpChannel39   **/40  PolkadotPrimitivesV2AbridgedHrmpChannel: {41    maxCapacity: 'u32',42    maxTotalSize: 'u32',43    maxMessageSize: 'u32',44    msgCount: 'u32',45    totalSize: 'u32',46    mqcHead: 'Option<H256>'47  },48  /**49   * Lookup20: polkadot_primitives::v2::AbridgedHostConfiguration50   **/51  PolkadotPrimitivesV2AbridgedHostConfiguration: {52    maxCodeSize: 'u32',53    maxHeadDataSize: 'u32',54    maxUpwardQueueCount: 'u32',55    maxUpwardQueueSize: 'u32',56    maxUpwardMessageSize: 'u32',57    maxUpwardMessageNumPerCandidate: 'u32',58    hrmpMaxMessageNumPerCandidate: 'u32',59    validationUpgradeCooldown: 'u32',60    validationUpgradeDelay: 'u32'61  },62  /**63   * Lookup26: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>64   **/65  PolkadotCorePrimitivesOutboundHrmpMessage: {66    recipient: 'u32',67    data: 'Bytes'68  },69  /**70   * Lookup28: cumulus_pallet_parachain_system::pallet::Call<T>71   **/72  CumulusPalletParachainSystemCall: {73    _enum: {74      set_validation_data: {75        data: 'CumulusPrimitivesParachainInherentParachainInherentData',76      },77      sudo_send_upward_message: {78        message: 'Bytes',79      },80      authorize_upgrade: {81        codeHash: 'H256',82      },83      enact_authorized_upgrade: {84        code: 'Bytes'85      }86    }87  },88  /**89   * Lookup29: cumulus_primitives_parachain_inherent::ParachainInherentData90   **/91  CumulusPrimitivesParachainInherentParachainInherentData: {92    validationData: 'PolkadotPrimitivesV2PersistedValidationData',93    relayChainState: 'SpTrieStorageProof',94    downwardMessages: 'Vec<PolkadotCorePrimitivesInboundDownwardMessage>',95    horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'96  },97  /**98   * Lookup31: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>99   **/100  PolkadotCorePrimitivesInboundDownwardMessage: {101    sentAt: 'u32',102    msg: 'Bytes'103  },104  /**105   * Lookup34: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>106   **/107  PolkadotCorePrimitivesInboundHrmpMessage: {108    sentAt: 'u32',109    data: 'Bytes'110  },111  /**112   * Lookup37: cumulus_pallet_parachain_system::pallet::Event<T>113   **/114  CumulusPalletParachainSystemEvent: {115    _enum: {116      ValidationFunctionStored: 'Null',117      ValidationFunctionApplied: {118        relayChainBlockNum: 'u32',119      },120      ValidationFunctionDiscarded: 'Null',121      UpgradeAuthorized: {122        codeHash: 'H256',123      },124      DownwardMessagesReceived: {125        count: 'u32',126      },127      DownwardMessagesProcessed: {128        weightUsed: 'u64',129        dmqHead: 'H256'130      }131    }132  },133  /**134   * Lookup38: cumulus_pallet_parachain_system::pallet::Error<T>135   **/136  CumulusPalletParachainSystemError: {137    _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']138  },139  /**140   * Lookup41: pallet_balances::AccountData<Balance>141   **/142  PalletBalancesAccountData: {143    free: 'u128',144    reserved: 'u128',145    miscFrozen: 'u128',146    feeFrozen: 'u128'147  },148  /**149   * Lookup43: pallet_balances::BalanceLock<Balance>150   **/151  PalletBalancesBalanceLock: {152    id: '[u8;8]',153    amount: 'u128',154    reasons: 'PalletBalancesReasons'155  },156  /**157   * Lookup45: pallet_balances::Reasons158   **/159  PalletBalancesReasons: {160    _enum: ['Fee', 'Misc', 'All']161  },162  /**163   * Lookup48: pallet_balances::ReserveData<ReserveIdentifier, Balance>164   **/165  PalletBalancesReserveData: {166    id: '[u8;16]',167    amount: 'u128'168  },169  /**170   * Lookup51: pallet_balances::Releases171   **/172  PalletBalancesReleases: {173    _enum: ['V1_0_0', 'V2_0_0']174  },175  /**176   * Lookup52: pallet_balances::pallet::Call<T, I>177   **/178  PalletBalancesCall: {179    _enum: {180      transfer: {181        dest: 'MultiAddress',182        value: 'Compact<u128>',183      },184      set_balance: {185        who: 'MultiAddress',186        newFree: 'Compact<u128>',187        newReserved: 'Compact<u128>',188      },189      force_transfer: {190        source: 'MultiAddress',191        dest: 'MultiAddress',192        value: 'Compact<u128>',193      },194      transfer_keep_alive: {195        dest: 'MultiAddress',196        value: 'Compact<u128>',197      },198      transfer_all: {199        dest: 'MultiAddress',200        keepAlive: 'bool',201      },202      force_unreserve: {203        who: 'MultiAddress',204        amount: 'u128'205      }206    }207  },208  /**209   * Lookup58: pallet_balances::pallet::Event<T, I>210   **/211  PalletBalancesEvent: {212    _enum: {213      Endowed: {214        account: 'AccountId32',215        freeBalance: 'u128',216      },217      DustLost: {218        account: 'AccountId32',219        amount: 'u128',220      },221      Transfer: {222        from: 'AccountId32',223        to: 'AccountId32',224        amount: 'u128',225      },226      BalanceSet: {227        who: 'AccountId32',228        free: 'u128',229        reserved: 'u128',230      },231      Reserved: {232        who: 'AccountId32',233        amount: 'u128',234      },235      Unreserved: {236        who: 'AccountId32',237        amount: 'u128',238      },239      ReserveRepatriated: {240        from: 'AccountId32',241        to: 'AccountId32',242        amount: 'u128',243        destinationStatus: 'FrameSupportTokensMiscBalanceStatus',244      },245      Deposit: {246        who: 'AccountId32',247        amount: 'u128',248      },249      Withdraw: {250        who: 'AccountId32',251        amount: 'u128',252      },253      Slashed: {254        who: 'AccountId32',255        amount: 'u128'256      }257    }258  },259  /**260   * Lookup59: frame_support::traits::tokens::misc::BalanceStatus261   **/262  FrameSupportTokensMiscBalanceStatus: {263    _enum: ['Free', 'Reserved']264  },265  /**266   * Lookup60: pallet_balances::pallet::Error<T, I>267   **/268  PalletBalancesError: {269    _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves']270  },271  /**272   * Lookup63: pallet_timestamp::pallet::Call<T>273   **/274  PalletTimestampCall: {275    _enum: {276      set: {277        now: 'Compact<u64>'278      }279    }280  },281  /**282   * Lookup66: pallet_transaction_payment::Releases283   **/284  PalletTransactionPaymentReleases: {285    _enum: ['V1Ancient', 'V2']286  },287  /**288   * Lookup67: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>289   **/290  PalletTreasuryProposal: {291    proposer: 'AccountId32',292    value: 'u128',293    beneficiary: 'AccountId32',294    bond: 'u128'295  },296  /**297   * Lookup70: pallet_treasury::pallet::Call<T, I>298   **/299  PalletTreasuryCall: {300    _enum: {301      propose_spend: {302        value: 'Compact<u128>',303        beneficiary: 'MultiAddress',304      },305      reject_proposal: {306        proposalId: 'Compact<u32>',307      },308      approve_proposal: {309        proposalId: 'Compact<u32>',310      },311      remove_approval: {312        proposalId: 'Compact<u32>'313      }314    }315  },316  /**317   * Lookup72: pallet_treasury::pallet::Event<T, I>318   **/319  PalletTreasuryEvent: {320    _enum: {321      Proposed: {322        proposalIndex: 'u32',323      },324      Spending: {325        budgetRemaining: 'u128',326      },327      Awarded: {328        proposalIndex: 'u32',329        award: 'u128',330        account: 'AccountId32',331      },332      Rejected: {333        proposalIndex: 'u32',334        slashed: 'u128',335      },336      Burnt: {337        burntFunds: 'u128',338      },339      Rollover: {340        rolloverBalance: 'u128',341      },342      Deposit: {343        value: 'u128'344      }345    }346  },347  /**348   * Lookup75: frame_support::PalletId349   **/350  FrameSupportPalletId: '[u8;8]',351  /**352   * Lookup76: pallet_treasury::pallet::Error<T, I>353   **/354  PalletTreasuryError: {355    _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'ProposalNotApproved']356  },357  /**358   * Lookup77: pallet_sudo::pallet::Call<T>359   **/360  PalletSudoCall: {361    _enum: {362      sudo: {363        call: 'Call',364      },365      sudo_unchecked_weight: {366        call: 'Call',367        weight: 'u64',368      },369      set_key: {370        _alias: {371          new_: 'new',372        },373        new_: 'MultiAddress',374      },375      sudo_as: {376        who: 'MultiAddress',377        call: 'Call'378      }379    }380  },381  /**382   * Lookup79: frame_system::pallet::Call<T>383   **/384  FrameSystemCall: {385    _enum: {386      fill_block: {387        ratio: 'Perbill',388      },389      remark: {390        remark: 'Bytes',391      },392      set_heap_pages: {393        pages: 'u64',394      },395      set_code: {396        code: 'Bytes',397      },398      set_code_without_checks: {399        code: 'Bytes',400      },401      set_storage: {402        items: 'Vec<(Bytes,Bytes)>',403      },404      kill_storage: {405        _alias: {406          keys_: 'keys',407        },408        keys_: 'Vec<Bytes>',409      },410      kill_prefix: {411        prefix: 'Bytes',412        subkeys: 'u32',413      },414      remark_with_event: {415        remark: 'Bytes'416      }417    }418  },419  /**420   * Lookup83: orml_vesting::module::Call<T>421   **/422  OrmlVestingModuleCall: {423    _enum: {424      claim: 'Null',425      vested_transfer: {426        dest: 'MultiAddress',427        schedule: 'OrmlVestingVestingSchedule',428      },429      update_vesting_schedules: {430        who: 'MultiAddress',431        vestingSchedules: 'Vec<OrmlVestingVestingSchedule>',432      },433      claim_for: {434        dest: 'MultiAddress'435      }436    }437  },438  /**439   * Lookup84: orml_vesting::VestingSchedule<BlockNumber, Balance>440   **/441  OrmlVestingVestingSchedule: {442    start: 'u32',443    period: 'u32',444    periodCount: 'u32',445    perPeriod: 'Compact<u128>'446  },447  /**448   * Lookup86: cumulus_pallet_xcmp_queue::pallet::Call<T>449   **/450  CumulusPalletXcmpQueueCall: {451    _enum: {452      service_overweight: {453        index: 'u64',454        weightLimit: 'u64',455      },456      suspend_xcm_execution: 'Null',457      resume_xcm_execution: 'Null',458      update_suspend_threshold: {459        _alias: {460          new_: 'new',461        },462        new_: 'u32',463      },464      update_drop_threshold: {465        _alias: {466          new_: 'new',467        },468        new_: 'u32',469      },470      update_resume_threshold: {471        _alias: {472          new_: 'new',473        },474        new_: 'u32',475      },476      update_threshold_weight: {477        _alias: {478          new_: 'new',479        },480        new_: 'u64',481      },482      update_weight_restrict_decay: {483        _alias: {484          new_: 'new',485        },486        new_: 'u64',487      },488      update_xcmp_max_individual_weight: {489        _alias: {490          new_: 'new',491        },492        new_: 'u64'493      }494    }495  },496  /**497   * Lookup87: pallet_xcm::pallet::Call<T>498   **/499  PalletXcmCall: {500    _enum: {501      send: {502        dest: 'XcmVersionedMultiLocation',503        message: 'XcmVersionedXcm',504      },505      teleport_assets: {506        dest: 'XcmVersionedMultiLocation',507        beneficiary: 'XcmVersionedMultiLocation',508        assets: 'XcmVersionedMultiAssets',509        feeAssetItem: 'u32',510      },511      reserve_transfer_assets: {512        dest: 'XcmVersionedMultiLocation',513        beneficiary: 'XcmVersionedMultiLocation',514        assets: 'XcmVersionedMultiAssets',515        feeAssetItem: 'u32',516      },517      execute: {518        message: 'XcmVersionedXcm',519        maxWeight: 'u64',520      },521      force_xcm_version: {522        location: 'XcmV1MultiLocation',523        xcmVersion: 'u32',524      },525      force_default_xcm_version: {526        maybeXcmVersion: 'Option<u32>',527      },528      force_subscribe_version_notify: {529        location: 'XcmVersionedMultiLocation',530      },531      force_unsubscribe_version_notify: {532        location: 'XcmVersionedMultiLocation',533      },534      limited_reserve_transfer_assets: {535        dest: 'XcmVersionedMultiLocation',536        beneficiary: 'XcmVersionedMultiLocation',537        assets: 'XcmVersionedMultiAssets',538        feeAssetItem: 'u32',539        weightLimit: 'XcmV2WeightLimit',540      },541      limited_teleport_assets: {542        dest: 'XcmVersionedMultiLocation',543        beneficiary: 'XcmVersionedMultiLocation',544        assets: 'XcmVersionedMultiAssets',545        feeAssetItem: 'u32',546        weightLimit: 'XcmV2WeightLimit'547      }548    }549  },550  /**551   * Lookup88: xcm::VersionedMultiLocation552   **/553  XcmVersionedMultiLocation: {554    _enum: {555      V0: 'XcmV0MultiLocation',556      V1: 'XcmV1MultiLocation'557    }558  },559  /**560   * Lookup89: xcm::v0::multi_location::MultiLocation561   **/562  XcmV0MultiLocation: {563    _enum: {564      Null: 'Null',565      X1: 'XcmV0Junction',566      X2: '(XcmV0Junction,XcmV0Junction)',567      X3: '(XcmV0Junction,XcmV0Junction,XcmV0Junction)',568      X4: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',569      X5: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',570      X6: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',571      X7: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)',572      X8: '(XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction,XcmV0Junction)'573    }574  },575  /**576   * Lookup90: xcm::v0::junction::Junction577   **/578  XcmV0Junction: {579    _enum: {580      Parent: 'Null',581      Parachain: 'Compact<u32>',582      AccountId32: {583        network: 'XcmV0JunctionNetworkId',584        id: '[u8;32]',585      },586      AccountIndex64: {587        network: 'XcmV0JunctionNetworkId',588        index: 'Compact<u64>',589      },590      AccountKey20: {591        network: 'XcmV0JunctionNetworkId',592        key: '[u8;20]',593      },594      PalletInstance: 'u8',595      GeneralIndex: 'Compact<u128>',596      GeneralKey: 'Bytes',597      OnlyChild: 'Null',598      Plurality: {599        id: 'XcmV0JunctionBodyId',600        part: 'XcmV0JunctionBodyPart'601      }602    }603  },604  /**605   * Lookup91: xcm::v0::junction::NetworkId606   **/607  XcmV0JunctionNetworkId: {608    _enum: {609      Any: 'Null',610      Named: 'Bytes',611      Polkadot: 'Null',612      Kusama: 'Null'613    }614  },615  /**616   * Lookup92: xcm::v0::junction::BodyId617   **/618  XcmV0JunctionBodyId: {619    _enum: {620      Unit: 'Null',621      Named: 'Bytes',622      Index: 'Compact<u32>',623      Executive: 'Null',624      Technical: 'Null',625      Legislative: 'Null',626      Judicial: 'Null'627    }628  },629  /**630   * Lookup93: xcm::v0::junction::BodyPart631   **/632  XcmV0JunctionBodyPart: {633    _enum: {634      Voice: 'Null',635      Members: {636        count: 'Compact<u32>',637      },638      Fraction: {639        nom: 'Compact<u32>',640        denom: 'Compact<u32>',641      },642      AtLeastProportion: {643        nom: 'Compact<u32>',644        denom: 'Compact<u32>',645      },646      MoreThanProportion: {647        nom: 'Compact<u32>',648        denom: 'Compact<u32>'649      }650    }651  },652  /**653   * Lookup94: xcm::v1::multilocation::MultiLocation654   **/655  XcmV1MultiLocation: {656    parents: 'u8',657    interior: 'XcmV1MultilocationJunctions'658  },659  /**660   * Lookup95: xcm::v1::multilocation::Junctions661   **/662  XcmV1MultilocationJunctions: {663    _enum: {664      Here: 'Null',665      X1: 'XcmV1Junction',666      X2: '(XcmV1Junction,XcmV1Junction)',667      X3: '(XcmV1Junction,XcmV1Junction,XcmV1Junction)',668      X4: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',669      X5: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',670      X6: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',671      X7: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)',672      X8: '(XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction,XcmV1Junction)'673    }674  },675  /**676   * Lookup96: xcm::v1::junction::Junction677   **/678  XcmV1Junction: {679    _enum: {680      Parachain: 'Compact<u32>',681      AccountId32: {682        network: 'XcmV0JunctionNetworkId',683        id: '[u8;32]',684      },685      AccountIndex64: {686        network: 'XcmV0JunctionNetworkId',687        index: 'Compact<u64>',688      },689      AccountKey20: {690        network: 'XcmV0JunctionNetworkId',691        key: '[u8;20]',692      },693      PalletInstance: 'u8',694      GeneralIndex: 'Compact<u128>',695      GeneralKey: 'Bytes',696      OnlyChild: 'Null',697      Plurality: {698        id: 'XcmV0JunctionBodyId',699        part: 'XcmV0JunctionBodyPart'700      }701    }702  },703  /**704   * Lookup97: xcm::VersionedXcm<Call>705   **/706  XcmVersionedXcm: {707    _enum: {708      V0: 'XcmV0Xcm',709      V1: 'XcmV1Xcm',710      V2: 'XcmV2Xcm'711    }712  },713  /**714   * Lookup98: xcm::v0::Xcm<Call>715   **/716  XcmV0Xcm: {717    _enum: {718      WithdrawAsset: {719        assets: 'Vec<XcmV0MultiAsset>',720        effects: 'Vec<XcmV0Order>',721      },722      ReserveAssetDeposit: {723        assets: 'Vec<XcmV0MultiAsset>',724        effects: 'Vec<XcmV0Order>',725      },726      TeleportAsset: {727        assets: 'Vec<XcmV0MultiAsset>',728        effects: 'Vec<XcmV0Order>',729      },730      QueryResponse: {731        queryId: 'Compact<u64>',732        response: 'XcmV0Response',733      },734      TransferAsset: {735        assets: 'Vec<XcmV0MultiAsset>',736        dest: 'XcmV0MultiLocation',737      },738      TransferReserveAsset: {739        assets: 'Vec<XcmV0MultiAsset>',740        dest: 'XcmV0MultiLocation',741        effects: 'Vec<XcmV0Order>',742      },743      Transact: {744        originType: 'XcmV0OriginKind',745        requireWeightAtMost: 'u64',746        call: 'XcmDoubleEncoded',747      },748      HrmpNewChannelOpenRequest: {749        sender: 'Compact<u32>',750        maxMessageSize: 'Compact<u32>',751        maxCapacity: 'Compact<u32>',752      },753      HrmpChannelAccepted: {754        recipient: 'Compact<u32>',755      },756      HrmpChannelClosing: {757        initiator: 'Compact<u32>',758        sender: 'Compact<u32>',759        recipient: 'Compact<u32>',760      },761      RelayedFrom: {762        who: 'XcmV0MultiLocation',763        message: 'XcmV0Xcm'764      }765    }766  },767  /**768   * Lookup100: xcm::v0::multi_asset::MultiAsset769   **/770  XcmV0MultiAsset: {771    _enum: {772      None: 'Null',773      All: 'Null',774      AllFungible: 'Null',775      AllNonFungible: 'Null',776      AllAbstractFungible: {777        id: 'Bytes',778      },779      AllAbstractNonFungible: {780        class: 'Bytes',781      },782      AllConcreteFungible: {783        id: 'XcmV0MultiLocation',784      },785      AllConcreteNonFungible: {786        class: 'XcmV0MultiLocation',787      },788      AbstractFungible: {789        id: 'Bytes',790        amount: 'Compact<u128>',791      },792      AbstractNonFungible: {793        class: 'Bytes',794        instance: 'XcmV1MultiassetAssetInstance',795      },796      ConcreteFungible: {797        id: 'XcmV0MultiLocation',798        amount: 'Compact<u128>',799      },800      ConcreteNonFungible: {801        class: 'XcmV0MultiLocation',802        instance: 'XcmV1MultiassetAssetInstance'803      }804    }805  },806  /**807   * Lookup101: xcm::v1::multiasset::AssetInstance808   **/809  XcmV1MultiassetAssetInstance: {810    _enum: {811      Undefined: 'Null',812      Index: 'Compact<u128>',813      Array4: '[u8;4]',814      Array8: '[u8;8]',815      Array16: '[u8;16]',816      Array32: '[u8;32]',817      Blob: 'Bytes'818    }819  },820  /**821   * Lookup104: xcm::v0::order::Order<Call>822   **/823  XcmV0Order: {824    _enum: {825      Null: 'Null',826      DepositAsset: {827        assets: 'Vec<XcmV0MultiAsset>',828        dest: 'XcmV0MultiLocation',829      },830      DepositReserveAsset: {831        assets: 'Vec<XcmV0MultiAsset>',832        dest: 'XcmV0MultiLocation',833        effects: 'Vec<XcmV0Order>',834      },835      ExchangeAsset: {836        give: 'Vec<XcmV0MultiAsset>',837        receive: 'Vec<XcmV0MultiAsset>',838      },839      InitiateReserveWithdraw: {840        assets: 'Vec<XcmV0MultiAsset>',841        reserve: 'XcmV0MultiLocation',842        effects: 'Vec<XcmV0Order>',843      },844      InitiateTeleport: {845        assets: 'Vec<XcmV0MultiAsset>',846        dest: 'XcmV0MultiLocation',847        effects: 'Vec<XcmV0Order>',848      },849      QueryHolding: {850        queryId: 'Compact<u64>',851        dest: 'XcmV0MultiLocation',852        assets: 'Vec<XcmV0MultiAsset>',853      },854      BuyExecution: {855        fees: 'XcmV0MultiAsset',856        weight: 'u64',857        debt: 'u64',858        haltOnError: 'bool',859        xcm: 'Vec<XcmV0Xcm>'860      }861    }862  },863  /**864   * Lookup106: xcm::v0::Response865   **/866  XcmV0Response: {867    _enum: {868      Assets: 'Vec<XcmV0MultiAsset>'869    }870  },871  /**872   * Lookup107: xcm::v0::OriginKind873   **/874  XcmV0OriginKind: {875    _enum: ['Native', 'SovereignAccount', 'Superuser', 'Xcm']876  },877  /**878   * Lookup108: xcm::double_encoded::DoubleEncoded<T>879   **/880  XcmDoubleEncoded: {881    encoded: 'Bytes'882  },883  /**884   * Lookup109: xcm::v1::Xcm<Call>885   **/886  XcmV1Xcm: {887    _enum: {888      WithdrawAsset: {889        assets: 'XcmV1MultiassetMultiAssets',890        effects: 'Vec<XcmV1Order>',891      },892      ReserveAssetDeposited: {893        assets: 'XcmV1MultiassetMultiAssets',894        effects: 'Vec<XcmV1Order>',895      },896      ReceiveTeleportedAsset: {897        assets: 'XcmV1MultiassetMultiAssets',898        effects: 'Vec<XcmV1Order>',899      },900      QueryResponse: {901        queryId: 'Compact<u64>',902        response: 'XcmV1Response',903      },904      TransferAsset: {905        assets: 'XcmV1MultiassetMultiAssets',906        beneficiary: 'XcmV1MultiLocation',907      },908      TransferReserveAsset: {909        assets: 'XcmV1MultiassetMultiAssets',910        dest: 'XcmV1MultiLocation',911        effects: 'Vec<XcmV1Order>',912      },913      Transact: {914        originType: 'XcmV0OriginKind',915        requireWeightAtMost: 'u64',916        call: 'XcmDoubleEncoded',917      },918      HrmpNewChannelOpenRequest: {919        sender: 'Compact<u32>',920        maxMessageSize: 'Compact<u32>',921        maxCapacity: 'Compact<u32>',922      },923      HrmpChannelAccepted: {924        recipient: 'Compact<u32>',925      },926      HrmpChannelClosing: {927        initiator: 'Compact<u32>',928        sender: 'Compact<u32>',929        recipient: 'Compact<u32>',930      },931      RelayedFrom: {932        who: 'XcmV1MultilocationJunctions',933        message: 'XcmV1Xcm',934      },935      SubscribeVersion: {936        queryId: 'Compact<u64>',937        maxResponseWeight: 'Compact<u64>',938      },939      UnsubscribeVersion: 'Null'940    }941  },942  /**943   * Lookup110: xcm::v1::multiasset::MultiAssets944   **/945  XcmV1MultiassetMultiAssets: 'Vec<XcmV1MultiAsset>',946  /**947   * Lookup112: xcm::v1::multiasset::MultiAsset948   **/949  XcmV1MultiAsset: {950    id: 'XcmV1MultiassetAssetId',951    fun: 'XcmV1MultiassetFungibility'952  },953  /**954   * Lookup113: xcm::v1::multiasset::AssetId955   **/956  XcmV1MultiassetAssetId: {957    _enum: {958      Concrete: 'XcmV1MultiLocation',959      Abstract: 'Bytes'960    }961  },962  /**963   * Lookup114: xcm::v1::multiasset::Fungibility964   **/965  XcmV1MultiassetFungibility: {966    _enum: {967      Fungible: 'Compact<u128>',968      NonFungible: 'XcmV1MultiassetAssetInstance'969    }970  },971  /**972   * Lookup116: xcm::v1::order::Order<Call>973   **/974  XcmV1Order: {975    _enum: {976      Noop: 'Null',977      DepositAsset: {978        assets: 'XcmV1MultiassetMultiAssetFilter',979        maxAssets: 'u32',980        beneficiary: 'XcmV1MultiLocation',981      },982      DepositReserveAsset: {983        assets: 'XcmV1MultiassetMultiAssetFilter',984        maxAssets: 'u32',985        dest: 'XcmV1MultiLocation',986        effects: 'Vec<XcmV1Order>',987      },988      ExchangeAsset: {989        give: 'XcmV1MultiassetMultiAssetFilter',990        receive: 'XcmV1MultiassetMultiAssets',991      },992      InitiateReserveWithdraw: {993        assets: 'XcmV1MultiassetMultiAssetFilter',994        reserve: 'XcmV1MultiLocation',995        effects: 'Vec<XcmV1Order>',996      },997      InitiateTeleport: {998        assets: 'XcmV1MultiassetMultiAssetFilter',999        dest: 'XcmV1MultiLocation',1000        effects: 'Vec<XcmV1Order>',1001      },1002      QueryHolding: {1003        queryId: 'Compact<u64>',1004        dest: 'XcmV1MultiLocation',1005        assets: 'XcmV1MultiassetMultiAssetFilter',1006      },1007      BuyExecution: {1008        fees: 'XcmV1MultiAsset',1009        weight: 'u64',1010        debt: 'u64',1011        haltOnError: 'bool',1012        instructions: 'Vec<XcmV1Xcm>'1013      }1014    }1015  },1016  /**1017   * Lookup117: xcm::v1::multiasset::MultiAssetFilter1018   **/1019  XcmV1MultiassetMultiAssetFilter: {1020    _enum: {1021      Definite: 'XcmV1MultiassetMultiAssets',1022      Wild: 'XcmV1MultiassetWildMultiAsset'1023    }1024  },1025  /**1026   * Lookup118: xcm::v1::multiasset::WildMultiAsset1027   **/1028  XcmV1MultiassetWildMultiAsset: {1029    _enum: {1030      All: 'Null',1031      AllOf: {1032        id: 'XcmV1MultiassetAssetId',1033        fun: 'XcmV1MultiassetWildFungibility'1034      }1035    }1036  },1037  /**1038   * Lookup119: xcm::v1::multiasset::WildFungibility1039   **/1040  XcmV1MultiassetWildFungibility: {1041    _enum: ['Fungible', 'NonFungible']1042  },1043  /**1044   * Lookup121: xcm::v1::Response1045   **/1046  XcmV1Response: {1047    _enum: {1048      Assets: 'XcmV1MultiassetMultiAssets',1049      Version: 'u32'1050    }1051  },1052  /**1053   * Lookup122: xcm::v2::Xcm<Call>1054   **/1055  XcmV2Xcm: 'Vec<XcmV2Instruction>',1056  /**1057   * Lookup124: xcm::v2::Instruction<Call>1058   **/1059  XcmV2Instruction: {1060    _enum: {1061      WithdrawAsset: 'XcmV1MultiassetMultiAssets',1062      ReserveAssetDeposited: 'XcmV1MultiassetMultiAssets',1063      ReceiveTeleportedAsset: 'XcmV1MultiassetMultiAssets',1064      QueryResponse: {1065        queryId: 'Compact<u64>',1066        response: 'XcmV2Response',1067        maxWeight: 'Compact<u64>',1068      },1069      TransferAsset: {1070        assets: 'XcmV1MultiassetMultiAssets',1071        beneficiary: 'XcmV1MultiLocation',1072      },1073      TransferReserveAsset: {1074        assets: 'XcmV1MultiassetMultiAssets',1075        dest: 'XcmV1MultiLocation',1076        xcm: 'XcmV2Xcm',1077      },1078      Transact: {1079        originType: 'XcmV0OriginKind',1080        requireWeightAtMost: 'Compact<u64>',1081        call: 'XcmDoubleEncoded',1082      },1083      HrmpNewChannelOpenRequest: {1084        sender: 'Compact<u32>',1085        maxMessageSize: 'Compact<u32>',1086        maxCapacity: 'Compact<u32>',1087      },1088      HrmpChannelAccepted: {1089        recipient: 'Compact<u32>',1090      },1091      HrmpChannelClosing: {1092        initiator: 'Compact<u32>',1093        sender: 'Compact<u32>',1094        recipient: 'Compact<u32>',1095      },1096      ClearOrigin: 'Null',1097      DescendOrigin: 'XcmV1MultilocationJunctions',1098      ReportError: {1099        queryId: 'Compact<u64>',1100        dest: 'XcmV1MultiLocation',1101        maxResponseWeight: 'Compact<u64>',1102      },1103      DepositAsset: {1104        assets: 'XcmV1MultiassetMultiAssetFilter',1105        maxAssets: 'Compact<u32>',1106        beneficiary: 'XcmV1MultiLocation',1107      },1108      DepositReserveAsset: {1109        assets: 'XcmV1MultiassetMultiAssetFilter',1110        maxAssets: 'Compact<u32>',1111        dest: 'XcmV1MultiLocation',1112        xcm: 'XcmV2Xcm',1113      },1114      ExchangeAsset: {1115        give: 'XcmV1MultiassetMultiAssetFilter',1116        receive: 'XcmV1MultiassetMultiAssets',1117      },1118      InitiateReserveWithdraw: {1119        assets: 'XcmV1MultiassetMultiAssetFilter',1120        reserve: 'XcmV1MultiLocation',1121        xcm: 'XcmV2Xcm',1122      },1123      InitiateTeleport: {1124        assets: 'XcmV1MultiassetMultiAssetFilter',1125        dest: 'XcmV1MultiLocation',1126        xcm: 'XcmV2Xcm',1127      },1128      QueryHolding: {1129        queryId: 'Compact<u64>',1130        dest: 'XcmV1MultiLocation',1131        assets: 'XcmV1MultiassetMultiAssetFilter',1132        maxResponseWeight: 'Compact<u64>',1133      },1134      BuyExecution: {1135        fees: 'XcmV1MultiAsset',1136        weightLimit: 'XcmV2WeightLimit',1137      },1138      RefundSurplus: 'Null',1139      SetErrorHandler: 'XcmV2Xcm',1140      SetAppendix: 'XcmV2Xcm',1141      ClearError: 'Null',1142      ClaimAsset: {1143        assets: 'XcmV1MultiassetMultiAssets',1144        ticket: 'XcmV1MultiLocation',1145      },1146      Trap: 'Compact<u64>',1147      SubscribeVersion: {1148        queryId: 'Compact<u64>',1149        maxResponseWeight: 'Compact<u64>',1150      },1151      UnsubscribeVersion: 'Null'1152    }1153  },1154  /**1155   * Lookup125: xcm::v2::Response1156   **/1157  XcmV2Response: {1158    _enum: {1159      Null: 'Null',1160      Assets: 'XcmV1MultiassetMultiAssets',1161      ExecutionResult: 'Option<(u32,XcmV2TraitsError)>',1162      Version: 'u32'1163    }1164  },1165  /**1166   * Lookup128: xcm::v2::traits::Error1167   **/1168  XcmV2TraitsError: {1169    _enum: {1170      Overflow: 'Null',1171      Unimplemented: 'Null',1172      UntrustedReserveLocation: 'Null',1173      UntrustedTeleportLocation: 'Null',1174      MultiLocationFull: 'Null',1175      MultiLocationNotInvertible: 'Null',1176      BadOrigin: 'Null',1177      InvalidLocation: 'Null',1178      AssetNotFound: 'Null',1179      FailedToTransactAsset: 'Null',1180      NotWithdrawable: 'Null',1181      LocationCannotHold: 'Null',1182      ExceedsMaxMessageSize: 'Null',1183      DestinationUnsupported: 'Null',1184      Transport: 'Null',1185      Unroutable: 'Null',1186      UnknownClaim: 'Null',1187      FailedToDecode: 'Null',1188      MaxWeightInvalid: 'Null',1189      NotHoldingFees: 'Null',1190      TooExpensive: 'Null',1191      Trap: 'u64',1192      UnhandledXcmVersion: 'Null',1193      WeightLimitReached: 'u64',1194      Barrier: 'Null',1195      WeightNotComputable: 'Null'1196    }1197  },1198  /**1199   * Lookup129: xcm::v2::WeightLimit1200   **/1201  XcmV2WeightLimit: {1202    _enum: {1203      Unlimited: 'Null',1204      Limited: 'Compact<u64>'1205    }1206  },1207  /**1208   * Lookup130: xcm::VersionedMultiAssets1209   **/1210  XcmVersionedMultiAssets: {1211    _enum: {1212      V0: 'Vec<XcmV0MultiAsset>',1213      V1: 'XcmV1MultiassetMultiAssets'1214    }1215  },1216  /**1217   * Lookup145: cumulus_pallet_xcm::pallet::Call<T>1218   **/1219  CumulusPalletXcmCall: 'Null',1220  /**1221   * Lookup146: cumulus_pallet_dmp_queue::pallet::Call<T>1222   **/1223  CumulusPalletDmpQueueCall: {1224    _enum: {1225      service_overweight: {1226        index: 'u64',1227        weightLimit: 'u64'1228      }1229    }1230  },1231  /**1232   * Lookup147: pallet_inflation::pallet::Call<T>1233   **/1234  PalletInflationCall: {1235    _enum: {1236      start_inflation: {1237        inflationStartRelayBlock: 'u32'1238      }1239    }1240  },1241  /**1242   * Lookup148: pallet_unique::Call<T>1243   **/1244  PalletUniqueCall: {1245    _enum: {1246      create_collection: {1247        collectionName: 'Vec<u16>',1248        collectionDescription: 'Vec<u16>',1249        tokenPrefix: 'Bytes',1250        mode: 'UpDataStructsCollectionMode',1251      },1252      create_collection_ex: {1253        data: 'UpDataStructsCreateCollectionData',1254      },1255      destroy_collection: {1256        collectionId: 'u32',1257      },1258      add_to_allow_list: {1259        collectionId: 'u32',1260        address: 'PalletEvmAccountBasicCrossAccountIdRepr',1261      },1262      remove_from_allow_list: {1263        collectionId: 'u32',1264        address: 'PalletEvmAccountBasicCrossAccountIdRepr',1265      },1266      change_collection_owner: {1267        collectionId: 'u32',1268        newOwner: 'AccountId32',1269      },1270      add_collection_admin: {1271        collectionId: 'u32',1272        newAdmin: 'PalletEvmAccountBasicCrossAccountIdRepr',1273      },1274      remove_collection_admin: {1275        collectionId: 'u32',1276        accountId: 'PalletEvmAccountBasicCrossAccountIdRepr',1277      },1278      set_collection_sponsor: {1279        collectionId: 'u32',1280        newSponsor: 'AccountId32',1281      },1282      confirm_sponsorship: {1283        collectionId: 'u32',1284      },1285      remove_collection_sponsor: {1286        collectionId: 'u32',1287      },1288      create_item: {1289        collectionId: 'u32',1290        owner: 'PalletEvmAccountBasicCrossAccountIdRepr',1291        data: 'UpDataStructsCreateItemData',1292      },1293      create_multiple_items: {1294        collectionId: 'u32',1295        owner: 'PalletEvmAccountBasicCrossAccountIdRepr',1296        itemsData: 'Vec<UpDataStructsCreateItemData>',1297      },1298      set_collection_properties: {1299        collectionId: 'u32',1300        properties: 'Vec<UpDataStructsProperty>',1301      },1302      delete_collection_properties: {1303        collectionId: 'u32',1304        propertyKeys: 'Vec<Bytes>',1305      },1306      set_token_properties: {1307        collectionId: 'u32',1308        tokenId: 'u32',1309        properties: 'Vec<UpDataStructsProperty>',1310      },1311      delete_token_properties: {1312        collectionId: 'u32',1313        tokenId: 'u32',1314        propertyKeys: 'Vec<Bytes>',1315      },1316      set_token_property_permissions: {1317        collectionId: 'u32',1318        propertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',1319      },1320      create_multiple_items_ex: {1321        collectionId: 'u32',1322        data: 'UpDataStructsCreateItemExData',1323      },1324      set_transfers_enabled_flag: {1325        collectionId: 'u32',1326        value: 'bool',1327      },1328      burn_item: {1329        collectionId: 'u32',1330        itemId: 'u32',1331        value: 'u128',1332      },1333      burn_from: {1334        collectionId: 'u32',1335        from: 'PalletEvmAccountBasicCrossAccountIdRepr',1336        itemId: 'u32',1337        value: 'u128',1338      },1339      transfer: {1340        recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',1341        collectionId: 'u32',1342        itemId: 'u32',1343        value: 'u128',1344      },1345      approve: {1346        spender: 'PalletEvmAccountBasicCrossAccountIdRepr',1347        collectionId: 'u32',1348        itemId: 'u32',1349        amount: 'u128',1350      },1351      transfer_from: {1352        from: 'PalletEvmAccountBasicCrossAccountIdRepr',1353        recipient: 'PalletEvmAccountBasicCrossAccountIdRepr',1354        collectionId: 'u32',1355        itemId: 'u32',1356        value: 'u128',1357      },1358      set_collection_limits: {1359        collectionId: 'u32',1360        newLimit: 'UpDataStructsCollectionLimits',1361      },1362      set_collection_permissions: {1363        collectionId: 'u32',1364        newPermission: 'UpDataStructsCollectionPermissions',1365      },1366      repartition: {1367        collectionId: 'u32',1368        tokenId: 'u32',1369        amount: 'u128'1370      }1371    }1372  },1373  /**1374   * Lookup154: up_data_structs::CollectionMode1375   **/1376  UpDataStructsCollectionMode: {1377    _enum: {1378      NFT: 'Null',1379      Fungible: 'u8',1380      ReFungible: 'Null'1381    }1382  },1383  /**1384   * Lookup155: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>1385   **/1386  UpDataStructsCreateCollectionData: {1387    mode: 'UpDataStructsCollectionMode',1388    access: 'Option<UpDataStructsAccessMode>',1389    name: 'Vec<u16>',1390    description: 'Vec<u16>',1391    tokenPrefix: 'Bytes',1392    pendingSponsor: 'Option<AccountId32>',1393    limits: 'Option<UpDataStructsCollectionLimits>',1394    permissions: 'Option<UpDataStructsCollectionPermissions>',1395    tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',1396    properties: 'Vec<UpDataStructsProperty>'1397  },1398  /**1399   * Lookup157: up_data_structs::AccessMode1400   **/1401  UpDataStructsAccessMode: {1402    _enum: ['Normal', 'AllowList']1403  },1404  /**1405   * Lookup160: up_data_structs::CollectionLimits1406   **/1407  UpDataStructsCollectionLimits: {1408    accountTokenOwnershipLimit: 'Option<u32>',1409    sponsoredDataSize: 'Option<u32>',1410    sponsoredDataRateLimit: 'Option<UpDataStructsSponsoringRateLimit>',1411    tokenLimit: 'Option<u32>',1412    sponsorTransferTimeout: 'Option<u32>',1413    sponsorApproveTimeout: 'Option<u32>',1414    ownerCanTransfer: 'Option<bool>',1415    ownerCanDestroy: 'Option<bool>',1416    transfersEnabled: 'Option<bool>'1417  },1418  /**1419   * Lookup162: up_data_structs::SponsoringRateLimit1420   **/1421  UpDataStructsSponsoringRateLimit: {1422    _enum: {1423      SponsoringDisabled: 'Null',1424      Blocks: 'u32'1425    }1426  },1427  /**1428   * Lookup165: up_data_structs::CollectionPermissions1429   **/1430  UpDataStructsCollectionPermissions: {1431    access: 'Option<UpDataStructsAccessMode>',1432    mintMode: 'Option<bool>',1433    nesting: 'Option<UpDataStructsNestingPermissions>'1434  },1435  /**1436   * Lookup167: up_data_structs::NestingPermissions1437   **/1438  UpDataStructsNestingPermissions: {1439    tokenOwner: 'bool',1440    collectionAdmin: 'bool',1441    restricted: 'Option<UpDataStructsOwnerRestrictedSet>'1442  },1443  /**1444   * Lookup169: up_data_structs::OwnerRestrictedSet1445   **/1446  UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',1447  /**1448   * Lookup175: up_data_structs::PropertyKeyPermission1449   **/1450  UpDataStructsPropertyKeyPermission: {1451    key: 'Bytes',1452    permission: 'UpDataStructsPropertyPermission'1453  },1454  /**1455   * Lookup177: up_data_structs::PropertyPermission1456   **/1457  UpDataStructsPropertyPermission: {1458    mutable: 'bool',1459    collectionAdmin: 'bool',1460    tokenOwner: 'bool'1461  },1462  /**1463   * Lookup180: up_data_structs::Property1464   **/1465  UpDataStructsProperty: {1466    key: 'Bytes',1467    value: 'Bytes'1468  },1469  /**1470   * Lookup183: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>1471   **/1472  PalletEvmAccountBasicCrossAccountIdRepr: {1473    _enum: {1474      Substrate: 'AccountId32',1475      Ethereum: 'H160'1476    }1477  },1478  /**1479   * Lookup185: up_data_structs::CreateItemData1480   **/1481  UpDataStructsCreateItemData: {1482    _enum: {1483      NFT: 'UpDataStructsCreateNftData',1484      Fungible: 'UpDataStructsCreateFungibleData',1485      ReFungible: 'UpDataStructsCreateReFungibleData'1486    }1487  },1488  /**1489   * Lookup186: up_data_structs::CreateNftData1490   **/1491  UpDataStructsCreateNftData: {1492    properties: 'Vec<UpDataStructsProperty>'1493  },1494  /**1495   * Lookup187: up_data_structs::CreateFungibleData1496   **/1497  UpDataStructsCreateFungibleData: {1498    value: 'u128'1499  },1500  /**1501   * Lookup188: up_data_structs::CreateReFungibleData1502   **/1503  UpDataStructsCreateReFungibleData: {1504    constData: 'Bytes',1505    pieces: 'u128',1506    properties: 'Vec<UpDataStructsProperty>'1507  },1508  /**1509   * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1510   **/1511  UpDataStructsCreateItemExData: {1512    _enum: {1513      NFT: 'Vec<UpDataStructsCreateNftExData>',1514      Fungible: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',1515      RefungibleMultipleItems: 'Vec<UpDataStructsCreateRefungibleExData>',1516      RefungibleMultipleOwners: 'UpDataStructsCreateRefungibleExData'1517    }1518  },1519  /**1520   * Lookup195: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1521   **/1522  UpDataStructsCreateNftExData: {1523    properties: 'Vec<UpDataStructsProperty>',1524    owner: 'PalletEvmAccountBasicCrossAccountIdRepr'1525  },1526  /**1527   * Lookup202: up_data_structs::CreateRefungibleExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1528   **/1529  UpDataStructsCreateRefungibleExData: {1530    constData: 'Bytes',1531    users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',1532    properties: 'Vec<UpDataStructsProperty>'1533  },1534  /**1535   * Lookup204: pallet_unique_scheduler::pallet::Call<T>1536   **/1537  PalletUniqueSchedulerCall: {1538    _enum: {1539      schedule_named: {1540        id: '[u8;16]',1541        when: 'u32',1542        maybePeriodic: 'Option<(u32,u32)>',1543        priority: 'u8',1544        call: 'FrameSupportScheduleMaybeHashed',1545      },1546      cancel_named: {1547        id: '[u8;16]',1548      },1549      schedule_named_after: {1550        id: '[u8;16]',1551        after: 'u32',1552        maybePeriodic: 'Option<(u32,u32)>',1553        priority: 'u8',1554        call: 'FrameSupportScheduleMaybeHashed'1555      }1556    }1557  },1558  /**1559   * Lookup206: frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>1560   **/1561  FrameSupportScheduleMaybeHashed: {1562    _enum: {1563      Value: 'Call',1564      Hash: 'H256'1565    }1566  },1567  /**1568   * Lookup207: pallet_template_transaction_payment::Call<T>1569   **/1570  PalletTemplateTransactionPaymentCall: 'Null',1571  /**1572   * Lookup208: pallet_structure::pallet::Call<T>1573   **/1574  PalletStructureCall: 'Null',1575  /**1576   * Lookup209: pallet_rmrk_core::pallet::Call<T>1577   **/1578  PalletRmrkCoreCall: {1579    _enum: {1580      create_collection: {1581        metadata: 'Bytes',1582        max: 'Option<u32>',1583        symbol: 'Bytes',1584      },1585      destroy_collection: {1586        collectionId: 'u32',1587      },1588      change_collection_issuer: {1589        collectionId: 'u32',1590        newIssuer: 'MultiAddress',1591      },1592      lock_collection: {1593        collectionId: 'u32',1594      },1595      mint_nft: {1596        owner: 'Option<AccountId32>',1597        collectionId: 'u32',1598        recipient: 'Option<AccountId32>',1599        royaltyAmount: 'Option<Permill>',1600        metadata: 'Bytes',1601        transferable: 'bool',1602        resources: 'Option<Vec<RmrkTraitsResourceResourceTypes>>',1603      },1604      burn_nft: {1605        collectionId: 'u32',1606        nftId: 'u32',1607        maxBurns: 'u32',1608      },1609      send: {1610        rmrkCollectionId: 'u32',1611        rmrkNftId: 'u32',1612        newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',1613      },1614      accept_nft: {1615        rmrkCollectionId: 'u32',1616        rmrkNftId: 'u32',1617        newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',1618      },1619      reject_nft: {1620        rmrkCollectionId: 'u32',1621        rmrkNftId: 'u32',1622      },1623      accept_resource: {1624        rmrkCollectionId: 'u32',1625        rmrkNftId: 'u32',1626        resourceId: 'u32',1627      },1628      accept_resource_removal: {1629        rmrkCollectionId: 'u32',1630        rmrkNftId: 'u32',1631        resourceId: 'u32',1632      },1633      set_property: {1634        rmrkCollectionId: 'Compact<u32>',1635        maybeNftId: 'Option<u32>',1636        key: 'Bytes',1637        value: 'Bytes',1638      },1639      set_priority: {1640        rmrkCollectionId: 'u32',1641        rmrkNftId: 'u32',1642        priorities: 'Vec<u32>',1643      },1644      add_basic_resource: {1645        rmrkCollectionId: 'u32',1646        nftId: 'u32',1647        resource: 'RmrkTraitsResourceBasicResource',1648      },1649      add_composable_resource: {1650        rmrkCollectionId: 'u32',1651        nftId: 'u32',1652        resource: 'RmrkTraitsResourceComposableResource',1653      },1654      add_slot_resource: {1655        rmrkCollectionId: 'u32',1656        nftId: 'u32',1657        resource: 'RmrkTraitsResourceSlotResource',1658      },1659      remove_resource: {1660        rmrkCollectionId: 'u32',1661        nftId: 'u32',1662        resourceId: 'u32'1663      }1664    }1665  },1666  /**1667   * Lookup215: rmrk_traits::resource::ResourceTypes<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1668   **/1669  RmrkTraitsResourceResourceTypes: {1670    _enum: {1671      Basic: 'RmrkTraitsResourceBasicResource',1672      Composable: 'RmrkTraitsResourceComposableResource',1673      Slot: 'RmrkTraitsResourceSlotResource'1674    }1675  },1676  /**1677   * Lookup217: rmrk_traits::resource::BasicResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>1678   **/1679  RmrkTraitsResourceBasicResource: {1680    src: 'Option<Bytes>',1681    metadata: 'Option<Bytes>',1682    license: 'Option<Bytes>',1683    thumb: 'Option<Bytes>'1684  },1685  /**1686   * Lookup219: rmrk_traits::resource::ComposableResource<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1687   **/1688  RmrkTraitsResourceComposableResource: {1689    parts: 'Vec<u32>',1690    base: 'u32',1691    src: 'Option<Bytes>',1692    metadata: 'Option<Bytes>',1693    license: 'Option<Bytes>',1694    thumb: 'Option<Bytes>'1695  },1696  /**1697   * Lookup220: rmrk_traits::resource::SlotResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>1698   **/1699  RmrkTraitsResourceSlotResource: {1700    base: 'u32',1701    src: 'Option<Bytes>',1702    metadata: 'Option<Bytes>',1703    slot: 'u32',1704    license: 'Option<Bytes>',1705    thumb: 'Option<Bytes>'1706  },1707  /**1708   * Lookup222: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>1709   **/1710  RmrkTraitsNftAccountIdOrCollectionNftTuple: {1711    _enum: {1712      AccountId: 'AccountId32',1713      CollectionAndNftTuple: '(u32,u32)'1714    }1715  },1716  /**1717   * Lookup226: pallet_rmrk_equip::pallet::Call<T>1718   **/1719  PalletRmrkEquipCall: {1720    _enum: {1721      create_base: {1722        baseType: 'Bytes',1723        symbol: 'Bytes',1724        parts: 'Vec<RmrkTraitsPartPartType>',1725      },1726      theme_add: {1727        baseId: 'u32',1728        theme: 'RmrkTraitsTheme',1729      },1730      equippable: {1731        baseId: 'u32',1732        slotId: 'u32',1733        equippables: 'RmrkTraitsPartEquippableList'1734      }1735    }1736  },1737  /**1738   * Lookup229: rmrk_traits::part::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1739   **/1740  RmrkTraitsPartPartType: {1741    _enum: {1742      FixedPart: 'RmrkTraitsPartFixedPart',1743      SlotPart: 'RmrkTraitsPartSlotPart'1744    }1745  },1746  /**1747   * Lookup231: rmrk_traits::part::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>1748   **/1749  RmrkTraitsPartFixedPart: {1750    id: 'u32',1751    z: 'u32',1752    src: 'Bytes'1753  },1754  /**1755   * Lookup232: rmrk_traits::part::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>1756   **/1757  RmrkTraitsPartSlotPart: {1758    id: 'u32',1759    equippable: 'RmrkTraitsPartEquippableList',1760    src: 'Bytes',1761    z: 'u32'1762  },1763  /**1764   * Lookup233: rmrk_traits::part::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>1765   **/1766  RmrkTraitsPartEquippableList: {1767    _enum: {1768      All: 'Null',1769      Empty: 'Null',1770      Custom: 'Vec<u32>'1771    }1772  },1773  /**1774   * Lookup235: rmrk_traits::theme::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>, S>>1775   **/1776  RmrkTraitsTheme: {1777    name: 'Bytes',1778    properties: 'Vec<RmrkTraitsThemeThemeProperty>',1779    inherit: 'bool'1780  },1781  /**1782   * Lookup237: rmrk_traits::theme::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>1783   **/1784  RmrkTraitsThemeThemeProperty: {1785    key: 'Bytes',1786    value: 'Bytes'1787  },1788  /**1789   * Lookup239: pallet_evm::pallet::Call<T>1790   **/1791  PalletEvmCall: {1792    _enum: {1793      withdraw: {1794        address: 'H160',1795        value: 'u128',1796      },1797      call: {1798        source: 'H160',1799        target: 'H160',1800        input: 'Bytes',1801        value: 'U256',1802        gasLimit: 'u64',1803        maxFeePerGas: 'U256',1804        maxPriorityFeePerGas: 'Option<U256>',1805        nonce: 'Option<U256>',1806        accessList: 'Vec<(H160,Vec<H256>)>',1807      },1808      create: {1809        source: 'H160',1810        init: 'Bytes',1811        value: 'U256',1812        gasLimit: 'u64',1813        maxFeePerGas: 'U256',1814        maxPriorityFeePerGas: 'Option<U256>',1815        nonce: 'Option<U256>',1816        accessList: 'Vec<(H160,Vec<H256>)>',1817      },1818      create2: {1819        source: 'H160',1820        init: 'Bytes',1821        salt: 'H256',1822        value: 'U256',1823        gasLimit: 'u64',1824        maxFeePerGas: 'U256',1825        maxPriorityFeePerGas: 'Option<U256>',1826        nonce: 'Option<U256>',1827        accessList: 'Vec<(H160,Vec<H256>)>'1828      }1829    }1830  },1831  /**1832   * Lookup245: pallet_ethereum::pallet::Call<T>1833   **/1834  PalletEthereumCall: {1835    _enum: {1836      transact: {1837        transaction: 'EthereumTransactionTransactionV2'1838      }1839    }1840  },1841  /**1842   * Lookup246: ethereum::transaction::TransactionV21843   **/1844  EthereumTransactionTransactionV2: {1845    _enum: {1846      Legacy: 'EthereumTransactionLegacyTransaction',1847      EIP2930: 'EthereumTransactionEip2930Transaction',1848      EIP1559: 'EthereumTransactionEip1559Transaction'1849    }1850  },1851  /**1852   * Lookup247: ethereum::transaction::LegacyTransaction1853   **/1854  EthereumTransactionLegacyTransaction: {1855    nonce: 'U256',1856    gasPrice: 'U256',1857    gasLimit: 'U256',1858    action: 'EthereumTransactionTransactionAction',1859    value: 'U256',1860    input: 'Bytes',1861    signature: 'EthereumTransactionTransactionSignature'1862  },1863  /**1864   * Lookup248: ethereum::transaction::TransactionAction1865   **/1866  EthereumTransactionTransactionAction: {1867    _enum: {1868      Call: 'H160',1869      Create: 'Null'1870    }1871  },1872  /**1873   * Lookup249: ethereum::transaction::TransactionSignature1874   **/1875  EthereumTransactionTransactionSignature: {1876    v: 'u64',1877    r: 'H256',1878    s: 'H256'1879  },1880  /**1881   * Lookup251: ethereum::transaction::EIP2930Transaction1882   **/1883  EthereumTransactionEip2930Transaction: {1884    chainId: 'u64',1885    nonce: 'U256',1886    gasPrice: 'U256',1887    gasLimit: 'U256',1888    action: 'EthereumTransactionTransactionAction',1889    value: 'U256',1890    input: 'Bytes',1891    accessList: 'Vec<EthereumTransactionAccessListItem>',1892    oddYParity: 'bool',1893    r: 'H256',1894    s: 'H256'1895  },1896  /**1897   * Lookup253: ethereum::transaction::AccessListItem1898   **/1899  EthereumTransactionAccessListItem: {1900    address: 'H160',1901    storageKeys: 'Vec<H256>'1902  },1903  /**1904   * Lookup254: ethereum::transaction::EIP1559Transaction1905   **/1906  EthereumTransactionEip1559Transaction: {1907    chainId: 'u64',1908    nonce: 'U256',1909    maxPriorityFeePerGas: 'U256',1910    maxFeePerGas: 'U256',1911    gasLimit: 'U256',1912    action: 'EthereumTransactionTransactionAction',1913    value: 'U256',1914    input: 'Bytes',1915    accessList: 'Vec<EthereumTransactionAccessListItem>',1916    oddYParity: 'bool',1917    r: 'H256',1918    s: 'H256'1919  },1920  /**1921   * Lookup255: pallet_evm_migration::pallet::Call<T>1922   **/1923  PalletEvmMigrationCall: {1924    _enum: {1925      begin: {1926        address: 'H160',1927      },1928      set_data: {1929        address: 'H160',1930        data: 'Vec<(H256,H256)>',1931      },1932      finish: {1933        address: 'H160',1934        code: 'Bytes'1935      }1936    }1937  },1938  /**1939   * Lookup258: pallet_sudo::pallet::Event<T>1940   **/1941  PalletSudoEvent: {1942    _enum: {1943      Sudid: {1944        sudoResult: 'Result<Null, SpRuntimeDispatchError>',1945      },1946      KeyChanged: {1947        oldSudoer: 'Option<AccountId32>',1948      },1949      SudoAsDone: {1950        sudoResult: 'Result<Null, SpRuntimeDispatchError>'1951      }1952    }1953  },1954  /**1955   * Lookup260: sp_runtime::DispatchError1956   **/1957  SpRuntimeDispatchError: {1958    _enum: {1959      Other: 'Null',1960      CannotLookup: 'Null',1961      BadOrigin: 'Null',1962      Module: 'SpRuntimeModuleError',1963      ConsumerRemaining: 'Null',1964      NoProviders: 'Null',1965      TooManyConsumers: 'Null',1966      Token: 'SpRuntimeTokenError',1967      Arithmetic: 'SpRuntimeArithmeticError',1968      Transactional: 'SpRuntimeTransactionalError'1969    }1970  },1971  /**1972   * Lookup261: sp_runtime::ModuleError1973   **/1974  SpRuntimeModuleError: {1975    index: 'u8',1976    error: '[u8;4]'1977  },1978  /**1979   * Lookup262: sp_runtime::TokenError1980   **/1981  SpRuntimeTokenError: {1982    _enum: ['NoFunds', 'WouldDie', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported']1983  },1984  /**1985   * Lookup263: sp_runtime::ArithmeticError1986   **/1987  SpRuntimeArithmeticError: {1988    _enum: ['Underflow', 'Overflow', 'DivisionByZero']1989  },1990  /**1991   * Lookup264: sp_runtime::TransactionalError1992   **/1993  SpRuntimeTransactionalError: {1994    _enum: ['LimitReached', 'NoLayer']1995  },1996  /**1997   * Lookup265: pallet_sudo::pallet::Error<T>1998   **/1999  PalletSudoError: {2000    _enum: ['RequireSudo']2001  },2002  /**2003   * Lookup266: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>2004   **/2005  FrameSystemAccountInfo: {2006    nonce: 'u32',2007    consumers: 'u32',2008    providers: 'u32',2009    sufficients: 'u32',2010    data: 'PalletBalancesAccountData'2011  },2012  /**2013   * Lookup267: frame_support::weights::PerDispatchClass<T>2014   **/2015  FrameSupportWeightsPerDispatchClassU64: {2016    normal: 'u64',2017    operational: 'u64',2018    mandatory: 'u64'2019  },2020  /**2021   * Lookup268: sp_runtime::generic::digest::Digest2022   **/2023  SpRuntimeDigest: {2024    logs: 'Vec<SpRuntimeDigestDigestItem>'2025  },2026  /**2027   * Lookup270: sp_runtime::generic::digest::DigestItem2028   **/2029  SpRuntimeDigestDigestItem: {2030    _enum: {2031      Other: 'Bytes',2032      __Unused1: 'Null',2033      __Unused2: 'Null',2034      __Unused3: 'Null',2035      Consensus: '([u8;4],Bytes)',2036      Seal: '([u8;4],Bytes)',2037      PreRuntime: '([u8;4],Bytes)',2038      __Unused7: 'Null',2039      RuntimeEnvironmentUpdated: 'Null'2040    }2041  },2042  /**2043   * Lookup272: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>2044   **/2045  FrameSystemEventRecord: {2046    phase: 'FrameSystemPhase',2047    event: 'Event',2048    topics: 'Vec<H256>'2049  },2050  /**2051   * Lookup274: frame_system::pallet::Event<T>2052   **/2053  FrameSystemEvent: {2054    _enum: {2055      ExtrinsicSuccess: {2056        dispatchInfo: 'FrameSupportWeightsDispatchInfo',2057      },2058      ExtrinsicFailed: {2059        dispatchError: 'SpRuntimeDispatchError',2060        dispatchInfo: 'FrameSupportWeightsDispatchInfo',2061      },2062      CodeUpdated: 'Null',2063      NewAccount: {2064        account: 'AccountId32',2065      },2066      KilledAccount: {2067        account: 'AccountId32',2068      },2069      Remarked: {2070        _alias: {2071          hash_: 'hash',2072        },2073        sender: 'AccountId32',2074        hash_: 'H256'2075      }2076    }2077  },2078  /**2079   * Lookup275: frame_support::weights::DispatchInfo2080   **/2081  FrameSupportWeightsDispatchInfo: {2082    weight: 'u64',2083    class: 'FrameSupportWeightsDispatchClass',2084    paysFee: 'FrameSupportWeightsPays'2085  },2086  /**2087   * Lookup276: frame_support::weights::DispatchClass2088   **/2089  FrameSupportWeightsDispatchClass: {2090    _enum: ['Normal', 'Operational', 'Mandatory']2091  },2092  /**2093   * Lookup277: frame_support::weights::Pays2094   **/2095  FrameSupportWeightsPays: {2096    _enum: ['Yes', 'No']2097  },2098  /**2099   * Lookup278: orml_vesting::module::Event<T>2100   **/2101  OrmlVestingModuleEvent: {2102    _enum: {2103      VestingScheduleAdded: {2104        from: 'AccountId32',2105        to: 'AccountId32',2106        vestingSchedule: 'OrmlVestingVestingSchedule',2107      },2108      Claimed: {2109        who: 'AccountId32',2110        amount: 'u128',2111      },2112      VestingSchedulesUpdated: {2113        who: 'AccountId32'2114      }2115    }2116  },2117  /**2118   * Lookup279: cumulus_pallet_xcmp_queue::pallet::Event<T>2119   **/2120  CumulusPalletXcmpQueueEvent: {2121    _enum: {2122      Success: 'Option<H256>',2123      Fail: '(Option<H256>,XcmV2TraitsError)',2124      BadVersion: 'Option<H256>',2125      BadFormat: 'Option<H256>',2126      UpwardMessageSent: 'Option<H256>',2127      XcmpMessageSent: 'Option<H256>',2128      OverweightEnqueued: '(u32,u32,u64,u64)',2129      OverweightServiced: '(u64,u64)'2130    }2131  },2132  /**2133   * Lookup280: pallet_xcm::pallet::Event<T>2134   **/2135  PalletXcmEvent: {2136    _enum: {2137      Attempted: 'XcmV2TraitsOutcome',2138      Sent: '(XcmV1MultiLocation,XcmV1MultiLocation,XcmV2Xcm)',2139      UnexpectedResponse: '(XcmV1MultiLocation,u64)',2140      ResponseReady: '(u64,XcmV2Response)',2141      Notified: '(u64,u8,u8)',2142      NotifyOverweight: '(u64,u8,u8,u64,u64)',2143      NotifyDispatchError: '(u64,u8,u8)',2144      NotifyDecodeFailed: '(u64,u8,u8)',2145      InvalidResponder: '(XcmV1MultiLocation,u64,Option<XcmV1MultiLocation>)',2146      InvalidResponderVersion: '(XcmV1MultiLocation,u64)',2147      ResponseTaken: 'u64',2148      AssetsTrapped: '(H256,XcmV1MultiLocation,XcmVersionedMultiAssets)',2149      VersionChangeNotified: '(XcmV1MultiLocation,u32)',2150      SupportedVersionChanged: '(XcmV1MultiLocation,u32)',2151      NotifyTargetSendFail: '(XcmV1MultiLocation,u64,XcmV2TraitsError)',2152      NotifyTargetMigrationFail: '(XcmVersionedMultiLocation,u64)'2153    }2154  },2155  /**2156   * Lookup281: xcm::v2::traits::Outcome2157   **/2158  XcmV2TraitsOutcome: {2159    _enum: {2160      Complete: 'u64',2161      Incomplete: '(u64,XcmV2TraitsError)',2162      Error: 'XcmV2TraitsError'2163    }2164  },2165  /**2166   * Lookup283: cumulus_pallet_xcm::pallet::Event<T>2167   **/2168  CumulusPalletXcmEvent: {2169    _enum: {2170      InvalidFormat: '[u8;8]',2171      UnsupportedVersion: '[u8;8]',2172      ExecutedDownward: '([u8;8],XcmV2TraitsOutcome)'2173    }2174  },2175  /**2176   * Lookup284: cumulus_pallet_dmp_queue::pallet::Event<T>2177   **/2178  CumulusPalletDmpQueueEvent: {2179    _enum: {2180      InvalidFormat: {2181        messageId: '[u8;32]',2182      },2183      UnsupportedVersion: {2184        messageId: '[u8;32]',2185      },2186      ExecutedDownward: {2187        messageId: '[u8;32]',2188        outcome: 'XcmV2TraitsOutcome',2189      },2190      WeightExhausted: {2191        messageId: '[u8;32]',2192        remainingWeight: 'u64',2193        requiredWeight: 'u64',2194      },2195      OverweightEnqueued: {2196        messageId: '[u8;32]',2197        overweightIndex: 'u64',2198        requiredWeight: 'u64',2199      },2200      OverweightServiced: {2201        overweightIndex: 'u64',2202        weightUsed: 'u64'2203      }2204    }2205  },2206  /**2207   * Lookup285: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2208   **/2209  PalletUniqueRawEvent: {2210    _enum: {2211      CollectionSponsorRemoved: 'u32',2212      CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2213      CollectionOwnedChanged: '(u32,AccountId32)',2214      CollectionSponsorSet: '(u32,AccountId32)',2215      SponsorshipConfirmed: '(u32,AccountId32)',2216      CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2217      AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2218      AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',2219      CollectionLimitSet: 'u32',2220      CollectionPermissionSet: 'u32'2221    }2222  },2223  /**2224   * Lookup286: pallet_unique_scheduler::pallet::Event<T>2225   **/2226  PalletUniqueSchedulerEvent: {2227    _enum: {2228      Scheduled: {2229        when: 'u32',2230        index: 'u32',2231      },2232      Canceled: {2233        when: 'u32',2234        index: 'u32',2235      },2236      Dispatched: {2237        task: '(u32,u32)',2238        id: 'Option<[u8;16]>',2239        result: 'Result<Null, SpRuntimeDispatchError>',2240      },2241      CallLookupFailed: {2242        task: '(u32,u32)',2243        id: 'Option<[u8;16]>',2244        error: 'FrameSupportScheduleLookupError'2245      }2246    }2247  },2248  /**2249   * Lookup288: frame_support::traits::schedule::LookupError2250   **/2251  FrameSupportScheduleLookupError: {2252    _enum: ['Unknown', 'BadFormat']2253  },2254  /**2255   * Lookup289: pallet_common::pallet::Event<T>2256   **/2257  PalletCommonEvent: {2258    _enum: {2259      CollectionCreated: '(u32,u8,AccountId32)',2260      CollectionDestroyed: 'u32',2261      ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2262      ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2263      Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2264      Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)',2265      CollectionPropertySet: '(u32,Bytes)',2266      CollectionPropertyDeleted: '(u32,Bytes)',2267      TokenPropertySet: '(u32,u32,Bytes)',2268      TokenPropertyDeleted: '(u32,u32,Bytes)',2269      PropertyPermissionSet: '(u32,Bytes)'2270    }2271  },2272  /**2273   * Lookup290: pallet_structure::pallet::Event<T>2274   **/2275  PalletStructureEvent: {2276    _enum: {2277      Executed: 'Result<Null, SpRuntimeDispatchError>'2278    }2279  },2280  /**2281   * Lookup291: pallet_rmrk_core::pallet::Event<T>2282   **/2283  PalletRmrkCoreEvent: {2284    _enum: {2285      CollectionCreated: {2286        issuer: 'AccountId32',2287        collectionId: 'u32',2288      },2289      CollectionDestroyed: {2290        issuer: 'AccountId32',2291        collectionId: 'u32',2292      },2293      IssuerChanged: {2294        oldIssuer: 'AccountId32',2295        newIssuer: 'AccountId32',2296        collectionId: 'u32',2297      },2298      CollectionLocked: {2299        issuer: 'AccountId32',2300        collectionId: 'u32',2301      },2302      NftMinted: {2303        owner: 'AccountId32',2304        collectionId: 'u32',2305        nftId: 'u32',2306      },2307      NFTBurned: {2308        owner: 'AccountId32',2309        nftId: 'u32',2310      },2311      NFTSent: {2312        sender: 'AccountId32',2313        recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2314        collectionId: 'u32',2315        nftId: 'u32',2316        approvalRequired: 'bool',2317      },2318      NFTAccepted: {2319        sender: 'AccountId32',2320        recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2321        collectionId: 'u32',2322        nftId: 'u32',2323      },2324      NFTRejected: {2325        sender: 'AccountId32',2326        collectionId: 'u32',2327        nftId: 'u32',2328      },2329      PropertySet: {2330        collectionId: 'u32',2331        maybeNftId: 'Option<u32>',2332        key: 'Bytes',2333        value: 'Bytes',2334      },2335      ResourceAdded: {2336        nftId: 'u32',2337        resourceId: 'u32',2338      },2339      ResourceRemoval: {2340        nftId: 'u32',2341        resourceId: 'u32',2342      },2343      ResourceAccepted: {2344        nftId: 'u32',2345        resourceId: 'u32',2346      },2347      ResourceRemovalAccepted: {2348        nftId: 'u32',2349        resourceId: 'u32',2350      },2351      PrioritySet: {2352        collectionId: 'u32',2353        nftId: 'u32'2354      }2355    }2356  },2357  /**2358   * Lookup292: pallet_rmrk_equip::pallet::Event<T>2359   **/2360  PalletRmrkEquipEvent: {2361    _enum: {2362      BaseCreated: {2363        issuer: 'AccountId32',2364        baseId: 'u32',2365      },2366      EquippablesUpdated: {2367        baseId: 'u32',2368        slotId: 'u32'2369      }2370    }2371  },2372  /**2373   * Lookup293: pallet_evm::pallet::Event<T>2374   **/2375  PalletEvmEvent: {2376    _enum: {2377      Log: 'EthereumLog',2378      Created: 'H160',2379      CreatedFailed: 'H160',2380      Executed: 'H160',2381      ExecutedFailed: 'H160',2382      BalanceDeposit: '(AccountId32,H160,U256)',2383      BalanceWithdraw: '(AccountId32,H160,U256)'2384    }2385  },2386  /**2387   * Lookup294: ethereum::log::Log2388   **/2389  EthereumLog: {2390    address: 'H160',2391    topics: 'Vec<H256>',2392    data: 'Bytes'2393  },2394  /**2395   * Lookup295: pallet_ethereum::pallet::Event2396   **/2397  PalletEthereumEvent: {2398    _enum: {2399      Executed: '(H160,H160,H256,EvmCoreErrorExitReason)'2400    }2401  },2402  /**2403   * Lookup296: evm_core::error::ExitReason2404   **/2405  EvmCoreErrorExitReason: {2406    _enum: {2407      Succeed: 'EvmCoreErrorExitSucceed',2408      Error: 'EvmCoreErrorExitError',2409      Revert: 'EvmCoreErrorExitRevert',2410      Fatal: 'EvmCoreErrorExitFatal'2411    }2412  },2413  /**2414   * Lookup297: evm_core::error::ExitSucceed2415   **/2416  EvmCoreErrorExitSucceed: {2417    _enum: ['Stopped', 'Returned', 'Suicided']2418  },2419  /**2420   * Lookup298: evm_core::error::ExitError2421   **/2422  EvmCoreErrorExitError: {2423    _enum: {2424      StackUnderflow: 'Null',2425      StackOverflow: 'Null',2426      InvalidJump: 'Null',2427      InvalidRange: 'Null',2428      DesignatedInvalid: 'Null',2429      CallTooDeep: 'Null',2430      CreateCollision: 'Null',2431      CreateContractLimit: 'Null',2432      OutOfOffset: 'Null',2433      OutOfGas: 'Null',2434      OutOfFund: 'Null',2435      PCUnderflow: 'Null',2436      CreateEmpty: 'Null',2437      Other: 'Text',2438      InvalidCode: 'Null'2439    }2440  },2441  /**2442   * Lookup301: evm_core::error::ExitRevert2443   **/2444  EvmCoreErrorExitRevert: {2445    _enum: ['Reverted']2446  },2447  /**2448   * Lookup302: evm_core::error::ExitFatal2449   **/2450  EvmCoreErrorExitFatal: {2451    _enum: {2452      NotSupported: 'Null',2453      UnhandledInterrupt: 'Null',2454      CallErrorAsFatal: 'EvmCoreErrorExitError',2455      Other: 'Text'2456    }2457  },2458  /**2459   * Lookup303: frame_system::Phase2460   **/2461  FrameSystemPhase: {2462    _enum: {2463      ApplyExtrinsic: 'u32',2464      Finalization: 'Null',2465      Initialization: 'Null'2466    }2467  },2468  /**2469   * Lookup305: frame_system::LastRuntimeUpgradeInfo2470   **/2471  FrameSystemLastRuntimeUpgradeInfo: {2472    specVersion: 'Compact<u32>',2473    specName: 'Text'2474  },2475  /**2476   * Lookup306: frame_system::limits::BlockWeights2477   **/2478  FrameSystemLimitsBlockWeights: {2479    baseBlock: 'u64',2480    maxBlock: 'u64',2481    perClass: 'FrameSupportWeightsPerDispatchClassWeightsPerClass'2482  },2483  /**2484   * Lookup307: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>2485   **/2486  FrameSupportWeightsPerDispatchClassWeightsPerClass: {2487    normal: 'FrameSystemLimitsWeightsPerClass',2488    operational: 'FrameSystemLimitsWeightsPerClass',2489    mandatory: 'FrameSystemLimitsWeightsPerClass'2490  },2491  /**2492   * Lookup308: frame_system::limits::WeightsPerClass2493   **/2494  FrameSystemLimitsWeightsPerClass: {2495    baseExtrinsic: 'u64',2496    maxExtrinsic: 'Option<u64>',2497    maxTotal: 'Option<u64>',2498    reserved: 'Option<u64>'2499  },2500  /**2501   * Lookup310: frame_system::limits::BlockLength2502   **/2503  FrameSystemLimitsBlockLength: {2504    max: 'FrameSupportWeightsPerDispatchClassU32'2505  },2506  /**2507   * Lookup311: frame_support::weights::PerDispatchClass<T>2508   **/2509  FrameSupportWeightsPerDispatchClassU32: {2510    normal: 'u32',2511    operational: 'u32',2512    mandatory: 'u32'2513  },2514  /**2515   * Lookup312: frame_support::weights::RuntimeDbWeight2516   **/2517  FrameSupportWeightsRuntimeDbWeight: {2518    read: 'u64',2519    write: 'u64'2520  },2521  /**2522   * Lookup313: sp_version::RuntimeVersion2523   **/2524  SpVersionRuntimeVersion: {2525    specName: 'Text',2526    implName: 'Text',2527    authoringVersion: 'u32',2528    specVersion: 'u32',2529    implVersion: 'u32',2530    apis: 'Vec<([u8;8],u32)>',2531    transactionVersion: 'u32',2532    stateVersion: 'u8'2533  },2534  /**2535   * Lookup317: frame_system::pallet::Error<T>2536   **/2537  FrameSystemError: {2538    _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']2539  },2540  /**2541   * Lookup319: orml_vesting::module::Error<T>2542   **/2543  OrmlVestingModuleError: {2544    _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']2545  },2546  /**2547   * Lookup321: cumulus_pallet_xcmp_queue::InboundChannelDetails2548   **/2549  CumulusPalletXcmpQueueInboundChannelDetails: {2550    sender: 'u32',2551    state: 'CumulusPalletXcmpQueueInboundState',2552    messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'2553  },2554  /**2555   * Lookup322: cumulus_pallet_xcmp_queue::InboundState2556   **/2557  CumulusPalletXcmpQueueInboundState: {2558    _enum: ['Ok', 'Suspended']2559  },2560  /**2561   * Lookup325: polkadot_parachain::primitives::XcmpMessageFormat2562   **/2563  PolkadotParachainPrimitivesXcmpMessageFormat: {2564    _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']2565  },2566  /**2567   * Lookup328: cumulus_pallet_xcmp_queue::OutboundChannelDetails2568   **/2569  CumulusPalletXcmpQueueOutboundChannelDetails: {2570    recipient: 'u32',2571    state: 'CumulusPalletXcmpQueueOutboundState',2572    signalsExist: 'bool',2573    firstIndex: 'u16',2574    lastIndex: 'u16'2575  },2576  /**2577   * Lookup329: cumulus_pallet_xcmp_queue::OutboundState2578   **/2579  CumulusPalletXcmpQueueOutboundState: {2580    _enum: ['Ok', 'Suspended']2581  },2582  /**2583   * Lookup331: cumulus_pallet_xcmp_queue::QueueConfigData2584   **/2585  CumulusPalletXcmpQueueQueueConfigData: {2586    suspendThreshold: 'u32',2587    dropThreshold: 'u32',2588    resumeThreshold: 'u32',2589    thresholdWeight: 'u64',2590    weightRestrictDecay: 'u64',2591    xcmpMaxIndividualWeight: 'u64'2592  },2593  /**2594   * Lookup333: cumulus_pallet_xcmp_queue::pallet::Error<T>2595   **/2596  CumulusPalletXcmpQueueError: {2597    _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']2598  },2599  /**2600   * Lookup334: pallet_xcm::pallet::Error<T>2601   **/2602  PalletXcmError: {2603    _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']2604  },2605  /**2606   * Lookup335: cumulus_pallet_xcm::pallet::Error<T>2607   **/2608  CumulusPalletXcmError: 'Null',2609  /**2610   * Lookup336: cumulus_pallet_dmp_queue::ConfigData2611   **/2612  CumulusPalletDmpQueueConfigData: {2613    maxIndividual: 'u64'2614  },2615  /**2616   * Lookup337: cumulus_pallet_dmp_queue::PageIndexData2617   **/2618  CumulusPalletDmpQueuePageIndexData: {2619    beginUsed: 'u32',2620    endUsed: 'u32',2621    overweightCount: 'u64'2622  },2623  /**2624   * Lookup340: cumulus_pallet_dmp_queue::pallet::Error<T>2625   **/2626  CumulusPalletDmpQueueError: {2627    _enum: ['Unknown', 'OverLimit']2628  },2629  /**2630   * Lookup344: pallet_unique::Error<T>2631   **/2632  PalletUniqueError: {2633    _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']2634  },2635  /**2636   * Lookup347: pallet_unique_scheduler::ScheduledV3<frame_support::traits::schedule::MaybeHashed<opal_runtime::Call, primitive_types::H256>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>2637   **/2638  PalletUniqueSchedulerScheduledV3: {2639    maybeId: 'Option<[u8;16]>',2640    priority: 'u8',2641    call: 'FrameSupportScheduleMaybeHashed',2642    maybePeriodic: 'Option<(u32,u32)>',2643    origin: 'OpalRuntimeOriginCaller'2644  },2645  /**2646   * Lookup348: opal_runtime::OriginCaller2647   **/2648  OpalRuntimeOriginCaller: {2649    _enum: {2650      __Unused0: 'Null',2651      __Unused1: 'Null',2652      __Unused2: 'Null',2653      __Unused3: 'Null',2654      Void: 'SpCoreVoid',2655      __Unused5: 'Null',2656      __Unused6: 'Null',2657      __Unused7: 'Null',2658      __Unused8: 'Null',2659      __Unused9: 'Null',2660      __Unused10: 'Null',2661      __Unused11: 'Null',2662      __Unused12: 'Null',2663      __Unused13: 'Null',2664      __Unused14: 'Null',2665      __Unused15: 'Null',2666      __Unused16: 'Null',2667      __Unused17: 'Null',2668      __Unused18: 'Null',2669      __Unused19: 'Null',2670      __Unused20: 'Null',2671      __Unused21: 'Null',2672      __Unused22: 'Null',2673      __Unused23: 'Null',2674      __Unused24: 'Null',2675      __Unused25: 'Null',2676      __Unused26: 'Null',2677      __Unused27: 'Null',2678      __Unused28: 'Null',2679      __Unused29: 'Null',2680      __Unused30: 'Null',2681      __Unused31: 'Null',2682      __Unused32: 'Null',2683      __Unused33: 'Null',2684      __Unused34: 'Null',2685      __Unused35: 'Null',2686      system: 'FrameSupportDispatchRawOrigin',2687      __Unused37: 'Null',2688      __Unused38: 'Null',2689      __Unused39: 'Null',2690      __Unused40: 'Null',2691      __Unused41: 'Null',2692      __Unused42: 'Null',2693      __Unused43: 'Null',2694      __Unused44: 'Null',2695      __Unused45: 'Null',2696      __Unused46: 'Null',2697      __Unused47: 'Null',2698      __Unused48: 'Null',2699      __Unused49: 'Null',2700      __Unused50: 'Null',2701      PolkadotXcm: 'PalletXcmOrigin',2702      CumulusXcm: 'CumulusPalletXcmOrigin',2703      __Unused53: 'Null',2704      __Unused54: 'Null',2705      __Unused55: 'Null',2706      __Unused56: 'Null',2707      __Unused57: 'Null',2708      __Unused58: 'Null',2709      __Unused59: 'Null',2710      __Unused60: 'Null',2711      __Unused61: 'Null',2712      __Unused62: 'Null',2713      __Unused63: 'Null',2714      __Unused64: 'Null',2715      __Unused65: 'Null',2716      __Unused66: 'Null',2717      __Unused67: 'Null',2718      __Unused68: 'Null',2719      __Unused69: 'Null',2720      __Unused70: 'Null',2721      __Unused71: 'Null',2722      __Unused72: 'Null',2723      __Unused73: 'Null',2724      __Unused74: 'Null',2725      __Unused75: 'Null',2726      __Unused76: 'Null',2727      __Unused77: 'Null',2728      __Unused78: 'Null',2729      __Unused79: 'Null',2730      __Unused80: 'Null',2731      __Unused81: 'Null',2732      __Unused82: 'Null',2733      __Unused83: 'Null',2734      __Unused84: 'Null',2735      __Unused85: 'Null',2736      __Unused86: 'Null',2737      __Unused87: 'Null',2738      __Unused88: 'Null',2739      __Unused89: 'Null',2740      __Unused90: 'Null',2741      __Unused91: 'Null',2742      __Unused92: 'Null',2743      __Unused93: 'Null',2744      __Unused94: 'Null',2745      __Unused95: 'Null',2746      __Unused96: 'Null',2747      __Unused97: 'Null',2748      __Unused98: 'Null',2749      __Unused99: 'Null',2750      __Unused100: 'Null',2751      Ethereum: 'PalletEthereumRawOrigin'2752    }2753  },2754  /**2755   * Lookup349: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>2756   **/2757  FrameSupportDispatchRawOrigin: {2758    _enum: {2759      Root: 'Null',2760      Signed: 'AccountId32',2761      None: 'Null'2762    }2763  },2764  /**2765   * Lookup350: pallet_xcm::pallet::Origin2766   **/2767  PalletXcmOrigin: {2768    _enum: {2769      Xcm: 'XcmV1MultiLocation',2770      Response: 'XcmV1MultiLocation'2771    }2772  },2773  /**2774   * Lookup351: cumulus_pallet_xcm::pallet::Origin2775   **/2776  CumulusPalletXcmOrigin: {2777    _enum: {2778      Relay: 'Null',2779      SiblingParachain: 'u32'2780    }2781  },2782  /**2783   * Lookup352: pallet_ethereum::RawOrigin2784   **/2785  PalletEthereumRawOrigin: {2786    _enum: {2787      EthereumTransaction: 'H160'2788    }2789  },2790  /**2791   * Lookup353: sp_core::Void2792   **/2793  SpCoreVoid: 'Null',2794  /**2795   * Lookup354: pallet_unique_scheduler::pallet::Error<T>2796   **/2797  PalletUniqueSchedulerError: {2798    _enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange']2799  },2800  /**2801   * Lookup355: up_data_structs::Collection<sp_core::crypto::AccountId32>2802   **/2803  UpDataStructsCollection: {2804    owner: 'AccountId32',2805    mode: 'UpDataStructsCollectionMode',2806    name: 'Vec<u16>',2807    description: 'Vec<u16>',2808    tokenPrefix: 'Bytes',2809    sponsorship: 'UpDataStructsSponsorshipState',2810    limits: 'UpDataStructsCollectionLimits',2811    permissions: 'UpDataStructsCollectionPermissions',2812    externalCollection: 'bool'2813  },2814  /**2815   * Lookup356: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>2816   **/2817  UpDataStructsSponsorshipState: {2818    _enum: {2819      Disabled: 'Null',2820      Unconfirmed: 'AccountId32',2821      Confirmed: 'AccountId32'2822    }2823  },2824  /**2825   * Lookup357: up_data_structs::Properties2826   **/2827  UpDataStructsProperties: {2828    map: 'UpDataStructsPropertiesMapBoundedVec',2829    consumedSpace: 'u32',2830    spaceLimit: 'u32'2831  },2832  /**2833   * Lookup358: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>2834   **/2835  UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',2836  /**2837   * Lookup363: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>2838   **/2839  UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',2840  /**2841   * Lookup370: up_data_structs::CollectionStats2842   **/2843  UpDataStructsCollectionStats: {2844    created: 'u32',2845    destroyed: 'u32',2846    alive: 'u32'2847  },2848  /**2849   * Lookup371: up_data_structs::TokenChild2850   **/2851  UpDataStructsTokenChild: {2852    token: 'u32',2853    collection: 'u32'2854  },2855  /**2856   * Lookup372: PhantomType::up_data_structs<T>2857   **/2858  PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',2859  /**2860   * Lookup374: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2861   **/2862  UpDataStructsTokenData: {2863    properties: 'Vec<UpDataStructsProperty>',2864    owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>',2865    pieces: 'u128'2866  },2867  /**2868   * Lookup376: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>2869   **/2870  UpDataStructsRpcCollection: {2871    owner: 'AccountId32',2872    mode: 'UpDataStructsCollectionMode',2873    name: 'Vec<u16>',2874    description: 'Vec<u16>',2875    tokenPrefix: 'Bytes',2876    sponsorship: 'UpDataStructsSponsorshipState',2877    limits: 'UpDataStructsCollectionLimits',2878    permissions: 'UpDataStructsCollectionPermissions',2879    tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',2880    properties: 'Vec<UpDataStructsProperty>',2881    readOnly: 'bool'2882  },2883  /**2884   * Lookup377: rmrk_traits::collection::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>2885   **/2886  RmrkTraitsCollectionCollectionInfo: {2887    issuer: 'AccountId32',2888    metadata: 'Bytes',2889    max: 'Option<u32>',2890    symbol: 'Bytes',2891    nftsCount: 'u32'2892  },2893  /**2894   * Lookup378: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>2895   **/2896  RmrkTraitsNftNftInfo: {2897    owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',2898    royalty: 'Option<RmrkTraitsNftRoyaltyInfo>',2899    metadata: 'Bytes',2900    equipped: 'bool',2901    pending: 'bool'2902  },2903  /**2904   * Lookup380: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>2905   **/2906  RmrkTraitsNftRoyaltyInfo: {2907    recipient: 'AccountId32',2908    amount: 'Permill'2909  },2910  /**2911   * Lookup381: rmrk_traits::resource::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>2912   **/2913  RmrkTraitsResourceResourceInfo: {2914    id: 'u32',2915    resource: 'RmrkTraitsResourceResourceTypes',2916    pending: 'bool',2917    pendingRemoval: 'bool'2918  },2919  /**2920   * Lookup382: rmrk_traits::property::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>2921   **/2922  RmrkTraitsPropertyPropertyInfo: {2923    key: 'Bytes',2924    value: 'Bytes'2925  },2926  /**2927   * Lookup383: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>2928   **/2929  RmrkTraitsBaseBaseInfo: {2930    issuer: 'AccountId32',2931    baseType: 'Bytes',2932    symbol: 'Bytes'2933  },2934  /**2935   * Lookup384: rmrk_traits::nft::NftChild2936   **/2937  RmrkTraitsNftNftChild: {2938    collectionId: 'u32',2939    nftId: 'u32'2940  },2941  /**2942   * Lookup386: pallet_common::pallet::Error<T>2943   **/2944  PalletCommonError: {2945    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal']2946  },2947  /**2948   * Lookup388: pallet_fungible::pallet::Error<T>2949   **/2950  PalletFungibleError: {2951    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']2952  },2953  /**2954   * Lookup389: pallet_refungible::ItemData2955   **/2956  PalletRefungibleItemData: {2957    constData: 'Bytes'2958  },2959  /**2960   * Lookup393: pallet_refungible::pallet::Error<T>2961   **/2962  PalletRefungibleError: {2963    _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']2964  },2965  /**2966   * Lookup394: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>2967   **/2968  PalletNonfungibleItemData: {2969    owner: 'PalletEvmAccountBasicCrossAccountIdRepr'2970  },2971  /**2972   * Lookup396: up_data_structs::PropertyScope2973   **/2974  UpDataStructsPropertyScope: {2975    _enum: ['None', 'Rmrk']2976  },2977  /**2978   * Lookup398: pallet_nonfungible::pallet::Error<T>2979   **/2980  PalletNonfungibleError: {2981    _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']2982  },2983  /**2984   * Lookup399: pallet_structure::pallet::Error<T>2985   **/2986  PalletStructureError: {2987    _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']2988  },2989  /**2990   * Lookup400: pallet_rmrk_core::pallet::Error<T>2991   **/2992  PalletRmrkCoreError: {2993    _enum: ['CorruptedCollectionType', 'NftTypeEncodeError', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId']2994  },2995  /**2996   * Lookup402: pallet_rmrk_equip::pallet::Error<T>2997   **/2998  PalletRmrkEquipError: {2999    _enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']3000  },3001  /**3002   * Lookup405: pallet_evm::pallet::Error<T>3003   **/3004  PalletEvmError: {3005    _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']3006  },3007  /**3008   * Lookup408: fp_rpc::TransactionStatus3009   **/3010  FpRpcTransactionStatus: {3011    transactionHash: 'H256',3012    transactionIndex: 'u32',3013    from: 'H160',3014    to: 'Option<H160>',3015    contractAddress: 'Option<H160>',3016    logs: 'Vec<EthereumLog>',3017    logsBloom: 'EthbloomBloom'3018  },3019  /**3020   * Lookup410: ethbloom::Bloom3021   **/3022  EthbloomBloom: '[u8;256]',3023  /**3024   * Lookup412: ethereum::receipt::ReceiptV33025   **/3026  EthereumReceiptReceiptV3: {3027    _enum: {3028      Legacy: 'EthereumReceiptEip658ReceiptData',3029      EIP2930: 'EthereumReceiptEip658ReceiptData',3030      EIP1559: 'EthereumReceiptEip658ReceiptData'3031    }3032  },3033  /**3034   * Lookup413: ethereum::receipt::EIP658ReceiptData3035   **/3036  EthereumReceiptEip658ReceiptData: {3037    statusCode: 'u8',3038    usedGas: 'U256',3039    logsBloom: 'EthbloomBloom',3040    logs: 'Vec<EthereumLog>'3041  },3042  /**3043   * Lookup414: ethereum::block::Block<ethereum::transaction::TransactionV2>3044   **/3045  EthereumBlock: {3046    header: 'EthereumHeader',3047    transactions: 'Vec<EthereumTransactionTransactionV2>',3048    ommers: 'Vec<EthereumHeader>'3049  },3050  /**3051   * Lookup415: ethereum::header::Header3052   **/3053  EthereumHeader: {3054    parentHash: 'H256',3055    ommersHash: 'H256',3056    beneficiary: 'H160',3057    stateRoot: 'H256',3058    transactionsRoot: 'H256',3059    receiptsRoot: 'H256',3060    logsBloom: 'EthbloomBloom',3061    difficulty: 'U256',3062    number: 'U256',3063    gasLimit: 'U256',3064    gasUsed: 'U256',3065    timestamp: 'u64',3066    extraData: 'Bytes',3067    mixHash: 'H256',3068    nonce: 'EthereumTypesHashH64'3069  },3070  /**3071   * Lookup416: ethereum_types::hash::H643072   **/3073  EthereumTypesHashH64: '[u8;8]',3074  /**3075   * Lookup421: pallet_ethereum::pallet::Error<T>3076   **/3077  PalletEthereumError: {3078    _enum: ['InvalidSignature', 'PreLogExists']3079  },3080  /**3081   * Lookup422: pallet_evm_coder_substrate::pallet::Error<T>3082   **/3083  PalletEvmCoderSubstrateError: {3084    _enum: ['OutOfGas', 'OutOfFund']3085  },3086  /**3087   * Lookup423: pallet_evm_contract_helpers::SponsoringModeT3088   **/3089  PalletEvmContractHelpersSponsoringModeT: {3090    _enum: ['Disabled', 'Allowlisted', 'Generous']3091  },3092  /**3093   * Lookup425: pallet_evm_contract_helpers::pallet::Error<T>3094   **/3095  PalletEvmContractHelpersError: {3096    _enum: ['NoPermission']3097  },3098  /**3099   * Lookup426: pallet_evm_migration::pallet::Error<T>3100   **/3101  PalletEvmMigrationError: {3102    _enum: ['AccountNotEmpty', 'AccountIsNotMigrating']3103  },3104  /**3105   * Lookup428: sp_runtime::MultiSignature3106   **/3107  SpRuntimeMultiSignature: {3108    _enum: {3109      Ed25519: 'SpCoreEd25519Signature',3110      Sr25519: 'SpCoreSr25519Signature',3111      Ecdsa: 'SpCoreEcdsaSignature'3112    }3113  },3114  /**3115   * Lookup429: sp_core::ed25519::Signature3116   **/3117  SpCoreEd25519Signature: '[u8;64]',3118  /**3119   * Lookup431: sp_core::sr25519::Signature3120   **/3121  SpCoreSr25519Signature: '[u8;64]',3122  /**3123   * Lookup432: sp_core::ecdsa::Signature3124   **/3125  SpCoreEcdsaSignature: '[u8;65]',3126  /**3127   * Lookup435: frame_system::extensions::check_spec_version::CheckSpecVersion<T>3128   **/3129  FrameSystemExtensionsCheckSpecVersion: 'Null',3130  /**3131   * Lookup436: frame_system::extensions::check_genesis::CheckGenesis<T>3132   **/3133  FrameSystemExtensionsCheckGenesis: 'Null',3134  /**3135   * Lookup439: frame_system::extensions::check_nonce::CheckNonce<T>3136   **/3137  FrameSystemExtensionsCheckNonce: 'Compact<u32>',3138  /**3139   * Lookup440: frame_system::extensions::check_weight::CheckWeight<T>3140   **/3141  FrameSystemExtensionsCheckWeight: 'Null',3142  /**3143   * Lookup441: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>3144   **/3145  PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',3146  /**3147   * Lookup442: opal_runtime::Runtime3148   **/3149  OpalRuntimeRuntime: 'Null',3150  /**3151   * Lookup443: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>3152   **/3153  PalletEthereumFakeTransactionFinalizer: 'Null'3154};
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1629,6 +1629,7 @@
   export interface UpDataStructsCreateReFungibleData extends Struct {
     readonly constData: Bytes;
     readonly pieces: u128;
+    readonly properties: Vec<UpDataStructsProperty>;
   }
 
   /** @name UpDataStructsCreateItemExData (193) */
@@ -1654,6 +1655,7 @@
   export interface UpDataStructsCreateRefungibleExData extends Struct {
     readonly constData: Bytes;
     readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
+    readonly properties: Vec<UpDataStructsProperty>;
   }
 
   /** @name PalletUniqueSchedulerCall (204) */
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -63,6 +63,11 @@
       [collectionParam, tokenParam], 
       `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
     ),
+    tokenOwners: fun(
+      'Returns 10 tokens owners in no particular order', 
+      [collectionParam, tokenParam], 
+      `Vec<${CROSS_ACCOUNT_ID_TYPE}>`
+    ),
     tokenChildren: fun(
       'Get tokens nested directly into the token', 
       [collectionParam, tokenParam], 
@@ -85,6 +90,17 @@
       'Vec<UpDataStructsPropertyKeyPermission>',
     ),
 
+    constMetadata: fun(
+      'Get token constant metadata', 
+      [collectionParam, tokenParam], 
+      'Vec<u8>',
+    ),
+    variableMetadata: fun(
+      'Get token variable metadata', 
+      [collectionParam, tokenParam], 
+      'Vec<u8>',
+    ),
+
     tokenData: fun(
       'Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT',
       [collectionParam, tokenParam, propertyKeysParam],
@@ -128,7 +144,11 @@
       'bool',
     ),
 
-    lastTokenId: fun('Get the last token ID created in a collection', [collectionParam], 'u32'),
+    lastTokenId: fun(
+      'Get the last token ID created in a collection', 
+      [collectionParam], 
+      'u32',
+    ),
     collectionById: fun(
       'Get a collection by the specified ID', 
       [collectionParam], 
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -2,6 +2,7 @@
 import usingApi, {executeTransaction} from '../substrate/substrate-api';
 import {
   addCollectionAdminExpectSuccess,
+  CollectionMode,
   createCollectionExpectSuccess,
   setCollectionPermissionsExpectSuccess,
   createItemExpectSuccess,
@@ -23,9 +24,9 @@
     });
   });
 
-  it('Makes sure collectionById supplies required fields', async () => {
+  async function testMakeSureSuppliesRequired(mode: CollectionMode) {
     await usingApi(async api => {
-      const collectionId = await createCollectionExpectSuccess();
+      const collectionId = await createCollectionExpectSuccess({mode: mode});
 
       const collectionOption = await api.rpc.unique.collectionById(collectionId);
       expect(collectionOption.isSome).to.be.true;
@@ -57,7 +58,15 @@
       expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);
       expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);
     });
+  }
+
+  it('Makes sure collectionById supplies required fields for NFT', async () => {
+    await testMakeSureSuppliesRequired({type: 'NFT'});
   });
+
+  it('Makes sure collectionById supplies required fields for ReFungible', async () => {
+    await testMakeSureSuppliesRequired({type: 'ReFungible'});
+  });
 });
 
 // ---------- COLLECTION PROPERTIES
@@ -79,9 +88,10 @@
     });
   });
 
-  it('Sets properties for a collection', async () => {
+
+  async function testSetsPropertiesForCollection(mode: string) {
     await usingApi(async api => {
-      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));
+      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));
       const {collectionId} = getCreateCollectionResult(events);
 
       // As owner
@@ -106,48 +116,54 @@
         {key: 'black_hole', value: ''},
       ]);
     });
+  }
+  it('Sets properties for a NFT collection', async () => {
+    await testSetsPropertiesForCollection('NFT');
   });
+  it('Sets properties for a ReFungible collection', async () => {
+    await testSetsPropertiesForCollection('ReFungible');
+  });
 
-  it('Check valid names for collection properties keys', async () => {
+  async function testCheckValidNames(mode: string) {
     await usingApi(async api => {
-      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));
+      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));
       const {collectionId} = getCreateCollectionResult(events);
-
+  
       // alpha symbols
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 
       )).to.not.be.rejected;
-
+  
       // numeric symbols
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 
       )).to.not.be.rejected;
-
+  
       // underscore symbol
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 
       )).to.not.be.rejected;
-
+  
       // dash symbol
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 
       )).to.not.be.rejected;
-
+  
       // underscore symbol
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 
       )).to.not.be.rejected;
-
+  
       const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];
       const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();
       expect(properties).to.be.deep.equal([
@@ -158,54 +174,72 @@
         {key: 'build.rs', value: ''},
       ]);
     });
+  }
+  it('Check valid names for NFT collection properties keys', async () => {
+    await testCheckValidNames('NFT');
+  });
+  it('Check valid names for ReFungible collection properties keys', async () => {
+    await testCheckValidNames('ReFungible');
   });
 
-  it('Changes properties of a collection', async () => {
+  async function testChangesProperties(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 
       )).to.not.be.rejected;
-
+  
       // Mutate the properties
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 
       )).to.not.be.rejected;
-
+  
       const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();
       expect(properties).to.be.deep.equal([
         {key: 'electron', value: 'bonded'},
         {key: 'black_hole', value: 'LIGO'},
       ]);
     });
+  }
+  it('Changes properties of a NFT collection', async () => {
+    await testChangesProperties({type: 'NFT'});
+  });
+  it('Changes properties of a ReFungible collection', async () => {
+    await testChangesProperties({type: 'ReFungible'});
   });
 
-  it('Deletes properties of a collection', async () => {
+  async function testDeleteProperties(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 
       )).to.not.be.rejected;
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.deleteCollectionProperties(collection, ['electron']), 
       )).to.not.be.rejected;
-
+  
       const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();
       expect(properties).to.be.deep.equal([
         {key: 'black_hole', value: 'LIGO'},
       ]);
-    });
+    });  
+  }
+  it('Deletes properties of a NFT collection', async () => {
+    await testDeleteProperties({type: 'NFT'});
+  });
+  it('Deletes properties of a ReFungible collection', async () => {
+    await testDeleteProperties({type: 'ReFungible'});
   });
 });
 
@@ -217,10 +251,10 @@
     });
   });
   
-  it('Fails to set properties in a collection if not its onwer/administrator', async () => {
+  async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         bob, 
@@ -230,14 +264,20 @@
       const properties = (await api.query.common.collectionProperties(collection)).toJSON();
       expect(properties.map).to.be.empty;
       expect(properties.consumedSpace).to.equal(0);
-    });
+    });  
+  }
+  it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {
+    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});
   });
+  it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {
+    await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});
+  });
   
-  it('Fails to set properties that exceed the limits', async () => {
+  async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
+      const collection = await createCollectionExpectSuccess({mode: mode});
       const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 
-
+  
       // Mute the general tx parsing error, too many bytes to process
       {
         console.error = () => {};
@@ -247,10 +287,10 @@
           api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 
         )).to.be.rejected;
       }
-
+  
       let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();
       expect(properties).to.be.empty;
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
@@ -259,16 +299,22 @@
           {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 
         ]), 
       )).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
+  
       properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();
       expect(properties).to.be.empty;
-    });
+    });  
+  }
+  it('Fails to set properties that exceed the limits (NFT)', async () => {
+    await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});
+  });
+  it('Fails to set properties that exceed the limits (ReFungible)', async () => {
+    await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});
   });
   
-  it('Fails to set more properties than it is allowed', async () => {
+  async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       const propertiesToBeSet = [];
       for (let i = 0; i < 65; i++) {
         propertiesToBeSet.push({
@@ -276,29 +322,35 @@
           value: Math.random() > 0.5 ? 'high' : 'low',
         });
       }
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 
       )).to.be.rejectedWith(/common\.PropertyLimitReached/);
-
+  
       const properties = (await api.query.common.collectionProperties(collection)).toJSON();
       expect(properties.map).to.be.empty;
       expect(properties.consumedSpace).to.equal(0);
-    });
+    });  
+  }
+  it('Fails to set more properties than it is allowed (NFT)', async () => {
+    await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});
   });
-
-  it('Fails to set properties with invalid names', async () => {
+  it('Fails to set more properties than it is allowed (ReFungible)', async () => {
+    await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});
+  });
+  
+  async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       const invalidProperties = [
         [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
         [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
         [{key: 'déjà vu', value: 'hmm...'}],
       ];
-
+  
       for (let i = 0; i < invalidProperties.length; i++) {
         await expect(executeTransaction(
           api, 
@@ -306,13 +358,13 @@
           api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 
         ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
       }
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 
       ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
@@ -320,14 +372,14 @@
           {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
         ]), 
       ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;
-
+  
       const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
-
+  
       const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();
       expect(properties).to.be.deep.equal([
         {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
       ]);
-
+  
       for (let i = 0; i < invalidProperties.length; i++) {
         await expect(executeTransaction(
           api, 
@@ -336,7 +388,13 @@
         ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
       }
     });
+  }
+  it('Fails to set properties with invalid names (NFT)', async () => {
+    await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});
   });
+  it('Fails to set properties with invalid names (ReFungible)', async () => {
+    await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});
+  });
 });
 
 // ---------- ACCESS RIGHTS
@@ -357,54 +415,66 @@
     });
   });
   
-  it('Sets access rights to properties of a collection', async () => {
+  async function testSetsAccessRightsToProperties(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 
       )).to.not.be.rejected;
-
+  
       await addCollectionAdminExpectSuccess(alice, collection, bob.address);
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 
       )).to.not.be.rejected;
-
+  
       const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();
       expect(propertyRights).to.be.deep.equal([
         {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},
         {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},
       ]);
-    });
+    });  
+  }
+  it('Sets access rights to properties of a collection (NFT)', async () => {
+    await testSetsAccessRightsToProperties({type: 'NFT'});
   });
+  it('Sets access rights to properties of a collection (ReFungible)', async () => {
+    await testSetsAccessRightsToProperties({type: 'ReFungible'});
+  });
   
-  it('Changes access rights to properties of a collection', async () => {
+  async function testChangesAccessRightsToProperty(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 
       )).to.not.be.rejected;
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 
       )).to.not.be.rejected;
-
+  
       const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();
       expect(propertyRights).to.be.deep.equal([
         {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
       ]);
     });
+  }
+  it('Changes access rights to properties of a NFT collection', async () => {
+    await testChangesAccessRightsToProperty({type: 'NFT'});
   });
+  it('Changes access rights to properties of a ReFungible collection', async () => {
+    await testChangesAccessRightsToProperty({type: 'ReFungible'});
+  });
 });
 
 describe('Negative Integration Test: Access Rights to Token Properties', () => {
@@ -415,25 +485,31 @@
     });
   });
 
-  it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {
+  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         bob, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 
       )).to.be.rejectedWith(/common\.NoPermission/);
-
+  
       const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();
       expect(propertyRights).to.be.empty;
     });
+  }
+  it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {
+    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});
   });
+  it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {
+    await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});
+  });
 
-  it('Prevents from adding too many possible properties', async () => {
+  async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       const constitution = [];
       for (let i = 0; i < 65; i++) {
         constitution.push({
@@ -441,51 +517,63 @@
           permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
         });
       }
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, constitution), 
       )).to.be.rejectedWith(/common\.PropertyLimitReached/);
-
+  
       const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();
       expect(propertyRights).to.be.empty;
-    });
+    });  
+  }
+  it('Prevents from adding too many possible properties (NFT)', async () => {
+    await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});
   });
+  it('Prevents from adding too many possible properties (ReFungible)', async () => {
+    await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});
+  });
 
-  it('Prevents access rights to be modified if constant', async () => {
+  async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 
       )).to.not.be.rejected;
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 
       )).to.be.rejectedWith(/common\.NoPermission/);
-
+  
       const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();
       expect(propertyRights).to.deep.equal([
         {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
       ]);
-    });
+    });  
+  }
+  it('Prevents access rights to be modified if constant (NFT)', async () => {
+    await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});
+  });
+  it('Prevents access rights to be modified if constant (ReFungible)', async () => {
+    await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});
   });
 
-  it('Prevents adding properties with invalid names', async () => {
+  async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-
+      const collection = await createCollectionExpectSuccess({mode: mode});
+  
       const invalidProperties = [
         [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
         [{key: 'G#4', permission: {tokenOwner: true}}],
         [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
       ];
-
+  
       for (let i = 0; i < invalidProperties.length; i++) {
         await expect(executeTransaction(
           api, 
@@ -493,13 +581,13 @@
           api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 
         ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
       }
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 
       ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
+  
       const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
       await expect(executeTransaction(
         api, 
@@ -508,30 +596,33 @@
           {key: correctKey, permission: {collectionAdmin: true}},
         ]), 
       ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;
-
+  
       const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
-
+  
       const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();
       expect(propertyRights).to.be.deep.equal([
         {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
       ]);
     });
+  }
+  it('Prevents adding properties with invalid names (NFT)', async () => {
+    await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});
+  });
+  it('Prevents adding properties with invalid names (ReFungible)', async () => {
+    await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});
   });
 });
 
 // ---------- TOKEN PROPERTIES
 
 describe('Integration Test: Token Properties', () => {
-  let collection: number;
-  let token: number;
-  let nestedToken: number;
   let permissions: {permission: any, signers: IKeyringPair[]}[];
 
   before(async () => {
     await usingApi(async (api, privateKeyWrapper) => {
-      alice = privateKeyWrapper('//Alice');
-      bob = privateKeyWrapper('//Bob');
-      charlie = privateKeyWrapper('//Charlie');
+      alice = privateKeyWrapper('//Alice'); // collection owner
+      bob = privateKeyWrapper('//Bob'); // collection admin
+      charlie = privateKeyWrapper('//Charlie'); // token owner
 
       permissions = [
         {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
@@ -543,36 +634,34 @@
       ];
     });
   });
-
-  beforeEach(async () => {
-    await usingApi(async () => {
-      collection = await createCollectionExpectSuccess();
-      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
-
-      token = await createItemExpectSuccess(alice, collection, 'NFT');
-      nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
-
-      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
-      await transferExpectSuccess(collection, token, alice, charlie);
-    });
-  });
   
-  it('Reads yet empty properties of a token', async () => {
+  async function testReadsYetEmptyProperties(mode: CollectionMode) {
     await usingApi(async api => {
-      const collection = await createCollectionExpectSuccess();
-      const token = await createItemExpectSuccess(alice, collection, 'NFT');
+      const collection = await createCollectionExpectSuccess({mode: mode});
+      const token = await createItemExpectSuccess(alice, collection, mode.type);
   
       const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
       expect(properties.map).to.be.empty;
       expect(properties.consumedSpace).to.be.equal(0);
-
+  
       const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;
       expect(tokenData).to.be.empty;
     });
+  }
+  it('Reads yet empty properties of a token (NFT)', async () => {
+    await testReadsYetEmptyProperties({type: 'NFT'});
   });
+  it('Reads yet empty properties of a token (ReFungible)', async () => {
+    await testReadsYetEmptyProperties({type: 'ReFungible'});
+  });
 
-  it('Assigns properties to a token according to permissions', async () => {
+  async function testAssignPropertiesAccordingToPermissions(mode: CollectionMode, pieces: number) {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: mode});
+      const token = await createItemExpectSuccess(alice, collection, mode.type);
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);
+
       const propertyKeys: string[] = [];
       let i = 0;
       for (const permission of permissions) {
@@ -603,10 +692,21 @@
         expect(tokensData[i].value).to.be.equal('Serotonin increase');
       }
     });
+  }
+  it('Assigns properties to a token according to permissions (NFT)', async () => {
+    await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);
+  });
+  it('Assigns properties to a token according to permissions (ReFungible)', async () => {
+    await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);
   });
 
-  it('Changes properties of a token according to permissions', async () => {
+  async function testChangesPropertiesAccordingPermission(mode: CollectionMode, pieces: number) {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: mode});
+      const token = await createItemExpectSuccess(alice, collection, mode.type);
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);
+
       const propertyKeys: string[] = [];
       let i = 0;
       for (const permission of permissions) {
@@ -615,29 +715,29 @@
         for (const signer of permission.signers) {
           const key = i + '_' + signer.address;
           propertyKeys.push(key);
-
+  
           await expect(executeTransaction(
             api, 
             alice, 
             api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 
           ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
           await expect(executeTransaction(
             api, 
             signer, 
             api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 
           ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
           await expect(executeTransaction(
             api, 
             signer, 
             api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 
           ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;
         }
-
+  
         i++;
       }
-
+  
       const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];
       const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];
       for (let i = 0; i < properties.length; i++) {
@@ -645,32 +745,43 @@
         expect(tokensData[i].value).to.be.equal('Serotonin stable');
       }
     });
+  }
+  it('Changes properties of a token according to permissions (NFT)', async () => {
+    await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);
   });
+  it('Changes properties of a token according to permissions (ReFungible)', async () => {
+    await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);
+  });
 
-  it('Deletes properties of a token according to permissions', async () => {
+  async function testDeletePropertiesAccordingPermission(mode: CollectionMode, pieces: number) {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: mode});
+      const token = await createItemExpectSuccess(alice, collection, mode.type);
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);
+
       const propertyKeys: string[] = [];
       let i = 0;
-
+  
       for (const permission of permissions) {
         if (!permission.permission.mutable) continue;
         
         for (const signer of permission.signers) {
           const key = i + '_' + signer.address;
           propertyKeys.push(key);
-
+  
           await expect(executeTransaction(
             api, 
             alice, 
             api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 
           ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
           await expect(executeTransaction(
             api, 
             signer, 
             api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 
           ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
           await expect(executeTransaction(
             api, 
             signer, 
@@ -680,17 +791,30 @@
         
         i++;
       }
-
+  
       const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];
       expect(properties).to.be.empty;
       const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];
       expect(tokensData).to.be.empty;
       expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);
     });
+  }
+  it('Deletes properties of a token according to permissions (NFT)', async () => {
+    await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);
   });
+  it('Deletes properties of a token according to permissions (ReFungible)', async () => {
+    await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);
+  });
 
   it('Assigns properties to a nested token according to permissions', async () => {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
+      const token = await createItemExpectSuccess(alice, collection, 'NFT');
+      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie);
+
       const propertyKeys: string[] = [];
       let i = 0;
       for (const permission of permissions) {
@@ -725,6 +849,13 @@
 
   it('Changes properties of a nested token according to permissions', async () => {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
+      const token = await createItemExpectSuccess(alice, collection, 'NFT');
+      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie);
+
       const propertyKeys: string[] = [];
       let i = 0;
       for (const permission of permissions) {
@@ -767,6 +898,13 @@
 
   it('Deletes properties of a nested token according to permissions', async () => {
     await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+      await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
+      const token = await createItemExpectSuccess(alice, collection, 'NFT');
+      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+      await transferExpectSuccess(collection, token, alice, charlie);
+
       const propertyKeys: string[] = [];
       let i = 0;
 
@@ -832,11 +970,11 @@
     });
   });
 
-  beforeEach(async () => {
-    collection = await createCollectionExpectSuccess();
-    token = await createItemExpectSuccess(alice, collection, 'NFT');
+  async function prepare(mode: CollectionMode, pieces: number) {
+    collection = await createCollectionExpectSuccess({mode: mode});
+    token = await createItemExpectSuccess(alice, collection, mode.type);
     await addCollectionAdminExpectSuccess(alice, collection, bob.address);
-    await transferExpectSuccess(collection, token, alice, charlie);
+    await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);
         
     await usingApi(async api => {
       let i = 0;
@@ -848,71 +986,89 @@
           alice, 
           api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 
         ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
         await expect(executeTransaction(
           api, 
           signer, 
           api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 
         ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
-
+  
         i++;
       }
-
+  
       originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;
-    });
-  });
+    }); 
+  }
 
-  it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {
+  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(mode: CollectionMode, pieces: number) {
+    await prepare(mode, pieces);
+  
     await usingApi(async api => {
       let i = -1;
       for (const forbiddance of constitution) {
         i++;
         if (!forbiddance.permission.mutable) continue;
-
+  
         await expect(executeTransaction(
           api, 
           forbiddance.sinner, 
           api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 
         ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);
-
+  
         await expect(executeTransaction(
           api, 
           forbiddance.sinner, 
           api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 
         ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);
       }
-
+  
       const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
       expect(properties.consumedSpace).to.be.equal(originalSpace);
     });
+  }
+  it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {
+    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);
   });
+  it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {
+    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);
+  });
 
-  it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {
+  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(mode: CollectionMode, pieces: number) {
+    await prepare(mode, pieces);
+    
     await usingApi(async api => {
       let i = -1;
       for (const permission of constitution) {
         i++;
         if (permission.permission.mutable) continue;
-
+  
         await expect(executeTransaction(
           api, 
           permission.signers[0], 
           api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 
         ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);
-
+  
         await expect(executeTransaction(
           api, 
           permission.signers[0], 
           api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 
         ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);
       }
-
+  
       const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
       expect(properties.consumedSpace).to.be.equal(originalSpace);
-    });
+    });  
+  }
+  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {
+    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);
   });
+  it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {
+    await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);
+  });
+
+  async function testForbidsAddingPropertiesIfPropertyNotDeclared(mode: CollectionMode, pieces: number) {
+    await prepare(mode, pieces);
 
-  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {
     await usingApi(async api => {
       await expect(executeTransaction(
         api, 
@@ -925,20 +1081,28 @@
         alice, 
         api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 
       ), 'on setting a new non-permitted property').to.not.be.rejected;
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
         api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 
       ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);
-
+  
       expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;
       const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
       expect(properties.consumedSpace).to.be.equal(originalSpace);
     });
+  }
+  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {
+    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);
+  });
+  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {
+    await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);
   });
 
-  it('Forbids adding too many properties to a token', async () => {
+  async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {
+    await prepare(mode, pieces);
+
     await usingApi(async api => {
       await expect(executeTransaction(
         api, 
@@ -948,7 +1112,7 @@
           {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},
         ]), 
       ), 'on setting a new non-permitted property').to.not.be.rejected;
-
+  
       // Mute the general tx parsing error
       {
         console.error = () => {};
@@ -958,7 +1122,7 @@
           api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 
         )).to.be.rejected;
       }
-
+  
       await expect(executeTransaction(
         api, 
         alice, 
@@ -967,10 +1131,107 @@
           {key: 'young_years', value: 'neverending'.repeat(1490)},
         ]), 
       )).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
+  
       expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;
       const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
       expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);
     });
+  }
+  it('Forbids adding too many properties to a token (NFT)', async () => {
+    await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);
+  });
+  it('Forbids adding too many properties to a token (ReFungible)', async () => {
+    await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);
+  });
+});
+
+describe('ReFungible token properties permissions tests', () => {
+  let collection: number;
+  let token: number;
+
+  before(async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      alice = privateKeyWrapper('//Alice');
+      bob = privateKeyWrapper('//Bob');
+      charlie = privateKeyWrapper('//Charlie');
+    });
+  });
+
+  beforeEach(async () => {
+    await usingApi(async api => {
+      collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
+      token = await createItemExpectSuccess(alice, collection, 'ReFungible');
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 
+      )).to.not.be.rejected;
+    });
+  });
+
+  it('Forbids add token property with tokenOwher==true but signer have\'t all pieces', async () => {
+    await usingApi(async api => {
+      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');
+  
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [
+          {key: 'key', value: 'word'}, 
+        ]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+    });
+  });
+
+  it('Forbids mutate token property with tokenOwher==true but signer have\'t all pieces', async () => {
+    await usingApi(async api => {
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 
+      )).to.not.be.rejected;
+  
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [
+          {key: 'key', value: 'word'}, 
+        ]), 
+      )).to.be.not.rejected;
+
+      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');
+  
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [
+          {key: 'key', value: 'bad word'}, 
+        ]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+    });
+  });
+
+  it('Forbids delete token property with tokenOwher==true but signer have\'t all pieces', async () => {
+    await usingApi(async api => {
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [
+          {key: 'key', value: 'word'}, 
+        ]), 
+      )).to.be.not.rejected;
+
+      await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');
+  
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.deleteTokenProperties(collection, token, [
+          'key',
+        ]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+    });
   });
 });
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {default as usingApi} from './substrate/substrate-api';
+import {default as usingApi, submitTransactionAsync} from './substrate/substrate-api';
 import {IKeyringPair} from '@polkadot/types/types';
 import {
   createCollectionExpectSuccess,
@@ -30,6 +30,12 @@
   transfer,
   burnItem,
   repartitionRFT,
+  createCollectionWithPropsExpectSuccess,
+  getDetailedCollectionInfo,
+  normalizeAccountId,
+  CrossAccountId,
+  getCreateItemsResult,
+  getDestroyItemsResult,
 } from './util/helpers';
 
 import chai from 'chai';
@@ -51,14 +57,14 @@
   it('Create refungible collection and token', async () => {
     await usingApi(async api => {
       const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
-      expect(createCollectionResult.success).to.be.true;    
+      expect(createCollectionResult.success).to.be.true;
       const collectionId  = createCollectionResult.collectionId;
-
+      
       const itemCountBefore = await getLastTokenId(api, collectionId);
       const result = await createRefungibleToken(api, alice, collectionId, 100n);
-
+      
       const itemCountAfter = await getLastTokenId(api, collectionId);
-
+      
       // What to expect
       // tslint:disable-next-line:no-unused-expression
       expect(result.success).to.be.true;
@@ -67,7 +73,43 @@
       expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());
     });
   });
-
+  
+  it('RPC method tokenOnewrs for refungible collection and token', async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+      const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+      
+      const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});
+      const collectionId = createCollectionResult.collectionId;
+      
+      const result = await createRefungibleToken(api, alice, collectionId, 10_000n);
+      const aliceTokenId = result.itemId;
+      
+      
+      await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+      await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+      
+      for (let i = 0; i < 7; i++) {
+        await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 50*(i+1));
+      } 
+      
+      const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+      const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+      
+      const aliceID = normalizeAccountId(alice);
+      const bobId = normalizeAccountId(bob);
+      
+      // What to expect
+      // tslint:disable-next-line:no-unused-expression
+      expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+      expect(owners.length).to.be.equal(10);
+      
+      const eleven = privateKeyWrapper('11');
+      expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+      expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+    });
+  });
+  
   it('Transfer token pieces', async () => {
     await usingApi(async api => {
       const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
@@ -186,4 +228,67 @@
       await expect(transfer(api, collectionId, tokenId, bob, alice, 160n)).to.eventually.be.rejected;
     });
   });
+
+  it('Repartition with increased amount', async () => {
+    await usingApi(async api => {
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;
+
+      const tx = api.tx.unique.repartition(collectionId, tokenId, 200n);
+      const events = await submitTransactionAsync(alice, tx);
+      const substrateEvents = getCreateItemsResult(events);
+      expect(substrateEvents).to.include.deep.members([
+        {
+          success: true,
+          collectionId,
+          itemId: tokenId,
+          recipient: {Substrate: alice.address},
+          amount: 100,
+        },
+      ]);
+    });
+  });
+
+  it('Repartition with decreased amount', async () => {
+    await usingApi(async api => {
+      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;
+      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;
+
+      const tx = api.tx.unique.repartition(collectionId, tokenId, 50n);
+      const events = await submitTransactionAsync(alice, tx);
+      const substrateEvents = getDestroyItemsResult(events);
+      expect(substrateEvents).to.include.deep.members([
+        {
+          success: true,
+          collectionId,
+          itemId: tokenId,
+          owner: {Substrate: alice.address},
+          amount: 50,
+        },
+      ]);
+    });
+  });
+});
+
+describe('Test Refungible properties:', () => {
+  before(async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      alice = privateKeyWrapper('//Alice');
+      bob = privateKeyWrapper('//Bob');
+    });
+  });
+  
+  it('Сreate new collection with properties', async () => {
+    await usingApi(async api => {
+      const properties = [{key: 'key1', value: 'val1'}];
+      const propertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}];
+      const collectionId = await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'ReFungible'},
+        properties: properties,
+        propPerm: propertyPermissions, 
+      });
+      const collection = (await getDetailedCollectionInfo(api, collectionId))!;
+      expect(collection.properties.toHuman()).to.be.deep.equal(properties);
+      expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);
+    });
+  });
 });
modifiedtests/src/rpc.test.tsdiffbeforeafterboth
--- a/tests/src/rpc.test.ts
+++ b/tests/src/rpc.test.ts
@@ -1,12 +1,57 @@
+import {IKeyringPair} from '@polkadot/types/types';
 import {expect} from 'chai';
 import usingApi from './substrate/substrate-api';
-import {createCollectionExpectSuccess, getTokenOwner} from './util/helpers';
+import {createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, CrossAccountId, getTokenOwner, normalizeAccountId, transfer, U128_MAX} from './util/helpers';
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
 
-describe('getTokenOwner', () => {
+
+describe('integration test: RPC methods', () => {
+  before(async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      alice = privateKeyWrapper('//Alice');
+      bob = privateKeyWrapper('//Bob');
+    });
+  });
+
+  
   it('returns None for fungible collection', async () => {
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
       await expect(getTokenOwner(api, collection, 0)).to.be.rejectedWith(/^owner == null$/);
     });
   });
+  
+  it('RPC method tokenOwners for fungible collection and token', async () => {
+    await usingApi(async (api, privateKeyWrapper) => {
+      const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'};
+      const facelessCrowd = Array.from(Array(7).keys()).map(i => normalizeAccountId(privateKeyWrapper(i.toString())));
+      
+      const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}});
+      const collectionId = createCollectionResult.collectionId;
+      const aliceTokenId = await createFungibleItemExpectSuccess(alice, collectionId, {Value: U128_MAX}, alice.address);
+     
+      await transfer(api, collectionId, aliceTokenId, alice, bob, 1000n);
+      await transfer(api, collectionId, aliceTokenId, alice, ethAcc, 900n);
+            
+      for (let i = 0; i < 7; i++) {
+        await transfer(api, collectionId, aliceTokenId, alice, facelessCrowd[i], 1);
+      } 
+      
+      const owners = await api.rpc.unique.tokenOwners(collectionId, aliceTokenId);
+      const ids = (owners.toJSON() as CrossAccountId[]).map(s => normalizeAccountId(s));
+      const aliceID = normalizeAccountId(alice);
+      const bobId = normalizeAccountId(bob);
+
+      // What to expect
+      // tslint:disable-next-line:no-unused-expression
+      expect(ids).to.deep.include.members([aliceID, ethAcc, bobId, ...facelessCrowd]);
+      expect(owners.length == 10).to.be.true;
+      
+      const eleven = privateKeyWrapper('11');
+      expect(await transfer(api, collectionId, aliceTokenId, alice, eleven, 10n)).to.be.true;
+      expect((await api.rpc.unique.tokenOwners(collectionId, aliceTokenId)).length).to.be.equal(10);
+    });
+  });
 });
\ No newline at end of file
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -103,6 +103,15 @@
   collectionId: number;
   itemId: number;
   recipient?: CrossAccountId;
+  amount?: number;
+}
+
+interface DestroyItemResult {
+  success: boolean;
+  collectionId: number;
+  itemId: number;
+  owner: CrossAccountId;
+  amount: number;
 }
 
 interface TransferResult {
@@ -220,12 +229,14 @@
     const collectionId = parseInt(data[0].toString(), 10);
     const itemId = parseInt(data[1].toString(), 10);
     const recipient = normalizeAccountId(data[2].toJSON() as any);
+    const amount = parseInt(data[3].toString(), 10);
 
     const itemRes: CreateItemResult = {
       success: true,
       collectionId,
       itemId,
       recipient,
+      amount,
     };
 
     results.push(itemRes);
@@ -255,6 +266,31 @@
   return result;
 }
 
+export function getDestroyItemsResult(events: EventRecord[]): DestroyItemResult[] {
+  const results: DestroyItemResult[] = [];
+  
+  const genericResult = getGenericResult<DestroyItemResult[]>(events, 'common', 'ItemDestroyed', (data) => {
+    const collectionId = parseInt(data[0].toString(), 10);
+    const itemId = parseInt(data[1].toString(), 10);
+    const owner = normalizeAccountId(data[2].toJSON() as any);
+    const amount = parseInt(data[3].toString(), 10);
+
+    const itemRes: DestroyItemResult = {
+      success: true,
+      collectionId,
+      itemId,
+      owner,
+      amount,
+    };
+
+    results.push(itemRes);
+    return results;
+  });
+
+  if (!genericResult.success) return [];
+  return results;
+}
+
 export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult {
   for (const {event} of events) {
     if (api.events.common.Transfer.is(event)) {
@@ -284,7 +320,7 @@
   type: 'ReFungible';
 }
 
-type CollectionMode = Nft | Fungible | ReFungible;
+export type CollectionMode = Nft | Fungible | ReFungible;
 
 export type Property = {
   key: any,
@@ -1414,7 +1450,7 @@
       tx = api.tx.unique.createItem(collectionId, to, createData as any);
     }
 
-    const events = await submitTransactionAsync(sender, tx);
+    const events = await executeTransaction(api, sender, tx);
     const result = getCreateItemResult(events);
 
     const itemCountAfter = await getLastTokenId(api, collectionId);