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

difftreelog

refactor Remove variable data from tokens

Daniel Shiposha2022-05-14parent: #c4410a4.patch.diff
in: master

23 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -71,13 +71,6 @@
 		token: TokenId,
 		at: Option<BlockHash>,
 	) -> Result<Vec<u8>>;
-	#[rpc(name = "unique_variableMetadata")]
-	fn variable_metadata(
-		&self,
-		collection: CollectionId,
-		token: TokenId,
-		at: Option<BlockHash>,
-	) -> Result<Vec<u8>>;
 
 	#[rpc(name = "unique_collectionProperties")]
 	fn collection_properties(
@@ -279,7 +272,6 @@
 	);
 	pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);
 	pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
-	pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
 
 	pass_method!(collection_properties(
 		collection: CollectionId,
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -33,7 +33,7 @@
 	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,
+	CUSTOM_DATA_LIMIT, CollectionLimits, CreateCollectionData, SponsorshipState,
 	CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,
 	PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,
 	PropertiesError, PropertyKeyPermission, TokenData, TrySet,
@@ -312,8 +312,6 @@
 		CollectionTokenPrefixLimitExceeded,
 		/// Total collections bound exceeded.
 		TotalCollectionsLimitExceeded,
-		/// variable_data exceeded data limit.
-		TokenVariableDataLimitExceeded,
 		/// Exceeded max admin count
 		CollectionAdminCountExceeded,
 		/// Collection limit bounds per collection exceeded
@@ -1073,7 +1071,6 @@
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
 	fn burn_from() -> Weight;
-	fn set_variable_metadata(bytes: u32) -> Weight;
 }
 
 pub trait CommonCollectionOperations<T: Config> {
@@ -1163,13 +1160,6 @@
 		nesting_budget: &dyn Budget,
 	) -> DispatchResultWithPostInfo;
 
-	fn set_variable_metadata(
-		&self,
-		sender: T::CrossAccountId,
-		token: TokenId,
-		data: BoundedVec<u8, CustomDataLimit>,
-	) -> DispatchResultWithPostInfo;
-
 	fn check_nesting(
 		&self,
 		sender: T::CrossAccountId,
@@ -1185,7 +1175,6 @@
 
 	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>;
 	/// Amount of unique collection tokens
 	fn total_supply(&self) -> u32;
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,
@@ -85,11 +85,6 @@
 	fn burn_from() -> Weight {
 		<SelfWeightOf<T>>::burn_from()
 	}
-
-	fn set_variable_metadata(_bytes: u32) -> Weight {
-		// Error
-		0
-	}
 }
 
 impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {
@@ -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,9 +316,6 @@
 		None
 	}
 	fn const_metadata(&self, _token: TokenId) -> Vec<u8> {
-		Vec::new()
-	}
-	fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {
 		Vec::new()
 	}
 
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,10 +28,8 @@
 
 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,
 	}
 }
@@ -125,14 +123,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,9 +16,9 @@
 
 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,
+	TokenId, CreateItemExData, CollectionId, budget::Budget, Property,
 	PropertyKey, PropertyKeyPermission,
 };
 use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
@@ -85,10 +85,6 @@
 
 	fn burn_from() -> Weight {
 		<SelfWeightOf<T>>::burn_from()
-	}
-
-	fn set_variable_metadata(bytes: u32) -> Weight {
-		<SelfWeightOf<T>>::set_variable_metadata(bytes)
 	}
 }
 
@@ -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(),
 		}),
@@ -325,19 +320,6 @@
 		} else {
 			Ok(().into())
 		}
-	}
-
-	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(
@@ -376,12 +358,6 @@
 	fn const_metadata(&self, token: TokenId) -> Vec<u8> {
 		<TokenData<T>>::get((self.id, token))
 			.map(|t| t.const_data)
-			.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()
 	}
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -24,7 +24,7 @@
 use up_data_structs::{TokenId, SchemaVersion};
 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,
@@ -274,7 +274,6 @@
 			&caller,
 			CreateItemData::<T> {
 				const_data: BoundedVec::default(),
-				variable_data: BoundedVec::default(),
 				properties: BoundedVec::default(),
 				owner: to,
 			},
@@ -322,7 +321,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 +385,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 +407,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 +450,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(),
 			});
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -49,17 +49,22 @@
 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 +83,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 +141,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>);
@@ -577,7 +598,6 @@
 				(collection.id, token),
 				ItemData {
 					const_data: data.const_data,
-					variable_data: data.variable_data,
 					owner: data.owner.clone(),
 				},
 			);
@@ -773,28 +793,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.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -61,6 +61,24 @@
 	}
 }
 
+// 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;
+	}
+}
+
 // Selector: 58800161
 contract ERC721 is Dummy, ERC165, ERC721Events {
 	// Selector: balanceOf(address) 70a08231
@@ -276,7 +294,7 @@
 	}
 }
 
-// Selector: e562194d
+// Selector: d74d154f
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) public {
@@ -301,26 +319,6 @@
 		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
 	function mintBulk(address to, uint256[] memory tokenIds)
 		public
@@ -354,5 +352,6 @@
 	ERC721Enumerable,
 	ERC721UniqueExtensions,
 	ERC721Mintable,
-	ERC721Burnable
+	ERC721Burnable,
+	CollectionProperties
 {}
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,9 +17,9 @@
 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,
+	CollectionId, TokenId, CreateItemExData, CreateRefungibleExData,
 	budget::Budget, Property, PropertyKey, PropertyKeyPermission,
 };
 use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};
@@ -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,
@@ -355,11 +337,6 @@
 	fn const_metadata(&self, token: TokenId) -> Vec<u8> {
 		<TokenData<T>>::get((self.id, token))
 			.const_data
-			.into_inner()
-	}
-	fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
-		<TokenData<T>>::get((self.id, token))
-			.variable_data
 			.into_inner()
 	}
 
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -41,16 +41,20 @@
 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 +77,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 +153,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 +514,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 +662,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/lib.rsdiffbeforeafterboth
