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

difftreelog

Restore variable_on_chain_schema in version 2

Daniel Shiposha2022-05-12parent: #b278b7e.patch.diff
in: master

1 file changed

modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
before · primitives/data-structs/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20	convert::{TryFrom, TryInto},21	fmt,22};23use frame_support::{24	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25	traits::Get,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;3738mod bounded;39pub mod budget;40pub mod mapping;41mod migration;4243pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;44pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;45pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;4647pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {48	100_00049} else {50	1051};52pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {53	100_00054} else {55	1056};57pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {58	204859} else {60	1061};62pub const COLLECTION_ADMINS_LIMIT: u32 = 5;63pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;64pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {65	1_000_00066} else {67	1068};6970// Timeouts for item types in passed blocks71pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;72pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;73pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;7475pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;7677// Schema limits78pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;79pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8081pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;8283pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;84pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;85pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8687pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;88pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;89pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;9091// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;92pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;93pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;9495pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =96	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;9798pub struct MaxPropertiesPermissionsEncodeLen;99100impl Get<u32> for MaxPropertiesPermissionsEncodeLen {101	fn get() -> u32 {102		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH103			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32104	}105}106107/// How much items can be created per single108/// create_many call109pub const MAX_ITEMS_PER_BATCH: u32 = 200;110111pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;112113#[derive(114	Encode,115	Decode,116	PartialEq,117	Eq,118	PartialOrd,119	Ord,120	Clone,121	Copy,122	Debug,123	Default,124	TypeInfo,125	MaxEncodedLen,126)]127#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]128pub struct CollectionId(pub u32);129impl EncodeLike<u32> for CollectionId {}130impl EncodeLike<CollectionId> for u32 {}131132#[derive(133	Encode,134	Decode,135	PartialEq,136	Eq,137	PartialOrd,138	Ord,139	Clone,140	Copy,141	Debug,142	Default,143	TypeInfo,144	MaxEncodedLen,145)]146#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]147pub struct TokenId(pub u32);148impl EncodeLike<u32> for TokenId {}149impl EncodeLike<TokenId> for u32 {}150151impl TokenId {152	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {153		self.0154			.checked_add(1)155			.ok_or(ArithmeticError::Overflow)156			.map(Self)157	}158}159160impl From<TokenId> for U256 {161	fn from(t: TokenId) -> Self {162		t.0.into()163	}164}165166impl TryFrom<U256> for TokenId {167	type Error = &'static str;168169	fn try_from(value: U256) -> Result<Self, Self::Error> {170		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))171	}172}173174#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]175#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]176pub struct TokenData<CrossAccountId> {177	pub const_data: Vec<u8>,178	pub properties: Vec<Property>,179	pub owner: Option<CrossAccountId>,180}181182pub struct OverflowError;183impl From<OverflowError> for &'static str {184	fn from(_: OverflowError) -> Self {185		"overflow occured"186	}187}188189pub type DecimalPoints = u8;190191#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]192#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]193pub enum CollectionMode {194	NFT,195	// decimal points196	Fungible(DecimalPoints),197	ReFungible,198}199200impl CollectionMode {201	pub fn id(&self) -> u8 {202		match self {203			CollectionMode::NFT => 1,204			CollectionMode::Fungible(_) => 2,205			CollectionMode::ReFungible => 3,206		}207	}208}209210pub trait SponsoringResolve<AccountId, Call> {211	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;212}213214#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]215#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]216pub enum AccessMode {217	Normal,218	AllowList,219}220impl Default for AccessMode {221	fn default() -> Self {222		Self::Normal223	}224}225226#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]227#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]228pub enum SchemaVersion {229	ImageURL,230	Unique,231}232impl Default for SchemaVersion {233	fn default() -> Self {234		Self::ImageURL235	}236}237238#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]239#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]240pub struct Ownership<AccountId> {241	pub owner: AccountId,242	pub fraction: u128,243}244245#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]246#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]247pub enum SponsorshipState<AccountId> {248	/// The fees are applied to the transaction sender249	Disabled,250	Unconfirmed(AccountId),251	/// Transactions are sponsored by specified account252	Confirmed(AccountId),253}254255impl<AccountId> SponsorshipState<AccountId> {256	pub fn sponsor(&self) -> Option<&AccountId> {257		match self {258			Self::Confirmed(sponsor) => Some(sponsor),259			_ => None,260		}261	}262263	pub fn pending_sponsor(&self) -> Option<&AccountId> {264		match self {265			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),266			_ => None,267		}268	}269270	pub fn confirmed(&self) -> bool {271		matches!(self, Self::Confirmed(_))272	}273}274275impl<T> Default for SponsorshipState<T> {276	fn default() -> Self {277		Self::Disabled278	}279}280281/// Used in storage282#[struct_versioning::versioned(version = 2, upper)]283#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]284pub struct Collection<AccountId> {285	pub owner: AccountId,286	pub mode: CollectionMode,287	pub access: AccessMode,288	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,289	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,290	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,291	pub mint_mode: bool,292293	#[version(..2)]294	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,295296	pub schema_version: SchemaVersion,297	pub sponsorship: SponsorshipState<AccountId>,298299	#[version(..2)]300	pub limits: CollectionLimitsVersion1, // Collection private restrictions301	#[version(2.., upper(limits.into()))]302	pub limits: CollectionLimitsVersion2,303304	#[version(..2)]305	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,306307	pub meta_update_permission: MetaUpdatePermission,308}309310/// Used in RPC calls311#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]312#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]313pub struct RpcCollection<AccountId> {314	pub owner: AccountId,315	pub mode: CollectionMode,316	pub access: AccessMode,317	pub name: Vec<u16>,318	pub description: Vec<u16>,319	pub token_prefix: Vec<u8>,320	pub mint_mode: bool,321	pub offchain_schema: Vec<u8>,322	pub schema_version: SchemaVersion,323	pub sponsorship: SponsorshipState<AccountId>,324	pub limits: CollectionLimits,325	pub const_on_chain_schema: Vec<u8>,326	pub meta_update_permission: MetaUpdatePermission,327	pub token_property_permissions: Vec<PropertyKeyPermission>,328	pub properties: Vec<Property>,329}330331#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]332#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]333pub enum CollectionField {334	ConstOnChainSchema,335	OffchainSchema,336}337338#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]339#[derivative(Debug, Default(bound = ""))]340pub struct CreateCollectionData<AccountId> {341	#[derivative(Default(value = "CollectionMode::NFT"))]342	pub mode: CollectionMode,343	pub access: Option<AccessMode>,344	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,345	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,346	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,347	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,348	pub schema_version: Option<SchemaVersion>,349	pub pending_sponsor: Option<AccountId>,350	pub limits: Option<CollectionLimits>,351	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,352	pub meta_update_permission: Option<MetaUpdatePermission>,353	pub token_property_permissions: CollectionPropertiesPermissionsVec,354	pub properties: CollectionPropertiesVec,355}356357pub type CollectionPropertiesPermissionsVec =358	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;359360pub type CollectionPropertiesVec =361	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;362363#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]364#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]365pub struct NftItemType<AccountId> {366	pub owner: AccountId,367	pub const_data: Vec<u8>,368	pub variable_data: Vec<u8>,369}370371#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]372#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]373pub struct FungibleItemType {374	pub value: u128,375}376377#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]378#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]379pub struct ReFungibleItemType<AccountId> {380	pub owner: Vec<Ownership<AccountId>>,381	pub const_data: Vec<u8>,382	pub variable_data: Vec<u8>,383}384385/// All fields are wrapped in `Option`s, where None means chain default386#[struct_versioning::versioned(version = 2, upper)]387#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]388#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]389pub struct CollectionLimits {390	pub account_token_ownership_limit: Option<u32>,391	pub sponsored_data_size: Option<u32>,392	/// None - setVariableMetadata is not sponsored393	/// Some(v) - setVariableMetadata is sponsored394	///           if there is v block between txs395	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,396	pub token_limit: Option<u32>,397398	// Timeouts for item types in passed blocks399	pub sponsor_transfer_timeout: Option<u32>,400	pub sponsor_approve_timeout: Option<u32>,401	pub owner_can_transfer: Option<bool>,402	pub owner_can_destroy: Option<bool>,403	pub transfers_enabled: Option<bool>,404405	#[version(2.., upper(None))]406	pub nesting_rule: Option<NestingRule>,407}408409impl CollectionLimits {410	pub fn account_token_ownership_limit(&self) -> u32 {411		self.account_token_ownership_limit412			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)413			.min(MAX_TOKEN_OWNERSHIP)414	}415	pub fn sponsored_data_size(&self) -> u32 {416		self.sponsored_data_size417			.unwrap_or(CUSTOM_DATA_LIMIT)418			.min(CUSTOM_DATA_LIMIT)419	}420	pub fn token_limit(&self) -> u32 {421		self.token_limit422			.unwrap_or(COLLECTION_TOKEN_LIMIT)423			.min(COLLECTION_TOKEN_LIMIT)424	}425	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {426		self.sponsor_transfer_timeout427			.unwrap_or(default)428			.min(MAX_SPONSOR_TIMEOUT)429	}430	pub fn sponsor_approve_timeout(&self) -> u32 {431		self.sponsor_approve_timeout432			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)433			.min(MAX_SPONSOR_TIMEOUT)434	}435	pub fn owner_can_transfer(&self) -> bool {436		self.owner_can_transfer.unwrap_or(true)437	}438	pub fn owner_can_destroy(&self) -> bool {439		self.owner_can_destroy.unwrap_or(true)440	}441	pub fn transfers_enabled(&self) -> bool {442		self.transfers_enabled.unwrap_or(true)443	}444	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {445		match self446			.sponsored_data_rate_limit447			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)448		{449			SponsoringRateLimit::SponsoringDisabled => None,450			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),451		}452	}453	pub fn nesting_rule(&self) -> &NestingRule {454		static DEFAULT: NestingRule = NestingRule::Disabled;455		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)456	}457}458459#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]460#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]461#[derivative(Debug)]462pub enum NestingRule {463	/// No one can nest tokens464	Disabled,465	/// Owner can nest any tokens466	Owner,467	/// Owner can nest tokens from specified collections468	OwnerRestricted(469		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]470		#[derivative(Debug(format_with = "bounded::set_debug"))]471		BoundedBTreeSet<CollectionId, ConstU32<16>>,472	),473}474475#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]476#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]477pub enum SponsoringRateLimit {478	SponsoringDisabled,479	Blocks(u32),480}481482#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]483#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]484#[derivative(Debug)]485pub struct CreateNftData {486	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]487	#[derivative(Debug(format_with = "bounded::vec_debug"))]488	pub const_data: BoundedVec<u8, CustomDataLimit>,489	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]490	#[derivative(Debug(format_with = "bounded::vec_debug"))]491	pub variable_data: BoundedVec<u8, CustomDataLimit>,492493	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]494	#[derivative(Debug(format_with = "bounded::vec_debug"))]495	pub properties: CollectionPropertiesVec,496}497498#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]499#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]500pub struct CreateFungibleData {501	pub value: u128,502}503504#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]505#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]506#[derivative(Debug)]507pub struct CreateReFungibleData {508	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]509	#[derivative(Debug(format_with = "bounded::vec_debug"))]510	pub const_data: BoundedVec<u8, CustomDataLimit>,511	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]512	#[derivative(Debug(format_with = "bounded::vec_debug"))]513	pub variable_data: BoundedVec<u8, CustomDataLimit>,514	pub pieces: u128,515}516517#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]518#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]519pub enum MetaUpdatePermission {520	ItemOwner,521	Admin,522	None,523}524525impl Default for MetaUpdatePermission {526	fn default() -> Self {527		Self::ItemOwner528	}529}530531#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]532#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]533pub enum CreateItemData {534	NFT(CreateNftData),535	Fungible(CreateFungibleData),536	ReFungible(CreateReFungibleData),537}538539#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]540#[derivative(Debug)]541pub struct CreateNftExData<CrossAccountId> {542	#[derivative(Debug(format_with = "bounded::vec_debug"))]543	pub const_data: BoundedVec<u8, CustomDataLimit>,544	#[derivative(Debug(format_with = "bounded::vec_debug"))]545	pub variable_data: BoundedVec<u8, CustomDataLimit>,546	#[derivative(Debug(format_with = "bounded::vec_debug"))]547	pub properties: CollectionPropertiesVec,548	pub owner: CrossAccountId,549}550551#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]552#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]553pub struct CreateRefungibleExData<CrossAccountId> {554	#[derivative(Debug(format_with = "bounded::vec_debug"))]555	pub const_data: BoundedVec<u8, CustomDataLimit>,556	#[derivative(Debug(format_with = "bounded::vec_debug"))]557	pub variable_data: BoundedVec<u8, CustomDataLimit>,558	#[derivative(Debug(format_with = "bounded::map_debug"))]559	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,560}561562#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]563#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]564pub enum CreateItemExData<CrossAccountId> {565	NFT(566		#[derivative(Debug(format_with = "bounded::vec_debug"))]567		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,568	),569	Fungible(570		#[derivative(Debug(format_with = "bounded::map_debug"))]571		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,572	),573	/// Many tokens, each may have only one owner574	RefungibleMultipleItems(575		#[derivative(Debug(format_with = "bounded::vec_debug"))]576		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,577	),578	/// Single token, which may have many owners579	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),580}581582impl CreateItemData {583	pub fn data_size(&self) -> usize {584		match self {585			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),586			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),587			_ => 0,588		}589	}590}591592impl From<CreateNftData> for CreateItemData {593	fn from(item: CreateNftData) -> Self {594		CreateItemData::NFT(item)595	}596}597598impl From<CreateReFungibleData> for CreateItemData {599	fn from(item: CreateReFungibleData) -> Self {600		CreateItemData::ReFungible(item)601	}602}603604impl From<CreateFungibleData> for CreateItemData {605	fn from(item: CreateFungibleData) -> Self {606		CreateItemData::Fungible(item)607	}608}609610#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]611#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]612pub struct CollectionStats {613	pub created: u32,614	pub destroyed: u32,615	pub alive: u32,616}617618#[derive(Encode, Decode, PartialEq, Clone, Debug)]619pub struct PhantomType<T>(core::marker::PhantomData<T>);620621impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {622	type Identity = PhantomType<T>;623624	fn type_info() -> scale_info::Type {625		use scale_info::{626			Type, Path,627			build::{FieldsBuilder, UnnamedFields},628			type_params,629		};630		Type::builder()631			.path(Path::new("up_data_structs", "PhantomType"))632			.type_params(type_params!(T))633			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))634	}635}636impl<T> MaxEncodedLen for PhantomType<T> {637	fn max_encoded_len() -> usize {638		0639	}640}641642pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;643pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;644645#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]646#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]647pub struct PropertyPermission {648	pub mutable: bool,649	pub collection_admin: bool,650	pub token_owner: bool,651}652653impl PropertyPermission {654	pub fn none() -> Self {655		Self {656			mutable: true,657			collection_admin: false,658			token_owner: false,659		}660	}661}662663#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]664#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]665pub struct Property {666	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]667	pub key: PropertyKey,668669	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]670	pub value: PropertyValue,671}672673#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]674#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]675pub struct PropertyKeyPermission {676	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]677	pub key: PropertyKey,678679	pub permission: PropertyPermission,680}681682pub enum PropertiesError {683	NoSpaceForProperty,684	PropertyLimitReached,685	InvalidCharacterInPropertyKey,686	EmptyPropertyKey,687}688689pub trait TrySet: Sized {690	type Value;691692	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;693694	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>695	where696		I: Iterator<Item = (PropertyKey, Self::Value)>,697	{698		for (key, value) in iter {699			self.try_set(key, value)?;700		}701702		Ok(())703	}704}705706#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]707#[derivative(Default(bound = ""))]708pub struct PropertiesMap<Value>(709	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,710);711712impl<Value> PropertiesMap<Value> {713	pub fn new() -> Self {714		Self(BoundedBTreeMap::new())715	}716717	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {718		Self::check_property_key(key)?;719720		Ok(self.0.remove(key))721	}722723	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {724		self.0.get(key)725	}726727	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {728		self.0.iter()729	}730731	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {732		if key.is_empty() {733			return Err(PropertiesError::EmptyPropertyKey);734		}735736		for byte in key.as_slice().iter() {737			match char::from_u32(*byte as u32) {738				Some(ch)739					if ch.is_ascii_alphanumeric()740					|| ch == '_'741					|| ch == '-' => { /* OK */ },742				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)743			}744		}745746		Ok(())747	}748}749750impl<Value> TrySet for PropertiesMap<Value> {751	type Value = Value;752753	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {754		Self::check_property_key(&key)?;755756		self.0757			.try_insert(key, value)758			.map_err(|_| PropertiesError::PropertyLimitReached)?;759760		Ok(())761	}762}763764pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;765766#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]767pub struct Properties {768	map: PropertiesMap<PropertyValue>,769	consumed_space: u32,770	space_limit: u32,771}772773impl Properties {774	pub fn new(space_limit: u32) -> Self {775		Self {776			map: PropertiesMap::new(),777			consumed_space: 0,778			space_limit,779		}780	}781782	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {783		let value = self.map.remove(key)?;784785		if let Some(ref value) = value {786			let value_len = value.len() as u32;787			self.consumed_space -= value_len;788		}789790		Ok(value)791	}792793	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {794		self.map.get(key)795	}796797	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {798		self.map.iter()799	}800}801802impl TrySet for Properties {803	type Value = PropertyValue;804805	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {806		let value_len = value.len();807808		if self.consumed_space as usize + value_len > self.space_limit as usize {809			return Err(PropertiesError::NoSpaceForProperty);810		}811812		self.map.try_set(key, value)?;813814		self.consumed_space += value_len as u32;815816		Ok(())817	}818}819820pub struct CollectionProperties;821822impl Get<Properties> for CollectionProperties {823	fn get() -> Properties {824		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)825	}826}827828pub struct TokenProperties;829830impl Get<Properties> for TokenProperties {831	fn get() -> Properties {832		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)833	}834}
after · primitives/data-structs/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20	convert::{TryFrom, TryInto},21	fmt,22};23use frame_support::{24	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25	traits::Get,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;3738mod bounded;39pub mod budget;40pub mod mapping;41mod migration;4243pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;44pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;45pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;4647pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {48	100_00049} else {50	1051};52pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {53	100_00054} else {55	1056};57pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {58	204859} else {60	1061};62pub const COLLECTION_ADMINS_LIMIT: u32 = 5;63pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;64pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {65	1_000_00066} else {67	1068};6970// Timeouts for item types in passed blocks71pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;72pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;73pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;7475pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;7677// Schema limits78pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;79pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;80pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8182pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;8384pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;85pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;86pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8788pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;89pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;90pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;9192// pub const MAX_PROPERTY_KEYS_OVERALL_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH * MAX_PROPERTIES_PER_ITEM;93pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;94pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;9596pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =97	MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;9899pub struct MaxPropertiesPermissionsEncodeLen;100101impl Get<u32> for MaxPropertiesPermissionsEncodeLen {102	fn get() -> u32 {103		MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH104			+ <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32105	}106}107108/// How much items can be created per single109/// create_many call110pub const MAX_ITEMS_PER_BATCH: u32 = 200;111112pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;113114#[derive(115	Encode,116	Decode,117	PartialEq,118	Eq,119	PartialOrd,120	Ord,121	Clone,122	Copy,123	Debug,124	Default,125	TypeInfo,126	MaxEncodedLen,127)]128#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]129pub struct CollectionId(pub u32);130impl EncodeLike<u32> for CollectionId {}131impl EncodeLike<CollectionId> for u32 {}132133#[derive(134	Encode,135	Decode,136	PartialEq,137	Eq,138	PartialOrd,139	Ord,140	Clone,141	Copy,142	Debug,143	Default,144	TypeInfo,145	MaxEncodedLen,146)]147#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]148pub struct TokenId(pub u32);149impl EncodeLike<u32> for TokenId {}150impl EncodeLike<TokenId> for u32 {}151152impl TokenId {153	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {154		self.0155			.checked_add(1)156			.ok_or(ArithmeticError::Overflow)157			.map(Self)158	}159}160161impl From<TokenId> for U256 {162	fn from(t: TokenId) -> Self {163		t.0.into()164	}165}166167impl TryFrom<U256> for TokenId {168	type Error = &'static str;169170	fn try_from(value: U256) -> Result<Self, Self::Error> {171		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))172	}173}174175#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]176#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]177pub struct TokenData<CrossAccountId> {178	pub const_data: Vec<u8>,179	pub properties: Vec<Property>,180	pub owner: Option<CrossAccountId>,181}182183pub struct OverflowError;184impl From<OverflowError> for &'static str {185	fn from(_: OverflowError) -> Self {186		"overflow occured"187	}188}189190pub type DecimalPoints = u8;191192#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]193#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]194pub enum CollectionMode {195	NFT,196	// decimal points197	Fungible(DecimalPoints),198	ReFungible,199}200201impl CollectionMode {202	pub fn id(&self) -> u8 {203		match self {204			CollectionMode::NFT => 1,205			CollectionMode::Fungible(_) => 2,206			CollectionMode::ReFungible => 3,207		}208	}209}210211pub trait SponsoringResolve<AccountId, Call> {212	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;213}214215#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]216#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]217pub enum AccessMode {218	Normal,219	AllowList,220}221impl Default for AccessMode {222	fn default() -> Self {223		Self::Normal224	}225}226227#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]228#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]229pub enum SchemaVersion {230	ImageURL,231	Unique,232}233impl Default for SchemaVersion {234	fn default() -> Self {235		Self::ImageURL236	}237}238239#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]240#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]241pub struct Ownership<AccountId> {242	pub owner: AccountId,243	pub fraction: u128,244}245246#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]247#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]248pub enum SponsorshipState<AccountId> {249	/// The fees are applied to the transaction sender250	Disabled,251	Unconfirmed(AccountId),252	/// Transactions are sponsored by specified account253	Confirmed(AccountId),254}255256impl<AccountId> SponsorshipState<AccountId> {257	pub fn sponsor(&self) -> Option<&AccountId> {258		match self {259			Self::Confirmed(sponsor) => Some(sponsor),260			_ => None,261		}262	}263264	pub fn pending_sponsor(&self) -> Option<&AccountId> {265		match self {266			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),267			_ => None,268		}269	}270271	pub fn confirmed(&self) -> bool {272		matches!(self, Self::Confirmed(_))273	}274}275276impl<T> Default for SponsorshipState<T> {277	fn default() -> Self {278		Self::Disabled279	}280}281282/// Used in storage283#[struct_versioning::versioned(version = 2, upper)]284#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]285pub struct Collection<AccountId> {286	pub owner: AccountId,287	pub mode: CollectionMode,288	pub access: AccessMode,289	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,290	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,291	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,292	pub mint_mode: bool,293294	#[version(..2)]295	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,296297	pub schema_version: SchemaVersion,298	pub sponsorship: SponsorshipState<AccountId>,299300	#[version(..2)]301	pub limits: CollectionLimitsVersion1, // Collection private restrictions302	#[version(2.., upper(limits.into()))]303	pub limits: CollectionLimitsVersion2,304305	#[version(..2)]306	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,307308	#[version(..2)]309	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,310311	pub meta_update_permission: MetaUpdatePermission,312}313314/// Used in RPC calls315#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]316#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]317pub struct RpcCollection<AccountId> {318	pub owner: AccountId,319	pub mode: CollectionMode,320	pub access: AccessMode,321	pub name: Vec<u16>,322	pub description: Vec<u16>,323	pub token_prefix: Vec<u8>,324	pub mint_mode: bool,325	pub offchain_schema: Vec<u8>,326	pub schema_version: SchemaVersion,327	pub sponsorship: SponsorshipState<AccountId>,328	pub limits: CollectionLimits,329	pub const_on_chain_schema: Vec<u8>,330	pub meta_update_permission: MetaUpdatePermission,331	pub token_property_permissions: Vec<PropertyKeyPermission>,332	pub properties: Vec<Property>,333}334335#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]336#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]337pub enum CollectionField {338	ConstOnChainSchema,339	OffchainSchema,340}341342#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]343#[derivative(Debug, Default(bound = ""))]344pub struct CreateCollectionData<AccountId> {345	#[derivative(Default(value = "CollectionMode::NFT"))]346	pub mode: CollectionMode,347	pub access: Option<AccessMode>,348	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,349	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,350	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,351	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,352	pub schema_version: Option<SchemaVersion>,353	pub pending_sponsor: Option<AccountId>,354	pub limits: Option<CollectionLimits>,355	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,356	pub meta_update_permission: Option<MetaUpdatePermission>,357	pub token_property_permissions: CollectionPropertiesPermissionsVec,358	pub properties: CollectionPropertiesVec,359}360361pub type CollectionPropertiesPermissionsVec =362	BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;363364pub type CollectionPropertiesVec =365	BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;366367#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]368#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]369pub struct NftItemType<AccountId> {370	pub owner: AccountId,371	pub const_data: Vec<u8>,372	pub variable_data: Vec<u8>,373}374375#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]376#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]377pub struct FungibleItemType {378	pub value: u128,379}380381#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]382#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]383pub struct ReFungibleItemType<AccountId> {384	pub owner: Vec<Ownership<AccountId>>,385	pub const_data: Vec<u8>,386	pub variable_data: Vec<u8>,387}388389/// All fields are wrapped in `Option`s, where None means chain default390#[struct_versioning::versioned(version = 2, upper)]391#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]392#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]393pub struct CollectionLimits {394	pub account_token_ownership_limit: Option<u32>,395	pub sponsored_data_size: Option<u32>,396	/// None - setVariableMetadata is not sponsored397	/// Some(v) - setVariableMetadata is sponsored398	///           if there is v block between txs399	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,400	pub token_limit: Option<u32>,401402	// Timeouts for item types in passed blocks403	pub sponsor_transfer_timeout: Option<u32>,404	pub sponsor_approve_timeout: Option<u32>,405	pub owner_can_transfer: Option<bool>,406	pub owner_can_destroy: Option<bool>,407	pub transfers_enabled: Option<bool>,408409	#[version(2.., upper(None))]410	pub nesting_rule: Option<NestingRule>,411}412413impl CollectionLimits {414	pub fn account_token_ownership_limit(&self) -> u32 {415		self.account_token_ownership_limit416			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)417			.min(MAX_TOKEN_OWNERSHIP)418	}419	pub fn sponsored_data_size(&self) -> u32 {420		self.sponsored_data_size421			.unwrap_or(CUSTOM_DATA_LIMIT)422			.min(CUSTOM_DATA_LIMIT)423	}424	pub fn token_limit(&self) -> u32 {425		self.token_limit426			.unwrap_or(COLLECTION_TOKEN_LIMIT)427			.min(COLLECTION_TOKEN_LIMIT)428	}429	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {430		self.sponsor_transfer_timeout431			.unwrap_or(default)432			.min(MAX_SPONSOR_TIMEOUT)433	}434	pub fn sponsor_approve_timeout(&self) -> u32 {435		self.sponsor_approve_timeout436			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)437			.min(MAX_SPONSOR_TIMEOUT)438	}439	pub fn owner_can_transfer(&self) -> bool {440		self.owner_can_transfer.unwrap_or(true)441	}442	pub fn owner_can_destroy(&self) -> bool {443		self.owner_can_destroy.unwrap_or(true)444	}445	pub fn transfers_enabled(&self) -> bool {446		self.transfers_enabled.unwrap_or(true)447	}448	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {449		match self450			.sponsored_data_rate_limit451			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)452		{453			SponsoringRateLimit::SponsoringDisabled => None,454			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),455		}456	}457	pub fn nesting_rule(&self) -> &NestingRule {458		static DEFAULT: NestingRule = NestingRule::Disabled;459		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)460	}461}462463#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]464#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]465#[derivative(Debug)]466pub enum NestingRule {467	/// No one can nest tokens468	Disabled,469	/// Owner can nest any tokens470	Owner,471	/// Owner can nest tokens from specified collections472	OwnerRestricted(473		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]474		#[derivative(Debug(format_with = "bounded::set_debug"))]475		BoundedBTreeSet<CollectionId, ConstU32<16>>,476	),477}478479#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]480#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]481pub enum SponsoringRateLimit {482	SponsoringDisabled,483	Blocks(u32),484}485486#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]487#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]488#[derivative(Debug)]489pub struct CreateNftData {490	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]491	#[derivative(Debug(format_with = "bounded::vec_debug"))]492	pub const_data: BoundedVec<u8, CustomDataLimit>,493	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]494	#[derivative(Debug(format_with = "bounded::vec_debug"))]495	pub variable_data: BoundedVec<u8, CustomDataLimit>,496497	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]498	#[derivative(Debug(format_with = "bounded::vec_debug"))]499	pub properties: CollectionPropertiesVec,500}501502#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]503#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]504pub struct CreateFungibleData {505	pub value: u128,506}507508#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]509#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]510#[derivative(Debug)]511pub struct CreateReFungibleData {512	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]513	#[derivative(Debug(format_with = "bounded::vec_debug"))]514	pub const_data: BoundedVec<u8, CustomDataLimit>,515	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]516	#[derivative(Debug(format_with = "bounded::vec_debug"))]517	pub variable_data: BoundedVec<u8, CustomDataLimit>,518	pub pieces: u128,519}520521#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]522#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]523pub enum MetaUpdatePermission {524	ItemOwner,525	Admin,526	None,527}528529impl Default for MetaUpdatePermission {530	fn default() -> Self {531		Self::ItemOwner532	}533}534535#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]536#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]537pub enum CreateItemData {538	NFT(CreateNftData),539	Fungible(CreateFungibleData),540	ReFungible(CreateReFungibleData),541}542543#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]544#[derivative(Debug)]545pub struct CreateNftExData<CrossAccountId> {546	#[derivative(Debug(format_with = "bounded::vec_debug"))]547	pub const_data: BoundedVec<u8, CustomDataLimit>,548	#[derivative(Debug(format_with = "bounded::vec_debug"))]549	pub variable_data: BoundedVec<u8, CustomDataLimit>,550	#[derivative(Debug(format_with = "bounded::vec_debug"))]551	pub properties: CollectionPropertiesVec,552	pub owner: CrossAccountId,553}554555#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]556#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]557pub struct CreateRefungibleExData<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::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::NFT(data) => data.variable_data.len() + data.const_data.len(),590			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),591			_ => 0,592		}593	}594}595596impl From<CreateNftData> for CreateItemData {597	fn from(item: CreateNftData) -> Self {598		CreateItemData::NFT(item)599	}600}601602impl From<CreateReFungibleData> for CreateItemData {603	fn from(item: CreateReFungibleData) -> Self {604		CreateItemData::ReFungible(item)605	}606}607608impl From<CreateFungibleData> for CreateItemData {609	fn from(item: CreateFungibleData) -> Self {610		CreateItemData::Fungible(item)611	}612}613614#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]615#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]616pub struct CollectionStats {617	pub created: u32,618	pub destroyed: u32,619	pub alive: u32,620}621622#[derive(Encode, Decode, PartialEq, Clone, Debug)]623pub struct PhantomType<T>(core::marker::PhantomData<T>);624625impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {626	type Identity = PhantomType<T>;627628	fn type_info() -> scale_info::Type {629		use scale_info::{630			Type, Path,631			build::{FieldsBuilder, UnnamedFields},632			type_params,633		};634		Type::builder()635			.path(Path::new("up_data_structs", "PhantomType"))636			.type_params(type_params!(T))637			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))638	}639}640impl<T> MaxEncodedLen for PhantomType<T> {641	fn max_encoded_len() -> usize {642		0643	}644}645646pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;647pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;648649#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]650#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]651pub struct PropertyPermission {652	pub mutable: bool,653	pub collection_admin: bool,654	pub token_owner: bool,655}656657impl PropertyPermission {658	pub fn none() -> Self {659		Self {660			mutable: true,661			collection_admin: false,662			token_owner: false,663		}664	}665}666667#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]668#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]669pub struct Property {670	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]671	pub key: PropertyKey,672673	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]674	pub value: PropertyValue,675}676677#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]678#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]679pub struct PropertyKeyPermission {680	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]681	pub key: PropertyKey,682683	pub permission: PropertyPermission,684}685686pub enum PropertiesError {687	NoSpaceForProperty,688	PropertyLimitReached,689	InvalidCharacterInPropertyKey,690	EmptyPropertyKey,691}692693pub trait TrySet: Sized {694	type Value;695696	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;697698	fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>699	where700		I: Iterator<Item = (PropertyKey, Self::Value)>,701	{702		for (key, value) in iter {703			self.try_set(key, value)?;704		}705706		Ok(())707	}708}709710#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]711#[derivative(Default(bound = ""))]712pub struct PropertiesMap<Value>(713	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,714);715716impl<Value> PropertiesMap<Value> {717	pub fn new() -> Self {718		Self(BoundedBTreeMap::new())719	}720721	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {722		Self::check_property_key(key)?;723724		Ok(self.0.remove(key))725	}726727	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {728		self.0.get(key)729	}730731	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {732		self.0.iter()733	}734735	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {736		if key.is_empty() {737			return Err(PropertiesError::EmptyPropertyKey);738		}739740		for byte in key.as_slice().iter() {741			match char::from_u32(*byte as u32) {742				Some(ch)743					if ch.is_ascii_alphanumeric()744					|| ch == '_'745					|| ch == '-' => { /* OK */ },746				_ => return Err(PropertiesError::InvalidCharacterInPropertyKey)747			}748		}749750		Ok(())751	}752}753754impl<Value> TrySet for PropertiesMap<Value> {755	type Value = Value;756757	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {758		Self::check_property_key(&key)?;759760		self.0761			.try_insert(key, value)762			.map_err(|_| PropertiesError::PropertyLimitReached)?;763764		Ok(())765	}766}767768pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;769770#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]771pub struct Properties {772	map: PropertiesMap<PropertyValue>,773	consumed_space: u32,774	space_limit: u32,775}776777impl Properties {778	pub fn new(space_limit: u32) -> Self {779		Self {780			map: PropertiesMap::new(),781			consumed_space: 0,782			space_limit,783		}784	}785786	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {787		let value = self.map.remove(key)?;788789		if let Some(ref value) = value {790			let value_len = value.len() as u32;791			self.consumed_space -= value_len;792		}793794		Ok(value)795	}796797	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {798		self.map.get(key)799	}800801	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {802		self.map.iter()803	}804}805806impl TrySet for Properties {807	type Value = PropertyValue;808809	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {810		let value_len = value.len();811812		if self.consumed_space as usize + value_len > self.space_limit as usize {813			return Err(PropertiesError::NoSpaceForProperty);814		}815816		self.map.try_set(key, value)?;817818		self.consumed_space += value_len as u32;819820		Ok(())821	}822}823824pub struct CollectionProperties;825826impl Get<Properties> for CollectionProperties {827	fn get() -> Properties {828		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)829	}830}831832pub struct TokenProperties;833834impl Get<Properties> for TokenProperties {835	fn get() -> Properties {836		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)837	}838}