git.delta.rocks / unique-network / refs/commits / 04a22c8dcea1

difftreelog

refactor remove meta update permission

Daniel Shiposha2022-05-15parent: #07f2d6c.patch.diff
in: master

11 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -22,7 +22,7 @@
 use pallet_evm::account::CrossAccountId;
 use frame_support::{
 	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},
-	ensure, fail,
+	ensure,
 	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},
 	BoundedVec,
 	weights::Pays,
@@ -30,7 +30,7 @@
 use pallet_evm::GasWeightMapping;
 use up_data_structs::{
 	COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionId, CreateItemData,
-	MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,
+	MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, TokenId,
 	CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,
 	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,
 	CUSTOM_DATA_LIMIT, CollectionLimits, CreateCollectionData, SponsorshipState,
@@ -134,21 +134,6 @@
 			<Error<T>>::AddressNotInAllowlist
 		);
 		Ok(())
-	}
-
-	pub fn check_can_update_meta(
-		&self,
-		subject: &T::CrossAccountId,
-		item_owner: &T::CrossAccountId,
-	) -> DispatchResult {
-		match self.meta_update_permission {
-			MetaUpdatePermission::ItemOwner => {
-				ensure!(subject == item_owner, <Error<T>>::NoPermission);
-				Ok(())
-			}
-			MetaUpdatePermission::Admin => self.check_is_owner_or_admin(subject),
-			MetaUpdatePermission::None => fail!(<Error<T>>::NoPermission),
-		}
 	}
 }
 
@@ -565,7 +550,6 @@
 			schema_version,
 			sponsorship,
 			limits,
-			meta_update_permission,
 		} = <CollectionById<T>>::get(collection)?;
 
 		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)
@@ -595,7 +579,6 @@
 			schema_version,
 			sponsorship,
 			limits,
-			meta_update_permission,
 			offchain_schema: <CollectionData<T>>::get((
 				collection,
 				CollectionField::OffchainSchema,
@@ -656,7 +639,6 @@
 				.limits
 				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))
 				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,
-			meta_update_permission: data.meta_update_permission.unwrap_or_default(),
 		};
 
 		let mut collection_properties = up_data_structs::CollectionProperties::get();
modifiedpallets/unique/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -168,9 +168,4 @@
 			nesting_rule: None,
 		};
 	}: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)
-
-	set_meta_update_permission_flag {
-		let caller: T::AccountId = account("caller", 0, SEED);
-		let collection = create_nft_collection::<T>(caller.clone())?;
-	}: _(RawOrigin::Signed(caller.clone()), collection, MetaUpdatePermission::Admin)
 }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -38,12 +38,12 @@
 	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,
+	SchemaVersion, SponsorshipState, CreateCollectionData,
 	CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,
 };
 use pallet_evm::account::CrossAccountId;
 use pallet_common::{
-	CollectionHandle, Pallet as PalletCommon, Error as CommonError, CommonWeightInfo,
+	CollectionHandle, Pallet as PalletCommon, CommonWeightInfo,
 	dispatch::dispatch_call, dispatch::CollectionDispatch,
 };
 
@@ -925,34 +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 meta_update_permission value for particular collection
-		///
-		/// # Permissions
-		///
-		/// * Collection Owner.
-		///
-		/// # Arguments
-		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * value: New flag value.
-		#[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]
-		#[transactional]
-		pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {
-			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-
-			ensure!(
-				target_collection.meta_update_permission != MetaUpdatePermission::None,
-				<CommonError<T>>::MetadataFlagFrozen,
-			);
-			target_collection.check_is_owner(&sender)?;
-
-			target_collection.meta_update_permission = value;
-
-			target_collection.save()
 		}
 
 		/// Set schema standard
modifiedpallets/unique/src/weights.rsdiffbeforeafterboth
--- a/pallets/unique/src/weights.rs
+++ b/pallets/unique/src/weights.rs
@@ -49,7 +49,6 @@
 	fn set_const_on_chain_schema(b: u32, ) -> Weight;
 	fn set_schema_version() -> Weight;
 	fn set_collection_limits() -> Weight;
-	fn set_meta_update_permission_flag() -> Weight;
 }
 
 /// Weights for pallet_unique using the Substrate node and recommended hardware.