before · pallets/unique/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20	clippy::too_many_arguments,21	clippy::unnecessary_mut_passed,22	clippy::unused_unit23)]2425use frame_support::{26	decl_module, decl_storage, decl_error, decl_event,27	dispatch::DispatchResult,28	ensure,29	weights::{Weight},30	transactional,31	pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32	BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38	CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,39	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,40	AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,41	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,42	CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46	CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,47	dispatch::dispatch_call, dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56	/// Error for non-fungible-token module.57	pub enum Error for Module<T: Config> {58		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59		CollectionDecimalPointLimitExceeded,60		/// This address is not set as sponsor, use setCollectionSponsor first.61		ConfirmUnsetSponsorFail,62		/// Length of items properties must be greater than 0.63		EmptyArgument,64	}65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970	/// Weight information for extrinsics in this pallet.71	type WeightInfo: WeightInfo;72	type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76	pub enum Event<T>77	where78		<T as frame_system::Config>::AccountId,79		<T as pallet_evm::account::Config>::CrossAccountId,80	{81		/// Collection sponsor was removed82		///83		/// # Arguments84		///85		/// * collection_id: Globally unique collection identifier.86		CollectionSponsorRemoved(CollectionId),8788		/// Collection admin was added89		///90		/// # Arguments91		///92		/// * collection_id: Globally unique collection identifier.93		///94		/// * admin:  Admin address.95		CollectionAdminAdded(CollectionId, CrossAccountId),9697		/// Collection owned was change98		///99		/// # Arguments100		///101		/// * collection_id: Globally unique collection identifier.102		///103		/// * owner:  New owner address.104		CollectionOwnedChanged(CollectionId, AccountId),105106		/// Collection sponsor was set107		///108		/// # Arguments109		///110		/// * collection_id: Globally unique collection identifier.111		///112		/// * owner:  New sponsor address.113		CollectionSponsorSet(CollectionId, AccountId),114115		/// const on chain schema was set116		///117		/// # Arguments118		///119		/// * collection_id: Globally unique collection identifier.120		ConstOnChainSchemaSet(CollectionId),121122		/// New sponsor was confirm123		///124		/// # Arguments125		///126		/// * collection_id: Globally unique collection identifier.127		///128		/// * sponsor:  New sponsor address.129		SponsorshipConfirmed(CollectionId, AccountId),130131		/// Collection admin was removed132		///133		/// # Arguments134		///135		/// * collection_id: Globally unique collection identifier.136		///137		/// * admin:  Admin address.138		CollectionAdminRemoved(CollectionId, CrossAccountId),139140		/// Address was remove from allow list141		///142		/// # Arguments143		///144		/// * collection_id: Globally unique collection identifier.145		///146		/// * user:  Address.147		AllowListAddressRemoved(CollectionId, CrossAccountId),148149		/// Address was add to allow list150		///151		/// # Arguments152		///153		/// * collection_id: Globally unique collection identifier.154		///155		/// * user:  Address.156		AllowListAddressAdded(CollectionId, CrossAccountId),157158		/// Collection limits was set159		///160		/// # Arguments161		///162		/// * collection_id: Globally unique collection identifier.163		CollectionLimitSet(CollectionId),164165		/// Mint permission	was set166		///167		/// # Arguments168		///169		/// * collection_id: Globally unique collection identifier.170		MintPermissionSet(CollectionId),171172		/// Offchain schema was set173		///174		/// # Arguments175		///176		/// * collection_id: Globally unique collection identifier.177		OffchainSchemaSet(CollectionId),178179		/// Public access mode was set180		///181		/// # Arguments182		///183		/// * collection_id: Globally unique collection identifier.184		///185		/// * mode: New access state.186		PublicAccessModeSet(CollectionId, AccessMode),187188		/// Schema version was set189		///190		/// # Arguments191		///192		/// * collection_id: Globally unique collection identifier.193		SchemaVersionSet(CollectionId),194	}195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204//                    i.e autoincrementing index205//                    can use non-cryptographic hash206// real - key is controlled by user207//        but it is hard to generate enough colliding values, i.e owner of signed txs208//        can use non-cryptographic hash209// controlled - key is completly controlled by users210//              i.e maps with mutable keys211//              should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216//      collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218//      same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220//      no confirmation required, so addresses can be easily generated221decl_storage! {222	trait Store for Module<T: Config> as Unique {223224		//#region Private members225		/// Used for migrations226		ChainVersion: u64;227		//#endregion228229		//#region Tokens transfer rate limit baskets230		/// (Collection id (controlled?2), who created (real))231		/// TODO: Off chain worker should remove from this map when collection gets removed232		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233		/// Collection id (controlled?2), token id (controlled?2)234		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235		/// Collection id (controlled?2), owning user (real)236		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237		/// Collection id (controlled?2), token id (controlled?2)238		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239		//#endregion240241		/// Variable metadata sponsoring242		/// Collection id (controlled?2), token id (controlled?2)243		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;244		/// Approval sponsoring245		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;246		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;247		pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;248	}249}250251decl_module! {252	pub struct Module<T: Config> for enum Call253	where254		origin: T::Origin255	{256		type Error = Error<T>;257258		fn deposit_event() = default;259260		fn on_initialize(_now: T::BlockNumber) -> Weight {261			0262		}263264		/// 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.265		///266		/// # Permissions267		///268		/// * Anyone.269		///270		/// # Arguments271		///272		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.273		///274		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.275		///276		/// * token_prefix: UTF-8 string with token prefix.277		///278		/// * mode: [CollectionMode] collection type and type dependent data.279		// returns collection ID280		#[weight = <SelfWeightOf<T>>::create_collection()]281		#[transactional]282		#[deprecated]283		pub fn create_collection(origin,284								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,285								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,286								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,287								 mode: CollectionMode) -> DispatchResult  {288			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {289				name: collection_name,290				description: collection_description,291				token_prefix,292				mode,293				..Default::default()294			};295			Self::create_collection_ex(origin, data)296		}297298		/// This method creates a collection299		///300		/// Prefer it to deprecated [`created_collection`] method301		#[weight = <SelfWeightOf<T>>::create_collection()]302		#[transactional]303		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {304			let sender = ensure_signed(origin)?;305306			// =========307308			T::CollectionDispatch::create(sender, data)?;309310			Ok(())311		}312313		/// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.314		///315		/// # Permissions316		///317		/// * Collection Owner.318		///319		/// # Arguments320		///321		/// * collection_id: collection to destroy.322		#[weight = <SelfWeightOf<T>>::destroy_collection()]323		#[transactional]324		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {325			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);326			let collection = <CollectionHandle<T>>::try_get(collection_id)?;327328			// =========329330			T::CollectionDispatch::destroy(sender, collection)?;331332			<NftTransferBasket<T>>::remove_prefix(collection_id, None);333			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);334			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);335336			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);337			<NftApproveBasket<T>>::remove_prefix(collection_id, None);338			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);339			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);340341			Ok(())342		}343344		/// Add an address to allow list.345		///346		/// # Permissions347		///348		/// * Collection Owner349		/// * Collection Admin350		///351		/// # Arguments352		///353		/// * collection_id.354		///355		/// * address.356		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]357		#[transactional]358		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{359360			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);361			let collection = <CollectionHandle<T>>::try_get(collection_id)?;362363			<PalletCommon<T>>::toggle_allowlist(364				&collection,365				&sender,366				&address,367				true,368			)?;369370			Self::deposit_event(Event::<T>::AllowListAddressAdded(371				collection_id,372				address373			));374375			Ok(())376		}377378		/// Remove an address from allow list.379		///380		/// # Permissions381		///382		/// * Collection Owner383		/// * Collection Admin384		///385		/// # Arguments386		///387		/// * collection_id.388		///389		/// * address.390		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]391		#[transactional]392		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{393394			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);395			let collection = <CollectionHandle<T>>::try_get(collection_id)?;396397			<PalletCommon<T>>::toggle_allowlist(398				&collection,399				&sender,400				&address,401				false,402			)?;403404			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(405				collection_id,406				address407			));408409			Ok(())410		}411412		/// Toggle between normal and allow list access for the methods with access for `Anyone`.413		///414		/// # Permissions415		///416		/// * Collection Owner.417		///418		/// # Arguments419		///420		/// * collection_id.421		///422		/// * mode: [AccessMode]423		#[weight = <SelfWeightOf<T>>::set_public_access_mode()]424		#[transactional]425		pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult426		{427			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);428429			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;430			target_collection.check_is_owner(&sender)?;431432			target_collection.access = mode.clone();433434			<Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(435				collection_id,436				mode437			));438439			target_collection.save()440		}441442		/// Allows Anyone to create tokens if:443		/// * Allow List is enabled, and444		/// * Address is added to allow list, and445		/// * This method was called with True parameter446		///447		/// # Permissions448		/// * Collection Owner449		///450		/// # Arguments451		///452		/// * collection_id.453		///454		/// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.455		#[weight = <SelfWeightOf<T>>::set_mint_permission()]456		#[transactional]457		pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult458		{459			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);460461			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;462			target_collection.check_is_owner(&sender)?;463464			target_collection.mint_mode = mint_permission;465466			<Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(467				collection_id468			));469470			target_collection.save()471		}472473		/// Change the owner of the collection.474		///475		/// # Permissions476		///477		/// * Collection Owner.478		///479		/// # Arguments480		///481		/// * collection_id.482		///483		/// * new_owner.484		#[weight = <SelfWeightOf<T>>::change_collection_owner()]485		#[transactional]486		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {487488			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);489490			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;491			target_collection.check_is_owner(&sender)?;492493			target_collection.owner = new_owner.clone();494			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(495				collection_id,496				new_owner497			));498499			target_collection.save()500		}501502		/// Adds an admin of the Collection.503		/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.504		///505		/// # Permissions506		///507		/// * Collection Owner.508		/// * Collection Admin.509		///510		/// # Arguments511		///512		/// * collection_id: ID of the Collection to add admin for.513		///514		/// * new_admin_id: Address of new admin to add.515		#[weight = <SelfWeightOf<T>>::add_collection_admin()]516		#[transactional]517		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {518			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);519			let collection = <CollectionHandle<T>>::try_get(collection_id)?;520521			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(522				collection_id,523				new_admin_id.clone()524			));525526			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)527		}528529		/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.530		///531		/// # Permissions532		///533		/// * Collection Owner.534		/// * Collection Admin.535		///536		/// # Arguments537		///538		/// * collection_id: ID of the Collection to remove admin for.539		///540		/// * account_id: Address of admin to remove.541		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]542		#[transactional]543		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {544			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);545			let collection = <CollectionHandle<T>>::try_get(collection_id)?;546547			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(548				collection_id,549				account_id.clone()550			));551552			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)553		}554555		/// # Permissions556		///557		/// * Collection Owner558		///559		/// # Arguments560		///561		/// * collection_id.562		///563		/// * new_sponsor.564		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]565		#[transactional]566		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {567			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);568569			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;570			target_collection.check_is_owner(&sender)?;571572			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());573574			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(575				collection_id,576				new_sponsor577			));578579			target_collection.save()580		}581582		/// # Permissions583		///584		/// * Sponsor.585		///586		/// # Arguments587		///588		/// * collection_id.589		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]590		#[transactional]591		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {592			let sender = ensure_signed(origin)?;593594			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;595			ensure!(596				target_collection.sponsorship.pending_sponsor() == Some(&sender),597				Error::<T>::ConfirmUnsetSponsorFail598			);599600			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());601602			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(603				collection_id,604				sender605			));606607			target_collection.save()608		}609610		/// Switch back to pay-per-own-transaction model.611		///612		/// # Permissions613		///614		/// * Collection owner.615		///616		/// # Arguments617		///618		/// * collection_id.619		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]620		#[transactional]621		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {622			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);623624			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;625			target_collection.check_is_owner(&sender)?;626627			target_collection.sponsorship = SponsorshipState::Disabled;628629			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(630				collection_id631			));632			target_collection.save()633		}634635		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.636		///637		/// # Permissions638		///639		/// * Collection Owner.640		/// * Collection Admin.641		/// * Anyone if642		///     * Allow List is enabled, and643		///     * Address is added to allow list, and644		///     * MintPermission is enabled (see SetMintPermission method)645		///646		/// # Arguments647		///648		/// * collection_id: ID of the collection.649		///650		/// * owner: Address, initial owner of the NFT.651		///652		/// * data: Token data to store on chain.653		#[weight = T::CommonWeightInfo::create_item()]654		#[transactional]655		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {656			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);657			let budget = budget::Value::new(2);658659			dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))660		}661662		/// This method creates multiple items in a collection created with CreateCollection method.663		///664		/// # Permissions665		///666		/// * Collection Owner.667		/// * Collection Admin.668		/// * Anyone if669		///     * Allow List is enabled, and670		///     * Address is added to allow list, and671		///     * MintPermission is enabled (see SetMintPermission method)672		///673		/// # Arguments674		///675		/// * collection_id: ID of the collection.676		///677		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].678		///679		/// * owner: Address, initial owner of the NFT.680		#[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]681		#[transactional]682		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {683			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);684			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);685			let budget = budget::Value::new(2);686687			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))688		}689690		#[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]691		#[transactional]692		pub fn set_collection_properties(693			origin,694			collection_id: CollectionId,695			properties: Vec<Property>696		) -> DispatchResultWithPostInfo {697			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);698699			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);700701			dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))702		}703704		#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]705		#[transactional]706		pub fn delete_collection_properties(707			origin,708			collection_id: CollectionId,709			property_keys: Vec<PropertyKey>,710		) -> DispatchResultWithPostInfo {711			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);712713			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);714715			dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))716		}717718		#[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]719		#[transactional]720		pub fn set_token_properties(721			origin,722			collection_id: CollectionId,723			token_id: TokenId,724			properties: Vec<Property>725		) -> DispatchResultWithPostInfo {726			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);727728			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);729730			dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))731		}732733		#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]734		#[transactional]735		pub fn delete_token_properties(736			origin,737			collection_id: CollectionId,738			token_id: TokenId,739			property_keys: Vec<PropertyKey>740		) -> DispatchResultWithPostInfo {741			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);742743			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);744745			dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))746		}747748		#[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]749		#[transactional]750		pub fn set_property_permissions(751			origin,752			collection_id: CollectionId,753			property_permissions: Vec<PropertyKeyPermission>,754		) -> DispatchResultWithPostInfo {755			ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);756757			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);758759			dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))760		}761762		#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]763		#[transactional]764		pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {765			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);766			let budget = budget::Value::new(2);767768			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))769		}770771		// TODO! transaction weight772773		/// Set transfers_enabled value for particular collection774		///775		/// # Permissions776		///777		/// * Collection Owner.778		///779		/// # Arguments780		///781		/// * collection_id: ID of the collection.782		///783		/// * value: New flag value.784		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]785		#[transactional]786		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {787			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);788			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;789			target_collection.check_is_owner(&sender)?;790791			// =========792793			target_collection.limits.transfers_enabled = Some(value);794			target_collection.save()795		}796797		/// Destroys a concrete instance of NFT.798		///799		/// # Permissions800		///801		/// * Collection Owner.802		/// * Collection Admin.803		/// * Current NFT Owner.804		///805		/// # Arguments806		///807		/// * collection_id: ID of the collection.808		///809		/// * item_id: ID of NFT to burn.810		#[weight = T::CommonWeightInfo::burn_item()]811		#[transactional]812		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {813			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);814815			let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;816			if value == 1 {817				<NftTransferBasket<T>>::remove(collection_id, item_id);818				<NftApproveBasket<T>>::remove(collection_id, item_id);819			}820			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?821			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());822			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));823			Ok(post_info)824		}825826		/// Destroys a concrete instance of NFT on behalf of the owner827		/// See also: [`approve`]828		///829		/// # Permissions830		///831		/// * Collection Owner.832		/// * Collection Admin.833		/// * Current NFT Owner.834		///835		/// # Arguments836		///837		/// * collection_id: ID of the collection.838		///839		/// * item_id: ID of NFT to burn.840		///841		/// * from: owner of item842		#[weight = T::CommonWeightInfo::burn_from()]843		#[transactional]844		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {845			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);846			let budget = budget::Value::new(2);847848			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))849		}850851		/// Change ownership of the token.852		///853		/// # Permissions854		///855		/// * Collection Owner856		/// * Collection Admin857		/// * Current NFT owner858		///859		/// # Arguments860		///861		/// * recipient: Address of token recipient.862		///863		/// * collection_id.864		///865		/// * item_id: ID of the item866		///     * Non-Fungible Mode: Required.867		///     * Fungible Mode: Ignored.868		///     * Re-Fungible Mode: Required.869		///870		/// * value: Amount to transfer.871		///     * Non-Fungible Mode: Ignored872		///     * Fungible Mode: Must specify transferred amount873		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)874		#[weight = T::CommonWeightInfo::transfer()]875		#[transactional]876		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {877			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);878			let budget = budget::Value::new(2);879880			dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))881		}882883		/// Set, change, or remove approved address to transfer the ownership of the NFT.884		///885		/// # Permissions886		///887		/// * Collection Owner888		/// * Collection Admin889		/// * Current NFT owner890		///891		/// # Arguments892		///893		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).894		///895		/// * collection_id.896		///897		/// * item_id: ID of the item.898		#[weight = T::CommonWeightInfo::approve()]899		#[transactional]900		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {901			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);902903			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))904		}905906		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.907		///908		/// # Permissions909		/// * Collection Owner910		/// * Collection Admin911		/// * Current NFT owner912		/// * Address approved by current NFT owner913		///914		/// # Arguments915		///916		/// * from: Address that owns token.917		///918		/// * recipient: Address of token recipient.919		///920		/// * collection_id.921		///922		/// * item_id: ID of the item.923		///924		/// * value: Amount to transfer.925		#[weight = T::CommonWeightInfo::transfer_from()]926		#[transactional]927		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {928			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);929			let budget = budget::Value::new(2);930931			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))932		}933934		/// Set off-chain data schema.935		///936		/// # Permissions937		///938		/// * Collection Owner939		/// * Collection Admin940		///941		/// # Arguments942		///943		/// * collection_id.944		///945		/// * schema: String representing the offchain data schema.946		#[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]947		#[transactional]948		pub fn set_variable_meta_data (949			origin,950			collection_id: CollectionId,951			item_id: TokenId,952			data: BoundedVec<u8, CustomDataLimit>,953		) -> DispatchResultWithPostInfo {954			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);955956			dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))957		}958959		/// Set meta_update_permission value for particular collection960		///961		/// # Permissions962		///963		/// * Collection Owner.964		///965		/// # Arguments966		///967		/// * collection_id: ID of the collection.968		///969		/// * value: New flag value.970		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]971		#[transactional]972		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {973			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);974			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;975976			ensure!(977				target_collection.meta_update_permission != MetaUpdatePermission::None,978				<CommonError<T>>::MetadataFlagFrozen,979			);980			target_collection.check_is_owner(&sender)?;981982			target_collection.meta_update_permission = value;983984			target_collection.save()985		}986987		/// Set schema standard988		/// ImageURL989		/// Unique990		///991		/// # Permissions992		///993		/// * Collection Owner994		/// * Collection Admin995		///996		/// # Arguments997		///998		/// * collection_id.999		///1000		/// * schema: SchemaVersion: enum1001		#[weight = <SelfWeightOf<T>>::set_schema_version()]1002		#[transactional]1003		pub fn set_schema_version(1004			origin,1005			collection_id: CollectionId,1006			version: SchemaVersion1007		) -> DispatchResult {1008			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1009			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1010			target_collection.check_is_owner_or_admin(&sender)?;1011			target_collection.schema_version = version;10121013			<Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(1014				collection_id1015			));10161017			target_collection.save()1018		}10191020		/// Set off-chain data schema.1021		///1022		/// # Permissions1023		///1024		/// * Collection Owner1025		/// * Collection Admin1026		///1027		/// # Arguments1028		///1029		/// * collection_id.1030		///1031		/// * schema: String representing the offchain data schema.1032		#[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]1033		#[transactional]1034		pub fn set_offchain_schema(1035			origin,1036			collection_id: CollectionId,1037			schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1038		) -> DispatchResult {1039			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1040			let collection = <CollectionHandle<T>>::try_get(collection_id)?;10411042			// =========10431044			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10451046			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1047				collection_id1048			));1049			Ok(())1050		}10511052		/// Set const on-chain data schema.1053		///1054		/// # Permissions1055		///1056		/// * Collection Owner1057		/// * Collection Admin1058		///1059		/// # Arguments1060		///1061		/// * collection_id.1062		///1063		/// * schema: String representing the const on-chain data schema.1064		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1065		#[transactional]1066		pub fn set_const_on_chain_schema (1067			origin,1068			collection_id: CollectionId,1069			schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1070		) -> DispatchResult {1071			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1072			let collection = <CollectionHandle<T>>::try_get(collection_id)?;10731074			// =========10751076			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10771078			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1079				collection_id1080			));1081			Ok(())1082		}10831084		#[weight = <SelfWeightOf<T>>::set_collection_limits()]1085		#[transactional]1086		pub fn set_collection_limits(1087			origin,1088			collection_id: CollectionId,1089			new_limit: CollectionLimits,1090		) -> DispatchResult {1091			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1092			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1093			target_collection.check_is_owner(&sender)?;1094			let old_limit = &target_collection.limits;10951096			target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10971098			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1099				collection_id1100			));11011102			target_collection.save()1103		}1104	}1105}
after · pallets/unique/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20	clippy::too_many_arguments,21	clippy::unnecessary_mut_passed,22	clippy::unused_unit23)]2425use frame_support::{26	decl_module, decl_storage, decl_error, decl_event,27	dispatch::DispatchResult,28	ensure,29	weights::{Weight},30	transactional,31	pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32	BoundedVec,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38	CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,39	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,40	AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,41	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData,42	CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46	CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,47	dispatch::dispatch_call, dispatch::CollectionDispatch,48};4950#[cfg(feature = "runtime-benchmarks")]51mod benchmarking;52pub mod weights;53use weights::WeightInfo;5455decl_error! {56	/// Error for non-fungible-token module.57	pub enum Error for Module<T: Config> {58		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.59		CollectionDecimalPointLimitExceeded,60		/// This address is not set as sponsor, use setCollectionSponsor first.61		ConfirmUnsetSponsorFail,62		/// Length of items properties must be greater than 0.63		EmptyArgument,64	}65}6667pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {68	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;6970	/// Weight information for extrinsics in this pallet.71	type WeightInfo: WeightInfo;72	type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;73}7475decl_event! {76	pub enum Event<T>77	where78		<T as frame_system::Config>::AccountId,79		<T as pallet_evm::account::Config>::CrossAccountId,80	{81		/// Collection sponsor was removed82		///83		/// # Arguments84		///85		/// * collection_id: Globally unique collection identifier.86		CollectionSponsorRemoved(CollectionId),8788		/// Collection admin was added89		///90		/// # Arguments91		///92		/// * collection_id: Globally unique collection identifier.93		///94		/// * admin:  Admin address.95		CollectionAdminAdded(CollectionId, CrossAccountId),9697		/// Collection owned was change98		///99		/// # Arguments100		///101		/// * collection_id: Globally unique collection identifier.102		///103		/// * owner:  New owner address.104		CollectionOwnedChanged(CollectionId, AccountId),105106		/// Collection sponsor was set107		///108		/// # Arguments109		///110		/// * collection_id: Globally unique collection identifier.111		///112		/// * owner:  New sponsor address.113		CollectionSponsorSet(CollectionId, AccountId),114115		/// const on chain schema was set116		///117		/// # Arguments118		///119		/// * collection_id: Globally unique collection identifier.120		ConstOnChainSchemaSet(CollectionId),121122		/// New sponsor was confirm123		///124		/// # Arguments125		///126		/// * collection_id: Globally unique collection identifier.127		///128		/// * sponsor:  New sponsor address.129		SponsorshipConfirmed(CollectionId, AccountId),130131		/// Collection admin was removed132		///133		/// # Arguments134		///135		/// * collection_id: Globally unique collection identifier.136		///137		/// * admin:  Admin address.138		CollectionAdminRemoved(CollectionId, CrossAccountId),139140		/// Address was remove from allow list141		///142		/// # Arguments143		///144		/// * collection_id: Globally unique collection identifier.145		///146		/// * user:  Address.147		AllowListAddressRemoved(CollectionId, CrossAccountId),148149		/// Address was add to allow list150		///151		/// # Arguments152		///153		/// * collection_id: Globally unique collection identifier.154		///155		/// * user:  Address.156		AllowListAddressAdded(CollectionId, CrossAccountId),157158		/// Collection limits was set159		///160		/// # Arguments161		///162		/// * collection_id: Globally unique collection identifier.163		CollectionLimitSet(CollectionId),164165		/// Mint permission	was set166		///167		/// # Arguments168		///169		/// * collection_id: Globally unique collection identifier.170		MintPermissionSet(CollectionId),171172		/// Offchain schema was set173		///174		/// # Arguments175		///176		/// * collection_id: Globally unique collection identifier.177		OffchainSchemaSet(CollectionId),178179		/// Public access mode was set180		///181		/// # Arguments182		///183		/// * collection_id: Globally unique collection identifier.184		///185		/// * mode: New access state.186		PublicAccessModeSet(CollectionId, AccessMode),187188		/// Schema version was set189		///190		/// # Arguments191		///192		/// * collection_id: Globally unique collection identifier.193		SchemaVersionSet(CollectionId),194	}195}196197type SelfWeightOf<T> = <T as Config>::WeightInfo;198199// # Used definitions200//201// ## User control levels202//203// chain-controlled - key is uncontrolled by user204//                    i.e autoincrementing index205//                    can use non-cryptographic hash206// real - key is controlled by user207//        but it is hard to generate enough colliding values, i.e owner of signed txs208//        can use non-cryptographic hash209// controlled - key is completly controlled by users210//              i.e maps with mutable keys211//              should use cryptographic hash212//213// ## User control level downgrade reasons214//215// ?1 - chain-controlled -> controlled216//      collections/tokens can be destroyed, resulting in massive holes217// ?2 - chain-controlled -> controlled218//      same as ?1, but can be only added, resulting in easier exploitation219// ?3 - real -> controlled220//      no confirmation required, so addresses can be easily generated221decl_storage! {222	trait Store for Module<T: Config> as Unique {223224		//#region Private members225		/// Used for migrations226		ChainVersion: u64;227		//#endregion228229		//#region Tokens transfer rate limit baskets230		/// (Collection id (controlled?2), who created (real))231		/// TODO: Off chain worker should remove from this map when collection gets removed232		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;233		/// Collection id (controlled?2), token id (controlled?2)234		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;235		/// Collection id (controlled?2), owning user (real)236		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;237		/// Collection id (controlled?2), token id (controlled?2)238		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239		//#endregion240241		/// Approval sponsoring242		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;243		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;244		pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;245	}246}247248decl_module! {249	pub struct Module<T: Config> for enum Call250	where251		origin: T::Origin252	{253		type Error = Error<T>;254255		fn deposit_event() = default;256257		fn on_initialize(_now: T::BlockNumber) -> Weight {258			0259		}260261		/// 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.262		///263		/// # Permissions264		///265		/// * Anyone.266		///267		/// # Arguments268		///269		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.270		///271		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.272		///273		/// * token_prefix: UTF-8 string with token prefix.274		///275		/// * mode: [CollectionMode] collection type and type dependent data.276		// returns collection ID277		#[weight = <SelfWeightOf<T>>::create_collection()]278		#[transactional]279		#[deprecated]280		pub fn create_collection(origin,281								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,282								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,283								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,284								 mode: CollectionMode) -> DispatchResult  {285			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {286				name: collection_name,287				description: collection_description,288				token_prefix,289				mode,290				..Default::default()291			};292			Self::create_collection_ex(origin, data)293		}294295		/// This method creates a collection296		///297		/// Prefer it to deprecated [`created_collection`] method298		#[weight = <SelfWeightOf<T>>::create_collection()]299		#[transactional]300		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {301			let sender = ensure_signed(origin)?;302303			// =========304305			T::CollectionDispatch::create(sender, data)?;306307			Ok(())308		}309310		/// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.311		///312		/// # Permissions313		///314		/// * Collection Owner.315		///316		/// # Arguments317		///318		/// * collection_id: collection to destroy.319		#[weight = <SelfWeightOf<T>>::destroy_collection()]320		#[transactional]321		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {322			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);323			let collection = <CollectionHandle<T>>::try_get(collection_id)?;324325			// =========326327			T::CollectionDispatch::destroy(sender, collection)?;328329			<NftTransferBasket<T>>::remove_prefix(collection_id, None);330			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);331			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);332333			<NftApproveBasket<T>>::remove_prefix(collection_id, None);334			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);335			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);336337			Ok(())338		}339340		/// Add an address to allow list.341		///342		/// # Permissions343		///344		/// * Collection Owner345		/// * Collection Admin346		///347		/// # Arguments348		///349		/// * collection_id.350		///351		/// * address.352		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]353		#[transactional]354		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{355356			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);357			let collection = <CollectionHandle<T>>::try_get(collection_id)?;358359			<PalletCommon<T>>::toggle_allowlist(360				&collection,361				&sender,362				&address,363				true,364			)?;365366			Self::deposit_event(Event::<T>::AllowListAddressAdded(367				collection_id,368				address369			));370371			Ok(())372		}373374		/// Remove an address from allow list.375		///376		/// # Permissions377		///378		/// * Collection Owner379		/// * Collection Admin380		///381		/// # Arguments382		///383		/// * collection_id.384		///385		/// * address.386		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]387		#[transactional]388		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{389390			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);391			let collection = <CollectionHandle<T>>::try_get(collection_id)?;392393			<PalletCommon<T>>::toggle_allowlist(394				&collection,395				&sender,396				&address,397				false,398			)?;399400			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(401				collection_id,402				address403			));404405			Ok(())406		}407408		/// Toggle between normal and allow list access for the methods with access for `Anyone`.409		///410		/// # Permissions411		///412		/// * Collection Owner.413		///414		/// # Arguments415		///416		/// * collection_id.417		///418		/// * mode: [AccessMode]419		#[weight = <SelfWeightOf<T>>::set_public_access_mode()]420		#[transactional]421		pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult422		{423			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);424425			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;426			target_collection.check_is_owner(&sender)?;427428			target_collection.access = mode.clone();429430			<Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(431				collection_id,432				mode433			));434435			target_collection.save()436		}437438		/// Allows Anyone to create tokens if:439		/// * Allow List is enabled, and440		/// * Address is added to allow list, and441		/// * This method was called with True parameter442		///443		/// # Permissions444		/// * Collection Owner445		///446		/// # Arguments447		///448		/// * collection_id.449		///450		/// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.451		#[weight = <SelfWeightOf<T>>::set_mint_permission()]452		#[transactional]453		pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult454		{455			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);456457			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;458			target_collection.check_is_owner(&sender)?;459460			target_collection.mint_mode = mint_permission;461462			<Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(463				collection_id464			));465466			target_collection.save()467		}468469		/// Change the owner of the collection.470		///471		/// # Permissions472		///473		/// * Collection Owner.474		///475		/// # Arguments476		///477		/// * collection_id.478		///479		/// * new_owner.480		#[weight = <SelfWeightOf<T>>::change_collection_owner()]481		#[transactional]482		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {483484			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);485486			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;487			target_collection.check_is_owner(&sender)?;488489			target_collection.owner = new_owner.clone();490			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(491				collection_id,492				new_owner493			));494495			target_collection.save()496		}497498		/// Adds an admin of the Collection.499		/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.500		///501		/// # Permissions502		///503		/// * Collection Owner.504		/// * Collection Admin.505		///506		/// # Arguments507		///508		/// * collection_id: ID of the Collection to add admin for.509		///510		/// * new_admin_id: Address of new admin to add.511		#[weight = <SelfWeightOf<T>>::add_collection_admin()]512		#[transactional]513		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {514			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);515			let collection = <CollectionHandle<T>>::try_get(collection_id)?;516517			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(518				collection_id,519				new_admin_id.clone()520			));521522			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)523		}524525		/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.526		///527		/// # Permissions528		///529		/// * Collection Owner.530		/// * Collection Admin.531		///532		/// # Arguments533		///534		/// * collection_id: ID of the Collection to remove admin for.535		///536		/// * account_id: Address of admin to remove.537		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]538		#[transactional]539		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {540			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);541			let collection = <CollectionHandle<T>>::try_get(collection_id)?;542543			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(544				collection_id,545				account_id.clone()546			));547548			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)549		}550551		/// # Permissions552		///553		/// * Collection Owner554		///555		/// # Arguments556		///557		/// * collection_id.558		///559		/// * new_sponsor.560		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]561		#[transactional]562		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {563			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);564565			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;566			target_collection.check_is_owner(&sender)?;567568			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());569570			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(571				collection_id,572				new_sponsor573			));574575			target_collection.save()576		}577578		/// # Permissions579		///580		/// * Sponsor.581		///582		/// # Arguments583		///584		/// * collection_id.585		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]586		#[transactional]587		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {588			let sender = ensure_signed(origin)?;589590			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;591			ensure!(592				target_collection.sponsorship.pending_sponsor() == Some(&sender),593				Error::<T>::ConfirmUnsetSponsorFail594			);595596			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());597598			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(599				collection_id,600				sender601			));602603			target_collection.save()604		}605606		/// Switch back to pay-per-own-transaction model.607		///608		/// # Permissions609		///610		/// * Collection owner.611		///612		/// # Arguments613		///614		/// * collection_id.615		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]616		#[transactional]617		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {618			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);619620			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;621			target_collection.check_is_owner(&sender)?;622623			target_collection.sponsorship = SponsorshipState::Disabled;624625			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(626				collection_id627			));628			target_collection.save()629		}630631		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.632		///633		/// # Permissions634		///635		/// * Collection Owner.636		/// * Collection Admin.637		/// * Anyone if638		///     * Allow List is enabled, and639		///     * Address is added to allow list, and640		///     * MintPermission is enabled (see SetMintPermission method)641		///642		/// # Arguments643		///644		/// * collection_id: ID of the collection.645		///646		/// * owner: Address, initial owner of the NFT.647		///648		/// * data: Token data to store on chain.649		#[weight = T::CommonWeightInfo::create_item()]650		#[transactional]651		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {652			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);653			let budget = budget::Value::new(2);654655			dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))656		}657658		/// This method creates multiple items in a collection created with CreateCollection method.659		///660		/// # Permissions661		///662		/// * Collection Owner.663		/// * Collection Admin.664		/// * Anyone if665		///     * Allow List is enabled, and666		///     * Address is added to allow list, and667		///     * MintPermission is enabled (see SetMintPermission method)668		///669		/// # Arguments670		///671		/// * collection_id: ID of the collection.672		///673		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].674		///675		/// * owner: Address, initial owner of the NFT.676		#[weight = T::CommonWeightInfo::create_multiple_items(items_data.len() as u32)]677		#[transactional]678		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {679			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);680			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);681			let budget = budget::Value::new(2);682683			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))684		}685686		#[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]687		#[transactional]688		pub fn set_collection_properties(689			origin,690			collection_id: CollectionId,691			properties: Vec<Property>692		) -> DispatchResultWithPostInfo {693			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);694695			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);696697			dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))698		}699700		#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]701		#[transactional]702		pub fn delete_collection_properties(703			origin,704			collection_id: CollectionId,705			property_keys: Vec<PropertyKey>,706		) -> DispatchResultWithPostInfo {707			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);708709			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);710711			dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))712		}713714		#[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]715		#[transactional]716		pub fn set_token_properties(717			origin,718			collection_id: CollectionId,719			token_id: TokenId,720			properties: Vec<Property>721		) -> DispatchResultWithPostInfo {722			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);723724			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);725726			dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))727		}728729		#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]730		#[transactional]731		pub fn delete_token_properties(732			origin,733			collection_id: CollectionId,734			token_id: TokenId,735			property_keys: Vec<PropertyKey>736		) -> DispatchResultWithPostInfo {737			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);738739			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);740741			dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))742		}743744		#[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]745		#[transactional]746		pub fn set_property_permissions(747			origin,748			collection_id: CollectionId,749			property_permissions: Vec<PropertyKeyPermission>,750		) -> DispatchResultWithPostInfo {751			ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);752753			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);754755			dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))756		}757758		#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]759		#[transactional]760		pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {761			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);762			let budget = budget::Value::new(2);763764			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))765		}766767		// TODO! transaction weight768769		/// Set transfers_enabled value for particular collection770		///771		/// # Permissions772		///773		/// * Collection Owner.774		///775		/// # Arguments776		///777		/// * collection_id: ID of the collection.778		///779		/// * value: New flag value.780		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]781		#[transactional]782		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {783			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);784			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;785			target_collection.check_is_owner(&sender)?;786787			// =========788789			target_collection.limits.transfers_enabled = Some(value);790			target_collection.save()791		}792793		/// Destroys a concrete instance of NFT.794		///795		/// # Permissions796		///797		/// * Collection Owner.798		/// * Collection Admin.799		/// * Current NFT Owner.800		///801		/// # Arguments802		///803		/// * collection_id: ID of the collection.804		///805		/// * item_id: ID of NFT to burn.806		#[weight = T::CommonWeightInfo::burn_item()]807		#[transactional]808		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {809			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);810811			let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;812			if value == 1 {813				<NftTransferBasket<T>>::remove(collection_id, item_id);814				<NftApproveBasket<T>>::remove(collection_id, item_id);815			}816			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?817			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());818			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));819			Ok(post_info)820		}821822		/// Destroys a concrete instance of NFT on behalf of the owner823		/// See also: [`approve`]824		///825		/// # Permissions826		///827		/// * Collection Owner.828		/// * Collection Admin.829		/// * Current NFT Owner.830		///831		/// # Arguments832		///833		/// * collection_id: ID of the collection.834		///835		/// * item_id: ID of NFT to burn.836		///837		/// * from: owner of item838		#[weight = T::CommonWeightInfo::burn_from()]839		#[transactional]840		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {841			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);842			let budget = budget::Value::new(2);843844			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))845		}846847		/// Change ownership of the token.848		///849		/// # Permissions850		///851		/// * Collection Owner852		/// * Collection Admin853		/// * Current NFT owner854		///855		/// # Arguments856		///857		/// * recipient: Address of token recipient.858		///859		/// * collection_id.860		///861		/// * item_id: ID of the item862		///     * Non-Fungible Mode: Required.863		///     * Fungible Mode: Ignored.864		///     * Re-Fungible Mode: Required.865		///866		/// * value: Amount to transfer.867		///     * Non-Fungible Mode: Ignored868		///     * Fungible Mode: Must specify transferred amount869		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)870		#[weight = T::CommonWeightInfo::transfer()]871		#[transactional]872		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {873			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);874			let budget = budget::Value::new(2);875876			dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))877		}878879		/// Set, change, or remove approved address to transfer the ownership of the NFT.880		///881		/// # Permissions882		///883		/// * Collection Owner884		/// * Collection Admin885		/// * Current NFT owner886		///887		/// # Arguments888		///889		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).890		///891		/// * collection_id.892		///893		/// * item_id: ID of the item.894		#[weight = T::CommonWeightInfo::approve()]895		#[transactional]896		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {897			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);898899			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))900		}901902		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.903		///904		/// # Permissions905		/// * Collection Owner906		/// * Collection Admin907		/// * Current NFT owner908		/// * Address approved by current NFT owner909		///910		/// # Arguments911		///912		/// * from: Address that owns token.913		///914		/// * recipient: Address of token recipient.915		///916		/// * collection_id.917		///918		/// * item_id: ID of the item.919		///920		/// * value: Amount to transfer.921		#[weight = T::CommonWeightInfo::transfer_from()]922		#[transactional]923		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {924			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);925			let budget = budget::Value::new(2);926927			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))928		}929930		/// Set meta_update_permission value for particular collection931		///932		/// # Permissions933		///934		/// * Collection Owner.935		///936		/// # Arguments937		///938		/// * collection_id: ID of the collection.939		///940		/// * value: New flag value.941		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]942		#[transactional]943		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {944			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);945			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;946947			ensure!(948				target_collection.meta_update_permission != MetaUpdatePermission::None,949				<CommonError<T>>::MetadataFlagFrozen,950			);951			target_collection.check_is_owner(&sender)?;952953			target_collection.meta_update_permission = value;954955			target_collection.save()956		}957958		/// Set schema standard959		/// ImageURL960		/// Unique961		///962		/// # Permissions963		///964		/// * Collection Owner965		/// * Collection Admin966		///967		/// # Arguments968		///969		/// * collection_id.970		///971		/// * schema: SchemaVersion: enum972		#[weight = <SelfWeightOf<T>>::set_schema_version()]973		#[transactional]974		pub fn set_schema_version(975			origin,976			collection_id: CollectionId,977			version: SchemaVersion978		) -> DispatchResult {979			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);980			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;981			target_collection.check_is_owner_or_admin(&sender)?;982			target_collection.schema_version = version;983984			<Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(985				collection_id986			));987988			target_collection.save()989		}990991		/// Set off-chain data schema.992		///993		/// # Permissions994		///995		/// * Collection Owner996		/// * Collection Admin997		///998		/// # Arguments999		///1000		/// * collection_id.1001		///1002		/// * schema: String representing the offchain data schema.1003		#[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]1004		#[transactional]1005		pub fn set_offchain_schema(1006			origin,1007			collection_id: CollectionId,1008			schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,1009		) -> DispatchResult {1010			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1011			let collection = <CollectionHandle<T>>::try_get(collection_id)?;10121013			// =========10141015			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;10161017			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(1018				collection_id1019			));1020			Ok(())1021		}10221023		/// Set const on-chain data schema.1024		///1025		/// # Permissions1026		///1027		/// * Collection Owner1028		/// * Collection Admin1029		///1030		/// # Arguments1031		///1032		/// * collection_id.1033		///1034		/// * schema: String representing the const on-chain data schema.1035		#[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]1036		#[transactional]1037		pub fn set_const_on_chain_schema (1038			origin,1039			collection_id: CollectionId,1040			schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>1041		) -> DispatchResult {1042			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1043			let collection = <CollectionHandle<T>>::try_get(collection_id)?;10441045			// =========10461047			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;10481049			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(1050				collection_id1051			));1052			Ok(())1053		}10541055		#[weight = <SelfWeightOf<T>>::set_collection_limits()]1056		#[transactional]1057		pub fn set_collection_limits(1058			origin,1059			collection_id: CollectionId,1060			new_limit: CollectionLimits,1061		) -> DispatchResult {1062			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1063			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1064			target_collection.check_is_owner(&sender)?;1065			let old_limit = &target_collection.limits;10661067			target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;10681069			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1070				collection_id1071			));10721073			target_collection.save()1074		}1075	}1076}
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -364,28 +364,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)]
@@ -393,6 +371,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
@@ -490,9 +470,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"))]
@@ -512,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>,
 	pub pieces: u128,
 }
 
