git.delta.rocks / unique-network / refs/commits / f621fdc52c76

difftreelog

source

primitives/data-structs/src/lib.rs27.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,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(false)413	}414	pub fn owner_can_transfer_instaled(&self) -> bool {415		self.owner_can_transfer.is_some()416	}417	pub fn owner_can_destroy(&self) -> bool {418		self.owner_can_destroy.unwrap_or(true)419	}420	pub fn transfers_enabled(&self) -> bool {421		self.transfers_enabled.unwrap_or(true)422	}423	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {424		match self425			.sponsored_data_rate_limit426			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)427		{428			SponsoringRateLimit::SponsoringDisabled => None,429			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),430		}431	}432}433434// When adding/removing fields from this struct - don't forget to also update clamp_limits435#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]436#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]437pub struct CollectionPermissions {438	pub access: Option<AccessMode>,439	pub mint_mode: Option<bool>,440	pub nesting: Option<NestingPermissions>,441}442443impl CollectionPermissions {444	pub fn access(&self) -> AccessMode {445		self.access.unwrap_or(AccessMode::Normal)446	}447	pub fn mint_mode(&self) -> bool {448		self.mint_mode.unwrap_or(false)449	}450	pub fn nesting(&self) -> &NestingPermissions {451		static DEFAULT: NestingPermissions = NestingPermissions {452			token_owner: false,453			collection_admin: false,454			restricted: None,455456			permissive: false,457		};458		self.nesting.as_ref().unwrap_or(&DEFAULT)459	}460}461462type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;463464#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]465#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]466#[derivative(Debug)]467pub struct OwnerRestrictedSet(468	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]469	#[derivative(Debug(format_with = "bounded::set_debug"))]470	pub OwnerRestrictedSetInner,471);472impl OwnerRestrictedSet {473	pub fn new() -> Self {474		Self(Default::default())475	}476}477impl core::ops::Deref for OwnerRestrictedSet {478	type Target = OwnerRestrictedSetInner;479	fn deref(&self) -> &Self::Target {480		&self.0481	}482}483impl core::ops::DerefMut for OwnerRestrictedSet {484	fn deref_mut(&mut self) -> &mut Self::Target {485		&mut self.0486	}487}488489#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]490#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]491#[derivative(Debug)]492pub struct NestingPermissions {493	/// Owner of token can nest tokens under it494	pub token_owner: bool,495	/// Admin of token collection can nest tokens under token496	pub collection_admin: bool,497	/// If set - only tokens from specified collections can be nested498	pub restricted: Option<OwnerRestrictedSet>,499500	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`501	pub permissive: bool,502}503504#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]505#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]506pub enum SponsoringRateLimit {507	SponsoringDisabled,508	Blocks(u32),509}510511#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]512#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]513#[derivative(Debug)]514pub struct CreateNftData {515	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]516	#[derivative(Debug(format_with = "bounded::vec_debug"))]517	pub properties: CollectionPropertiesVec,518}519520#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]521#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]522pub struct CreateFungibleData {523	pub value: u128,524}525526#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]527#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]528#[derivative(Debug)]529pub struct CreateReFungibleData {530	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]531	#[derivative(Debug(format_with = "bounded::vec_debug"))]532	pub const_data: BoundedVec<u8, CustomDataLimit>,533	pub pieces: u128,534}535536#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]537#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]538pub enum MetaUpdatePermission {539	ItemOwner,540	Admin,541	None,542}543544#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]545#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]546pub enum CreateItemData {547	NFT(CreateNftData),548	Fungible(CreateFungibleData),549	ReFungible(CreateReFungibleData),550}551552#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]553#[derivative(Debug)]554pub struct CreateNftExData<CrossAccountId> {555	#[derivative(Debug(format_with = "bounded::vec_debug"))]556	pub properties: CollectionPropertiesVec,557	pub owner: CrossAccountId,558}559560#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]561#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]562pub struct CreateRefungibleExData<CrossAccountId> {563	#[derivative(Debug(format_with = "bounded::vec_debug"))]564	pub const_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::ReFungible(data) => data.const_data.len(),593			_ => 0,594		}595	}596}597598impl From<CreateNftData> for CreateItemData {599	fn from(item: CreateNftData) -> Self {600		CreateItemData::NFT(item)601	}602}603604impl From<CreateReFungibleData> for CreateItemData {605	fn from(item: CreateReFungibleData) -> Self {606		CreateItemData::ReFungible(item)607	}608}609610impl From<CreateFungibleData> for CreateItemData {611	fn from(item: CreateFungibleData) -> Self {612		CreateItemData::Fungible(item)613	}614}615616#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]617#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]618// todo possibly rename to be used generally as an address pair619pub struct TokenChild {620	pub token: TokenId,621	pub collection: CollectionId,622}623624#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]625#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]626pub struct CollectionStats {627	pub created: u32,628	pub destroyed: u32,629	pub alive: u32,630}631632#[derive(Encode, Decode, Clone, Debug)]633#[cfg_attr(feature = "std", derive(PartialEq))]634pub struct PhantomType<T>(core::marker::PhantomData<T>);635636impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {637	type Identity = PhantomType<T>;638639	fn type_info() -> scale_info::Type {640		use scale_info::{641			Type, Path,642			build::{FieldsBuilder, UnnamedFields},643			type_params,644		};645		Type::builder()646			.path(Path::new("up_data_structs", "PhantomType"))647			.type_params(type_params!(T))648			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))649	}650}651impl<T> MaxEncodedLen for PhantomType<T> {652	fn max_encoded_len() -> usize {653		0654	}655}656657pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;658pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;659660#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]661#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]662pub struct PropertyPermission {663	pub mutable: bool,664	pub collection_admin: bool,665	pub token_owner: bool,666}667668impl PropertyPermission {669	pub fn none() -> Self {670		Self {671			mutable: true,672			collection_admin: false,673			token_owner: false,674		}675	}676}677678#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]679#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]680pub struct Property {681	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]682	pub key: PropertyKey,683684	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]685	pub value: PropertyValue,686}687688impl Into<(PropertyKey, PropertyValue)> for Property {689	fn into(self) -> (PropertyKey, PropertyValue) {690		(self.key, self.value)691	}692}693694#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]695#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]696pub struct PropertyKeyPermission {697	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]698	pub key: PropertyKey,699700	pub permission: PropertyPermission,701}702703impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {704	fn into(self) -> (PropertyKey, PropertyPermission) {705		(self.key, self.permission)706	}707}708709#[derive(Debug)]710pub enum PropertiesError {711	NoSpaceForProperty,712	PropertyLimitReached,713	InvalidCharacterInPropertyKey,714	PropertyKeyIsTooLong,715	EmptyPropertyKey,716}717718#[derive(Clone, Copy)]719pub enum PropertyScope {720	None,721	Rmrk,722}723724impl PropertyScope {725	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {726		let scope_str: &[u8] = match self {727			Self::None => return Ok(key),728			Self::Rmrk => b"rmrk",729		};730731		[scope_str, b":", key.as_slice()]732			.concat()733			.try_into()734			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)735	}736}737738pub trait TrySetProperty: Sized {739	type Value;740741	fn try_scoped_set(742		&mut self,743		scope: PropertyScope,744		key: PropertyKey,745		value: Self::Value,746	) -> Result<(), PropertiesError>;747748	fn try_scoped_set_from_iter<I, KV>(749		&mut self,750		scope: PropertyScope,751		iter: I,752	) -> Result<(), PropertiesError>753	where754		I: Iterator<Item = KV>,755		KV: Into<(PropertyKey, Self::Value)>,756	{757		for kv in iter {758			let (key, value) = kv.into();759			self.try_scoped_set(scope, key, value)?;760		}761762		Ok(())763	}764765	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {766		self.try_scoped_set(PropertyScope::None, key, value)767	}768769	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>770	where771		I: Iterator<Item = KV>,772		KV: Into<(PropertyKey, Self::Value)>,773	{774		self.try_scoped_set_from_iter(PropertyScope::None, iter)775	}776}777778#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]779#[derivative(Default(bound = ""))]780pub struct PropertiesMap<Value>(781	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,782);783784impl<Value> PropertiesMap<Value> {785	pub fn new() -> Self {786		Self(BoundedBTreeMap::new())787	}788789	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {790		Self::check_property_key(key)?;791792		Ok(self.0.remove(key))793	}794795	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {796		self.0.get(key)797	}798799	pub fn contains_key(&self, key: &PropertyKey) -> bool {800		self.0.contains_key(key)801	}802803	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {804		if key.is_empty() {805			return Err(PropertiesError::EmptyPropertyKey);806		}807808		for byte in key.as_slice().iter() {809			let byte = *byte;810811			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {812				return Err(PropertiesError::InvalidCharacterInPropertyKey);813			}814		}815816		Ok(())817	}818}819820impl<Value> IntoIterator for PropertiesMap<Value> {821	type Item = (PropertyKey, Value);822	type IntoIter = <823		BoundedBTreeMap<824			PropertyKey,825			Value,826			ConstU32<MAX_PROPERTIES_PER_ITEM>827		> as IntoIterator828	>::IntoIter;829830	fn into_iter(self) -> Self::IntoIter {831		self.0.into_iter()832	}833}834835impl<Value> TrySetProperty for PropertiesMap<Value> {836	type Value = Value;837838	fn try_scoped_set(839		&mut self,840		scope: PropertyScope,841		key: PropertyKey,842		value: Self::Value,843	) -> Result<(), PropertiesError> {844		Self::check_property_key(&key)?;845846		let key = scope.apply(key)?;847		self.0848			.try_insert(key, value)849			.map_err(|_| PropertiesError::PropertyLimitReached)?;850851		Ok(())852	}853}854855pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;856857#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]858pub struct Properties {859	map: PropertiesMap<PropertyValue>,860	consumed_space: u32,861	space_limit: u32,862}863864impl Properties {865	pub fn new(space_limit: u32) -> Self {866		Self {867			map: PropertiesMap::new(),868			consumed_space: 0,869			space_limit,870		}871	}872873	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {874		let value = self.map.remove(key)?;875876		if let Some(ref value) = value {877			let value_len = value.len() as u32;878			self.consumed_space -= value_len;879		}880881		Ok(value)882	}883884	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {885		self.map.get(key)886	}887}888889impl IntoIterator for Properties {890	type Item = (PropertyKey, PropertyValue);891	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;892893	fn into_iter(self) -> Self::IntoIter {894		self.map.into_iter()895	}896}897898impl TrySetProperty for Properties {899	type Value = PropertyValue;900901	fn try_scoped_set(902		&mut self,903		scope: PropertyScope,904		key: PropertyKey,905		value: Self::Value,906	) -> Result<(), PropertiesError> {907		let value_len = value.len();908909		if self.consumed_space as usize + value_len > self.space_limit as usize910			&& !cfg!(feature = "runtime-benchmarks")911		{912			return Err(PropertiesError::NoSpaceForProperty);913		}914915		self.map.try_scoped_set(scope, key, value)?;916917		self.consumed_space += value_len as u32;918919		Ok(())920	}921}922923pub struct CollectionProperties;924925impl Get<Properties> for CollectionProperties {926	fn get() -> Properties {927		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)928	}929}930931pub struct TokenProperties;932933impl Get<Properties> for TokenProperties {934	fn get() -> Properties {935		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)936	}937}938939// RMRK940// todo document?941parameter_types! {942	#[derive(PartialEq, TypeInfo)]943	pub const RmrkStringLimit: u32 = 128;944	#[derive(PartialEq)]945	pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;946	#[derive(PartialEq)]947	pub const RmrkResourceSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;948	#[derive(PartialEq)]949	pub const RmrkKeyLimit: u32 = 32;950	#[derive(PartialEq)]951	pub const RmrkValueLimit: u32 = 256;952	#[derive(PartialEq)]953	pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;954	#[derive(PartialEq)]955	pub const RmrkPartsLimit: u32 = 25;956	#[derive(PartialEq)]957	pub const RmrkMaxPriorities: u32 = 25;958	#[derive(PartialEq)]959	pub const MaxResourcesOnMint: u32 = 100;960}961962impl From<RmrkCollectionId> for CollectionId {963	fn from(id: RmrkCollectionId) -> Self {964		Self(id)965	}966}967968impl From<RmrkNftId> for TokenId {969	fn from(id: RmrkNftId) -> Self {970		Self(id)971	}972}973974pub type RmrkCollectionInfo<AccountId> =975	CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;976pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;977pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;978pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;979pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;980pub type RmrkPartType =981	PartType<RmrkString, BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>>;982pub type RmrkThemeProperty = ThemeProperty<RmrkString>;983pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;984pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;985986pub type RmrkBasicResource = BasicResource<RmrkString>;987pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;988pub type RmrkSlotResource = SlotResource<RmrkString>;989990pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;991pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;992pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;993pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;994pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;995pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed996997pub type RmrkRpcString = Vec<u8>;998pub type RmrkThemeName = RmrkRpcString;999pub type RmrkPropertyKey = RmrkRpcString;