@@ -167,12 +166,6 @@
 	// Storage: Common CollectionById (r:1 w:1)
 	fn set_collection_limits() -> Weight {
 		(15_339_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(1 as Weight))
-			.saturating_add(T::DbWeight::get().writes(1 as Weight))
-	}
-	// Storage: Common CollectionById (r:1 w:1)
-	fn set_meta_update_permission_flag() -> Weight {
-		(7_214_000 as Weight)
 			.saturating_add(T::DbWeight::get().reads(1 as Weight))
 			.saturating_add(T::DbWeight::get().writes(1 as Weight))
 	}
@@ -292,12 +285,6 @@
 	// Storage: Common CollectionById (r:1 w:1)
 	fn set_collection_limits() -> Weight {
 		(15_339_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
-	}
-	// Storage: Common CollectionById (r:1 w:1)
-	fn set_meta_update_permission_flag() -> Weight {
-		(7_214_000 as Weight)
 			.saturating_add(RocksDbWeight::get().reads(1 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(1 as Weight))
 	}
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
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/// 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}
modifiedruntime/tests/src/tests.rsdiffbeforeafterboth
--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -18,7 +18,7 @@
 use crate::{Test, TestCrossAccountId, CollectionCreationPrice, Origin, Unique, new_test_ext};
 use up_data_structs::{
 	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
-	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,
+	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT,
 	TokenId, MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionField, SchemaVersion,
 	CollectionMode, AccessMode,
 };
@@ -2467,32 +2467,6 @@
 		assert_eq!(
 			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),
 			1
-		);
-	});
-}
-
-#[test]
-fn set_variable_meta_flag_after_freeze() {
-	new_test_ext().execute_with(|| {
-		// default_limits();
-
-		let collection_id =
-			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));
-
-		let origin2 = Origin::signed(2);
-
-		assert_ok!(Unique::set_meta_update_permission_flag(
-			origin2.clone(),
-			collection_id,
-			MetaUpdatePermission::None,
-		));
-		assert_noop!(
-			Unique::set_meta_update_permission_flag(
-				origin2.clone(),
-				collection_id,
-				MetaUpdatePermission::Admin
-			),
-			CommonError::<Test>::MetadataFlagFrozen
 		);
 	});
 }
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -74,7 +74,6 @@
           accountTokenOwnershipLimit: 3,
         },
         constOnChainSchema: '0x333333',
-        metaUpdatePermission: 'Admin',
       });
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateCollectionResult(events);
@@ -91,7 +90,6 @@
       expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address);
       expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
       expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
-      expect(collection.metaUpdatePermission.isAdmin).to.be.true;
     });
   });
 });
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import privateKey from '../substrate/privateKey';
-import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE, setMetadataUpdatePermissionFlagExpectSuccess} from '../util/helpers';
+import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import {expect} from 'chai';
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import privateKey from '../../substrate/privateKey';
-import {createCollectionExpectSuccess, createItemExpectSuccess, setMetadataUpdatePermissionFlagExpectSuccess} from '../../util/helpers';
+import {createCollectionExpectSuccess, createItemExpectSuccess} from '../../util/helpers';
 import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents} from '../util/helpers';
 import nonFungibleAbi from '../nonFungibleAbi.json';
 import {expect} from 'chai';
modifiedtests/src/nesting/migration-check.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/migration-check.test.ts
+++ b/tests/src/nesting/migration-check.test.ts
@@ -37,7 +37,6 @@
           accountTokenOwnershipLimit: 3,
         },
         constOnChainSchema: '0x333333',
-        metaUpdatePermission: 'Admin',
       });
       const events = await submitTransactionAsync(alice, tx);
       const result = getCreateCollectionResult(events);
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -650,28 +650,6 @@
   });
 }
 
-export async function setMetadataUpdatePermissionFlagExpectSuccess(sender: IKeyringPair, collectionId: number, flag: string) {
-
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
-    const events = await submitTransactionAsync(sender, tx);
-    const result = getGenericResult(events);
-
-    expect(result.success).to.be.true;
-  });
-}
-
-export async function setMetadataUpdatePermissionFlagExpectFailure(sender: IKeyringPair, collectionId: number, flag: string) {
-
-  await usingApi(async (api) => {
-    const tx = api.tx.unique.setMetaUpdatePermissionFlag(collectionId, flag as any);
-    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
-    const result = getGenericResult(events);
-
-    expect(result.success).to.be.false;
-  });
-}
-
 export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {
   await usingApi(async (api) => {
     const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);