git.delta.rocks / unique-network / refs/commits / 6ac8e66dbab7

difftreelog

source

primitives/data-structs/src/lib.rs22.6 KiBsourcehistory
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;83// u32::max is not const: OFFCHAIN_SCHEMA_LIMIT.max(VARIABLE_ON_CHAIN_SCHEMA_LIMIT).max(CONST_ON_CHAIN_SCHEMA_LIMIT);8485pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;86pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;87pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8889pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;90pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;91pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;9293// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;94pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;95pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;9697pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =98	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;99100pub struct MaxPropertiesPermissionsEncodeLen;101102impl Get<u32> for MaxPropertiesPermissionsEncodeLen {103	fn get() -> u32 {104		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH105			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32106	}107}108109/// How much items can be created per single110/// create_many call111pub const MAX_ITEMS_PER_BATCH: u32 = 200;112113pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;114115#[derive(116	Encode,117	Decode,118	PartialEq,119	Eq,120	PartialOrd,121	Ord,122	Clone,123	Copy,124	Debug,125	Default,126	TypeInfo,127	MaxEncodedLen,128)]129#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]130pub struct CollectionId(pub u32);131impl EncodeLike<u32> for CollectionId {}132impl EncodeLike<CollectionId> for u32 {}133134#[derive(135	Encode,136	Decode,137	PartialEq,138	Eq,139	PartialOrd,140	Ord,141	Clone,142	Copy,143	Debug,144	Default,145	TypeInfo,146	MaxEncodedLen,147)]148#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]149pub struct TokenId(pub u32);150impl EncodeLike<u32> for TokenId {}151impl EncodeLike<TokenId> for u32 {}152153impl TokenId {154	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {155		self.0156			.checked_add(1)157			.ok_or(ArithmeticError::Overflow)158			.map(Self)159	}160}161162impl From<TokenId> for U256 {163	fn from(t: TokenId) -> Self {164		t.0.into()165	}166}167168impl TryFrom<U256> for TokenId {169	type Error = &'static str;170171	fn try_from(value: U256) -> Result<Self, Self::Error> {172		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))173	}174}175176#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]177#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]178pub struct TokenData<CrossAccountId> {179	pub const_data: Vec<u8>,180	pub properties: Vec<Property>,181	pub owner: Option<CrossAccountId>,182}183184pub struct OverflowError;185impl From<OverflowError> for &'static str {186	fn from(_: OverflowError) -> Self {187		"overflow occured"188	}189}190191pub type DecimalPoints = u8;192193#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]194#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]195pub enum CollectionMode {196	NFT,197	// decimal points198	Fungible(DecimalPoints),199	ReFungible,200}201202impl CollectionMode {203	pub fn id(&self) -> u8 {204		match self {205			CollectionMode::NFT => 1,206			CollectionMode::Fungible(_) => 2,207			CollectionMode::ReFungible => 3,208		}209	}210}211212pub trait SponsoringResolve<AccountId, Call> {213	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;214}215216#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]217#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]218pub enum AccessMode {219	Normal,220	AllowList,221}222impl Default for AccessMode {223	fn default() -> Self {224		Self::Normal225	}226}227228#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]229#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]230pub enum SchemaVersion {231	ImageURL,232	Unique,233}234impl Default for SchemaVersion {235	fn default() -> Self {236		Self::ImageURL237	}238}239240#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]241#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]242pub struct Ownership<AccountId> {243	pub owner: AccountId,244	pub fraction: u128,245}246247#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]248#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]249pub enum SponsorshipState<AccountId> {250	/// The fees are applied to the transaction sender251	Disabled,252	Unconfirmed(AccountId),253	/// Transactions are sponsored by specified account254	Confirmed(AccountId),255}256257impl<AccountId> SponsorshipState<AccountId> {258	pub fn sponsor(&self) -> Option<&AccountId> {259		match self {260			Self::Confirmed(sponsor) => Some(sponsor),261			_ => None,262		}263	}264265	pub fn pending_sponsor(&self) -> Option<&AccountId> {266		match self {267			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),268			_ => None,269		}270	}271272	pub fn confirmed(&self) -> bool {273		matches!(self, Self::Confirmed(_))274	}275}276277impl<T> Default for SponsorshipState<T> {278	fn default() -> Self {279		Self::Disabled280	}281}282283/// Used in storage284#[struct_versioning::versioned(version = 2, upper)]285#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]286pub struct Collection<AccountId> {287	pub owner: AccountId,288	pub mode: CollectionMode,289	pub access: AccessMode,290	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,291	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,292	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,293	pub mint_mode: bool,294295	#[version(..2)]296	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,297298	pub schema_version: SchemaVersion,299	pub sponsorship: SponsorshipState<AccountId>,300301	#[version(..2)]302	pub limits: CollectionLimitsVersion1, // Collection private restrictions303	#[version(2.., upper(limits.into()))]304	pub limits: CollectionLimitsVersion2,305306	#[version(..2)]307	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,308	#[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 variable_on_chain_schema: Vec<u8>,330	pub const_on_chain_schema: Vec<u8>,331	pub meta_update_permission: MetaUpdatePermission,332	pub token_property_permissions: Vec<PropertyKeyPermission>,333	pub properties: Vec<Property>,334}335336#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]337#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]338pub enum CollectionField {339	VariableOnChainSchema,340	ConstOnChainSchema,341	OffchainSchema,342}343344#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]345#[derivative(Debug, Default(bound = ""))]346pub struct CreateCollectionData<AccountId> {347	#[derivative(Default(value = "CollectionMode::NFT"))]348	pub mode: CollectionMode,349	pub access: Option<AccessMode>,350	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,351	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,352	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,353	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,354	pub schema_version: Option<SchemaVersion>,355	pub pending_sponsor: Option<AccountId>,356	pub limits: Option<CollectionLimits>,357	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,358	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,359	pub meta_update_permission: Option<MetaUpdatePermission>,360	pub token_property_permissions: CollectionPropertiesPermissionsVec,361	pub properties: CollectionPropertiesVec,362}363364pub type CollectionPropertiesPermissionsVec =365	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;366367pub type CollectionPropertiesVec =368	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;369370#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]371#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]372pub struct NftItemType<AccountId> {373	pub owner: AccountId,374	pub const_data: Vec<u8>,375	pub variable_data: Vec<u8>,376}377378#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]379#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]380pub struct FungibleItemType {381	pub value: u128,382}383384#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]385#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]386pub struct ReFungibleItemType<AccountId> {387	pub owner: Vec<Ownership<AccountId>>,388	pub const_data: Vec<u8>,389	pub variable_data: Vec<u8>,390}391392/// All fields are wrapped in `Option`s, where None means chain default393#[struct_versioning::versioned(version = 2, upper)]394#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]395#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]396pub struct CollectionLimits {397	pub account_token_ownership_limit: Option<u32>,398	pub sponsored_data_size: Option<u32>,399	/// None - setVariableMetadata is not sponsored400	/// Some(v) - setVariableMetadata is sponsored401	///           if there is v block between txs402	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,403	pub token_limit: Option<u32>,404405	// Timeouts for item types in passed blocks406	pub sponsor_transfer_timeout: Option<u32>,407	pub sponsor_approve_timeout: Option<u32>,408	pub owner_can_transfer: Option<bool>,409	pub owner_can_destroy: Option<bool>,410	pub transfers_enabled: Option<bool>,411412	#[version(2.., upper(None))]413	pub nesting_rule: Option<NestingRule>,414}415416impl CollectionLimits {417	pub fn account_token_ownership_limit(&self) -> u32 {418		self.account_token_ownership_limit419			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)420			.min(MAX_TOKEN_OWNERSHIP)421	}422	pub fn sponsored_data_size(&self) -> u32 {423		self.sponsored_data_size424			.unwrap_or(CUSTOM_DATA_LIMIT)425			.min(CUSTOM_DATA_LIMIT)426	}427	pub fn token_limit(&self) -> u32 {428		self.token_limit429			.unwrap_or(COLLECTION_TOKEN_LIMIT)430			.min(COLLECTION_TOKEN_LIMIT)431	}432	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {433		self.sponsor_transfer_timeout434			.unwrap_or(default)435			.min(MAX_SPONSOR_TIMEOUT)436	}437	pub fn sponsor_approve_timeout(&self) -> u32 {438		self.sponsor_approve_timeout439			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)440			.min(MAX_SPONSOR_TIMEOUT)441	}442	pub fn owner_can_transfer(&self) -> bool {443		self.owner_can_transfer.unwrap_or(true)444	}445	pub fn owner_can_destroy(&self) -> bool {446		self.owner_can_destroy.unwrap_or(true)447	}448	pub fn transfers_enabled(&self) -> bool {449		self.transfers_enabled.unwrap_or(true)450	}451	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {452		match self453			.sponsored_data_rate_limit454			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)455		{456			SponsoringRateLimit::SponsoringDisabled => None,457			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),458		}459	}460	pub fn nesting_rule(&self) -> &NestingRule {461		static DEFAULT: NestingRule = NestingRule::Owner;462		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)463	}464}465466#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]467#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]468#[derivative(Debug)]469pub enum NestingRule {470	/// No one can nest tokens471	Disabled,472	/// Owner can nest any tokens473	Owner,474	/// Owner can nest tokens from specified collections475	OwnerRestricted(476		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]477		#[derivative(Debug(format_with = "bounded::set_debug"))]478		BoundedBTreeSet<CollectionId, ConstU32<16>>,479	),480}481482#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]483#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]484pub enum SponsoringRateLimit {485	SponsoringDisabled,486	Blocks(u32),487}488489#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]490#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]491#[derivative(Debug)]492pub struct CreateNftData {493	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]494	#[derivative(Debug(format_with = "bounded::vec_debug"))]495	pub const_data: BoundedVec<u8, CustomDataLimit>,496	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]497	#[derivative(Debug(format_with = "bounded::vec_debug"))]498	pub variable_data: BoundedVec<u8, CustomDataLimit>,499500	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]501	#[derivative(Debug(format_with = "bounded::vec_debug"))]502	pub properties: CollectionPropertiesVec,503}504505#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]506#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]507pub struct CreateFungibleData {508	pub value: u128,509}510511#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]512#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]513#[derivative(Debug)]514pub struct CreateReFungibleData {515	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]516	#[derivative(Debug(format_with = "bounded::vec_debug"))]517	pub const_data: BoundedVec<u8, CustomDataLimit>,518	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]519	#[derivative(Debug(format_with = "bounded::vec_debug"))]520	pub variable_data: BoundedVec<u8, CustomDataLimit>,521	pub pieces: u128,522}523524#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]525#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]526pub enum MetaUpdatePermission {527	ItemOwner,528	Admin,529	None,530}531532impl Default for MetaUpdatePermission {533	fn default() -> Self {534		Self::ItemOwner535	}536}537538#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]539#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]540pub enum CreateItemData {541	NFT(CreateNftData),542	Fungible(CreateFungibleData),543	ReFungible(CreateReFungibleData),544}545546#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]547#[derivative(Debug)]548pub struct CreateNftExData<CrossAccountId> {549	#[derivative(Debug(format_with = "bounded::vec_debug"))]550	pub const_data: BoundedVec<u8, CustomDataLimit>,551	#[derivative(Debug(format_with = "bounded::vec_debug"))]552	pub variable_data: BoundedVec<u8, CustomDataLimit>,553	#[derivative(Debug(format_with = "bounded::vec_debug"))]554	pub properties: CollectionPropertiesVec,555	pub owner: CrossAccountId,556}557558#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]559#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]560pub struct CreateRefungibleExData<CrossAccountId> {561	#[derivative(Debug(format_with = "bounded::vec_debug"))]562	pub const_data: BoundedVec<u8, CustomDataLimit>,563	#[derivative(Debug(format_with = "bounded::vec_debug"))]564	pub variable_data: BoundedVec<u8, CustomDataLimit>,565	#[derivative(Debug(format_with = "bounded::map_debug"))]566	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,567}568569#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]570#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]571pub enum CreateItemExData<CrossAccountId> {572	NFT(573		#[derivative(Debug(format_with = "bounded::vec_debug"))]574		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,575	),576	Fungible(577		#[derivative(Debug(format_with = "bounded::map_debug"))]578		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,579	),580	/// Many tokens, each may have only one owner581	RefungibleMultipleItems(582		#[derivative(Debug(format_with = "bounded::vec_debug"))]583		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,584	),585	/// Single token, which may have many owners586	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),587}588589impl CreateItemData {590	pub fn data_size(&self) -> usize {591		match self {592			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),593			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),594			_ => 0,595		}596	}597}598599impl From<CreateNftData> for CreateItemData {600	fn from(item: CreateNftData) -> Self {601		CreateItemData::NFT(item)602	}603}604605impl From<CreateReFungibleData> for CreateItemData {606	fn from(item: CreateReFungibleData) -> Self {607		CreateItemData::ReFungible(item)608	}609}610611impl From<CreateFungibleData> for CreateItemData {612	fn from(item: CreateFungibleData) -> Self {613		CreateItemData::Fungible(item)614	}615}616617#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]618#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]619pub struct CollectionStats {620	pub created: u32,621	pub destroyed: u32,622	pub alive: u32,623}624625#[derive(Encode, Decode, PartialEq, Clone, Debug)]626pub struct PhantomType<T>(core::marker::PhantomData<T>);627628impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {629	type Identity = PhantomType<T>;630631	fn type_info() -> scale_info::Type {632		use scale_info::{633			Type, Path,634			build::{FieldsBuilder, UnnamedFields},635			type_params,636		};637		Type::builder()638			.path(Path::new("up_data_structs", "PhantomType"))639			.type_params(type_params!(T))640			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))641	}642}643impl<T> MaxEncodedLen for PhantomType<T> {644	fn max_encoded_len() -> usize {645		0646	}647}648649pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;650pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;651652#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]653#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]654pub struct PropertyPermission {655	pub mutable: bool,656	pub collection_admin: bool,657	pub token_owner: bool,658}659660impl PropertyPermission {661	pub fn none() -> Self {662		Self {663			mutable: true,664			collection_admin: false,665			token_owner: false,666		}667	}668}669670#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]671#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]672pub struct Property {673	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]674	pub key: PropertyKey,675676	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]677	pub value: PropertyValue,678}679680#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]681#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]682pub struct PropertyKeyPermission {683	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]684	pub key: PropertyKey,685686	pub permission: PropertyPermission,687}688689pub enum PropertiesError {690	NoSpaceForProperty,691	PropertyLimitReached,692}693694pub type PropertiesMap =695	BoundedBTreeMap<PropertyKey, PropertyValue, ConstU32<MAX_PROPERTIES_PER_ITEM>>;696pub type PropertiesPermissionMap =697	BoundedBTreeMap<PropertyKey, PropertyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;698699#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]700pub struct Properties {701	map: PropertiesMap,702	consumed_space: u32,703	space_limit: u32,704}705706impl Properties {707	pub fn new(space_limit: u32) -> Self {708		Self {709			map: BoundedBTreeMap::new(),710			consumed_space: 0,711			space_limit,712		}713	}714715	pub fn from_collection_props_vec(716		data: CollectionPropertiesVec,717	) -> Result<Self, PropertiesError> {718		let mut props = Self::new(MAX_COLLECTION_PROPERTIES_SIZE);719720		for property in data.into_iter() {721			props.try_set_property(property)?;722		}723724		Ok(props)725	}726727	pub fn try_set_property(&mut self, property: Property) -> Result<(), PropertiesError> {728		let value_len = property.value.len();729730		if self.consumed_space as usize + value_len > self.space_limit as usize {731			return Err(PropertiesError::NoSpaceForProperty);732		}733734		self.map735			.try_insert(property.key, property.value)736			.map_err(|_| PropertiesError::PropertyLimitReached)?;737738		self.consumed_space += value_len as u32;739740		Ok(())741	}742743	pub fn remove_property(&mut self, key: &PropertyKey) {744		let property = self.map.get(key);745746		if let Some(value) = property {747			let value_len = value.len() as u32;748749			self.map.remove(key);750			self.consumed_space -= value_len;751		}752	}753754	pub fn get_property(&self, key: &PropertyKey) -> Option<&PropertyValue> {755		self.map.get(key)756	}757758	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {759		self.map.iter()760	}761}762763pub struct CollectionProperties;764765impl Get<Properties> for CollectionProperties {766	fn get() -> Properties {767		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)768	}769}770771pub struct TokenProperties;772773impl Get<Properties> for TokenProperties {774	fn get() -> Properties {775		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)776	}777}