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

difftreelog

Merge branch 'feature/pallet-structure-rebased' of https://github.com/UniqueNetwork/unique-chain into feature/pallet-structure-rebased

Fahrrader2022-05-19parents: #547ee7a #aa4cd0e.patch.diff
in: master

68 files changed

modified.maintain/scripts/generate_api.shdiffbeforeafterboth
--- a/.maintain/scripts/generate_api.sh
+++ b/.maintain/scripts/generate_api.sh
@@ -7,6 +7,5 @@
 sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw
 formatted=$(mktemp)
 prettier --use-tabs $raw > $formatted
-solhint --fix $formatted
 
 mv $formatted $OUTPUT
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6391,6 +6391,7 @@
  "sp-core",
  "sp-runtime",
  "sp-std",
+ "struct-versioning",
  "up-data-structs",
 ]
 
@@ -6508,6 +6509,7 @@
  "sp-core",
  "sp-runtime",
  "sp-std",
+ "struct-versioning",
  "up-data-structs",
 ]
 
modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -30,8 +30,8 @@
 // RMRK
 use rmrk_rpc::RmrkApi as RmrkRuntimeApi;
 use up_data_structs::{
-	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild,
-	RmrkThemeName, RmrkPropertyKey, RmrkResourceId
+	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkPropertyKey,
+	RmrkResourceId,
 };
 
 pub use rmrk_unique_rpc::RmrkApi;
@@ -75,13 +75,6 @@
 	) -> Result<Option<CrossAccountId>>;
 	#[rpc(name = "unique_constMetadata")]
 	fn const_metadata(
-		&self,
-		collection: CollectionId,
-		token: TokenId,
-		at: Option<BlockHash>,
-	) -> Result<Vec<u8>>;
-	#[rpc(name = "unique_variableMetadata")]
-	fn variable_metadata(
 		&self,
 		collection: CollectionId,
 		token: TokenId,
@@ -92,7 +85,7 @@
 	fn collection_properties(
 		&self,
 		collection: CollectionId,
-		keys: Vec<String>,
+		keys: Option<Vec<String>>,
 		at: Option<BlockHash>,
 	) -> Result<Vec<Property>>;
 
@@ -101,7 +94,7 @@
 		&self,
 		collection: CollectionId,
 		token_id: TokenId,
-		properties: Vec<String>,
+		keys: Option<Vec<String>>,
 		at: Option<BlockHash>,
 	) -> Result<Vec<Property>>;
 
@@ -109,7 +102,7 @@
 	fn property_permissions(
 		&self,
 		collection: CollectionId,
-		keys: Vec<String>,
+		keys: Option<Vec<String>>,
 		at: Option<BlockHash>,
 	) -> Result<Vec<PropertyKeyPermission>>;
 
@@ -118,7 +111,7 @@
 		&self,
 		collection: CollectionId,
 		token_id: TokenId,
-		keys: Vec<String>,
+		keys: Option<Vec<String>>,
 		at: Option<BlockHash>,
 	) -> Result<TokenData<CrossAccountId>>;
 
@@ -428,10 +421,6 @@
 	);
 	pass_method!(
 		const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>, unique_api
-	);
-	pass_method!(
-		variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>,
-		unique_api
 	);
 	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);
 	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);
@@ -445,7 +434,7 @@
 		collection: CollectionId,
 
 		#[map(|keys| string_keys_to_bytes_keys(keys))]
-		keys: Vec<String>
+		keys: Option<Vec<String>>
 	) -> Vec<Property>, unique_api);
 
 	pass_method!(token_properties(
@@ -453,14 +442,14 @@
 		token_id: TokenId,
 
 		#[map(|keys| string_keys_to_bytes_keys(keys))]
-		properties: Vec<String>
+		keys: Option<Vec<String>>
 	) -> Vec<Property>, unique_api);
 
 	pass_method!(property_permissions(
 		collection: CollectionId,
 
 		#[map(|keys| string_keys_to_bytes_keys(keys))]
-		keys: Vec<String>
+		keys: Option<Vec<String>>
 	) -> Vec<PropertyKeyPermission>, unique_api);
 
 	pass_method!(token_data(
@@ -468,7 +457,7 @@
 		token_id: TokenId,
 
 		#[map(|keys| string_keys_to_bytes_keys(keys))]
-		keys: Vec<String>,
+		keys: Option<Vec<String>>,
 	) -> TokenData<CrossAccountId>, unique_api);
 
 	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);
@@ -549,6 +538,6 @@
 	pass_method!(theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Option<Theme>, rmrk_api);
 }
 
-fn string_keys_to_bytes_keys(keys: Vec<String>) -> Vec<Vec<u8>> {
-	keys.into_iter().map(|key| key.into_bytes()).collect()
+fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {
+	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())
 }
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -65,25 +65,12 @@
 use fc_rpc_core::types::FilterPool;
 use fc_mapping_sync::{MappingSyncWorker, SyncStrategy};
 
-use unique_runtime_common::types::{
-	AuraId,
-	RuntimeInstance,
-	AccountId,
-	Balance,
-	Index,
-	Hash,
-	Block,
-};
+use unique_runtime_common::types::{AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block};
 
 // RMRK
 use up_data_structs::{
-	RmrkCollectionInfo,
-	RmrkInstanceInfo,
-	RmrkResourceInfo,
-	RmrkPropertyInfo,
-	RmrkBaseInfo,
-	RmrkPartType,
-	RmrkTheme,
+	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
+	RmrkPartType, RmrkTheme,
 };
 
 /// Unique native executor instance.
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -41,17 +41,12 @@
 use std::{collections::BTreeMap, sync::Arc};
 
 use unique_runtime_common::types::{
-	Hash,
-	AccountId,
-	RuntimeInstance,
-	Index,
-	Block,
-	BlockNumber,
-	Balance,
+	Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance,
 };
 // RMRK
 use up_data_structs::{
-	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo, RmrkPartType, RmrkTheme, 
+	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo,
+	RmrkPartType, RmrkTheme,
 };
 
 /// Public io handler for exporting into other modules
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -21,7 +21,7 @@
 use sp_std::vec::Vec;
 use up_data_structs::Property;
 
-use crate::{Pallet, CollectionHandle, Config};
+use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
 
 /// Does not always represent a full collection, for RFT it is either
 /// collection (Implementing ERC721), or specific collection token (Implementing ERC20)
@@ -33,24 +33,35 @@
 
 #[solidity_interface(name = "CollectionProperties")]
 impl<T: Config> CollectionHandle<T> {
-	fn set_property(&mut self, caller: caller, key: string, value: string) -> Result<()> {
-		<Pallet<T>>::set_collection_property(
-			self,
-			&T::CrossAccountId::from_eth(caller),
-			Property {
-				key: <Vec<u8>>::from(key)
-					.try_into()
-					.map_err(|_| "key too large")?,
-				value: <Vec<u8>>::from(value)
-					.try_into()
-					.map_err(|_| "value too large")?,
-			},
-		)
-		.map_err(dispatch_to_evm::<T>)?;
-		Ok(())
+	fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let key = <Vec<u8>>::from(key)
+			.try_into()
+			.map_err(|_| "key too large")?;
+		let value = value.try_into().map_err(|_| "value too large")?;
+
+		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })
+			.map_err(dispatch_to_evm::<T>)
 	}
 
-	fn delete_property(&mut self, caller: caller, key: string) -> Result<()> {
-		self.set_property(caller, key, string::new())
+	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let key = <Vec<u8>>::from(key)
+			.try_into()
+			.map_err(|_| "key too large")?;
+
+		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)
+	}
+
+	/// Throws error if key not found
+	fn collection_property(&self, key: string) -> Result<bytes> {
+		let key = <Vec<u8>>::from(key)
+			.try_into()
+			.map_err(|_| "key too large")?;
+
+		let props = <CollectionProperties<T>>::get(self.id);
+		let prop = props.get(&key).ok_or("key not found")?;
+
+		Ok(prop.to_vec())
 	}
 }
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -22,23 +22,56 @@
 use pallet_evm::account::CrossAccountId;
 use frame_support::{
 	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},
-	ensure, fail,
+	ensure,
 	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},
 	BoundedVec,
 	weights::Pays,
+	transactional,
 };
 use pallet_evm::GasWeightMapping;
 use up_data_structs::{
-	COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionId, CreateItemData,
-	MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,
-	CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,
-	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,
-	CUSTOM_DATA_LIMIT, CollectionLimits, CustomDataLimit, CreateCollectionData, SponsorshipState,
-	CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,
-	PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,
-	PropertiesError, PropertyKeyPermission, TokenData, TrySet,
+	COLLECTION_NUMBER_LIMIT,
+	Collection,
+	RpcCollection,
+	CollectionId,
+	CreateItemData,
+	MAX_TOKEN_PREFIX_LENGTH,
+	COLLECTION_ADMINS_LIMIT,
+	TokenId,
+	CollectionStats,
+	MAX_TOKEN_OWNERSHIP,
+	CollectionMode,
+	NFT_SPONSOR_TRANSFER_TIMEOUT,
+	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+	MAX_SPONSOR_TIMEOUT,
+	CUSTOM_DATA_LIMIT,
+	CollectionLimits,
+	CreateCollectionData,
+	SponsorshipState,
+	CreateItemExData,
+	SponsoringRateLimit,
+	budget::Budget,
+	COLLECTION_FIELD_LIMIT,
+	CollectionField,
+	PhantomType,
+	Property,
+	Properties,
+	PropertiesPermissionMap,
+	PropertyKey,
+	PropertyPermission,
+	PropertiesError,
+	PropertyKeyPermission,
+	TokenData,
+	TrySetProperty,
 	// RMRK
-	RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, RmrkBaseInfo, RmrkPartType, RmrkTheme,
+	RmrkCollectionInfo,
+	RmrkInstanceInfo,
+	RmrkResourceInfo,
+	RmrkPropertyInfo,
+	RmrkBaseInfo,
+	RmrkPartType,
+	RmrkTheme,
 	RmrkNftChild,
 };
 
@@ -138,21 +171,6 @@
 			<Error<T>>::AddressNotInAllowlist
 		);
 		Ok(())
-	}
-
-	pub fn check_can_update_meta(
-		&self,
-		subject: &T::CrossAccountId,
-		item_owner: &T::CrossAccountId,
-	) -> DispatchResult {
-		match self.meta_update_permission {
-			MetaUpdatePermission::ItemOwner => {
-				ensure!(subject == item_owner, <Error<T>>::NoPermission);
-				Ok(())
-			}
-			MetaUpdatePermission::Admin => self.check_is_owner_or_admin(subject),
-			MetaUpdatePermission::None => fail!(<Error<T>>::NoPermission),
-		}
 	}
 }
 
@@ -316,8 +334,6 @@
 		CollectionTokenPrefixLimitExceeded,
 		/// Total collections bound exceeded.
 		TotalCollectionsLimitExceeded,
-		/// variable_data exceeded data limit.
-		TokenVariableDataLimitExceeded,
 		/// Exceeded max admin count
 		CollectionAdminCountExceeded,
 		/// Collection limit bounds per collection exceeded
@@ -366,8 +382,8 @@
 		/// Tried to store more property keys than allowed
 		PropertyLimitReached,
 
-		/// Unable to read array of unbounded keys
-		UnableToReadUnboundedKeys,
+		/// Property key is too long
+		PropertyKeyIsTooLong,
 
 		/// Only ASCII letters, digits, and '_', '-' are allowed
 		InvalidCharacterInPropertyKey,
@@ -580,7 +596,6 @@
 			schema_version,
 			sponsorship,
 			limits,
-			meta_update_permission,
 		} = <CollectionById<T>>::get(collection)?;
 
 		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)
@@ -610,7 +625,6 @@
 			schema_version,
 			sponsorship,
 			limits,
-			meta_update_permission,
 			offchain_schema: <CollectionData<T>>::get((
 				collection,
 				CollectionField::OffchainSchema,
@@ -671,7 +685,6 @@
 				.limits
 				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))
 				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,
-			meta_update_permission: data.meta_update_permission.unwrap_or_default(),
 		};
 
 		let mut collection_properties = up_data_structs::CollectionProperties::get();
@@ -775,6 +788,7 @@
 		Ok(())
 	}
 
+	#[transactional]
 	pub fn set_collection_properties(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -807,6 +821,7 @@
 		Ok(())
 	}
 
+	#[transactional]
 	pub fn delete_collection_properties(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -849,6 +864,7 @@
 		Ok(())
 	}
 
+	#[transactional]
 	pub fn set_property_permissions(
 		collection: &CollectionHandle<T>,
 		sender: &T::CrossAccountId,
@@ -867,60 +883,69 @@
 		keys.into_iter()
 			.map(|key| -> Result<PropertyKey, DispatchError> {
 				key.try_into()
-					.map_err(|_| <Error<T>>::UnableToReadUnboundedKeys.into())
+					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())
 			})
 			.collect::<Result<Vec<PropertyKey>, DispatchError>>()
-	}
-
-	pub fn check_property_key(key: &PropertyKey) -> Result<(), DispatchError> {
-		let key_str = sp_std::str::from_utf8(key.as_slice())
-			.map_err(|_| <Error<T>>::InvalidCharacterInPropertyKey)?;
-
-		for ch in key_str.chars() {
-			if !ch.is_ascii_alphanumeric() && ch != '_' && ch != '-' {
-				return Err(<Error<T>>::InvalidCharacterInPropertyKey.into());
-			}
-		}
-
-		Ok(())
 	}
 
 	pub fn filter_collection_properties(
 		collection_id: CollectionId,
-		keys: Vec<PropertyKey>,
+		keys: Option<Vec<PropertyKey>>,
 	) -> Result<Vec<Property>, DispatchError> {
 		let properties = Self::collection_properties(collection_id);
 
 		let properties = keys
-			.into_iter()
-			.filter_map(|key| {
-				properties.get(&key).map(|value| Property {
-					key,
-					value: value.clone(),
-				})
+			.map(|keys| {
+				keys.into_iter()
+					.filter_map(|key| {
+						properties.get(&key).map(|value| Property {
+							key,
+							value: value.clone(),
+						})
+					})
+					.collect()
 			})
-			.collect();
+			.unwrap_or_else(|| {
+				properties
+					.iter()
+					.map(|(key, value)| Property {
+						key: key.clone(),
+						value: value.clone(),
+					})
+					.collect()
+			});
 
 		Ok(properties)
 	}
 
 	pub fn filter_property_permissions(
 		collection_id: CollectionId,
-		keys: Vec<PropertyKey>,
+		keys: Option<Vec<PropertyKey>>,
 	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
 		let permissions = Self::property_permissions(collection_id);
 
 		let key_permissions = keys
-			.into_iter()
-			.filter_map(|key| {
+			.map(|keys| {
+				keys.into_iter()
+					.filter_map(|key| {
+						permissions
+							.get(&key)
+							.map(|permission| PropertyKeyPermission {
+								key,
+								permission: permission.clone(),
+							})
+					})
+					.collect()
+			})
+			.unwrap_or_else(|| {
 				permissions
-					.get(&key)
-					.map(|permission| PropertyKeyPermission {
-						key,
+					.iter()
+					.map(|(key, permission)| PropertyKeyPermission {
+						key: key.clone(),
 						permission: permission.clone(),
 					})
-			})
-			.collect();
+					.collect()
+			});
 
 		Ok(key_permissions)
 	}
@@ -1086,7 +1111,6 @@
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
 	fn burn_from() -> Weight;
-	fn set_variable_metadata(bytes: u32) -> Weight;
 }
 
 pub trait CommonCollectionOperations<T: Config> {
@@ -1174,13 +1198,6 @@
 		token: TokenId,
 		amount: u128,
 		nesting_budget: &dyn Budget,
-	) -> DispatchResultWithPostInfo;
-
-	fn set_variable_metadata(
-		&self,
-		sender: T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
 	) -> DispatchResultWithPostInfo;
 
 	fn check_nesting(
@@ -1198,8 +1215,7 @@
 
 	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;
 	fn const_metadata(&self, token: TokenId) -> Vec<u8>;
-	fn variable_metadata(&self, token: TokenId) -> Vec<u8>;
-	fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property>;
+	fn token_properties(&self, token_id: 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)
@@ -1232,6 +1248,7 @@
 			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,
 			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,
 			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,
+			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,
 			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,
 		}
 	}
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -16,12 +16,12 @@
 
 use core::marker::PhantomData;
 
-use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
 use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget};
 use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
 use sp_runtime::ArithmeticError;
 use sp_std::{vec::Vec, vec};
-use up_data_structs::{CustomDataLimit, Property, PropertyKey, PropertyKeyPermission};
+use up_data_structs::{Property, PropertyKey, PropertyKeyPermission};
 
 use crate::{
 	Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,
@@ -84,11 +84,6 @@
 
 	fn burn_from() -> Weight {
 		<SelfWeightOf<T>>::burn_from()
-	}
-
-	fn set_variable_metadata(_bytes: u32) -> Weight {
-		// Error
-		0
 	}
 }
 
@@ -287,15 +282,6 @@
 		fail!(<Error<T>>::SettingPropertiesNotAllowed)
 	}
 
-	fn set_variable_metadata(
-		&self,
-		_sender: T::CrossAccountId,
-		_token: TokenId,
-		_data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResultWithPostInfo {
-		fail!(<Error<T>>::FungibleItemsDontHaveData)
-	}
-
 	fn check_nesting(
 		&self,
 		_sender: <T>::CrossAccountId,
@@ -330,13 +316,14 @@
 		None
 	}
 	fn const_metadata(&self, _token: TokenId) -> Vec<u8> {
-		Vec::new()
-	}
-	fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {
 		Vec::new()
 	}
 
-	fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {
+	fn token_properties(
+		&self,
+		_token_id: TokenId,
+		_keys: Option<Vec<PropertyKey>>,
+	) -> Vec<Property> {
 		Vec::new()
 	}
 
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
@@ -8,8 +8,13 @@
 	uint8 dummy;
 	string stub_error = "this contract is implemented in native";
 }
+
 contract ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool) {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
 		require(false, stub_error);
 		interfaceID;
 		return true;
@@ -19,24 +24,11 @@
 // Inline
 contract ERC20Events {
 	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-// Selector: 56fd500b
-contract CollectionProperties is Dummy, ERC165 {
-	// Selector: setProperty(string,string) 62d9491f
-	function setProperty(string memory key, string memory value) public {
-		require(false, stub_error);
-		key;
-		value;
-		dummy = 0;
-	}
-	// Selector: deleteProperty(string) 34241914
-	function deleteProperty(string memory key) public {
-		require(false, stub_error);
-		key;
-		dummy = 0;
-	}
+	event Approval(
+		address indexed owner,
+		address indexed spender,
+		uint256 value
+	);
 }
 
 // Selector: 79cc6790
@@ -59,24 +51,28 @@
 		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);
@@ -84,6 +80,7 @@
 		dummy;
 		return 0;
 	}
+
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 amount) public returns (bool) {
 		require(false, stub_error);
@@ -92,8 +89,13 @@
 		dummy = 0;
 		return false;
 	}
+
 	// Selector: transferFrom(address,address,uint256) 23b872dd
-	function transferFrom(address from, address to, uint256 amount) public returns (bool) {
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) public returns (bool) {
 		require(false, stub_error);
 		from;
 		to;
@@ -101,6 +103,7 @@
 		dummy = 0;
 		return false;
 	}
+
 	// Selector: approve(address,uint256) 095ea7b3
 	function approve(address spender, uint256 amount) public returns (bool) {
 		require(false, stub_error);
@@ -109,8 +112,13 @@
 		dummy = 0;
 		return false;
 	}
+
 	// Selector: allowance(address,address) dd62ed3e
-	function allowance(address owner, address spender) public view returns (uint256) {
+	function allowance(address owner, address spender)
+		public
+		view
+		returns (uint256)
+	{
 		require(false, stub_error);
 		owner;
 		spender;
@@ -119,6 +127,44 @@
 	}
 }
 
-contract UniqueFungible is Dummy, ERC165, ERC20, ERC20UniqueExtensions, CollectionProperties {
+// Selector: 9b5e29c5
+contract CollectionProperties 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"";
+	}
 }
 
+contract UniqueFungible is
+	Dummy,
+	ERC165,
+	ERC20,
+	ERC20UniqueExtensions,
+	CollectionProperties
+{}
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -27,6 +27,7 @@
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
+struct-versioning = { path = "../../crates/struct-versioning" }
 
 [features]
 default = ["std"]
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -28,12 +28,7 @@
 
 fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {
 	let const_data = create_data::<CUSTOM_DATA_LIMIT>();
-	let variable_data = create_data::<CUSTOM_DATA_LIMIT>();
-	CreateItemData::<T> {
-		const_data,
-		variable_data,
-		owner,
-	}
+	CreateItemData::<T> { const_data, owner }
 }
 fn create_max_item<T: Config>(
 	collection: &NonfungibleHandle<T>,
@@ -125,14 +120,4 @@
 		let item = create_max_item(&collection, &owner, sender.clone())?;
 		<Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;
 	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?}
-
-	set_variable_metadata {
-		let b in 0..CUSTOM_DATA_LIMIT;
-		bench_init!{
-			owner: sub; collection: collection(owner);
-			owner: cross_from_sub; sender: cross_sub;
-		};
-		let item = create_max_item(&collection, &owner, sender.clone())?;
-		let data = create_var_data(b).try_into().unwrap();
-	}: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}
 }
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -16,10 +16,10 @@
 
 use core::marker::PhantomData;
 
-use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
 use up_data_structs::{
-	TokenId, CustomDataLimit, CreateItemExData, CollectionId, budget::Budget, Property,
-	PropertyKey, PropertyKeyPermission,
+	TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,
+	PropertyKeyPermission,
 };
 use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
 use sp_runtime::DispatchError;
@@ -86,10 +86,6 @@
 	fn burn_from() -> Weight {
 		<SelfWeightOf<T>>::burn_from()
 	}
-
-	fn set_variable_metadata(bytes: u32) -> Weight {
-		<SelfWeightOf<T>>::set_variable_metadata(bytes)
-	}
 }
 
 fn map_create_data<T: Config>(
@@ -99,7 +95,6 @@
 	match data {
 		up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {
 			const_data: data.const_data,
-			variable_data: data.variable_data,
 			properties: data.properties,
 			owner: to.clone(),
 		}),
@@ -184,7 +179,7 @@
 		let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);
 
 		with_weight(
-			<Pallet<T>>::delete_collection_properties(self, &sender, property_keys),
+			<Pallet<T>>::delete_collection_properties(self, sender, property_keys),
 			weight,
 		)
 	}
@@ -327,19 +322,6 @@
 		}
 	}
 
-	fn set_variable_metadata(
-		&self,
-		sender: T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResultWithPostInfo {
-		let len = data.len();
-		with_weight(
-			<Pallet<T>>::set_variable_metadata(self, &sender, token, data),
-			<CommonWeights<T>>::set_variable_metadata(len as u32),
-		)
-	}
-
 	fn check_nesting(
 		&self,
 		sender: T::CrossAccountId,
@@ -379,24 +361,29 @@
 			.unwrap_or_default()
 			.into_inner()
 	}
-	fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
-		<TokenData<T>>::get((self.id, token))
-			.map(|t| t.variable_data)
-			.unwrap_or_default()
-			.into_inner()
-	}
 
-	fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property> {
+	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {
 		let properties = <Pallet<T>>::token_properties((self.id, token_id));
 
-		keys.into_iter()
-			.filter_map(|key| {
-				properties.get(&key).map(|value| Property {
-					key,
+		keys.map(|keys| {
+			keys.into_iter()
+				.filter_map(|key| {
+					properties.get(&key).map(|value| Property {
+						key,
+						value: value.clone(),
+					})
+				})
+				.collect()
+		})
+		.unwrap_or_else(|| {
+			properties
+				.iter()
+				.map(|(key, value)| Property {
+					key: key.clone(),
 					value: value.clone(),
 				})
-			})
-			.collect()
+				.collect()
+		})
 	}
 
 	fn total_supply(&self) -> u32 {
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -21,10 +21,10 @@
 };
 use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::BoundedVec;
-use up_data_structs::{TokenId, SchemaVersion};
+use up_data_structs::{TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property};
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_core::{H160, U256};
-use sp_std::{vec::Vec, vec};
+use sp_std::vec::Vec;
 use pallet_common::{
 	erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall},
 	CollectionHandle,
@@ -35,9 +35,80 @@
 
 use crate::{
 	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
-	SelfWeightOf, weights::WeightInfo,
+	SelfWeightOf, weights::WeightInfo, TokenProperties,
 };
 
+#[solidity_interface(name = "TokenProperties")]
+impl<T: Config> NonfungibleHandle<T> {
+	fn set_token_property_permission(
+		&mut self,
+		caller: caller,
+		key: string,
+		is_mutable: bool,
+		collection_admin: bool,
+		token_owner: bool,
+	) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		<Pallet<T>>::set_property_permission(
+			self,
+			&caller,
+			PropertyKeyPermission {
+				key: <Vec<u8>>::from(key)
+					.try_into()
+					.map_err(|_| "too long key")?,
+				permission: PropertyPermission {
+					mutable: is_mutable,
+					collection_admin,
+					token_owner,
+				},
+			},
+		)
+		.map_err(dispatch_to_evm::<T>)
+	}
+
+	fn set_property(
+		&mut self,
+		caller: caller,
+		token_id: uint256,
+		key: string,
+		value: bytes,
+	) -> Result<()> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+		let key = <Vec<u8>>::from(key)
+			.try_into()
+			.map_err(|_| "key too long")?;
+		let value = value.try_into().map_err(|_| "value too long")?;
+
+		<Pallet<T>>::set_token_property(self, &caller, TokenId(token_id), Property { key, value })
+			.map_err(dispatch_to_evm::<T>)
+	}
+
+	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")?;
+		let key = <Vec<u8>>::from(key)
+			.try_into()
+			.map_err(|_| "key too long")?;
+
+		<Pallet<T>>::delete_token_property(self, &caller, TokenId(token_id), key)
+			.map_err(dispatch_to_evm::<T>)
+	}
+
+	/// Throws error if key not found
+	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)
+			.try_into()
+			.map_err(|_| "key too long")?;
+
+		let props = <TokenProperties<T>>::get((self.id, token_id));
+		let prop = props.get(&key).ok_or("key not found")?;
+
+		Ok(prop.to_vec())
+	}
+}
+
 fn error_unsupported_schema_version() -> Error {
 	alloc::format!(
 		"Unsupported schema version! Support only {:?}",
@@ -274,7 +345,6 @@
 			&caller,
 			CreateItemData::<T> {
 				const_data: BoundedVec::default(),
-				variable_data: BoundedVec::default(),
 				properties: BoundedVec::default(),
 				owner: to,
 			},
@@ -322,7 +392,6 @@
 				const_data: Vec::<u8>::from(token_uri)
 					.try_into()
 					.map_err(|_| "token uri is too long")?,
-				variable_data: BoundedVec::default(),
 				properties: BoundedVec::default(),
 				owner: to,
 			},
@@ -387,37 +456,6 @@
 			.into())
 	}
 
-	#[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]
-	fn set_variable_metadata(
-		&mut self,
-		caller: caller,
-		token_id: uint256,
-		data: bytes,
-	) -> Result<void> {
-		let caller = T::CrossAccountId::from_eth(caller);
-		let token = token_id.try_into()?;
-
-		<Pallet<T>>::set_variable_metadata(
-			self,
-			&caller,
-			token,
-			data.try_into()
-				.map_err(|_| "metadata size exceeded limit")?,
-		)
-		.map_err(dispatch_to_evm::<T>)?;
-		Ok(())
-	}
-
-	fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
-		self.consume_store_reads(1)?;
-		let token: TokenId = token_id.try_into()?;
-
-		Ok(<TokenData<T>>::get((self.id, token))
-			.ok_or("token not found")?
-			.variable_data
-			.into_inner())
-	}
-
 	#[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);
@@ -440,7 +478,6 @@
 		let data = (0..total_tokens)
 			.map(|_| CreateItemData::<T> {
 				const_data: BoundedVec::default(),
-				variable_data: BoundedVec::default(),
 				properties: BoundedVec::default(),
 				owner: to.clone(),
 			})
@@ -484,7 +521,6 @@
 				const_data: Vec::<u8>::from(token_uri)
 					.try_into()
 					.map_err(|_| "token uri is too long")?,
-				variable_data: vec![].try_into().unwrap(),
 				properties: BoundedVec::default(),
 				owner: to.clone(),
 			});
@@ -505,7 +541,8 @@
 		ERC721UniqueExtensions,
 		ERC721Mintable,
 		ERC721Burnable,
-		via("CollectionHandle<T>", common_mut, CollectionProperties)
+		via("CollectionHandle<T>", common_mut, CollectionProperties),
+		TokenProperties,
 	)
 )]
 impl<T: Config> NonfungibleHandle<T> {}
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -18,11 +18,11 @@
 
 use erc::ERC721Events;
 use evm_coder::ToLog;
-use frame_support::{BoundedVec, ensure, fail};
+use frame_support::{BoundedVec, ensure, fail, transactional};
 use up_data_structs::{
 	AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,
 	mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,
-	PropertyKey, PropertyKeyPermission, Properties, TrySet,
+	PropertyKey, PropertyKeyPermission, Properties, TrySetProperty,
 };
 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
 use pallet_common::{
@@ -49,17 +49,24 @@
 pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
+#[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
 pub struct ItemData<CrossAccountId> {
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
+
+	#[version(..2)]
 	pub variable_data: BoundedVec<u8, CustomDataLimit>,
+
 	pub owner: CrossAccountId,
 }
 
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};
+	use frame_support::{
+		Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion,
+	};
+	use frame_system::pallet_prelude::*;
 	use up_data_structs::{CollectionId, TokenId};
 	use super::weights::WeightInfo;
 
@@ -78,7 +85,10 @@
 		type WeightInfo: WeightInfo;
 	}
 
+	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
 	#[pallet::pallet]
+	#[pallet::storage_version(STORAGE_VERSION)]
 	#[pallet::generate_store(pub(super) trait Store)]
 	pub struct Pallet<T>(_);
 
@@ -133,6 +143,19 @@
 		Value = T::CrossAccountId,
 		QueryKind = OptionQuery,
 	>;
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+		fn on_runtime_upgrade() -> Weight {
+			if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
+				<TokenData<T>>::translate_values::<ItemDataVersion1<T::CrossAccountId>, _>(|v| {
+					Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))
+				})
+			}
+
+			0
+		}
+	}
 }
 
 pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
@@ -286,6 +309,7 @@
 		Ok(())
 	}
 
+	#[transactional]
 	pub fn set_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -329,8 +353,8 @@
 	) -> DispatchResult {
 		let permission = <PalletCommon<T>>::property_permissions(collection.id)
 			.get(property_key)
-			.map(|p| p.clone())
-			.unwrap_or(PropertyPermission::none());
+			.cloned()
+			.unwrap_or_else(PropertyPermission::none);
 
 		let token_data = <TokenData<T>>::get((collection.id, token_id))
 			.ok_or(<CommonError<T>>::TokenNotFound)?;
@@ -369,6 +393,7 @@
 		}
 	}
 
+	#[transactional]
 	pub fn delete_token_properties(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
@@ -406,6 +431,14 @@
 		<PalletCommon<T>>::set_property_permissions(collection, sender, property_permissions)
 	}
 
+	pub fn set_property_permission(
+		collection: &CollectionHandle<T>,
+		sender: &T::CrossAccountId,
+		permission: PropertyKeyPermission,
+	) -> DispatchResult {
+		<PalletCommon<T>>::set_property_permission(collection, sender, permission)
+	}
+
 	pub fn transfer(
 		collection: &NonfungibleHandle<T>,
 		from: &T::CrossAccountId,
@@ -577,7 +610,6 @@
 				(collection.id, token),
 				ItemData {
 					const_data: data.const_data,
-					variable_data: data.variable_data,
 					owner: data.owner.clone(),
 				},
 			);
@@ -773,28 +805,6 @@
 		// =========
 
 		Self::burn(collection, from, token)
-	}
-
-	pub fn set_variable_metadata(
-		collection: &NonfungibleHandle<T>,
-		sender: &T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResult {
-		let token_data =
-			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
-		collection.check_can_update_meta(sender, &token_data.owner)?;
-
-		// =========
-
-		<TokenData<T>>::insert(
-			(collection.id, token),
-			ItemData {
-				variable_data: data,
-				..token_data
-			},
-		);
-		Ok(())
 	}
 
 	pub fn check_nesting(
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
@@ -51,6 +51,60 @@
 	event MintingFinished();
 }
 
+// Selector: 41369377
+contract TokenProperties is Dummy, ERC165 {
+	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
+	function setTokenPropertyPermission(
+		string memory key,
+		bool isMutable,
+		bool collectionAdmin,
+		bool tokenOwner
+	) public {
+		require(false, stub_error);
+		key;
+		isMutable;
+		collectionAdmin;
+		tokenOwner;
+		dummy = 0;
+	}
+
+	// Selector: setProperty(uint256,string,bytes) 1752d67b
+	function setProperty(
+		uint256 tokenId,
+		string memory key,
+		bytes memory value
+	) public {
+		require(false, stub_error);
+		tokenId;
+		key;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: deleteProperty(uint256,string) 066111d1
+	function deleteProperty(uint256 tokenId, string memory key) public {
+		require(false, stub_error);
+		tokenId;
+		key;
+		dummy = 0;
+	}
+
+	// Throws error if key not found
+	//
+	// Selector: property(uint256,string) 7228c327
+	function property(uint256 tokenId, string memory key)
+		public
+		view
+		returns (bytes memory)
+	{
+		require(false, stub_error);
+		tokenId;
+		key;
+		dummy;
+		return hex"";
+	}
+}
+
 // Selector: 42966c68
 contract ERC721Burnable is Dummy, ERC165 {
 	// Selector: burn(uint256) 42966c68
@@ -276,7 +330,41 @@
 	}
 }
 
-// Selector: e562194d
+// Selector: 9b5e29c5
+contract CollectionProperties 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: d74d154f
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) public {
@@ -299,26 +387,6 @@
 		require(false, stub_error);
 		dummy;
 		return 0;
-	}
-
-	// Selector: setVariableMetadata(uint256,bytes) d4eac26d
-	function setVariableMetadata(uint256 tokenId, bytes memory data) public {
-		require(false, stub_error);
-		tokenId;
-		data;
-		dummy = 0;
-	}
-
-	// Selector: getVariableMetadata(uint256) e6c5ce6f
-	function getVariableMetadata(uint256 tokenId)
-		public
-		view
-		returns (bytes memory)
-	{
-		require(false, stub_error);
-		tokenId;
-		dummy;
-		return hex"";
 	}
 
 	// Selector: mintBulk(address,uint256[]) 44a9945e
@@ -354,5 +422,7 @@
 	ERC721Enumerable,
 	ERC721UniqueExtensions,
 	ERC721Mintable,
-	ERC721Burnable
+	ERC721Burnable,
+	CollectionProperties,
+	TokenProperties
 {}
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -45,7 +45,6 @@
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
 	fn burn_from() -> Weight;
-	fn set_variable_metadata(b: u32, ) -> Weight;
 }
 
 /// Weights for pallet_nonfungible using the Substrate node and recommended hardware.
@@ -155,12 +154,6 @@
 		(27_580_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:1)
-	fn set_variable_metadata(_b: u32, ) -> Weight {
-		(7_700_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(1 as Weight))
-			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 }
 
@@ -270,11 +263,5 @@
 		(27_580_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:1)
-	fn set_variable_metadata(_b: u32, ) -> Weight {
-		(7_700_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 }
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -24,6 +24,7 @@
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
+struct-versioning = { path = "../../crates/struct-versioning" }
 
 [features]
 default = ["std"]
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -31,10 +31,8 @@
 	users: impl IntoIterator<Item = (CrossAccountId, u128)>,
 ) -> CreateRefungibleExData<CrossAccountId> {
 	let const_data = create_data::<CUSTOM_DATA_LIMIT>();
-	let variable_data = create_data::<CUSTOM_DATA_LIMIT>();
 	CreateRefungibleExData {
 		const_data,
-		variable_data,
 		users: users
 			.into_iter()
 			.collect::<BTreeMap<_, _>>()
@@ -203,14 +201,4 @@
 		let item = create_max_item(&collection, &owner, [(sender.clone(), 200)])?;
 		<Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;
 	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}
-
-	set_variable_metadata {
-		let b in 0..CUSTOM_DATA_LIMIT;
-		bench_init!{
-			owner: sub; collection: collection(owner);
-			sender: cross_from_sub(owner);
-		};
-		let item = create_max_item(&collection, &sender, [(sender.clone(), 200)])?;
-		let data = create_var_data(b).try_into().unwrap();
-	}: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}
 }
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -17,10 +17,10 @@
 use core::marker::PhantomData;
 
 use sp_std::collections::btree_map::BTreeMap;
-use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight, BoundedVec};
+use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight};
 use up_data_structs::{
-	CollectionId, TokenId, CustomDataLimit, CreateItemExData, CreateRefungibleExData,
-	budget::Budget, Property, PropertyKey, PropertyKeyPermission,
+	CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,
+	PropertyKey, PropertyKeyPermission,
 };
 use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
 use sp_runtime::DispatchError;
@@ -110,10 +110,6 @@
 
 	fn burn_from() -> Weight {
 		<SelfWeightOf<T>>::burn_from()
-	}
-
-	fn set_variable_metadata(bytes: u32) -> Weight {
-		<SelfWeightOf<T>>::set_variable_metadata(bytes)
 	}
 }
 
@@ -124,7 +120,6 @@
 	match data {
 		up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {
 			const_data: data.const_data,
-			variable_data: data.variable_data,
 			users: {
 				let mut out = BTreeMap::new();
 				out.insert(to.clone(), data.pieces);
@@ -306,19 +301,6 @@
 		fail!(<Error<T>>::SettingPropertiesNotAllowed)
 	}
 
-	fn set_variable_metadata(
-		&self,
-		sender: T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResultWithPostInfo {
-		let len = data.len();
-		with_weight(
-			<Pallet<T>>::set_variable_metadata(self, &sender, token, data),
-			<CommonWeights<T>>::set_variable_metadata(len as u32),
-		)
-	}
-
 	fn check_nesting(
 		&self,
 		_sender: <T>::CrossAccountId,
@@ -357,13 +339,12 @@
 			.const_data
 			.into_inner()
 	}
-	fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
-		<TokenData<T>>::get((self.id, token))
-			.variable_data
-			.into_inner()
-	}
 
-	fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {
+	fn token_properties(
+		&self,
+		_token_id: TokenId,
+		_keys: Option<Vec<PropertyKey>>,
+	) -> Vec<Property> {
 		Vec::new()
 	}
 
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -41,16 +41,23 @@
 pub mod weights;
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
+#[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]
 pub struct ItemData {
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
+
+	#[version(..2)]
 	pub variable_data: BoundedVec<u8, CustomDataLimit>,
 }
 
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};
+	use frame_support::{
+		Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key,
+		traits::StorageVersion,
+	};
+	use frame_system::pallet_prelude::*;
 	use up_data_structs::{CollectionId, TokenId};
 	use super::weights::WeightInfo;
 
@@ -73,7 +80,10 @@
 		type WeightInfo: WeightInfo;
 	}
 
+	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
 	#[pallet::pallet]
+	#[pallet::storage_version(STORAGE_VERSION)]
 	#[pallet::generate_store(pub(super) trait Store)]
 	pub struct Pallet<T>(_);
 
@@ -146,6 +156,19 @@
 		Value = u128,
 		QueryKind = ValueQuery,
 	>;
+
+	#[pallet::hooks]
+	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
+		fn on_runtime_upgrade() -> Weight {
+			if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
+				<TokenData<T>>::translate_values::<ItemDataVersion1, _>(|v| {
+					Some(<ItemDataVersion2>::from(v))
+				})
+			}
+
+			0
+		}
+	}
 }
 
 pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
@@ -494,7 +517,6 @@
 				(collection.id, token_id),
 				ItemData {
 					const_data: token.const_data,
-					variable_data: token.variable_data,
 				},
 			);
 			for (user, amount) in token.users.into_iter() {
@@ -643,31 +665,6 @@
 		if let Some(allowance) = allowance {
 			Self::set_allowance_unchecked(collection, from, spender, token, allowance);
 		}
-		Ok(())
-	}
-
-	pub fn set_variable_metadata(
-		collection: &RefungibleHandle<T>,
-		sender: &T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResult {
-		collection.check_can_update_meta(
-			sender,
-			&T::CrossAccountId::from_sub(collection.owner.clone()),
-		)?;
-
-		let token_data = <TokenData<T>>::get((collection.id, token));
-
-		// =========
-
-		<TokenData<T>>::insert(
-			(collection.id, token),
-			ItemData {
-				variable_data: data,
-				..token_data
-			},
-		);
 		Ok(())
 	}
 
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -53,7 +53,6 @@
 	fn transfer_from_removing() -> Weight;
 	fn transfer_from_creating_removing() -> Weight;
 	fn burn_from() -> Weight;
-	fn set_variable_metadata(b: u32, ) -> Weight;
 }
 
 /// Weights for pallet_refungible using the Substrate node and recommended hardware.
@@ -242,12 +241,6 @@
 		(42_043_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(7 as Weight))
-	}
-	// Storage: Refungible TokenData (r:1 w:1)
-	fn set_variable_metadata(_b: u32, ) -> Weight {
-		(7_364_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(1 as Weight))
-			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
 }
 
@@ -436,11 +429,5 @@
 		(42_043_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
-	}
-	// Storage: Refungible TokenData (r:1 w:1)
-	fn set_variable_metadata(_b: u32, ) -> Weight {
-		(7_364_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
 }
modifiedpallets/unique/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -168,9 +168,4 @@
 			nesting_rule: None,
 		};
 	}: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)
-
-	set_meta_update_permission_flag {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let collection = create_nft_collection::<T>(caller.clone())?;
-	}: _(RawOrigin::Signed(caller.clone()), collection, MetaUpdatePermission::Admin)
 }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -35,16 +35,16 @@
 use frame_system::{self as system, ensure_signed};
 use sp_runtime::{sp_std::prelude::Vec};
 use up_data_structs::{
-	CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,
-	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
-	AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,
-	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,
-	CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,
+	CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH,
+	MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,
+	CollectionLimits, CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState,
+	CreateCollectionData, CreateItemExData, budget, CollectionField, Property, PropertyKey,
+	PropertyKeyPermission,
 };
 use pallet_evm::account::CrossAccountId;
 use pallet_common::{
-	CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,
-	dispatch::dispatch_call, dispatch::CollectionDispatch,
+	CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,
+	dispatch::CollectionDispatch,
 };
 
 #[cfg(feature = "runtime-benchmarks")]
@@ -240,7 +240,9 @@
 
 		/// Variable metadata sponsoring
 		/// Collection id (controlled?2), token id (controlled?2)
+		#[deprecated]
 		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
+
 		/// Approval sponsoring
 		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
 		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
@@ -261,6 +263,14 @@
 			0
 		}
 
+		fn on_runtime_upgrade() -> Weight {
+			let limit = None;
+
+			<VariableMetaDataBasket<T>>::remove_all(limit);
+
+			0
+		}
+
 		/// 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.
 		///
 		/// # Permissions
@@ -333,7 +343,6 @@
 			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);
 			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);
 
-			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);
 			<NftApproveBasket<T>>::remove_prefix(collection_id, None);
 			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);
 			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);
@@ -929,59 +938,6 @@
 			let budget = budget::Value::new(2);
 
 			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))
-		}
-
-		/// Set off-chain data schema.
-		///
-		/// # Permissions
-		///
-		/// * Collection Owner
-		/// * Collection Admin
-		///
-		/// # Arguments
-		///
-		/// * collection_id.
-		///
-		/// * schema: String representing the offchain data schema.
-		#[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]
-		#[transactional]
-		pub fn set_variable_meta_data (
-			origin,
-			collection_id: CollectionId,
-			item_id: TokenId,
-			data: BoundedVec<u8, CustomDataLimit>,
-		) -> DispatchResultWithPostInfo {
-			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-
-			dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))
-		}
-
-		/// Set meta_update_permission value for particular collection
-		///
-		/// # Permissions
-		///
-		/// * Collection Owner.
-		///
-		/// # Arguments
-		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * value: New flag value.
-		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]
-		#[transactional]
-		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {
-			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-
-			ensure!(
-				target_collection.meta_update_permission != MetaUpdatePermission::None,
-				<CommonError<T>>::MetadataFlagFrozen,
-			);
-			target_collection.check_is_owner(&sender)?;
-
-			target_collection.meta_update_permission = value;
-
-			target_collection.save()
 		}
 
 		/// Set schema standard
modifiedpallets/unique/src/weights.rsdiffbeforeafterboth
--- a/pallets/unique/src/weights.rs
+++ b/pallets/unique/src/weights.rs
@@ -49,7 +49,6 @@
 	fn set_const_on_chain_schema(b: u32, ) -> Weight;
 	fn set_schema_version() -> Weight;
 	fn set_collection_limits() -> Weight;
-	fn set_meta_update_permission_flag() -> Weight;
 }
 
 /// Weights for pallet_unique using the Substrate node and recommended hardware.
@@ -167,12 +166,6 @@
 	// Storage: Common CollectionById (r:1 w:1)
 	fn set_collection_limits() -> Weight {
 		(15_339_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(1 as Weight))
-			.saturating_add(T::DbWeight::get().writes(1 as Weight))
-	}
-	// Storage: Common CollectionById (r:1 w:1)
-	fn set_meta_update_permission_flag() -> Weight {
-		(7_214_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
@@ -292,12 +285,6 @@
 	// Storage: Common CollectionById (r:1 w:1)
 	fn set_collection_limits() -> Weight {
 		(15_339_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
-	}
-	// Storage: Common CollectionById (r:1 w:1)
-	fn set_meta_update_permission_flag() -> Weight {
-		(7_214_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -22,7 +22,8 @@
 };
 use frame_support::{
 	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},
-	traits::Get, parameter_types,
+	traits::Get,
+	parameter_types,
 };
 
 #[cfg(feature = "serde")]
@@ -40,7 +41,10 @@
 	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,
 };
 pub use rmrk_types::{
-	primitives::{CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId, PartId as RmrkPartId, ResourceId as RmrkResourceId},
+	primitives::{
+		CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,
+		PartId as RmrkPartId, ResourceId as RmrkResourceId,
+	},
 	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
 };
 
@@ -85,6 +89,7 @@
 
 // Schema limits
 pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;
+pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;
 pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;
 
 pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;
@@ -318,8 +323,12 @@
 	pub limits: CollectionLimitsVersion2,
 
 	#[version(..2)]
+	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
+
+	#[version(..2)]
 	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
 
+	#[version(..2)]
 	pub meta_update_permission: MetaUpdatePermission,
 }
 
@@ -339,7 +348,6 @@
 	pub sponsorship: SponsorshipState<AccountId>,
 	pub limits: CollectionLimits,
 	pub const_on_chain_schema: Vec<u8>,
-	pub meta_update_permission: MetaUpdatePermission,
 	pub token_property_permissions: Vec<PropertyKeyPermission>,
 	pub properties: Vec<Property>,
 }
@@ -365,7 +373,6 @@
 	pub pending_sponsor: Option<AccountId>,
 	pub limits: Option<CollectionLimits>,
 	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
-	pub meta_update_permission: Option<MetaUpdatePermission>,
 	pub token_property_permissions: CollectionPropertiesPermissionsVec,
 	pub properties: CollectionPropertiesVec,
 }
@@ -376,28 +383,6 @@
 pub type CollectionPropertiesVec =
 	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;
 
-#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct NftItemType<AccountId> {
-	pub owner: AccountId,
-	pub const_data: Vec<u8>,
-	pub variable_data: Vec<u8>,
-}
-
-#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct FungibleItemType {
-	pub value: u128,
-}
-
-#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct ReFungibleItemType<AccountId> {
-	pub owner: Vec<Ownership<AccountId>>,
-	pub const_data: Vec<u8>,
-	pub variable_data: Vec<u8>,
-}
-
 /// All fields are wrapped in `Option`s, where None means chain default
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
@@ -405,6 +390,8 @@
 pub struct CollectionLimits {
 	pub account_token_ownership_limit: Option<u32>,
 	pub sponsored_data_size: Option<u32>,
+
+	/// FIXME should we delete this or repurpose it?
 	/// None - setVariableMetadata is not sponsored
 	/// Some(v) - setVariableMetadata is sponsored
 	///           if there is v block between txs
@@ -502,9 +489,6 @@
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
-	#[derivative(Debug(format_with = "bounded::vec_debug"))]
-	pub variable_data: BoundedVec<u8, CustomDataLimit>,
 
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
@@ -524,26 +508,16 @@
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
-	#[derivative(Debug(format_with = "bounded::vec_debug"))]
-	pub variable_data: BoundedVec<u8, CustomDataLimit>,
 	pub pieces: u128,
 }
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub enum MetaUpdatePermission {
 	ItemOwner,
 	Admin,
 	None,
 }
 
-impl Default for MetaUpdatePermission {
-	fn default() -> Self {
-		Self::ItemOwner
-	}
-}
-
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum CreateItemData {
@@ -557,8 +531,6 @@
 pub struct CreateNftExData<CrossAccountId> {
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
-	#[derivative(Debug(format_with = "bounded::vec_debug"))]
-	pub variable_data: BoundedVec<u8, CustomDataLimit>,
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub properties: CollectionPropertiesVec,
 	pub owner: CrossAccountId,
@@ -569,8 +541,6 @@
 pub struct CreateRefungibleExData<CrossAccountId> {
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
-	#[derivative(Debug(format_with = "bounded::vec_debug"))]
-	pub variable_data: BoundedVec<u8, CustomDataLimit>,
 	#[derivative(Debug(format_with = "bounded::map_debug"))]
 	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
 }
@@ -598,8 +568,8 @@
 impl CreateItemData {
 	pub fn data_size(&self) -> usize {
 		match self {
-			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),
-			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),
+			CreateItemData::NFT(data) => data.const_data.len(),
+			CreateItemData::ReFungible(data) => data.const_data.len(),
 			_ => 0,
 		}
 	}
@@ -700,24 +670,65 @@
 	NoSpaceForProperty,
 	PropertyLimitReached,
 	InvalidCharacterInPropertyKey,
+	PropertyKeyIsTooLong,
 	EmptyPropertyKey,
 }
 
-pub trait TrySet: Sized {
+#[derive(Clone, Copy)]
+pub enum PropertyScope {
+	None,
+	Rmrk,
+}
+
+impl PropertyScope {
+	fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {
+		let scope_str: &[u8] = match self {
+			Self::None => return Ok(key),
+			Self::Rmrk => b"rmrk",
+		};
+
+		[scope_str, b":", key.as_slice()]
+			.concat()
+			.try_into()
+			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)
+	}
+}
+
+pub trait TrySetProperty: Sized {
 	type Value;
 
-	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;
+	fn try_scoped_set(
+		&mut self,
+		scope: PropertyScope,
+		key: PropertyKey,
+		value: Self::Value,
+	) -> Result<(), PropertiesError>;
 
-	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>
+	fn try_scoped_set_from_iter<I>(
+		&mut self,
+		scope: PropertyScope,
+		iter: I,
+	) -> Result<(), PropertiesError>
 	where
 		I: Iterator<Item = (PropertyKey, Self::Value)>,
 	{
 		for (key, value) in iter {
-			self.try_set(key, value)?;
+			self.try_scoped_set(scope, key, value)?;
 		}
 
 		Ok(())
 	}
+
+	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {
+		self.try_scoped_set(PropertyScope::None, key, value)
+	}
+
+	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>
+	where
+		I: Iterator<Item = (PropertyKey, Self::Value)>,
+	{
+		self.try_scoped_set_from_iter(PropertyScope::None, iter)
+	}
 }
 
 #[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]
@@ -751,12 +762,10 @@
 		}
 
 		for byte in key.as_slice().iter() {
-			match char::from_u32(*byte as u32) {
-				Some(ch)
-					if ch.is_ascii_alphanumeric()
-					|| ch == '_'
-					|| ch == '-' => { /* OK */ },
-				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)
+			let byte = *byte;
+
+			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' {
+				return Err(PropertiesError::InvalidCharacterInPropertyKey);
 			}
 		}
 
@@ -764,12 +773,18 @@
 	}
 }
 
-impl<Value> TrySet for PropertiesMap<Value> {
+impl<Value> TrySetProperty for PropertiesMap<Value> {
 	type Value = Value;
 
-	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {
+	fn try_scoped_set(
+		&mut self,
+		scope: PropertyScope,
+		key: PropertyKey,
+		value: Self::Value,
+	) -> Result<(), PropertiesError> {
 		Self::check_property_key(&key)?;
 
+		let key = scope.apply(key)?;
 		self.0
 			.try_insert(key, value)
 			.map_err(|_| PropertiesError::PropertyLimitReached)?;
@@ -816,17 +831,22 @@
 	}
 }
 
-impl TrySet for Properties {
+impl TrySetProperty for Properties {
 	type Value = PropertyValue;
 
-	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {
+	fn try_scoped_set(
+		&mut self,
+		scope: PropertyScope,
+		key: PropertyKey,
+		value: Self::Value,
+	) -> Result<(), PropertiesError> {
 		let value_len = value.len();
 
 		if self.consumed_space as usize + value_len > self.space_limit as usize {
 			return Err(PropertiesError::NoSpaceForProperty);
 		}
 
-		self.map.try_set(key, value)?;
+		self.map.try_scoped_set(scope, key, value)?;
 
 		self.consumed_space += value_len as u32;
 
@@ -869,34 +889,23 @@
 	pub const RmrkPartsLimit: u32 = 3;
 }
 
-pub type RmrkCollectionInfo<AccountId> = CollectionInfo<
-	RmrkString,
-	BoundedVec<u8, RmrkCollectionSymbolLimit>,
-	AccountId
->;
-pub type RmrkInstanceInfo<AccountId> = NftInfo<
-	AccountId, 
-	Permill,
-	RmrkString
->;
-pub type RmrkResourceInfo = ResourceInfo::<
+pub type RmrkCollectionInfo<AccountId> =
+	CollectionInfo<RmrkString, BoundedVec<u8, RmrkCollectionSymbolLimit>, AccountId>;
+pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
+pub type RmrkResourceInfo = ResourceInfo<
 	BoundedVec<u8, RmrkResourceSymbolLimit>,
 	RmrkString,
-	BoundedVec<RmrkPartId, RmrkPartsLimit>
->;
-pub type RmrkPropertyInfo = PropertyInfo<
-	BoundedVec<u8, RmrkKeyLimit>, 
-	BoundedVec<u8, RmrkValueLimit>
+	BoundedVec<RmrkPartId, RmrkPartsLimit>,
 >;
+pub type RmrkPropertyInfo =
+	PropertyInfo<BoundedVec<u8, RmrkKeyLimit>, BoundedVec<u8, RmrkValueLimit>>;
 pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
-pub type RmrkPartType = PartType<
-	RmrkString,
-	BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>
->;
+pub type RmrkPartType =
+	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;
 pub type RmrkTheme = Theme<RmrkString, Vec<ThemeProperty<RmrkString>>>;
 
 pub type RmrkRpcString = Vec<u8>;
 pub type RmrkThemeName = RmrkRpcString;
 pub type RmrkPropertyKey = RmrkRpcString;
 
-type RmrkString = BoundedVec<u8, RmrkStringLimit>;
\ No newline at end of file
+type RmrkString = BoundedVec<u8, RmrkStringLimit>;
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -42,22 +42,25 @@
 		fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
 		fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
 		fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;
-		fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;
 
-		fn collection_properties(collection: CollectionId, properties: Vec<Vec<u8>>) -> Result<Vec<Property>>;
+		fn collection_properties(collection: CollectionId, properties: Option<Vec<Vec<u8>>>) -> Result<Vec<Property>>;
 
 		fn token_properties(
 			collection: CollectionId,
 			token_id: TokenId,
-			properties: Vec<Vec<u8>>
+			properties: Option<Vec<Vec<u8>>>
 		) -> Result<Vec<Property>>;
 
 		fn property_permissions(
 			collection: CollectionId,
-			properties: Vec<Vec<u8>>
+			properties: Option<Vec<Vec<u8>>>
 		) -> Result<Vec<PropertyKeyPermission>>;
 
-		fn token_data(collection: CollectionId, token_id: TokenId, keys: Vec<Vec<u8>>) -> Result<TokenData<CrossAccountId>>;
+		fn token_data(
+			collection: CollectionId,
+			token_id: TokenId,
+			keys: Option<Vec<Vec<u8>>>
+		) -> Result<TokenData<CrossAccountId>>;
 
 		fn total_supply(collection: CollectionId) -> Result<u32>;
 		fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32>;
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -32,15 +32,14 @@
                 fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {
                     dispatch_unique_runtime!(collection.const_metadata(token))
                 }
-                fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {
-                    dispatch_unique_runtime!(collection.variable_metadata(token))
-                }
 
                 fn collection_properties(
                     collection: CollectionId,
-                    keys: Vec<Vec<u8>>
+                    keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<Property>, DispatchError> {
-                    let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
+                    let keys = keys.map(
+                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
 
                     pallet_common::Pallet::<Runtime>::filter_collection_properties(collection, keys)
                 }
@@ -48,17 +47,22 @@
                 fn token_properties(
                     collection: CollectionId,
                     token_id: TokenId,
-                    keys: Vec<Vec<u8>>
+                    keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<Property>, DispatchError> {
-                    let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
+                    let keys = keys.map(
+                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
+
                     dispatch_unique_runtime!(collection.token_properties(token_id, keys))
                 }
 
                 fn property_permissions(
                     collection: CollectionId,
-                    keys: Vec<Vec<u8>>
+                    keys: Option<Vec<Vec<u8>>>
                 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
-                    let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
+                    let keys = keys.map(
+                        |keys| pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)
+                    ).transpose()?;
 
                     pallet_common::Pallet::<Runtime>::filter_property_permissions(collection, keys)
                 }
@@ -66,7 +70,7 @@
                 fn token_data(
                     collection: CollectionId,
                     token_id: TokenId,
-                    keys: Vec<Vec<u8>>
+                    keys: Option<Vec<Vec<u8>>>
                 ) -> Result<TokenData<CrossAccountId>, DispatchError> {
                     let token_data = TokenData {
                         const_data: Self::const_metadata(collection, token_id)?,
@@ -232,7 +236,7 @@
                                     })
                                 })
                                 .collect();
-        
+
                             properties
                         }
                         None => {
@@ -253,7 +257,7 @@
                     let token_id = TokenId(nft_id);
 
 		            let properties = pallet_nonfungible::Pallet::<Runtime>::token_properties((collection_id, token_id)); // todo look into usage of nonfungible
-                    
+
                     return Ok(match filter_keys {
                         Some(keys) => {
                             let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
@@ -266,7 +270,7 @@
                                     })
                                 })
                                 .collect();
-        
+
                             properties
                         }
                         None => {
@@ -300,7 +304,7 @@
                     let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(
                         Vec::from([String::from("rmrk:base-type").into_bytes()])
                     )?;
-                    let properties = pallet_common::Pallet::<Runtime>::filter_collection_properties(collection_id, keys)?;
+                    let properties = pallet_common::Pallet::<Runtime>::filter_collection_properties(collection_id, Some(keys))?;
                     //ensure!(properties.len() == 1); // todo make sure it's fine to have ensure in place // no access to errors from here? displace?
 
                     Ok(Some( RmrkBaseInfo {
modifiedruntime/common/src/sponsoring.rsdiffbeforeafterboth
--- a/runtime/common/src/sponsoring.rs
+++ b/runtime/common/src/sponsoring.rs
@@ -21,17 +21,16 @@
 	storage::{StorageMap, StorageDoubleMap, StorageNMap},
 };
 use up_data_structs::{
-	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MetaUpdatePermission,
-	NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode,
-	CreateItemData,
+	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
+	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,
 };
 use sp_runtime::traits::Saturating;
 use pallet_common::{CollectionHandle};
 use pallet_evm::account::CrossAccountId;
 use pallet_unique::{
 	Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
-	NftApproveBasket, VariableMetaDataBasket, CreateItemBasket, ReFungibleTransferBasket,
-	FungibleTransferBasket, NftTransferBasket,
+	NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,
+	NftTransferBasket,
 };
 use pallet_fungible::Config as FungibleConfig;
 use pallet_nonfungible::Config as NonfungibleConfig;
@@ -136,63 +135,6 @@
 	}
 
 	CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);
-
-	Some(())
-}
-
-pub fn withdraw_set_variable_meta_data<T: Config>(
-	who: &T::CrossAccountId,
-	collection: &CollectionHandle<T>,
-	item_id: &TokenId,
-	data: &[u8],
-) -> Option<()> {
-	// TODO: make it work for admins
-	if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {
-		return None;
-	}
-	// preliminary sponsoring correctness check
-	match collection.mode {
-		CollectionMode::NFT => {
-			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
-			if !owner.conv_eq(who) {
-				return None;
-			}
-		}
-		CollectionMode::Fungible(_) => {
-			if item_id != &TokenId::default() {
-				return None;
-			}
-			if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
-				return None;
-			}
-		}
-		CollectionMode::ReFungible => {
-			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
-				return None;
-			}
-		}
-	}
-
-	// Can't sponsor fungible collection, this tx will be rejected
-	// as invalid
-	if matches!(collection.mode, CollectionMode::Fungible(_)) {
-		return None;
-	}
-	if data.len() > collection.limits.sponsored_data_size() as usize {
-		return None;
-	}
-
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection.limits.sponsored_data_rate_limit()?;
-
-	if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	<VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);
 
 	Some(())
 }
@@ -290,20 +232,6 @@
 			} => {
 				let (sponsor, collection) = load(*collection_id)?;
 				withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
-			}
-			UniqueCall::set_variable_meta_data {
-				collection_id,
-				item_id,
-				data,
-			} => {
-				let (sponsor, collection) = load(*collection_id)?;
-				withdraw_set_variable_meta_data::<T>(
-					&T::CrossAccountId::from_sub(who.clone()),
-					&collection,
-					item_id,
-					data,
-				)
-				.map(|()| sponsor)
 			}
 			_ => None,
 		}
modifiedruntime/common/src/weights.rsdiffbeforeafterboth
--- a/runtime/common/src/weights.rs
+++ b/runtime/common/src/weights.rs
@@ -86,10 +86,6 @@
 		dispatch_weight::<T>() + max_weight_of!(transfer_from())
 	}
 
-	fn set_variable_metadata(bytes: u32) -> Weight {
-		dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))
-	}
-
 	fn burn_from() -> Weight {
 		dispatch_weight::<T>() + max_weight_of!(burn_from())
 	}
modifiedruntime/tests/src/tests.rsdiffbeforeafterboth
before · runtime/tests/src/tests.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Tests to be written here18use crate::{Test, TestCrossAccountId, CollectionCreationPrice, Origin, Unique, new_test_ext};19use up_data_structs::{20	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,21	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,22	TokenId, MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionField, SchemaVersion,23	CollectionMode, AccessMode,24};25use frame_support::{assert_noop, assert_ok, assert_err};26use sp_std::convert::TryInto;27use pallet_evm::account::CrossAccountId;28use pallet_common::Error as CommonError;29use pallet_unique::Error as UniqueError;3031fn add_balance(user: u64, value: u64) {32	const DONOR_USER: u64 = 999;33	assert_ok!(<pallet_balances::Pallet<Test>>::set_balance(34		Origin::root(),35		DONOR_USER,36		value,37		038	));39	assert_ok!(<pallet_balances::Pallet<Test>>::force_transfer(40		Origin::root(),41		DONOR_USER,42		user,43		value44	));45}4647fn default_nft_data() -> CreateNftData {48	CreateNftData {49		const_data: vec![1, 2, 3].try_into().unwrap(),50		variable_data: vec![3, 2, 1].try_into().unwrap(),51	}52}5354fn default_fungible_data() -> CreateFungibleData {55	CreateFungibleData { value: 5 }56}5758fn default_re_fungible_data() -> CreateReFungibleData {59	CreateReFungibleData {60		const_data: vec![1, 2, 3].try_into().unwrap(),61		variable_data: vec![3, 2, 1].try_into().unwrap(),62		pieces: 1023,63	}64}6566fn create_test_collection_for_owner(67	mode: &CollectionMode,68	owner: u64,69	id: CollectionId,70) -> CollectionId {71	add_balance(owner, CollectionCreationPrice::get() as u64 + 1);7273	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();74	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();75	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();7677	let data: CreateCollectionData<u64> = CreateCollectionData {78		name: col_name1.try_into().unwrap(),79		description: col_desc1.try_into().unwrap(),80		token_prefix: token_prefix1.try_into().unwrap(),81		mode: mode.clone(),82		..Default::default()83	};8485	let origin1 = Origin::signed(owner);86	assert_ok!(Unique::create_collection_ex(origin1, data));8788	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();89	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();90	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();91	assert_eq!(92		<pallet_common::CollectionById<Test>>::get(id)93			.unwrap()94			.owner,95		owner96	);97	assert_eq!(98		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,99		saved_col_name100	);101	assert_eq!(102		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,103		*mode104	);105	assert_eq!(106		<pallet_common::CollectionById<Test>>::get(id)107			.unwrap()108			.description,109		saved_description110	);111	assert_eq!(112		<pallet_common::CollectionById<Test>>::get(id)113			.unwrap()114			.token_prefix,115		saved_prefix116	);117	id118}119120fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {121	create_test_collection_for_owner(&mode, 1, id)122}123124fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {125	let origin1 = Origin::signed(1);126	assert_ok!(Unique::create_item(127		origin1,128		collection_id,129		account(1),130		data.clone()131	));132}133134fn account(sub: u64) -> TestCrossAccountId {135	TestCrossAccountId::from_sub(sub)136}137138// Use cases tests region139// #region140141#[test]142fn set_version_schema() {143	new_test_ext().execute_with(|| {144		let origin1 = Origin::signed(1);145		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));146147		assert_ok!(Unique::set_schema_version(148			origin1,149			collection_id,150			SchemaVersion::Unique151		));152		assert_eq!(153			<pallet_common::CollectionById<Test>>::get(collection_id)154				.unwrap()155				.schema_version,156			SchemaVersion::Unique157		);158	});159}160161#[test]162fn check_not_sufficient_founds() {163	new_test_ext().execute_with(|| {164		let acc: u64 = 1;165		<pallet_balances::Pallet<Test>>::set_balance(Origin::root(), acc, 0, 0).unwrap();166167		let name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();168		let description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();169		let token_prefix: Vec<u8> = b"token_prefix1\0".to_vec();170171		let data: CreateCollectionData<<Test as frame_system::Config>::AccountId> =172			CreateCollectionData {173				name: name.try_into().unwrap(),174				description: description.try_into().unwrap(),175				token_prefix: token_prefix.try_into().unwrap(),176				mode: CollectionMode::NFT,177				..Default::default()178			};179180		let result = Unique::create_collection_ex(Origin::signed(acc), data);181		assert_err!(result, <CommonError<Test>>::NotSufficientFounds);182	});183}184185#[test]186fn create_fungible_collection_fails_with_large_decimal_numbers() {187	new_test_ext().execute_with(|| {188		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();189		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();190		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();191192		let data: CreateCollectionData<u64> = CreateCollectionData {193			name: col_name1.try_into().unwrap(),194			description: col_desc1.try_into().unwrap(),195			token_prefix: token_prefix1.try_into().unwrap(),196			mode: CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1),197			..Default::default()198		};199200		let origin1 = Origin::signed(1);201		assert_noop!(202			Unique::create_collection_ex(origin1, data),203			UniqueError::<Test>::CollectionDecimalPointLimitExceeded204		);205	});206}207208#[test]209fn create_nft_item() {210	new_test_ext().execute_with(|| {211		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));212213		let data = default_nft_data();214		create_test_item(collection_id, &data.clone().into());215216		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();217		assert_eq!(item.const_data, data.const_data.into_inner());218		assert_eq!(item.variable_data, data.variable_data.into_inner());219	});220}221222// Use cases tests region223// #region224#[test]225fn create_nft_multiple_items() {226	new_test_ext().execute_with(|| {227		create_test_collection(&CollectionMode::NFT, CollectionId(1));228229		let origin1 = Origin::signed(1);230231		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];232233		assert_ok!(Unique::create_multiple_items(234			origin1,235			CollectionId(1),236			account(1),237			items_data238				.clone()239				.into_iter()240				.map(|d| { d.into() })241				.collect()242		));243		for (index, data) in items_data.into_iter().enumerate() {244			let item = <pallet_nonfungible::TokenData<Test>>::get((245				CollectionId(1),246				TokenId((index + 1) as u32),247			))248			.unwrap();249			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());250			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());251		}252	});253}254255#[test]256fn create_refungible_item() {257	new_test_ext().execute_with(|| {258		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));259260		let data = default_re_fungible_data();261		create_test_item(collection_id, &data.clone().into());262		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));263		let balance =264			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));265		assert_eq!(item.const_data, data.const_data.into_inner());266		assert_eq!(item.variable_data, data.variable_data.into_inner());267		assert_eq!(balance, 1023);268	});269}270271#[test]272fn create_multiple_refungible_items() {273	new_test_ext().execute_with(|| {274		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));275276		let origin1 = Origin::signed(1);277278		let items_data = vec![279			default_re_fungible_data(),280			default_re_fungible_data(),281			default_re_fungible_data(),282		];283284		assert_ok!(Unique::create_multiple_items(285			origin1,286			CollectionId(1),287			account(1),288			items_data289				.clone()290				.into_iter()291				.map(|d| { d.into() })292				.collect()293		));294		for (index, data) in items_data.into_iter().enumerate() {295			let item = <pallet_refungible::TokenData<Test>>::get((296				CollectionId(1),297				TokenId((index + 1) as u32),298			));299			let balance =300				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));301			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());302			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());303			assert_eq!(balance, 1023);304		}305	});306}307308#[test]309fn create_fungible_item() {310	new_test_ext().execute_with(|| {311		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));312313		let data = default_fungible_data();314		create_test_item(collection_id, &data.into());315316		assert_eq!(317			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),318			5319		);320	});321}322323//#[test]324// fn create_multiple_fungible_items() {325//     new_test_ext().execute_with(|| {326//         default_limits();327328//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));329330//         let origin1 = Origin::signed(1);331332//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];333334//         assert_ok!(Unique::create_multiple_items(335//             origin1.clone(),336//             1,337//             1,338//             items_data.clone().into_iter().map(|d| { d.into() }).collect()339//         ));340341//         for (index, _) in items_data.iter().enumerate() {342//             assert_eq!(Unique::fungible_item_id(1, (index + 1) as TokenId).value, 5);343//         }344//         assert_eq!(Unique::balance_count(1, 1), 3000);345//         assert_eq!(Unique::address_tokens(1, 1), [1, 2, 3]);346//     });347// }348349#[test]350fn transfer_fungible_item() {351	new_test_ext().execute_with(|| {352		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));353354		let origin1 = Origin::signed(1);355		let origin2 = Origin::signed(2);356357		let data = default_fungible_data();358		create_test_item(collection_id, &data.into());359360		assert_eq!(361			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),362			5363		);364365		// change owner scenario366		assert_ok!(Unique::transfer(367			origin1,368			account(2),369			CollectionId(1),370			TokenId(0),371			5372		));373		assert_eq!(374			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),375			0376		);377378		// split item scenario379		assert_ok!(Unique::transfer(380			origin2.clone(),381			account(3),382			CollectionId(1),383			TokenId(0),384			3385		));386387		// split item and new owner has account scenario388		assert_ok!(Unique::transfer(389			origin2,390			account(3),391			CollectionId(1),392			TokenId(0),393			1394		));395		assert_eq!(396			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),397			1398		);399		assert_eq!(400			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),401			4402		);403	});404}405406#[test]407fn transfer_refungible_item() {408	new_test_ext().execute_with(|| {409		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));410411		// Create RFT 1 in 1023 pieces for account 1412		let data = default_re_fungible_data();413		create_test_item(collection_id, &data.clone().into());414		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));415		assert_eq!(item.const_data, data.const_data.into_inner());416		assert_eq!(item.variable_data, data.variable_data.into_inner());417		assert_eq!(418			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),419			1420		);421		assert_eq!(422			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),423			1023424		);425		assert_eq!(426			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),427			true428		);429430		// Account 1 transfers all 1023 pieces of RFT 1 to account 2431		let origin1 = Origin::signed(1);432		let origin2 = Origin::signed(2);433		assert_ok!(Unique::transfer(434			origin1,435			account(2),436			CollectionId(1),437			TokenId(1),438			1023439		));440		assert_eq!(441			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),442			1023443		);444		assert_eq!(445			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),446			0447		);448		assert_eq!(449			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),450			1451		);452		assert_eq!(453			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),454			false455		);456		assert_eq!(457			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),458			true459		);460461		// Account 2 transfers 500 pieces of RFT 1 to account 3462		assert_ok!(Unique::transfer(463			origin2.clone(),464			account(3),465			CollectionId(1),466			TokenId(1),467			500468		));469		assert_eq!(470			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),471			523472		);473		assert_eq!(474			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),475			500476		);477		assert_eq!(478			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),479			1480		);481		assert_eq!(482			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),483			1484		);485		assert_eq!(486			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),487			true488		);489		assert_eq!(490			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),491			true492		);493494		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance495		assert_ok!(Unique::transfer(496			origin2,497			account(3),498			CollectionId(1),499			TokenId(1),500			200501		));502		assert_eq!(503			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),504			323505		);506		assert_eq!(507			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),508			700509		);510		assert_eq!(511			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),512			1513		);514		assert_eq!(515			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),516			1517		);518		assert_eq!(519			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),520			true521		);522		assert_eq!(523			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),524			true525		);526	});527}528529#[test]530fn transfer_nft_item() {531	new_test_ext().execute_with(|| {532		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));533534		let data = default_nft_data();535		create_test_item(collection_id, &data.into());536		assert_eq!(537			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),538			1539		);540		assert_eq!(541			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),542			true543		);544545		let origin1 = Origin::signed(1);546		// default scenario547		assert_ok!(Unique::transfer(548			origin1,549			account(2),550			CollectionId(1),551			TokenId(1),552			1553		));554		assert_eq!(555			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),556			0557		);558		assert_eq!(559			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),560			1561		);562		assert_eq!(563			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),564			false565		);566		assert_eq!(567			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),568			true569		);570	});571}572573#[test]574fn transfer_nft_item_wrong_value() {575	new_test_ext().execute_with(|| {576		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));577578		let data = default_nft_data();579		create_test_item(collection_id, &data.into());580		assert_eq!(581			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),582			1583		);584		assert_eq!(585			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),586			true587		);588589		let origin1 = Origin::signed(1);590591		assert_noop!(592			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)593				.map_err(|e| e.error),594			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount595		);596	});597}598599#[test]600fn transfer_nft_item_zero_value() {601	new_test_ext().execute_with(|| {602		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));603604		let data = default_nft_data();605		create_test_item(collection_id, &data.into());606		assert_eq!(607			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),608			1609		);610		assert_eq!(611			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),612			true613		);614615		let origin1 = Origin::signed(1);616617		// Transferring 0 amount works on NFT...618		assert_ok!(Unique::transfer(619			origin1,620			account(2),621			CollectionId(1),622			TokenId(1),623			0624		));625		// ... and results in no transfer626		assert_eq!(627			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),628			1629		);630		assert_eq!(631			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),632			true633		);634	});635}636637#[test]638fn nft_approve_and_transfer_from() {639	new_test_ext().execute_with(|| {640		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));641642		let data = default_nft_data();643		create_test_item(collection_id, &data.into());644645		let origin1 = Origin::signed(1);646		let origin2 = Origin::signed(2);647648		assert_eq!(649			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),650			1651		);652		assert_eq!(653			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),654			true655		);656657		// neg transfer_from658		assert_noop!(659			Unique::transfer_from(660				origin2.clone(),661				account(1),662				account(2),663				CollectionId(1),664				TokenId(1),665				1666			)667			.map_err(|e| e.error),668			CommonError::<Test>::ApprovedValueTooLow669		);670671		// do approve672		assert_ok!(Unique::approve(673			origin1,674			account(2),675			CollectionId(1),676			TokenId(1),677			1678		));679		assert_eq!(680			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),681			account(2)682		);683684		assert_ok!(Unique::transfer_from(685			origin2,686			account(1),687			account(3),688			CollectionId(1),689			TokenId(1),690			1691		));692		assert!(693			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()694		);695	});696}697698#[test]699fn nft_approve_and_transfer_from_allow_list() {700	new_test_ext().execute_with(|| {701		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));702703		let origin1 = Origin::signed(1);704		let origin2 = Origin::signed(2);705706		// Create NFT 1 for account 1707		let data = default_nft_data();708		create_test_item(collection_id, &data.clone().into());709		assert_eq!(710			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))711				.unwrap()712				.const_data,713			&data.const_data.into_inner()714		);715		assert_eq!(716			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),717			1718		);719		assert_eq!(720			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),721			true722		);723724		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list725		assert_ok!(Unique::set_mint_permission(726			origin1.clone(),727			CollectionId(1),728			true729		));730		assert_ok!(Unique::set_public_access_mode(731			origin1.clone(),732			CollectionId(1),733			AccessMode::AllowList734		));735		assert_ok!(Unique::add_to_allow_list(736			origin1.clone(),737			CollectionId(1),738			account(1)739		));740		assert_ok!(Unique::add_to_allow_list(741			origin1.clone(),742			CollectionId(1),743			account(2)744		));745		assert_ok!(Unique::add_to_allow_list(746			origin1.clone(),747			CollectionId(1),748			account(3)749		));750751		// Account 1 approves account 2 for NFT 1752		assert_ok!(Unique::approve(753			origin1.clone(),754			account(2),755			CollectionId(1),756			TokenId(1),757			1758		));759		assert_eq!(760			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),761			account(2)762		);763764		// Account 2 transfers NFT 1 from account 1 to account 3765		assert_ok!(Unique::transfer_from(766			origin2,767			account(1),768			account(3),769			CollectionId(1),770			TokenId(1),771			1772		));773		assert!(774			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()775		);776	});777}778779#[test]780fn refungible_approve_and_transfer_from() {781	new_test_ext().execute_with(|| {782		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));783784		let origin1 = Origin::signed(1);785		let origin2 = Origin::signed(2);786787		// Create RFT 1 in 1023 pieces for account 1788		let data = default_re_fungible_data();789		create_test_item(collection_id, &data.into());790791		assert_eq!(792			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),793			1794		);795		assert_eq!(796			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),797			1023798		);799		assert_eq!(800			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),801			true802		);803804		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list805		assert_ok!(Unique::set_mint_permission(806			origin1.clone(),807			CollectionId(1),808			true809		));810		assert_ok!(Unique::set_public_access_mode(811			origin1.clone(),812			CollectionId(1),813			AccessMode::AllowList814		));815		assert_ok!(Unique::add_to_allow_list(816			origin1.clone(),817			CollectionId(1),818			account(1)819		));820		assert_ok!(Unique::add_to_allow_list(821			origin1.clone(),822			CollectionId(1),823			account(2)824		));825		assert_ok!(Unique::add_to_allow_list(826			origin1.clone(),827			CollectionId(1),828			account(3)829		));830831		// Account 1 approves account 2 for 1023 pieces of RFT 1832		assert_ok!(Unique::approve(833			origin1,834			account(2),835			CollectionId(1),836			TokenId(1),837			1023838		));839		assert_eq!(840			<pallet_refungible::Allowance<Test>>::get((841				CollectionId(1),842				TokenId(1),843				account(1),844				account(2)845			)),846			1023847		);848849		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3850		assert_ok!(Unique::transfer_from(851			origin2,852			account(1),853			account(3),854			CollectionId(1),855			TokenId(1),856			100857		));858		assert_eq!(859			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),860			1861		);862		assert_eq!(863			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),864			1865		);866		assert_eq!(867			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),868			923869		);870		assert_eq!(871			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),872			100873		);874		assert_eq!(875			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),876			true877		);878		assert_eq!(879			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),880			true881		);882		assert_eq!(883			<pallet_refungible::Allowance<Test>>::get((884				CollectionId(1),885				TokenId(1),886				account(1),887				account(2)888			)),889			923890		);891	});892}893894#[test]895fn fungible_approve_and_transfer_from() {896	new_test_ext().execute_with(|| {897		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));898899		let data = default_fungible_data();900		create_test_item(collection_id, &data.into());901902		let origin1 = Origin::signed(1);903		let origin2 = Origin::signed(2);904905		assert_ok!(Unique::set_mint_permission(906			origin1.clone(),907			CollectionId(1),908			true909		));910		assert_ok!(Unique::set_public_access_mode(911			origin1.clone(),912			CollectionId(1),913			AccessMode::AllowList914		));915		assert_ok!(Unique::add_to_allow_list(916			origin1.clone(),917			CollectionId(1),918			account(1)919		));920		assert_ok!(Unique::add_to_allow_list(921			origin1.clone(),922			CollectionId(1),923			account(2)924		));925		assert_ok!(Unique::add_to_allow_list(926			origin1.clone(),927			CollectionId(1),928			account(3)929		));930931		// do approve932		assert_ok!(Unique::approve(933			origin1.clone(),934			account(2),935			CollectionId(1),936			TokenId(0),937			5938		));939		assert_eq!(940			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),941			5942		);943		assert_ok!(Unique::approve(944			origin1,945			account(3),946			CollectionId(1),947			TokenId(0),948			5949		));950		assert_eq!(951			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),952			5953		);954		assert_eq!(955			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),956			5957		);958959		assert_ok!(Unique::transfer_from(960			origin2.clone(),961			account(1),962			account(3),963			CollectionId(1),964			TokenId(0),965			4966		));967968		assert_eq!(969			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),970			1971		);972973		assert_noop!(974			Unique::transfer_from(975				origin2,976				account(1),977				account(3),978				CollectionId(1),979				TokenId(0),980				4981			)982			.map_err(|e| e.error),983			CommonError::<Test>::ApprovedValueTooLow984		);985	});986}987988#[test]989fn change_collection_owner() {990	new_test_ext().execute_with(|| {991		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));992993		let origin1 = Origin::signed(1);994		assert_ok!(Unique::change_collection_owner(origin1, collection_id, 2));995		assert_eq!(996			<pallet_common::CollectionById<Test>>::get(collection_id)997				.unwrap()998				.owner,999			21000		);1001	});1002}10031004#[test]1005fn destroy_collection() {1006	new_test_ext().execute_with(|| {1007		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10081009		let origin1 = Origin::signed(1);1010		assert_ok!(Unique::destroy_collection(origin1, collection_id));1011	});1012}10131014#[test]1015fn burn_nft_item() {1016	new_test_ext().execute_with(|| {1017		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10181019		let origin1 = Origin::signed(1);10201021		let data = default_nft_data();1022		create_test_item(collection_id, &data.into());10231024		// check balance (collection with id = 1, user id = 1)1025		assert_eq!(1026			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1027			11028		);10291030		// burn item1031		assert_ok!(Unique::burn_item(1032			origin1.clone(),1033			collection_id,1034			TokenId(1),1035			11036		));1037		assert_eq!(1038			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1039			01040		);1041	});1042}10431044#[test]1045fn burn_same_nft_item_twice() {1046	new_test_ext().execute_with(|| {1047		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10481049		let origin1 = Origin::signed(1);10501051		let data = default_nft_data();1052		create_test_item(collection_id, &data.into());10531054		// check balance (collection with id = 1, user id = 1)1055		assert_eq!(1056			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1057			11058		);10591060		// burn item1061		assert_ok!(Unique::burn_item(1062			origin1.clone(),1063			collection_id,1064			TokenId(1),1065			11066		));10671068		// burn item again1069		assert_noop!(1070			Unique::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),1071			CommonError::<Test>::TokenNotFound1072		);10731074		assert_eq!(1075			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1076			01077		);1078	});1079}10801081#[test]1082fn burn_fungible_item() {1083	new_test_ext().execute_with(|| {1084		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10851086		let origin1 = Origin::signed(1);1087		assert_ok!(Unique::add_collection_admin(1088			origin1.clone(),1089			collection_id,1090			account(2)1091		));10921093		let data = default_fungible_data();1094		create_test_item(collection_id, &data.into());10951096		// check balance (collection with id = 1, user id = 1)1097		assert_eq!(1098			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1099			51100		);11011102		// burn item1103		assert_ok!(Unique::burn_item(1104			origin1.clone(),1105			CollectionId(1),1106			TokenId(0),1107			51108		));1109		assert_noop!(1110			Unique::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),1111			CommonError::<Test>::TokenValueTooLow1112		);11131114		assert_eq!(1115			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1116			01117		);1118	});1119}11201121#[test]1122fn burn_fungible_item_with_token_id() {1123	new_test_ext().execute_with(|| {1124		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));11251126		let origin1 = Origin::signed(1);1127		assert_ok!(Unique::add_collection_admin(1128			origin1.clone(),1129			collection_id,1130			account(2)1131		));11321133		let data = default_fungible_data();1134		create_test_item(collection_id, &data.into());11351136		// check balance (collection with id = 1, user id = 1)1137		assert_eq!(1138			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1139			51140		);11411142		// Try to burn item using Token ID1143		assert_noop!(1144			Unique::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),1145			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId1146		);1147	});1148}1149#[test]1150fn burn_refungible_item() {1151	new_test_ext().execute_with(|| {1152		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));1153		let origin1 = Origin::signed(1);11541155		assert_ok!(Unique::set_mint_permission(1156			origin1.clone(),1157			collection_id,1158			true1159		));1160		assert_ok!(Unique::set_public_access_mode(1161			origin1.clone(),1162			collection_id,1163			AccessMode::AllowList1164		));1165		assert_ok!(Unique::add_to_allow_list(1166			origin1.clone(),1167			collection_id,1168			account(1)1169		));11701171		assert_ok!(Unique::add_collection_admin(1172			origin1.clone(),1173			collection_id,1174			account(2)1175		));11761177		let data = default_re_fungible_data();1178		create_test_item(collection_id, &data.into());11791180		// check balance (collection with id = 1, user id = 2)1181		assert_eq!(1182			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),1183			11184		);1185		assert_eq!(1186			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1187			10231188		);11891190		// burn item1191		assert_ok!(Unique::burn_item(1192			origin1.clone(),1193			collection_id,1194			TokenId(1),1195			10231196		));1197		assert_noop!(1198			Unique::burn_item(origin1, collection_id, TokenId(1), 1023).map_err(|e| e.error),1199			CommonError::<Test>::TokenValueTooLow1200		);12011202		assert_eq!(1203			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1204			01205		);1206	});1207}12081209#[test]1210fn add_collection_admin() {1211	new_test_ext().execute_with(|| {1212		let collection1_id =1213			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1214		let origin1 = Origin::signed(1);12151216		// Add collection admins1217		assert_ok!(Unique::add_collection_admin(1218			origin1.clone(),1219			collection1_id,1220			account(2)1221		));1222		assert_ok!(Unique::add_collection_admin(1223			origin1,1224			collection1_id,1225			account(3)1226		));12271228		// Owner is not an admin by default1229		assert_eq!(1230			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),1231			false1232		);1233		assert!(<pallet_common::IsAdmin<Test>>::get((1234			CollectionId(1),1235			account(2)1236		)));1237		assert!(<pallet_common::IsAdmin<Test>>::get((1238			CollectionId(1),1239			account(3)1240		)));1241	});1242}12431244#[test]1245fn remove_collection_admin() {1246	new_test_ext().execute_with(|| {1247		let collection1_id =1248			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1249		let origin1 = Origin::signed(1);1250		let origin2 = Origin::signed(2);12511252		// Add collection admins 2 and 31253		assert_ok!(Unique::add_collection_admin(1254			origin1.clone(),1255			collection1_id,1256			account(2)1257		));1258		assert_ok!(Unique::add_collection_admin(1259			origin1,1260			collection1_id,1261			account(3)1262		));12631264		assert!(<pallet_common::IsAdmin<Test>>::get((1265			CollectionId(1),1266			account(2)1267		)));1268		assert!(<pallet_common::IsAdmin<Test>>::get((1269			CollectionId(1),1270			account(3)1271		)));12721273		// remove admin 31274		assert_ok!(Unique::remove_collection_admin(1275			origin2,1276			CollectionId(1),1277			account(3)1278		));12791280		// 2 is still admin, 3 is not an admin anymore1281		assert!(<pallet_common::IsAdmin<Test>>::get((1282			CollectionId(1),1283			account(2)1284		)));1285		assert_eq!(1286			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),1287			false1288		);1289	});1290}12911292#[test]1293fn balance_of() {1294	new_test_ext().execute_with(|| {1295		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1296		let fungible_collection_id =1297			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));1298		let re_fungible_collection_id =1299			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));13001301		// check balance before1302		assert_eq!(1303			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1304			01305		);1306		assert_eq!(1307			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1308			01309		);1310		assert_eq!(1311			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1312			01313		);13141315		let nft_data = default_nft_data();1316		create_test_item(nft_collection_id, &nft_data.into());13171318		let fungible_data = default_fungible_data();1319		create_test_item(fungible_collection_id, &fungible_data.into());13201321		let re_fungible_data = default_re_fungible_data();1322		create_test_item(re_fungible_collection_id, &re_fungible_data.into());13231324		// check balance (collection with id = 1, user id = 1)1325		assert_eq!(1326			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1327			11328		);1329		assert_eq!(1330			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1331			51332		);1333		assert_eq!(1334			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1335			11336		);13371338		assert_eq!(1339			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),1340			true1341		);1342		assert_eq!(1343			<pallet_refungible::Owned<Test>>::get((1344				re_fungible_collection_id,1345				account(1),1346				TokenId(1)1347			)),1348			true1349		);1350	});1351}13521353#[test]1354fn approve() {1355	new_test_ext().execute_with(|| {1356		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));13571358		let data = default_nft_data();1359		create_test_item(collection_id, &data.into());13601361		let origin1 = Origin::signed(1);13621363		// approve1364		assert_ok!(Unique::approve(1365			origin1,1366			account(2),1367			CollectionId(1),1368			TokenId(1),1369			11370		));1371		assert_eq!(1372			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1373			account(2)1374		);1375	});1376}13771378#[test]1379fn transfer_from() {1380	new_test_ext().execute_with(|| {1381		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1382		let origin1 = Origin::signed(1);1383		let origin2 = Origin::signed(2);13841385		let data = default_nft_data();1386		create_test_item(collection_id, &data.into());13871388		// approve1389		assert_ok!(Unique::approve(1390			origin1.clone(),1391			account(2),1392			CollectionId(1),1393			TokenId(1),1394			11395		));1396		assert_eq!(1397			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1398			account(2)1399		);14001401		assert_ok!(Unique::set_mint_permission(1402			origin1.clone(),1403			CollectionId(1),1404			true1405		));1406		assert_ok!(Unique::set_public_access_mode(1407			origin1.clone(),1408			CollectionId(1),1409			AccessMode::AllowList1410		));1411		assert_ok!(Unique::add_to_allow_list(1412			origin1.clone(),1413			CollectionId(1),1414			account(1)1415		));1416		assert_ok!(Unique::add_to_allow_list(1417			origin1.clone(),1418			CollectionId(1),1419			account(2)1420		));1421		assert_ok!(Unique::add_to_allow_list(1422			origin1,1423			CollectionId(1),1424			account(3)1425		));14261427		assert_ok!(Unique::transfer_from(1428			origin2,1429			account(1),1430			account(2),1431			CollectionId(1),1432			TokenId(1),1433			11434		));14351436		// after transfer1437		assert_eq!(1438			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),1439			01440		);1441		assert_eq!(1442			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),1443			11444		);1445	});1446}14471448// #endregion14491450// Coverage tests region1451// #region14521453#[test]1454fn owner_can_add_address_to_allow_list() {1455	new_test_ext().execute_with(|| {1456		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14571458		let origin1 = Origin::signed(1);1459		assert_ok!(Unique::add_to_allow_list(1460			origin1,1461			collection_id,1462			account(2)1463		));1464		assert!(<pallet_common::Allowlist<Test>>::get((1465			collection_id,1466			account(2)1467		)));1468	});1469}14701471#[test]1472fn admin_can_add_address_to_allow_list() {1473	new_test_ext().execute_with(|| {1474		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1475		let origin1 = Origin::signed(1);1476		let origin2 = Origin::signed(2);14771478		assert_ok!(Unique::add_collection_admin(1479			origin1,1480			collection_id,1481			account(2)1482		));1483		assert_ok!(Unique::add_to_allow_list(1484			origin2,1485			collection_id,1486			account(3)1487		));1488		assert!(<pallet_common::Allowlist<Test>>::get((1489			collection_id,1490			account(3)1491		)));1492	});1493}14941495#[test]1496fn nonprivileged_user_cannot_add_address_to_allow_list() {1497	new_test_ext().execute_with(|| {1498		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14991500		let origin2 = Origin::signed(2);1501		assert_noop!(1502			Unique::add_to_allow_list(origin2, collection_id, account(3)),1503			CommonError::<Test>::NoPermission1504		);1505	});1506}15071508#[test]1509fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {1510	new_test_ext().execute_with(|| {1511		let origin1 = Origin::signed(1);15121513		assert_noop!(1514			Unique::add_to_allow_list(origin1, CollectionId(1), account(2)),1515			CommonError::<Test>::CollectionNotFound1516		);1517	});1518}15191520#[test]1521fn nobody_can_add_address_to_allow_list_of_deleted_collection() {1522	new_test_ext().execute_with(|| {1523		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15241525		let origin1 = Origin::signed(1);1526		assert_ok!(Unique::destroy_collection(origin1.clone(), collection_id));1527		assert_noop!(1528			Unique::add_to_allow_list(origin1, collection_id, account(2)),1529			CommonError::<Test>::CollectionNotFound1530		);1531	});1532}15331534// If address is already added to allow list, nothing happens1535#[test]1536fn address_is_already_added_to_allow_list() {1537	new_test_ext().execute_with(|| {1538		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1539		let origin1 = Origin::signed(1);15401541		assert_ok!(Unique::add_to_allow_list(1542			origin1.clone(),1543			collection_id,1544			account(2)1545		));1546		assert_ok!(Unique::add_to_allow_list(1547			origin1,1548			collection_id,1549			account(2)1550		));1551		assert!(<pallet_common::Allowlist<Test>>::get((1552			collection_id,1553			account(2)1554		)));1555	});1556}15571558#[test]1559fn owner_can_remove_address_from_allow_list() {1560	new_test_ext().execute_with(|| {1561		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15621563		let origin1 = Origin::signed(1);1564		assert_ok!(Unique::add_to_allow_list(1565			origin1.clone(),1566			collection_id,1567			account(2)1568		));1569		assert_ok!(Unique::remove_from_allow_list(1570			origin1,1571			collection_id,1572			account(2)1573		));1574		assert_eq!(1575			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1576			false1577		);1578	});1579}15801581#[test]1582fn admin_can_remove_address_from_allow_list() {1583	new_test_ext().execute_with(|| {1584		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1585		let origin1 = Origin::signed(1);1586		let origin2 = Origin::signed(2);15871588		// Owner adds admin1589		assert_ok!(Unique::add_collection_admin(1590			origin1.clone(),1591			collection_id,1592			account(2)1593		));15941595		// Owner adds address 3 to allow list1596		assert_ok!(Unique::add_to_allow_list(1597			origin1,1598			collection_id,1599			account(3)1600		));16011602		// Admin removes address 3 from allow list1603		assert_ok!(Unique::remove_from_allow_list(1604			origin2,1605			collection_id,1606			account(3)1607		));1608		assert_eq!(1609			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),1610			false1611		);1612	});1613}16141615#[test]1616fn nonprivileged_user_cannot_remove_address_from_allow_list() {1617	new_test_ext().execute_with(|| {1618		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1619		let origin1 = Origin::signed(1);1620		let origin2 = Origin::signed(2);16211622		assert_ok!(Unique::add_to_allow_list(1623			origin1,1624			collection_id,1625			account(2)1626		));1627		assert_noop!(1628			Unique::remove_from_allow_list(origin2, collection_id, account(2)),1629			CommonError::<Test>::NoPermission1630		);1631		assert!(<pallet_common::Allowlist<Test>>::get((1632			collection_id,1633			account(2)1634		)));1635	});1636}16371638#[test]1639fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {1640	new_test_ext().execute_with(|| {1641		let origin1 = Origin::signed(1);16421643		assert_noop!(1644			Unique::remove_from_allow_list(origin1, CollectionId(1), account(2)),1645			CommonError::<Test>::CollectionNotFound1646		);1647	});1648}16491650#[test]1651fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {1652	new_test_ext().execute_with(|| {1653		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1654		let origin1 = Origin::signed(1);1655		let origin2 = Origin::signed(2);16561657		// Add account 2 to allow list1658		assert_ok!(Unique::add_to_allow_list(1659			origin1.clone(),1660			collection_id,1661			account(2)1662		));16631664		// Account 2 is in collection allow-list1665		assert!(<pallet_common::Allowlist<Test>>::get((1666			collection_id,1667			account(2)1668		)));16691670		// Destroy collection1671		assert_ok!(Unique::destroy_collection(origin1, collection_id));16721673		// Attempt to remove account 2 from collection allow-list => error1674		assert_noop!(1675			Unique::remove_from_allow_list(origin2, collection_id, account(2)),1676			CommonError::<Test>::CollectionNotFound1677		);16781679		// Account 2 is not found in collection allow-list anyway1680		assert_eq!(1681			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1682			false1683		);1684	});1685}16861687// If address is already removed from allow list, nothing happens1688#[test]1689fn address_is_already_removed_from_allow_list() {1690	new_test_ext().execute_with(|| {1691		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1692		let origin1 = Origin::signed(1);16931694		assert_ok!(Unique::add_to_allow_list(1695			origin1.clone(),1696			collection_id,1697			account(2)1698		));1699		assert_ok!(Unique::remove_from_allow_list(1700			origin1.clone(),1701			collection_id,1702			account(2)1703		));1704		assert_eq!(1705			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1706			false1707		);1708		assert_ok!(Unique::remove_from_allow_list(1709			origin1,1710			collection_id,1711			account(2)1712		));1713		assert_eq!(1714			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1715			false1716		);1717	});1718}17191720// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)1721#[test]1722fn allow_list_test_1() {1723	new_test_ext().execute_with(|| {1724		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17251726		let origin1 = Origin::signed(1);17271728		let data = default_nft_data();1729		create_test_item(collection_id, &data.into());17301731		assert_ok!(Unique::set_public_access_mode(1732			origin1.clone(),1733			collection_id,1734			AccessMode::AllowList1735		));1736		assert_ok!(Unique::add_to_allow_list(1737			origin1.clone(),1738			collection_id,1739			account(2)1740		));17411742		assert_noop!(1743			Unique::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)1744				.map_err(|e| e.error),1745			CommonError::<Test>::AddressNotInAllowlist1746		);1747	});1748}17491750#[test]1751fn allow_list_test_2() {1752	new_test_ext().execute_with(|| {1753		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1754		let origin1 = Origin::signed(1);17551756		let data = default_nft_data();1757		create_test_item(collection_id, &data.into());17581759		assert_ok!(Unique::set_public_access_mode(1760			origin1.clone(),1761			collection_id,1762			AccessMode::AllowList1763		));1764		assert_ok!(Unique::add_to_allow_list(1765			origin1.clone(),1766			collection_id,1767			account(1)1768		));1769		assert_ok!(Unique::add_to_allow_list(1770			origin1.clone(),1771			collection_id,1772			account(2)1773		));17741775		// do approve1776		assert_ok!(Unique::approve(1777			origin1.clone(),1778			account(1),1779			collection_id,1780			TokenId(1),1781			11782		));1783		assert_eq!(1784			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1785			account(1)1786		);17871788		assert_ok!(Unique::remove_from_allow_list(1789			origin1.clone(),1790			collection_id,1791			account(1)1792		));17931794		assert_noop!(1795			Unique::transfer_from(1796				origin1,1797				account(1),1798				account(3),1799				CollectionId(1),1800				TokenId(1),1801				11802			)1803			.map_err(|e| e.error),1804			CommonError::<Test>::AddressNotInAllowlist1805		);1806	});1807}18081809// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)1810#[test]1811fn allow_list_test_3() {1812	new_test_ext().execute_with(|| {1813		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18141815		let origin1 = Origin::signed(1);18161817		let data = default_nft_data();1818		create_test_item(collection_id, &data.into());18191820		assert_ok!(Unique::set_public_access_mode(1821			origin1.clone(),1822			collection_id,1823			AccessMode::AllowList1824		));1825		assert_ok!(Unique::add_to_allow_list(1826			origin1.clone(),1827			collection_id,1828			account(1)1829		));18301831		assert_noop!(1832			Unique::transfer(origin1, account(3), collection_id, TokenId(1), 1)1833				.map_err(|e| e.error),1834			CommonError::<Test>::AddressNotInAllowlist1835		);1836	});1837}18381839#[test]1840fn allow_list_test_4() {1841	new_test_ext().execute_with(|| {1842		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18431844		let origin1 = Origin::signed(1);18451846		let data = default_nft_data();1847		create_test_item(collection_id, &data.into());18481849		assert_ok!(Unique::set_public_access_mode(1850			origin1.clone(),1851			collection_id,1852			AccessMode::AllowList1853		));1854		assert_ok!(Unique::add_to_allow_list(1855			origin1.clone(),1856			collection_id,1857			account(1)1858		));1859		assert_ok!(Unique::add_to_allow_list(1860			origin1.clone(),1861			collection_id,1862			account(2)1863		));18641865		// do approve1866		assert_ok!(Unique::approve(1867			origin1.clone(),1868			account(1),1869			collection_id,1870			TokenId(1),1871			11872		));1873		assert_eq!(1874			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1875			account(1)1876		);18771878		assert_ok!(Unique::remove_from_allow_list(1879			origin1.clone(),1880			collection_id,1881			account(2)1882		));18831884		assert_noop!(1885			Unique::transfer_from(1886				origin1,1887				account(1),1888				account(3),1889				collection_id,1890				TokenId(1),1891				11892			)1893			.map_err(|e| e.error),1894			CommonError::<Test>::AddressNotInAllowlist1895		);1896	});1897}18981899// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)1900#[test]1901fn allow_list_test_5() {1902	new_test_ext().execute_with(|| {1903		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19041905		let origin1 = Origin::signed(1);19061907		let data = default_nft_data();1908		create_test_item(collection_id, &data.into());19091910		assert_ok!(Unique::set_public_access_mode(1911			origin1.clone(),1912			collection_id,1913			AccessMode::AllowList1914		));1915		assert_noop!(1916			Unique::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),1917			CommonError::<Test>::AddressNotInAllowlist1918		);1919	});1920}19211922// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).1923#[test]1924fn allow_list_test_6() {1925	new_test_ext().execute_with(|| {1926		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19271928		let origin1 = Origin::signed(1);19291930		let data = default_nft_data();1931		create_test_item(collection_id, &data.into());19321933		assert_ok!(Unique::set_public_access_mode(1934			origin1.clone(),1935			collection_id,1936			AccessMode::AllowList1937		));19381939		// do approve1940		assert_noop!(1941			Unique::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)1942				.map_err(|e| e.error),1943			CommonError::<Test>::AddressNotInAllowlist1944		);1945	});1946}19471948// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and1949//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)1950#[test]1951fn allow_list_test_7() {1952	new_test_ext().execute_with(|| {1953		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19541955		let data = default_nft_data();1956		create_test_item(collection_id, &data.into());19571958		let origin1 = Origin::signed(1);19591960		assert_ok!(Unique::set_public_access_mode(1961			origin1.clone(),1962			collection_id,1963			AccessMode::AllowList1964		));1965		assert_ok!(Unique::add_to_allow_list(1966			origin1.clone(),1967			collection_id,1968			account(1)1969		));1970		assert_ok!(Unique::add_to_allow_list(1971			origin1.clone(),1972			collection_id,1973			account(2)1974		));19751976		assert_ok!(Unique::transfer(1977			origin1,1978			account(2),1979			CollectionId(1),1980			TokenId(1),1981			11982		));1983	});1984}19851986#[test]1987fn allow_list_test_8() {1988	new_test_ext().execute_with(|| {1989		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19901991		// Create NFT for account 11992		let data = default_nft_data();1993		create_test_item(collection_id, &data.into());19941995		let origin1 = Origin::signed(1);19961997		// Toggle Allow List mode and add accounts 1 and 21998		assert_ok!(Unique::set_public_access_mode(1999			origin1.clone(),2000			collection_id,2001			AccessMode::AllowList2002		));2003		assert_ok!(Unique::add_to_allow_list(2004			origin1.clone(),2005			collection_id,2006			account(1)2007		));2008		assert_ok!(Unique::add_to_allow_list(2009			origin1.clone(),2010			collection_id,2011			account(2)2012		));20132014		// Sself-approve account 1 for NFT 12015		assert_ok!(Unique::approve(2016			origin1.clone(),2017			account(1),2018			CollectionId(1),2019			TokenId(1),2020			12021		));2022		assert_eq!(2023			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),2024			account(1)2025		);20262027		// Transfer from 1 to 22028		assert_ok!(Unique::transfer_from(2029			origin1,2030			account(1),2031			account(2),2032			CollectionId(1),2033			TokenId(1),2034			12035		));2036	});2037}20382039// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.2040#[test]2041fn allow_list_test_9() {2042	new_test_ext().execute_with(|| {2043		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2044		let origin1 = Origin::signed(1);20452046		assert_ok!(Unique::set_public_access_mode(2047			origin1.clone(),2048			collection_id,2049			AccessMode::AllowList2050		));2051		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));20522053		let data = default_nft_data();2054		create_test_item(collection_id, &data.into());2055	});2056}20572058// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.2059#[test]2060fn allow_list_test_10() {2061	new_test_ext().execute_with(|| {2062		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20632064		let origin1 = Origin::signed(1);2065		let origin2 = Origin::signed(2);20662067		assert_ok!(Unique::set_public_access_mode(2068			origin1.clone(),2069			collection_id,2070			AccessMode::AllowList2071		));2072		assert_ok!(Unique::set_mint_permission(2073			origin1.clone(),2074			collection_id,2075			false2076		));20772078		assert_ok!(Unique::add_collection_admin(2079			origin1,2080			collection_id,2081			account(2)2082		));20832084		assert_ok!(Unique::create_item(2085			origin2,2086			collection_id,2087			account(2),2088			default_nft_data().into()2089		));2090	});2091}20922093// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.2094#[test]2095fn allow_list_test_11() {2096	new_test_ext().execute_with(|| {2097		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20982099		let origin1 = Origin::signed(1);2100		let origin2 = Origin::signed(2);21012102		assert_ok!(Unique::set_public_access_mode(2103			origin1.clone(),2104			collection_id,2105			AccessMode::AllowList2106		));2107		assert_ok!(Unique::set_mint_permission(2108			origin1.clone(),2109			collection_id,2110			false2111		));2112		assert_ok!(Unique::add_to_allow_list(2113			origin1,2114			collection_id,2115			account(2)2116		));21172118		assert_noop!(2119			Unique::create_item(2120				origin2,2121				CollectionId(1),2122				account(2),2123				default_nft_data().into()2124			)2125			.map_err(|e| e.error),2126			CommonError::<Test>::PublicMintingNotAllowed2127		);2128	});2129}21302131// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.2132#[test]2133fn allow_list_test_12() {2134	new_test_ext().execute_with(|| {2135		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21362137		let origin1 = Origin::signed(1);2138		let origin2 = Origin::signed(2);21392140		assert_ok!(Unique::set_public_access_mode(2141			origin1.clone(),2142			collection_id,2143			AccessMode::AllowList2144		));2145		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));21462147		assert_noop!(2148			Unique::create_item(2149				origin2,2150				CollectionId(1),2151				account(2),2152				default_nft_data().into()2153			)2154			.map_err(|e| e.error),2155			CommonError::<Test>::PublicMintingNotAllowed2156		);2157	});2158}21592160// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.2161#[test]2162fn allow_list_test_13() {2163	new_test_ext().execute_with(|| {2164		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21652166		let origin1 = Origin::signed(1);21672168		assert_ok!(Unique::set_public_access_mode(2169			origin1.clone(),2170			collection_id,2171			AccessMode::AllowList2172		));2173		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));21742175		let data = default_nft_data();2176		create_test_item(collection_id, &data.into());2177	});2178}21792180// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.2181#[test]2182fn allow_list_test_14() {2183	new_test_ext().execute_with(|| {2184		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21852186		let origin1 = Origin::signed(1);2187		let origin2 = Origin::signed(2);21882189		assert_ok!(Unique::set_public_access_mode(2190			origin1.clone(),2191			collection_id,2192			AccessMode::AllowList2193		));2194		assert_ok!(Unique::set_mint_permission(2195			origin1.clone(),2196			collection_id,2197			true2198		));21992200		assert_ok!(Unique::add_collection_admin(2201			origin1,2202			collection_id,2203			account(2)2204		));22052206		assert_ok!(Unique::create_item(2207			origin2,2208			collection_id,2209			account(2),2210			default_nft_data().into()2211		));2212	});2213}22142215// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.2216#[test]2217fn allow_list_test_15() {2218	new_test_ext().execute_with(|| {2219		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22202221		let origin1 = Origin::signed(1);2222		let origin2 = Origin::signed(2);22232224		assert_ok!(Unique::set_public_access_mode(2225			origin1.clone(),2226			collection_id,2227			AccessMode::AllowList2228		));2229		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));22302231		assert_noop!(2232			Unique::create_item(2233				origin2,2234				collection_id,2235				account(2),2236				default_nft_data().into()2237			)2238			.map_err(|e| e.error),2239			CommonError::<Test>::AddressNotInAllowlist2240		);2241	});2242}22432244// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.2245#[test]2246fn allow_list_test_16() {2247	new_test_ext().execute_with(|| {2248		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22492250		let origin1 = Origin::signed(1);2251		let origin2 = Origin::signed(2);22522253		assert_ok!(Unique::set_public_access_mode(2254			origin1.clone(),2255			collection_id,2256			AccessMode::AllowList2257		));2258		assert_ok!(Unique::set_mint_permission(2259			origin1.clone(),2260			collection_id,2261			true2262		));2263		assert_ok!(Unique::add_to_allow_list(2264			origin1,2265			collection_id,2266			account(2)2267		));22682269		assert_ok!(Unique::create_item(2270			origin2,2271			collection_id,2272			account(2),2273			default_nft_data().into()2274		));2275	});2276}22772278// Total number of collections. Positive test2279#[test]2280fn total_number_collections_bound() {2281	new_test_ext().execute_with(|| {2282		create_test_collection(&CollectionMode::NFT, CollectionId(1));2283	});2284}22852286#[test]2287fn create_max_collections() {2288	new_test_ext().execute_with(|| {2289		for i in 1..COLLECTION_NUMBER_LIMIT {2290			create_test_collection(&CollectionMode::NFT, CollectionId(i));2291		}2292	});2293}22942295// Total number of collections. Negative test2296#[test]2297fn total_number_collections_bound_neg() {2298	new_test_ext().execute_with(|| {2299		let origin1 = Origin::signed(1);23002301		for i in 1..=COLLECTION_NUMBER_LIMIT {2302			create_test_collection(&CollectionMode::NFT, CollectionId(i));2303		}23042305		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();2306		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();2307		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();23082309		let data: CreateCollectionData<u64> = CreateCollectionData {2310			name: col_name1.try_into().unwrap(),2311			description: col_desc1.try_into().unwrap(),2312			token_prefix: token_prefix1.try_into().unwrap(),2313			mode: CollectionMode::NFT,2314			..Default::default()2315		};23162317		// 11-th collection in chain. Expects error2318		assert_noop!(2319			Unique::create_collection_ex(origin1, data),2320			CommonError::<Test>::TotalCollectionsLimitExceeded2321		);2322	});2323}23242325// Owned tokens by a single address. Positive test2326#[test]2327fn owned_tokens_bound() {2328	new_test_ext().execute_with(|| {2329		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23302331		let data = default_nft_data();2332		create_test_item(collection_id, &data.clone().into());2333		create_test_item(collection_id, &data.into());2334	});2335}23362337// Owned tokens by a single address. Negotive test2338#[test]2339fn owned_tokens_bound_neg() {2340	new_test_ext().execute_with(|| {2341		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23422343		let origin1 = Origin::signed(1);23442345		for _ in 1..=MAX_TOKEN_OWNERSHIP {2346			let data = default_nft_data();2347			create_test_item(collection_id, &data.clone().into());2348		}23492350		let data = default_nft_data();2351		assert_noop!(2352			Unique::create_item(origin1, CollectionId(1), account(1), data.into())2353				.map_err(|e| e.error),2354			CommonError::<Test>::AccountTokenLimitExceeded2355		);2356	});2357}23582359// Number of collection admins. Positive test2360#[test]2361fn collection_admins_bound() {2362	new_test_ext().execute_with(|| {2363		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23642365		let origin1 = Origin::signed(1);23662367		assert_ok!(Unique::add_collection_admin(2368			origin1.clone(),2369			collection_id,2370			account(2)2371		));2372		assert_ok!(Unique::add_collection_admin(2373			origin1,2374			collection_id,2375			account(3)2376		));2377	});2378}23792380// Number of collection admins. Negotive test2381#[test]2382fn collection_admins_bound_neg() {2383	new_test_ext().execute_with(|| {2384		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23852386		let origin1 = Origin::signed(1);23872388		for i in 0..COLLECTION_ADMINS_LIMIT {2389			assert_ok!(Unique::add_collection_admin(2390				origin1.clone(),2391				collection_id,2392				account((2 + i).into())2393			));2394		}2395		assert_noop!(2396			Unique::add_collection_admin(2397				origin1,2398				collection_id,2399				account((3 + COLLECTION_ADMINS_LIMIT).into())2400			),2401			CommonError::<Test>::CollectionAdminCountExceeded2402		);2403	});2404}2405// #endregion24062407#[test]2408fn set_const_on_chain_schema() {2409	new_test_ext().execute_with(|| {2410		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24112412		let origin1 = Origin::signed(1);2413		assert_ok!(Unique::set_const_on_chain_schema(2414			origin1,2415			collection_id,2416			b"test const on chain schema".to_vec().try_into().unwrap()2417		));24182419		assert_eq!(2420			<pallet_common::CollectionData<Test>>::get((2421				collection_id,2422				CollectionField::ConstOnChainSchema2423			)),2424			b"test const on chain schema".to_vec()2425		);2426	});2427}24282429#[test]2430fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {2431	new_test_ext().execute_with(|| {2432		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24332434		let origin1 = Origin::signed(1);24352436		let data = default_nft_data();2437		create_test_item(CollectionId(1), &data.into());24382439		let variable_data = b"test data".to_vec();2440		assert_ok!(Unique::set_variable_meta_data(2441			origin1,2442			collection_id,2443			TokenId(1),2444			variable_data.clone().try_into().unwrap()2445		));24462447		assert_eq!(2448			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2449				.unwrap()2450				.variable_data,2451			variable_data2452		);2453	});2454}24552456#[test]2457fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {2458	new_test_ext().execute_with(|| {2459		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));24602461		let origin1 = Origin::signed(1);24622463		let data = default_re_fungible_data();2464		create_test_item(collection_id, &data.into());24652466		let variable_data = b"test data".to_vec();2467		assert_ok!(Unique::set_variable_meta_data(2468			origin1,2469			collection_id,2470			TokenId(1),2471			variable_data.clone().try_into().unwrap()2472		));24732474		assert_eq!(2475			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,2476			variable_data2477		);2478	});2479}24802481#[test]2482fn set_variable_meta_data_on_fungible_token_fails() {2483	new_test_ext().execute_with(|| {2484		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));24852486		let origin1 = Origin::signed(1);24872488		let data = default_fungible_data();2489		create_test_item(collection_id, &data.into());24902491		let variable_data = b"test data".to_vec();2492		assert_noop!(2493			Unique::set_variable_meta_data(2494				origin1,2495				collection_id,2496				TokenId(0),2497				variable_data.try_into().unwrap()2498			)2499			.map_err(|e| e.error),2500			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData2501		);2502	});2503}25042505#[test]2506fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {2507	new_test_ext().execute_with(|| {2508		//default_limits();25092510		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25112512		let origin1 = Origin::signed(1);25132514		let data = default_nft_data();2515		create_test_item(collection_id, &data.into());25162517		assert_ok!(Unique::set_meta_update_permission_flag(2518			origin1.clone(),2519			collection_id,2520			MetaUpdatePermission::ItemOwner,2521		));25222523		let variable_data = b"ten chars.".to_vec();2524		assert_ok!(Unique::set_variable_meta_data(2525			origin1,2526			collection_id,2527			TokenId(1),2528			variable_data.clone().try_into().unwrap()2529		));25302531		assert_eq!(2532			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))2533				.unwrap()2534				.variable_data,2535			variable_data2536		);2537	});2538}25392540#[test]2541fn collection_transfer_flag_works() {2542	new_test_ext().execute_with(|| {2543		let origin1 = Origin::signed(1);25442545		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2546		assert_ok!(Unique::set_transfers_enabled_flag(2547			origin1,2548			collection_id,2549			true2550		));25512552		let data = default_nft_data();2553		create_test_item(collection_id, &data.into());2554		assert_eq!(2555			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2556			12557		);2558		assert_eq!(2559			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2560			true2561		);25622563		let origin1 = Origin::signed(1);25642565		// default scenario2566		assert_ok!(Unique::transfer(2567			origin1,2568			account(2),2569			collection_id,2570			TokenId(1),2571			12572		));2573		assert_eq!(2574			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2575			false2576		);2577		assert_eq!(2578			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2579			true2580		);2581		assert_eq!(2582			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2583			02584		);2585		assert_eq!(2586			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2587			12588		);2589	});2590}25912592#[test]2593fn set_variable_meta_data_on_nft_with_admin_flag() {2594	new_test_ext().execute_with(|| {2595		// default_limits();25962597		let collection_id =2598			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));25992600		let origin1 = Origin::signed(1);2601		let origin2 = Origin::signed(2);26022603		assert_ok!(Unique::set_mint_permission(2604			origin2.clone(),2605			collection_id,2606			true2607		));2608		assert_ok!(Unique::add_to_allow_list(2609			origin2.clone(),2610			collection_id,2611			account(1)2612		));26132614		assert_ok!(Unique::add_collection_admin(2615			origin2.clone(),2616			collection_id,2617			account(1)2618		));26192620		let data = default_nft_data();2621		create_test_item(collection_id, &data.into());26222623		assert_ok!(Unique::set_meta_update_permission_flag(2624			origin2.clone(),2625			collection_id,2626			MetaUpdatePermission::Admin,2627		));26282629		let variable_data = b"test.".to_vec();2630		assert_ok!(Unique::set_variable_meta_data(2631			origin1,2632			collection_id,2633			TokenId(1),2634			variable_data.clone().try_into().unwrap()2635		));26362637		assert_eq!(2638			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2639				.unwrap()2640				.variable_data,2641			variable_data2642		);2643	});2644}26452646#[test]2647fn set_variable_meta_data_on_nft_with_admin_flag_neg() {2648	new_test_ext().execute_with(|| {2649		// default_limits();26502651		let collection_id =2652			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));26532654		let origin1 = Origin::signed(1);2655		let origin2 = Origin::signed(2);26562657		assert_ok!(Unique::set_mint_permission(2658			origin2.clone(),2659			collection_id,2660			true2661		));2662		assert_ok!(Unique::add_to_allow_list(2663			origin2.clone(),2664			collection_id,2665			account(1)2666		));26672668		let data = default_nft_data();2669		create_test_item(collection_id, &data.into());26702671		assert_ok!(Unique::set_meta_update_permission_flag(2672			origin2.clone(),2673			collection_id,2674			MetaUpdatePermission::Admin,2675		));26762677		let variable_data = b"test.".to_vec();2678		assert_noop!(2679			Unique::set_variable_meta_data(2680				origin1,2681				collection_id,2682				TokenId(1),2683				variable_data.try_into().unwrap()2684			)2685			.map_err(|e| e.error),2686			CommonError::<Test>::NoPermission2687		);2688	});2689}26902691#[test]2692fn set_variable_meta_flag_after_freeze() {2693	new_test_ext().execute_with(|| {2694		// default_limits();26952696		let collection_id =2697			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));26982699		let origin2 = Origin::signed(2);27002701		assert_ok!(Unique::set_meta_update_permission_flag(2702			origin2.clone(),2703			collection_id,2704			MetaUpdatePermission::None,2705		));2706		assert_noop!(2707			Unique::set_meta_update_permission_flag(2708				origin2.clone(),2709				collection_id,2710				MetaUpdatePermission::Admin2711			),2712			CommonError::<Test>::MetadataFlagFrozen2713		);2714	});2715}27162717#[test]2718fn set_variable_meta_data_on_nft_with_none_flag_neg() {2719	new_test_ext().execute_with(|| {2720		// default_limits();27212722		let collection_id =2723			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));2724		let origin1 = Origin::signed(1);27252726		let data = default_nft_data();2727		create_test_item(collection_id, &data.into());27282729		assert_ok!(Unique::set_meta_update_permission_flag(2730			origin1.clone(),2731			collection_id,2732			MetaUpdatePermission::None,2733		));27342735		let variable_data = b"test.".to_vec();2736		assert_noop!(2737			Unique::set_variable_meta_data(2738				origin1.clone(),2739				collection_id,2740				TokenId(1),2741				variable_data.try_into().unwrap()2742			)2743			.map_err(|e| e.error),2744			CommonError::<Test>::NoPermission2745		);2746	});2747}27482749#[test]2750fn collection_transfer_flag_works_neg() {2751	new_test_ext().execute_with(|| {2752		let origin1 = Origin::signed(1);27532754		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2755		assert_ok!(Unique::set_transfers_enabled_flag(2756			origin1,2757			collection_id,2758			false2759		));27602761		let data = default_nft_data();2762		create_test_item(collection_id, &data.into());2763		assert_eq!(2764			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2765			12766		);2767		assert_eq!(2768			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2769			true2770		);27712772		let origin1 = Origin::signed(1);27732774		// default scenario2775		assert_noop!(2776			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)2777				.map_err(|e| e.error),2778			CommonError::<Test>::TransferNotAllowed2779		);2780		assert_eq!(2781			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2782			12783		);2784		assert_eq!(2785			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2786			02787		);2788		assert_eq!(2789			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2790			true2791		);2792		assert_eq!(2793			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2794			false2795		);2796	});2797}27982799#[test]2800fn collection_sponsoring() {2801	new_test_ext().execute_with(|| {2802		// default_limits();2803		let user1 = 1_u64;2804		let user2 = 777_u64;2805		let origin1 = Origin::signed(user1);2806		let origin2 = Origin::signed(user2);2807		let account2 = account(user2);28082809		let collection_id =2810			create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));2811		assert_ok!(Unique::set_collection_sponsor(2812			origin1.clone(),2813			collection_id,2814			user12815		));2816		assert_ok!(Unique::confirm_sponsorship(origin1.clone(), collection_id));28172818		// Expect error while have no permissions2819		assert!(Unique::create_item(2820			origin2.clone(),2821			collection_id,2822			account2.clone(),2823			default_nft_data().into()2824		)2825		.is_err());28262827		assert_ok!(Unique::set_public_access_mode(2828			origin1.clone(),2829			collection_id,2830			AccessMode::AllowList2831		));2832		assert_ok!(Unique::add_to_allow_list(2833			origin1.clone(),2834			collection_id,2835			account2.clone()2836		));2837		assert_ok!(Unique::set_mint_permission(2838			origin1.clone(),2839			collection_id,2840			true2841		));28422843		assert_ok!(Unique::create_item(2844			origin2,2845			collection_id,2846			account2,2847			default_nft_data().into()2848		));2849	});2850}
after · runtime/tests/src/tests.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Tests to be written here18use crate::{Test, TestCrossAccountId, CollectionCreationPrice, Origin, Unique, new_test_ext};19use up_data_structs::{20	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,21	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, TokenId,22	MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionField, SchemaVersion, CollectionMode,23	AccessMode,24};25use frame_support::{assert_noop, assert_ok, assert_err};26use sp_std::convert::TryInto;27use pallet_evm::account::CrossAccountId;28use pallet_common::Error as CommonError;29use pallet_unique::Error as UniqueError;3031fn add_balance(user: u64, value: u64) {32	const DONOR_USER: u64 = 999;33	assert_ok!(<pallet_balances::Pallet<Test>>::set_balance(34		Origin::root(),35		DONOR_USER,36		value,37		038	));39	assert_ok!(<pallet_balances::Pallet<Test>>::force_transfer(40		Origin::root(),41		DONOR_USER,42		user,43		value44	));45}4647fn default_nft_data() -> CreateNftData {48	CreateNftData {49		const_data: vec![1, 2, 3].try_into().unwrap(),50		properties: vec![].try_into().unwrap(),51	}52}5354fn default_fungible_data() -> CreateFungibleData {55	CreateFungibleData { value: 5 }56}5758fn default_re_fungible_data() -> CreateReFungibleData {59	CreateReFungibleData {60		const_data: vec![1, 2, 3].try_into().unwrap(),61		pieces: 1023,62	}63}6465fn create_test_collection_for_owner(66	mode: &CollectionMode,67	owner: u64,68	id: CollectionId,69) -> CollectionId {70	add_balance(owner, CollectionCreationPrice::get() as u64 + 1);7172	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();73	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();74	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();7576	let data: CreateCollectionData<u64> = CreateCollectionData {77		name: col_name1.try_into().unwrap(),78		description: col_desc1.try_into().unwrap(),79		token_prefix: token_prefix1.try_into().unwrap(),80		mode: mode.clone(),81		..Default::default()82	};8384	let origin1 = Origin::signed(owner);85	assert_ok!(Unique::create_collection_ex(origin1, data));8687	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();88	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();89	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();90	assert_eq!(91		<pallet_common::CollectionById<Test>>::get(id)92			.unwrap()93			.owner,94		owner95	);96	assert_eq!(97		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,98		saved_col_name99	);100	assert_eq!(101		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,102		*mode103	);104	assert_eq!(105		<pallet_common::CollectionById<Test>>::get(id)106			.unwrap()107			.description,108		saved_description109	);110	assert_eq!(111		<pallet_common::CollectionById<Test>>::get(id)112			.unwrap()113			.token_prefix,114		saved_prefix115	);116	id117}118119fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {120	create_test_collection_for_owner(&mode, 1, id)121}122123fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {124	let origin1 = Origin::signed(1);125	assert_ok!(Unique::create_item(126		origin1,127		collection_id,128		account(1),129		data.clone()130	));131}132133fn account(sub: u64) -> TestCrossAccountId {134	TestCrossAccountId::from_sub(sub)135}136137// Use cases tests region138// #region139140#[test]141fn set_version_schema() {142	new_test_ext().execute_with(|| {143		let origin1 = Origin::signed(1);144		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));145146		assert_ok!(Unique::set_schema_version(147			origin1,148			collection_id,149			SchemaVersion::Unique150		));151		assert_eq!(152			<pallet_common::CollectionById<Test>>::get(collection_id)153				.unwrap()154				.schema_version,155			SchemaVersion::Unique156		);157	});158}159160#[test]161fn check_not_sufficient_founds() {162	new_test_ext().execute_with(|| {163		let acc: u64 = 1;164		<pallet_balances::Pallet<Test>>::set_balance(Origin::root(), acc, 0, 0).unwrap();165166		let name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();167		let description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();168		let token_prefix: Vec<u8> = b"token_prefix1\0".to_vec();169170		let data: CreateCollectionData<<Test as frame_system::Config>::AccountId> =171			CreateCollectionData {172				name: name.try_into().unwrap(),173				description: description.try_into().unwrap(),174				token_prefix: token_prefix.try_into().unwrap(),175				mode: CollectionMode::NFT,176				..Default::default()177			};178179		let result = Unique::create_collection_ex(Origin::signed(acc), data);180		assert_err!(result, <CommonError<Test>>::NotSufficientFounds);181	});182}183184#[test]185fn create_fungible_collection_fails_with_large_decimal_numbers() {186	new_test_ext().execute_with(|| {187		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();188		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();189		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();190191		let data: CreateCollectionData<u64> = CreateCollectionData {192			name: col_name1.try_into().unwrap(),193			description: col_desc1.try_into().unwrap(),194			token_prefix: token_prefix1.try_into().unwrap(),195			mode: CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1),196			..Default::default()197		};198199		let origin1 = Origin::signed(1);200		assert_noop!(201			Unique::create_collection_ex(origin1, data),202			UniqueError::<Test>::CollectionDecimalPointLimitExceeded203		);204	});205}206207#[test]208fn create_nft_item() {209	new_test_ext().execute_with(|| {210		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));211212		let data = default_nft_data();213		create_test_item(collection_id, &data.clone().into());214215		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();216		assert_eq!(item.const_data, data.const_data.into_inner());217	});218}219220// Use cases tests region221// #region222#[test]223fn create_nft_multiple_items() {224	new_test_ext().execute_with(|| {225		create_test_collection(&CollectionMode::NFT, CollectionId(1));226227		let origin1 = Origin::signed(1);228229		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];230231		assert_ok!(Unique::create_multiple_items(232			origin1,233			CollectionId(1),234			account(1),235			items_data236				.clone()237				.into_iter()238				.map(|d| { d.into() })239				.collect()240		));241		for (index, data) in items_data.into_iter().enumerate() {242			let item = <pallet_nonfungible::TokenData<Test>>::get((243				CollectionId(1),244				TokenId((index + 1) as u32),245			))246			.unwrap();247			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());248		}249	});250}251252#[test]253fn create_refungible_item() {254	new_test_ext().execute_with(|| {255		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));256257		let data = default_re_fungible_data();258		create_test_item(collection_id, &data.clone().into());259		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));260		let balance =261			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));262		assert_eq!(item.const_data, data.const_data.into_inner());263		assert_eq!(balance, 1023);264	});265}266267#[test]268fn create_multiple_refungible_items() {269	new_test_ext().execute_with(|| {270		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));271272		let origin1 = Origin::signed(1);273274		let items_data = vec![275			default_re_fungible_data(),276			default_re_fungible_data(),277			default_re_fungible_data(),278		];279280		assert_ok!(Unique::create_multiple_items(281			origin1,282			CollectionId(1),283			account(1),284			items_data285				.clone()286				.into_iter()287				.map(|d| { d.into() })288				.collect()289		));290		for (index, data) in items_data.into_iter().enumerate() {291			let item = <pallet_refungible::TokenData<Test>>::get((292				CollectionId(1),293				TokenId((index + 1) as u32),294			));295			let balance =296				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));297			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());298			assert_eq!(balance, 1023);299		}300	});301}302303#[test]304fn create_fungible_item() {305	new_test_ext().execute_with(|| {306		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));307308		let data = default_fungible_data();309		create_test_item(collection_id, &data.into());310311		assert_eq!(312			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),313			5314		);315	});316}317318//#[test]319// fn create_multiple_fungible_items() {320//     new_test_ext().execute_with(|| {321//         default_limits();322323//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));324325//         let origin1 = Origin::signed(1);326327//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];328329//         assert_ok!(Unique::create_multiple_items(330//             origin1.clone(),331//             1,332//             1,333//             items_data.clone().into_iter().map(|d| { d.into() }).collect()334//         ));335336//         for (index, _) in items_data.iter().enumerate() {337//             assert_eq!(Unique::fungible_item_id(1, (index + 1) as TokenId).value, 5);338//         }339//         assert_eq!(Unique::balance_count(1, 1), 3000);340//         assert_eq!(Unique::address_tokens(1, 1), [1, 2, 3]);341//     });342// }343344#[test]345fn transfer_fungible_item() {346	new_test_ext().execute_with(|| {347		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));348349		let origin1 = Origin::signed(1);350		let origin2 = Origin::signed(2);351352		let data = default_fungible_data();353		create_test_item(collection_id, &data.into());354355		assert_eq!(356			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),357			5358		);359360		// change owner scenario361		assert_ok!(Unique::transfer(362			origin1,363			account(2),364			CollectionId(1),365			TokenId(0),366			5367		));368		assert_eq!(369			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),370			0371		);372373		// split item scenario374		assert_ok!(Unique::transfer(375			origin2.clone(),376			account(3),377			CollectionId(1),378			TokenId(0),379			3380		));381382		// split item and new owner has account scenario383		assert_ok!(Unique::transfer(384			origin2,385			account(3),386			CollectionId(1),387			TokenId(0),388			1389		));390		assert_eq!(391			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),392			1393		);394		assert_eq!(395			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),396			4397		);398	});399}400401#[test]402fn transfer_refungible_item() {403	new_test_ext().execute_with(|| {404		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));405406		// Create RFT 1 in 1023 pieces for account 1407		let data = default_re_fungible_data();408		create_test_item(collection_id, &data.clone().into());409		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));410		assert_eq!(item.const_data, data.const_data.into_inner());411		assert_eq!(412			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),413			1414		);415		assert_eq!(416			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),417			1023418		);419		assert_eq!(420			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),421			true422		);423424		// Account 1 transfers all 1023 pieces of RFT 1 to account 2425		let origin1 = Origin::signed(1);426		let origin2 = Origin::signed(2);427		assert_ok!(Unique::transfer(428			origin1,429			account(2),430			CollectionId(1),431			TokenId(1),432			1023433		));434		assert_eq!(435			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),436			1023437		);438		assert_eq!(439			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),440			0441		);442		assert_eq!(443			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),444			1445		);446		assert_eq!(447			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),448			false449		);450		assert_eq!(451			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),452			true453		);454455		// Account 2 transfers 500 pieces of RFT 1 to account 3456		assert_ok!(Unique::transfer(457			origin2.clone(),458			account(3),459			CollectionId(1),460			TokenId(1),461			500462		));463		assert_eq!(464			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),465			523466		);467		assert_eq!(468			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),469			500470		);471		assert_eq!(472			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),473			1474		);475		assert_eq!(476			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),477			1478		);479		assert_eq!(480			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),481			true482		);483		assert_eq!(484			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),485			true486		);487488		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance489		assert_ok!(Unique::transfer(490			origin2,491			account(3),492			CollectionId(1),493			TokenId(1),494			200495		));496		assert_eq!(497			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),498			323499		);500		assert_eq!(501			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),502			700503		);504		assert_eq!(505			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),506			1507		);508		assert_eq!(509			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),510			1511		);512		assert_eq!(513			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),514			true515		);516		assert_eq!(517			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),518			true519		);520	});521}522523#[test]524fn transfer_nft_item() {525	new_test_ext().execute_with(|| {526		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));527528		let data = default_nft_data();529		create_test_item(collection_id, &data.into());530		assert_eq!(531			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),532			1533		);534		assert_eq!(535			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),536			true537		);538539		let origin1 = Origin::signed(1);540		// default scenario541		assert_ok!(Unique::transfer(542			origin1,543			account(2),544			CollectionId(1),545			TokenId(1),546			1547		));548		assert_eq!(549			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),550			0551		);552		assert_eq!(553			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),554			1555		);556		assert_eq!(557			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),558			false559		);560		assert_eq!(561			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),562			true563		);564	});565}566567#[test]568fn transfer_nft_item_wrong_value() {569	new_test_ext().execute_with(|| {570		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));571572		let data = default_nft_data();573		create_test_item(collection_id, &data.into());574		assert_eq!(575			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),576			1577		);578		assert_eq!(579			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),580			true581		);582583		let origin1 = Origin::signed(1);584585		assert_noop!(586			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)587				.map_err(|e| e.error),588			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount589		);590	});591}592593#[test]594fn transfer_nft_item_zero_value() {595	new_test_ext().execute_with(|| {596		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));597598		let data = default_nft_data();599		create_test_item(collection_id, &data.into());600		assert_eq!(601			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),602			1603		);604		assert_eq!(605			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),606			true607		);608609		let origin1 = Origin::signed(1);610611		// Transferring 0 amount works on NFT...612		assert_ok!(Unique::transfer(613			origin1,614			account(2),615			CollectionId(1),616			TokenId(1),617			0618		));619		// ... and results in no transfer620		assert_eq!(621			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),622			1623		);624		assert_eq!(625			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),626			true627		);628	});629}630631#[test]632fn nft_approve_and_transfer_from() {633	new_test_ext().execute_with(|| {634		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));635636		let data = default_nft_data();637		create_test_item(collection_id, &data.into());638639		let origin1 = Origin::signed(1);640		let origin2 = Origin::signed(2);641642		assert_eq!(643			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),644			1645		);646		assert_eq!(647			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),648			true649		);650651		// neg transfer_from652		assert_noop!(653			Unique::transfer_from(654				origin2.clone(),655				account(1),656				account(2),657				CollectionId(1),658				TokenId(1),659				1660			)661			.map_err(|e| e.error),662			CommonError::<Test>::ApprovedValueTooLow663		);664665		// do approve666		assert_ok!(Unique::approve(667			origin1,668			account(2),669			CollectionId(1),670			TokenId(1),671			1672		));673		assert_eq!(674			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),675			account(2)676		);677678		assert_ok!(Unique::transfer_from(679			origin2,680			account(1),681			account(3),682			CollectionId(1),683			TokenId(1),684			1685		));686		assert!(687			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()688		);689	});690}691692#[test]693fn nft_approve_and_transfer_from_allow_list() {694	new_test_ext().execute_with(|| {695		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));696697		let origin1 = Origin::signed(1);698		let origin2 = Origin::signed(2);699700		// Create NFT 1 for account 1701		let data = default_nft_data();702		create_test_item(collection_id, &data.clone().into());703		assert_eq!(704			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))705				.unwrap()706				.const_data,707			&data.const_data.into_inner()708		);709		assert_eq!(710			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),711			1712		);713		assert_eq!(714			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),715			true716		);717718		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list719		assert_ok!(Unique::set_mint_permission(720			origin1.clone(),721			CollectionId(1),722			true723		));724		assert_ok!(Unique::set_public_access_mode(725			origin1.clone(),726			CollectionId(1),727			AccessMode::AllowList728		));729		assert_ok!(Unique::add_to_allow_list(730			origin1.clone(),731			CollectionId(1),732			account(1)733		));734		assert_ok!(Unique::add_to_allow_list(735			origin1.clone(),736			CollectionId(1),737			account(2)738		));739		assert_ok!(Unique::add_to_allow_list(740			origin1.clone(),741			CollectionId(1),742			account(3)743		));744745		// Account 1 approves account 2 for NFT 1746		assert_ok!(Unique::approve(747			origin1.clone(),748			account(2),749			CollectionId(1),750			TokenId(1),751			1752		));753		assert_eq!(754			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),755			account(2)756		);757758		// Account 2 transfers NFT 1 from account 1 to account 3759		assert_ok!(Unique::transfer_from(760			origin2,761			account(1),762			account(3),763			CollectionId(1),764			TokenId(1),765			1766		));767		assert!(768			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()769		);770	});771}772773#[test]774fn refungible_approve_and_transfer_from() {775	new_test_ext().execute_with(|| {776		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));777778		let origin1 = Origin::signed(1);779		let origin2 = Origin::signed(2);780781		// Create RFT 1 in 1023 pieces for account 1782		let data = default_re_fungible_data();783		create_test_item(collection_id, &data.into());784785		assert_eq!(786			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),787			1788		);789		assert_eq!(790			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),791			1023792		);793		assert_eq!(794			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),795			true796		);797798		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list799		assert_ok!(Unique::set_mint_permission(800			origin1.clone(),801			CollectionId(1),802			true803		));804		assert_ok!(Unique::set_public_access_mode(805			origin1.clone(),806			CollectionId(1),807			AccessMode::AllowList808		));809		assert_ok!(Unique::add_to_allow_list(810			origin1.clone(),811			CollectionId(1),812			account(1)813		));814		assert_ok!(Unique::add_to_allow_list(815			origin1.clone(),816			CollectionId(1),817			account(2)818		));819		assert_ok!(Unique::add_to_allow_list(820			origin1.clone(),821			CollectionId(1),822			account(3)823		));824825		// Account 1 approves account 2 for 1023 pieces of RFT 1826		assert_ok!(Unique::approve(827			origin1,828			account(2),829			CollectionId(1),830			TokenId(1),831			1023832		));833		assert_eq!(834			<pallet_refungible::Allowance<Test>>::get((835				CollectionId(1),836				TokenId(1),837				account(1),838				account(2)839			)),840			1023841		);842843		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3844		assert_ok!(Unique::transfer_from(845			origin2,846			account(1),847			account(3),848			CollectionId(1),849			TokenId(1),850			100851		));852		assert_eq!(853			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),854			1855		);856		assert_eq!(857			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),858			1859		);860		assert_eq!(861			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),862			923863		);864		assert_eq!(865			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),866			100867		);868		assert_eq!(869			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),870			true871		);872		assert_eq!(873			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),874			true875		);876		assert_eq!(877			<pallet_refungible::Allowance<Test>>::get((878				CollectionId(1),879				TokenId(1),880				account(1),881				account(2)882			)),883			923884		);885	});886}887888#[test]889fn fungible_approve_and_transfer_from() {890	new_test_ext().execute_with(|| {891		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));892893		let data = default_fungible_data();894		create_test_item(collection_id, &data.into());895896		let origin1 = Origin::signed(1);897		let origin2 = Origin::signed(2);898899		assert_ok!(Unique::set_mint_permission(900			origin1.clone(),901			CollectionId(1),902			true903		));904		assert_ok!(Unique::set_public_access_mode(905			origin1.clone(),906			CollectionId(1),907			AccessMode::AllowList908		));909		assert_ok!(Unique::add_to_allow_list(910			origin1.clone(),911			CollectionId(1),912			account(1)913		));914		assert_ok!(Unique::add_to_allow_list(915			origin1.clone(),916			CollectionId(1),917			account(2)918		));919		assert_ok!(Unique::add_to_allow_list(920			origin1.clone(),921			CollectionId(1),922			account(3)923		));924925		// do approve926		assert_ok!(Unique::approve(927			origin1.clone(),928			account(2),929			CollectionId(1),930			TokenId(0),931			5932		));933		assert_eq!(934			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),935			5936		);937		assert_ok!(Unique::approve(938			origin1,939			account(3),940			CollectionId(1),941			TokenId(0),942			5943		));944		assert_eq!(945			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),946			5947		);948		assert_eq!(949			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),950			5951		);952953		assert_ok!(Unique::transfer_from(954			origin2.clone(),955			account(1),956			account(3),957			CollectionId(1),958			TokenId(0),959			4960		));961962		assert_eq!(963			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),964			1965		);966967		assert_noop!(968			Unique::transfer_from(969				origin2,970				account(1),971				account(3),972				CollectionId(1),973				TokenId(0),974				4975			)976			.map_err(|e| e.error),977			CommonError::<Test>::ApprovedValueTooLow978		);979	});980}981982#[test]983fn change_collection_owner() {984	new_test_ext().execute_with(|| {985		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));986987		let origin1 = Origin::signed(1);988		assert_ok!(Unique::change_collection_owner(origin1, collection_id, 2));989		assert_eq!(990			<pallet_common::CollectionById<Test>>::get(collection_id)991				.unwrap()992				.owner,993			2994		);995	});996}997998#[test]999fn destroy_collection() {1000	new_test_ext().execute_with(|| {1001		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10021003		let origin1 = Origin::signed(1);1004		assert_ok!(Unique::destroy_collection(origin1, collection_id));1005	});1006}10071008#[test]1009fn burn_nft_item() {1010	new_test_ext().execute_with(|| {1011		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10121013		let origin1 = Origin::signed(1);10141015		let data = default_nft_data();1016		create_test_item(collection_id, &data.into());10171018		// check balance (collection with id = 1, user id = 1)1019		assert_eq!(1020			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1021			11022		);10231024		// burn item1025		assert_ok!(Unique::burn_item(1026			origin1.clone(),1027			collection_id,1028			TokenId(1),1029			11030		));1031		assert_eq!(1032			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1033			01034		);1035	});1036}10371038#[test]1039fn burn_same_nft_item_twice() {1040	new_test_ext().execute_with(|| {1041		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));10421043		let origin1 = Origin::signed(1);10441045		let data = default_nft_data();1046		create_test_item(collection_id, &data.into());10471048		// check balance (collection with id = 1, user id = 1)1049		assert_eq!(1050			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1051			11052		);10531054		// burn item1055		assert_ok!(Unique::burn_item(1056			origin1.clone(),1057			collection_id,1058			TokenId(1),1059			11060		));10611062		// burn item again1063		assert_noop!(1064			Unique::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),1065			CommonError::<Test>::TokenNotFound1066		);10671068		assert_eq!(1069			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1070			01071		);1072	});1073}10741075#[test]1076fn burn_fungible_item() {1077	new_test_ext().execute_with(|| {1078		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10791080		let origin1 = Origin::signed(1);1081		assert_ok!(Unique::add_collection_admin(1082			origin1.clone(),1083			collection_id,1084			account(2)1085		));10861087		let data = default_fungible_data();1088		create_test_item(collection_id, &data.into());10891090		// check balance (collection with id = 1, user id = 1)1091		assert_eq!(1092			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1093			51094		);10951096		// burn item1097		assert_ok!(Unique::burn_item(1098			origin1.clone(),1099			CollectionId(1),1100			TokenId(0),1101			51102		));1103		assert_noop!(1104			Unique::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),1105			CommonError::<Test>::TokenValueTooLow1106		);11071108		assert_eq!(1109			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1110			01111		);1112	});1113}11141115#[test]1116fn burn_fungible_item_with_token_id() {1117	new_test_ext().execute_with(|| {1118		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));11191120		let origin1 = Origin::signed(1);1121		assert_ok!(Unique::add_collection_admin(1122			origin1.clone(),1123			collection_id,1124			account(2)1125		));11261127		let data = default_fungible_data();1128		create_test_item(collection_id, &data.into());11291130		// check balance (collection with id = 1, user id = 1)1131		assert_eq!(1132			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1133			51134		);11351136		// Try to burn item using Token ID1137		assert_noop!(1138			Unique::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),1139			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId1140		);1141	});1142}1143#[test]1144fn burn_refungible_item() {1145	new_test_ext().execute_with(|| {1146		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));1147		let origin1 = Origin::signed(1);11481149		assert_ok!(Unique::set_mint_permission(1150			origin1.clone(),1151			collection_id,1152			true1153		));1154		assert_ok!(Unique::set_public_access_mode(1155			origin1.clone(),1156			collection_id,1157			AccessMode::AllowList1158		));1159		assert_ok!(Unique::add_to_allow_list(1160			origin1.clone(),1161			collection_id,1162			account(1)1163		));11641165		assert_ok!(Unique::add_collection_admin(1166			origin1.clone(),1167			collection_id,1168			account(2)1169		));11701171		let data = default_re_fungible_data();1172		create_test_item(collection_id, &data.into());11731174		// check balance (collection with id = 1, user id = 2)1175		assert_eq!(1176			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),1177			11178		);1179		assert_eq!(1180			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1181			10231182		);11831184		// burn item1185		assert_ok!(Unique::burn_item(1186			origin1.clone(),1187			collection_id,1188			TokenId(1),1189			10231190		));1191		assert_noop!(1192			Unique::burn_item(origin1, collection_id, TokenId(1), 1023).map_err(|e| e.error),1193			CommonError::<Test>::TokenValueTooLow1194		);11951196		assert_eq!(1197			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1198			01199		);1200	});1201}12021203#[test]1204fn add_collection_admin() {1205	new_test_ext().execute_with(|| {1206		let collection1_id =1207			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1208		let origin1 = Origin::signed(1);12091210		// Add collection admins1211		assert_ok!(Unique::add_collection_admin(1212			origin1.clone(),1213			collection1_id,1214			account(2)1215		));1216		assert_ok!(Unique::add_collection_admin(1217			origin1,1218			collection1_id,1219			account(3)1220		));12211222		// Owner is not an admin by default1223		assert_eq!(1224			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),1225			false1226		);1227		assert!(<pallet_common::IsAdmin<Test>>::get((1228			CollectionId(1),1229			account(2)1230		)));1231		assert!(<pallet_common::IsAdmin<Test>>::get((1232			CollectionId(1),1233			account(3)1234		)));1235	});1236}12371238#[test]1239fn remove_collection_admin() {1240	new_test_ext().execute_with(|| {1241		let collection1_id =1242			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1243		let origin1 = Origin::signed(1);1244		let origin2 = Origin::signed(2);12451246		// Add collection admins 2 and 31247		assert_ok!(Unique::add_collection_admin(1248			origin1.clone(),1249			collection1_id,1250			account(2)1251		));1252		assert_ok!(Unique::add_collection_admin(1253			origin1,1254			collection1_id,1255			account(3)1256		));12571258		assert!(<pallet_common::IsAdmin<Test>>::get((1259			CollectionId(1),1260			account(2)1261		)));1262		assert!(<pallet_common::IsAdmin<Test>>::get((1263			CollectionId(1),1264			account(3)1265		)));12661267		// remove admin 31268		assert_ok!(Unique::remove_collection_admin(1269			origin2,1270			CollectionId(1),1271			account(3)1272		));12731274		// 2 is still admin, 3 is not an admin anymore1275		assert!(<pallet_common::IsAdmin<Test>>::get((1276			CollectionId(1),1277			account(2)1278		)));1279		assert_eq!(1280			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),1281			false1282		);1283	});1284}12851286#[test]1287fn balance_of() {1288	new_test_ext().execute_with(|| {1289		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1290		let fungible_collection_id =1291			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));1292		let re_fungible_collection_id =1293			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));12941295		// check balance before1296		assert_eq!(1297			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1298			01299		);1300		assert_eq!(1301			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1302			01303		);1304		assert_eq!(1305			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1306			01307		);13081309		let nft_data = default_nft_data();1310		create_test_item(nft_collection_id, &nft_data.into());13111312		let fungible_data = default_fungible_data();1313		create_test_item(fungible_collection_id, &fungible_data.into());13141315		let re_fungible_data = default_re_fungible_data();1316		create_test_item(re_fungible_collection_id, &re_fungible_data.into());13171318		// check balance (collection with id = 1, user id = 1)1319		assert_eq!(1320			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1321			11322		);1323		assert_eq!(1324			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1325			51326		);1327		assert_eq!(1328			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1329			11330		);13311332		assert_eq!(1333			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),1334			true1335		);1336		assert_eq!(1337			<pallet_refungible::Owned<Test>>::get((1338				re_fungible_collection_id,1339				account(1),1340				TokenId(1)1341			)),1342			true1343		);1344	});1345}13461347#[test]1348fn approve() {1349	new_test_ext().execute_with(|| {1350		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));13511352		let data = default_nft_data();1353		create_test_item(collection_id, &data.into());13541355		let origin1 = Origin::signed(1);13561357		// approve1358		assert_ok!(Unique::approve(1359			origin1,1360			account(2),1361			CollectionId(1),1362			TokenId(1),1363			11364		));1365		assert_eq!(1366			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1367			account(2)1368		);1369	});1370}13711372#[test]1373fn transfer_from() {1374	new_test_ext().execute_with(|| {1375		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1376		let origin1 = Origin::signed(1);1377		let origin2 = Origin::signed(2);13781379		let data = default_nft_data();1380		create_test_item(collection_id, &data.into());13811382		// approve1383		assert_ok!(Unique::approve(1384			origin1.clone(),1385			account(2),1386			CollectionId(1),1387			TokenId(1),1388			11389		));1390		assert_eq!(1391			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1392			account(2)1393		);13941395		assert_ok!(Unique::set_mint_permission(1396			origin1.clone(),1397			CollectionId(1),1398			true1399		));1400		assert_ok!(Unique::set_public_access_mode(1401			origin1.clone(),1402			CollectionId(1),1403			AccessMode::AllowList1404		));1405		assert_ok!(Unique::add_to_allow_list(1406			origin1.clone(),1407			CollectionId(1),1408			account(1)1409		));1410		assert_ok!(Unique::add_to_allow_list(1411			origin1.clone(),1412			CollectionId(1),1413			account(2)1414		));1415		assert_ok!(Unique::add_to_allow_list(1416			origin1,1417			CollectionId(1),1418			account(3)1419		));14201421		assert_ok!(Unique::transfer_from(1422			origin2,1423			account(1),1424			account(2),1425			CollectionId(1),1426			TokenId(1),1427			11428		));14291430		// after transfer1431		assert_eq!(1432			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),1433			01434		);1435		assert_eq!(1436			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),1437			11438		);1439	});1440}14411442// #endregion14431444// Coverage tests region1445// #region14461447#[test]1448fn owner_can_add_address_to_allow_list() {1449	new_test_ext().execute_with(|| {1450		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14511452		let origin1 = Origin::signed(1);1453		assert_ok!(Unique::add_to_allow_list(1454			origin1,1455			collection_id,1456			account(2)1457		));1458		assert!(<pallet_common::Allowlist<Test>>::get((1459			collection_id,1460			account(2)1461		)));1462	});1463}14641465#[test]1466fn admin_can_add_address_to_allow_list() {1467	new_test_ext().execute_with(|| {1468		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1469		let origin1 = Origin::signed(1);1470		let origin2 = Origin::signed(2);14711472		assert_ok!(Unique::add_collection_admin(1473			origin1,1474			collection_id,1475			account(2)1476		));1477		assert_ok!(Unique::add_to_allow_list(1478			origin2,1479			collection_id,1480			account(3)1481		));1482		assert!(<pallet_common::Allowlist<Test>>::get((1483			collection_id,1484			account(3)1485		)));1486	});1487}14881489#[test]1490fn nonprivileged_user_cannot_add_address_to_allow_list() {1491	new_test_ext().execute_with(|| {1492		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14931494		let origin2 = Origin::signed(2);1495		assert_noop!(1496			Unique::add_to_allow_list(origin2, collection_id, account(3)),1497			CommonError::<Test>::NoPermission1498		);1499	});1500}15011502#[test]1503fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {1504	new_test_ext().execute_with(|| {1505		let origin1 = Origin::signed(1);15061507		assert_noop!(1508			Unique::add_to_allow_list(origin1, CollectionId(1), account(2)),1509			CommonError::<Test>::CollectionNotFound1510		);1511	});1512}15131514#[test]1515fn nobody_can_add_address_to_allow_list_of_deleted_collection() {1516	new_test_ext().execute_with(|| {1517		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15181519		let origin1 = Origin::signed(1);1520		assert_ok!(Unique::destroy_collection(origin1.clone(), collection_id));1521		assert_noop!(1522			Unique::add_to_allow_list(origin1, collection_id, account(2)),1523			CommonError::<Test>::CollectionNotFound1524		);1525	});1526}15271528// If address is already added to allow list, nothing happens1529#[test]1530fn address_is_already_added_to_allow_list() {1531	new_test_ext().execute_with(|| {1532		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1533		let origin1 = Origin::signed(1);15341535		assert_ok!(Unique::add_to_allow_list(1536			origin1.clone(),1537			collection_id,1538			account(2)1539		));1540		assert_ok!(Unique::add_to_allow_list(1541			origin1,1542			collection_id,1543			account(2)1544		));1545		assert!(<pallet_common::Allowlist<Test>>::get((1546			collection_id,1547			account(2)1548		)));1549	});1550}15511552#[test]1553fn owner_can_remove_address_from_allow_list() {1554	new_test_ext().execute_with(|| {1555		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15561557		let origin1 = Origin::signed(1);1558		assert_ok!(Unique::add_to_allow_list(1559			origin1.clone(),1560			collection_id,1561			account(2)1562		));1563		assert_ok!(Unique::remove_from_allow_list(1564			origin1,1565			collection_id,1566			account(2)1567		));1568		assert_eq!(1569			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1570			false1571		);1572	});1573}15741575#[test]1576fn admin_can_remove_address_from_allow_list() {1577	new_test_ext().execute_with(|| {1578		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1579		let origin1 = Origin::signed(1);1580		let origin2 = Origin::signed(2);15811582		// Owner adds admin1583		assert_ok!(Unique::add_collection_admin(1584			origin1.clone(),1585			collection_id,1586			account(2)1587		));15881589		// Owner adds address 3 to allow list1590		assert_ok!(Unique::add_to_allow_list(1591			origin1,1592			collection_id,1593			account(3)1594		));15951596		// Admin removes address 3 from allow list1597		assert_ok!(Unique::remove_from_allow_list(1598			origin2,1599			collection_id,1600			account(3)1601		));1602		assert_eq!(1603			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),1604			false1605		);1606	});1607}16081609#[test]1610fn nonprivileged_user_cannot_remove_address_from_allow_list() {1611	new_test_ext().execute_with(|| {1612		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1613		let origin1 = Origin::signed(1);1614		let origin2 = Origin::signed(2);16151616		assert_ok!(Unique::add_to_allow_list(1617			origin1,1618			collection_id,1619			account(2)1620		));1621		assert_noop!(1622			Unique::remove_from_allow_list(origin2, collection_id, account(2)),1623			CommonError::<Test>::NoPermission1624		);1625		assert!(<pallet_common::Allowlist<Test>>::get((1626			collection_id,1627			account(2)1628		)));1629	});1630}16311632#[test]1633fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {1634	new_test_ext().execute_with(|| {1635		let origin1 = Origin::signed(1);16361637		assert_noop!(1638			Unique::remove_from_allow_list(origin1, CollectionId(1), account(2)),1639			CommonError::<Test>::CollectionNotFound1640		);1641	});1642}16431644#[test]1645fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {1646	new_test_ext().execute_with(|| {1647		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1648		let origin1 = Origin::signed(1);1649		let origin2 = Origin::signed(2);16501651		// Add account 2 to allow list1652		assert_ok!(Unique::add_to_allow_list(1653			origin1.clone(),1654			collection_id,1655			account(2)1656		));16571658		// Account 2 is in collection allow-list1659		assert!(<pallet_common::Allowlist<Test>>::get((1660			collection_id,1661			account(2)1662		)));16631664		// Destroy collection1665		assert_ok!(Unique::destroy_collection(origin1, collection_id));16661667		// Attempt to remove account 2 from collection allow-list => error1668		assert_noop!(1669			Unique::remove_from_allow_list(origin2, collection_id, account(2)),1670			CommonError::<Test>::CollectionNotFound1671		);16721673		// Account 2 is not found in collection allow-list anyway1674		assert_eq!(1675			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1676			false1677		);1678	});1679}16801681// If address is already removed from allow list, nothing happens1682#[test]1683fn address_is_already_removed_from_allow_list() {1684	new_test_ext().execute_with(|| {1685		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1686		let origin1 = Origin::signed(1);16871688		assert_ok!(Unique::add_to_allow_list(1689			origin1.clone(),1690			collection_id,1691			account(2)1692		));1693		assert_ok!(Unique::remove_from_allow_list(1694			origin1.clone(),1695			collection_id,1696			account(2)1697		));1698		assert_eq!(1699			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1700			false1701		);1702		assert_ok!(Unique::remove_from_allow_list(1703			origin1,1704			collection_id,1705			account(2)1706		));1707		assert_eq!(1708			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1709			false1710		);1711	});1712}17131714// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)1715#[test]1716fn allow_list_test_1() {1717	new_test_ext().execute_with(|| {1718		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17191720		let origin1 = Origin::signed(1);17211722		let data = default_nft_data();1723		create_test_item(collection_id, &data.into());17241725		assert_ok!(Unique::set_public_access_mode(1726			origin1.clone(),1727			collection_id,1728			AccessMode::AllowList1729		));1730		assert_ok!(Unique::add_to_allow_list(1731			origin1.clone(),1732			collection_id,1733			account(2)1734		));17351736		assert_noop!(1737			Unique::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)1738				.map_err(|e| e.error),1739			CommonError::<Test>::AddressNotInAllowlist1740		);1741	});1742}17431744#[test]1745fn allow_list_test_2() {1746	new_test_ext().execute_with(|| {1747		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1748		let origin1 = Origin::signed(1);17491750		let data = default_nft_data();1751		create_test_item(collection_id, &data.into());17521753		assert_ok!(Unique::set_public_access_mode(1754			origin1.clone(),1755			collection_id,1756			AccessMode::AllowList1757		));1758		assert_ok!(Unique::add_to_allow_list(1759			origin1.clone(),1760			collection_id,1761			account(1)1762		));1763		assert_ok!(Unique::add_to_allow_list(1764			origin1.clone(),1765			collection_id,1766			account(2)1767		));17681769		// do approve1770		assert_ok!(Unique::approve(1771			origin1.clone(),1772			account(1),1773			collection_id,1774			TokenId(1),1775			11776		));1777		assert_eq!(1778			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1779			account(1)1780		);17811782		assert_ok!(Unique::remove_from_allow_list(1783			origin1.clone(),1784			collection_id,1785			account(1)1786		));17871788		assert_noop!(1789			Unique::transfer_from(1790				origin1,1791				account(1),1792				account(3),1793				CollectionId(1),1794				TokenId(1),1795				11796			)1797			.map_err(|e| e.error),1798			CommonError::<Test>::AddressNotInAllowlist1799		);1800	});1801}18021803// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)1804#[test]1805fn allow_list_test_3() {1806	new_test_ext().execute_with(|| {1807		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18081809		let origin1 = Origin::signed(1);18101811		let data = default_nft_data();1812		create_test_item(collection_id, &data.into());18131814		assert_ok!(Unique::set_public_access_mode(1815			origin1.clone(),1816			collection_id,1817			AccessMode::AllowList1818		));1819		assert_ok!(Unique::add_to_allow_list(1820			origin1.clone(),1821			collection_id,1822			account(1)1823		));18241825		assert_noop!(1826			Unique::transfer(origin1, account(3), collection_id, TokenId(1), 1)1827				.map_err(|e| e.error),1828			CommonError::<Test>::AddressNotInAllowlist1829		);1830	});1831}18321833#[test]1834fn allow_list_test_4() {1835	new_test_ext().execute_with(|| {1836		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18371838		let origin1 = Origin::signed(1);18391840		let data = default_nft_data();1841		create_test_item(collection_id, &data.into());18421843		assert_ok!(Unique::set_public_access_mode(1844			origin1.clone(),1845			collection_id,1846			AccessMode::AllowList1847		));1848		assert_ok!(Unique::add_to_allow_list(1849			origin1.clone(),1850			collection_id,1851			account(1)1852		));1853		assert_ok!(Unique::add_to_allow_list(1854			origin1.clone(),1855			collection_id,1856			account(2)1857		));18581859		// do approve1860		assert_ok!(Unique::approve(1861			origin1.clone(),1862			account(1),1863			collection_id,1864			TokenId(1),1865			11866		));1867		assert_eq!(1868			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1869			account(1)1870		);18711872		assert_ok!(Unique::remove_from_allow_list(1873			origin1.clone(),1874			collection_id,1875			account(2)1876		));18771878		assert_noop!(1879			Unique::transfer_from(1880				origin1,1881				account(1),1882				account(3),1883				collection_id,1884				TokenId(1),1885				11886			)1887			.map_err(|e| e.error),1888			CommonError::<Test>::AddressNotInAllowlist1889		);1890	});1891}18921893// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)1894#[test]1895fn allow_list_test_5() {1896	new_test_ext().execute_with(|| {1897		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18981899		let origin1 = Origin::signed(1);19001901		let data = default_nft_data();1902		create_test_item(collection_id, &data.into());19031904		assert_ok!(Unique::set_public_access_mode(1905			origin1.clone(),1906			collection_id,1907			AccessMode::AllowList1908		));1909		assert_noop!(1910			Unique::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),1911			CommonError::<Test>::AddressNotInAllowlist1912		);1913	});1914}19151916// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).1917#[test]1918fn allow_list_test_6() {1919	new_test_ext().execute_with(|| {1920		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19211922		let origin1 = Origin::signed(1);19231924		let data = default_nft_data();1925		create_test_item(collection_id, &data.into());19261927		assert_ok!(Unique::set_public_access_mode(1928			origin1.clone(),1929			collection_id,1930			AccessMode::AllowList1931		));19321933		// do approve1934		assert_noop!(1935			Unique::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)1936				.map_err(|e| e.error),1937			CommonError::<Test>::AddressNotInAllowlist1938		);1939	});1940}19411942// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and1943//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)1944#[test]1945fn allow_list_test_7() {1946	new_test_ext().execute_with(|| {1947		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19481949		let data = default_nft_data();1950		create_test_item(collection_id, &data.into());19511952		let origin1 = Origin::signed(1);19531954		assert_ok!(Unique::set_public_access_mode(1955			origin1.clone(),1956			collection_id,1957			AccessMode::AllowList1958		));1959		assert_ok!(Unique::add_to_allow_list(1960			origin1.clone(),1961			collection_id,1962			account(1)1963		));1964		assert_ok!(Unique::add_to_allow_list(1965			origin1.clone(),1966			collection_id,1967			account(2)1968		));19691970		assert_ok!(Unique::transfer(1971			origin1,1972			account(2),1973			CollectionId(1),1974			TokenId(1),1975			11976		));1977	});1978}19791980#[test]1981fn allow_list_test_8() {1982	new_test_ext().execute_with(|| {1983		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19841985		// Create NFT for account 11986		let data = default_nft_data();1987		create_test_item(collection_id, &data.into());19881989		let origin1 = Origin::signed(1);19901991		// Toggle Allow List mode and add accounts 1 and 21992		assert_ok!(Unique::set_public_access_mode(1993			origin1.clone(),1994			collection_id,1995			AccessMode::AllowList1996		));1997		assert_ok!(Unique::add_to_allow_list(1998			origin1.clone(),1999			collection_id,2000			account(1)2001		));2002		assert_ok!(Unique::add_to_allow_list(2003			origin1.clone(),2004			collection_id,2005			account(2)2006		));20072008		// Sself-approve account 1 for NFT 12009		assert_ok!(Unique::approve(2010			origin1.clone(),2011			account(1),2012			CollectionId(1),2013			TokenId(1),2014			12015		));2016		assert_eq!(2017			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),2018			account(1)2019		);20202021		// Transfer from 1 to 22022		assert_ok!(Unique::transfer_from(2023			origin1,2024			account(1),2025			account(2),2026			CollectionId(1),2027			TokenId(1),2028			12029		));2030	});2031}20322033// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.2034#[test]2035fn allow_list_test_9() {2036	new_test_ext().execute_with(|| {2037		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2038		let origin1 = Origin::signed(1);20392040		assert_ok!(Unique::set_public_access_mode(2041			origin1.clone(),2042			collection_id,2043			AccessMode::AllowList2044		));2045		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));20462047		let data = default_nft_data();2048		create_test_item(collection_id, &data.into());2049	});2050}20512052// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.2053#[test]2054fn allow_list_test_10() {2055	new_test_ext().execute_with(|| {2056		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20572058		let origin1 = Origin::signed(1);2059		let origin2 = Origin::signed(2);20602061		assert_ok!(Unique::set_public_access_mode(2062			origin1.clone(),2063			collection_id,2064			AccessMode::AllowList2065		));2066		assert_ok!(Unique::set_mint_permission(2067			origin1.clone(),2068			collection_id,2069			false2070		));20712072		assert_ok!(Unique::add_collection_admin(2073			origin1,2074			collection_id,2075			account(2)2076		));20772078		assert_ok!(Unique::create_item(2079			origin2,2080			collection_id,2081			account(2),2082			default_nft_data().into()2083		));2084	});2085}20862087// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.2088#[test]2089fn allow_list_test_11() {2090	new_test_ext().execute_with(|| {2091		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20922093		let origin1 = Origin::signed(1);2094		let origin2 = Origin::signed(2);20952096		assert_ok!(Unique::set_public_access_mode(2097			origin1.clone(),2098			collection_id,2099			AccessMode::AllowList2100		));2101		assert_ok!(Unique::set_mint_permission(2102			origin1.clone(),2103			collection_id,2104			false2105		));2106		assert_ok!(Unique::add_to_allow_list(2107			origin1,2108			collection_id,2109			account(2)2110		));21112112		assert_noop!(2113			Unique::create_item(2114				origin2,2115				CollectionId(1),2116				account(2),2117				default_nft_data().into()2118			)2119			.map_err(|e| e.error),2120			CommonError::<Test>::PublicMintingNotAllowed2121		);2122	});2123}21242125// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.2126#[test]2127fn allow_list_test_12() {2128	new_test_ext().execute_with(|| {2129		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21302131		let origin1 = Origin::signed(1);2132		let origin2 = Origin::signed(2);21332134		assert_ok!(Unique::set_public_access_mode(2135			origin1.clone(),2136			collection_id,2137			AccessMode::AllowList2138		));2139		assert_ok!(Unique::set_mint_permission(origin1, collection_id, false));21402141		assert_noop!(2142			Unique::create_item(2143				origin2,2144				CollectionId(1),2145				account(2),2146				default_nft_data().into()2147			)2148			.map_err(|e| e.error),2149			CommonError::<Test>::PublicMintingNotAllowed2150		);2151	});2152}21532154// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.2155#[test]2156fn allow_list_test_13() {2157	new_test_ext().execute_with(|| {2158		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21592160		let origin1 = Origin::signed(1);21612162		assert_ok!(Unique::set_public_access_mode(2163			origin1.clone(),2164			collection_id,2165			AccessMode::AllowList2166		));2167		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));21682169		let data = default_nft_data();2170		create_test_item(collection_id, &data.into());2171	});2172}21732174// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.2175#[test]2176fn allow_list_test_14() {2177	new_test_ext().execute_with(|| {2178		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21792180		let origin1 = Origin::signed(1);2181		let origin2 = Origin::signed(2);21822183		assert_ok!(Unique::set_public_access_mode(2184			origin1.clone(),2185			collection_id,2186			AccessMode::AllowList2187		));2188		assert_ok!(Unique::set_mint_permission(2189			origin1.clone(),2190			collection_id,2191			true2192		));21932194		assert_ok!(Unique::add_collection_admin(2195			origin1,2196			collection_id,2197			account(2)2198		));21992200		assert_ok!(Unique::create_item(2201			origin2,2202			collection_id,2203			account(2),2204			default_nft_data().into()2205		));2206	});2207}22082209// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.2210#[test]2211fn allow_list_test_15() {2212	new_test_ext().execute_with(|| {2213		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22142215		let origin1 = Origin::signed(1);2216		let origin2 = Origin::signed(2);22172218		assert_ok!(Unique::set_public_access_mode(2219			origin1.clone(),2220			collection_id,2221			AccessMode::AllowList2222		));2223		assert_ok!(Unique::set_mint_permission(origin1, collection_id, true));22242225		assert_noop!(2226			Unique::create_item(2227				origin2,2228				collection_id,2229				account(2),2230				default_nft_data().into()2231			)2232			.map_err(|e| e.error),2233			CommonError::<Test>::AddressNotInAllowlist2234		);2235	});2236}22372238// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.2239#[test]2240fn allow_list_test_16() {2241	new_test_ext().execute_with(|| {2242		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22432244		let origin1 = Origin::signed(1);2245		let origin2 = Origin::signed(2);22462247		assert_ok!(Unique::set_public_access_mode(2248			origin1.clone(),2249			collection_id,2250			AccessMode::AllowList2251		));2252		assert_ok!(Unique::set_mint_permission(2253			origin1.clone(),2254			collection_id,2255			true2256		));2257		assert_ok!(Unique::add_to_allow_list(2258			origin1,2259			collection_id,2260			account(2)2261		));22622263		assert_ok!(Unique::create_item(2264			origin2,2265			collection_id,2266			account(2),2267			default_nft_data().into()2268		));2269	});2270}22712272// Total number of collections. Positive test2273#[test]2274fn total_number_collections_bound() {2275	new_test_ext().execute_with(|| {2276		create_test_collection(&CollectionMode::NFT, CollectionId(1));2277	});2278}22792280#[test]2281fn create_max_collections() {2282	new_test_ext().execute_with(|| {2283		for i in 1..COLLECTION_NUMBER_LIMIT {2284			create_test_collection(&CollectionMode::NFT, CollectionId(i));2285		}2286	});2287}22882289// Total number of collections. Negative test2290#[test]2291fn total_number_collections_bound_neg() {2292	new_test_ext().execute_with(|| {2293		let origin1 = Origin::signed(1);22942295		for i in 1..=COLLECTION_NUMBER_LIMIT {2296			create_test_collection(&CollectionMode::NFT, CollectionId(i));2297		}22982299		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();2300		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();2301		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();23022303		let data: CreateCollectionData<u64> = CreateCollectionData {2304			name: col_name1.try_into().unwrap(),2305			description: col_desc1.try_into().unwrap(),2306			token_prefix: token_prefix1.try_into().unwrap(),2307			mode: CollectionMode::NFT,2308			..Default::default()2309		};23102311		// 11-th collection in chain. Expects error2312		assert_noop!(2313			Unique::create_collection_ex(origin1, data),2314			CommonError::<Test>::TotalCollectionsLimitExceeded2315		);2316	});2317}23182319// Owned tokens by a single address. Positive test2320#[test]2321fn owned_tokens_bound() {2322	new_test_ext().execute_with(|| {2323		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23242325		let data = default_nft_data();2326		create_test_item(collection_id, &data.clone().into());2327		create_test_item(collection_id, &data.into());2328	});2329}23302331// Owned tokens by a single address. Negotive test2332#[test]2333fn owned_tokens_bound_neg() {2334	new_test_ext().execute_with(|| {2335		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23362337		let origin1 = Origin::signed(1);23382339		for _ in 1..=MAX_TOKEN_OWNERSHIP {2340			let data = default_nft_data();2341			create_test_item(collection_id, &data.clone().into());2342		}23432344		let data = default_nft_data();2345		assert_noop!(2346			Unique::create_item(origin1, CollectionId(1), account(1), data.into())2347				.map_err(|e| e.error),2348			CommonError::<Test>::AccountTokenLimitExceeded2349		);2350	});2351}23522353// Number of collection admins. Positive test2354#[test]2355fn collection_admins_bound() {2356	new_test_ext().execute_with(|| {2357		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23582359		let origin1 = Origin::signed(1);23602361		assert_ok!(Unique::add_collection_admin(2362			origin1.clone(),2363			collection_id,2364			account(2)2365		));2366		assert_ok!(Unique::add_collection_admin(2367			origin1,2368			collection_id,2369			account(3)2370		));2371	});2372}23732374// Number of collection admins. Negotive test2375#[test]2376fn collection_admins_bound_neg() {2377	new_test_ext().execute_with(|| {2378		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23792380		let origin1 = Origin::signed(1);23812382		for i in 0..COLLECTION_ADMINS_LIMIT {2383			assert_ok!(Unique::add_collection_admin(2384				origin1.clone(),2385				collection_id,2386				account((2 + i).into())2387			));2388		}2389		assert_noop!(2390			Unique::add_collection_admin(2391				origin1,2392				collection_id,2393				account((3 + COLLECTION_ADMINS_LIMIT).into())2394			),2395			CommonError::<Test>::CollectionAdminCountExceeded2396		);2397	});2398}2399// #endregion24002401#[test]2402fn set_const_on_chain_schema() {2403	new_test_ext().execute_with(|| {2404		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24052406		let origin1 = Origin::signed(1);2407		assert_ok!(Unique::set_const_on_chain_schema(2408			origin1,2409			collection_id,2410			b"test const on chain schema".to_vec().try_into().unwrap()2411		));24122413		assert_eq!(2414			<pallet_common::CollectionData<Test>>::get((2415				collection_id,2416				CollectionField::ConstOnChainSchema2417			)),2418			b"test const on chain schema".to_vec()2419		);2420	});2421}24222423#[test]2424fn collection_transfer_flag_works() {2425	new_test_ext().execute_with(|| {2426		let origin1 = Origin::signed(1);24272428		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2429		assert_ok!(Unique::set_transfers_enabled_flag(2430			origin1,2431			collection_id,2432			true2433		));24342435		let data = default_nft_data();2436		create_test_item(collection_id, &data.into());2437		assert_eq!(2438			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2439			12440		);2441		assert_eq!(2442			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2443			true2444		);24452446		let origin1 = Origin::signed(1);24472448		// default scenario2449		assert_ok!(Unique::transfer(2450			origin1,2451			account(2),2452			collection_id,2453			TokenId(1),2454			12455		));2456		assert_eq!(2457			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2458			false2459		);2460		assert_eq!(2461			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2462			true2463		);2464		assert_eq!(2465			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2466			02467		);2468		assert_eq!(2469			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2470			12471		);2472	});2473}24742475#[test]2476fn collection_transfer_flag_works_neg() {2477	new_test_ext().execute_with(|| {2478		let origin1 = Origin::signed(1);24792480		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2481		assert_ok!(Unique::set_transfers_enabled_flag(2482			origin1,2483			collection_id,2484			false2485		));24862487		let data = default_nft_data();2488		create_test_item(collection_id, &data.into());2489		assert_eq!(2490			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2491			12492		);2493		assert_eq!(2494			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2495			true2496		);24972498		let origin1 = Origin::signed(1);24992500		// default scenario2501		assert_noop!(2502			Unique::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)2503				.map_err(|e| e.error),2504			CommonError::<Test>::TransferNotAllowed2505		);2506		assert_eq!(2507			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2508			12509		);2510		assert_eq!(2511			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2512			02513		);2514		assert_eq!(2515			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2516			true2517		);2518		assert_eq!(2519			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2520			false2521		);2522	});2523}25242525#[test]2526fn collection_sponsoring() {2527	new_test_ext().execute_with(|| {2528		// default_limits();2529		let user1 = 1_u64;2530		let user2 = 777_u64;2531		let origin1 = Origin::signed(user1);2532		let origin2 = Origin::signed(user2);2533		let account2 = account(user2);25342535		let collection_id =2536			create_test_collection_for_owner(&CollectionMode::NFT, user1, CollectionId(1));2537		assert_ok!(Unique::set_collection_sponsor(2538			origin1.clone(),2539			collection_id,2540			user12541		));2542		assert_ok!(Unique::confirm_sponsorship(origin1.clone(), collection_id));25432544		// Expect error while have no permissions2545		assert!(Unique::create_item(2546			origin2.clone(),2547			collection_id,2548			account2.clone(),2549			default_nft_data().into()2550		)2551		.is_err());25522553		assert_ok!(Unique::set_public_access_mode(2554			origin1.clone(),2555			collection_id,2556			AccessMode::AllowList2557		));2558		assert_ok!(Unique::add_to_allow_list(2559			origin1.clone(),2560			collection_id,2561			account2.clone()2562		));2563		assert_ok!(Unique::set_mint_permission(2564			origin1.clone(),2565			collection_id,2566			true2567		));25682569		assert_ok!(Unique::create_item(2570			origin2,2571			collection_id,2572			account2,2573			default_nft_data().into()2574		));2575	});2576}
modifiedsmart_contracs/transfer/lib.rsdiffbeforeafterboth
--- a/smart_contracs/transfer/lib.rs
+++ b/smart_contracs/transfer/lib.rs
@@ -58,14 +58,12 @@
 pub enum CreateItemData {
     Nft {
         const_data: Vec<u8>,
-        variable_data: Vec<u8>,
     },
     Fungible {
         value: u128,
     },
     ReFungible {
         const_data: Vec<u8>,
-        variable_data: Vec<u8>,
         pieces: u128,
     },
 }
@@ -88,8 +86,6 @@
     fn approve(spender: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);
     #[ink(extension = 4, returns_result = false)]
     fn transfer_from(owner: DefaultAccountId, recipient: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);
-    #[ink(extension = 5, returns_result = false)]
-    fn set_variable_meta_data(collection_id: u32, item_id: u32, data: Vec<u8>);
     #[ink(extension = 6, returns_result = false)]
     fn toggle_allow_list(collection_id: u32, address: DefaultAccountId, allowlisted: bool);
 }
@@ -143,12 +139,6 @@
             let _ = self.env()
                 .extension()
                 .transfer_from(owner, recipient, collection_id, item_id, amount);
-        }
-        #[ink(message)]
-        pub fn set_variable_meta_data(&mut self, collection_id: u32, item_id: u32, data: Vec<u8>) {
-            let _ = self.env()
-                .extension()
-                .set_variable_meta_data(collection_id, item_id, data);
         }
         #[ink(message)]
         pub fn toggle_allow_list(&mut self, collection_id: u32, address: AccountId, allowlisted: bool) {
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -40,7 +40,6 @@
     "testMigrationStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",
     "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",
     "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",
-    "testSetVariableMetaData": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetaData.test.ts",
     "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",
     "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts",
     "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts",
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -111,7 +111,7 @@
       await addToAllowListExpectSuccess(alice, collectionId, contract.address);
       await addToAllowListExpectSuccess(alice, collectionId, bob.address);
 
-      const transferTx = contract.tx.createItem(value, gasLimit, bob.address, collectionId, {Nft: {const_data: '0x010203', variable_data: '0x020304'}});
+      const transferTx = contract.tx.createItem(value, gasLimit, bob.address, collectionId, {Nft: {const_data: '0x010203'}});
       const events = await submitTransactionAsync(alice, transferTx);
       const result = getGenericResult(events);
       expect(result.success).to.be.true;
@@ -121,7 +121,6 @@
         {
           owner: bob.address,
           constData: '0x010203',
-          variableData: '0x020304',
         },
       ]);
     });
@@ -140,9 +139,9 @@
       await addToAllowListExpectSuccess(alice, collectionId, bob.address);
 
       const transferTx = contract.tx.createMultipleItems(value, gasLimit, bob.address, collectionId, [
-        {Nft: {const_data: '0x010203', variable_data: '0x020304'}},
-        {Nft: {const_data: '0x010204', variable_data: '0x020305'}},
-        {Nft: {const_data: '0x010205', variable_data: '0x020306'}},
+        {Nft: {const_data: '0x010203'}},
+        {Nft: {const_data: '0x010204'}},
+        {Nft: {const_data: '0x010205'}},
       ]);
       const events = await submitTransactionAsync(alice, transferTx);
       const result = getGenericResult(events);
@@ -155,17 +154,14 @@
         {
           Owner: bob.address,
           ConstData: '0x010203',
-          VariableData: '0x020304',
         },
         {
           Owner: bob.address,
           ConstData: '0x010204',
-          VariableData: '0x020305',
         },
         {
           Owner: bob.address,
           ConstData: '0x010205',
-          VariableData: '0x020306',
         },
       ]);
     });
@@ -208,24 +204,6 @@
 
       const token: any = (await api.query.unique.nftItemList(collectionId, tokenId) as any).unwrap();
       expect(token.owner.toString()).to.be.equal(charlie.address);
-    });
-  });
-
-  it('SetVariableMetaData CE', async () => {
-    await usingApi(async api => {
-      const alice = privateKey('//Alice');
-
-      const collectionId = await createCollectionExpectSuccess();
-      const [contract] = await deployTransferContract(api);
-      const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', contract.address.toString());
-
-      const transferTx = contract.tx.setVariableMetaData(value, gasLimit, collectionId, tokenId, '0x121314');
-      const events = await submitTransactionAsync(alice, transferTx);
-      const result = getGenericResult(events);
-      expect(result.success).to.be.true;
-
-      const token: any = (await api.query.unique.nftItemList(collectionId, tokenId) as any).unwrap();
-      expect(token.variableData.toString()).to.be.equal('0x121314');
     });
   });
 
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -74,7 +74,6 @@
           accountTokenOwnershipLimit: 3,
         },
         constOnChainSchema: '0x333333',
-        metaUpdatePermission: 'Admin',
       });
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateCollectionResult(events);
@@ -91,7 +90,6 @@
       expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address);
       expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
       expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
-      expect(collection.metaUpdatePermission.isAdmin).to.be.true;
     });
   });
 });
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -30,7 +30,6 @@
   getBalance,
   getTokenOwner,
   getLastTokenId,
-  getVariableMetadata,
   getConstMetadata,
   getCreatedCollectionCount,
   createCollectionWithPropsExpectSuccess,
@@ -47,9 +46,9 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       const alice = privateKey('//Alice');
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -63,10 +62,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 
@@ -97,9 +92,9 @@
       expect(itemsListIndexBefore).to.be.equal(0);
       const alice = privateKey('//Alice');
       const args = [
-        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},
-        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},
-        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},
+        {ReFungible: {const_data: [0x31], pieces: 1}},
+        {ReFungible: {const_data: [0x32], pieces: 1}},
+        {ReFungible: {const_data: [0x33], pieces: 1}},
       ];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
@@ -114,10 +109,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 
@@ -130,8 +121,8 @@
         tokenLimit: 2,
       });
       const args = [
-        {NFT: {const_data: 'A', variable_data: 'A'}},
-        {NFT: {const_data: 'B', variable_data: 'B'}},
+        {NFT: {const_data: 'A'}},
+        {NFT: {const_data: 'B'}},
       ];
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -146,9 +137,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       const alice = privateKey('//Alice');
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const bob = privateKey('//Bob');
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -156,9 +148,9 @@
       expect(itemsListIndexAfter).to.be.equal(3);
 
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]),
       )).to.not.be.rejected;
 
       expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));
@@ -168,10 +160,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 
@@ -181,9 +169,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       const alice = privateKey('//Alice');
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const bob = privateKey('//Bob');
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -191,9 +180,9 @@
       expect(itemsListIndexAfter).to.be.equal(3);
 
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]),
       )).to.not.be.rejected;
 
       expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));
@@ -203,10 +192,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 
@@ -216,9 +201,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       const alice = privateKey('//Alice');
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const bob = privateKey('//Bob');
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -226,9 +212,9 @@
       expect(itemsListIndexAfter).to.be.equal(3);
 
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collectionId, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]),
       )).to.not.be.rejected;
 
       expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address));
@@ -238,10 +224,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 });
@@ -264,9 +246,9 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
       await submitTransactionAsync(bob, createMultipleItemsTx);
@@ -280,10 +262,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 
@@ -314,9 +292,9 @@
       expect(itemsListIndexBefore).to.be.equal(0);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
       const args = [
-        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},
-        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},
-        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},
+        {ReFungible: {const_data: [0x31], pieces: 1}},
+        {ReFungible: {const_data: [0x32], pieces: 1}},
+        {ReFungible: {const_data: [0x33], pieces: 1}},
       ];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(bob.address), args);
@@ -331,10 +309,6 @@
       expect(await getConstMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
       expect(await getConstMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
       expect(await getConstMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
-
-      expect(await getVariableMetadata(api, collectionId, 1)).to.be.deep.equal([0x31]);
-      expect(await getVariableMetadata(api, collectionId, 2)).to.be.deep.equal([0x32]);
-      expect(await getVariableMetadata(api, collectionId, 3)).to.be.deep.equal([0x33]);
     });
   });
 });
@@ -356,9 +330,9 @@
       const collectionId = await createCollectionExpectSuccess();
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await expect(submitTransactionAsync(bob, createMultipleItemsTx)).to.be.rejected;
@@ -387,9 +361,9 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       const args = [
-        {ReFungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},
-        {ReFungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},
-        {ReFungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},
+        {ReFungible: {const_data: [0x31], pieces: 1}},
+        {ReFungible: {const_data: [0x32], pieces: 1}},
+        {ReFungible: {const_data: [0x33], pieces: 1}},
       ];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
@@ -412,9 +386,9 @@
       const collectionId = await createCollectionExpectSuccess();
       const alice = privateKey('//Alice');
       const args = [
-        {NFT: {const_data: 'A'.repeat(2049), variable_data: 'A'.repeat(2049)}},
-        {NFT: {const_data: 'B'.repeat(2049), variable_data: 'B'.repeat(2049)}},
-        {NFT: {const_data: 'C'.repeat(2049), variable_data: 'C'.repeat(2049)}},
+        {NFT: {const_data: 'A'.repeat(2049)}},
+        {NFT: {const_data: 'B'.repeat(2049)}},
+        {NFT: {const_data: 'C'.repeat(2049)}},
       ];
       const createMultipleItemsTx = api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
@@ -424,9 +398,9 @@
       const collectionIdReFungible =
         await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const argsReFungible = [
-        {ReFungible: ['1'.repeat(2049), '1'.repeat(2049), 10]},
-        {ReFungible: ['2'.repeat(2049), '2'.repeat(2049), 10]},
-        {ReFungible: ['3'.repeat(2049), '3'.repeat(2049), 10]},
+        {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);
@@ -449,9 +423,8 @@
     await usingApi(async (api: ApiPromise) => {
       const collectionId = await createCollectionExpectSuccess();
       const args = [
-        {NFT: {const_data: 'A', variable_data: 'A'}},
-        {NFT: {const_data: 'B', variable_data: 'B'.repeat(2049)}},
-        {NFT: {const_data: 'C'.repeat(2049), variable_data: 'C'}},
+        {NFT: {const_data: 'A'}},
+        {NFT: {const_data: 'B'.repeat(2049)}},
       ];
       const createMultipleItemsTx = await api.tx.unique
         .createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
@@ -467,8 +440,8 @@
         tokenLimit: 1,
       });
       const args = [
-        {NFT: {const_data: 'A', variable_data: 'A'}},
-        {NFT: {const_data: 'B', variable_data: 'B'}},
+        {NFT: {const_data: 'A'}},
+        {NFT: {const_data: 'B'}},
       ];
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected;
@@ -482,10 +455,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
-      
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
+
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
 
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -493,9 +466,9 @@
 
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
 
@@ -510,10 +483,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
-      
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
+
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
 
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -521,9 +494,9 @@
 
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
     });
@@ -535,10 +508,10 @@
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
       expect(itemsListIndexBefore).to.be.equal(0);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
-      
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
+
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
 
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -546,9 +519,9 @@
 
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
     });
@@ -562,28 +535,28 @@
       expect(itemsListIndexBefore).to.be.equal(0);
       await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
 
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
-      
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
+
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
 
       const result = getCreateItemsResult(events);
-      
+
       const prps = [];
-      
+
       for (let i = 0; i < 65; i++) {
         prps.push({key: `key${i}`, value: `value${i}`});
       }
 
       await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collectionId, prps))).to.be.rejectedWith(/common\.PropertyLimitReached/);
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps),
         )).to.be.rejected;
       }
     });
@@ -595,10 +568,10 @@
         propPerm:   [{key: 'key1', mutable: true, collectionAdmin: false, tokenOwner: false}]});
       const itemsListIndexBefore = await getLastTokenId(api, collectionId);
       expect(itemsListIndexBefore).to.be.equal(0);
-      const args = [{Nft: {const_data: '0x31', variable_data: '0x31'}},
-        {Nft: {const_data: '0x32', variable_data: '0x32'}},
-        {Nft: {const_data: '0x33', variable_data: '0x33'}}];
-      
+      const args = [{Nft: {const_data: '0x31'}},
+        {Nft: {const_data: '0x32'}},
+        {Nft: {const_data: '0x33'}}];
+
       const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args);
 
       const events = await submitTransactionAsync(alice, createMultipleItemsTx);
@@ -609,9 +582,9 @@
 
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]),
         )).to.be.rejected;
       }
     });
modifiedtests/src/createMultipleItemsEx.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItemsEx.test.ts
+++ b/tests/src/createMultipleItemsEx.test.ts
@@ -30,15 +30,12 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
 
@@ -61,22 +58,19 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
 
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]),
       )).to.not.be.rejected;
 
       await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
@@ -98,28 +92,25 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]),
       )).to.not.be.rejected;
 
       await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
         NFT: data,
       }));
-      
 
+
       const tokens = await api.query.nonfungible.tokenData.entries(collection);
       const json = tokens.map(([, token]) => token.toJSON());
       expect(json).to.be.deep.equal(data);
@@ -136,28 +127,25 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
       await expect(executeTransaction(
-        api, 
-        alice, 
-        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]), 
+        api,
+        alice,
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]),
       )).to.not.be.rejected;
 
       await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, {
         NFT: data,
       }));
-      
 
+
       const tokens = await api.query.nonfungible.tokenData.entries(collection);
       const json = tokens.map(([, token]) => token.toJSON());
       expect(json).to.be.deep.equal(data);
@@ -184,15 +172,15 @@
 
       const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
       await executeTransaction(api, alice, tx);
-      
+
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateItemsResult(events);
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
     });
@@ -218,15 +206,15 @@
 
       const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
       await executeTransaction(api, alice, tx);
-      
+
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateItemsResult(events);
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
     });
@@ -251,15 +239,15 @@
 
       const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
       await executeTransaction(api, alice, tx);
-      
+
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateItemsResult(events);
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, [{key: 'key1', value: 'v2'}]),
         )).to.be.rejected;
       }
     });
@@ -284,24 +272,24 @@
 
       const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
       await executeTransaction(api, alice, tx);
-      
+
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateItemsResult(events);
 
       const prps = [];
-      
+
       for (let i = 0; i < 65; i++) {
         prps.push({key: `key${i}`, value: `value${i}`});
       }
 
       await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collection, prps))).to.be.rejectedWith(/common\.PropertyLimitReached/);
 
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps),
         )).to.be.rejected;
       }
     });
@@ -326,7 +314,7 @@
 
       const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data});
       await executeTransaction(api, alice, tx);
-      
+
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateItemsResult(events);
 
@@ -334,12 +322,12 @@
 
       await expect(executeTransaction(api, bob, api.tx.unique.setCollectionProperties(collection, prps))).to.be.rejectedWith(/common\.NoSpaceForProperty/);
 
-      
+
       for (const elem of result) {
         await expect(executeTransaction(
-          api, 
-          bob, 
-          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps), 
+          api,
+          bob,
+          api.tx.unique.setTokenProperties(elem.collectionId, elem.itemId, prps),
         )).to.be.rejected;
       }
     });
@@ -355,15 +343,12 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
 
@@ -386,15 +371,12 @@
         {
           owner: {substrate: alice.address},
           constData: '0x0000',
-          variableData: '0x1111',
         }, {
           owner: {substrate: bob.address},
           constData: '0x2222',
-          variableData: '0x3333',
         }, {
           owner: {substrate: charlie.address},
           constData: '0x4444',
-          variableData: '0x5555',
         },
       ];
 
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -22,6 +22,12 @@
 	);
 }
 
+// Selector: 79cc6790
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) external returns (bool);
+}
+
 // Selector: 942e8b22
 interface ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
@@ -59,4 +65,28 @@
 		returns (uint256);
 }
 
-interface UniqueFungible is Dummy, ERC165, ERC20 {}
+// Selector: 9b5e29c5
+interface CollectionProperties 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);
+}
+
+interface UniqueFungible is
+	Dummy,
+	ERC165,
+	ERC20,
+	ERC20UniqueExtensions,
+	CollectionProperties
+{}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -42,6 +42,35 @@
 	event MintingFinished();
 }
 
+// Selector: 41369377
+interface TokenProperties is Dummy, ERC165 {
+	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
+	function setTokenPropertyPermission(
+		string memory key,
+		bool isMutable,
+		bool collectionAdmin,
+		bool tokenOwner
+	) external;
+
+	// Selector: setProperty(uint256,string,bytes) 1752d67b
+	function setProperty(
+		uint256 tokenId,
+		string memory key,
+		bytes memory value
+	) external;
+
+	// Selector: deleteProperty(uint256,string) 066111d1
+	function deleteProperty(uint256 tokenId, string memory key) external;
+
+	// Throws error if key not found
+	//
+	// Selector: property(uint256,string) 7228c327
+	function property(uint256 tokenId, string memory key)
+		external
+		view
+		returns (bytes memory);
+}
+
 // Selector: 42966c68
 interface ERC721Burnable is Dummy, ERC165 {
 	// Selector: burn(uint256) 42966c68
@@ -162,7 +191,25 @@
 	function totalSupply() external view returns (uint256);
 }
 
-// Selector: e562194d
+// Selector: 9b5e29c5
+interface CollectionProperties 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: d74d154f
 interface ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) external;
@@ -172,16 +219,7 @@
 
 	// Selector: nextTokenId() 75794a3c
 	function nextTokenId() external view returns (uint256);
-
-	// Selector: setVariableMetadata(uint256,bytes) d4eac26d
-	function setVariableMetadata(uint256 tokenId, bytes memory data) external;
 
-	// Selector: getVariableMetadata(uint256) e6c5ce6f
-	function getVariableMetadata(uint256 tokenId)
-		external
-		view
-		returns (bytes memory);
-
 	// Selector: mintBulk(address,uint256[]) 44a9945e
 	function mintBulk(address to, uint256[] memory tokenIds)
 		external
@@ -201,5 +239,7 @@
 	ERC721Enumerable,
 	ERC721UniqueExtensions,
 	ERC721Mintable,
-	ERC721Burnable
+	ERC721Burnable,
+	CollectionProperties,
+	TokenProperties
 {}
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -79,7 +79,7 @@
       minter = createEthAccount(web3);
     });
   });
-  
+
   itWeb3('interfaceID == 0xffffffff always false', async ({web3}) => {
     expect(await contract(web3).methods.supportsInterface('0xffffffff').call()).to.be.false;
   });
@@ -101,7 +101,7 @@
   });
 
   itWeb3('ERC721UniqueExtensions support', async ({web3}) => {
-    expect(await contract(web3).methods.supportsInterface('0xe562194d').call()).to.be.true;
+    expect(await contract(web3).methods.supportsInterface('0xd74d154f').call()).to.be.true;
   });
 
   itWeb3('ERC721Burnable support', async ({web3}) => {
addedtests/src/eth/collectionProperties.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/collectionProperties.test.ts
@@ -0,0 +1,54 @@
+import privateKey from '../substrate/privateKey';
+import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess} from '../util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3} from './util/helpers';
+import nonFungibleAbi from './nonFungibleAbi.json';
+import {expect} from 'chai';
+import {executeTransaction} from '../substrate/substrate-api';
+
+describe('EVM collection properties', () => {
+  itWeb3('Can be set', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+
+    await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    await contract.methods.setCollectionProperty('testKey', Buffer.from('testValue')).send({from: caller});
+
+    const [{value}] = (await api.rpc.unique.collectionProperties(collection, ['testKey'])).toHuman()! as any;
+    expect(value).to.equal('testValue');
+  });
+  itWeb3('Can be deleted', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+
+    await executeTransaction(api, alice, api.tx.unique.setCollectionProperties(collection, [{key: 'testKey', value: 'testValue'}]));
+
+    await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    await contract.methods.deleteCollectionProperty('testKey').send({from: caller});
+
+    const result = (await api.rpc.unique.collectionProperties(collection, ['testKey'])).toJSON()! as any;
+    expect(result.length).to.equal(0);
+  });
+  itWeb3('Can be read', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = createEthAccount(web3);
+    const collection = await createCollectionExpectSuccess({mode: {type:'NFT'}});
+
+    await executeTransaction(api, alice, api.tx.unique.setCollectionProperties(collection, [{key: 'testKey', value: 'testValue'}]));
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    const value = await contract.methods.collectionProperty('testKey').call();
+    expect(value).to.equal(web3.utils.toHex('testValue'));
+  });
+});
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import privateKey from '../substrate/privateKey';
-import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE, setMetadataUpdatePermissionFlagExpectSuccess} from '../util/helpers';
+import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import {expect} from 'chai';
@@ -331,41 +331,6 @@
       const balance = await contract.methods.balanceOf(receiver).call();
       expect(+balance).to.equal(1);
     }
-  });
-
-  itWeb3('Can perform getVariableMetadata', async ({web3, api}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKey('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3);
-
-    const item = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
-    await setMetadataUpdatePermissionFlagExpectSuccess(alice, collection, 'Admin');
-    await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
-  });
-
-  itWeb3('Can perform setVariableMetadata', async ({web3, api}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKey('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3);
-
-    const item = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
-
-    expect(await contract.methods.setVariableMetadata(item, '0x010203').send({from: owner}));
-    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
   });
 });
 
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -1,614 +1,738 @@
 [
-    {
-        "anonymous": false,
-        "inputs": [
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "owner",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "approved",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "Approval",
-        "type": "event"
-    },
-    {
-        "anonymous": false,
-        "inputs": [
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "owner",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "operator",
-                "type": "address"
-            },
-            {
-                "indexed": false,
-                "internalType": "bool",
-                "name": "approved",
-                "type": "bool"
-            }
-        ],
-        "name": "ApprovalForAll",
-        "type": "event"
-    },
-    {
-        "anonymous": false,
-        "inputs": [],
-        "name": "MintingFinished",
-        "type": "event"
-    },
-    {
-        "anonymous": false,
-        "inputs": [
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "from",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "Transfer",
-        "type": "event"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "approved",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "approve",
-        "outputs": [],
-        "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": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "burn",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "finishMinting",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "getApproved",
-        "outputs": [
-            {
-                "internalType": "address",
-                "name": "",
-                "type": "address"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "getVariableMetadata",
-        "outputs": [
-            {
-                "internalType": "bytes",
-                "name": "",
-                "type": "bytes"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "owner",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "operator",
-                "type": "address"
-            }
-        ],
-        "name": "isApprovedForAll",
-        "outputs": [
-            {
-                "internalType": "address",
-                "name": "",
-                "type": "address"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "mint",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256[]",
-                "name": "tokenIds",
-                "type": "uint256[]"
-            }
-        ],
-        "name": "mintBulk",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "components": [
-                    {
-                        "internalType": "uint256",
-                        "name": "field_0",
-                        "type": "uint256"
-                    },
-                    {
-                        "internalType": "string",
-                        "name": "field_1",
-                        "type": "string"
-                    }
-                ],
-                "internalType": "struct Tuple0[]",
-                "name": "tokens",
-                "type": "tuple[]"
-            }
-        ],
-        "name": "mintBulkWithTokenURI",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            },
-            {
-                "internalType": "string",
-                "name": "tokenUri",
-                "type": "string"
-            }
-        ],
-        "name": "mintWithTokenURI",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "mintingFinished",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "name",
-        "outputs": [
-            {
-                "internalType": "string",
-                "name": "",
-                "type": "string"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "nextTokenId",
-        "outputs": [
-            {
-                "internalType": "uint256",
-                "name": "",
-                "type": "uint256"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "ownerOf",
-        "outputs": [
-            {
-                "internalType": "address",
-                "name": "",
-                "type": "address"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "from",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "safeTransferFrom",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "from",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            },
-            {
-                "internalType": "bytes",
-                "name": "data",
-                "type": "bytes"
-            }
-        ],
-        "name": "safeTransferFromWithData",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "operator",
-                "type": "address"
-            },
-            {
-                "internalType": "bool",
-                "name": "approved",
-                "type": "bool"
-            }
-        ],
-        "name": "setApprovalForAll",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            },
-            {
-                "internalType": "bytes",
-                "name": "data",
-                "type": "bytes"
-            }
-        ],
-        "name": "setVariableMetadata",
-        "outputs": [],
-        "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": [
-            {
-                "internalType": "uint256",
-                "name": "index",
-                "type": "uint256"
-            }
-        ],
-        "name": "tokenByIndex",
-        "outputs": [
-            {
-                "internalType": "uint256",
-                "name": "",
-                "type": "uint256"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "owner",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "index",
-                "type": "uint256"
-            }
-        ],
-        "name": "tokenOfOwnerByIndex",
-        "outputs": [
-            {
-                "internalType": "uint256",
-                "name": "",
-                "type": "uint256"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "tokenURI",
-        "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": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "transfer",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "from",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "internalType": "uint256",
-                "name": "tokenId",
-                "type": "uint256"
-            }
-        ],
-        "name": "transferFrom",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    }
-]
+	{
+		"anonymous": false,
+		"inputs": [
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "owner",
+				"type": "address"
+			},
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "approved",
+				"type": "address"
+			},
+			{
+				"indexed": true,
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "Approval",
+		"type": "event"
+	},
+	{
+		"anonymous": false,
+		"inputs": [
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "owner",
+				"type": "address"
+			},
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "operator",
+				"type": "address"
+			},
+			{
+				"indexed": false,
+				"internalType": "bool",
+				"name": "approved",
+				"type": "bool"
+			}
+		],
+		"name": "ApprovalForAll",
+		"type": "event"
+	},
+	{
+		"anonymous": false,
+		"inputs": [],
+		"name": "MintingFinished",
+		"type": "event"
+	},
+	{
+		"anonymous": false,
+		"inputs": [
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "from",
+				"type": "address"
+			},
+			{
+				"indexed": true,
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"indexed": true,
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "Transfer",
+		"type": "event"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "approved",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "approve",
+		"outputs": [],
+		"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": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "burn",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "from",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "burnFrom",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			}
+		],
+		"name": "collectionProperty",
+		"outputs": [
+			{
+				"internalType": "bytes",
+				"name": "",
+				"type": "bytes"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			}
+		],
+		"name": "deleteCollectionProperty",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			},
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			}
+		],
+		"name": "deleteProperty",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [],
+		"name": "finishMinting",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "getApproved",
+		"outputs": [
+			{
+				"internalType": "address",
+				"name": "",
+				"type": "address"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "owner",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "operator",
+				"type": "address"
+			}
+		],
+		"name": "isApprovedForAll",
+		"outputs": [
+			{
+				"internalType": "address",
+				"name": "",
+				"type": "address"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "mint",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256[]",
+				"name": "tokenIds",
+				"type": "uint256[]"
+			}
+		],
+		"name": "mintBulk",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"components": [
+					{
+						"internalType": "uint256",
+						"name": "field_0",
+						"type": "uint256"
+					},
+					{
+						"internalType": "string",
+						"name": "field_1",
+						"type": "string"
+					}
+				],
+				"internalType": "struct Tuple0[]",
+				"name": "tokens",
+				"type": "tuple[]"
+			}
+		],
+		"name": "mintBulkWithTokenURI",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			},
+			{
+				"internalType": "string",
+				"name": "tokenUri",
+				"type": "string"
+			}
+		],
+		"name": "mintWithTokenURI",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [],
+		"name": "mintingFinished",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [],
+		"name": "name",
+		"outputs": [
+			{
+				"internalType": "string",
+				"name": "",
+				"type": "string"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [],
+		"name": "nextTokenId",
+		"outputs": [
+			{
+				"internalType": "uint256",
+				"name": "",
+				"type": "uint256"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "ownerOf",
+		"outputs": [
+			{
+				"internalType": "address",
+				"name": "",
+				"type": "address"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			},
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			}
+		],
+		"name": "property",
+		"outputs": [
+			{
+				"internalType": "bytes",
+				"name": "",
+				"type": "bytes"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "from",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "safeTransferFrom",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "from",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			},
+			{
+				"internalType": "bytes",
+				"name": "data",
+				"type": "bytes"
+			}
+		],
+		"name": "safeTransferFromWithData",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "operator",
+				"type": "address"
+			},
+			{
+				"internalType": "bool",
+				"name": "approved",
+				"type": "bool"
+			}
+		],
+		"name": "setApprovalForAll",
+		"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": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			},
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			},
+			{
+				"internalType": "bytes",
+				"name": "value",
+				"type": "bytes"
+			}
+		],
+		"name": "setProperty",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "string",
+				"name": "key",
+				"type": "string"
+			},
+			{
+				"internalType": "bool",
+				"name": "isMutable",
+				"type": "bool"
+			},
+			{
+				"internalType": "bool",
+				"name": "collectionAdmin",
+				"type": "bool"
+			},
+			{
+				"internalType": "bool",
+				"name": "tokenOwner",
+				"type": "bool"
+			}
+		],
+		"name": "setTokenPropertyPermission",
+		"outputs": [],
+		"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": [
+			{
+				"internalType": "uint256",
+				"name": "index",
+				"type": "uint256"
+			}
+		],
+		"name": "tokenByIndex",
+		"outputs": [
+			{
+				"internalType": "uint256",
+				"name": "",
+				"type": "uint256"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "owner",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "index",
+				"type": "uint256"
+			}
+		],
+		"name": "tokenOfOwnerByIndex",
+		"outputs": [
+			{
+				"internalType": "uint256",
+				"name": "",
+				"type": "uint256"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "tokenURI",
+		"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": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "transfer",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "from",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "to",
+				"type": "address"
+			},
+			{
+				"internalType": "uint256",
+				"name": "tokenId",
+				"type": "uint256"
+			}
+		],
+		"name": "transferFrom",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	}
+]
\ No newline at end of file
modifiedtests/src/eth/proxy/UniqueNFTProxy.abidiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.abi
+++ b/tests/src/eth/proxy/UniqueNFTProxy.abi
@@ -1 +1 @@
-[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getVariableMetadata","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBulk","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"field_0","type":"uint256"},{"internalType":"string","name":"field_1","type":"string"}],"internalType":"struct Tuple0[]","name":"tokens","type":"tuple[]"}],"name":"mintBulkWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setVariableMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"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":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","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":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
+[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"}],"name":"deleteProperty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBulk","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"field_0","type":"uint256"},{"internalType":"string","name":"field_1","type":"string"}],"internalType":"struct Tuple0[]","name":"tokens","type":"tuple[]"}],"name":"mintBulkWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setProperty","outputs":[],"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":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","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":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
modifiedtests/src/eth/proxy/UniqueNFTProxy.bindiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.bin
+++ b/tests/src/eth/proxy/UniqueNFTProxy.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b5060405161168d38038061168d83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b6115fa806100936000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806350bb4e7f116100f9578063a22cb46511610097578063d4eac26d11610071578063d4eac26d1461036b578063e6c5ce6f1461037e578063e985e9c514610391578063f4f4b500146103a457600080fd5b8063a22cb46514610332578063a9059cbb14610345578063c87b56dd1461035857600080fd5b806370a08231116100d357806370a082311461030757806375794a3c1461031a5780637d64bcb41461032257806395d89b411461032a57600080fd5b806350bb4e7f146102ce57806360a11672146102e15780636352211e146102f457600080fd5b80632f745c591161016657806342842e0e1161014057806342842e0e1461028257806342966c681461029557806344a9945e146102a85780634f6ccce7146102bb57600080fd5b80632f745c5914610249578063365430061461025c57806340c10f191461026f57600080fd5b806305d2035b146101ae57806306fdde03146101cb578063081812fc146101e0578063095ea7b31461020b57806318160ddd1461022057806323b872dd14610236575b600080fd5b6101b66103b7565b60405190151581526020015b60405180910390f35b6101d3610443565b6040516101c2919061148a565b6101f36101ee366004611277565b6104c3565b6040516001600160a01b0390911681526020016101c2565b61021e61021936600461118c565b610547565b005b6102286105b2565b6040519081526020016101c2565b61021e610244366004610eff565b610639565b61022861025736600461118c565b6106ad565b6101b661026a366004610fac565b610739565b6101b661027d36600461118c565b6107be565b61021e610290366004610eff565b6107f8565b61021e6102a3366004611277565b610839565b6101b66102b63660046110b1565b61089a565b6102286102c9366004611277565b6108cd565b6101b66102dc3660046111b8565b61094b565b61021e6102ef366004610f40565b6109da565b6101f3610302366004611277565b610a49565b610228610315366004610e8c565b610a7b565b610228610aae565b6101b6610afd565b6101d3610b62565b61021e61034036600461115e565b610ba6565b61021e61035336600461118c565b610be0565b6101d3610366366004611277565b610c19565b61021e6103793660046112a9565b610c9b565b6101d361038c366004611277565b610ccd565b6101f361039f366004610ec6565b610cff565b6101b66103b23660046112f0565b610d85565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561040657600080fd5b505afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611211565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b15801561048757600080fd5b505afa15801561049b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261043e919081019061122e565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b60206040518083038186803b15801561050957600080fd5b505afa15801561051d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190610ea9565b92915050565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b505afa158015610615573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611290565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b15801561069057600080fd5b505af11580156106a4573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c599060440160206040518083038186803b1580156106fa57600080fd5b505afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611290565b9392505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061076c908690869060040161137f565b602060405180830381600087803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611211565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161076c565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e90606401610676565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561087f57600080fd5b505af1158015610893573d6000803e3d6000fd5b5050505050565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061076c9086908690600401611404565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b60206040518083038186803b15801561091357600080fd5b505afa158015610927573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611290565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109809087908790879060040161145a565b602060405180830381600087803b15801561099a57600080fd5b505af11580156109ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d29190611211565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a10908790879087908790600401611342565b600060405180830381600087803b158015610a2a57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b505050505b50505050565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e906024016104f1565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a08231906024016108fb565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610b4e57600080fd5b505af115801561041a573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b15801561048757600080fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb4659060440161057c565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb9060440161057c565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd906024015b60006040518083038186803b158015610c5f57600080fd5b505afa158015610c73573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610541919081019061122e565b60005460405163d4eac26d60e01b81526001600160a01b039091169063d4eac26d9061057c908590859060040161149d565b60005460405163e6c5ce6f60e01b8152600481018390526060916001600160a01b03169063e6c5ce6f90602401610c47565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c59060440160206040518083038186803b158015610d4d57600080fd5b505afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190610ea9565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b158015610dce57600080fd5b505afa158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611211565b6000610e19610e1484611534565b6114df565b9050828152838383011115610e2d57600080fd5b61073283602083018461155c565b600082601f830112610e4c57600080fd5b8135610e5a610e1482611534565b818152846020838601011115610e6f57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610e9e57600080fd5b81356107328161159e565b600060208284031215610ebb57600080fd5b81516107328161159e565b60008060408385031215610ed957600080fd5b8235610ee48161159e565b91506020830135610ef48161159e565b809150509250929050565b600080600060608486031215610f1457600080fd5b8335610f1f8161159e565b92506020840135610f2f8161159e565b929592945050506040919091013590565b60008060008060808587031215610f5657600080fd5b8435610f618161159e565b93506020850135610f718161159e565b925060408501359150606085013567ffffffffffffffff811115610f9457600080fd5b610fa087828801610e3b565b91505092959194509250565b60008060408385031215610fbf57600080fd5b8235610fca8161159e565b915060208381013567ffffffffffffffff80821115610fe857600080fd5b818601915086601f830112610ffc57600080fd5b813561100a610e1482611510565b8082825285820191508585018a878560051b880101111561102a57600080fd5b60005b848110156110a05781358681111561104457600080fd5b87016040818e03601f1901121561105a57600080fd5b6110626114b6565b89820135815260408201358881111561107a57600080fd5b6110888f8c83860101610e3b565b828c015250855250928701929087019060010161102d565b50979a909950975050505050505050565b600080604083850312156110c457600080fd5b82356110cf8161159e565b915060208381013567ffffffffffffffff8111156110ec57600080fd5b8401601f810186136110fd57600080fd5b803561110b610e1482611510565b80828252848201915084840189868560051b870101111561112b57600080fd5b600094505b8385101561114e578035835260019490940193918501918501611130565b5080955050505050509250929050565b6000806040838503121561117157600080fd5b823561117c8161159e565b91506020830135610ef4816115b6565b6000806040838503121561119f57600080fd5b82356111aa8161159e565b946020939093013593505050565b6000806000606084860312156111cd57600080fd5b83356111d88161159e565b925060208401359150604084013567ffffffffffffffff8111156111fb57600080fd5b61120786828701610e3b565b9150509250925092565b60006020828403121561122357600080fd5b8151610732816115b6565b60006020828403121561124057600080fd5b815167ffffffffffffffff81111561125757600080fd5b8201601f8101841361126857600080fd5b6109d284825160208401610e06565b60006020828403121561128957600080fd5b5035919050565b6000602082840312156112a257600080fd5b5051919050565b600080604083850312156112bc57600080fd5b82359150602083013567ffffffffffffffff8111156112da57600080fd5b6112e685828601610e3b565b9150509250929050565b60006020828403121561130257600080fd5b813563ffffffff8116811461073257600080fd5b6000815180845261132e81602086016020860161155c565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061137590830184611316565b9695505050505050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b828110156113f557888603605f190184528151805187528501518587018890526113e288880182611316565b96505092840192908401906001016113b6565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561144d57845183529383019391830191600101611431565b5090979650505050505050565b60018060a01b03841681528260208201526060604082015260006114816060830184611316565b95945050505050565b6020815260006107326020830184611316565b8281526040602082015260006109d26040830184611316565b6040805190810167ffffffffffffffff811182821017156114d9576114d9611588565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561150857611508611588565b604052919050565b600067ffffffffffffffff82111561152a5761152a611588565b5060051b60200190565b600067ffffffffffffffff82111561154e5761154e611588565b50601f01601f191660200190565b60005b8381101561157757818101518382015260200161155f565b83811115610a435750506000910152565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146115b357600080fd5b50565b80151581146115b357600080fdfea2646970667358221220669a75a3efcdc6b60606caa5c7e41cab1d727e89a03fd231d1cda27f4de159a064736f6c63430008070033
\ No newline at end of file
+608060405234801561001057600080fd5b506040516116bb3803806116bb83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b611628806100936000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80634f6ccce7116100f957806379cc679011610097578063a22cb46511610071578063a22cb46514610399578063a9059cbb146103ac578063c87b56dd146103bf578063e985e9c5146103d257600080fd5b806379cc6790146103765780637d64bcb41461038957806395d89b411461039157600080fd5b806362d9491f116100d357806362d9491f146103355780636352211e1461034857806370a082311461035b57806375794a3c1461036e57600080fd5b80634f6ccce7146102fc57806350bb4e7f1461030f57806360a116721461032257600080fd5b80632f745c591161016657806340c10f191161014057806340c10f19146102b057806342842e0e146102c357806342966c68146102d657806344a9945e146102e957600080fd5b80632f745c5914610277578063342419141461028a578063365430061461029d57600080fd5b8063081812fc116101a2578063081812fc1461020e578063095ea7b31461023957806318160ddd1461024e57806323b872dd1461026457600080fd5b806301ffc9a7146101c957806305d2035b146101f157806306fdde03146101f9575b600080fd5b6101dc6101d7366004610dca565b6103e5565b60405190151581526020015b60405180910390f35b6101dc610462565b6102016104df565b6040516101e89190610e4c565b61022161021c366004610e5f565b610550565b6040516001600160a01b0390911681526020016101e8565b61024c610247366004610e90565b6105bf565b005b61025661062a565b6040519081526020016101e8565b61024c610272366004610ebc565b6106a2565b610256610285366004610e90565b610716565b61024c610298366004610ff3565b610793565b6101dc6102ab36600461104c565b6107f8565b6101dc6102be366004610e90565b61086e565b61024c6102d1366004610ebc565b6108a8565b61024c6102e4366004610e5f565b6108e9565b6101dc6102f736600461114f565b61091a565b61025661030a366004610e5f565b61094d565b6101dc61031d3660046111f5565b6109bc565b61024c61033036600461124e565b610a3c565b61024c6103433660046112ce565b610aab565b610221610356366004610e5f565b610add565b610256610369366004611332565b610b0f565b610256610b42565b61024c610384366004610e90565b610b96565b6101dc610bcf565b610201610c25565b61024c6103a736600461135d565b610c6e565b61024c6103ba366004610e90565b610ca8565b6102016103cd366004610e5f565b610ce1565b6102216103e0366004611396565b610d53565b600080546040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b03909116906301ffc9a790602401602060405180830381865afa158015610438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c91906113c4565b92915050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da91906113c4565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde0392600480820193918290030181865afa158015610528573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104da91908101906113e1565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611458565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561060e57600080fd5b505af1158015610622573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da9190611475565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b1580156106f957600080fd5b505af115801561070d573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c5990604401602060405180830381865afa158015610768573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611475565b9392505050565b600054604051630d09064560e21b81526001600160a01b03909116906334241914906107c3908490600401610e4c565b600060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b5050505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061082b908690869060040161148e565b6020604051808303816000875af115801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c91906113c4565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161082b565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e906064016106df565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c68906024016107c3565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061082b9086908690600401611513565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045c9190611475565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109f190879087908790600401611569565b6020604051808303816000875af1158015610a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3491906113c4565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a72908790879087908790600401611590565b600060405180830381600087803b158015610a8c57600080fd5b505af1158015610aa0573d6000803e3d6000fd5b505050505b50505050565b6000546040516362d9491f60e01b81526001600160a01b03909116906362d9491f906105f490859085906004016115cd565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e9060240161057e565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a082319060240161097b565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b60005460405163079cc67960e41b81526001600160a01b03848116600483015260248201849052909116906379cc6790906044016105f4565b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b81526004016020604051808303816000875af11580156104b6573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b4192600480820193918290030181865afa158015610528573d6000803e3d6000fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb465906044016105f4565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016105f4565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610d2b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261045c91908101906113e1565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c590604401602060405180830381865afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078c9190611458565b600060208284031215610ddc57600080fd5b81356001600160e01b03198116811461078c57600080fd5b60005b83811015610e0f578181015183820152602001610df7565b83811115610aa55750506000910152565b60008151808452610e38816020860160208601610df4565b601f01601f19169290920160200192915050565b60208152600061078c6020830184610e20565b600060208284031215610e7157600080fd5b5035919050565b6001600160a01b0381168114610e8d57600080fd5b50565b60008060408385031215610ea357600080fd5b8235610eae81610e78565b946020939093013593505050565b600080600060608486031215610ed157600080fd5b8335610edc81610e78565b92506020840135610eec81610e78565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f3657610f36610efd565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610f6557610f65610efd565b604052919050565b600067ffffffffffffffff821115610f8757610f87610efd565b50601f01601f191660200190565b6000610fa8610fa384610f6d565b610f3c565b9050828152838383011115610fbc57600080fd5b828260208301376000602084830101529392505050565b600082601f830112610fe457600080fd5b61078c83833560208501610f95565b60006020828403121561100557600080fd5b813567ffffffffffffffff81111561101c57600080fd5b610a3484828501610fd3565b600067ffffffffffffffff82111561104257611042610efd565b5060051b60200190565b600080604080848603121561106057600080fd5b833561106b81610e78565b925060208481013567ffffffffffffffff8082111561108957600080fd5b818701915087601f83011261109d57600080fd5b81356110ab610fa382611028565b81815260059190911b8301840190848101908a8311156110ca57600080fd5b8585015b8381101561113d578035858111156110e65760008081fd5b8601808d03601f19018913156110fc5760008081fd5b611104610f13565b888201358152898201358781111561111c5760008081fd5b61112a8f8b83860101610fd3565b828b0152508452509186019186016110ce565b50809750505050505050509250929050565b6000806040838503121561116257600080fd5b823561116d81610e78565b915060208381013567ffffffffffffffff81111561118a57600080fd5b8401601f8101861361119b57600080fd5b80356111a9610fa382611028565b81815260059190911b820183019083810190888311156111c857600080fd5b928401925b828410156111e6578335825292840192908401906111cd565b80955050505050509250929050565b60008060006060848603121561120a57600080fd5b833561121581610e78565b925060208401359150604084013567ffffffffffffffff81111561123857600080fd5b61124486828701610fd3565b9150509250925092565b6000806000806080858703121561126457600080fd5b843561126f81610e78565b9350602085013561127f81610e78565b925060408501359150606085013567ffffffffffffffff8111156112a257600080fd5b8501601f810187136112b357600080fd5b6112c287823560208401610f95565b91505092959194509250565b600080604083850312156112e157600080fd5b823567ffffffffffffffff808211156112f957600080fd5b61130586838701610fd3565b9350602085013591508082111561131b57600080fd5b5061132885828601610fd3565b9150509250929050565b60006020828403121561134457600080fd5b813561078c81610e78565b8015158114610e8d57600080fd5b6000806040838503121561137057600080fd5b823561137b81610e78565b9150602083013561138b8161134f565b809150509250929050565b600080604083850312156113a957600080fd5b82356113b481610e78565b9150602083013561138b81610e78565b6000602082840312156113d657600080fd5b815161078c8161134f565b6000602082840312156113f357600080fd5b815167ffffffffffffffff81111561140a57600080fd5b8201601f8101841361141b57600080fd5b8051611429610fa382610f6d565b81815285602083850101111561143e57600080fd5b61144f826020830160208601610df4565b95945050505050565b60006020828403121561146a57600080fd5b815161078c81610e78565b60006020828403121561148757600080fd5b5051919050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b8281101561150457888603605f190184528151805187528501518587018890526114f188880182610e20565b96505092840192908401906001016114c5565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561155c57845183529383019391830191600101611540565b5090979650505050505050565b60018060a01b038416815282602082015260606040820152600061144f6060830184610e20565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906115c390830184610e20565b9695505050505050565b6040815260006115e06040830185610e20565b828103602084015261144f8185610e2056fea26469706673582212205bdf4275f4b714a1029ccfe77c0f9a0e20e121a932e1e5840cace97dfa886da964736f6c634300080d0033
\ No newline at end of file
modifiedtests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.sol
+++ b/tests/src/eth/proxy/UniqueNFTProxy.sol
@@ -148,29 +148,17 @@
         return proxied.nextTokenId();
     }
 
-    function supportsInterface(uint32 interfaceId)
+    function burnFrom(address from, uint256 tokenId) external override {
+        return proxied.burnFrom(from, tokenId);
+    }
+
+    function supportsInterface(bytes4 interfaceId)
         external
         view
         override
         returns (bool)
     {
         return proxied.supportsInterface(interfaceId);
-    }
-
-    function setVariableMetadata(uint256 tokenId, bytes memory data)
-        external
-        override
-    {
-        return proxied.setVariableMetadata(tokenId, data);
-    }
-
-    function getVariableMetadata(uint256 tokenId)
-        external
-        view
-        override
-        returns (bytes memory)
-    {
-        return proxied.getVariableMetadata(tokenId);
     }
 
     function mintBulk(address to, uint256[] memory tokenIds)
@@ -188,4 +176,12 @@
     {
         return proxied.mintBulkWithTokenURI(to, tokens);
     }
+
+    function setProperty(string memory key, string memory value) external override {
+        return proxied.setProperty(key, value);
+    }
+
+	function deleteProperty(string memory key) external override {
+        return proxied.deleteProperty(key);
+    }
 }
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import privateKey from '../../substrate/privateKey';
-import {createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess, setMetadataUpdatePermissionFlagExpectSuccess} from '../../util/helpers';
+import {createCollectionExpectSuccess, createItemExpectSuccess} from '../../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents} from '../util/helpers';
 import nonFungibleAbi from '../nonFungibleAbi.json';
 import {expect} from 'chai';
@@ -333,36 +333,5 @@
       const balance = await contract.methods.balanceOf(receiver).call();
       expect(+balance).to.equal(1);
     }
-  });
-
-  itWeb3('Can perform getVariableMetadata', async ({web3, api}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKey('//Alice');
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const address = collectionIdToAddress(collection);
-    const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));
-    const item = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});
-    await setMetadataUpdatePermissionFlagExpectSuccess(alice, collection, 'Admin');
-    await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);
-
-    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
-  });
-
-  itWeb3('Can perform setVariableMetadata', async ({web3, api}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKey('//Alice');
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const address = collectionIdToAddress(collection);
-    const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));
-    const item = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});
-
-    expect(await contract.methods.setVariableMetadata(item, '0x010203').send({from: caller}));
-    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
   });
 });
addedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/tokenProperties.test.ts
@@ -0,0 +1,95 @@
+import privateKey from '../substrate/privateKey';
+import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess} from '../util/helpers';
+import {cartesian, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3} from './util/helpers';
+import nonFungibleAbi from './nonFungibleAbi.json';
+import {expect} from 'chai';
+import {executeTransaction} from '../substrate/substrate-api';
+
+describe('EVM token properties', () => {
+  itWeb3('Can be reconfigured', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+    for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {
+      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+      await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});
+      
+      const address = collectionIdToAddress(collection);
+      const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+  
+      await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller});
+  
+      const state = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();
+      expect(state).to.be.deep.equal({
+        [web3.utils.toHex('testKey')]: {mutable, collectionAdmin, tokenOwner},
+      });
+    }
+  });
+  itWeb3('Can be set', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const token = await createItemExpectSuccess(alice, collection, 'NFT');
+
+    await executeTransaction(api, alice, api.tx.unique.setPropertyPermissions(collection, [{
+      key: 'testKey',
+      permission: {
+        collectionAdmin: true,
+      },
+    }]));
+
+    await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    await contract.methods.setProperty(token, 'testKey', Buffer.from('testValue')).send({from: caller});
+
+    const [{value}] = (await api.rpc.unique.tokenProperties(collection, token, ['testKey'])).toHuman()! as any;
+    expect(value).to.equal('testValue');
+  });
+  itWeb3('Can be deleted', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+    const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    const token = await createItemExpectSuccess(alice, collection, 'NFT');
+
+    await executeTransaction(api, alice, api.tx.unique.setPropertyPermissions(collection, [{
+      key: 'testKey',
+      permission: {
+        mutable: true,
+        collectionAdmin: true,
+      },
+    }]));
+    await executeTransaction(api, alice, api.tx.unique.setTokenProperties(collection, token, [{key: 'testKey', value: 'testValue'}]));
+
+    await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    await contract.methods.deleteProperty(token, 'testKey').send({from: caller});
+
+    const result = (await api.rpc.unique.tokenProperties(collection, token, ['testKey'])).toJSON()! as any;
+    expect(result.length).to.equal(0);
+  });
+  itWeb3('Can be read', async({web3, api}) => {
+    const alice = privateKey('//Alice');
+    const caller = createEthAccount(web3);
+    const collection = await createCollectionExpectSuccess({mode: {type:'NFT'}});
+    const token = await createItemExpectSuccess(alice, collection, 'NFT');
+
+    await executeTransaction(api, alice, api.tx.unique.setPropertyPermissions(collection, [{
+      key: 'testKey',
+      permission: {
+        collectionAdmin: true,
+      },
+    }]));
+    await executeTransaction(api, alice, api.tx.unique.setTokenProperties(collection, token, [{key: 'testKey', value: 'testValue'}]));
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    const value = await contract.methods.property(token, 'testKey').call();
+    expect(value).to.equal(web3.utils.toHex('testValue'));
+  });
+});
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -322,3 +322,15 @@
 
   return before - after;
 }
+
+type ElementOf<A> = A extends readonly (infer T)[] ? T : never;
+// I want a fancier api, not a memory efficiency
+export function* cartesian<T extends Array<Array<any>>, R extends Array<any>>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf<T[K]>}]> {
+  if(args.length === 0) {
+    yield internalRest as any;
+    return;
+  }
+  for(const value of args[0]) {
+    yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
+  }
+}
\ No newline at end of file
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -137,6 +137,10 @@
        **/
       OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;
       /**
+       * Property key is too long
+       **/
+      PropertyKeyIsTooLong: AugmentedError<ApiType>;
+      /**
        * Tried to store more property keys than allowed
        **/
       PropertyLimitReached: AugmentedError<ApiType>;
@@ -156,10 +160,6 @@
        * Item balance not enough.
        **/
       TokenValueTooLow: AugmentedError<ApiType>;
-      /**
-       * variable_data exceeded data limit.
-       **/
-      TokenVariableDataLimitExceeded: AugmentedError<ApiType>;
       /**
        * Total collections bound exceeded.
        **/
@@ -168,10 +168,6 @@
        * Collection settings not allowing items transferring
        **/
       TransferNotAllowed: AugmentedError<ApiType>;
-      /**
-       * Unable to read array of unbounded keys
-       **/
-      UnableToReadUnboundedKeys: AugmentedError<ApiType>;
       /**
        * Target collection doesn't supports this operation
        **/
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -1,7 +1,7 @@
 // Auto-generated via `yarn polkadot-types-from-chain`, do not edit
 /* eslint-disable */
 
-import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenData } from './unique';
+import type { PalletEvmAccountBasicCrossAccountIdRepr, RmrkTypesBaseInfo, RmrkTypesCollectionInfo, RmrkTypesNftChild, RmrkTypesNftInfo, RmrkTypesPartType, RmrkTypesPropertyInfo, RmrkTypesResourceInfo, RmrkTypesTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenData } from './unique';
 import type { AugmentedRpc } from '@polkadot/rpc-core/types';
 import type { Metadata, StorageKey } from '@polkadot/types';
 import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, u128, u32, u64 } from '@polkadot/types-codec';
@@ -401,19 +401,19 @@
       /**
        * Get base info
        **/
-      base: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTraitsBaseBaseInfo>>>;
+      base: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTypesBaseInfo>>>;
       /**
        * Get all Base's parts
        **/
-      baseParts: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTraitsPartPartType>>>;
+      baseParts: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTypesPartType>>>;
       /**
        * Get collection by id
        **/
-      collectionById: AugmentedRpc<(id: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTraitsCollectionCollectionInfo>>>;
+      collectionById: AugmentedRpc<(id: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTypesCollectionInfo>>>;
       /**
        * Get collection properties
        **/
-      collectionProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTraitsPropertyPropertyInfo>>>;
+      collectionProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTypesPropertyInfo>>>;
       /**
        * Get the latest created collection id
        **/
@@ -421,15 +421,15 @@
       /**
        * Get NFT by collection id and NFT id
        **/
-      nftById: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTraitsNftNftInfo>>>;
+      nftById: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTypesNftInfo>>>;
       /**
        * Get NFT children
        **/
-      nftChildren: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTraitsNftNftChild>>>;
+      nftChildren: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTypesNftChild>>>;
       /**
        * Get NFT properties
        **/
-      nftProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTraitsPropertyPropertyInfo>>>;
+      nftProperties: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTypesPropertyInfo>>>;
       /**
        * Get NFT resource priorities
        **/
@@ -437,7 +437,7 @@
       /**
        * Get NFT resources
        **/
-      nftResources: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTraitsResourceResourceInfo>>>;
+      nftResources: AugmentedRpc<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<RmrkTypesResourceInfo>>>;
       /**
        * Get Base's theme names
        **/
@@ -445,7 +445,7 @@
       /**
        * Get Theme's keys values
        **/
-      themes: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, themeName: Text | string, keys: Option<Vec<Text>> | null | object | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTraitsTheme>>>;
+      themes: AugmentedRpc<(baseId: u32 | AnyNumber | Uint8Array, themeName: Text | string, keys: Option<Vec<Text>> | null | object | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<RmrkTypesTheme>>>;
     };
     rpc: {
       /**
@@ -659,7 +659,7 @@
       /**
        * Get collection properties
        **/
-      collectionProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
+      collectionProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
       /**
        * Get collection stats
        **/
@@ -687,11 +687,11 @@
       /**
        * Get property permissions
        **/
-      propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
+      propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
       /**
        * Get token data
        **/
-      tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
+      tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
       /**
        * Check if token exists
        **/
@@ -703,7 +703,7 @@
       /**
        * Get token properties
        **/
-      tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
+      tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
       /**
        * Get token owner, in case of nested token - find parent recursive
        **/
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -5,7 +5,7 @@
 import type { Bytes, Compact, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';
 import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types';
 import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsAccessMode, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsMetaUpdatePermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsSchemaVersion, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsAccessMode, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsSchemaVersion, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 declare module '@polkadot/api-base/types/submittable' {
   export interface AugmentedSubmittables<ApiType extends ApiTypes> {
@@ -679,7 +679,7 @@
        * 
        * Prefer it to deprecated [`created_collection`] method
        **/
-      createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; offchainSchema?: any; schemaVersion?: any; pendingSponsor?: any; limits?: any; constOnChainSchema?: any; metaUpdatePermission?: any; tokenPropertyPermissions?: any; properties?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
+      createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; offchainSchema?: any; schemaVersion?: any; pendingSponsor?: any; limits?: any; constOnChainSchema?: any; tokenPropertyPermissions?: any; properties?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
       /**
        * This method creates a concrete instance of NFT Collection created with CreateCollection method.
        * 
@@ -809,20 +809,6 @@
        **/
       setConstOnChainSchema: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, schema: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Bytes]>;
       /**
-       * Set meta_update_permission value for particular collection
-       * 
-       * # Permissions
-       * 
-       * * Collection Owner.
-       * 
-       * # Arguments
-       * 
-       * * collection_id: ID of the collection.
-       * 
-       * * value: New flag value.
-       **/
-      setMetaUpdatePermissionFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: UpDataStructsMetaUpdatePermission | 'ItemOwner' | 'Admin' | 'None' | number | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsMetaUpdatePermission]>;
-      /**
        * Allows Anyone to create tokens if:
        * * Allow List is enabled, and
        * * Address is added to allow list, and
@@ -900,21 +886,6 @@
        * * value: New flag value.
        **/
       setTransfersEnabledFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
-      /**
-       * Set off-chain data schema.
-       * 
-       * # Permissions
-       * 
-       * * Collection Owner
-       * * Collection Admin
-       * 
-       * # Arguments
-       * 
-       * * collection_id.
-       * 
-       * * schema: String representing the offchain data schema.
-       **/
-      setVariableMetaData: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, data: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, Bytes]>;
       /**
        * Change ownership of the token.
        * 
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -1,7 +1,7 @@
 // Auto-generated via `yarn polkadot-types-from-defs`, do not edit
 /* eslint-disable */
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportStorageBoundedBTreeSet, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTypesAccountIdOrCollectionNftTuple, RmrkTypesBaseInfo, RmrkTypesCollectionInfo, RmrkTypesEquippableList, RmrkTypesFixedPart, RmrkTypesNftChild, RmrkTypesNftInfo, RmrkTypesPartType, RmrkTypesPropertyInfo, RmrkTypesResourceInfo, RmrkTypesRoyaltyInfo, RmrkTypesSlotPart, RmrkTypesTheme, RmrkTypesThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsMetaUpdatePermission, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTypesAccountIdOrCollectionNftTuple, RmrkTypesBaseInfo, RmrkTypesCollectionInfo, RmrkTypesEquippableList, RmrkTypesFixedPart, RmrkTypesNftChild, RmrkTypesNftInfo, RmrkTypesPartType, RmrkTypesPropertyInfo, RmrkTypesResourceInfo, RmrkTypesRoyaltyInfo, RmrkTypesSlotPart, RmrkTypesTheme, RmrkTypesThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique';
 import type { Data, StorageKey } from '@polkadot/types';
 import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec';
 import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
@@ -478,7 +478,6 @@
     ForkTreePendingChangeNode: ForkTreePendingChangeNode;
     FpRpcTransactionStatus: FpRpcTransactionStatus;
     FrameSupportPalletId: FrameSupportPalletId;
-    FrameSupportStorageBoundedBTreeSet: FrameSupportStorageBoundedBTreeSet;
     FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
     FrameSupportWeightsDispatchClass: FrameSupportWeightsDispatchClass;
     FrameSupportWeightsDispatchInfo: FrameSupportWeightsDispatchInfo;
@@ -1204,7 +1203,6 @@
     UpDataStructsCreateNftExData: UpDataStructsCreateNftExData;
     UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData;
     UpDataStructsCreateRefungibleExData: UpDataStructsCreateRefungibleExData;
-    UpDataStructsMetaUpdatePermission: UpDataStructsMetaUpdatePermission;
     UpDataStructsNestingRule: UpDataStructsNestingRule;
     UpDataStructsProperties: UpDataStructsProperties;
     UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec;
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1360,15 +1360,6 @@
         itemId: 'u32',
         value: 'u128',
       },
-      set_variable_meta_data: {
-        collectionId: 'u32',
-        itemId: 'u32',
-        data: 'Bytes',
-      },
-      set_meta_update_permission_flag: {
-        collectionId: 'u32',
-        value: 'UpDataStructsMetaUpdatePermission',
-      },
       set_schema_version: {
         collectionId: 'u32',
         version: 'UpDataStructsSchemaVersion',
@@ -1411,7 +1402,6 @@
     pendingSponsor: 'Option<AccountId32>',
     limits: 'Option<UpDataStructsCollectionLimits>',
     constOnChainSchema: 'Bytes',
-    metaUpdatePermission: 'Option<UpDataStructsMetaUpdatePermission>',
     tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
     properties: 'Vec<UpDataStructsProperty>'
   },
@@ -1462,20 +1452,14 @@
     }
   },
   /**
-   * Lookup177: up_data_structs::MetaUpdatePermission
+   * Lookup177: up_data_structs::PropertyKeyPermission
    **/
-  UpDataStructsMetaUpdatePermission: {
-    _enum: ['ItemOwner', 'Admin', 'None']
-  },
-  /**
-   * Lookup179: up_data_structs::PropertyKeyPermission
-   **/
   UpDataStructsPropertyKeyPermission: {
     key: 'Bytes',
     permission: 'UpDataStructsPropertyPermission'
   },
   /**
-   * Lookup181: up_data_structs::PropertyPermission
+   * Lookup179: up_data_structs::PropertyPermission
    **/
   UpDataStructsPropertyPermission: {
     mutable: 'bool',
@@ -1483,14 +1467,14 @@
     tokenOwner: 'bool'
   },
   /**
-   * Lookup184: up_data_structs::Property
+   * Lookup182: up_data_structs::Property
    **/
   UpDataStructsProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup186: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
+   * Lookup184: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
    **/
   PalletEvmAccountBasicCrossAccountIdRepr: {
     _enum: {
@@ -1499,7 +1483,7 @@
     }
   },
   /**
-   * Lookup188: up_data_structs::CreateItemData
+   * Lookup186: up_data_structs::CreateItemData
    **/
   UpDataStructsCreateItemData: {
     _enum: {
@@ -1509,29 +1493,27 @@
     }
   },
   /**
-   * Lookup189: up_data_structs::CreateNftData
+   * Lookup187: up_data_structs::CreateNftData
    **/
   UpDataStructsCreateNftData: {
     constData: 'Bytes',
-    variableData: 'Bytes',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup191: up_data_structs::CreateFungibleData
+   * Lookup189: up_data_structs::CreateFungibleData
    **/
   UpDataStructsCreateFungibleData: {
     value: 'u128'
   },
   /**
-   * Lookup192: up_data_structs::CreateReFungibleData
+   * Lookup190: up_data_structs::CreateReFungibleData
    **/
   UpDataStructsCreateReFungibleData: {
     constData: 'Bytes',
-    variableData: 'Bytes',
     pieces: 'u128'
   },
   /**
-   * Lookup196: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup194: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateItemExData: {
     _enum: {
@@ -1542,32 +1524,30 @@
     }
   },
   /**
-   * Lookup198: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup196: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateNftExData: {
     constData: 'Bytes',
-    variableData: 'Bytes',
     properties: 'Vec<UpDataStructsProperty>',
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup205: up_data_structs::CreateRefungibleExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup203: up_data_structs::CreateRefungibleExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateRefungibleExData: {
     constData: 'Bytes',
-    variableData: 'Bytes',
     users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>'
   },
   /**
-   * Lookup207: pallet_template_transaction_payment::Call<T>
+   * Lookup205: pallet_template_transaction_payment::Call<T>
    **/
   PalletTemplateTransactionPaymentCall: 'Null',
   /**
-   * Lookup208: pallet_structure::pallet::Call<T>
+   * Lookup206: pallet_structure::pallet::Call<T>
    **/
   PalletStructureCall: 'Null',
   /**
-   * Lookup209: pallet_evm::pallet::Call<T>
+   * Lookup207: pallet_evm::pallet::Call<T>
    **/
   PalletEvmCall: {
     _enum: {
@@ -1610,7 +1590,7 @@
     }
   },
   /**
-   * Lookup215: pallet_ethereum::pallet::Call<T>
+   * Lookup213: pallet_ethereum::pallet::Call<T>
    **/
   PalletEthereumCall: {
     _enum: {
@@ -1620,7 +1600,7 @@
     }
   },
   /**
-   * Lookup216: ethereum::transaction::TransactionV2
+   * Lookup214: ethereum::transaction::TransactionV2
    **/
   EthereumTransactionTransactionV2: {
     _enum: {
@@ -1630,7 +1610,7 @@
     }
   },
   /**
-   * Lookup217: ethereum::transaction::LegacyTransaction
+   * Lookup215: ethereum::transaction::LegacyTransaction
    **/
   EthereumTransactionLegacyTransaction: {
     nonce: 'U256',
@@ -1642,7 +1622,7 @@
     signature: 'EthereumTransactionTransactionSignature'
   },
   /**
-   * Lookup218: ethereum::transaction::TransactionAction
+   * Lookup216: ethereum::transaction::TransactionAction
    **/
   EthereumTransactionTransactionAction: {
     _enum: {
@@ -1651,7 +1631,7 @@
     }
   },
   /**
-   * Lookup219: ethereum::transaction::TransactionSignature
+   * Lookup217: ethereum::transaction::TransactionSignature
    **/
   EthereumTransactionTransactionSignature: {
     v: 'u64',
@@ -1659,7 +1639,7 @@
     s: 'H256'
   },
   /**
-   * Lookup221: ethereum::transaction::EIP2930Transaction
+   * Lookup219: ethereum::transaction::EIP2930Transaction
    **/
   EthereumTransactionEip2930Transaction: {
     chainId: 'u64',
@@ -1675,14 +1655,14 @@
     s: 'H256'
   },
   /**
-   * Lookup223: ethereum::transaction::AccessListItem
+   * Lookup221: ethereum::transaction::AccessListItem
    **/
   EthereumTransactionAccessListItem: {
     address: 'H160',
     storageKeys: 'Vec<H256>'
   },
   /**
-   * Lookup224: ethereum::transaction::EIP1559Transaction
+   * Lookup222: ethereum::transaction::EIP1559Transaction
    **/
   EthereumTransactionEip1559Transaction: {
     chainId: 'u64',
@@ -1699,7 +1679,7 @@
     s: 'H256'
   },
   /**
-   * Lookup225: pallet_evm_migration::pallet::Call<T>
+   * Lookup223: pallet_evm_migration::pallet::Call<T>
    **/
   PalletEvmMigrationCall: {
     _enum: {
@@ -1717,7 +1697,7 @@
     }
   },
   /**
-   * Lookup228: pallet_sudo::pallet::Event<T>
+   * Lookup226: pallet_sudo::pallet::Event<T>
    **/
   PalletSudoEvent: {
     _enum: {
@@ -1733,7 +1713,7 @@
     }
   },
   /**
-   * Lookup230: sp_runtime::DispatchError
+   * Lookup228: sp_runtime::DispatchError
    **/
   SpRuntimeDispatchError: {
     _enum: {
@@ -1750,38 +1730,38 @@
     }
   },
   /**
-   * Lookup231: sp_runtime::ModuleError
+   * Lookup229: sp_runtime::ModuleError
    **/
   SpRuntimeModuleError: {
     index: 'u8',
     error: '[u8;4]'
   },
   /**
-   * Lookup232: sp_runtime::TokenError
+   * Lookup230: sp_runtime::TokenError
    **/
   SpRuntimeTokenError: {
     _enum: ['NoFunds', 'WouldDie', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported']
   },
   /**
-   * Lookup233: sp_runtime::ArithmeticError
+   * Lookup231: sp_runtime::ArithmeticError
    **/
   SpRuntimeArithmeticError: {
     _enum: ['Underflow', 'Overflow', 'DivisionByZero']
   },
   /**
-   * Lookup234: sp_runtime::TransactionalError
+   * Lookup232: sp_runtime::TransactionalError
    **/
   SpRuntimeTransactionalError: {
     _enum: ['LimitReached', 'NoLayer']
   },
   /**
-   * Lookup235: pallet_sudo::pallet::Error<T>
+   * Lookup233: pallet_sudo::pallet::Error<T>
    **/
   PalletSudoError: {
     _enum: ['RequireSudo']
   },
   /**
-   * Lookup236: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>
+   * Lookup234: frame_system::AccountInfo<Index, pallet_balances::AccountData<Balance>>
    **/
   FrameSystemAccountInfo: {
     nonce: 'u32',
@@ -1791,7 +1771,7 @@
     data: 'PalletBalancesAccountData'
   },
   /**
-   * Lookup237: frame_support::weights::PerDispatchClass<T>
+   * Lookup235: frame_support::weights::PerDispatchClass<T>
    **/
   FrameSupportWeightsPerDispatchClassU64: {
     normal: 'u64',
@@ -1799,13 +1779,13 @@
     mandatory: 'u64'
   },
   /**
-   * Lookup238: sp_runtime::generic::digest::Digest
+   * Lookup236: sp_runtime::generic::digest::Digest
    **/
   SpRuntimeDigest: {
     logs: 'Vec<SpRuntimeDigestDigestItem>'
   },
   /**
-   * Lookup240: sp_runtime::generic::digest::DigestItem
+   * Lookup238: sp_runtime::generic::digest::DigestItem
    **/
   SpRuntimeDigestDigestItem: {
     _enum: {
@@ -1821,7 +1801,7 @@
     }
   },
   /**
-   * Lookup242: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>
+   * Lookup240: frame_system::EventRecord<opal_runtime::Event, primitive_types::H256>
    **/
   FrameSystemEventRecord: {
     phase: 'FrameSystemPhase',
@@ -1829,7 +1809,7 @@
     topics: 'Vec<H256>'
   },
   /**
-   * Lookup244: frame_system::pallet::Event<T>
+   * Lookup242: frame_system::pallet::Event<T>
    **/
   FrameSystemEvent: {
     _enum: {
@@ -1857,7 +1837,7 @@
     }
   },
   /**
-   * Lookup245: frame_support::weights::DispatchInfo
+   * Lookup243: frame_support::weights::DispatchInfo
    **/
   FrameSupportWeightsDispatchInfo: {
     weight: 'u64',
@@ -1865,19 +1845,19 @@
     paysFee: 'FrameSupportWeightsPays'
   },
   /**
-   * Lookup246: frame_support::weights::DispatchClass
+   * Lookup244: frame_support::weights::DispatchClass
    **/
   FrameSupportWeightsDispatchClass: {
     _enum: ['Normal', 'Operational', 'Mandatory']
   },
   /**
-   * Lookup247: frame_support::weights::Pays
+   * Lookup245: frame_support::weights::Pays
    **/
   FrameSupportWeightsPays: {
     _enum: ['Yes', 'No']
   },
   /**
-   * Lookup248: orml_vesting::module::Event<T>
+   * Lookup246: orml_vesting::module::Event<T>
    **/
   OrmlVestingModuleEvent: {
     _enum: {
@@ -1896,7 +1876,7 @@
     }
   },
   /**
-   * Lookup249: cumulus_pallet_xcmp_queue::pallet::Event<T>
+   * Lookup247: cumulus_pallet_xcmp_queue::pallet::Event<T>
    **/
   CumulusPalletXcmpQueueEvent: {
     _enum: {
@@ -1911,7 +1891,7 @@
     }
   },
   /**
-   * Lookup250: pallet_xcm::pallet::Event<T>
+   * Lookup248: pallet_xcm::pallet::Event<T>
    **/
   PalletXcmEvent: {
     _enum: {
@@ -1934,7 +1914,7 @@
     }
   },
   /**
-   * Lookup251: xcm::v2::traits::Outcome
+   * Lookup249: xcm::v2::traits::Outcome
    **/
   XcmV2TraitsOutcome: {
     _enum: {
@@ -1944,7 +1924,7 @@
     }
   },
   /**
-   * Lookup253: cumulus_pallet_xcm::pallet::Event<T>
+   * Lookup251: cumulus_pallet_xcm::pallet::Event<T>
    **/
   CumulusPalletXcmEvent: {
     _enum: {
@@ -1954,7 +1934,7 @@
     }
   },
   /**
-   * Lookup254: cumulus_pallet_dmp_queue::pallet::Event<T>
+   * Lookup252: cumulus_pallet_dmp_queue::pallet::Event<T>
    **/
   CumulusPalletDmpQueueEvent: {
     _enum: {
@@ -1967,7 +1947,7 @@
     }
   },
   /**
-   * Lookup255: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup253: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletUniqueRawEvent: {
     _enum: {
@@ -1988,7 +1968,7 @@
     }
   },
   /**
-   * Lookup256: pallet_common::pallet::Event<T>
+   * Lookup254: pallet_common::pallet::Event<T>
    **/
   PalletCommonEvent: {
     _enum: {
@@ -2006,7 +1986,7 @@
     }
   },
   /**
-   * Lookup257: pallet_structure::pallet::Event<T>
+   * Lookup255: pallet_structure::pallet::Event<T>
    **/
   PalletStructureEvent: {
     _enum: {
@@ -2014,7 +1994,7 @@
     }
   },
   /**
-   * Lookup258: pallet_evm::pallet::Event<T>
+   * Lookup256: pallet_evm::pallet::Event<T>
    **/
   PalletEvmEvent: {
     _enum: {
@@ -2028,7 +2008,7 @@
     }
   },
   /**
-   * Lookup259: ethereum::log::Log
+   * Lookup257: ethereum::log::Log
    **/
   EthereumLog: {
     address: 'H160',
@@ -2036,7 +2016,7 @@
     data: 'Bytes'
   },
   /**
-   * Lookup260: pallet_ethereum::pallet::Event
+   * Lookup258: pallet_ethereum::pallet::Event
    **/
   PalletEthereumEvent: {
     _enum: {
@@ -2044,7 +2024,7 @@
     }
   },
   /**
-   * Lookup261: evm_core::error::ExitReason
+   * Lookup259: evm_core::error::ExitReason
    **/
   EvmCoreErrorExitReason: {
     _enum: {
@@ -2055,13 +2035,13 @@
     }
   },
   /**
-   * Lookup262: evm_core::error::ExitSucceed
+   * Lookup260: evm_core::error::ExitSucceed
    **/
   EvmCoreErrorExitSucceed: {
     _enum: ['Stopped', 'Returned', 'Suicided']
   },
   /**
-   * Lookup263: evm_core::error::ExitError
+   * Lookup261: evm_core::error::ExitError
    **/
   EvmCoreErrorExitError: {
     _enum: {
@@ -2083,13 +2063,13 @@
     }
   },
   /**
-   * Lookup266: evm_core::error::ExitRevert
+   * Lookup264: evm_core::error::ExitRevert
    **/
   EvmCoreErrorExitRevert: {
     _enum: ['Reverted']
   },
   /**
-   * Lookup267: evm_core::error::ExitFatal
+   * Lookup265: evm_core::error::ExitFatal
    **/
   EvmCoreErrorExitFatal: {
     _enum: {
@@ -2100,7 +2080,7 @@
     }
   },
   /**
-   * Lookup268: frame_system::Phase
+   * Lookup266: frame_system::Phase
    **/
   FrameSystemPhase: {
     _enum: {
@@ -2110,14 +2090,14 @@
     }
   },
   /**
-   * Lookup270: frame_system::LastRuntimeUpgradeInfo
+   * Lookup268: frame_system::LastRuntimeUpgradeInfo
    **/
   FrameSystemLastRuntimeUpgradeInfo: {
     specVersion: 'Compact<u32>',
     specName: 'Text'
   },
   /**
-   * Lookup271: frame_system::limits::BlockWeights
+   * Lookup269: frame_system::limits::BlockWeights
    **/
   FrameSystemLimitsBlockWeights: {
     baseBlock: 'u64',
@@ -2125,7 +2105,7 @@
     perClass: 'FrameSupportWeightsPerDispatchClassWeightsPerClass'
   },
   /**
-   * Lookup272: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
+   * Lookup270: frame_support::weights::PerDispatchClass<frame_system::limits::WeightsPerClass>
    **/
   FrameSupportWeightsPerDispatchClassWeightsPerClass: {
     normal: 'FrameSystemLimitsWeightsPerClass',
@@ -2133,7 +2113,7 @@
     mandatory: 'FrameSystemLimitsWeightsPerClass'
   },
   /**
-   * Lookup273: frame_system::limits::WeightsPerClass
+   * Lookup271: frame_system::limits::WeightsPerClass
    **/
   FrameSystemLimitsWeightsPerClass: {
     baseExtrinsic: 'u64',
@@ -2142,13 +2122,13 @@
     reserved: 'Option<u64>'
   },
   /**
-   * Lookup275: frame_system::limits::BlockLength
+   * Lookup273: frame_system::limits::BlockLength
    **/
   FrameSystemLimitsBlockLength: {
     max: 'FrameSupportWeightsPerDispatchClassU32'
   },
   /**
-   * Lookup276: frame_support::weights::PerDispatchClass<T>
+   * Lookup274: frame_support::weights::PerDispatchClass<T>
    **/
   FrameSupportWeightsPerDispatchClassU32: {
     normal: 'u32',
@@ -2156,14 +2136,14 @@
     mandatory: 'u32'
   },
   /**
-   * Lookup277: frame_support::weights::RuntimeDbWeight
+   * Lookup275: frame_support::weights::RuntimeDbWeight
    **/
   FrameSupportWeightsRuntimeDbWeight: {
     read: 'u64',
     write: 'u64'
   },
   /**
-   * Lookup278: sp_version::RuntimeVersion
+   * Lookup276: sp_version::RuntimeVersion
    **/
   SpVersionRuntimeVersion: {
     specName: 'Text',
@@ -2176,19 +2156,19 @@
     stateVersion: 'u8'
   },
   /**
-   * Lookup282: frame_system::pallet::Error<T>
+   * Lookup280: frame_system::pallet::Error<T>
    **/
   FrameSystemError: {
     _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
   },
   /**
-   * Lookup284: orml_vesting::module::Error<T>
+   * Lookup282: orml_vesting::module::Error<T>
    **/
   OrmlVestingModuleError: {
     _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
   },
   /**
-   * Lookup286: cumulus_pallet_xcmp_queue::InboundChannelDetails
+   * Lookup284: cumulus_pallet_xcmp_queue::InboundChannelDetails
    **/
   CumulusPalletXcmpQueueInboundChannelDetails: {
     sender: 'u32',
@@ -2196,19 +2176,19 @@
     messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'
   },
   /**
-   * Lookup287: cumulus_pallet_xcmp_queue::InboundState
+   * Lookup285: cumulus_pallet_xcmp_queue::InboundState
    **/
   CumulusPalletXcmpQueueInboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup290: polkadot_parachain::primitives::XcmpMessageFormat
+   * Lookup288: polkadot_parachain::primitives::XcmpMessageFormat
    **/
   PolkadotParachainPrimitivesXcmpMessageFormat: {
     _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
   },
   /**
-   * Lookup293: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+   * Lookup291: cumulus_pallet_xcmp_queue::OutboundChannelDetails
    **/
   CumulusPalletXcmpQueueOutboundChannelDetails: {
     recipient: 'u32',
@@ -2218,13 +2198,13 @@
     lastIndex: 'u16'
   },
   /**
-   * Lookup294: cumulus_pallet_xcmp_queue::OutboundState
+   * Lookup292: cumulus_pallet_xcmp_queue::OutboundState
    **/
   CumulusPalletXcmpQueueOutboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup296: cumulus_pallet_xcmp_queue::QueueConfigData
+   * Lookup294: cumulus_pallet_xcmp_queue::QueueConfigData
    **/
   CumulusPalletXcmpQueueQueueConfigData: {
     suspendThreshold: 'u32',
@@ -2235,29 +2215,29 @@
     xcmpMaxIndividualWeight: 'u64'
   },
   /**
-   * Lookup298: cumulus_pallet_xcmp_queue::pallet::Error<T>
+   * Lookup296: cumulus_pallet_xcmp_queue::pallet::Error<T>
    **/
   CumulusPalletXcmpQueueError: {
     _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
   },
   /**
-   * Lookup299: pallet_xcm::pallet::Error<T>
+   * Lookup297: pallet_xcm::pallet::Error<T>
    **/
   PalletXcmError: {
     _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']
   },
   /**
-   * Lookup300: cumulus_pallet_xcm::pallet::Error<T>
+   * Lookup298: cumulus_pallet_xcm::pallet::Error<T>
    **/
   CumulusPalletXcmError: 'Null',
   /**
-   * Lookup301: cumulus_pallet_dmp_queue::ConfigData
+   * Lookup299: cumulus_pallet_dmp_queue::ConfigData
    **/
   CumulusPalletDmpQueueConfigData: {
     maxIndividual: 'u64'
   },
   /**
-   * Lookup302: cumulus_pallet_dmp_queue::PageIndexData
+   * Lookup300: cumulus_pallet_dmp_queue::PageIndexData
    **/
   CumulusPalletDmpQueuePageIndexData: {
     beginUsed: 'u32',
@@ -2265,19 +2245,19 @@
     overweightCount: 'u64'
   },
   /**
-   * Lookup305: cumulus_pallet_dmp_queue::pallet::Error<T>
+   * Lookup303: cumulus_pallet_dmp_queue::pallet::Error<T>
    **/
   CumulusPalletDmpQueueError: {
     _enum: ['Unknown', 'OverLimit']
   },
   /**
-   * Lookup309: pallet_unique::Error<T>
+   * Lookup307: pallet_unique::Error<T>
    **/
   PalletUniqueError: {
     _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument']
   },
   /**
-   * Lookup310: up_data_structs::Collection<sp_core::crypto::AccountId32>
+   * Lookup308: up_data_structs::Collection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCollection: {
     owner: 'AccountId32',
@@ -2289,11 +2269,10 @@
     mintMode: 'bool',
     schemaVersion: 'UpDataStructsSchemaVersion',
     sponsorship: 'UpDataStructsSponsorshipState',
-    limits: 'UpDataStructsCollectionLimits',
-    metaUpdatePermission: 'UpDataStructsMetaUpdatePermission'
+    limits: 'UpDataStructsCollectionLimits'
   },
   /**
-   * Lookup311: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+   * Lookup309: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
    **/
   UpDataStructsSponsorshipState: {
     _enum: {
@@ -2303,7 +2282,7 @@
     }
   },
   /**
-   * Lookup312: up_data_structs::Properties
+   * Lookup310: up_data_structs::Properties
    **/
   UpDataStructsProperties: {
     map: 'UpDataStructsPropertiesMapBoundedVec',
@@ -2311,21 +2290,21 @@
     spaceLimit: 'u32'
   },
   /**
-   * Lookup313: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup311: up_data_structs::PropertiesMap<frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
   /**
-   * Lookup318: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+   * Lookup316: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
    **/
   UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
   /**
-   * Lookup324: up_data_structs::CollectionField
+   * Lookup322: up_data_structs::CollectionField
    **/
   UpDataStructsCollectionField: {
     _enum: ['ConstOnChainSchema', 'OffchainSchema']
   },
   /**
-   * Lookup327: up_data_structs::CollectionStats
+   * Lookup325: up_data_structs::CollectionStats
    **/
   UpDataStructsCollectionStats: {
     created: 'u32',
@@ -2333,11 +2312,11 @@
     alive: 'u32'
   },
   /**
-   * Lookup328: PhantomType::up_data_structs<up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>>
+   * Lookup326: PhantomType::up_data_structs<up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>>
    **/
-  PhantomTypeUpDataStructsTokenData: '[Lookup329;0]',
+  PhantomTypeUpDataStructsTokenData: '[Lookup327;0]',
   /**
-   * Lookup329: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup327: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsTokenData: {
     constData: 'Bytes',
@@ -2345,11 +2324,11 @@
     owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>'
   },
   /**
-   * Lookup332: PhantomType::up_data_structs<up_data_structs::RpcCollection<sp_core::crypto::AccountId32>>
+   * Lookup330: PhantomType::up_data_structs<up_data_structs::RpcCollection<sp_core::crypto::AccountId32>>
    **/
-  PhantomTypeUpDataStructsRpcCollection: '[Lookup333;0]',
+  PhantomTypeUpDataStructsRpcCollection: '[Lookup331;0]',
   /**
-   * Lookup333: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+   * Lookup331: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsRpcCollection: {
     owner: 'AccountId32',
@@ -2364,16 +2343,15 @@
     sponsorship: 'UpDataStructsSponsorshipState',
     limits: 'UpDataStructsCollectionLimits',
     constOnChainSchema: 'Bytes',
-    metaUpdatePermission: 'UpDataStructsMetaUpdatePermission',
     tokenPropertyPermissions: 'Vec<UpDataStructsPropertyKeyPermission>',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup335: PhantomType::up_data_structs<rmrk_types::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>>
+   * Lookup333: PhantomType::up_data_structs<rmrk_types::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>>
    **/
-  PhantomTypeUpDataStructsCollectionInfo: '[Lookup336;0]',
+  PhantomTypeUpDataStructsCollectionInfo: '[Lookup334;0]',
   /**
-   * Lookup336: rmrk_types::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
+   * Lookup334: rmrk_types::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
    **/
   RmrkTypesCollectionInfo: {
     issuer: 'AccountId32',
@@ -2383,11 +2361,11 @@
     nftsCount: 'u32'
   },
   /**
-   * Lookup340: PhantomType::up_data_structs<rmrk_types::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
+   * Lookup338: PhantomType::up_data_structs<rmrk_types::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
    **/
-  PhantomTypeUpDataStructsNftInfo: '[Lookup341;0]',
+  PhantomTypeUpDataStructsNftInfo: '[Lookup339;0]',
   /**
-   * Lookup341: rmrk_types::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup339: rmrk_types::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesNftInfo: {
     owner: 'RmrkTypesAccountIdOrCollectionNftTuple',
@@ -2397,7 +2375,7 @@
     pending: 'bool'
   },
   /**
-   * Lookup342: rmrk_types::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
+   * Lookup340: rmrk_types::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
    **/
   RmrkTypesAccountIdOrCollectionNftTuple: {
     _enum: {
@@ -2406,18 +2384,18 @@
     }
   },
   /**
-   * Lookup344: rmrk_types::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
+   * Lookup342: rmrk_types::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
    **/
   RmrkTypesRoyaltyInfo: {
     recipient: 'AccountId32',
     amount: 'Permill'
   },
   /**
-   * Lookup346: PhantomType::up_data_structs<rmrk_types::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
+   * Lookup344: PhantomType::up_data_structs<rmrk_types::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
    **/
-  PhantomTypeUpDataStructsResourceInfo: '[Lookup347;0]',
+  PhantomTypeUpDataStructsResourceInfo: '[Lookup345;0]',
   /**
-   * Lookup347: rmrk_types::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup345: rmrk_types::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesResourceInfo: {
     id: 'Bytes',
@@ -2432,22 +2410,22 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup353: PhantomType::up_data_structs<rmrk_types::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
+   * Lookup351: PhantomType::up_data_structs<rmrk_types::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
    **/
-  PhantomTypeUpDataStructsPropertyInfo: '[Lookup354;0]',
+  PhantomTypeUpDataStructsPropertyInfo: '[Lookup352;0]',
   /**
-   * Lookup354: rmrk_types::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup352: rmrk_types::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesPropertyInfo: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup358: PhantomType::up_data_structs<rmrk_types::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
+   * Lookup356: PhantomType::up_data_structs<rmrk_types::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
    **/
-  PhantomTypeUpDataStructsBaseInfo: '[Lookup359;0]',
+  PhantomTypeUpDataStructsBaseInfo: '[Lookup357;0]',
   /**
-   * Lookup359: rmrk_types::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup357: rmrk_types::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesBaseInfo: {
     issuer: 'AccountId32',
@@ -2455,11 +2433,11 @@
     symbol: 'Bytes'
   },
   /**
-   * Lookup361: PhantomType::up_data_structs<rmrk_types::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
+   * Lookup359: PhantomType::up_data_structs<rmrk_types::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>>
    **/
-  PhantomTypeUpDataStructsPartType: '[Lookup362;0]',
+  PhantomTypeUpDataStructsPartType: '[Lookup360;0]',
   /**
-   * Lookup362: rmrk_types::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup360: rmrk_types::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesPartType: {
     _enum: {
@@ -2468,7 +2446,7 @@
     }
   },
   /**
-   * Lookup364: rmrk_types::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup362: rmrk_types::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesFixedPart: {
     id: 'u32',
@@ -2476,7 +2454,7 @@
     src: 'Bytes'
   },
   /**
-   * Lookup365: rmrk_types::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup363: rmrk_types::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesSlotPart: {
     id: 'u32',
@@ -2485,7 +2463,7 @@
     z: 'u32'
   },
   /**
-   * Lookup366: rmrk_types::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup364: rmrk_types::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesEquippableList: {
     _enum: {
@@ -2495,11 +2473,11 @@
     }
   },
   /**
-   * Lookup368: PhantomType::up_data_structs<rmrk_types::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, BoundedPropertyList>>
+   * Lookup366: PhantomType::up_data_structs<rmrk_types::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, BoundedPropertyList>>
    **/
-  PhantomTypeUpDataStructsTheme: '[Lookup369;0]',
+  PhantomTypeUpDataStructsTheme: '[Lookup367;0]',
   /**
-   * Lookup369: rmrk_types::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, BoundedPropertyList>
+   * Lookup367: rmrk_types::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, BoundedPropertyList>
    **/
   RmrkTypesTheme: {
     name: 'Bytes',
@@ -2507,76 +2485,74 @@
     inherit: 'bool'
   },
   /**
-   * Lookup371: rmrk_types::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+   * Lookup369: rmrk_types::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTypesThemeProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup373: PhantomType::up_data_structs<rmrk_types::NftChild>
+   * Lookup371: PhantomType::up_data_structs<rmrk_types::NftChild>
    **/
-  PhantomTypeUpDataStructsNftChild: '[Lookup374;0]',
+  PhantomTypeUpDataStructsNftChild: '[Lookup372;0]',
   /**
-   * Lookup374: rmrk_types::NftChild
+   * Lookup372: rmrk_types::NftChild
    **/
   RmrkTypesNftChild: {
     collectionId: 'u32',
     nftId: 'u32'
   },
   /**
-   * Lookup376: pallet_common::pallet::Error<T>
+   * Lookup374: pallet_common::pallet::Error<T>
    **/
   PalletCommonError: {
-    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'TokenVariableDataLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'NestingIsDisabled', 'OnlyOwnerAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'UnableToReadUnboundedKeys', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey']
+    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'NestingIsDisabled', 'OnlyOwnerAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey']
   },
   /**
-   * Lookup378: pallet_fungible::pallet::Error<T>
+   * Lookup376: pallet_fungible::pallet::Error<T>
    **/
   PalletFungibleError: {
     _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup379: pallet_refungible::ItemData
+   * Lookup377: pallet_refungible::ItemData
    **/
   PalletRefungibleItemData: {
-    constData: 'Bytes',
-    variableData: 'Bytes'
+    constData: 'Bytes'
   },
   /**
-   * Lookup383: pallet_refungible::pallet::Error<T>
+   * Lookup381: pallet_refungible::pallet::Error<T>
    **/
   PalletRefungibleError: {
     _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup384: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup382: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletNonfungibleItemData: {
     constData: 'Bytes',
-    variableData: 'Bytes',
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup385: pallet_nonfungible::pallet::Error<T>
+   * Lookup383: pallet_nonfungible::pallet::Error<T>
    **/
   PalletNonfungibleError: {
     _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount']
   },
   /**
-   * Lookup386: pallet_structure::pallet::Error<T>
+   * Lookup384: pallet_structure::pallet::Error<T>
    **/
   PalletStructureError: {
     _enum: ['OuroborosDetected', 'DepthLimit', 'TokenNotFound']
   },
   /**
-   * Lookup389: pallet_evm::pallet::Error<T>
+   * Lookup387: pallet_evm::pallet::Error<T>
    **/
   PalletEvmError: {
     _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']
   },
   /**
-   * Lookup392: fp_rpc::TransactionStatus
+   * Lookup390: fp_rpc::TransactionStatus
    **/
   FpRpcTransactionStatus: {
     transactionHash: 'H256',
@@ -2588,11 +2564,11 @@
     logsBloom: 'EthbloomBloom'
   },
   /**
-   * Lookup394: ethbloom::Bloom
+   * Lookup392: ethbloom::Bloom
    **/
   EthbloomBloom: '[u8;256]',
   /**
-   * Lookup396: ethereum::receipt::ReceiptV3
+   * Lookup394: ethereum::receipt::ReceiptV3
    **/
   EthereumReceiptReceiptV3: {
     _enum: {
@@ -2602,7 +2578,7 @@
     }
   },
   /**
-   * Lookup397: ethereum::receipt::EIP658ReceiptData
+   * Lookup395: ethereum::receipt::EIP658ReceiptData
    **/
   EthereumReceiptEip658ReceiptData: {
     statusCode: 'u8',
@@ -2611,7 +2587,7 @@
     logs: 'Vec<EthereumLog>'
   },
   /**
-   * Lookup398: ethereum::block::Block<ethereum::transaction::TransactionV2>
+   * Lookup396: ethereum::block::Block<ethereum::transaction::TransactionV2>
    **/
   EthereumBlock: {
     header: 'EthereumHeader',
@@ -2619,7 +2595,7 @@
     ommers: 'Vec<EthereumHeader>'
   },
   /**
-   * Lookup399: ethereum::header::Header
+   * Lookup397: ethereum::header::Header
    **/
   EthereumHeader: {
     parentHash: 'H256',
@@ -2639,41 +2615,41 @@
     nonce: 'EthereumTypesHashH64'
   },
   /**
-   * Lookup400: ethereum_types::hash::H64
+   * Lookup398: ethereum_types::hash::H64
    **/
   EthereumTypesHashH64: '[u8;8]',
   /**
-   * Lookup405: pallet_ethereum::pallet::Error<T>
+   * Lookup403: pallet_ethereum::pallet::Error<T>
    **/
   PalletEthereumError: {
     _enum: ['InvalidSignature', 'PreLogExists']
   },
   /**
-   * Lookup406: pallet_evm_coder_substrate::pallet::Error<T>
+   * Lookup404: pallet_evm_coder_substrate::pallet::Error<T>
    **/
   PalletEvmCoderSubstrateError: {
     _enum: ['OutOfGas', 'OutOfFund']
   },
   /**
-   * Lookup407: pallet_evm_contract_helpers::SponsoringModeT
+   * Lookup405: pallet_evm_contract_helpers::SponsoringModeT
    **/
   PalletEvmContractHelpersSponsoringModeT: {
     _enum: ['Disabled', 'Allowlisted', 'Generous']
   },
   /**
-   * Lookup409: pallet_evm_contract_helpers::pallet::Error<T>
+   * Lookup407: pallet_evm_contract_helpers::pallet::Error<T>
    **/
   PalletEvmContractHelpersError: {
     _enum: ['NoPermission']
   },
   /**
-   * Lookup410: pallet_evm_migration::pallet::Error<T>
+   * Lookup408: pallet_evm_migration::pallet::Error<T>
    **/
   PalletEvmMigrationError: {
     _enum: ['AccountNotEmpty', 'AccountIsNotMigrating']
   },
   /**
-   * Lookup412: sp_runtime::MultiSignature
+   * Lookup410: sp_runtime::MultiSignature
    **/
   SpRuntimeMultiSignature: {
     _enum: {
@@ -2683,43 +2659,43 @@
     }
   },
   /**
-   * Lookup413: sp_core::ed25519::Signature
+   * Lookup411: sp_core::ed25519::Signature
    **/
   SpCoreEd25519Signature: '[u8;64]',
   /**
-   * Lookup415: sp_core::sr25519::Signature
+   * Lookup413: sp_core::sr25519::Signature
    **/
   SpCoreSr25519Signature: '[u8;64]',
   /**
-   * Lookup416: sp_core::ecdsa::Signature
+   * Lookup414: sp_core::ecdsa::Signature
    **/
   SpCoreEcdsaSignature: '[u8;65]',
   /**
-   * Lookup419: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+   * Lookup417: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
    **/
   FrameSystemExtensionsCheckSpecVersion: 'Null',
   /**
-   * Lookup420: frame_system::extensions::check_genesis::CheckGenesis<T>
+   * Lookup418: frame_system::extensions::check_genesis::CheckGenesis<T>
    **/
   FrameSystemExtensionsCheckGenesis: 'Null',
   /**
-   * Lookup423: frame_system::extensions::check_nonce::CheckNonce<T>
+   * Lookup421: frame_system::extensions::check_nonce::CheckNonce<T>
    **/
   FrameSystemExtensionsCheckNonce: 'Compact<u32>',
   /**
-   * Lookup424: frame_system::extensions::check_weight::CheckWeight<T>
+   * Lookup422: frame_system::extensions::check_weight::CheckWeight<T>
    **/
   FrameSystemExtensionsCheckWeight: 'Null',
   /**
-   * Lookup425: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+   * Lookup423: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
    **/
   PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
   /**
-   * Lookup426: opal_runtime::Runtime
+   * Lookup424: opal_runtime::Runtime
    **/
   OpalRuntimeRuntime: 'Null',
   /**
-   * Lookup427: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+   * Lookup425: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
    **/
   PalletEthereumFakeTransactionFinalizer: 'Null'
 };
modifiedtests/src/interfaces/registry.tsdiffbeforeafterboth
--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -1,7 +1,7 @@
 // Auto-generated via `yarn polkadot-types-from-defs`, do not edit
 /* eslint-disable */
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTypesAccountIdOrCollectionNftTuple, RmrkTypesBaseInfo, RmrkTypesCollectionInfo, RmrkTypesEquippableList, RmrkTypesFixedPart, RmrkTypesNftChild, RmrkTypesNftInfo, RmrkTypesPartType, RmrkTypesPropertyInfo, RmrkTypesResourceInfo, RmrkTypesRoyaltyInfo, RmrkTypesSlotPart, RmrkTypesTheme, RmrkTypesThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsMetaUpdatePermission, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTypesAccountIdOrCollectionNftTuple, RmrkTypesBaseInfo, RmrkTypesCollectionInfo, RmrkTypesEquippableList, RmrkTypesFixedPart, RmrkTypesNftChild, RmrkTypesNftInfo, RmrkTypesPartType, RmrkTypesPropertyInfo, RmrkTypesResourceInfo, RmrkTypesRoyaltyInfo, RmrkTypesSlotPart, RmrkTypesTheme, RmrkTypesThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 declare module '@polkadot/types/types/registry' {
   export interface InterfaceTypes {
@@ -183,7 +183,6 @@
     UpDataStructsCreateNftExData: UpDataStructsCreateNftExData;
     UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData;
     UpDataStructsCreateRefungibleExData: UpDataStructsCreateRefungibleExData;
-    UpDataStructsMetaUpdatePermission: UpDataStructsMetaUpdatePermission;
     UpDataStructsNestingRule: UpDataStructsNestingRule;
     UpDataStructsProperties: UpDataStructsProperties;
     UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec;
modifiedtests/src/interfaces/rmrk/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/definitions.ts
+++ b/tests/src/interfaces/rmrk/definitions.ts
@@ -33,14 +33,14 @@
     types,
     rpc: {
         lastCollectionIdx: fn('Get the latest created collection id', [], 'u32'),
-        collectionById: fn('Get collection by id', [{name: 'id', type: 'u32'}], 'Option<RmrkTraitsCollectionCollectionInfo>'),
+        collectionById: fn('Get collection by id', [{name: 'id', type: 'u32'}], 'Option<RmrkTypesCollectionInfo>'),
         nftById: fn(
             'Get NFT by collection id and NFT id',
             [
                 {name: 'collectionId', type: 'u32'},
                 {name: 'nftId', type: 'u32'},
             ],
-            'Option<RmrkTraitsNftNftInfo>'
+            'Option<RmrkTypesNftInfo>'
         ),
         accountTokens: fn(
             'Get tokens owned by an account in a collection',
@@ -56,12 +56,12 @@
                 {name: 'collectionId', type: 'u32'},
                 {name: 'nftId', type: 'u32'},
             ],
-            'Vec<RmrkTraitsNftNftChild>'
+            'Vec<RmrkTypesNftChild>'
         ),
         collectionProperties: fn(
             'Get collection properties',
             [{name: 'collectionId', type: 'u32'}],
-            'Vec<RmrkTraitsPropertyPropertyInfo>'
+            'Vec<RmrkTypesPropertyInfo>'
         ),
         nftProperties: fn(
             'Get NFT properties',
@@ -69,7 +69,7 @@
                 {name: 'collectionId', type: 'u32'},
                 {name: 'nftId', type: 'u32'}
             ],
-            'Vec<RmrkTraitsPropertyPropertyInfo>'
+            'Vec<RmrkTypesPropertyInfo>'
         ),
         nftResources: fn(
             'Get NFT resources',
@@ -77,7 +77,7 @@
                 {name: 'collectionId', type: 'u32'},
                 {name: 'nftId', type: 'u32'}
             ],
-            'Vec<RmrkTraitsResourceResourceInfo>'
+            'Vec<RmrkTypesResourceInfo>'
         ),
         nftResourcePriorities: fn(
             'Get NFT resource priorities',
@@ -90,12 +90,12 @@
         base: fn(
             'Get base info',
             [{name: 'baseId', type: 'u32'}],
-            'Option<RmrkTraitsBaseBaseInfo>'
+            'Option<RmrkTypesBaseInfo>'
         ),
         baseParts: fn(
             'Get all Base\'s parts',
             [{name: 'baseId', type: 'u32'}],
-            'Vec<RmrkTraitsPartPartType>'
+            'Vec<RmrkTypesPartType>'
         ),
         themeNames: fn(
             'Get Base\'s theme names',
@@ -109,7 +109,7 @@
                 {name: 'themeName', type: 'String'},
                 {name: 'keys', type: 'Option<Vec<String>>'}
             ],
-            'Option<RmrkTraitsTheme>'
+            'Option<RmrkTypesTheme>'
         )
     }
 };
modifiedtests/src/interfaces/rmrk/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/rmrk/types.ts
+++ b/tests/src/interfaces/rmrk/types.ts
@@ -446,9 +446,6 @@
 /** @name FrameSupportPalletId */
 export interface FrameSupportPalletId extends U8aFixed {}
 
-/** @name FrameSupportStorageBoundedBTreeSet */
-export interface FrameSupportStorageBoundedBTreeSet extends BTreeSet<u32> {}
-
 /** @name FrameSupportTokensMiscBalanceStatus */
 export interface FrameSupportTokensMiscBalanceStatus extends Enum {
   readonly isFree: boolean;
@@ -875,7 +872,6 @@
   readonly isCollectionDescriptionLimitExceeded: boolean;
   readonly isCollectionTokenPrefixLimitExceeded: boolean;
   readonly isTotalCollectionsLimitExceeded: boolean;
-  readonly isTokenVariableDataLimitExceeded: boolean;
   readonly isCollectionAdminCountExceeded: boolean;
   readonly isCollectionLimitBoundsExceeded: boolean;
   readonly isOwnerPermissionsCantBeReverted: boolean;
@@ -896,10 +892,10 @@
   readonly isCollectionFieldSizeExceeded: boolean;
   readonly isNoSpaceForProperty: boolean;
   readonly isPropertyLimitReached: boolean;
-  readonly isUnableToReadUnboundedKeys: boolean;
+  readonly isPropertyKeyIsTooLong: boolean;
   readonly isInvalidCharacterInPropertyKey: boolean;
   readonly isEmptyPropertyKey: boolean;
-  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'TokenVariableDataLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'UnableToReadUnboundedKeys' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
+  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
 }
 
 /** @name PalletCommonEvent */
@@ -1115,7 +1111,6 @@
 /** @name PalletNonfungibleItemData */
 export interface PalletNonfungibleItemData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
 }
 
@@ -1131,7 +1126,6 @@
 /** @name PalletRefungibleItemData */
 export interface PalletRefungibleItemData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
 }
 
 /** @name PalletStructureCall */
@@ -1438,17 +1432,6 @@
     readonly collectionId: u32;
     readonly itemId: u32;
     readonly value: u128;
-  } & Struct;
-  readonly isSetVariableMetaData: boolean;
-  readonly asSetVariableMetaData: {
-    readonly collectionId: u32;
-    readonly itemId: u32;
-    readonly data: Bytes;
-  } & Struct;
-  readonly isSetMetaUpdatePermissionFlag: boolean;
-  readonly asSetMetaUpdatePermissionFlag: {
-    readonly collectionId: u32;
-    readonly value: UpDataStructsMetaUpdatePermission;
   } & Struct;
   readonly isSetSchemaVersion: boolean;
   readonly asSetSchemaVersion: {
@@ -1470,7 +1453,7 @@
     readonly collectionId: u32;
     readonly newLimit: UpDataStructsCollectionLimits;
   } & Struct;
-  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetVariableMetaData' | 'SetMetaUpdatePermissionFlag' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
+  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
 }
 
 /** @name PalletUniqueError */
@@ -1632,34 +1615,34 @@
 }
 
 /** @name PhantomTypeUpDataStructsBaseInfo */
-export interface PhantomTypeUpDataStructsBaseInfo extends Vec<Lookup359> {}
+export interface PhantomTypeUpDataStructsBaseInfo extends Vec<Lookup357> {}
 
 /** @name PhantomTypeUpDataStructsCollectionInfo */
-export interface PhantomTypeUpDataStructsCollectionInfo extends Vec<Lookup336> {}
+export interface PhantomTypeUpDataStructsCollectionInfo extends Vec<Lookup334> {}
 
 /** @name PhantomTypeUpDataStructsNftChild */
-export interface PhantomTypeUpDataStructsNftChild extends Vec<Lookup374> {}
+export interface PhantomTypeUpDataStructsNftChild extends Vec<Lookup372> {}
 
 /** @name PhantomTypeUpDataStructsNftInfo */
-export interface PhantomTypeUpDataStructsNftInfo extends Vec<Lookup341> {}
+export interface PhantomTypeUpDataStructsNftInfo extends Vec<Lookup339> {}
 
 /** @name PhantomTypeUpDataStructsPartType */
-export interface PhantomTypeUpDataStructsPartType extends Vec<Lookup362> {}
+export interface PhantomTypeUpDataStructsPartType extends Vec<Lookup360> {}
 
 /** @name PhantomTypeUpDataStructsPropertyInfo */
-export interface PhantomTypeUpDataStructsPropertyInfo extends Vec<Lookup354> {}
+export interface PhantomTypeUpDataStructsPropertyInfo extends Vec<Lookup352> {}
 
 /** @name PhantomTypeUpDataStructsResourceInfo */
-export interface PhantomTypeUpDataStructsResourceInfo extends Vec<Lookup347> {}
+export interface PhantomTypeUpDataStructsResourceInfo extends Vec<Lookup345> {}
 
 /** @name PhantomTypeUpDataStructsRpcCollection */
-export interface PhantomTypeUpDataStructsRpcCollection extends Vec<Lookup333> {}
+export interface PhantomTypeUpDataStructsRpcCollection extends Vec<Lookup331> {}
 
 /** @name PhantomTypeUpDataStructsTheme */
-export interface PhantomTypeUpDataStructsTheme extends Vec<Lookup369> {}
+export interface PhantomTypeUpDataStructsTheme extends Vec<Lookup367> {}
 
 /** @name PhantomTypeUpDataStructsTokenData */
-export interface PhantomTypeUpDataStructsTokenData extends Vec<Lookup329> {}
+export interface PhantomTypeUpDataStructsTokenData extends Vec<Lookup327> {}
 
 /** @name PolkadotCorePrimitivesInboundDownwardMessage */
 export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
@@ -1963,7 +1946,6 @@
   readonly schemaVersion: UpDataStructsSchemaVersion;
   readonly sponsorship: UpDataStructsSponsorshipState;
   readonly limits: UpDataStructsCollectionLimits;
-  readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
 }
 
 /** @name UpDataStructsCollectionField */
@@ -2015,7 +1997,6 @@
   readonly pendingSponsor: Option<AccountId32>;
   readonly limits: Option<UpDataStructsCollectionLimits>;
   readonly constOnChainSchema: Bytes;
-  readonly metaUpdatePermission: Option<UpDataStructsMetaUpdatePermission>;
   readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
   readonly properties: Vec<UpDataStructsProperty>;
 }
@@ -2052,14 +2033,12 @@
 /** @name UpDataStructsCreateNftData */
 export interface UpDataStructsCreateNftData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly properties: Vec<UpDataStructsProperty>;
 }
 
 /** @name UpDataStructsCreateNftExData */
 export interface UpDataStructsCreateNftExData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly properties: Vec<UpDataStructsProperty>;
   readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
 }
@@ -2067,31 +2046,21 @@
 /** @name UpDataStructsCreateReFungibleData */
 export interface UpDataStructsCreateReFungibleData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly pieces: u128;
 }
 
 /** @name UpDataStructsCreateRefungibleExData */
 export interface UpDataStructsCreateRefungibleExData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
 }
 
-/** @name UpDataStructsMetaUpdatePermission */
-export interface UpDataStructsMetaUpdatePermission extends Enum {
-  readonly isItemOwner: boolean;
-  readonly isAdmin: boolean;
-  readonly isNone: boolean;
-  readonly type: 'ItemOwner' | 'Admin' | 'None';
-}
-
 /** @name UpDataStructsNestingRule */
 export interface UpDataStructsNestingRule extends Enum {
   readonly isDisabled: boolean;
   readonly isOwner: boolean;
   readonly isOwnerRestricted: boolean;
-  readonly asOwnerRestricted: FrameSupportStorageBoundedBTreeSet;
+  readonly asOwnerRestricted: BTreeSet<u32>;
   readonly type: 'Disabled' | 'Owner' | 'OwnerRestricted';
 }
 
@@ -2141,7 +2110,6 @@
   readonly sponsorship: UpDataStructsSponsorshipState;
   readonly limits: UpDataStructsCollectionLimits;
   readonly constOnChainSchema: Bytes;
-  readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
   readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
   readonly properties: Vec<UpDataStructsProperty>;
 }
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1493,17 +1493,6 @@
       readonly itemId: u32;
       readonly value: u128;
     } & Struct;
-    readonly isSetVariableMetaData: boolean;
-    readonly asSetVariableMetaData: {
-      readonly collectionId: u32;
-      readonly itemId: u32;
-      readonly data: Bytes;
-    } & Struct;
-    readonly isSetMetaUpdatePermissionFlag: boolean;
-    readonly asSetMetaUpdatePermissionFlag: {
-      readonly collectionId: u32;
-      readonly value: UpDataStructsMetaUpdatePermission;
-    } & Struct;
     readonly isSetSchemaVersion: boolean;
     readonly asSetSchemaVersion: {
       readonly collectionId: u32;
@@ -1524,7 +1513,7 @@
       readonly collectionId: u32;
       readonly newLimit: UpDataStructsCollectionLimits;
     } & Struct;
-    readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetVariableMetaData' | 'SetMetaUpdatePermissionFlag' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
+    readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
   }
 
   /** @name UpDataStructsCollectionMode (156) */
@@ -1548,7 +1537,6 @@
     readonly pendingSponsor: Option<AccountId32>;
     readonly limits: Option<UpDataStructsCollectionLimits>;
     readonly constOnChainSchema: Bytes;
-    readonly metaUpdatePermission: Option<UpDataStructsMetaUpdatePermission>;
     readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
     readonly properties: Vec<UpDataStructsProperty>;
   }
@@ -1598,34 +1586,26 @@
     readonly type: 'Disabled' | 'Owner' | 'OwnerRestricted';
   }
 
-  /** @name UpDataStructsMetaUpdatePermission (177) */
-  export interface UpDataStructsMetaUpdatePermission extends Enum {
-    readonly isItemOwner: boolean;
-    readonly isAdmin: boolean;
-    readonly isNone: boolean;
-    readonly type: 'ItemOwner' | 'Admin' | 'None';
-  }
-
-  /** @name UpDataStructsPropertyKeyPermission (179) */
+  /** @name UpDataStructsPropertyKeyPermission (177) */
   export interface UpDataStructsPropertyKeyPermission extends Struct {
     readonly key: Bytes;
     readonly permission: UpDataStructsPropertyPermission;
   }
 
-  /** @name UpDataStructsPropertyPermission (181) */
+  /** @name UpDataStructsPropertyPermission (179) */
   export interface UpDataStructsPropertyPermission extends Struct {
     readonly mutable: bool;
     readonly collectionAdmin: bool;
     readonly tokenOwner: bool;
   }
 
-  /** @name UpDataStructsProperty (184) */
+  /** @name UpDataStructsProperty (182) */
   export interface UpDataStructsProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name PalletEvmAccountBasicCrossAccountIdRepr (186) */
+  /** @name PalletEvmAccountBasicCrossAccountIdRepr (184) */
   export interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
     readonly isSubstrate: boolean;
     readonly asSubstrate: AccountId32;
@@ -1634,7 +1614,7 @@
     readonly type: 'Substrate' | 'Ethereum';
   }
 
-  /** @name UpDataStructsCreateItemData (188) */
+  /** @name UpDataStructsCreateItemData (186) */
   export interface UpDataStructsCreateItemData extends Enum {
     readonly isNft: boolean;
     readonly asNft: UpDataStructsCreateNftData;
@@ -1645,26 +1625,24 @@
     readonly type: 'Nft' | 'Fungible' | 'ReFungible';
   }
 
-  /** @name UpDataStructsCreateNftData (189) */
+  /** @name UpDataStructsCreateNftData (187) */
   export interface UpDataStructsCreateNftData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateFungibleData (191) */
+  /** @name UpDataStructsCreateFungibleData (189) */
   export interface UpDataStructsCreateFungibleData extends Struct {
     readonly value: u128;
   }
 
-  /** @name UpDataStructsCreateReFungibleData (192) */
+  /** @name UpDataStructsCreateReFungibleData (190) */
   export interface UpDataStructsCreateReFungibleData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
     readonly pieces: u128;
   }
 
-  /** @name UpDataStructsCreateItemExData (196) */
+  /** @name UpDataStructsCreateItemExData (194) */
   export interface UpDataStructsCreateItemExData extends Enum {
     readonly isNft: boolean;
     readonly asNft: Vec<UpDataStructsCreateNftExData>;
@@ -1677,28 +1655,26 @@
     readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
   }
 
-  /** @name UpDataStructsCreateNftExData (198) */
+  /** @name UpDataStructsCreateNftExData (196) */
   export interface UpDataStructsCreateNftExData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name UpDataStructsCreateRefungibleExData (205) */
+  /** @name UpDataStructsCreateRefungibleExData (203) */
   export interface UpDataStructsCreateRefungibleExData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
     readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
   }
 
-  /** @name PalletTemplateTransactionPaymentCall (207) */
+  /** @name PalletTemplateTransactionPaymentCall (205) */
   export type PalletTemplateTransactionPaymentCall = Null;
 
-  /** @name PalletStructureCall (208) */
+  /** @name PalletStructureCall (206) */
   export type PalletStructureCall = Null;
 
-  /** @name PalletEvmCall (209) */
+  /** @name PalletEvmCall (207) */
   export interface PalletEvmCall extends Enum {
     readonly isWithdraw: boolean;
     readonly asWithdraw: {
@@ -1743,7 +1719,7 @@
     readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
   }
 
-  /** @name PalletEthereumCall (215) */
+  /** @name PalletEthereumCall (213) */
   export interface PalletEthereumCall extends Enum {
     readonly isTransact: boolean;
     readonly asTransact: {
@@ -1752,7 +1728,7 @@
     readonly type: 'Transact';
   }
 
-  /** @name EthereumTransactionTransactionV2 (216) */
+  /** @name EthereumTransactionTransactionV2 (214) */
   export interface EthereumTransactionTransactionV2 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumTransactionLegacyTransaction;
@@ -1763,7 +1739,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumTransactionLegacyTransaction (217) */
+  /** @name EthereumTransactionLegacyTransaction (215) */
   export interface EthereumTransactionLegacyTransaction extends Struct {
     readonly nonce: U256;
     readonly gasPrice: U256;
@@ -1774,7 +1750,7 @@
     readonly signature: EthereumTransactionTransactionSignature;
   }
 
-  /** @name EthereumTransactionTransactionAction (218) */
+  /** @name EthereumTransactionTransactionAction (216) */
   export interface EthereumTransactionTransactionAction extends Enum {
     readonly isCall: boolean;
     readonly asCall: H160;
@@ -1782,14 +1758,14 @@
     readonly type: 'Call' | 'Create';
   }
 
-  /** @name EthereumTransactionTransactionSignature (219) */
+  /** @name EthereumTransactionTransactionSignature (217) */
   export interface EthereumTransactionTransactionSignature extends Struct {
     readonly v: u64;
     readonly r: H256;
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionEip2930Transaction (221) */
+  /** @name EthereumTransactionEip2930Transaction (219) */
   export interface EthereumTransactionEip2930Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -1804,13 +1780,13 @@
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionAccessListItem (223) */
+  /** @name EthereumTransactionAccessListItem (221) */
   export interface EthereumTransactionAccessListItem extends Struct {
     readonly address: H160;
     readonly storageKeys: Vec<H256>;
   }
 
-  /** @name EthereumTransactionEip1559Transaction (224) */
+  /** @name EthereumTransactionEip1559Transaction (222) */
   export interface EthereumTransactionEip1559Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -1826,7 +1802,7 @@
     readonly s: H256;
   }
 
-  /** @name PalletEvmMigrationCall (225) */
+  /** @name PalletEvmMigrationCall (223) */
   export interface PalletEvmMigrationCall extends Enum {
     readonly isBegin: boolean;
     readonly asBegin: {
@@ -1845,7 +1821,7 @@
     readonly type: 'Begin' | 'SetData' | 'Finish';
   }
 
-  /** @name PalletSudoEvent (228) */
+  /** @name PalletSudoEvent (226) */
   export interface PalletSudoEvent extends Enum {
     readonly isSudid: boolean;
     readonly asSudid: {
@@ -1862,7 +1838,7 @@
     readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone';
   }
 
-  /** @name SpRuntimeDispatchError (230) */
+  /** @name SpRuntimeDispatchError (228) */
   export interface SpRuntimeDispatchError extends Enum {
     readonly isOther: boolean;
     readonly isCannotLookup: boolean;
@@ -1881,13 +1857,13 @@
     readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional';
   }
 
-  /** @name SpRuntimeModuleError (231) */
+  /** @name SpRuntimeModuleError (229) */
   export interface SpRuntimeModuleError extends Struct {
     readonly index: u8;
     readonly error: U8aFixed;
   }
 
-  /** @name SpRuntimeTokenError (232) */
+  /** @name SpRuntimeTokenError (230) */
   export interface SpRuntimeTokenError extends Enum {
     readonly isNoFunds: boolean;
     readonly isWouldDie: boolean;
@@ -1899,7 +1875,7 @@
     readonly type: 'NoFunds' | 'WouldDie' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported';
   }
 
-  /** @name SpRuntimeArithmeticError (233) */
+  /** @name SpRuntimeArithmeticError (231) */
   export interface SpRuntimeArithmeticError extends Enum {
     readonly isUnderflow: boolean;
     readonly isOverflow: boolean;
@@ -1907,20 +1883,20 @@
     readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero';
   }
 
-  /** @name SpRuntimeTransactionalError (234) */
+  /** @name SpRuntimeTransactionalError (232) */
   export interface SpRuntimeTransactionalError extends Enum {
     readonly isLimitReached: boolean;
     readonly isNoLayer: boolean;
     readonly type: 'LimitReached' | 'NoLayer';
   }
 
-  /** @name PalletSudoError (235) */
+  /** @name PalletSudoError (233) */
   export interface PalletSudoError extends Enum {
     readonly isRequireSudo: boolean;
     readonly type: 'RequireSudo';
   }
 
-  /** @name FrameSystemAccountInfo (236) */
+  /** @name FrameSystemAccountInfo (234) */
   export interface FrameSystemAccountInfo extends Struct {
     readonly nonce: u32;
     readonly consumers: u32;
@@ -1929,19 +1905,19 @@
     readonly data: PalletBalancesAccountData;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassU64 (237) */
+  /** @name FrameSupportWeightsPerDispatchClassU64 (235) */
   export interface FrameSupportWeightsPerDispatchClassU64 extends Struct {
     readonly normal: u64;
     readonly operational: u64;
     readonly mandatory: u64;
   }
 
-  /** @name SpRuntimeDigest (238) */
+  /** @name SpRuntimeDigest (236) */
   export interface SpRuntimeDigest extends Struct {
     readonly logs: Vec<SpRuntimeDigestDigestItem>;
   }
 
-  /** @name SpRuntimeDigestDigestItem (240) */
+  /** @name SpRuntimeDigestDigestItem (238) */
   export interface SpRuntimeDigestDigestItem extends Enum {
     readonly isOther: boolean;
     readonly asOther: Bytes;
@@ -1955,14 +1931,14 @@
     readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated';
   }
 
-  /** @name FrameSystemEventRecord (242) */
+  /** @name FrameSystemEventRecord (240) */
   export interface FrameSystemEventRecord extends Struct {
     readonly phase: FrameSystemPhase;
     readonly event: Event;
     readonly topics: Vec<H256>;
   }
 
-  /** @name FrameSystemEvent (244) */
+  /** @name FrameSystemEvent (242) */
   export interface FrameSystemEvent extends Enum {
     readonly isExtrinsicSuccess: boolean;
     readonly asExtrinsicSuccess: {
@@ -1990,14 +1966,14 @@
     readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked';
   }
 
-  /** @name FrameSupportWeightsDispatchInfo (245) */
+  /** @name FrameSupportWeightsDispatchInfo (243) */
   export interface FrameSupportWeightsDispatchInfo extends Struct {
     readonly weight: u64;
     readonly class: FrameSupportWeightsDispatchClass;
     readonly paysFee: FrameSupportWeightsPays;
   }
 
-  /** @name FrameSupportWeightsDispatchClass (246) */
+  /** @name FrameSupportWeightsDispatchClass (244) */
   export interface FrameSupportWeightsDispatchClass extends Enum {
     readonly isNormal: boolean;
     readonly isOperational: boolean;
@@ -2005,14 +1981,14 @@
     readonly type: 'Normal' | 'Operational' | 'Mandatory';
   }
 
-  /** @name FrameSupportWeightsPays (247) */
+  /** @name FrameSupportWeightsPays (245) */
   export interface FrameSupportWeightsPays extends Enum {
     readonly isYes: boolean;
     readonly isNo: boolean;
     readonly type: 'Yes' | 'No';
   }
 
-  /** @name OrmlVestingModuleEvent (248) */
+  /** @name OrmlVestingModuleEvent (246) */
   export interface OrmlVestingModuleEvent extends Enum {
     readonly isVestingScheduleAdded: boolean;
     readonly asVestingScheduleAdded: {
@@ -2032,7 +2008,7 @@
     readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated';
   }
 
-  /** @name CumulusPalletXcmpQueueEvent (249) */
+  /** @name CumulusPalletXcmpQueueEvent (247) */
   export interface CumulusPalletXcmpQueueEvent extends Enum {
     readonly isSuccess: boolean;
     readonly asSuccess: Option<H256>;
@@ -2053,7 +2029,7 @@
     readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'UpwardMessageSent' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced';
   }
 
-  /** @name PalletXcmEvent (250) */
+  /** @name PalletXcmEvent (248) */
   export interface PalletXcmEvent extends Enum {
     readonly isAttempted: boolean;
     readonly asAttempted: XcmV2TraitsOutcome;
@@ -2090,7 +2066,7 @@
     readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail';
   }
 
-  /** @name XcmV2TraitsOutcome (251) */
+  /** @name XcmV2TraitsOutcome (249) */
   export interface XcmV2TraitsOutcome extends Enum {
     readonly isComplete: boolean;
     readonly asComplete: u64;
@@ -2101,7 +2077,7 @@
     readonly type: 'Complete' | 'Incomplete' | 'Error';
   }
 
-  /** @name CumulusPalletXcmEvent (253) */
+  /** @name CumulusPalletXcmEvent (251) */
   export interface CumulusPalletXcmEvent extends Enum {
     readonly isInvalidFormat: boolean;
     readonly asInvalidFormat: U8aFixed;
@@ -2112,7 +2088,7 @@
     readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward';
   }
 
-  /** @name CumulusPalletDmpQueueEvent (254) */
+  /** @name CumulusPalletDmpQueueEvent (252) */
   export interface CumulusPalletDmpQueueEvent extends Enum {
     readonly isInvalidFormat: boolean;
     readonly asInvalidFormat: U8aFixed;
@@ -2129,7 +2105,7 @@
     readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced';
   }
 
-  /** @name PalletUniqueRawEvent (255) */
+  /** @name PalletUniqueRawEvent (253) */
   export interface PalletUniqueRawEvent extends Enum {
     readonly isCollectionSponsorRemoved: boolean;
     readonly asCollectionSponsorRemoved: u32;
@@ -2162,7 +2138,7 @@
     readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'ConstOnChainSchemaSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'MintPermissionSet' | 'OffchainSchemaSet' | 'PublicAccessModeSet' | 'SchemaVersionSet';
   }
 
-  /** @name PalletCommonEvent (256) */
+  /** @name PalletCommonEvent (254) */
   export interface PalletCommonEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
@@ -2189,14 +2165,14 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
   }
 
-  /** @name PalletStructureEvent (257) */
+  /** @name PalletStructureEvent (255) */
   export interface PalletStructureEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
     readonly type: 'Executed';
   }
 
-  /** @name PalletEvmEvent (258) */
+  /** @name PalletEvmEvent (256) */
   export interface PalletEvmEvent extends Enum {
     readonly isLog: boolean;
     readonly asLog: EthereumLog;
@@ -2215,21 +2191,21 @@
     readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw';
   }
 
-  /** @name EthereumLog (259) */
+  /** @name EthereumLog (257) */
   export interface EthereumLog extends Struct {
     readonly address: H160;
     readonly topics: Vec<H256>;
     readonly data: Bytes;
   }
 
-  /** @name PalletEthereumEvent (260) */
+  /** @name PalletEthereumEvent (258) */
   export interface PalletEthereumEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>;
     readonly type: 'Executed';
   }
 
-  /** @name EvmCoreErrorExitReason (261) */
+  /** @name EvmCoreErrorExitReason (259) */
   export interface EvmCoreErrorExitReason extends Enum {
     readonly isSucceed: boolean;
     readonly asSucceed: EvmCoreErrorExitSucceed;
@@ -2242,7 +2218,7 @@
     readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
   }
 
-  /** @name EvmCoreErrorExitSucceed (262) */
+  /** @name EvmCoreErrorExitSucceed (260) */
   export interface EvmCoreErrorExitSucceed extends Enum {
     readonly isStopped: boolean;
     readonly isReturned: boolean;
@@ -2250,7 +2226,7 @@
     readonly type: 'Stopped' | 'Returned' | 'Suicided';
   }
 
-  /** @name EvmCoreErrorExitError (263) */
+  /** @name EvmCoreErrorExitError (261) */
   export interface EvmCoreErrorExitError extends Enum {
     readonly isStackUnderflow: boolean;
     readonly isStackOverflow: boolean;
@@ -2271,13 +2247,13 @@
     readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode';
   }
 
-  /** @name EvmCoreErrorExitRevert (266) */
+  /** @name EvmCoreErrorExitRevert (264) */
   export interface EvmCoreErrorExitRevert extends Enum {
     readonly isReverted: boolean;
     readonly type: 'Reverted';
   }
 
-  /** @name EvmCoreErrorExitFatal (267) */
+  /** @name EvmCoreErrorExitFatal (265) */
   export interface EvmCoreErrorExitFatal extends Enum {
     readonly isNotSupported: boolean;
     readonly isUnhandledInterrupt: boolean;
@@ -2288,7 +2264,7 @@
     readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
   }
 
-  /** @name FrameSystemPhase (268) */
+  /** @name FrameSystemPhase (266) */
   export interface FrameSystemPhase extends Enum {
     readonly isApplyExtrinsic: boolean;
     readonly asApplyExtrinsic: u32;
@@ -2297,27 +2273,27 @@
     readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
   }
 
-  /** @name FrameSystemLastRuntimeUpgradeInfo (270) */
+  /** @name FrameSystemLastRuntimeUpgradeInfo (268) */
   export interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
     readonly specVersion: Compact<u32>;
     readonly specName: Text;
   }
 
-  /** @name FrameSystemLimitsBlockWeights (271) */
+  /** @name FrameSystemLimitsBlockWeights (269) */
   export interface FrameSystemLimitsBlockWeights extends Struct {
     readonly baseBlock: u64;
     readonly maxBlock: u64;
     readonly perClass: FrameSupportWeightsPerDispatchClassWeightsPerClass;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (272) */
+  /** @name FrameSupportWeightsPerDispatchClassWeightsPerClass (270) */
   export interface FrameSupportWeightsPerDispatchClassWeightsPerClass extends Struct {
     readonly normal: FrameSystemLimitsWeightsPerClass;
     readonly operational: FrameSystemLimitsWeightsPerClass;
     readonly mandatory: FrameSystemLimitsWeightsPerClass;
   }
 
-  /** @name FrameSystemLimitsWeightsPerClass (273) */
+  /** @name FrameSystemLimitsWeightsPerClass (271) */
   export interface FrameSystemLimitsWeightsPerClass extends Struct {
     readonly baseExtrinsic: u64;
     readonly maxExtrinsic: Option<u64>;
@@ -2325,25 +2301,25 @@
     readonly reserved: Option<u64>;
   }
 
-  /** @name FrameSystemLimitsBlockLength (275) */
+  /** @name FrameSystemLimitsBlockLength (273) */
   export interface FrameSystemLimitsBlockLength extends Struct {
     readonly max: FrameSupportWeightsPerDispatchClassU32;
   }
 
-  /** @name FrameSupportWeightsPerDispatchClassU32 (276) */
+  /** @name FrameSupportWeightsPerDispatchClassU32 (274) */
   export interface FrameSupportWeightsPerDispatchClassU32 extends Struct {
     readonly normal: u32;
     readonly operational: u32;
     readonly mandatory: u32;
   }
 
-  /** @name FrameSupportWeightsRuntimeDbWeight (277) */
+  /** @name FrameSupportWeightsRuntimeDbWeight (275) */
   export interface FrameSupportWeightsRuntimeDbWeight extends Struct {
     readonly read: u64;
     readonly write: u64;
   }
 
-  /** @name SpVersionRuntimeVersion (278) */
+  /** @name SpVersionRuntimeVersion (276) */
   export interface SpVersionRuntimeVersion extends Struct {
     readonly specName: Text;
     readonly implName: Text;
@@ -2355,7 +2331,7 @@
     readonly stateVersion: u8;
   }
 
-  /** @name FrameSystemError (282) */
+  /** @name FrameSystemError (280) */
   export interface FrameSystemError extends Enum {
     readonly isInvalidSpecName: boolean;
     readonly isSpecVersionNeedsToIncrease: boolean;
@@ -2366,7 +2342,7 @@
     readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
   }
 
-  /** @name OrmlVestingModuleError (284) */
+  /** @name OrmlVestingModuleError (282) */
   export interface OrmlVestingModuleError extends Enum {
     readonly isZeroVestingPeriod: boolean;
     readonly isZeroVestingPeriodCount: boolean;
@@ -2377,21 +2353,21 @@
     readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
   }
 
-  /** @name CumulusPalletXcmpQueueInboundChannelDetails (286) */
+  /** @name CumulusPalletXcmpQueueInboundChannelDetails (284) */
   export interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
     readonly sender: u32;
     readonly state: CumulusPalletXcmpQueueInboundState;
     readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesXcmpMessageFormat]>>;
   }
 
-  /** @name CumulusPalletXcmpQueueInboundState (287) */
+  /** @name CumulusPalletXcmpQueueInboundState (285) */
   export interface CumulusPalletXcmpQueueInboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (290) */
+  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (288) */
   export interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum {
     readonly isConcatenatedVersionedXcm: boolean;
     readonly isConcatenatedEncodedBlob: boolean;
@@ -2399,7 +2375,7 @@
     readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (293) */
+  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (291) */
   export interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
     readonly recipient: u32;
     readonly state: CumulusPalletXcmpQueueOutboundState;
@@ -2408,14 +2384,14 @@
     readonly lastIndex: u16;
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundState (294) */
+  /** @name CumulusPalletXcmpQueueOutboundState (292) */
   export interface CumulusPalletXcmpQueueOutboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name CumulusPalletXcmpQueueQueueConfigData (296) */
+  /** @name CumulusPalletXcmpQueueQueueConfigData (294) */
   export interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
     readonly suspendThreshold: u32;
     readonly dropThreshold: u32;
@@ -2425,7 +2401,7 @@
     readonly xcmpMaxIndividualWeight: u64;
   }
 
-  /** @name CumulusPalletXcmpQueueError (298) */
+  /** @name CumulusPalletXcmpQueueError (296) */
   export interface CumulusPalletXcmpQueueError extends Enum {
     readonly isFailedToSend: boolean;
     readonly isBadXcmOrigin: boolean;
@@ -2435,7 +2411,7 @@
     readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
   }
 
-  /** @name PalletXcmError (299) */
+  /** @name PalletXcmError (297) */
   export interface PalletXcmError extends Enum {
     readonly isUnreachable: boolean;
     readonly isSendFailure: boolean;
@@ -2453,29 +2429,29 @@
     readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed';
   }
 
-  /** @name CumulusPalletXcmError (300) */
+  /** @name CumulusPalletXcmError (298) */
   export type CumulusPalletXcmError = Null;
 
-  /** @name CumulusPalletDmpQueueConfigData (301) */
+  /** @name CumulusPalletDmpQueueConfigData (299) */
   export interface CumulusPalletDmpQueueConfigData extends Struct {
     readonly maxIndividual: u64;
   }
 
-  /** @name CumulusPalletDmpQueuePageIndexData (302) */
+  /** @name CumulusPalletDmpQueuePageIndexData (300) */
   export interface CumulusPalletDmpQueuePageIndexData extends Struct {
     readonly beginUsed: u32;
     readonly endUsed: u32;
     readonly overweightCount: u64;
   }
 
-  /** @name CumulusPalletDmpQueueError (305) */
+  /** @name CumulusPalletDmpQueueError (303) */
   export interface CumulusPalletDmpQueueError extends Enum {
     readonly isUnknown: boolean;
     readonly isOverLimit: boolean;
     readonly type: 'Unknown' | 'OverLimit';
   }
 
-  /** @name PalletUniqueError (309) */
+  /** @name PalletUniqueError (307) */
   export interface PalletUniqueError extends Enum {
     readonly isCollectionDecimalPointLimitExceeded: boolean;
     readonly isConfirmUnsetSponsorFail: boolean;
@@ -2483,7 +2459,7 @@
     readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument';
   }
 
-  /** @name UpDataStructsCollection (310) */
+  /** @name UpDataStructsCollection (308) */
   export interface UpDataStructsCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -2495,10 +2471,9 @@
     readonly schemaVersion: UpDataStructsSchemaVersion;
     readonly sponsorship: UpDataStructsSponsorshipState;
     readonly limits: UpDataStructsCollectionLimits;
-    readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
   }
 
-  /** @name UpDataStructsSponsorshipState (311) */
+  /** @name UpDataStructsSponsorshipState (309) */
   export interface UpDataStructsSponsorshipState extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -2508,47 +2483,47 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name UpDataStructsProperties (312) */
+  /** @name UpDataStructsProperties (310) */
   export interface UpDataStructsProperties extends Struct {
     readonly map: UpDataStructsPropertiesMapBoundedVec;
     readonly consumedSpace: u32;
     readonly spaceLimit: u32;
   }
 
-  /** @name UpDataStructsPropertiesMapBoundedVec (313) */
+  /** @name UpDataStructsPropertiesMapBoundedVec (311) */
   export interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
 
-  /** @name UpDataStructsPropertiesMapPropertyPermission (318) */
+  /** @name UpDataStructsPropertiesMapPropertyPermission (316) */
   export interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
 
-  /** @name UpDataStructsCollectionField (324) */
+  /** @name UpDataStructsCollectionField (322) */
   export interface UpDataStructsCollectionField extends Enum {
     readonly isConstOnChainSchema: boolean;
     readonly isOffchainSchema: boolean;
     readonly type: 'ConstOnChainSchema' | 'OffchainSchema';
   }
 
-  /** @name UpDataStructsCollectionStats (327) */
+  /** @name UpDataStructsCollectionStats (325) */
   export interface UpDataStructsCollectionStats extends Struct {
     readonly created: u32;
     readonly destroyed: u32;
     readonly alive: u32;
   }
 
-  /** @name PhantomTypeUpDataStructsTokenData (328) */
+  /** @name PhantomTypeUpDataStructsTokenData (326) */
   export interface PhantomTypeUpDataStructsTokenData extends Vec<UpDataStructsTokenData> {}
 
-  /** @name UpDataStructsTokenData (329) */
+  /** @name UpDataStructsTokenData (327) */
   export interface UpDataStructsTokenData extends Struct {
     readonly constData: Bytes;
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
   }
 
-  /** @name PhantomTypeUpDataStructsRpcCollection (332) */
+  /** @name PhantomTypeUpDataStructsRpcCollection (330) */
   export interface PhantomTypeUpDataStructsRpcCollection extends Vec<UpDataStructsRpcCollection> {}
 
-  /** @name UpDataStructsRpcCollection (333) */
+  /** @name UpDataStructsRpcCollection (331) */
   export interface UpDataStructsRpcCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -2562,15 +2537,14 @@
     readonly sponsorship: UpDataStructsSponsorshipState;
     readonly limits: UpDataStructsCollectionLimits;
     readonly constOnChainSchema: Bytes;
-    readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
     readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name PhantomTypeUpDataStructsCollectionInfo (335) */
+  /** @name PhantomTypeUpDataStructsCollectionInfo (333) */
   export interface PhantomTypeUpDataStructsCollectionInfo extends Vec<RmrkTypesCollectionInfo> {}
 
-  /** @name RmrkTypesCollectionInfo (336) */
+  /** @name RmrkTypesCollectionInfo (334) */
   export interface RmrkTypesCollectionInfo extends Struct {
     readonly issuer: AccountId32;
     readonly metadata: Bytes;
@@ -2579,10 +2553,10 @@
     readonly nftsCount: u32;
   }
 
-  /** @name PhantomTypeUpDataStructsNftInfo (340) */
+  /** @name PhantomTypeUpDataStructsNftInfo (338) */
   export interface PhantomTypeUpDataStructsNftInfo extends Vec<RmrkTypesNftInfo> {}
 
-  /** @name RmrkTypesNftInfo (341) */
+  /** @name RmrkTypesNftInfo (339) */
   export interface RmrkTypesNftInfo extends Struct {
     readonly owner: RmrkTypesAccountIdOrCollectionNftTuple;
     readonly royalty: Option<RmrkTypesRoyaltyInfo>;
@@ -2591,7 +2565,7 @@
     readonly pending: bool;
   }
 
-  /** @name RmrkTypesAccountIdOrCollectionNftTuple (342) */
+  /** @name RmrkTypesAccountIdOrCollectionNftTuple (340) */
   export interface RmrkTypesAccountIdOrCollectionNftTuple extends Enum {
     readonly isAccountId: boolean;
     readonly asAccountId: AccountId32;
@@ -2600,16 +2574,16 @@
     readonly type: 'AccountId' | 'CollectionAndNftTuple';
   }
 
-  /** @name RmrkTypesRoyaltyInfo (344) */
+  /** @name RmrkTypesRoyaltyInfo (342) */
   export interface RmrkTypesRoyaltyInfo extends Struct {
     readonly recipient: AccountId32;
     readonly amount: Permill;
   }
 
-  /** @name PhantomTypeUpDataStructsResourceInfo (346) */
+  /** @name PhantomTypeUpDataStructsResourceInfo (344) */
   export interface PhantomTypeUpDataStructsResourceInfo extends Vec<RmrkTypesResourceInfo> {}
 
-  /** @name RmrkTypesResourceInfo (347) */
+  /** @name RmrkTypesResourceInfo (345) */
   export interface RmrkTypesResourceInfo extends Struct {
     readonly id: Bytes;
     readonly pending: bool;
@@ -2623,29 +2597,29 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name PhantomTypeUpDataStructsPropertyInfo (353) */
+  /** @name PhantomTypeUpDataStructsPropertyInfo (351) */
   export interface PhantomTypeUpDataStructsPropertyInfo extends Vec<RmrkTypesPropertyInfo> {}
 
-  /** @name RmrkTypesPropertyInfo (354) */
+  /** @name RmrkTypesPropertyInfo (352) */
   export interface RmrkTypesPropertyInfo extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name PhantomTypeUpDataStructsBaseInfo (358) */
+  /** @name PhantomTypeUpDataStructsBaseInfo (356) */
   export interface PhantomTypeUpDataStructsBaseInfo extends Vec<RmrkTypesBaseInfo> {}
 
-  /** @name RmrkTypesBaseInfo (359) */
+  /** @name RmrkTypesBaseInfo (357) */
   export interface RmrkTypesBaseInfo extends Struct {
     readonly issuer: AccountId32;
     readonly baseType: Bytes;
     readonly symbol: Bytes;
   }
 
-  /** @name PhantomTypeUpDataStructsPartType (361) */
+  /** @name PhantomTypeUpDataStructsPartType (359) */
   export interface PhantomTypeUpDataStructsPartType extends Vec<RmrkTypesPartType> {}
 
-  /** @name RmrkTypesPartType (362) */
+  /** @name RmrkTypesPartType (360) */
   export interface RmrkTypesPartType extends Enum {
     readonly isFixedPart: boolean;
     readonly asFixedPart: RmrkTypesFixedPart;
@@ -2654,14 +2628,14 @@
     readonly type: 'FixedPart' | 'SlotPart';
   }
 
-  /** @name RmrkTypesFixedPart (364) */
+  /** @name RmrkTypesFixedPart (362) */
   export interface RmrkTypesFixedPart extends Struct {
     readonly id: u32;
     readonly z: u32;
     readonly src: Bytes;
   }
 
-  /** @name RmrkTypesSlotPart (365) */
+  /** @name RmrkTypesSlotPart (363) */
   export interface RmrkTypesSlotPart extends Struct {
     readonly id: u32;
     readonly equippable: RmrkTypesEquippableList;
@@ -2669,7 +2643,7 @@
     readonly z: u32;
   }
 
-  /** @name RmrkTypesEquippableList (366) */
+  /** @name RmrkTypesEquippableList (364) */
   export interface RmrkTypesEquippableList extends Enum {
     readonly isAll: boolean;
     readonly isEmpty: boolean;
@@ -2678,32 +2652,32 @@
     readonly type: 'All' | 'Empty' | 'Custom';
   }
 
-  /** @name PhantomTypeUpDataStructsTheme (368) */
+  /** @name PhantomTypeUpDataStructsTheme (366) */
   export interface PhantomTypeUpDataStructsTheme extends Vec<RmrkTypesTheme> {}
 
-  /** @name RmrkTypesTheme (369) */
+  /** @name RmrkTypesTheme (367) */
   export interface RmrkTypesTheme extends Struct {
     readonly name: Bytes;
     readonly properties: Vec<RmrkTypesThemeProperty>;
     readonly inherit: bool;
   }
 
-  /** @name RmrkTypesThemeProperty (371) */
+  /** @name RmrkTypesThemeProperty (369) */
   export interface RmrkTypesThemeProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name PhantomTypeUpDataStructsNftChild (373) */
+  /** @name PhantomTypeUpDataStructsNftChild (371) */
   export interface PhantomTypeUpDataStructsNftChild extends Vec<RmrkTypesNftChild> {}
 
-  /** @name RmrkTypesNftChild (374) */
+  /** @name RmrkTypesNftChild (372) */
   export interface RmrkTypesNftChild extends Struct {
     readonly collectionId: u32;
     readonly nftId: u32;
   }
 
-  /** @name PalletCommonError (376) */
+  /** @name PalletCommonError (374) */
   export interface PalletCommonError extends Enum {
     readonly isCollectionNotFound: boolean;
     readonly isMustBeTokenOwner: boolean;
@@ -2714,7 +2688,6 @@
     readonly isCollectionDescriptionLimitExceeded: boolean;
     readonly isCollectionTokenPrefixLimitExceeded: boolean;
     readonly isTotalCollectionsLimitExceeded: boolean;
-    readonly isTokenVariableDataLimitExceeded: boolean;
     readonly isCollectionAdminCountExceeded: boolean;
     readonly isCollectionLimitBoundsExceeded: boolean;
     readonly isOwnerPermissionsCantBeReverted: boolean;
@@ -2735,13 +2708,13 @@
     readonly isCollectionFieldSizeExceeded: boolean;
     readonly isNoSpaceForProperty: boolean;
     readonly isPropertyLimitReached: boolean;
-    readonly isUnableToReadUnboundedKeys: boolean;
+    readonly isPropertyKeyIsTooLong: boolean;
     readonly isInvalidCharacterInPropertyKey: boolean;
     readonly isEmptyPropertyKey: boolean;
-    readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'TokenVariableDataLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'UnableToReadUnboundedKeys' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
+    readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
   }
 
-  /** @name PalletFungibleError (378) */
+  /** @name PalletFungibleError (376) */
   export interface PalletFungibleError extends Enum {
     readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isFungibleItemsHaveNoId: boolean;
@@ -2751,13 +2724,12 @@
     readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletRefungibleItemData (379) */
+  /** @name PalletRefungibleItemData (377) */
   export interface PalletRefungibleItemData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
   }
 
-  /** @name PalletRefungibleError (383) */
+  /** @name PalletRefungibleError (381) */
   export interface PalletRefungibleError extends Enum {
     readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isWrongRefungiblePieces: boolean;
@@ -2766,21 +2738,20 @@
     readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletNonfungibleItemData (384) */
+  /** @name PalletNonfungibleItemData (382) */
   export interface PalletNonfungibleItemData extends Struct {
     readonly constData: Bytes;
-    readonly variableData: Bytes;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name PalletNonfungibleError (385) */
+  /** @name PalletNonfungibleError (383) */
   export interface PalletNonfungibleError extends Enum {
     readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isNonfungibleItemsHaveNoAmount: boolean;
     readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount';
   }
 
-  /** @name PalletStructureError (386) */
+  /** @name PalletStructureError (384) */
   export interface PalletStructureError extends Enum {
     readonly isOuroborosDetected: boolean;
     readonly isDepthLimit: boolean;
@@ -2788,7 +2759,7 @@
     readonly type: 'OuroborosDetected' | 'DepthLimit' | 'TokenNotFound';
   }
 
-  /** @name PalletEvmError (389) */
+  /** @name PalletEvmError (387) */
   export interface PalletEvmError extends Enum {
     readonly isBalanceLow: boolean;
     readonly isFeeOverflow: boolean;
@@ -2799,7 +2770,7 @@
     readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
   }
 
-  /** @name FpRpcTransactionStatus (392) */
+  /** @name FpRpcTransactionStatus (390) */
   export interface FpRpcTransactionStatus extends Struct {
     readonly transactionHash: H256;
     readonly transactionIndex: u32;
@@ -2810,10 +2781,10 @@
     readonly logsBloom: EthbloomBloom;
   }
 
-  /** @name EthbloomBloom (394) */
+  /** @name EthbloomBloom (392) */
   export interface EthbloomBloom extends U8aFixed {}
 
-  /** @name EthereumReceiptReceiptV3 (396) */
+  /** @name EthereumReceiptReceiptV3 (394) */
   export interface EthereumReceiptReceiptV3 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -2824,7 +2795,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumReceiptEip658ReceiptData (397) */
+  /** @name EthereumReceiptEip658ReceiptData (395) */
   export interface EthereumReceiptEip658ReceiptData extends Struct {
     readonly statusCode: u8;
     readonly usedGas: U256;
@@ -2832,14 +2803,14 @@
     readonly logs: Vec<EthereumLog>;
   }
 
-  /** @name EthereumBlock (398) */
+  /** @name EthereumBlock (396) */
   export interface EthereumBlock extends Struct {
     readonly header: EthereumHeader;
     readonly transactions: Vec<EthereumTransactionTransactionV2>;
     readonly ommers: Vec<EthereumHeader>;
   }
 
-  /** @name EthereumHeader (399) */
+  /** @name EthereumHeader (397) */
   export interface EthereumHeader extends Struct {
     readonly parentHash: H256;
     readonly ommersHash: H256;
@@ -2858,24 +2829,24 @@
     readonly nonce: EthereumTypesHashH64;
   }
 
-  /** @name EthereumTypesHashH64 (400) */
+  /** @name EthereumTypesHashH64 (398) */
   export interface EthereumTypesHashH64 extends U8aFixed {}
 
-  /** @name PalletEthereumError (405) */
+  /** @name PalletEthereumError (403) */
   export interface PalletEthereumError extends Enum {
     readonly isInvalidSignature: boolean;
     readonly isPreLogExists: boolean;
     readonly type: 'InvalidSignature' | 'PreLogExists';
   }
 
-  /** @name PalletEvmCoderSubstrateError (406) */
+  /** @name PalletEvmCoderSubstrateError (404) */
   export interface PalletEvmCoderSubstrateError extends Enum {
     readonly isOutOfGas: boolean;
     readonly isOutOfFund: boolean;
     readonly type: 'OutOfGas' | 'OutOfFund';
   }
 
-  /** @name PalletEvmContractHelpersSponsoringModeT (407) */
+  /** @name PalletEvmContractHelpersSponsoringModeT (405) */
   export interface PalletEvmContractHelpersSponsoringModeT extends Enum {
     readonly isDisabled: boolean;
     readonly isAllowlisted: boolean;
@@ -2883,20 +2854,20 @@
     readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
   }
 
-  /** @name PalletEvmContractHelpersError (409) */
+  /** @name PalletEvmContractHelpersError (407) */
   export interface PalletEvmContractHelpersError extends Enum {
     readonly isNoPermission: boolean;
     readonly type: 'NoPermission';
   }
 
-  /** @name PalletEvmMigrationError (410) */
+  /** @name PalletEvmMigrationError (408) */
   export interface PalletEvmMigrationError extends Enum {
     readonly isAccountNotEmpty: boolean;
     readonly isAccountIsNotMigrating: boolean;
     readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
   }
 
-  /** @name SpRuntimeMultiSignature (412) */
+  /** @name SpRuntimeMultiSignature (410) */
   export interface SpRuntimeMultiSignature extends Enum {
     readonly isEd25519: boolean;
     readonly asEd25519: SpCoreEd25519Signature;
@@ -2907,34 +2878,34 @@
     readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
   }
 
-  /** @name SpCoreEd25519Signature (413) */
+  /** @name SpCoreEd25519Signature (411) */
   export interface SpCoreEd25519Signature extends U8aFixed {}
 
-  /** @name SpCoreSr25519Signature (415) */
+  /** @name SpCoreSr25519Signature (413) */
   export interface SpCoreSr25519Signature extends U8aFixed {}
 
-  /** @name SpCoreEcdsaSignature (416) */
+  /** @name SpCoreEcdsaSignature (414) */
   export interface SpCoreEcdsaSignature extends U8aFixed {}
 
-  /** @name FrameSystemExtensionsCheckSpecVersion (419) */
+  /** @name FrameSystemExtensionsCheckSpecVersion (417) */
   export type FrameSystemExtensionsCheckSpecVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckGenesis (420) */
+  /** @name FrameSystemExtensionsCheckGenesis (418) */
   export type FrameSystemExtensionsCheckGenesis = Null;
 
-  /** @name FrameSystemExtensionsCheckNonce (423) */
+  /** @name FrameSystemExtensionsCheckNonce (421) */
   export interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
 
-  /** @name FrameSystemExtensionsCheckWeight (424) */
+  /** @name FrameSystemExtensionsCheckWeight (422) */
   export type FrameSystemExtensionsCheckWeight = Null;
 
-  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (425) */
+  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (423) */
   export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
 
-  /** @name OpalRuntimeRuntime (426) */
+  /** @name OpalRuntimeRuntime (424) */
   export type OpalRuntimeRuntime = Null;
 
-  /** @name PalletEthereumFakeTransactionFinalizer (427) */
+  /** @name PalletEthereumFakeTransactionFinalizer (425) */
   export type PalletEthereumFakeTransactionFinalizer = Null;
 
 } // declare module
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -26,7 +26,7 @@
 
 const collectionParam = {name: 'collection', type: 'u32'};
 const tokenParam = {name: 'tokenId', type: 'u32'};
-const propertyKeysParam = {name: 'propertyKeys', type: 'Vec<String>'};
+const propertyKeysParam = {name: 'propertyKeys', type: 'Vec<String>', isOptional: true};
 const crossAccountParam = (name = 'account') => ({name, type: CROSS_ACCOUNT_ID_TYPE});
 const atParam = {name: 'at', type: 'Hash', isOptional: true};
 
modifiedtests/src/interfaces/unique/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/types.ts
+++ b/tests/src/interfaces/unique/types.ts
@@ -446,9 +446,6 @@
 /** @name FrameSupportPalletId */
 export interface FrameSupportPalletId extends U8aFixed {}
 
-/** @name FrameSupportStorageBoundedBTreeSet */
-export interface FrameSupportStorageBoundedBTreeSet extends BTreeSet<u32> {}
-
 /** @name FrameSupportTokensMiscBalanceStatus */
 export interface FrameSupportTokensMiscBalanceStatus extends Enum {
   readonly isFree: boolean;
@@ -875,7 +872,6 @@
   readonly isCollectionDescriptionLimitExceeded: boolean;
   readonly isCollectionTokenPrefixLimitExceeded: boolean;
   readonly isTotalCollectionsLimitExceeded: boolean;
-  readonly isTokenVariableDataLimitExceeded: boolean;
   readonly isCollectionAdminCountExceeded: boolean;
   readonly isCollectionLimitBoundsExceeded: boolean;
   readonly isOwnerPermissionsCantBeReverted: boolean;
@@ -896,10 +892,10 @@
   readonly isCollectionFieldSizeExceeded: boolean;
   readonly isNoSpaceForProperty: boolean;
   readonly isPropertyLimitReached: boolean;
-  readonly isUnableToReadUnboundedKeys: boolean;
+  readonly isPropertyKeyIsTooLong: boolean;
   readonly isInvalidCharacterInPropertyKey: boolean;
   readonly isEmptyPropertyKey: boolean;
-  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'TokenVariableDataLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'UnableToReadUnboundedKeys' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
+  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
 }
 
 /** @name PalletCommonEvent */
@@ -1115,7 +1111,6 @@
 /** @name PalletNonfungibleItemData */
 export interface PalletNonfungibleItemData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
 }
 
@@ -1131,7 +1126,6 @@
 /** @name PalletRefungibleItemData */
 export interface PalletRefungibleItemData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
 }
 
 /** @name PalletStructureCall */
@@ -1438,17 +1432,6 @@
     readonly collectionId: u32;
     readonly itemId: u32;
     readonly value: u128;
-  } & Struct;
-  readonly isSetVariableMetaData: boolean;
-  readonly asSetVariableMetaData: {
-    readonly collectionId: u32;
-    readonly itemId: u32;
-    readonly data: Bytes;
-  } & Struct;
-  readonly isSetMetaUpdatePermissionFlag: boolean;
-  readonly asSetMetaUpdatePermissionFlag: {
-    readonly collectionId: u32;
-    readonly value: UpDataStructsMetaUpdatePermission;
   } & Struct;
   readonly isSetSchemaVersion: boolean;
   readonly asSetSchemaVersion: {
@@ -1470,7 +1453,7 @@
     readonly collectionId: u32;
     readonly newLimit: UpDataStructsCollectionLimits;
   } & Struct;
-  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetVariableMetaData' | 'SetMetaUpdatePermissionFlag' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
+  readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'SetPublicAccessMode' | 'SetMintPermission' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetSchemaVersion' | 'SetOffchainSchema' | 'SetConstOnChainSchema' | 'SetCollectionLimits';
 }
 
 /** @name PalletUniqueError */
@@ -1632,34 +1615,34 @@
 }
 
 /** @name PhantomTypeUpDataStructsBaseInfo */
-export interface PhantomTypeUpDataStructsBaseInfo extends Vec<Lookup359> {}
+export interface PhantomTypeUpDataStructsBaseInfo extends Vec<Lookup357> {}
 
 /** @name PhantomTypeUpDataStructsCollectionInfo */
-export interface PhantomTypeUpDataStructsCollectionInfo extends Vec<Lookup336> {}
+export interface PhantomTypeUpDataStructsCollectionInfo extends Vec<Lookup334> {}
 
 /** @name PhantomTypeUpDataStructsNftChild */
-export interface PhantomTypeUpDataStructsNftChild extends Vec<Lookup374> {}
+export interface PhantomTypeUpDataStructsNftChild extends Vec<Lookup372> {}
 
 /** @name PhantomTypeUpDataStructsNftInfo */
-export interface PhantomTypeUpDataStructsNftInfo extends Vec<Lookup341> {}
+export interface PhantomTypeUpDataStructsNftInfo extends Vec<Lookup339> {}
 
 /** @name PhantomTypeUpDataStructsPartType */
-export interface PhantomTypeUpDataStructsPartType extends Vec<Lookup362> {}
+export interface PhantomTypeUpDataStructsPartType extends Vec<Lookup360> {}
 
 /** @name PhantomTypeUpDataStructsPropertyInfo */
-export interface PhantomTypeUpDataStructsPropertyInfo extends Vec<Lookup354> {}
+export interface PhantomTypeUpDataStructsPropertyInfo extends Vec<Lookup352> {}
 
 /** @name PhantomTypeUpDataStructsResourceInfo */
-export interface PhantomTypeUpDataStructsResourceInfo extends Vec<Lookup347> {}
+export interface PhantomTypeUpDataStructsResourceInfo extends Vec<Lookup345> {}
 
 /** @name PhantomTypeUpDataStructsRpcCollection */
-export interface PhantomTypeUpDataStructsRpcCollection extends Vec<Lookup333> {}
+export interface PhantomTypeUpDataStructsRpcCollection extends Vec<Lookup331> {}
 
 /** @name PhantomTypeUpDataStructsTheme */
-export interface PhantomTypeUpDataStructsTheme extends Vec<Lookup369> {}
+export interface PhantomTypeUpDataStructsTheme extends Vec<Lookup367> {}
 
 /** @name PhantomTypeUpDataStructsTokenData */
-export interface PhantomTypeUpDataStructsTokenData extends Vec<Lookup329> {}
+export interface PhantomTypeUpDataStructsTokenData extends Vec<Lookup327> {}
 
 /** @name PolkadotCorePrimitivesInboundDownwardMessage */
 export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
@@ -1963,7 +1946,6 @@
   readonly schemaVersion: UpDataStructsSchemaVersion;
   readonly sponsorship: UpDataStructsSponsorshipState;
   readonly limits: UpDataStructsCollectionLimits;
-  readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
 }
 
 /** @name UpDataStructsCollectionField */
@@ -2015,7 +1997,6 @@
   readonly pendingSponsor: Option<AccountId32>;
   readonly limits: Option<UpDataStructsCollectionLimits>;
   readonly constOnChainSchema: Bytes;
-  readonly metaUpdatePermission: Option<UpDataStructsMetaUpdatePermission>;
   readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
   readonly properties: Vec<UpDataStructsProperty>;
 }
@@ -2052,14 +2033,12 @@
 /** @name UpDataStructsCreateNftData */
 export interface UpDataStructsCreateNftData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly properties: Vec<UpDataStructsProperty>;
 }
 
 /** @name UpDataStructsCreateNftExData */
 export interface UpDataStructsCreateNftExData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly properties: Vec<UpDataStructsProperty>;
   readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
 }
@@ -2067,31 +2046,21 @@
 /** @name UpDataStructsCreateReFungibleData */
 export interface UpDataStructsCreateReFungibleData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly pieces: u128;
 }
 
 /** @name UpDataStructsCreateRefungibleExData */
 export interface UpDataStructsCreateRefungibleExData extends Struct {
   readonly constData: Bytes;
-  readonly variableData: Bytes;
   readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
 }
 
-/** @name UpDataStructsMetaUpdatePermission */
-export interface UpDataStructsMetaUpdatePermission extends Enum {
-  readonly isItemOwner: boolean;
-  readonly isAdmin: boolean;
-  readonly isNone: boolean;
-  readonly type: 'ItemOwner' | 'Admin' | 'None';
-}
-
 /** @name UpDataStructsNestingRule */
 export interface UpDataStructsNestingRule extends Enum {
   readonly isDisabled: boolean;
   readonly isOwner: boolean;
   readonly isOwnerRestricted: boolean;
-  readonly asOwnerRestricted: FrameSupportStorageBoundedBTreeSet;
+  readonly asOwnerRestricted: BTreeSet<u32>;
   readonly type: 'Disabled' | 'Owner' | 'OwnerRestricted';
 }
 
@@ -2141,7 +2110,6 @@
   readonly sponsorship: UpDataStructsSponsorshipState;
   readonly limits: UpDataStructsCollectionLimits;
   readonly constOnChainSchema: Bytes;
-  readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
   readonly tokenPropertyPermissions: Vec<UpDataStructsPropertyKeyPermission>;
   readonly properties: Vec<UpDataStructsProperty>;
 }
deletedtests/src/metadataUpdate.test.tsdiffbeforeafterboth
--- a/tests/src/metadataUpdate.test.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import privateKey from './substrate/privateKey';
-import usingApi from './substrate/substrate-api';
-import {
-  createItemExpectSuccess,
-  createCollectionExpectSuccess,
-  enablePublicMintingExpectSuccess,
-  enableAllowListExpectSuccess,
-  setMetadataUpdatePermissionFlagExpectSuccess,
-  setVariableMetaDataExpectSuccess,
-  setMintPermissionExpectSuccess,
-  addToAllowListExpectSuccess,
-  addCollectionAdminExpectSuccess,
-  setVariableMetaDataExpectFailure,
-  setMetadataUpdatePermissionFlagExpectFailure,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-
-describe('Metadata update permissions with ItemOwner flag', () => {
-  it('ItemOwner can set variable metadata with ItemOwner permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'ItemOwner');
-
-      await setVariableMetaDataExpectSuccess(alice, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('Admin can\'n set variable metadata with ItemOwner permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'ItemOwner');
-
-      await setMintPermissionExpectSuccess(alice, nftCollectionId, true);
-      await addToAllowListExpectSuccess(alice, nftCollectionId, bob.address);
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-
-      await setVariableMetaDataExpectFailure(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('User can\'n set variable metadata with ItemOwner permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'ItemOwner');
-
-      await setMintPermissionExpectSuccess(alice, nftCollectionId, true);
-      await setVariableMetaDataExpectFailure(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-});
-
-describe('Metadata update permissions with Admin flag', () => {
-  it('Admin can set variable metadata with Admin permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'Admin');
-
-      await setMintPermissionExpectSuccess(alice, nftCollectionId, true);
-      await addToAllowListExpectSuccess(alice, nftCollectionId, bob.address);
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-
-      await setVariableMetaDataExpectSuccess(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('User can\'n can set variable metadata with Admin permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'Admin');
-
-      await setMintPermissionExpectSuccess(alice, nftCollectionId, true);
-      await addToAllowListExpectSuccess(alice, nftCollectionId, bob.address);
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-
-      await setVariableMetaDataExpectSuccess(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('ItemOwner can\'n can set variable metadata with Admin permission flag', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      await enablePublicMintingExpectSuccess(alice, nftCollectionId);
-      await addToAllowListExpectSuccess(alice, nftCollectionId, bob.address);
-      await enableAllowListExpectSuccess(alice, nftCollectionId);
-      const newNftTokenId = await createItemExpectSuccess(bob, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'Admin');
-
-      await setVariableMetaDataExpectFailure(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-});
-
-describe('Metadata update permissions with None flag', () => {
-  it('Nobody can set variable metadata with None flag (Regular)', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'None');
-
-      await setVariableMetaDataExpectFailure(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('Nobody can set variable metadata with None flag (Admin)', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'None');
-
-      await setMintPermissionExpectSuccess(alice, nftCollectionId, true);
-      await addToAllowListExpectSuccess(alice, nftCollectionId, bob.address);
-      await addCollectionAdminExpectSuccess(alice, nftCollectionId, bob.address);
-
-      await setVariableMetaDataExpectFailure(bob, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('Nobody can set variable metadata with None flag (ItemOwner)', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-
-      const data = [1, 2, 254, 255];
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'None');
-
-      await setVariableMetaDataExpectFailure(alice, nftCollectionId, newNftTokenId, data);
-    });
-  });
-
-  it('Nobody can set variable metadata flag after freeze', async () => {
-    await usingApi(async () => {
-      const alice = privateKey('//Alice');
-
-      // nft
-      const nftCollectionId = await createCollectionExpectSuccess();
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, nftCollectionId, 'None');
-      await setMetadataUpdatePermissionFlagExpectFailure(alice, nftCollectionId, 'Admin');
-    });
-  });
-});
modifiedtests/src/nesting/migration-check.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/migration-check.test.ts
+++ b/tests/src/nesting/migration-check.test.ts
@@ -37,7 +37,6 @@
           accountTokenOwnershipLimit: 3,
         },
         constOnChainSchema: '0x333333',
-        metaUpdatePermission: 'Admin',
       });
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateCollectionResult(events);
modifiedtests/src/nesting/rules-smoke.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/rules-smoke.test.ts
+++ b/tests/src/nesting/rules-smoke.test.ts
@@ -23,7 +23,7 @@
       nestTarget = {Ethereum: tokenIdToAddress(collection, token)};
     });
   });
-  
+
   it('called for fungible', async () => {
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'Fungible',decimalPoints:0}});
@@ -39,7 +39,7 @@
   it('called for nonfungible', async () => {
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-      await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {NFT: {ConstData: [], VariableData: {}}})))
+      await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {NFT: {ConstData: []}})))
         .to.be.rejectedWith(/^common\.SourceCollectionIsNotAllowedToNest$/);
 
       const token = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});
@@ -51,7 +51,7 @@
   it('called for refungible', async () => {
     await usingApi(async api => {
       const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
-      await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {ReFungible: {ConstData: [], VariableData: {}}})))
+      await expect(executeTransaction(api, alice, api.tx.unique.createItem(collection, nestTarget, {ReFungible: {ConstData: []}})))
         .to.be.rejectedWith(/^common\.SourceCollectionIsNotAllowedToNest$/);
 
       const token = await createItemExpectSuccess(alice, collection, 'ReFungible', {Substrate: alice.address});
@@ -60,4 +60,3 @@
     });
   });
 });
-  
\ No newline at end of file
deletedtests/src/setVariableMetaData.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableMetaData.test.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {IKeyringPair} from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import privateKey from './substrate/privateKey';
-import usingApi from './substrate/substrate-api';
-import {
-  burnItemExpectSuccess,
-  createCollectionExpectSuccess,
-  createItemExpectSuccess,
-  destroyCollectionExpectSuccess,
-  findNotExistingCollection,
-  setVariableMetaDataExpectFailure,
-  setVariableMetaDataExpectSuccess,
-  addCollectionAdminExpectSuccess,
-  setMetadataUpdatePermissionFlagExpectSuccess,
-  getVariableMetadata,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-describe('Integration Test setVariableMetaData', () => {
-  const data = [1, 2, 254, 255];
-
-  let alice: IKeyringPair;
-  let collectionId: number;
-  let tokenId: number;
-  before(async () => {
-    await usingApi(async () => {
-      alice = privateKey('//Alice');
-      collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-      tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
-    });
-  });
-
-  it('execute setVariableMetaData', async () => {
-    await setVariableMetaDataExpectSuccess(alice, collectionId, tokenId, data);
-  });
-
-  it('verify data was set', async () => {
-    await usingApi(async api => {
-      expect(await getVariableMetadata(api, collectionId, tokenId)).to.deep.equal(data);
-    });
-  });
-});
-
-describe('Integration Test collection admin setVariableMetaData', () => {
-  const data = [1, 2, 254, 255];
-
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-  let collectionId: number;
-  let tokenId: number;
-  before(async () => {
-    await usingApi(async () => {
-      alice = privateKey('//Alice');
-      bob = privateKey('//Bob');
-      collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-      tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');
-      await setMetadataUpdatePermissionFlagExpectSuccess(alice, collectionId, 'Admin');
-      await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
-    });
-  });
-
-  it('execute setVariableMetaData', async () => {
-    await setVariableMetaDataExpectSuccess(bob, collectionId, tokenId, data);
-  });
-
-  it('verify data was set', async () => {
-    await usingApi(async api => {
-      expect(await getVariableMetadata(api, collectionId, tokenId)).to.deep.equal(data);
-    });
-  });
-});
-
-describe('Negative Integration Test setVariableMetaData', () => {
-  const data = [1];
-
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  let validCollectionId: number;
-  let validTokenId: number;
-
-  before(async () => {
-    await usingApi(async () => {
-      alice = privateKey('//Alice');
-      bob = privateKey('//Bob');
-
-      validCollectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-      validTokenId = await createItemExpectSuccess(alice, validCollectionId, 'NFT');
-    });
-  });
-
-  it('fails on not existing collection id', async () => {
-    await usingApi(async api => {
-      const nonExistingCollectionId = await findNotExistingCollection(api);
-      await setVariableMetaDataExpectFailure(alice, nonExistingCollectionId, 1, data);
-    });
-  });
-  it('fails on removed collection id', async () => {
-    const removedCollectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-    const removedCollectionTokenId = await createItemExpectSuccess(alice, removedCollectionId, 'NFT');
-
-    await destroyCollectionExpectSuccess(removedCollectionId);
-    await setVariableMetaDataExpectFailure(alice, removedCollectionId, removedCollectionTokenId, data);
-  });
-  it('fails on removed token', async () => {
-    const removedTokenCollectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-    const removedTokenId = await createItemExpectSuccess(alice, removedTokenCollectionId, 'NFT');
-    await burnItemExpectSuccess(alice, removedTokenCollectionId, removedTokenId);
-
-    await setVariableMetaDataExpectFailure(alice, removedTokenCollectionId, removedTokenId, data);
-  });
-  it('fails on not existing token', async () => {
-    const nonExistingTokenId = validTokenId + 1;
-
-    await setVariableMetaDataExpectFailure(alice, validCollectionId, nonExistingTokenId, data);
-  });
-  it('fails on too long data', async () => {
-    const tooLongData = new Array(4097).fill(0xff);
-
-    await setVariableMetaDataExpectFailure(alice, validCollectionId, validTokenId, tooLongData);
-  });
-  it('fails on fungible token', async () => {
-    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
-    const fungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
-
-    await setVariableMetaDataExpectFailure(alice, fungibleCollectionId, fungibleTokenId, data);
-  });
-  it('fails on bad sender', async () => {
-    await setVariableMetaDataExpectFailure(bob, validCollectionId, validTokenId, data);
-  });
-});
deletedtests/src/setVariableMetadataSponsoringRateLimit.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableMetadataSponsoringRateLimit.test.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {IKeyringPair} from '@polkadot/types/types';
-import {expect} from 'chai';
-import privateKey from './substrate/privateKey';
-import usingApi from './substrate/substrate-api';
-import {
-  confirmSponsorshipExpectSuccess,
-  createCollectionExpectSuccess,
-  createItemExpectSuccess,
-  findUnusedAddress,
-  getDetailedCollectionInfo,
-  setCollectionLimitsExpectSuccess,
-  setCollectionSponsorExpectSuccess,
-  setVariableMetaDataExpectFailure,
-  setVariableMetaDataExpectSuccess,
-} from './util/helpers';
-
-describe('Integration Test setVariableMetadataSponsoringRateLimit', () => {
-  let alice: IKeyringPair;
-  let userWithNoBalance: IKeyringPair;
-
-  before(async () => {
-    await usingApi(async (api) => {
-      alice = privateKey('//Alice');
-      userWithNoBalance = await findUnusedAddress(api);
-    });
-  });
-
-  it('sponsored setVariableMetaData can be called twice with pause for free', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
-    await confirmSponsorshipExpectSuccess(collectionId);
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {
-      sponsoredDataRateLimit: {Blocks: 0},
-    });
-
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
-    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
-    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
-  });
-
-  it('sponsored setVariableMetaData can\'t be called twice without pause for free', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
-    await confirmSponsorshipExpectSuccess(collectionId);
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {
-      sponsoredDataRateLimit: {Blocks: 10},
-    });
-
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
-    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
-    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
-  });
-
-  it('sponsored setVariableMetaData can\'t be called for free with variable metadata above collection limits', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
-    await confirmSponsorshipExpectSuccess(collectionId);
-    await setCollectionLimitsExpectSuccess(alice, collectionId, {
-      sponsoredDataRateLimit: {Blocks: 0},
-      sponsoredDataSize: 1,
-    });
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
-
-    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1]);
-    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2]);
-  });
-
-  it('Default value of rate limit does not sponsor setting variable metadata', async () => {
-    const collectionId = await createCollectionExpectSuccess();
-    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
-    await confirmSponsorshipExpectSuccess(collectionId);
-
-    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
-    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1]);
-  });
-
-  it('sponsoring of data is disabled by default', async () => {
-    await usingApi(async api => {
-      const collectionId = await createCollectionExpectSuccess();
-
-      const collection = (await getDetailedCollectionInfo(api, collectionId))!;
-      // limit is none = default is used
-      expect(collection?.limits.sponsoredDataRateLimit.isNone);
-    });
-  });
-
-  it('sponsoring can be disabled explicitly', async () => {
-    await usingApi(async api => {
-      const collectionId = await createCollectionExpectSuccess();
-
-      await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsoredDataRateLimit: {Blocks: 6}});
-      {
-        const collection = (await getDetailedCollectionInfo(api, collectionId))!;
-        expect(collection?.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.equal(6);
-      }
-
-      await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsoredDataRateLimit: 'SponsoringDisabled'});
-      {
-        const collection = (await getDetailedCollectionInfo(api, collectionId))!;
-        // disabled sponsoring = default value
-        expect(collection?.limits.sponsoredDataRateLimit.unwrap().isNone).to.true;
-      }
-    });
-  });
-});
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -142,7 +142,6 @@
 export interface IReFungibleTokenDataType {
   owner: IReFungibleOwner[];
   constData: number[];
-  variableData: number[];
 }
 
 export function uniqueEventMessage(events: EventRecord[]): IGetMessage {
@@ -648,28 +647,6 @@
     const sender = privateKey(senderSeed);
     const tx = api.tx.unique.confirmSponsorship(collectionId);
     await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
-  });
-}
-
-export async function setMetadataUpdatePermissionFlagExpectSuccess(sender: IKeyringPair, collectionId: number, flag: string) {
-
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
-    const events = await submitTransactionAsync(sender, tx);
-    const result = getGenericResult(events);
-
-    expect(result.success).to.be.true;
-  });
-}
-
-export async function setMetadataUpdatePermissionFlagExpectFailure(sender: IKeyringPair, collectionId: number, flag: string) {
-
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
-    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
-    const result = getGenericResult(events);
-
-    expect(result.success).to.be.false;
   });
 }
 
@@ -794,23 +771,6 @@
   });
 }
 
-export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));
-    const events = await submitTransactionAsync(sender, tx);
-    const result = getGenericResult(events);
-
-    expect(result.success).to.be.true;
-  });
-}
-
-export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));
-    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
-  });
-}
-
 export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {
   await usingApi(async (api) => {
     const tx = api.tx.unique.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));
@@ -1137,13 +1097,6 @@
   collectionId: number,
 ): Promise<string[]> {
   return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any;
-}
-export async function getVariableMetadata(
-  api: ApiPromise,
-  collectionId: number,
-  tokenId: number,
-): Promise<number[]> {
-  return [...(await api.rpc.unique.variableMetadata(collectionId, tokenId))];
 }
 export async function getConstMetadata(
   api: ApiPromise,
@@ -1182,10 +1135,10 @@
       const createData = {fungible: {value: 10}};
       tx = api.tx.unique.createItem(collectionId, to, createData as any);
     } else if (createMode === 'ReFungible') {
-      const createData = {refungible: {const_data: [], variable_data: [], pieces: 100}};
+      const createData = {refungible: {const_data: [], pieces: 100}};
       tx = api.tx.unique.createItem(collectionId, to, createData as any);
     } else {
-      const createData = {nft: {const_data: [], variable_data: []}};
+      const createData = {nft: {const_data: []}};
       tx = api.tx.unique.createItem(collectionId, to, createData as any);
     }