git.delta.rocks / unique-network / refs/commits / 60b6dbd39371

difftreelog

source

primitives/data-structs/src/lib.rs27.3 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	parameter_types,27};2829#[cfg(feature = "serde")]30use serde::{Serialize, Deserialize};3132use sp_core::U256;33use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};34use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};35use frame_support::{BoundedVec, traits::ConstU32};36use derivative::Derivative;37use scale_info::TypeInfo;3839// RMRK40use rmrk_traits::{41	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,42	ResourceTypes, BasicResource, ComposableResource, SlotResource,43};44pub use rmrk_traits::{45	primitives::{46		CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,47		PartId as RmrkPartId, ResourceId as RmrkResourceId,48	},49	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,50	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,51};5253mod bounded;54pub mod budget;55pub mod mapping;56mod migration;5758pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;59pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;60pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;6162pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {63	100_00064} else {65	1066};67pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {68	100_00069} else {70	1071};72pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {73	204874} else {75	1076};77pub const COLLECTION_ADMINS_LIMIT: u32 = 5;78pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;79pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {80	1_000_00081} else {82	1083};8485// Timeouts for item types in passed blocks86pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;87pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;88pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;8990pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9192// Schema limits93pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;94pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;95pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;9697pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;9899pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;100pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;101pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;102103pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;104pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;105pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;106107pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;108pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;109110/// How much items can be created per single111/// create_many call112pub const MAX_ITEMS_PER_BATCH: u32 = 200;113114pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;115116#[derive(117	Encode,118	Decode,119	PartialEq,120	Eq,121	PartialOrd,122	Ord,123	Clone,124	Copy,125	Debug,126	Default,127	TypeInfo,128	MaxEncodedLen,129)]130#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]131pub struct CollectionId(pub u32);132impl EncodeLike<u32> for CollectionId {}133impl EncodeLike<CollectionId> for u32 {}134135#[derive(136	Encode,137	Decode,138	PartialEq,139	Eq,140	PartialOrd,141	Ord,142	Clone,143	Copy,144	Debug,145	Default,146	TypeInfo,147	MaxEncodedLen,148)]149#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]150pub struct TokenId(pub u32);151impl EncodeLike<u32> for TokenId {}152impl EncodeLike<TokenId> for u32 {}153154impl TokenId {155	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {156		self.0157			.checked_add(1)158			.ok_or(ArithmeticError::Overflow)159			.map(Self)160	}161}162163impl From<TokenId> for U256 {164	fn from(t: TokenId) -> Self {165		t.0.into()166	}167}168169impl TryFrom<U256> for TokenId {170	type Error = &'static str;171172	fn try_from(value: U256) -> Result<Self, Self::Error> {173		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))174	}175}176177#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]178#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]179pub struct TokenData<CrossAccountId> {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, Copy, 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	#[version(..2)]290	pub access: AccessMode,291	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,292	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,293	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,294295	#[version(..2)]296	pub mint_mode: bool,297298	#[version(..2)]299	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,300301	#[version(..2)]302	pub schema_version: SchemaVersion,303	pub sponsorship: SponsorshipState<AccountId>,304305	pub limits: CollectionLimits,306307	#[version(2.., upper(Default::default()))]308	pub permissions: CollectionPermissions,309310	/// Marks that this collection is not "unique", and managed from external.311	#[version(2.., upper(false))]312	pub external_collection: bool,313314	#[version(..2)]315	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,316317	#[version(..2)]318	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,319320	#[version(..2)]321	pub meta_update_permission: MetaUpdatePermission,322}323324/// Used in RPC calls325#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]326#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]327pub struct RpcCollection<AccountId> {328	pub owner: AccountId,329	pub mode: CollectionMode,330	pub name: Vec<u16>,331	pub description: Vec<u16>,332	pub token_prefix: Vec<u8>,333	pub sponsorship: SponsorshipState<AccountId>,334	pub limits: CollectionLimits,335	pub permissions: CollectionPermissions,336	pub token_property_permissions: Vec<PropertyKeyPermission>,337	pub properties: Vec<Property>,338	pub read_only: bool,339}340341#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]342#[derivative(Debug, Default(bound = ""))]343pub struct CreateCollectionData<AccountId> {344	#[derivative(Default(value = "CollectionMode::NFT"))]345	pub mode: CollectionMode,346	pub access: Option<AccessMode>,347	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,348	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,349	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,350	pub pending_sponsor: Option<AccountId>,351	pub limits: Option<CollectionLimits>,352	pub permissions: Option<CollectionPermissions>,353	pub token_property_permissions: CollectionPropertiesPermissionsVec,354	pub properties: CollectionPropertiesVec,355}356357pub type CollectionPropertiesPermissionsVec =358	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;359360pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;361362/// All fields are wrapped in `Option`s, where None means chain default363// When adding/removing fields from this struct - don't forget to also update clamp_limits364#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]365#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]366pub struct CollectionLimits {367	pub account_token_ownership_limit: Option<u32>,368	pub sponsored_data_size: Option<u32>,369370	/// FIXME should we delete this or repurpose it?371	/// None - setVariableMetadata is not sponsored372	/// Some(v) - setVariableMetadata is sponsored373	///           if there is v block between txs374	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,375	pub token_limit: Option<u32>,376377	// Timeouts for item types in passed blocks378	pub sponsor_transfer_timeout: Option<u32>,379	pub sponsor_approve_timeout: Option<u32>,380	pub owner_can_transfer: Option<bool>,381	pub owner_can_destroy: Option<bool>,382	pub transfers_enabled: Option<bool>,383}384385impl CollectionLimits {386	pub fn account_token_ownership_limit(&self) -> u32 {387		self.account_token_ownership_limit388			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)389			.min(MAX_TOKEN_OWNERSHIP)390	}391	pub fn sponsored_data_size(&self) -> u32 {392		self.sponsored_data_size393			.unwrap_or(CUSTOM_DATA_LIMIT)394			.min(CUSTOM_DATA_LIMIT)395	}396	pub fn token_limit(&self) -> u32 {397		self.token_limit398			.unwrap_or(COLLECTION_TOKEN_LIMIT)399			.min(COLLECTION_TOKEN_LIMIT)400	}401	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {402		self.sponsor_transfer_timeout403			.unwrap_or(default)404			.min(MAX_SPONSOR_TIMEOUT)405	}406	pub fn sponsor_approve_timeout(&self) -> u32 {407		self.sponsor_approve_timeout408			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)409			.min(MAX_SPONSOR_TIMEOUT)410	}411	pub fn owner_can_transfer(&self) -> bool {412		self.owner_can_transfer.unwrap_or(true)413	}414	pub fn owner_can_destroy(&self) -> bool {415		self.owner_can_destroy.unwrap_or(true)416	}417	pub fn transfers_enabled(&self) -> bool {418		self.transfers_enabled.unwrap_or(true)419	}420	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {421		match self422			.sponsored_data_rate_limit423			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)424		{425			SponsoringRateLimit::SponsoringDisabled => None,426			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),427		}428	}429}430431// When adding/removing fields from this struct - don't forget to also update clamp_limits432#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]433#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]434pub struct CollectionPermissions {435	pub access: Option<AccessMode>,436	pub mint_mode: Option<bool>,437	pub nesting: Option<NestingPermissions>,438}439440impl CollectionPermissions {441	pub fn access(&self) -> AccessMode {442		self.access.unwrap_or(AccessMode::Normal)443	}444	pub fn mint_mode(&self) -> bool {445		self.mint_mode.unwrap_or(false)446	}447	pub fn nesting(&self) -> &NestingPermissions {448		static DEFAULT: NestingPermissions = NestingPermissions {449			token_owner: false,450			admin: false,451			restricted: None,452453			permissive: false,454		};455		self.nesting.as_ref().unwrap_or(&DEFAULT)456	}457}458459type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;460461#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]462#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]463#[derivative(Debug)]464pub struct OwnerRestrictedSet(465	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]466	#[derivative(Debug(format_with = "bounded::set_debug"))]467	pub OwnerRestrictedSetInner,468);469impl OwnerRestrictedSet {470	pub fn new() -> Self {471		Self(Default::default())472	}473}474impl core::ops::Deref for OwnerRestrictedSet {475	type Target = OwnerRestrictedSetInner;476	fn deref(&self) -> &Self::Target {477		&self.0478	}479}480impl core::ops::DerefMut for OwnerRestrictedSet {481	fn deref_mut(&mut self) -> &mut Self::Target {482		&mut self.0483	}484}485486#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]487#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]488#[derivative(Debug)]489pub struct NestingPermissions {490	/// Owner of token can nest tokens under it491	pub token_owner: bool,492	/// Admin of token collection can nest tokens under token493	pub admin: bool,494	/// If set - only tokens from specified collections can be nested495	pub restricted: Option<OwnerRestrictedSet>,496497	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`498	pub permissive: bool,499}500501#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]502#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]503pub enum SponsoringRateLimit {504	SponsoringDisabled,505	Blocks(u32),506}507508#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]509#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]510#[derivative(Debug)]511pub struct CreateNftData {512	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]513	#[derivative(Debug(format_with = "bounded::vec_debug"))]514	pub properties: CollectionPropertiesVec,515}516517#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]518#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]519pub struct CreateFungibleData {520	pub value: u128,521}522523#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]524#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]525#[derivative(Debug)]526pub struct CreateReFungibleData {527	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]528	#[derivative(Debug(format_with = "bounded::vec_debug"))]529	pub const_data: BoundedVec<u8, CustomDataLimit>,530	pub pieces: u128,531}532533#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]534#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]535pub enum MetaUpdatePermission {536	ItemOwner,537	Admin,538	None,539}540541#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]542#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]543pub enum CreateItemData {544	NFT(CreateNftData),545	Fungible(CreateFungibleData),546	ReFungible(CreateReFungibleData),547}548549#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]550#[derivative(Debug)]551pub struct CreateNftExData<CrossAccountId> {552	#[derivative(Debug(format_with = "bounded::vec_debug"))]553	pub properties: CollectionPropertiesVec,554	pub owner: CrossAccountId,555}556557#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]558#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]559pub struct CreateRefungibleExData<CrossAccountId> {560	#[derivative(Debug(format_with = "bounded::vec_debug"))]561	pub const_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::ReFungible(data) => data.const_data.len(),590			_ => 0,591		}592	}593}594595impl From<CreateNftData> for CreateItemData {596	fn from(item: CreateNftData) -> Self {597		CreateItemData::NFT(item)598	}599}600601impl From<CreateReFungibleData> for CreateItemData {602	fn from(item: CreateReFungibleData) -> Self {603		CreateItemData::ReFungible(item)604	}605}606607impl From<CreateFungibleData> for CreateItemData {608	fn from(item: CreateFungibleData) -> Self {609		CreateItemData::Fungible(item)610	}611}612613#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]614#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]615// todo possibly rename to be used generally as an address pair616pub struct TokenChild {617	pub token: TokenId,618	pub collection: CollectionId,619}620621#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]622#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]623pub struct CollectionStats {624	pub created: u32,625	pub destroyed: u32,626	pub alive: u32,627}628629#[derive(Encode, Decode, Clone, Debug)]630#[cfg_attr(feature = "std", derive(PartialEq))]631pub struct PhantomType<T>(core::marker::PhantomData<T>);632633impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {634	type Identity = PhantomType<T>;635636	fn type_info() -> scale_info::Type {637		use scale_info::{638			Type, Path,639			build::{FieldsBuilder, UnnamedFields},640			type_params,641		};642		Type::builder()643			.path(Path::new("up_data_structs", "PhantomType"))644			.type_params(type_params!(T))645			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))646	}647}648impl<T> MaxEncodedLen for PhantomType<T> {649	fn max_encoded_len() -> usize {650		0651	}652}653654pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;655pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;656657#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]658#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]659pub struct PropertyPermission {660	pub mutable: bool,661	pub collection_admin: bool,662	pub token_owner: bool,663}664665impl PropertyPermission {666	pub fn none() -> Self {667		Self {668			mutable: true,669			collection_admin: false,670			token_owner: false,671		}672	}673}674675#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]676#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]677pub struct Property {678	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]679	pub key: PropertyKey,680681	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]682	pub value: PropertyValue,683}684685impl Into<(PropertyKey, PropertyValue)> for Property {686	fn into(self) -> (PropertyKey, PropertyValue) {687		(self.key, self.value)688	}689}690691#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]692#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]693pub struct PropertyKeyPermission {694	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]695	pub key: PropertyKey,696697	pub permission: PropertyPermission,698}699700impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {701	fn into(self) -> (PropertyKey, PropertyPermission) {702		(self.key, self.permission)703	}704}705706#[derive(Debug)]707pub enum PropertiesError {708	NoSpaceForProperty,709	PropertyLimitReached,710	InvalidCharacterInPropertyKey,711	PropertyKeyIsTooLong,712	EmptyPropertyKey,713}714715#[derive(Clone, Copy)]716pub enum PropertyScope {717	None,718	Rmrk,719}720721impl PropertyScope {722	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {723		let scope_str: &[u8] = match self {724			Self::None => return Ok(key),725			Self::Rmrk => b"rmrk",726		};727728		[scope_str, b":", key.as_slice()]729			.concat()730			.try_into()731			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)732	}733}734735pub trait TrySetProperty: Sized {736	type Value;737738	fn try_scoped_set(739		&mut self,740		scope: PropertyScope,741		key: PropertyKey,742		value: Self::Value,743	) -> Result<(), PropertiesError>;744745	fn try_scoped_set_from_iter<I, KV>(746		&mut self,747		scope: PropertyScope,748		iter: I,749	) -> Result<(), PropertiesError>750	where751		I: Iterator<Item = KV>,752		KV: Into<(PropertyKey, Self::Value)>,753	{754		for kv in iter {755			let (key, value) = kv.into();756			self.try_scoped_set(scope, key, value)?;757		}758759		Ok(())760	}761762	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {763		self.try_scoped_set(PropertyScope::None, key, value)764	}765766	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>767	where768		I: Iterator<Item = KV>,769		KV: Into<(PropertyKey, Self::Value)>,770	{771		self.try_scoped_set_from_iter(PropertyScope::None, iter)772	}773}774775#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]776#[derivative(Default(bound = ""))]777pub struct PropertiesMap<Value>(778	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,779);780781impl<Value> PropertiesMap<Value> {782	pub fn new() -> Self {783		Self(BoundedBTreeMap::new())784	}785786	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {787		Self::check_property_key(key)?;788789		Ok(self.0.remove(key))790	}791792	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {793		self.0.get(key)794	}795796	pub fn contains_key(&self, key: &PropertyKey) -> bool {797		self.0.contains_key(key)798	}799800	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {801		if key.is_empty() {802			return Err(PropertiesError::EmptyPropertyKey);803		}804805		for byte in key.as_slice().iter() {806			let byte = *byte;807808			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {809				return Err(PropertiesError::InvalidCharacterInPropertyKey);810			}811		}812813		Ok(())814	}815}816817impl<Value> IntoIterator for PropertiesMap<Value> {818	type Item = (PropertyKey, Value);819	type IntoIter = <820		BoundedBTreeMap<821			PropertyKey,822			Value,823			ConstU32<MAX_PROPERTIES_PER_ITEM>824		> as IntoIterator825	>::IntoIter;826827	fn into_iter(self) -> Self::IntoIter {828		self.0.into_iter()829	}830}831832impl<Value> TrySetProperty for PropertiesMap<Value> {833	type Value = Value;834835	fn try_scoped_set(836		&mut self,837		scope: PropertyScope,838		key: PropertyKey,839		value: Self::Value,840	) -> Result<(), PropertiesError> {841		Self::check_property_key(&key)?;842843		let key = scope.apply(key)?;844		self.0845			.try_insert(key, value)846			.map_err(|_| PropertiesError::PropertyLimitReached)?;847848		Ok(())849	}850}851852pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;853854#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]855pub struct Properties {856	map: PropertiesMap<PropertyValue>,857	consumed_space: u32,858	space_limit: u32,859}860861impl Properties {862	pub fn new(space_limit: u32) -> Self {863		Self {864			map: PropertiesMap::new(),865			consumed_space: 0,866			space_limit,867		}868	}869870	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {871		let value = self.map.remove(key)?;872873		if let Some(ref value) = value {874			let value_len = value.len() as u32;875			self.consumed_space -= value_len;876		}877878		Ok(value)879	}880881	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {882		self.map.get(key)883	}884}885886impl IntoIterator for Properties {887	type Item = (PropertyKey, PropertyValue);888	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;889890	fn into_iter(self) -> Self::IntoIter {891		self.map.into_iter()892	}893}894895impl TrySetProperty for Properties {896	type Value = PropertyValue;897898	fn try_scoped_set(899		&mut self,900		scope: PropertyScope,901		key: PropertyKey,902		value: Self::Value,903	) -> Result<(), PropertiesError> {904		let value_len = value.len();905906		if self.consumed_space as usize + value_len > self.space_limit as usize907			&& !cfg!(feature = "runtime-benchmarks")908		{909			return Err(PropertiesError::NoSpaceForProperty);910		}911912		self.map.try_scoped_set(scope, key, value)?;913914		self.consumed_space += value_len as u32;915916		Ok(())917	}918}919920pub struct CollectionProperties;921922impl Get<Properties> for CollectionProperties {923	fn get() -> Properties {924		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)925	}926}927928pub struct TokenProperties;929930impl Get<Properties> for TokenProperties {931	fn get() -> Properties {932		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)933	}934}935936// RMRK937// todo document?938parameter_types! {939	#[derive(PartialEq, TypeInfo)]940	pub const RmrkStringLimit: u32 = 128;941	#[derive(PartialEq)]942	pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;943	#[derive(PartialEq)]944	pub const RmrkResourceSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;945	#[derive(PartialEq)]946	pub const RmrkKeyLimit: u32 = 32;947	#[derive(PartialEq)]948	pub const RmrkValueLimit: u32 = 256;949	#[derive(PartialEq)]950	pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;951	#[derive(PartialEq)]952	pub const RmrkPartsLimit: u32 = 25;953	#[derive(PartialEq)]954	pub const RmrkMaxPriorities: u32 = 25;955}956957impl From<RmrkCollectionId> for CollectionId {958	fn from(id: RmrkCollectionId) -> Self {959		Self(id)960	}961}962963impl From<RmrkNftId> for TokenId {964	fn from(id: RmrkNftId) -> Self {965		Self(id)966	}967}968969pub type RmrkCollectionInfo<AccountId> =970	CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;971pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;972pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;973pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;974pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;975pub type RmrkPartType =976	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;977pub type RmrkThemeProperty = ThemeProperty<RmrkString>;978pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;979pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;980981pub type RmrkBasicResource = BasicResource<RmrkString>;982pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;983pub type RmrkSlotResource = SlotResource<RmrkString>;984985pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;986pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;987pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;988pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;989pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;990pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed991992pub type RmrkRpcString = Vec<u8>;993pub type RmrkThemeName = RmrkRpcString;994pub type RmrkPropertyKey = RmrkRpcString;