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
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -38,7 +38,7 @@
 	CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,
 	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
 	AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,
-	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,
+	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData,
 	CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,
 };
 use pallet_evm::account::CrossAccountId;
@@ -238,9 +238,6 @@
 		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>;
 		//#endregion
 
-		/// Variable metadata sponsoring
-		/// Collection id (controlled?2), token id (controlled?2)
-		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
 		/// Approval sponsoring
 		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
 		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
@@ -333,7 +330,6 @@
 			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);
 			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);
 
-			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);
 			<NftApproveBasket<T>>::remove_prefix(collection_id, None);
 			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);
 			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);
@@ -929,31 +925,6 @@
 			let budget = budget::Value::new(2);
 
 			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))
-		}
-
-		/// Set off-chain data schema.
-		///
-		/// # Permissions
-		///
-		/// * Collection Owner
-		/// * Collection Admin
-		///
-		/// # Arguments
-		///
-		/// * collection_id.
-		///
-		/// * schema: String representing the offchain data schema.
-		#[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]
-		#[transactional]
-		pub fn set_variable_meta_data (
-			origin,
-			collection_id: CollectionId,
-			item_id: TokenId,
-			data: BoundedVec<u8, CustomDataLimit>,
-		) -> DispatchResultWithPostInfo {
-			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-
-			dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))
 		}
 
 		/// Set meta_update_permission value for particular collection
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
before · primitives/data-structs/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#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20	convert::{TryFrom, TryInto},21	fmt,22};23use frame_support::{24	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25	traits::Get,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;3738mod bounded;39pub mod budget;40pub mod mapping;41mod migration;4243pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;44pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;45pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;4647pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {48	100_00049} else {50	1051};52pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {53	100_00054} else {55	1056};57pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {58	204859} else {60	1061};62pub const COLLECTION_ADMINS_LIMIT: u32 = 5;63pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;64pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {65	1_000_00066} else {67	1068};6970// Timeouts for item types in passed blocks71pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;72pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;73pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;7475pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;7677// Schema limits78pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;79pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;80pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8182pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;8384pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;85pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;86pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8788pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;89pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;90pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;9192// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;93pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;94pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;9596pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =97	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;9899pub struct MaxPropertiesPermissionsEncodeLen;100101impl Get<u32> for MaxPropertiesPermissionsEncodeLen {102	fn get() -> u32 {103		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH104			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32105	}106}107108/// How much items can be created per single109/// create_many call110pub const MAX_ITEMS_PER_BATCH: u32 = 200;111112pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;113114#[derive(115	Encode,116	Decode,117	PartialEq,118	Eq,119	PartialOrd,120	Ord,121	Clone,122	Copy,123	Debug,124	Default,125	TypeInfo,126	MaxEncodedLen,127)]128#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]129pub struct CollectionId(pub u32);130impl EncodeLike<u32> for CollectionId {}131impl EncodeLike<CollectionId> for u32 {}132133#[derive(134	Encode,135	Decode,136	PartialEq,137	Eq,138	PartialOrd,139	Ord,140	Clone,141	Copy,142	Debug,143	Default,144	TypeInfo,145	MaxEncodedLen,146)]147#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]148pub struct TokenId(pub u32);149impl EncodeLike<u32> for TokenId {}150impl EncodeLike<TokenId> for u32 {}151152impl TokenId {153	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {154		self.0155			.checked_add(1)156			.ok_or(ArithmeticError::Overflow)157			.map(Self)158	}159}160161impl From<TokenId> for U256 {162	fn from(t: TokenId) -> Self {163		t.0.into()164	}165}166167impl TryFrom<U256> for TokenId {168	type Error = &'static str;169170	fn try_from(value: U256) -> Result<Self, Self::Error> {171		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))172	}173}174175#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]176#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]177pub struct TokenData<CrossAccountId> {178	pub const_data: Vec<u8>,179	pub properties: Vec<Property>,180	pub owner: Option<CrossAccountId>,181}182183pub struct OverflowError;184impl From<OverflowError> for &'static str {185	fn from(_: OverflowError) -> Self {186		"overflow occured"187	}188}189190pub type DecimalPoints = u8;191192#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]193#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]194pub enum CollectionMode {195	NFT,196	// decimal points197	Fungible(DecimalPoints),198	ReFungible,199}200201impl CollectionMode {202	pub fn id(&self) -> u8 {203		match self {204			CollectionMode::NFT => 1,205			CollectionMode::Fungible(_) => 2,206			CollectionMode::ReFungible => 3,207		}208	}209}210211pub trait SponsoringResolve<AccountId, Call> {212	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;213}214215#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]216#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]217pub enum AccessMode {218	Normal,219	AllowList,220}221impl Default for AccessMode {222	fn default() -> Self {223		Self::Normal224	}225}226227#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]228#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]229pub enum SchemaVersion {230	ImageURL,231	Unique,232}233impl Default for SchemaVersion {234	fn default() -> Self {235		Self::ImageURL236	}237}238239#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]240#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]241pub struct Ownership<AccountId> {242	pub owner: AccountId,243	pub fraction: u128,244}245246#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]247#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]248pub enum SponsorshipState<AccountId> {249	/// The fees are applied to the transaction sender250	Disabled,251	Unconfirmed(AccountId),252	/// Transactions are sponsored by specified account253	Confirmed(AccountId),254}255256impl<AccountId> SponsorshipState<AccountId> {257	pub fn sponsor(&self) -> Option<&AccountId> {258		match self {259			Self::Confirmed(sponsor) => Some(sponsor),260			_ => None,261		}262	}263264	pub fn pending_sponsor(&self) -> Option<&AccountId> {265		match self {266			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),267			_ => None,268		}269	}270271	pub fn confirmed(&self) -> bool {272		matches!(self, Self::Confirmed(_))273	}274}275276impl<T> Default for SponsorshipState<T> {277	fn default() -> Self {278		Self::Disabled279	}280}281282/// Used in storage283#[struct_versioning::versioned(version = 2, upper)]284#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]285pub struct Collection<AccountId> {286	pub owner: AccountId,287	pub mode: CollectionMode,288	pub access: AccessMode,289	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,290	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,291	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,292	pub mint_mode: bool,293294	#[version(..2)]295	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,296297	pub schema_version: SchemaVersion,298	pub sponsorship: SponsorshipState<AccountId>,299300	#[version(..2)]301	pub limits: CollectionLimitsVersion1, // Collection private restrictions302	#[version(2.., upper(limits.into()))]303	pub limits: CollectionLimitsVersion2,304305	#[version(..2)]306	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,307308	#[version(..2)]309	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,310311	pub meta_update_permission: MetaUpdatePermission,312}313314/// Used in RPC calls315#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]316#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]317pub struct RpcCollection<AccountId> {318	pub owner: AccountId,319	pub mode: CollectionMode,320	pub access: AccessMode,321	pub name: Vec<u16>,322	pub description: Vec<u16>,323	pub token_prefix: Vec<u8>,324	pub mint_mode: bool,325	pub offchain_schema: Vec<u8>,326	pub schema_version: SchemaVersion,327	pub sponsorship: SponsorshipState<AccountId>,328	pub limits: CollectionLimits,329	pub const_on_chain_schema: Vec<u8>,330	pub meta_update_permission: MetaUpdatePermission,331	pub token_property_permissions: Vec<PropertyKeyPermission>,332	pub properties: Vec<Property>,333}334335#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]336#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]337pub enum CollectionField {338	ConstOnChainSchema,339	OffchainSchema,340}341342#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]343#[derivative(Debug, Default(bound = ""))]344pub struct CreateCollectionData<AccountId> {345	#[derivative(Default(value = "CollectionMode::NFT"))]346	pub mode: CollectionMode,347	pub access: Option<AccessMode>,348	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,349	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,350	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,351	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,352	pub schema_version: Option<SchemaVersion>,353	pub pending_sponsor: Option<AccountId>,354	pub limits: Option<CollectionLimits>,355	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,356	pub meta_update_permission: Option<MetaUpdatePermission>,357	pub token_property_permissions: CollectionPropertiesPermissionsVec,358	pub properties: CollectionPropertiesVec,359}360361pub type CollectionPropertiesPermissionsVec =362	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;363364pub type CollectionPropertiesVec =365	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;366367#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]368#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]369pub struct NftItemType<AccountId> {370	pub owner: AccountId,371	pub const_data: Vec<u8>,372	pub variable_data: Vec<u8>,373}374375#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]376#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]377pub struct FungibleItemType {378	pub value: u128,379}380381#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]382#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]383pub struct ReFungibleItemType<AccountId> {384	pub owner: Vec<Ownership<AccountId>>,385	pub const_data: Vec<u8>,386	pub variable_data: Vec<u8>,387}388389/// All fields are wrapped in `Option`s, where None means chain default390#[struct_versioning::versioned(version = 2, upper)]391#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]392#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]393pub struct CollectionLimits {394	pub account_token_ownership_limit: Option<u32>,395	pub sponsored_data_size: Option<u32>,396	/// None - setVariableMetadata is not sponsored397	/// Some(v) - setVariableMetadata is sponsored398	///           if there is v block between txs399	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,400	pub token_limit: Option<u32>,401402	// Timeouts for item types in passed blocks403	pub sponsor_transfer_timeout: Option<u32>,404	pub sponsor_approve_timeout: Option<u32>,405	pub owner_can_transfer: Option<bool>,406	pub owner_can_destroy: Option<bool>,407	pub transfers_enabled: Option<bool>,408409	#[version(2.., upper(None))]410	pub nesting_rule: Option<NestingRule>,411}412413impl CollectionLimits {414	pub fn account_token_ownership_limit(&self) -> u32 {415		self.account_token_ownership_limit416			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)417			.min(MAX_TOKEN_OWNERSHIP)418	}419	pub fn sponsored_data_size(&self) -> u32 {420		self.sponsored_data_size421			.unwrap_or(CUSTOM_DATA_LIMIT)422			.min(CUSTOM_DATA_LIMIT)423	}424	pub fn token_limit(&self) -> u32 {425		self.token_limit426			.unwrap_or(COLLECTION_TOKEN_LIMIT)427			.min(COLLECTION_TOKEN_LIMIT)428	}429	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {430		self.sponsor_transfer_timeout431			.unwrap_or(default)432			.min(MAX_SPONSOR_TIMEOUT)433	}434	pub fn sponsor_approve_timeout(&self) -> u32 {435		self.sponsor_approve_timeout436			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)437			.min(MAX_SPONSOR_TIMEOUT)438	}439	pub fn owner_can_transfer(&self) -> bool {440		self.owner_can_transfer.unwrap_or(true)441	}442	pub fn owner_can_destroy(&self) -> bool {443		self.owner_can_destroy.unwrap_or(true)444	}445	pub fn transfers_enabled(&self) -> bool {446		self.transfers_enabled.unwrap_or(true)447	}448	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {449		match self450			.sponsored_data_rate_limit451			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)452		{453			SponsoringRateLimit::SponsoringDisabled => None,454			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),455		}456	}457	pub fn nesting_rule(&self) -> &NestingRule {458		static DEFAULT: NestingRule = NestingRule::Disabled;459		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)460	}461}462463#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]464#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]465#[derivative(Debug)]466pub enum NestingRule {467	/// No one can nest tokens468	Disabled,469	/// Owner can nest any tokens470	Owner,471	/// Owner can nest tokens from specified collections472	OwnerRestricted(473		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]474		#[derivative(Debug(format_with = "bounded::set_debug"))]475		BoundedBTreeSet<CollectionId, ConstU32<16>>,476	),477}478479#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]480#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]481pub enum SponsoringRateLimit {482	SponsoringDisabled,483	Blocks(u32),484}485486#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]487#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]488#[derivative(Debug)]489pub struct CreateNftData {490	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]491	#[derivative(Debug(format_with = "bounded::vec_debug"))]492	pub const_data: BoundedVec<u8, CustomDataLimit>,493	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]494	#[derivative(Debug(format_with = "bounded::vec_debug"))]495	pub variable_data: BoundedVec<u8, CustomDataLimit>,496497	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]498	#[derivative(Debug(format_with = "bounded::vec_debug"))]499	pub properties: CollectionPropertiesVec,500}501502#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]503#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]504pub struct CreateFungibleData {505	pub value: u128,506}507508#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]509#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]510#[derivative(Debug)]511pub struct CreateReFungibleData {512	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]513	#[derivative(Debug(format_with = "bounded::vec_debug"))]514	pub const_data: BoundedVec<u8, CustomDataLimit>,515	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]516	#[derivative(Debug(format_with = "bounded::vec_debug"))]517	pub variable_data: BoundedVec<u8, CustomDataLimit>,518	pub pieces: u128,519}520521#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]522#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]523pub enum MetaUpdatePermission {524	ItemOwner,525	Admin,526	None,527}528529impl Default for MetaUpdatePermission {530	fn default() -> Self {531		Self::ItemOwner532	}533}534535#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]536#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]537pub enum CreateItemData {538	NFT(CreateNftData),539	Fungible(CreateFungibleData),540	ReFungible(CreateReFungibleData),541}542543#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]544#[derivative(Debug)]545pub struct CreateNftExData<CrossAccountId> {546	#[derivative(Debug(format_with = "bounded::vec_debug"))]547	pub const_data: BoundedVec<u8, CustomDataLimit>,548	#[derivative(Debug(format_with = "bounded::vec_debug"))]549	pub variable_data: BoundedVec<u8, CustomDataLimit>,550	#[derivative(Debug(format_with = "bounded::vec_debug"))]551	pub properties: CollectionPropertiesVec,552	pub owner: CrossAccountId,553}554555#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]556#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]557pub struct CreateRefungibleExData<CrossAccountId> {558	#[derivative(Debug(format_with = "bounded::vec_debug"))]559	pub const_data: BoundedVec<u8, CustomDataLimit>,560	#[derivative(Debug(format_with = "bounded::vec_debug"))]561	pub variable_data: BoundedVec<u8, CustomDataLimit>,562	#[derivative(Debug(format_with = "bounded::map_debug"))]563	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,564}565566#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]567#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]568pub enum CreateItemExData<CrossAccountId> {569	NFT(570		#[derivative(Debug(format_with = "bounded::vec_debug"))]571		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,572	),573	Fungible(574		#[derivative(Debug(format_with = "bounded::map_debug"))]575		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,576	),577	/// Many tokens, each may have only one owner578	RefungibleMultipleItems(579		#[derivative(Debug(format_with = "bounded::vec_debug"))]580		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,581	),582	/// Single token, which may have many owners583	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),584}585586impl CreateItemData {587	pub fn data_size(&self) -> usize {588		match self {589			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),590			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),591			_ => 0,592		}593	}594}595596impl From<CreateNftData> for CreateItemData {597	fn from(item: CreateNftData) -> Self {598		CreateItemData::NFT(item)599	}600}601602impl From<CreateReFungibleData> for CreateItemData {603	fn from(item: CreateReFungibleData) -> Self {604		CreateItemData::ReFungible(item)605	}606}607608impl From<CreateFungibleData> for CreateItemData {609	fn from(item: CreateFungibleData) -> Self {610		CreateItemData::Fungible(item)611	}612}613614#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]615#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]616pub struct CollectionStats {617	pub created: u32,618	pub destroyed: u32,619	pub alive: u32,620}621622#[derive(Encode, Decode, PartialEq, Clone, Debug)]623pub struct PhantomType<T>(core::marker::PhantomData<T>);624625impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {626	type Identity = PhantomType<T>;627628	fn type_info() -> scale_info::Type {629		use scale_info::{630			Type, Path,631			build::{FieldsBuilder, UnnamedFields},632			type_params,633		};634		Type::builder()635			.path(Path::new("up_data_structs", "PhantomType"))636			.type_params(type_params!(T))637			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))638	}639}640impl<T> MaxEncodedLen for PhantomType<T> {641	fn max_encoded_len() -> usize {642		0643	}644}645646pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;647pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;648649#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]650#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]651pub struct PropertyPermission {652	pub mutable: bool,653	pub collection_admin: bool,654	pub token_owner: bool,655}656657impl PropertyPermission {658	pub fn none() -> Self {659		Self {660			mutable: true,661			collection_admin: false,662			token_owner: false,663		}664	}665}666667#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]668#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]669pub struct Property {670	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]671	pub key: PropertyKey,672673	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]674	pub value: PropertyValue,675}676677#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]678#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]679pub struct PropertyKeyPermission {680	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]681	pub key: PropertyKey,682683	pub permission: PropertyPermission,684}685686pub enum PropertiesError {687	NoSpaceForProperty,688	PropertyLimitReached,689	InvalidCharacterInPropertyKey,690	EmptyPropertyKey,691}692693pub trait TrySet: Sized {694	type Value;695696	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;697698	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>699	where700		I: Iterator<Item = (PropertyKey, Self::Value)>,701	{702		for (key, value) in iter {703			self.try_set(key, value)?;704		}705706		Ok(())707	}708}709710#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]711#[derivative(Default(bound = ""))]712pub struct PropertiesMap<Value>(713	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,714);715716impl<Value> PropertiesMap<Value> {717	pub fn new() -> Self {718		Self(BoundedBTreeMap::new())719	}720721	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {722		Self::check_property_key(key)?;723724		Ok(self.0.remove(key))725	}726727	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {728		self.0.get(key)729	}730731	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {732		self.0.iter()733	}734735	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {736		if key.is_empty() {737			return Err(PropertiesError::EmptyPropertyKey);738		}739740		for byte in key.as_slice().iter() {741			match char::from_u32(*byte as u32) {742				Some(ch)743					if ch.is_ascii_alphanumeric()744					|| ch == '_'745					|| ch == '-' => { /* OK */ },746				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)747			}748		}749750		Ok(())751	}752}753754impl<Value> TrySet for PropertiesMap<Value> {755	type Value = Value;756757	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {758		Self::check_property_key(&key)?;759760		self.0761			.try_insert(key, value)762			.map_err(|_| PropertiesError::PropertyLimitReached)?;763764		Ok(())765	}766}767768pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;769770#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]771pub struct Properties {772	map: PropertiesMap<PropertyValue>,773	consumed_space: u32,774	space_limit: u32,775}776777impl Properties {778	pub fn new(space_limit: u32) -> Self {779		Self {780			map: PropertiesMap::new(),781			consumed_space: 0,782			space_limit,783		}784	}785786	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {787		let value = self.map.remove(key)?;788789		if let Some(ref value) = value {790			let value_len = value.len() as u32;791			self.consumed_space -= value_len;792		}793794		Ok(value)795	}796797	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {798		self.map.get(key)799	}800801	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {802		self.map.iter()803	}804}805806impl TrySet for Properties {807	type Value = PropertyValue;808809	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {810		let value_len = value.len();811812		if self.consumed_space as usize + value_len > self.space_limit as usize {813			return Err(PropertiesError::NoSpaceForProperty);814		}815816		self.map.try_set(key, value)?;817818		self.consumed_space += value_len as u32;819820		Ok(())821	}822}823824pub struct CollectionProperties;825826impl Get<Properties> for CollectionProperties {827	fn get() -> Properties {828		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)829	}830}831832pub struct TokenProperties;833834impl Get<Properties> for TokenProperties {835	fn get() -> Properties {836		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)837	}838}
after · primitives/data-structs/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#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20	convert::{TryFrom, TryInto},21	fmt,22};23use frame_support::{24	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25	traits::Get,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;3738mod bounded;39pub mod budget;40pub mod mapping;41mod migration;4243pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;44pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;45pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;4647pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {48	100_00049} else {50	1051};52pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {53	100_00054} else {55	1056};57pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {58	204859} else {60	1061};62pub const COLLECTION_ADMINS_LIMIT: u32 = 5;63pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;64pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {65	1_000_00066} else {67	1068};6970// Timeouts for item types in passed blocks71pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;72pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;73pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;7475pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;7677// Schema limits78pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;79pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;80pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8182pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;8384pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;85pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;86pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8788pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;89pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;90pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;9192// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;93pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;94pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;9596pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =97	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;9899pub struct MaxPropertiesPermissionsEncodeLen;100101impl Get<u32> for MaxPropertiesPermissionsEncodeLen {102	fn get() -> u32 {103		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH104			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32105	}106}107108/// How much items can be created per single109/// create_many call110pub const MAX_ITEMS_PER_BATCH: u32 = 200;111112pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;113114#[derive(115	Encode,116	Decode,117	PartialEq,118	Eq,119	PartialOrd,120	Ord,121	Clone,122	Copy,123	Debug,124	Default,125	TypeInfo,126	MaxEncodedLen,127)]128#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]129pub struct CollectionId(pub u32);130impl EncodeLike<u32> for CollectionId {}131impl EncodeLike<CollectionId> for u32 {}132133#[derive(134	Encode,135	Decode,136	PartialEq,137	Eq,138	PartialOrd,139	Ord,140	Clone,141	Copy,142	Debug,143	Default,144	TypeInfo,145	MaxEncodedLen,146)]147#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]148pub struct TokenId(pub u32);149impl EncodeLike<u32> for TokenId {}150impl EncodeLike<TokenId> for u32 {}151152impl TokenId {153	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {154		self.0155			.checked_add(1)156			.ok_or(ArithmeticError::Overflow)157			.map(Self)158	}159}160161impl From<TokenId> for U256 {162	fn from(t: TokenId) -> Self {163		t.0.into()164	}165}166167impl TryFrom<U256> for TokenId {168	type Error = &'static str;169170	fn try_from(value: U256) -> Result<Self, Self::Error> {171		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))172	}173}174175#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]176#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]177pub struct TokenData<CrossAccountId> {178	pub const_data: Vec<u8>,179	pub properties: Vec<Property>,180	pub owner: Option<CrossAccountId>,181}182183pub struct OverflowError;184impl From<OverflowError> for &'static str {185	fn from(_: OverflowError) -> Self {186		"overflow occured"187	}188}189190pub type DecimalPoints = u8;191192#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]193#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]194pub enum CollectionMode {195	NFT,196	// decimal points197	Fungible(DecimalPoints),198	ReFungible,199}200201impl CollectionMode {202	pub fn id(&self) -> u8 {203		match self {204			CollectionMode::NFT => 1,205			CollectionMode::Fungible(_) => 2,206			CollectionMode::ReFungible => 3,207		}208	}209}210211pub trait SponsoringResolve<AccountId, Call> {212	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;213}214215#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]216#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]217pub enum AccessMode {218	Normal,219	AllowList,220}221impl Default for AccessMode {222	fn default() -> Self {223		Self::Normal224	}225}226227#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]228#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]229pub enum SchemaVersion {230	ImageURL,231	Unique,232}233impl Default for SchemaVersion {234	fn default() -> Self {235		Self::ImageURL236	}237}238239#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]240#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]241pub struct Ownership<AccountId> {242	pub owner: AccountId,243	pub fraction: u128,244}245246#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]247#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]248pub enum SponsorshipState<AccountId> {249	/// The fees are applied to the transaction sender250	Disabled,251	Unconfirmed(AccountId),252	/// Transactions are sponsored by specified account253	Confirmed(AccountId),254}255256impl<AccountId> SponsorshipState<AccountId> {257	pub fn sponsor(&self) -> Option<&AccountId> {258		match self {259			Self::Confirmed(sponsor) => Some(sponsor),260			_ => None,261		}262	}263264	pub fn pending_sponsor(&self) -> Option<&AccountId> {265		match self {266			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),267			_ => None,268		}269	}270271	pub fn confirmed(&self) -> bool {272		matches!(self, Self::Confirmed(_))273	}274}275276impl<T> Default for SponsorshipState<T> {277	fn default() -> Self {278		Self::Disabled279	}280}281282/// Used in storage283#[struct_versioning::versioned(version = 2, upper)]284#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]285pub struct Collection<AccountId> {286	pub owner: AccountId,287	pub mode: CollectionMode,288	pub access: AccessMode,289	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,290	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,291	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,292	pub mint_mode: bool,293294	#[version(..2)]295	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,296297	pub schema_version: SchemaVersion,298	pub sponsorship: SponsorshipState<AccountId>,299300	#[version(..2)]301	pub limits: CollectionLimitsVersion1, // Collection private restrictions302	#[version(2.., upper(limits.into()))]303	pub limits: CollectionLimitsVersion2,304305	#[version(..2)]306	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,307308	#[version(..2)]309	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,310311	pub meta_update_permission: MetaUpdatePermission,312}313314/// Used in RPC calls315#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]316#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]317pub struct RpcCollection<AccountId> {318	pub owner: AccountId,319	pub mode: CollectionMode,320	pub access: AccessMode,321	pub name: Vec<u16>,322	pub description: Vec<u16>,323	pub token_prefix: Vec<u8>,324	pub mint_mode: bool,325	pub offchain_schema: Vec<u8>,326	pub schema_version: SchemaVersion,327	pub sponsorship: SponsorshipState<AccountId>,328	pub limits: CollectionLimits,329	pub const_on_chain_schema: Vec<u8>,330	pub meta_update_permission: MetaUpdatePermission,331	pub token_property_permissions: Vec<PropertyKeyPermission>,332	pub properties: Vec<Property>,333}334335#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]336#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]337pub enum CollectionField {338	ConstOnChainSchema,339	OffchainSchema,340}341342#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]343#[derivative(Debug, Default(bound = ""))]344pub struct CreateCollectionData<AccountId> {345	#[derivative(Default(value = "CollectionMode::NFT"))]346	pub mode: CollectionMode,347	pub access: Option<AccessMode>,348	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,349	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,350	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,351	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,352	pub schema_version: Option<SchemaVersion>,353	pub pending_sponsor: Option<AccountId>,354	pub limits: Option<CollectionLimits>,355	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,356	pub meta_update_permission: Option<MetaUpdatePermission>,357	pub token_property_permissions: CollectionPropertiesPermissionsVec,358	pub properties: CollectionPropertiesVec,359}360361pub type CollectionPropertiesPermissionsVec =362	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;363364pub type CollectionPropertiesVec =365	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;366367/// All fields are wrapped in `Option`s, where None means chain default368#[struct_versioning::versioned(version = 2, upper)]369#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]370#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]371pub struct CollectionLimits {372	pub account_token_ownership_limit: Option<u32>,373	pub sponsored_data_size: Option<u32>,374375	/// FIXME should we delete this or repurpose it?376	/// None - setVariableMetadata is not sponsored377	/// Some(v) - setVariableMetadata is sponsored378	///           if there is v block between txs379	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,380	pub token_limit: Option<u32>,381382	// Timeouts for item types in passed blocks383	pub sponsor_transfer_timeout: Option<u32>,384	pub sponsor_approve_timeout: Option<u32>,385	pub owner_can_transfer: Option<bool>,386	pub owner_can_destroy: Option<bool>,387	pub transfers_enabled: Option<bool>,388389	#[version(2.., upper(None))]390	pub nesting_rule: Option<NestingRule>,391}392393impl CollectionLimits {394	pub fn account_token_ownership_limit(&self) -> u32 {395		self.account_token_ownership_limit396			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)397			.min(MAX_TOKEN_OWNERSHIP)398	}399	pub fn sponsored_data_size(&self) -> u32 {400		self.sponsored_data_size401			.unwrap_or(CUSTOM_DATA_LIMIT)402			.min(CUSTOM_DATA_LIMIT)403	}404	pub fn token_limit(&self) -> u32 {405		self.token_limit406			.unwrap_or(COLLECTION_TOKEN_LIMIT)407			.min(COLLECTION_TOKEN_LIMIT)408	}409	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {410		self.sponsor_transfer_timeout411			.unwrap_or(default)412			.min(MAX_SPONSOR_TIMEOUT)413	}414	pub fn sponsor_approve_timeout(&self) -> u32 {415		self.sponsor_approve_timeout416			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)417			.min(MAX_SPONSOR_TIMEOUT)418	}419	pub fn owner_can_transfer(&self) -> bool {420		self.owner_can_transfer.unwrap_or(true)421	}422	pub fn owner_can_destroy(&self) -> bool {423		self.owner_can_destroy.unwrap_or(true)424	}425	pub fn transfers_enabled(&self) -> bool {426		self.transfers_enabled.unwrap_or(true)427	}428	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {429		match self430			.sponsored_data_rate_limit431			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)432		{433			SponsoringRateLimit::SponsoringDisabled => None,434			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),435		}436	}437	pub fn nesting_rule(&self) -> &NestingRule {438		static DEFAULT: NestingRule = NestingRule::Disabled;439		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)440	}441}442443#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]444#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]445#[derivative(Debug)]446pub enum NestingRule {447	/// No one can nest tokens448	Disabled,449	/// Owner can nest any tokens450	Owner,451	/// Owner can nest tokens from specified collections452	OwnerRestricted(453		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]454		#[derivative(Debug(format_with = "bounded::set_debug"))]455		BoundedBTreeSet<CollectionId, ConstU32<16>>,456	),457}458459#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]460#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]461pub enum SponsoringRateLimit {462	SponsoringDisabled,463	Blocks(u32),464}465466#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]467#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]468#[derivative(Debug)]469pub struct CreateNftData {470	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]471	#[derivative(Debug(format_with = "bounded::vec_debug"))]472	pub const_data: BoundedVec<u8, CustomDataLimit>,473474	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]475	#[derivative(Debug(format_with = "bounded::vec_debug"))]476	pub properties: CollectionPropertiesVec,477}478479#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]480#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]481pub struct CreateFungibleData {482	pub value: u128,483}484485#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]486#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]487#[derivative(Debug)]488pub struct CreateReFungibleData {489	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]490	#[derivative(Debug(format_with = "bounded::vec_debug"))]491	pub const_data: BoundedVec<u8, CustomDataLimit>,492	pub pieces: u128,493}494495#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]496#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]497pub enum MetaUpdatePermission {498	ItemOwner,499	Admin,500	None,501}502503impl Default for MetaUpdatePermission {504	fn default() -> Self {505		Self::ItemOwner506	}507}508509#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]510#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]511pub enum CreateItemData {512	NFT(CreateNftData),513	Fungible(CreateFungibleData),514	ReFungible(CreateReFungibleData),515}516517#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]518#[derivative(Debug)]519pub struct CreateNftExData<CrossAccountId> {520	#[derivative(Debug(format_with = "bounded::vec_debug"))]521	pub const_data: BoundedVec<u8, CustomDataLimit>,522	#[derivative(Debug(format_with = "bounded::vec_debug"))]523	pub properties: CollectionPropertiesVec,524	pub owner: CrossAccountId,525}526527#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]528#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]529pub struct CreateRefungibleExData<CrossAccountId> {530	#[derivative(Debug(format_with = "bounded::vec_debug"))]531	pub const_data: BoundedVec<u8, CustomDataLimit>,532	#[derivative(Debug(format_with = "bounded::map_debug"))]533	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,534}535536#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]537#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]538pub enum CreateItemExData<CrossAccountId> {539	NFT(540		#[derivative(Debug(format_with = "bounded::vec_debug"))]541		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,542	),543	Fungible(544		#[derivative(Debug(format_with = "bounded::map_debug"))]545		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,546	),547	/// Many tokens, each may have only one owner548	RefungibleMultipleItems(549		#[derivative(Debug(format_with = "bounded::vec_debug"))]550		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,551	),552	/// Single token, which may have many owners553	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),554}555556impl CreateItemData {557	pub fn data_size(&self) -> usize {558		match self {559			CreateItemData::NFT(data) => data.const_data.len(),560			CreateItemData::ReFungible(data) => data.const_data.len(),561			_ => 0,562		}563	}564}565566impl From<CreateNftData> for CreateItemData {567	fn from(item: CreateNftData) -> Self {568		CreateItemData::NFT(item)569	}570}571572impl From<CreateReFungibleData> for CreateItemData {573	fn from(item: CreateReFungibleData) -> Self {574		CreateItemData::ReFungible(item)575	}576}577578impl From<CreateFungibleData> for CreateItemData {579	fn from(item: CreateFungibleData) -> Self {580		CreateItemData::Fungible(item)581	}582}583584#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]585#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]586pub struct CollectionStats {587	pub created: u32,588	pub destroyed: u32,589	pub alive: u32,590}591592#[derive(Encode, Decode, PartialEq, Clone, Debug)]593pub struct PhantomType<T>(core::marker::PhantomData<T>);594595impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {596	type Identity = PhantomType<T>;597598	fn type_info() -> scale_info::Type {599		use scale_info::{600			Type, Path,601			build::{FieldsBuilder, UnnamedFields},602			type_params,603		};604		Type::builder()605			.path(Path::new("up_data_structs", "PhantomType"))606			.type_params(type_params!(T))607			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))608	}609}610impl<T> MaxEncodedLen for PhantomType<T> {611	fn max_encoded_len() -> usize {612		0613	}614}615616pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;617pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;618619#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]620#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]621pub struct PropertyPermission {622	pub mutable: bool,623	pub collection_admin: bool,624	pub token_owner: bool,625}626627impl PropertyPermission {628	pub fn none() -> Self {629		Self {630			mutable: true,631			collection_admin: false,632			token_owner: false,633		}634	}635}636637#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]638#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]639pub struct Property {640	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]641	pub key: PropertyKey,642643	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]644	pub value: PropertyValue,645}646647#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]648#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]649pub struct PropertyKeyPermission {650	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]651	pub key: PropertyKey,652653	pub permission: PropertyPermission,654}655656pub enum PropertiesError {657	NoSpaceForProperty,658	PropertyLimitReached,659	InvalidCharacterInPropertyKey,660	EmptyPropertyKey,661}662663pub trait TrySet: Sized {664	type Value;665666	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;667668	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>669	where670		I: Iterator<Item = (PropertyKey, Self::Value)>,671	{672		for (key, value) in iter {673			self.try_set(key, value)?;674		}675676		Ok(())677	}678}679680#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]681#[derivative(Default(bound = ""))]682pub struct PropertiesMap<Value>(683	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,684);685686impl<Value> PropertiesMap<Value> {687	pub fn new() -> Self {688		Self(BoundedBTreeMap::new())689	}690691	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {692		Self::check_property_key(key)?;693694		Ok(self.0.remove(key))695	}696697	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {698		self.0.get(key)699	}700701	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {702		self.0.iter()703	}704705	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {706		if key.is_empty() {707			return Err(PropertiesError::EmptyPropertyKey);708		}709710		for byte in key.as_slice().iter() {711			match char::from_u32(*byte as u32) {712				Some(ch)713					if ch.is_ascii_alphanumeric()714					|| ch == '_'715					|| ch == '-' => { /* OK */ },716				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)717			}718		}719720		Ok(())721	}722}723724impl<Value> TrySet for PropertiesMap<Value> {725	type Value = Value;726727	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {728		Self::check_property_key(&key)?;729730		self.0731			.try_insert(key, value)732			.map_err(|_| PropertiesError::PropertyLimitReached)?;733734		Ok(())735	}736}737738pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;739740#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]741pub struct Properties {742	map: PropertiesMap<PropertyValue>,743	consumed_space: u32,744	space_limit: u32,745}746747impl Properties {748	pub fn new(space_limit: u32) -> Self {749		Self {750			map: PropertiesMap::new(),751			consumed_space: 0,752			space_limit,753		}754	}755756	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {757		let value = self.map.remove(key)?;758759		if let Some(ref value) = value {760			let value_len = value.len() as u32;761			self.consumed_space -= value_len;762		}763764		Ok(value)765	}766767	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {768		self.map.get(key)769	}770771	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {772		self.map.iter()773	}774}775776impl TrySet for Properties {777	type Value = PropertyValue;778779	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {780		let value_len = value.len();781782		if self.consumed_space as usize + value_len > self.space_limit as usize {783			return Err(PropertiesError::NoSpaceForProperty);784		}785786		self.map.try_set(key, value)?;787788		self.consumed_space += value_len as u32;789790		Ok(())791	}792}793794pub struct CollectionProperties;795796impl Get<Properties> for CollectionProperties {797	fn get() -> Properties {798		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)799	}800}801802pub struct TokenProperties;803804impl Get<Properties> for TokenProperties {805	fn get() -> Properties {806		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)807	}808}
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) {