@@ -545,8 +519,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,
@@ -557,8 +529,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>>,
 }
@@ -586,8 +556,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,
 		}
 	}
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -42,7 +42,6 @@
 		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>>;
 
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -32,9 +32,6 @@
                 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,
modifiedruntime/common/src/sponsoring.rsdiffbeforeafterboth
--- a/runtime/common/src/sponsoring.rs
+++ b/runtime/common/src/sponsoring.rs
@@ -21,7 +21,7 @@
 	storage::{StorageMap, StorageDoubleMap, StorageNMap},
 };
 use up_data_structs::{
-	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MetaUpdatePermission,
+	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
 	NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode,
 	CreateItemData,
 };
@@ -30,7 +30,7 @@
 use pallet_evm::account::CrossAccountId;
 use pallet_unique::{
 	Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,
-	NftApproveBasket, VariableMetaDataBasket, CreateItemBasket, ReFungibleTransferBasket,
+	NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket,
 	FungibleTransferBasket, NftTransferBasket,
 };
 use pallet_fungible::Config as FungibleConfig;
@@ -139,64 +139,7 @@
 
 	Some(())
 }
-
-pub fn withdraw_set_variable_meta_data<T: Config>(
-	who: &T::CrossAccountId,
-	collection: &CollectionHandle<T>,
-	item_id: &TokenId,
-	data: &[u8],
-) -> Option<()> {
-	// TODO: make it work for admins
-	if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {
-		return None;
-	}
-	// preliminary sponsoring correctness check
-	match collection.mode {
-		CollectionMode::NFT => {
-			let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;
-			if !owner.conv_eq(who) {
-				return None;
-			}
-		}
-		CollectionMode::Fungible(_) => {
-			if item_id != &TokenId::default() {
-				return None;
-			}
-			if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {
-				return None;
-			}
-		}
-		CollectionMode::ReFungible => {
-			if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {
-				return None;
-			}
-		}
-	}
 
-	// Can't sponsor fungible collection, this tx will be rejected
-	// as invalid
-	if matches!(collection.mode, CollectionMode::Fungible(_)) {
-		return None;
-	}
-	if data.len() > collection.limits.sponsored_data_size() as usize {
-		return None;
-	}
-
-	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-	let limit = collection.limits.sponsored_data_rate_limit()?;
-
-	if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
-		let timeout = last_tx_block + limit.into();
-		if block_number < timeout {
-			return None;
-		}
-	}
-
-	<VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);
-
-	Some(())
-}
-
 pub fn withdraw_approve<T: Config>(
 	collection: &CollectionHandle<T>,
 	who: &T::AccountId,
@@ -290,20 +233,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
--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -47,7 +47,6 @@
 fn default_nft_data() -> CreateNftData {
 	CreateNftData {
 		const_data: vec![1, 2, 3].try_into().unwrap(),
-		variable_data: vec![3, 2, 1].try_into().unwrap(),
 	}
 }
 
@@ -58,7 +57,6 @@
 fn default_re_fungible_data() -> CreateReFungibleData {
 	CreateReFungibleData {
 		const_data: vec![1, 2, 3].try_into().unwrap(),
-		variable_data: vec![3, 2, 1].try_into().unwrap(),
 		pieces: 1023,
 	}
 }
@@ -215,7 +213,6 @@
 
 		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();
 		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
 	});
 }
 
