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

difftreelog

source

primitives/data-structs/src/lib.rs40.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//! # Primitives crate.18//!19//! This crate contains types, traits and constants.2021#![cfg_attr(not(feature = "std"), no_std)]2223use core::{24	convert::{TryFrom, TryInto},25	fmt,26	ops::Deref,27};2829use bondrewd::Bitfields;30use derivative::Derivative;31use evm_coder::AbiCoderFlags;32use frame_support::{33	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},34	traits::ConstU32,35	BoundedVec,36};37use parity_scale_codec::{Decode, Encode, EncodeLike, MaxEncodedLen};38use scale_info::TypeInfo;39use serde::{Deserialize, Serialize};40use sp_core::U256;41use sp_runtime::{sp_std::prelude::Vec, ArithmeticError};42use sp_std::collections::btree_set::BTreeSet;4344mod bondrewd_codec;45mod bounded;46pub mod budget;47pub mod mapping;48mod migration;4950/// Maximum of decimal points.51pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;5253/// Maximum pieces for refungible token.54pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;55pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5657/// Maximum tokens for user.58pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {59	100_000_00060} else {61	1062};6364/// Maximum for collections can be created.65pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {66	100_00067} else {68	1069};7071/// Maximum for various custom data of token.72pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {73	204874} else {75	1076};7778/// Maximum admins per collection.79pub const COLLECTION_ADMINS_LIMIT: u32 = 5;8081/// Maximum tokens per collection.82pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;8384/// Maximum tokens per account.85pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {86	100_000_00087} else {88	1089};9091/// Default timeout for transfer sponsoring NFT item.92pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;93/// Default timeout for transfer sponsoring fungible item.94pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;95/// Default timeout for transfer sponsoring refungible item.96pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;9798/// Default timeout for sponsored approving.99pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;100101// Schema limits102pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;103pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;104pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;105106// TODO: not used. Delete?107pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;108109/// Maximal length of a collection name.110pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;111112/// Maximal length of a collection description.113pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;114115/// Maximal length of a token prefix.116pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;117118/// Maximal length of a property key.119pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;120121/// Maximal length of a property value.122pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;123124/// A maximum number of token properties.125pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;126127/// Maximal lenght of extended property value.128pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;129130/// Maximum size for all collection properties.131pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;132133/// Maximum size of all token properties.134pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;135136/// How much items can be created per single137/// create_many call.138pub const MAX_ITEMS_PER_BATCH: u32 = 120;139140/// Used for limit bounded types of token custom data.141pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;142143/// Collection id.144#[derive(145	Encode,146	Decode,147	PartialEq,148	Eq,149	PartialOrd,150	Ord,151	Clone,152	Copy,153	Debug,154	Default,155	TypeInfo,156	MaxEncodedLen,157	Serialize,158	Deserialize,159)]160pub struct CollectionId(pub u32);161impl EncodeLike<u32> for CollectionId {}162impl EncodeLike<CollectionId> for u32 {}163164impl From<u32> for CollectionId {165	fn from(value: u32) -> Self {166		Self(value)167	}168}169170impl Deref for CollectionId {171	type Target = u32;172173	fn deref(&self) -> &Self::Target {174		&self.0175	}176}177178/// Token id.179#[derive(180	Encode,181	Decode,182	PartialEq,183	Eq,184	PartialOrd,185	Ord,186	Clone,187	Copy,188	Debug,189	Default,190	TypeInfo,191	MaxEncodedLen,192	Serialize,193	Deserialize,194)]195pub struct TokenId(pub u32);196impl EncodeLike<u32> for TokenId {}197impl EncodeLike<TokenId> for u32 {}198199impl TokenId {200	/// Try to get next token id.201	///202	/// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.203	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {204		self.0205			.checked_add(1)206			.ok_or(ArithmeticError::Overflow)207			.map(Self)208	}209}210211impl From<TokenId> for U256 {212	fn from(t: TokenId) -> Self {213		t.0.into()214	}215}216217impl TryFrom<U256> for TokenId {218	type Error = &'static str;219220	fn try_from(value: U256) -> Result<Self, Self::Error> {221		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))222	}223}224225/// Token data.226#[struct_versioning::versioned(version = 2, upper)]227#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]228pub struct TokenData<CrossAccountId> {229	/// Properties of token.230	pub properties: Vec<Property>,231232	/// Token owner.233	pub owner: Option<CrossAccountId>,234235	/// Token pieces.236	#[version(2.., upper(0))]237	pub pieces: u128,238}239240// TODO: unused type241pub struct OverflowError;242impl From<OverflowError> for &'static str {243	fn from(_: OverflowError) -> Self {244		"overflow occured"245	}246}247248/// Alias for decimal points type.249pub type DecimalPoints = u8;250251/// Collection mode.252///253/// Collection can represent various types of tokens.254/// Each collection can contain only one type of tokens at a time.255/// This type helps to understand which tokens the collection contains.256#[derive(257	Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,258)]259pub enum CollectionMode {260	/// Non fungible tokens.261	NFT,262	/// Fungible tokens.263	Fungible(DecimalPoints),264	/// Refungible tokens.265	ReFungible,266}267268impl CollectionMode {269	/// Get collection mod as number.270	pub fn id(&self) -> u8 {271		match self {272			CollectionMode::NFT => 1,273			CollectionMode::Fungible(_) => 2,274			CollectionMode::ReFungible => 3,275		}276	}277}278279// TODO: unused trait280pub trait SponsoringResolve<AccountId, Call> {281	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;282}283284/// Access mode for some token operations.285#[derive(286	Encode,287	Decode,288	Eq,289	Debug,290	Clone,291	Copy,292	PartialEq,293	TypeInfo,294	MaxEncodedLen,295	Serialize,296	Deserialize,297)]298pub enum AccessMode {299	/// Access grant for owner and admins. Used as default.300	Normal,301	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.302	AllowList,303}304impl Default for AccessMode {305	fn default() -> Self {306		Self::Normal307	}308}309310// TODO: remove in future.311#[derive(312	Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,313)]314pub enum SchemaVersion {315	ImageURL,316	Unique,317}318impl Default for SchemaVersion {319	fn default() -> Self {320		Self::ImageURL321	}322}323324// TODO: unused type325#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]326pub struct Ownership<AccountId> {327	pub owner: AccountId,328	pub fraction: u128,329}330331/// The state of collection sponsorship.332#[derive(333	Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,334)]335pub enum SponsorshipState<AccountId> {336	/// The fees are applied to the transaction sender.337	Disabled,338	/// The sponsor is under consideration. Until the sponsor gives his consent,339	/// the fee will still be charged to sender.340	Unconfirmed(AccountId),341	/// Transactions are sponsored by specified account.342	Confirmed(AccountId),343}344345impl<AccountId> SponsorshipState<AccountId> {346	/// Get a sponsor of the collection who has confirmed his status.347	pub fn sponsor(&self) -> Option<&AccountId> {348		match self {349			Self::Confirmed(sponsor) => Some(sponsor),350			_ => None,351		}352	}353354	/// Get a sponsor of the collection who has pending or confirmed status.355	pub fn pending_sponsor(&self) -> Option<&AccountId> {356		match self {357			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),358			_ => None,359		}360	}361362	/// Whether the sponsorship is confirmed.363	pub fn confirmed(&self) -> bool {364		matches!(self, Self::Confirmed(_))365	}366}367368impl<T> Default for SponsorshipState<T> {369	fn default() -> Self {370		Self::Disabled371	}372}373374pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;375pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;376pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;377378#[derive(AbiCoderFlags, Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]379#[bondrewd(enforce_bytes = 1)]380pub struct CollectionFlags {381	/// A collection of foreign assets382	#[bondrewd(bits = "0..1")]383	pub foreign: bool,384	/// Supports ERC721Metadata385	#[bondrewd(bits = "1..2")]386	pub erc721metadata: bool,387	/// External collections can't be managed using `unique` api388	#[bondrewd(bits = "7..8")]389	pub external: bool,390	/// Reserved flags391	#[bondrewd(bits = "2..7")]392	pub reserved: u8,393}394bondrewd_codec!(CollectionFlags);395396impl CollectionFlags {397	pub fn is_allowed_for_user(self) -> bool {398		!self.foreign && !self.external && self.reserved == 0399	}400}401402/// Base structure for represent collection.403///404/// Used to provide basic functionality for all types of collections.405///406/// #### Note407/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).408#[struct_versioning::versioned(version = 2, upper)]409#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]410pub struct Collection<AccountId> {411	/// Collection owner account.412	pub owner: AccountId,413414	/// Collection mode.415	pub mode: CollectionMode,416417	/// Access mode.418	#[version(..2)]419	pub access: AccessMode,420421	/// Collection name.422	pub name: CollectionName,423424	/// Collection description.425	pub description: CollectionDescription,426427	/// Token prefix.428	pub token_prefix: CollectionTokenPrefix,429430	#[version(..2)]431	pub mint_mode: bool,432433	#[version(..2)]434	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,435436	#[version(..2)]437	pub schema_version: SchemaVersion,438439	/// The state of sponsorship of the collection.440	pub sponsorship: SponsorshipState<AccountId>,441442	/// Collection limits.443	pub limits: CollectionLimits,444445	/// Collection permissions.446	#[version(2.., upper(Default::default()))]447	pub permissions: CollectionPermissions,448449	#[version(2.., upper(Default::default()))]450	pub flags: CollectionFlags,451452	#[version(..2)]453	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,454455	#[version(..2)]456	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,457458	#[version(..2)]459	pub meta_update_permission: MetaUpdatePermission,460}461462#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]463pub struct RpcCollectionFlags {464	/// Is collection is foreign.465	pub foreign: bool,466	/// Collection supports ERC721Metadata.467	pub erc721metadata: bool,468}469470/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).471#[struct_versioning::versioned(version = 2, upper)]472#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]473pub struct RpcCollection<AccountId> {474	/// Collection owner account.475	pub owner: AccountId,476477	/// Collection mode.478	pub mode: CollectionMode,479480	/// Collection name.481	pub name: Vec<u16>,482483	/// Collection description.484	pub description: Vec<u16>,485486	/// Token prefix.487	pub token_prefix: Vec<u8>,488489	/// The state of sponsorship of the collection.490	pub sponsorship: SponsorshipState<AccountId>,491492	/// Collection limits.493	pub limits: CollectionLimits,494495	/// Collection permissions.496	pub permissions: CollectionPermissions,497498	/// Token property permissions.499	pub token_property_permissions: Vec<PropertyKeyPermission>,500501	/// Collection properties.502	pub properties: Vec<Property>,503504	/// Is collection read only.505	pub read_only: bool,506507	/// Extra collection flags508	#[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]509	pub flags: RpcCollectionFlags,510}511512impl<AccountId> From<CollectionVersion1<AccountId>> for RpcCollection<AccountId> {513	fn from(value: CollectionVersion1<AccountId>) -> Self {514		let CollectionVersion1 {515			name,516			description,517			owner,518			mode,519			access,520			token_prefix,521			mint_mode,522			sponsorship,523			limits,524			..525		} = value;526527		RpcCollection {528			name: name.into_inner(),529			description: description.into_inner(),530			owner,531			mode,532			token_prefix: token_prefix.into_inner(),533			sponsorship,534			limits,535			permissions: CollectionPermissions {536				access: Some(access),537				mint_mode: Some(mint_mode),538				nesting: None,539			},540			token_property_permissions: Vec::default(),541			properties: Vec::default(),542			read_only: true,543544			flags: RpcCollectionFlags {545				foreign: false,546				erc721metadata: false,547			},548		}549	}550}551552pub struct RawEncoded(Vec<u8>);553554impl parity_scale_codec::Decode for RawEncoded {555	fn decode<I: parity_scale_codec::Input>(556		input: &mut I,557	) -> Result<Self, parity_scale_codec::Error> {558		let mut out = Vec::new();559		while let Ok(v) = input.read_byte() {560			out.push(v);561		}562		Ok(Self(out))563	}564}565566impl Deref for RawEncoded {567	type Target = Vec<u8>;568569	fn deref(&self) -> &Self::Target {570		&self.0571	}572}573574/// Data used for create collection.575///576/// All fields are wrapped in [`Option`], where `None` means chain default.577#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]578#[derivative(Debug, Default(bound = ""))]579pub struct CreateCollectionData<CrossAccountId> {580	/// Collection mode.581	#[derivative(Default(value = "CollectionMode::NFT"))]582	pub mode: CollectionMode,583584	/// Access mode.585	pub access: Option<AccessMode>,586587	/// Collection name.588	pub name: CollectionName,589590	/// Collection description.591	pub description: CollectionDescription,592593	/// Token prefix.594	pub token_prefix: CollectionTokenPrefix,595596	/// Collection limits.597	pub limits: Option<CollectionLimits>,598599	/// Collection permissions.600	pub permissions: Option<CollectionPermissions>,601602	/// Token property permissions.603	pub token_property_permissions: CollectionPropertiesPermissionsVec,604605	/// Collection properties.606	pub properties: CollectionPropertiesVec,607608	pub admin_list: Vec<CrossAccountId>,609610	/// Pending collection sponsor.611	pub pending_sponsor: Option<CrossAccountId>,612613	pub flags: CollectionFlags,614}615616/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].617// TODO: maybe rename to PropertiesPermissionsVec618pub type CollectionPropertiesPermissionsVec =619	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;620621/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].622pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;623624/// Limits and restrictions of a collection.625///626/// All fields are wrapped in [`Option`], where `None` means chain default.627///628/// Update with `pallet_common::Pallet::clamp_limits`.629// IMPORTANT: When adding/removing fields from this struct - don't forget to also630#[derive(631	Encode,632	Decode,633	Debug,634	Default,635	Clone,636	PartialEq,637	TypeInfo,638	MaxEncodedLen,639	Serialize,640	Deserialize,641)]642// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.643// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.644// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.645pub struct CollectionLimits {646	/// How many tokens can a user have on one account.647	/// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].648	/// * Limit - [`MAX_TOKEN_OWNERSHIP`].649	pub account_token_ownership_limit: Option<u32>,650651	/// How many bytes of data are available for sponsorship.652	/// * Default - [`CUSTOM_DATA_LIMIT`].653	/// * Limit - [`CUSTOM_DATA_LIMIT`].654	pub sponsored_data_size: Option<u32>,655656	// FIXME should we delete this or repurpose it?657	/// Times in how many blocks we sponsor data.658	///659	/// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.660	///661	/// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).662	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].663	///664	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]665	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,666	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]667668	/// How many tokens can be mined into this collection.669	///670	/// * Default - [`COLLECTION_TOKEN_LIMIT`].671	/// * Limit - [`COLLECTION_TOKEN_LIMIT`].672	pub token_limit: Option<u32>,673674	/// Timeouts for transfer sponsoring.675	///676	/// * Default677	///   - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]678	///   - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]679	///   - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]680	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].681	pub sponsor_transfer_timeout: Option<u32>,682683	/// Timeout for sponsoring an approval in passed blocks.684	///685	/// * Default - [`SPONSOR_APPROVE_TIMEOUT`].686	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].687	pub sponsor_approve_timeout: Option<u32>,688689	/// Whether the collection owner of the collection can send tokens (which belong to other users).690	///691	/// * Default - **false**.692	pub owner_can_transfer: Option<bool>,693694	/// Can the collection owner burn other people's tokens.695	///696	/// * Default - **true**.697	pub owner_can_destroy: Option<bool>,698699	/// Is it possible to send tokens from this collection between users.700	///701	/// * Default - **true**.702	pub transfers_enabled: Option<bool>,703}704705impl CollectionLimits {706	pub fn with_default_limits(collection_type: CollectionMode) -> Self {707		CollectionLimits {708			account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),709			sponsored_data_size: Some(CUSTOM_DATA_LIMIT),710			sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),711			token_limit: Some(COLLECTION_TOKEN_LIMIT),712			sponsor_transfer_timeout: match collection_type {713				CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),714				CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),715				CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),716			},717			sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),718			owner_can_transfer: Some(false),719			owner_can_destroy: Some(true),720			transfers_enabled: Some(true),721		}722	}723724	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).725	pub fn account_token_ownership_limit(&self) -> u32 {726		self.account_token_ownership_limit727			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)728			.min(MAX_TOKEN_OWNERSHIP)729	}730731	/// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).732	pub fn sponsored_data_size(&self) -> u32 {733		self.sponsored_data_size734			.unwrap_or(CUSTOM_DATA_LIMIT)735			.min(CUSTOM_DATA_LIMIT)736	}737738	/// Get effective value for [`token_limit`](self.token_limit).739	pub fn token_limit(&self) -> u32 {740		self.token_limit741			.unwrap_or(COLLECTION_TOKEN_LIMIT)742			.min(COLLECTION_TOKEN_LIMIT)743	}744745	// TODO: may be replace u32 to mode?746	/// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).747	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {748		self.sponsor_transfer_timeout749			.unwrap_or(default)750			.min(MAX_SPONSOR_TIMEOUT)751	}752753	/// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).754	pub fn sponsor_approve_timeout(&self) -> u32 {755		self.sponsor_approve_timeout756			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)757			.min(MAX_SPONSOR_TIMEOUT)758	}759760	/// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).761	pub fn owner_can_transfer(&self) -> bool {762		self.owner_can_transfer.unwrap_or(false)763	}764765	/// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).766	pub fn owner_can_transfer_instaled(&self) -> bool {767		self.owner_can_transfer.is_some()768	}769770	/// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).771	pub fn owner_can_destroy(&self) -> bool {772		self.owner_can_destroy.unwrap_or(true)773	}774775	/// Get effective value for [`transfers_enabled`](self.transfers_enabled).776	pub fn transfers_enabled(&self) -> bool {777		self.transfers_enabled.unwrap_or(true)778	}779780	/// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).781	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {782		match self783			.sponsored_data_rate_limit784			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)785		{786			SponsoringRateLimit::SponsoringDisabled => None,787			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),788		}789	}790}791792/// Permissions on certain operations within a collection.793///794/// Some fields are wrapped in [`Option`], where `None` means chain default.795///796/// Update with `pallet_common::Pallet::clamp_permissions`.797#[derive(798	Encode,799	Decode,800	Debug,801	Default,802	Clone,803	PartialEq,804	TypeInfo,805	MaxEncodedLen,806	Serialize,807	Deserialize,808)]809// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.810// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.811pub struct CollectionPermissions {812	/// Access mode.813	///814	/// * Default - [`AccessMode::Normal`].815	pub access: Option<AccessMode>,816817	/// Minting allowance.818	///819	/// * Default - **false**.820	pub mint_mode: Option<bool>,821822	/// Permissions for nesting.823	///824	/// * Default825	///   - `token_owner` - **false**826	///   - `collection_admin` - **false**827	///   - `restricted` - **None**828	pub nesting: Option<NestingPermissions>,829}830831impl CollectionPermissions {832	/// Get effective value for [`access`](self.access).833	pub fn access(&self) -> AccessMode {834		self.access.unwrap_or(AccessMode::Normal)835	}836837	/// Get effective value for [`mint_mode`](self.mint_mode).838	pub fn mint_mode(&self) -> bool {839		self.mint_mode.unwrap_or(false)840	}841842	/// Get effective value for [`nesting`](self.nesting).843	pub fn nesting(&self) -> &NestingPermissions {844		static DEFAULT: NestingPermissions = NestingPermissions {845			token_owner: false,846			collection_admin: false,847			restricted: None,848			#[cfg(feature = "runtime-benchmarks")]849			permissive: false,850		};851		self.nesting.as_ref().unwrap_or(&DEFAULT)852	}853}854855/// Inner set for collections allowed to nest.856type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;857858/// Wraper for collections set allowing nest.859#[derive(860	Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative, Serialize, Deserialize,861)]862#[derivative(Debug)]863pub struct OwnerRestrictedSet(864	#[serde(with = "bounded::set_serde")]865	#[derivative(Debug(format_with = "bounded::set_debug"))]866	pub OwnerRestrictedSetInner,867);868869impl OwnerRestrictedSet {870	/// Create new set.871	pub fn new() -> Self {872		Self(Default::default())873	}874}875impl Default for OwnerRestrictedSet {876	fn default() -> Self {877		Self::new()878	}879}880impl core::ops::Deref for OwnerRestrictedSet {881	type Target = OwnerRestrictedSetInner;882	fn deref(&self) -> &Self::Target {883		&self.0884	}885}886impl core::ops::DerefMut for OwnerRestrictedSet {887	fn deref_mut(&mut self) -> &mut Self::Target {888		&mut self.0889	}890}891892impl TryFrom<BTreeSet<CollectionId>> for OwnerRestrictedSet {893	type Error = ();894895	fn try_from(value: BTreeSet<CollectionId>) -> Result<Self, Self::Error> {896		Ok(Self(value.try_into()?))897	}898}899900/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.901#[derive(902	Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative, Serialize, Deserialize,903)]904#[derivative(Debug)]905pub struct NestingPermissions {906	/// Owner of token can nest tokens under it.907	pub token_owner: bool,908	/// Admin of token collection can nest tokens under token.909	pub collection_admin: bool,910	/// If set - only tokens from specified collections can be nested.911	pub restricted: Option<OwnerRestrictedSet>,912913	#[cfg(feature = "runtime-benchmarks")]914	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.915	pub permissive: bool,916}917918/// Enum denominating how often can sponsoring occur if it is enabled.919///920/// Used for [`collection limits`](CollectionLimits).921#[derive(922	Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,923)]924pub enum SponsoringRateLimit {925	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions926	SponsoringDisabled,927	/// Once per how many blocks can sponsorship of a transaction type occur928	Blocks(u32),929}930931/// Data used to describe an NFT at creation.932#[derive(933	Encode,934	Decode,935	MaxEncodedLen,936	Default,937	PartialEq,938	Clone,939	Derivative,940	TypeInfo,941	Serialize,942	Deserialize,943)]944#[derivative(Debug)]945pub struct CreateNftData {946	/// Key-value pairs used to describe the token as metadata947	#[serde(with = "bounded::vec_serde")]948	#[derivative(Debug(format_with = "bounded::vec_debug"))]949	/// Properties that wil be assignet to created item.950	pub properties: CollectionPropertiesVec,951}952953/// Data used to describe a Fungible token at creation.954#[derive(955	Encode,956	Decode,957	MaxEncodedLen,958	Default,959	Debug,960	Clone,961	PartialEq,962	TypeInfo,963	Serialize,964	Deserialize,965)]966pub struct CreateFungibleData {967	/// Number of fungible coins minted968	pub value: u128,969}970971/// Data used to describe a Refungible token at creation.972#[derive(973	Encode,974	Decode,975	MaxEncodedLen,976	Default,977	PartialEq,978	Clone,979	Derivative,980	TypeInfo,981	Serialize,982	Deserialize,983)]984#[derivative(Debug)]985pub struct CreateReFungibleData {986	/// Number of pieces the RFT is split into987	pub pieces: u128,988989	/// Key-value pairs used to describe the token as metadata990	#[serde(with = "bounded::vec_serde")]991	#[derivative(Debug(format_with = "bounded::vec_debug"))]992	pub properties: CollectionPropertiesVec,993}994995// TODO: remove this.996#[derive(997	Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,998)]999pub enum MetaUpdatePermission {1000	ItemOwner,1001	Admin,1002	None,1003}10041005/// Enum holding data used for creation of all three item types.1006/// Unified data for create item.1007#[derive(1008	Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1009)]1010pub enum CreateItemData {1011	/// Data for create NFT.1012	NFT(CreateNftData),1013	/// Data for create Fungible item.1014	Fungible(CreateFungibleData),1015	/// Data for create ReFungible item.1016	ReFungible(CreateReFungibleData),1017}10181019/// Extended data for create NFT.1020#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1021#[derivative(Debug)]1022pub struct CreateNftExData<CrossAccountId> {1023	/// Properties that wil be assignet to created item.1024	#[derivative(Debug(format_with = "bounded::vec_debug"))]1025	pub properties: CollectionPropertiesVec,10261027	/// Owner of creating item.1028	pub owner: CrossAccountId,1029}10301031/// Extended data for create ReFungible item.1032#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1033#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]1034pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {1035	#[derivative(Debug(format_with = "bounded::map_debug"))]1036	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,1037	#[derivative(Debug(format_with = "bounded::vec_debug"))]1038	pub properties: CollectionPropertiesVec,1039}10401041/// Extended data for create ReFungible item.1042#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1043#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]1044pub struct CreateRefungibleExSingleOwner<CrossAccountId> {1045	pub user: CrossAccountId,1046	pub pieces: u128,1047	#[derivative(Debug(format_with = "bounded::vec_debug"))]1048	pub properties: CollectionPropertiesVec,1049}10501051/// Unified extended data for creating item.1052#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1053#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]1054pub enum CreateItemExData<CrossAccountId> {1055	/// Extended data for create NFT.1056	NFT(1057		#[derivative(Debug(format_with = "bounded::vec_debug"))]1058		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,1059	),10601061	/// Extended data for create Fungible item.1062	Fungible(1063		#[derivative(Debug(format_with = "bounded::map_debug"))]1064		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,1065	),10661067	/// Extended data for create ReFungible item in case of1068	/// many tokens, each may have only one owner1069	RefungibleMultipleItems(1070		#[derivative(Debug(format_with = "bounded::vec_debug"))]1071		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,1072	),10731074	/// Extended data for create ReFungible item in case of1075	/// single token, which may have many owners1076	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),1077}10781079impl From<CreateNftData> for CreateItemData {1080	fn from(item: CreateNftData) -> Self {1081		CreateItemData::NFT(item)1082	}1083}10841085impl From<CreateReFungibleData> for CreateItemData {1086	fn from(item: CreateReFungibleData) -> Self {1087		CreateItemData::ReFungible(item)1088	}1089}10901091impl From<CreateFungibleData> for CreateItemData {1092	fn from(item: CreateFungibleData) -> Self {1093		CreateItemData::Fungible(item)1094	}1095}10961097/// Token's address, dictated by its collection and token IDs.1098#[derive(1099	Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1100)]1101// todo possibly rename to be used generally as an address pair1102pub struct TokenChild {1103	/// Token id.1104	pub token: TokenId,11051106	/// Collection id.1107	pub collection: CollectionId,1108}11091110/// Collection statistics.1111#[derive(1112	Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1113)]1114pub struct CollectionStats {1115	/// Number of created items.1116	pub created: u32,11171118	/// Number of burned items.1119	pub destroyed: u32,11201121	/// Number of current items.1122	pub alive: u32,1123}11241125/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1126#[derive(Encode, Decode, Clone, Debug)]1127#[cfg_attr(feature = "std", derive(PartialEq))]1128pub struct PhantomType<T>(core::marker::PhantomData<T>);11291130impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1131	type Identity = PhantomType<T>;11321133	fn type_info() -> scale_info::Type {1134		use scale_info::{1135			build::{FieldsBuilder, UnnamedFields},1136			form::MetaForm,1137			type_params, Path, Type,1138		};1139		Type::builder()1140			.path(Path::new("up_data_structs", "PhantomType"))1141			.type_params(type_params!(T))1142			.composite(1143				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1144			)1145	}1146}1147impl<T> MaxEncodedLen for PhantomType<T> {1148	fn max_encoded_len() -> usize {1149		01150	}1151}11521153/// Bounded vector of bytes.1154pub type BoundedBytes<S> = BoundedVec<u8, S>;11551156/// Extra properties for external collections.1157pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;11581159/// Property key.1160pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;11611162/// Property value.1163pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;11641165/// Property permission.1166#[derive(1167	Encode,1168	Decode,1169	TypeInfo,1170	Debug,1171	MaxEncodedLen,1172	PartialEq,1173	Clone,1174	Default,1175	Serialize,1176	Deserialize,1177)]1178pub struct PropertyPermission {1179	/// Permission to change the property and property permission.1180	///1181	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1182	pub mutable: bool,11831184	/// Change permission for the collection administrator.1185	pub collection_admin: bool,11861187	/// Permission to change the property for the owner of the token.1188	pub token_owner: bool,1189}11901191impl PropertyPermission {1192	/// Creates mutable property permission but changes restricted for collection admin and token owner.1193	pub fn none() -> Self {1194		Self {1195			mutable: true,1196			collection_admin: false,1197			token_owner: false,1198		}1199	}1200}12011202/// Property is simpl key-value record.1203#[derive(1204	Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen, Serialize, Deserialize,1205)]1206pub struct Property {1207	/// Property key.1208	#[serde(with = "bounded::vec_serde")]1209	pub key: PropertyKey,12101211	/// Property value.1212	#[serde(with = "bounded::vec_serde")]1213	pub value: PropertyValue,1214}12151216impl From<Property> for (PropertyKey, PropertyValue) {1217	fn from(value: Property) -> Self {1218		(value.key, value.value)1219	}1220}12211222/// Record for proprty key permission.1223#[derive(1224	Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Serialize, Deserialize,1225)]1226pub struct PropertyKeyPermission {1227	/// Key.1228	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1229	pub key: PropertyKey,12301231	/// Permission.1232	pub permission: PropertyPermission,1233}12341235impl From<PropertyKeyPermission> for (PropertyKey, PropertyPermission) {1236	fn from(value: PropertyKeyPermission) -> Self {1237		(value.key, value.permission)1238	}1239}12401241/// Errors for properties actions.1242#[derive(Debug)]1243pub enum PropertiesError {1244	/// The space allocated for properties has run out.1245	///1246	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1247	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1248	NoSpaceForProperty,12491250	/// The property limit has been reached.1251	///1252	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1253	PropertyLimitReached,12541255	/// Property key contains not allowed character.1256	InvalidCharacterInPropertyKey,12571258	/// Property key length is too long.1259	///1260	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1261	PropertyKeyIsTooLong,12621263	/// Property key is empty.1264	EmptyPropertyKey,1265}12661267/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1268#[derive(Debug)]1269pub enum TokenOwnerError {1270	NotFound,1271	MultipleOwners,1272}12731274/// Marker for scope of property.1275///1276/// Scoped property can't be changed by user. Used for external collections.1277#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1278pub enum PropertyScope {1279	None,1280	Rmrk,1281}12821283impl PropertyScope {1284	pub fn prefix(&self) -> &'static [u8] {1285		match self {1286			Self::None => b"",1287			Self::Rmrk => b"rmrk:",1288		}1289	}1290	/// Apply scope to property key.1291	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1292		let prefix = self.prefix();1293		if prefix == b"" {1294			return Ok(key);1295		}1296		[prefix, key.as_slice()]1297			.concat()1298			.try_into()1299			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1300	}1301}13021303/// Trait for operate with properties.1304pub trait TrySetProperty: Sized {1305	type Value;13061307	/// Try to set property with scope.1308	fn try_scoped_set(1309		&mut self,1310		scope: PropertyScope,1311		key: PropertyKey,1312		value: Self::Value,1313	) -> Result<Option<Self::Value>, PropertiesError>;13141315	/// Try to set property with scope from iterator.1316	fn try_scoped_set_from_iter<I, KV>(1317		&mut self,1318		scope: PropertyScope,1319		iter: I,1320	) -> Result<(), PropertiesError>1321	where1322		I: Iterator<Item = KV>,1323		KV: Into<(PropertyKey, Self::Value)>,1324	{1325		for kv in iter {1326			let (key, value) = kv.into();1327			self.try_scoped_set(scope, key, value)?;1328		}13291330		Ok(())1331	}13321333	/// Try to set property.1334	fn try_set(1335		&mut self,1336		key: PropertyKey,1337		value: Self::Value,1338	) -> Result<Option<Self::Value>, PropertiesError> {1339		self.try_scoped_set(PropertyScope::None, key, value)1340	}13411342	/// Try to set property from iterator.1343	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1344	where1345		I: Iterator<Item = KV>,1346		KV: Into<(PropertyKey, Self::Value)>,1347	{1348		self.try_scoped_set_from_iter(PropertyScope::None, iter)1349	}1350}13511352/// Wrapped map for storing properties.1353#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1354#[derivative(Default(bound = ""))]1355pub struct PropertiesMap<Value>(1356	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1357);13581359impl<Value> PropertiesMap<Value> {1360	/// Create new property map.1361	pub fn new() -> Self {1362		Self(BoundedBTreeMap::new())1363	}13641365	/// Remove property from map.1366	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1367		Self::check_property_key(key)?;13681369		Ok(self.0.remove(key))1370	}13711372	/// Get property with appropriate key from map.1373	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1374		self.0.get(key)1375	}13761377	/// Check if map contains key.1378	pub fn contains_key(&self, key: &PropertyKey) -> bool {1379		self.0.contains_key(key)1380	}13811382	/// Check if map contains key with key validation.1383	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1384		if key.is_empty() {1385			return Err(PropertiesError::EmptyPropertyKey);1386		}13871388		for byte in key.as_slice().iter() {1389			let byte = *byte;13901391			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1392				return Err(PropertiesError::InvalidCharacterInPropertyKey);1393			}1394		}13951396		Ok(())1397	}13981399	pub fn values(&self) -> impl Iterator<Item = &Value> {1400		self.0.values()1401	}14021403	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1404		self.0.iter()1405	}1406}14071408impl<Value> IntoIterator for PropertiesMap<Value> {1409	type Item = (PropertyKey, Value);1410	type IntoIter = <1411		BoundedBTreeMap<1412			PropertyKey,1413			Value,1414			ConstU32<MAX_PROPERTIES_PER_ITEM>1415		> as IntoIterator1416	>::IntoIter;14171418	fn into_iter(self) -> Self::IntoIter {1419		self.0.into_iter()1420	}1421}14221423impl<Value> TrySetProperty for PropertiesMap<Value> {1424	type Value = Value;14251426	fn try_scoped_set(1427		&mut self,1428		scope: PropertyScope,1429		key: PropertyKey,1430		value: Self::Value,1431	) -> Result<Option<Self::Value>, PropertiesError> {1432		Self::check_property_key(&key)?;14331434		let key = scope.apply(key)?;1435		self.01436			.try_insert(key, value)1437			.map_err(|_| PropertiesError::PropertyLimitReached)1438	}1439}14401441/// Alias for property permissions map.1442pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;14431444fn slice_size(data: &[u8]) -> u32 {1445	scoped_slice_size(PropertyScope::None, data)1446}1447fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1448	use parity_scale_codec::Compact;1449	let prefix = scope.prefix();1450	<Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321451		+ data.len() as u321452		+ prefix.len() as u321453}14541455/// Wrapper for properties map with consumed space control.1456#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1457pub struct Properties<const S: u32> {1458	map: PropertiesMap<PropertyValue>,1459	consumed_space: u32,1460	// May be not zero, previously served as a current S generic1461	_reserved: u32,1462}14631464impl<const S: u32> MaxEncodedLen for Properties<S> {1465	fn max_encoded_len() -> usize {1466		// len of map + len of consumed_space + len of space_limit1467		u32::max_encoded_len() * 3 + S as usize1468	}1469}14701471impl<const S: u32> Default for Properties<S> {1472	fn default() -> Self {1473		Self::new()1474	}1475}14761477impl<const S: u32> Properties<S> {1478	/// Create new properies container.1479	pub fn new() -> Self {1480		Self {1481			map: PropertiesMap::new(),1482			consumed_space: 0,1483			_reserved: 0,1484		}1485	}14861487	/// Remove propery with appropiate key.1488	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1489		let value = self.map.remove(key)?;14901491		if let Some(ref value) = value {1492			let kv_len = slice_size(key) + slice_size(value);1493			self.consumed_space = self.consumed_space.saturating_sub(kv_len);1494		}14951496		Ok(value)1497	}14981499	/// Get property with appropriate key.1500	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1501		self.map.get(key)1502	}15031504	/// Recomputes the consumed space for the current properties state.1505	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1506	pub fn recompute_consumed_space(&mut self) {1507		self.consumed_space = self1508			.map1509			.iter()1510			.map(|(key, value)| slice_size(key) + slice_size(value))1511			.sum();1512	}1513}15141515impl<const S: u32> IntoIterator for Properties<S> {1516	type Item = (PropertyKey, PropertyValue);1517	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;15181519	fn into_iter(self) -> Self::IntoIter {1520		self.map.into_iter()1521	}1522}15231524impl<const S: u32> TrySetProperty for Properties<S> {1525	type Value = PropertyValue;15261527	fn try_scoped_set(1528		&mut self,1529		scope: PropertyScope,1530		key: PropertyKey,1531		value: Self::Value,1532	) -> Result<Option<Self::Value>, PropertiesError> {1533		let key_size = scoped_slice_size(scope, &key);1534		let value_size = slice_size(&value);15351536		if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1537		{1538			return Err(PropertiesError::NoSpaceForProperty);1539		}15401541		let old_value = self.map.try_scoped_set(scope, key, value)?;15421543		if let Some(old_value) = old_value.as_ref() {1544			let old_value_size = slice_size(old_value);1545			self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1546		} else {1547			self.consumed_space += key_size + value_size;1548		}15491550		Ok(old_value)1551	}1552}15531554pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1555pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;