git.delta.rocks / unique-network / refs/commits / 547ee7a8f073

difftreelog

source

primitives/data-structs/src/lib.rs25.5 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, parameter_types,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;3738// RMRK39use rmrk_types::{40	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,41};42pub use rmrk_types::{43	primitives::{CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId, PartId as RmrkPartId, ResourceId as RmrkResourceId},44	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,45};4647mod bounded;48pub mod budget;49pub mod mapping;50mod migration;5152pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;53pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;54pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5556pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {57	100_00058} else {59	1060};61pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {62	100_00063} else {64	1065};66pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {67	204868} else {69	1070};71pub const COLLECTION_ADMINS_LIMIT: u32 = 5;72pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;73pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {74	1_000_00075} else {76	1077};7879// Timeouts for item types in passed blocks80pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;81pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;82pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;8384pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;8586// Schema limits87pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;88pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8990pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;9192pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;93pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;94pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;9596pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;97pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;98pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;99100// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;101pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;102pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;103104pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =105	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;106107// RMRK constants108pub const RMRK_STRING_LIMIT: u32 = 128;109pub const RMRK_COLLECTION_SYMBOL_LIMIT: u32 = 100;110pub const RMRK_RESOURCE_SYMBOL_LIMIT: u32 = 10;111pub const RMRK_KEY_LIMIT: u32 = 32;112pub const RMRK_VALUE_LIMIT: u32 = 256;113114pub struct MaxPropertiesPermissionsEncodeLen;115116impl Get<u32> for MaxPropertiesPermissionsEncodeLen {117	fn get() -> u32 {118		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH119			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32120	}121}122123/// How much items can be created per single124/// create_many call125pub const MAX_ITEMS_PER_BATCH: u32 = 200;126127pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;128129#[derive(130	Encode,131	Decode,132	PartialEq,133	Eq,134	PartialOrd,135	Ord,136	Clone,137	Copy,138	Debug,139	Default,140	TypeInfo,141	MaxEncodedLen,142)]143#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]144pub struct CollectionId(pub u32);145impl EncodeLike<u32> for CollectionId {}146impl EncodeLike<CollectionId> for u32 {}147148#[derive(149	Encode,150	Decode,151	PartialEq,152	Eq,153	PartialOrd,154	Ord,155	Clone,156	Copy,157	Debug,158	Default,159	TypeInfo,160	MaxEncodedLen,161)]162#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]163pub struct TokenId(pub u32);164impl EncodeLike<u32> for TokenId {}165impl EncodeLike<TokenId> for u32 {}166167impl TokenId {168	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {169		self.0170			.checked_add(1)171			.ok_or(ArithmeticError::Overflow)172			.map(Self)173	}174}175176impl From<TokenId> for U256 {177	fn from(t: TokenId) -> Self {178		t.0.into()179	}180}181182impl TryFrom<U256> for TokenId {183	type Error = &'static str;184185	fn try_from(value: U256) -> Result<Self, Self::Error> {186		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))187	}188}189190#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]191#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]192pub struct TokenData<CrossAccountId> {193	pub const_data: Vec<u8>,194	pub properties: Vec<Property>,195	pub owner: Option<CrossAccountId>,196}197198pub struct OverflowError;199impl From<OverflowError> for &'static str {200	fn from(_: OverflowError) -> Self {201		"overflow occured"202	}203}204205pub type DecimalPoints = u8;206207#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]208#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]209pub enum CollectionMode {210	NFT,211	// decimal points212	Fungible(DecimalPoints),213	ReFungible,214}215216impl CollectionMode {217	pub fn id(&self) -> u8 {218		match self {219			CollectionMode::NFT => 1,220			CollectionMode::Fungible(_) => 2,221			CollectionMode::ReFungible => 3,222		}223	}224}225226pub trait SponsoringResolve<AccountId, Call> {227	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;228}229230#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]231#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]232pub enum AccessMode {233	Normal,234	AllowList,235}236impl Default for AccessMode {237	fn default() -> Self {238		Self::Normal239	}240}241242#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]243#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]244pub enum SchemaVersion {245	ImageURL,246	Unique,247}248impl Default for SchemaVersion {249	fn default() -> Self {250		Self::ImageURL251	}252}253254#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]255#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]256pub struct Ownership<AccountId> {257	pub owner: AccountId,258	pub fraction: u128,259}260261#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]262#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]263pub enum SponsorshipState<AccountId> {264	/// The fees are applied to the transaction sender265	Disabled,266	Unconfirmed(AccountId),267	/// Transactions are sponsored by specified account268	Confirmed(AccountId),269}270271impl<AccountId> SponsorshipState<AccountId> {272	pub fn sponsor(&self) -> Option<&AccountId> {273		match self {274			Self::Confirmed(sponsor) => Some(sponsor),275			_ => None,276		}277	}278279	pub fn pending_sponsor(&self) -> Option<&AccountId> {280		match self {281			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),282			_ => None,283		}284	}285286	pub fn confirmed(&self) -> bool {287		matches!(self, Self::Confirmed(_))288	}289}290291impl<T> Default for SponsorshipState<T> {292	fn default() -> Self {293		Self::Disabled294	}295}296297/// Used in storage298#[struct_versioning::versioned(version = 2, upper)]299#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]300pub struct Collection<AccountId> {301	pub owner: AccountId,302	pub mode: CollectionMode,303	pub access: AccessMode,304	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,305	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,306	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,307	pub mint_mode: bool,308309	#[version(..2)]310	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,311312	pub schema_version: SchemaVersion,313	pub sponsorship: SponsorshipState<AccountId>,314315	#[version(..2)]316	pub limits: CollectionLimitsVersion1, // Collection private restrictions317	#[version(2.., upper(limits.into()))]318	pub limits: CollectionLimitsVersion2,319320	#[version(..2)]321	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,322323	pub meta_update_permission: MetaUpdatePermission,324}325326/// Used in RPC calls327#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]328#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]329pub struct RpcCollection<AccountId> {330	pub owner: AccountId,331	pub mode: CollectionMode,332	pub access: AccessMode,333	pub name: Vec<u16>,334	pub description: Vec<u16>,335	pub token_prefix: Vec<u8>,336	pub mint_mode: bool,337	pub offchain_schema: Vec<u8>,338	pub schema_version: SchemaVersion,339	pub sponsorship: SponsorshipState<AccountId>,340	pub limits: CollectionLimits,341	pub const_on_chain_schema: Vec<u8>,342	pub meta_update_permission: MetaUpdatePermission,343	pub token_property_permissions: Vec<PropertyKeyPermission>,344	pub properties: Vec<Property>,345}346347#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]348#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]349pub enum CollectionField {350	ConstOnChainSchema,351	OffchainSchema,352}353354#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]355#[derivative(Debug, Default(bound = ""))]356pub struct CreateCollectionData<AccountId> {357	#[derivative(Default(value = "CollectionMode::NFT"))]358	pub mode: CollectionMode,359	pub access: Option<AccessMode>,360	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,361	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,362	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,363	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,364	pub schema_version: Option<SchemaVersion>,365	pub pending_sponsor: Option<AccountId>,366	pub limits: Option<CollectionLimits>,367	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,368	pub meta_update_permission: Option<MetaUpdatePermission>,369	pub token_property_permissions: CollectionPropertiesPermissionsVec,370	pub properties: CollectionPropertiesVec,371}372373pub type CollectionPropertiesPermissionsVec =374	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;375376pub type CollectionPropertiesVec =377	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;378379#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]380#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]381pub struct NftItemType<AccountId> {382	pub owner: AccountId,383	pub const_data: Vec<u8>,384	pub variable_data: Vec<u8>,385}386387#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]388#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]389pub struct FungibleItemType {390	pub value: u128,391}392393#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]394#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]395pub struct ReFungibleItemType<AccountId> {396	pub owner: Vec<Ownership<AccountId>>,397	pub const_data: Vec<u8>,398	pub variable_data: Vec<u8>,399}400401/// All fields are wrapped in `Option`s, where None means chain default402#[struct_versioning::versioned(version = 2, upper)]403#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]404#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]405pub struct CollectionLimits {406	pub account_token_ownership_limit: Option<u32>,407	pub sponsored_data_size: Option<u32>,408	/// None - setVariableMetadata is not sponsored409	/// Some(v) - setVariableMetadata is sponsored410	///           if there is v block between txs411	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,412	pub token_limit: Option<u32>,413414	// Timeouts for item types in passed blocks415	pub sponsor_transfer_timeout: Option<u32>,416	pub sponsor_approve_timeout: Option<u32>,417	pub owner_can_transfer: Option<bool>,418	pub owner_can_destroy: Option<bool>,419	pub transfers_enabled: Option<bool>,420421	#[version(2.., upper(None))]422	pub nesting_rule: Option<NestingRule>,423}424425impl CollectionLimits {426	pub fn account_token_ownership_limit(&self) -> u32 {427		self.account_token_ownership_limit428			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)429			.min(MAX_TOKEN_OWNERSHIP)430	}431	pub fn sponsored_data_size(&self) -> u32 {432		self.sponsored_data_size433			.unwrap_or(CUSTOM_DATA_LIMIT)434			.min(CUSTOM_DATA_LIMIT)435	}436	pub fn token_limit(&self) -> u32 {437		self.token_limit438			.unwrap_or(COLLECTION_TOKEN_LIMIT)439			.min(COLLECTION_TOKEN_LIMIT)440	}441	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {442		self.sponsor_transfer_timeout443			.unwrap_or(default)444			.min(MAX_SPONSOR_TIMEOUT)445	}446	pub fn sponsor_approve_timeout(&self) -> u32 {447		self.sponsor_approve_timeout448			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)449			.min(MAX_SPONSOR_TIMEOUT)450	}451	pub fn owner_can_transfer(&self) -> bool {452		self.owner_can_transfer.unwrap_or(true)453	}454	pub fn owner_can_destroy(&self) -> bool {455		self.owner_can_destroy.unwrap_or(true)456	}457	pub fn transfers_enabled(&self) -> bool {458		self.transfers_enabled.unwrap_or(true)459	}460	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {461		match self462			.sponsored_data_rate_limit463			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)464		{465			SponsoringRateLimit::SponsoringDisabled => None,466			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),467		}468	}469	pub fn nesting_rule(&self) -> &NestingRule {470		static DEFAULT: NestingRule = NestingRule::Disabled;471		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)472	}473}474475#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]476#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]477#[derivative(Debug)]478pub enum NestingRule {479	/// No one can nest tokens480	Disabled,481	/// Owner can nest any tokens482	Owner,483	/// Owner can nest tokens from specified collections484	OwnerRestricted(485		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]486		#[derivative(Debug(format_with = "bounded::set_debug"))]487		BoundedBTreeSet<CollectionId, ConstU32<16>>,488	),489}490491#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]492#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]493pub enum SponsoringRateLimit {494	SponsoringDisabled,495	Blocks(u32),496}497498#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]499#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]500#[derivative(Debug)]501pub struct CreateNftData {502	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]503	#[derivative(Debug(format_with = "bounded::vec_debug"))]504	pub const_data: BoundedVec<u8, CustomDataLimit>,505	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]506	#[derivative(Debug(format_with = "bounded::vec_debug"))]507	pub variable_data: BoundedVec<u8, CustomDataLimit>,508509	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]510	#[derivative(Debug(format_with = "bounded::vec_debug"))]511	pub properties: CollectionPropertiesVec,512}513514#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]515#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]516pub struct CreateFungibleData {517	pub value: u128,518}519520#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]521#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]522#[derivative(Debug)]523pub struct CreateReFungibleData {524	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]525	#[derivative(Debug(format_with = "bounded::vec_debug"))]526	pub const_data: BoundedVec<u8, CustomDataLimit>,527	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]528	#[derivative(Debug(format_with = "bounded::vec_debug"))]529	pub variable_data: BoundedVec<u8, CustomDataLimit>,530	pub pieces: u128,531}532533#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]534#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]535pub enum MetaUpdatePermission {536	ItemOwner,537	Admin,538	None,539}540541impl Default for MetaUpdatePermission {542	fn default() -> Self {543		Self::ItemOwner544	}545}546547#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]548#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]549pub enum CreateItemData {550	NFT(CreateNftData),551	Fungible(CreateFungibleData),552	ReFungible(CreateReFungibleData),553}554555#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]556#[derivative(Debug)]557pub struct CreateNftExData<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::vec_debug"))]563	pub properties: CollectionPropertiesVec,564	pub owner: CrossAccountId,565}566567#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]568#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]569pub struct CreateRefungibleExData<CrossAccountId> {570	#[derivative(Debug(format_with = "bounded::vec_debug"))]571	pub const_data: BoundedVec<u8, CustomDataLimit>,572	#[derivative(Debug(format_with = "bounded::vec_debug"))]573	pub variable_data: BoundedVec<u8, CustomDataLimit>,574	#[derivative(Debug(format_with = "bounded::map_debug"))]575	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,576}577578#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]579#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]580pub enum CreateItemExData<CrossAccountId> {581	NFT(582		#[derivative(Debug(format_with = "bounded::vec_debug"))]583		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,584	),585	Fungible(586		#[derivative(Debug(format_with = "bounded::map_debug"))]587		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,588	),589	/// Many tokens, each may have only one owner590	RefungibleMultipleItems(591		#[derivative(Debug(format_with = "bounded::vec_debug"))]592		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,593	),594	/// Single token, which may have many owners595	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),596}597598impl CreateItemData {599	pub fn data_size(&self) -> usize {600		match self {601			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),602			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),603			_ => 0,604		}605	}606}607608impl From<CreateNftData> for CreateItemData {609	fn from(item: CreateNftData) -> Self {610		CreateItemData::NFT(item)611	}612}613614impl From<CreateReFungibleData> for CreateItemData {615	fn from(item: CreateReFungibleData) -> Self {616		CreateItemData::ReFungible(item)617	}618}619620impl From<CreateFungibleData> for CreateItemData {621	fn from(item: CreateFungibleData) -> Self {622		CreateItemData::Fungible(item)623	}624}625626#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]627#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]628pub struct CollectionStats {629	pub created: u32,630	pub destroyed: u32,631	pub alive: u32,632}633634#[derive(Encode, Decode, Clone, Debug)]635#[cfg_attr(feature = "std", derive(PartialEq))]636pub struct PhantomType<T>(core::marker::PhantomData<T>);637638impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {639	type Identity = PhantomType<T>;640641	fn type_info() -> scale_info::Type {642		use scale_info::{643			Type, Path,644			build::{FieldsBuilder, UnnamedFields},645			type_params,646		};647		Type::builder()648			.path(Path::new("up_data_structs", "PhantomType"))649			.type_params(type_params!(T))650			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))651	}652}653impl<T> MaxEncodedLen for PhantomType<T> {654	fn max_encoded_len() -> usize {655		0656	}657}658659pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;660pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;661662#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]663#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]664pub struct PropertyPermission {665	pub mutable: bool,666	pub collection_admin: bool,667	pub token_owner: bool,668}669670impl PropertyPermission {671	pub fn none() -> Self {672		Self {673			mutable: true,674			collection_admin: false,675			token_owner: false,676		}677	}678}679680#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]681#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]682pub struct Property {683	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]684	pub key: PropertyKey,685686	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]687	pub value: PropertyValue,688}689690#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]691#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]692pub struct PropertyKeyPermission {693	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]694	pub key: PropertyKey,695696	pub permission: PropertyPermission,697}698699pub enum PropertiesError {700	NoSpaceForProperty,701	PropertyLimitReached,702	InvalidCharacterInPropertyKey,703	EmptyPropertyKey,704}705706pub trait TrySet: Sized {707	type Value;708709	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;710711	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>712	where713		I: Iterator<Item = (PropertyKey, Self::Value)>,714	{715		for (key, value) in iter {716			self.try_set(key, value)?;717		}718719		Ok(())720	}721}722723#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]724#[derivative(Default(bound = ""))]725pub struct PropertiesMap<Value>(726	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,727);728729impl<Value> PropertiesMap<Value> {730	pub fn new() -> Self {731		Self(BoundedBTreeMap::new())732	}733734	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {735		Self::check_property_key(key)?;736737		Ok(self.0.remove(key))738	}739740	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {741		self.0.get(key)742	}743744	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {745		self.0.iter()746	}747748	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {749		if key.is_empty() {750			return Err(PropertiesError::EmptyPropertyKey);751		}752753		for byte in key.as_slice().iter() {754			match char::from_u32(*byte as u32) {755				Some(ch)756					if ch.is_ascii_alphanumeric()757					|| ch == '_'758					|| ch == '-' => { /* OK */ },759				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)760			}761		}762763		Ok(())764	}765}766767impl<Value> TrySet for PropertiesMap<Value> {768	type Value = Value;769770	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {771		Self::check_property_key(&key)?;772773		self.0774			.try_insert(key, value)775			.map_err(|_| PropertiesError::PropertyLimitReached)?;776777		Ok(())778	}779}780781pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;782783#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]784pub struct Properties {785	map: PropertiesMap<PropertyValue>,786	consumed_space: u32,787	space_limit: u32,788}789790impl Properties {791	pub fn new(space_limit: u32) -> Self {792		Self {793			map: PropertiesMap::new(),794			consumed_space: 0,795			space_limit,796		}797	}798799	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {800		let value = self.map.remove(key)?;801802		if let Some(ref value) = value {803			let value_len = value.len() as u32;804			self.consumed_space -= value_len;805		}806807		Ok(value)808	}809810	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {811		self.map.get(key)812	}813814	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {815		self.map.iter()816	}817}818819impl TrySet for Properties {820	type Value = PropertyValue;821822	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {823		let value_len = value.len();824825		if self.consumed_space as usize + value_len > self.space_limit as usize {826			return Err(PropertiesError::NoSpaceForProperty);827		}828829		self.map.try_set(key, value)?;830831		self.consumed_space += value_len as u32;832833		Ok(())834	}835}836837pub struct CollectionProperties;838839impl Get<Properties> for CollectionProperties {840	fn get() -> Properties {841		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)842	}843}844845pub struct TokenProperties;846847impl Get<Properties> for TokenProperties {848	fn get() -> Properties {849		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)850	}851}852853// RMRK854// todo document?855parameter_types! {856	#[derive(PartialEq, TypeInfo)]857	pub const RmrkStringLimit: u32 = 128;858	#[derive(PartialEq)]859	pub const RmrkCollectionSymbolLimit: u32 = 100;860	#[derive(PartialEq)]861	pub const RmrkResourceSymbolLimit: u32 = 10;862	#[derive(PartialEq)]863	pub const RmrkKeyLimit: u32 = 32;864	#[derive(PartialEq)]865	pub const RmrkValueLimit: u32 = 256;866	#[derive(PartialEq)]867	pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;868	#[derive(PartialEq)]869	pub const RmrkPartsLimit: u32 = 3;870}871872pub type RmrkCollectionInfo<AccountId> = CollectionInfo<873	RmrkString,874	BoundedVec<u8, RmrkCollectionSymbolLimit>,875	AccountId876>;877pub type RmrkInstanceInfo<AccountId> = NftInfo<878	AccountId, 879	Permill,880	RmrkString881>;882pub type RmrkResourceInfo = ResourceInfo::<883	BoundedVec<u8, RmrkResourceSymbolLimit>,884	RmrkString,885	BoundedVec<RmrkPartId, RmrkPartsLimit>886>;887pub type RmrkPropertyInfo = PropertyInfo<888	BoundedVec<u8, RmrkKeyLimit>, 889	BoundedVec<u8, RmrkValueLimit>890>;891pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;892pub type RmrkPartType = PartType<893	RmrkString,894	BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>895>;896pub type RmrkTheme = Theme<RmrkString, Vec<ThemeProperty<RmrkString>>>;897898pub type RmrkRpcString = Vec<u8>;899pub type RmrkThemeName = RmrkRpcString;900pub type RmrkPropertyKey = RmrkRpcString;901902type RmrkString = BoundedVec<u8, RmrkStringLimit>;