@@ -247,7 +244,6 @@
 			))
 			.unwrap();
 			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
-			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
 		}
 	});
 }
@@ -263,7 +259,6 @@
 		let balance =
 			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));
 		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
 		assert_eq!(balance, 1023);
 	});
 }
@@ -299,7 +294,6 @@
 			let balance =
 				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));
 			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
-			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
 			assert_eq!(balance, 1023);
 		}
 	});
@@ -413,7 +407,6 @@
 		create_test_item(collection_id, &data.clone().into());
 		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
 		assert_eq!(item.const_data, data.const_data.into_inner());
-		assert_eq!(item.variable_data, data.variable_data.into_inner());
 		assert_eq!(
 			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),
 			1
@@ -2427,117 +2420,6 @@
 }
 
 #[test]
-fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(CollectionId(1), &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_ok!(Unique::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_re_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_ok!(Unique::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_fungible_token_fails() {
-	new_test_ext().execute_with(|| {
-		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_fungible_data();
-		create_test_item(collection_id, &data.into());
-
-		let variable_data = b"test data".to_vec();
-		assert_noop!(
-			Unique::set_variable_meta_data(
-				origin1,
-				collection_id,
-				TokenId(0),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {
-	new_test_ext().execute_with(|| {
-		//default_limits();
-
-		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(Unique::set_meta_update_permission_flag(
-			origin1.clone(),
-			collection_id,
-			MetaUpdatePermission::ItemOwner,
-		));
-
-		let variable_data = b"ten chars.".to_vec();
-		assert_ok!(Unique::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
 fn collection_transfer_flag_works() {
 	new_test_ext().execute_with(|| {
 		let origin1 = Origin::signed(1);
@@ -2590,105 +2472,6 @@
 }
 
 #[test]
-fn set_variable_meta_data_on_nft_with_admin_flag() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(Unique::set_mint_permission(
-			origin2.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(Unique::add_to_allow_list(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		assert_ok!(Unique::add_collection_admin(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(Unique::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::Admin,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_ok!(Unique::set_variable_meta_data(
-			origin1,
-			collection_id,
-			TokenId(1),
-			variable_data.clone().try_into().unwrap()
-		));
-
-		assert_eq!(
-			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))
-				.unwrap()
-				.variable_data,
-			variable_data
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_admin_flag_neg() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin1 = Origin::signed(1);
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(Unique::set_mint_permission(
-			origin2.clone(),
-			collection_id,
-			true
-		));
-		assert_ok!(Unique::add_to_allow_list(
-			origin2.clone(),
-			collection_id,
-			account(1)
-		));
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(Unique::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::Admin,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_noop!(
-			Unique::set_variable_meta_data(
-				origin1,
-				collection_id,
-				TokenId(1),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::NoPermission
-		);
-	});
-}
-
-#[test]
 fn set_variable_meta_flag_after_freeze() {
 	new_test_ext().execute_with(|| {
 		// default_limits();
@@ -2710,38 +2493,6 @@
 				MetaUpdatePermission::Admin
 			),
 			CommonError::<Test>::MetadataFlagFrozen
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_data_on_nft_with_none_flag_neg() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		let origin1 = Origin::signed(1);
-
-		let data = default_nft_data();
-		create_test_item(collection_id, &data.into());
-
-		assert_ok!(Unique::set_meta_update_permission_flag(
-			origin1.clone(),
-			collection_id,
-			MetaUpdatePermission::None,
-		));
-
-		let variable_data = b"test.".to_vec();
-		assert_noop!(
-			Unique::set_variable_meta_data(
-				origin1.clone(),
-				collection_id,
-				TokenId(1),
-				variable_data.try_into().unwrap()
-			)
-			.map_err(|e| e.error),
-			CommonError::<Test>::NoPermission
 		);
 	});
 }
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) {