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

difftreelog

source

primitives/data-structs/src/lib.rs40.9 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};28use frame_support::storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet};2930#[cfg(feature = "serde")]31use serde::{Serialize, Deserialize};3233use sp_core::U256;34use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};35use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};36use bondrewd::Bitfields;37use frame_support::{BoundedVec, traits::ConstU32};38use derivative::Derivative;39use scale_info::TypeInfo;4041mod bondrewd_codec;42mod bounded;43pub mod budget;44pub mod mapping;45mod migration;4647/// Maximum of decimal points.48pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;4950/// Maximum pieces for refungible token.51pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;52pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5354/// Maximum tokens for user.55pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {56	100_00057} else {58	1059};6061/// Maximum for collections can be created.62pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {63	100_00064} else {65	1066};6768/// Maximum for various custom data of token.69pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {70	204871} else {72	1073};7475/// Maximum admins per collection.76pub const COLLECTION_ADMINS_LIMIT: u32 = 5;7778/// Maximum tokens per collection.79pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;8081/// Maximum tokens per account.82pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {83	1_000_00084} else {85	1086};8788/// Default timeout for transfer sponsoring NFT item.89pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;90/// Default timeout for transfer sponsoring fungible item.91pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;92/// Default timeout for transfer sponsoring refungible item.93pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;9495/// Default timeout for sponsored approving.96pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9798// Schema limits99pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;100pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;101pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;102103// TODO: not used. Delete?104pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;105106/// Maximal length of a collection name.107pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;108109/// Maximal length of a collection description.110pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;111112/// Maximal length of a token prefix.113pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;114115/// Maximal length of a property key.116pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;117118/// Maximal length of a property value.119pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;120121/// A maximum number of token properties.122pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;123124/// Maximal lenght of extended property value.125pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;126127/// Maximum size for all collection properties.128pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;129130/// Maximum size of all token properties.131pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;132133/// How much items can be created per single134/// create_many call.135pub const MAX_ITEMS_PER_BATCH: u32 = 200;136137/// Used for limit bounded types of token custom data.138pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;139140/// Collection id.141#[derive(142	Encode,143	Decode,144	PartialEq,145	Eq,146	PartialOrd,147	Ord,148	Clone,149	Copy,150	Debug,151	Default,152	TypeInfo,153	MaxEncodedLen,154)]155#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]156pub struct CollectionId(pub u32);157impl EncodeLike<u32> for CollectionId {}158impl EncodeLike<CollectionId> for u32 {}159160impl From<u32> for CollectionId {161	fn from(value: u32) -> Self {162		Self(value)163	}164}165166/// Token id.167#[derive(168	Encode,169	Decode,170	PartialEq,171	Eq,172	PartialOrd,173	Ord,174	Clone,175	Copy,176	Debug,177	Default,178	TypeInfo,179	MaxEncodedLen,180)]181#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]182pub struct TokenId(pub u32);183impl EncodeLike<u32> for TokenId {}184impl EncodeLike<TokenId> for u32 {}185186impl TokenId {187	/// Try to get next token id.188	///189	/// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.190	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {191		self.0192			.checked_add(1)193			.ok_or(ArithmeticError::Overflow)194			.map(Self)195	}196}197198impl From<TokenId> for U256 {199	fn from(t: TokenId) -> Self {200		t.0.into()201	}202}203204impl TryFrom<U256> for TokenId {205	type Error = &'static str;206207	fn try_from(value: U256) -> Result<Self, Self::Error> {208		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))209	}210}211212/// Token data.213#[struct_versioning::versioned(version = 2, upper)]214#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]215#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]216pub struct TokenData<CrossAccountId> {217	/// Properties of token.218	pub properties: Vec<Property>,219220	/// Token owner.221	pub owner: Option<CrossAccountId>,222223	/// Token pieces.224	#[version(2.., upper(0))]225	pub pieces: u128,226}227228// TODO: unused type229pub struct OverflowError;230impl From<OverflowError> for &'static str {231	fn from(_: OverflowError) -> Self {232		"overflow occured"233	}234}235236/// Alias for decimal points type.237pub type DecimalPoints = u8;238239/// Collection mode.240///241/// Collection can represent various types of tokens.242/// Each collection can contain only one type of tokens at a time.243/// This type helps to understand which tokens the collection contains.244#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]245#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]246pub enum CollectionMode {247	/// Non fungible tokens.248	NFT,249	/// Fungible tokens.250	Fungible(DecimalPoints),251	/// Refungible tokens.252	ReFungible,253}254255impl CollectionMode {256	/// Get collection mod as number.257	pub fn id(&self) -> u8 {258		match self {259			CollectionMode::NFT => 1,260			CollectionMode::Fungible(_) => 2,261			CollectionMode::ReFungible => 3,262		}263	}264}265266// TODO: unused trait267pub trait SponsoringResolve<AccountId, Call> {268	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;269}270271/// Access mode for some token operations.272#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]273#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]274pub enum AccessMode {275	/// Access grant for owner and admins. Used as default.276	Normal,277	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.278	AllowList,279}280impl Default for AccessMode {281	fn default() -> Self {282		Self::Normal283	}284}285286// TODO: remove in future.287#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]288#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]289pub enum SchemaVersion {290	ImageURL,291	Unique,292}293impl Default for SchemaVersion {294	fn default() -> Self {295		Self::ImageURL296	}297}298299// TODO: unused type300#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]301#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]302pub struct Ownership<AccountId> {303	pub owner: AccountId,304	pub fraction: u128,305}306307/// The state of collection sponsorship.308#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]309#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]310pub enum SponsorshipState<AccountId> {311	/// The fees are applied to the transaction sender.312	Disabled,313	/// The sponsor is under consideration. Until the sponsor gives his consent,314	/// the fee will still be charged to sender.315	Unconfirmed(AccountId),316	/// Transactions are sponsored by specified account.317	Confirmed(AccountId),318}319320impl<AccountId> SponsorshipState<AccountId> {321	/// Get a sponsor of the collection who has confirmed his status.322	pub fn sponsor(&self) -> Option<&AccountId> {323		match self {324			Self::Confirmed(sponsor) => Some(sponsor),325			_ => None,326		}327	}328329	/// Get a sponsor of the collection who has pending or confirmed status.330	pub fn pending_sponsor(&self) -> Option<&AccountId> {331		match self {332			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),333			_ => None,334		}335	}336337	/// Whether the sponsorship is confirmed.338	pub fn confirmed(&self) -> bool {339		matches!(self, Self::Confirmed(_))340	}341}342343impl<T> Default for SponsorshipState<T> {344	fn default() -> Self {345		Self::Disabled346	}347}348349pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;350pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;351pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;352353#[derive(Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]354#[bondrewd(enforce_bytes = 1)]355pub struct CollectionFlags {356	/// Tokens in foreign collections can be transferred, but not burnt357	#[bondrewd(bits = "0..1")]358	pub foreign: bool,359	/// Supports ERC721Metadata360	#[bondrewd(bits = "1..2")]361	pub erc721metadata: bool,362	/// External collections can't be managed using `unique` api363	#[bondrewd(bits = "7..8")]364	pub external: bool,365366	#[bondrewd(reserve, bits = "2..7")]367	pub reserved: u8,368}369bondrewd_codec!(CollectionFlags);370371/// Base structure for represent collection.372///373/// Used to provide basic functionality for all types of collections.374///375/// #### Note376/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).377#[struct_versioning::versioned(version = 2, upper)]378#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]379pub struct Collection<AccountId> {380	/// Collection owner account.381	pub owner: AccountId,382383	/// Collection mode.384	pub mode: CollectionMode,385386	/// Access mode.387	#[version(..2)]388	pub access: AccessMode,389390	/// Collection name.391	pub name: CollectionName,392393	/// Collection description.394	pub description: CollectionDescription,395396	/// Token prefix.397	pub token_prefix: CollectionTokenPrefix,398399	#[version(..2)]400	pub mint_mode: bool,401402	#[version(..2)]403	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,404405	#[version(..2)]406	pub schema_version: SchemaVersion,407408	/// The state of sponsorship of the collection.409	pub sponsorship: SponsorshipState<AccountId>,410411	/// Collection limits.412	pub limits: CollectionLimits,413414	/// Collection permissions.415	#[version(2.., upper(Default::default()))]416	pub permissions: CollectionPermissions,417418	#[version(2.., upper(Default::default()))]419	pub flags: CollectionFlags,420421	#[version(..2)]422	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,423424	#[version(..2)]425	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,426427	#[version(..2)]428	pub meta_update_permission: MetaUpdatePermission,429}430431#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo)]432#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]433pub struct RpcCollectionFlags {434	/// Is collection is foreign.435	pub foreign: bool,436	/// Collection supports ERC721Metadata.437	pub erc721metadata: bool,438}439440/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).441#[struct_versioning::versioned(version = 2, upper)]442#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo)]443#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]444pub struct RpcCollection<AccountId> {445	/// Collection owner account.446	pub owner: AccountId,447448	/// Collection mode.449	pub mode: CollectionMode,450451	/// Collection name.452	pub name: Vec<u16>,453454	/// Collection description.455	pub description: Vec<u16>,456457	/// Token prefix.458	pub token_prefix: Vec<u8>,459460	/// The state of sponsorship of the collection.461	pub sponsorship: SponsorshipState<AccountId>,462463	/// Collection limits.464	pub limits: CollectionLimits,465466	/// Collection permissions.467	pub permissions: CollectionPermissions,468469	/// Token property permissions.470	pub token_property_permissions: Vec<PropertyKeyPermission>,471472	/// Collection properties.473	pub properties: Vec<Property>,474475	/// Is collection read only.476	pub read_only: bool,477478	/// Extra collection flags479	#[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]480	pub flags: RpcCollectionFlags,481}482483impl<AccountId> From<CollectionVersion1<AccountId>> for RpcCollection<AccountId> {484	fn from(value: CollectionVersion1<AccountId>) -> Self {485		let CollectionVersion1 {486			name,487			description,488			owner,489			mode,490			access,491			token_prefix,492			mint_mode,493			sponsorship,494			limits,495			..496		} = value;497498		RpcCollection {499			name: name.into_inner(),500			description: description.into_inner(),501			owner,502			mode,503			token_prefix: token_prefix.into_inner(),504			sponsorship,505			limits,506			permissions: CollectionPermissions {507				access: Some(access),508				mint_mode: Some(mint_mode),509				nesting: None,510			},511			token_property_permissions: Vec::default(),512			properties: Vec::default(),513			read_only: true,514515			flags: RpcCollectionFlags {516				foreign: false,517				erc721metadata: false,518			},519		}520	}521}522523pub struct RawEncoded(Vec<u8>);524525impl codec::Decode for RawEncoded {526	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {527		let mut out = Vec::new();528		while let Ok(v) = input.read_byte() {529			out.push(v);530		}531		Ok(Self(out))532	}533}534535impl Deref for RawEncoded {536	type Target = Vec<u8>;537538	fn deref(&self) -> &Self::Target {539		&self.0540	}541}542543/// Data used for create collection.544///545/// All fields are wrapped in [`Option`], where `None` means chain default.546#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]547#[derivative(Debug, Default(bound = ""))]548pub struct CreateCollectionData<AccountId> {549	/// Collection mode.550	#[derivative(Default(value = "CollectionMode::NFT"))]551	pub mode: CollectionMode,552553	/// Access mode.554	pub access: Option<AccessMode>,555556	/// Collection name.557	pub name: CollectionName,558559	/// Collection description.560	pub description: CollectionDescription,561562	/// Token prefix.563	pub token_prefix: CollectionTokenPrefix,564565	/// Pending collection sponsor.566	pub pending_sponsor: Option<AccountId>,567568	/// Collection limits.569	pub limits: Option<CollectionLimits>,570571	/// Collection permissions.572	pub permissions: Option<CollectionPermissions>,573574	/// Token property permissions.575	pub token_property_permissions: CollectionPropertiesPermissionsVec,576577	/// Collection properties.578	pub properties: CollectionPropertiesVec,579}580581/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].582// TODO: maybe rename to PropertiesPermissionsVec583pub type CollectionPropertiesPermissionsVec =584	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;585586/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].587pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;588589/// Limits and restrictions of a collection.590///591/// All fields are wrapped in [`Option`], where `None` means chain default.592///593/// Update with `pallet_common::Pallet::clamp_limits`.594// IMPORTANT: When adding/removing fields from this struct - don't forget to also595#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]596#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]597// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.598// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.599// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.600pub struct CollectionLimits {601	/// How many tokens can a user have on one account.602	/// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].603	/// * Limit - [`MAX_TOKEN_OWNERSHIP`].604	pub account_token_ownership_limit: Option<u32>,605606	/// How many bytes of data are available for sponsorship.607	/// * Default - [`CUSTOM_DATA_LIMIT`].608	/// * Limit - [`CUSTOM_DATA_LIMIT`].609	pub sponsored_data_size: Option<u32>,610611	// FIXME should we delete this or repurpose it?612	/// Times in how many blocks we sponsor data.613	///614	/// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.615	///616	/// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).617	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].618	///619	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]620	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,621	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]622623	/// How many tokens can be mined into this collection.624	///625	/// * Default - [`COLLECTION_TOKEN_LIMIT`].626	/// * Limit - [`COLLECTION_TOKEN_LIMIT`].627	pub token_limit: Option<u32>,628629	/// Timeouts for transfer sponsoring.630	///631	/// * Default632	///   - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]633	///   - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]634	///   - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]635	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].636	pub sponsor_transfer_timeout: Option<u32>,637638	/// Timeout for sponsoring an approval in passed blocks.639	///640	/// * Default - [`SPONSOR_APPROVE_TIMEOUT`].641	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].642	pub sponsor_approve_timeout: Option<u32>,643644	/// Whether the collection owner of the collection can send tokens (which belong to other users).645	///646	/// * Default - **false**.647	pub owner_can_transfer: Option<bool>,648649	/// Can the collection owner burn other people's tokens.650	///651	/// * Default - **true**.652	pub owner_can_destroy: Option<bool>,653654	/// Is it possible to send tokens from this collection between users.655	///656	/// * Default - **true**.657	pub transfers_enabled: Option<bool>,658}659660impl CollectionLimits {661	pub fn with_default_limits(collection_type: CollectionMode) -> Self {662		CollectionLimits {663			account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),664			sponsored_data_size: Some(CUSTOM_DATA_LIMIT),665			sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),666			token_limit: Some(COLLECTION_TOKEN_LIMIT),667			sponsor_transfer_timeout: match collection_type {668				CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),669				CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),670				CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),671			},672			sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),673			owner_can_transfer: Some(false),674			owner_can_destroy: Some(true),675			transfers_enabled: Some(true),676		}677	}678679	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).680	pub fn account_token_ownership_limit(&self) -> u32 {681		self.account_token_ownership_limit682			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)683			.min(MAX_TOKEN_OWNERSHIP)684	}685686	/// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).687	pub fn sponsored_data_size(&self) -> u32 {688		self.sponsored_data_size689			.unwrap_or(CUSTOM_DATA_LIMIT)690			.min(CUSTOM_DATA_LIMIT)691	}692693	/// Get effective value for [`token_limit`](self.token_limit).694	pub fn token_limit(&self) -> u32 {695		self.token_limit696			.unwrap_or(COLLECTION_TOKEN_LIMIT)697			.min(COLLECTION_TOKEN_LIMIT)698	}699700	// TODO: may be replace u32 to mode?701	/// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).702	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {703		self.sponsor_transfer_timeout704			.unwrap_or(default)705			.min(MAX_SPONSOR_TIMEOUT)706	}707708	/// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).709	pub fn sponsor_approve_timeout(&self) -> u32 {710		self.sponsor_approve_timeout711			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)712			.min(MAX_SPONSOR_TIMEOUT)713	}714715	/// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).716	pub fn owner_can_transfer(&self) -> bool {717		self.owner_can_transfer.unwrap_or(false)718	}719720	/// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).721	pub fn owner_can_transfer_instaled(&self) -> bool {722		self.owner_can_transfer.is_some()723	}724725	/// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).726	pub fn owner_can_destroy(&self) -> bool {727		self.owner_can_destroy.unwrap_or(true)728	}729730	/// Get effective value for [`transfers_enabled`](self.transfers_enabled).731	pub fn transfers_enabled(&self) -> bool {732		self.transfers_enabled.unwrap_or(true)733	}734735	/// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).736	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {737		match self738			.sponsored_data_rate_limit739			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)740		{741			SponsoringRateLimit::SponsoringDisabled => None,742			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),743		}744	}745}746747/// Permissions on certain operations within a collection.748///749/// Some fields are wrapped in [`Option`], where `None` means chain default.750///751/// Update with `pallet_common::Pallet::clamp_permissions`.752#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]753#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]754// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.755// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.756pub struct CollectionPermissions {757	/// Access mode.758	///759	/// * Default - [`AccessMode::Normal`].760	pub access: Option<AccessMode>,761762	/// Minting allowance.763	///764	/// * Default - **false**.765	pub mint_mode: Option<bool>,766767	/// Permissions for nesting.768	///769	/// * Default770	///   - `token_owner` - **false**771	///   - `collection_admin` - **false**772	///   - `restricted` - **None**773	pub nesting: Option<NestingPermissions>,774}775776impl CollectionPermissions {777	/// Get effective value for [`access`](self.access).778	pub fn access(&self) -> AccessMode {779		self.access.unwrap_or(AccessMode::Normal)780	}781782	/// Get effective value for [`mint_mode`](self.mint_mode).783	pub fn mint_mode(&self) -> bool {784		self.mint_mode.unwrap_or(false)785	}786787	/// Get effective value for [`nesting`](self.nesting).788	pub fn nesting(&self) -> &NestingPermissions {789		static DEFAULT: NestingPermissions = NestingPermissions {790			token_owner: false,791			collection_admin: false,792			restricted: None,793			#[cfg(feature = "runtime-benchmarks")]794			permissive: false,795		};796		self.nesting.as_ref().unwrap_or(&DEFAULT)797	}798}799800/// Inner set for collections allowed to nest.801type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;802803/// Wraper for collections set allowing nest.804#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]805#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]806#[derivative(Debug)]807pub struct OwnerRestrictedSet(808	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]809	#[derivative(Debug(format_with = "bounded::set_debug"))]810	pub OwnerRestrictedSetInner,811);812813impl OwnerRestrictedSet {814	/// Create new set.815	pub fn new() -> Self {816		Self(Default::default())817	}818}819impl Default for OwnerRestrictedSet {820	fn default() -> Self {821		Self::new()822	}823}824impl core::ops::Deref for OwnerRestrictedSet {825	type Target = OwnerRestrictedSetInner;826	fn deref(&self) -> &Self::Target {827		&self.0828	}829}830impl core::ops::DerefMut for OwnerRestrictedSet {831	fn deref_mut(&mut self) -> &mut Self::Target {832		&mut self.0833	}834}835836/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.837#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]838#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]839#[derivative(Debug)]840pub struct NestingPermissions {841	/// Owner of token can nest tokens under it.842	pub token_owner: bool,843	/// Admin of token collection can nest tokens under token.844	pub collection_admin: bool,845	/// If set - only tokens from specified collections can be nested.846	pub restricted: Option<OwnerRestrictedSet>,847848	#[cfg(feature = "runtime-benchmarks")]849	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.850	pub permissive: bool,851}852853/// Enum denominating how often can sponsoring occur if it is enabled.854///855/// Used for [`collection limits`](CollectionLimits).856#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]857#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]858pub enum SponsoringRateLimit {859	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions860	SponsoringDisabled,861	/// Once per how many blocks can sponsorship of a transaction type occur862	Blocks(u32),863}864865/// Data used to describe an NFT at creation.866#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]867#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]868#[derivative(Debug)]869pub struct CreateNftData {870	/// Key-value pairs used to describe the token as metadata871	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]872	#[derivative(Debug(format_with = "bounded::vec_debug"))]873	/// Properties that wil be assignet to created item.874	pub properties: CollectionPropertiesVec,875}876877/// Data used to describe a Fungible token at creation.878#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]879#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]880pub struct CreateFungibleData {881	/// Number of fungible coins minted882	pub value: u128,883}884885/// Data used to describe a Refungible token at creation.886#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]887#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]888#[derivative(Debug)]889pub struct CreateReFungibleData {890	/// Number of pieces the RFT is split into891	pub pieces: u128,892893	/// Key-value pairs used to describe the token as metadata894	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]895	#[derivative(Debug(format_with = "bounded::vec_debug"))]896	pub properties: CollectionPropertiesVec,897}898899// TODO: remove this.900#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]901#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]902pub enum MetaUpdatePermission {903	ItemOwner,904	Admin,905	None,906}907908/// Enum holding data used for creation of all three item types.909/// Unified data for create item.910#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]911#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]912pub enum CreateItemData {913	/// Data for create NFT.914	NFT(CreateNftData),915	/// Data for create Fungible item.916	Fungible(CreateFungibleData),917	/// Data for create ReFungible item.918	ReFungible(CreateReFungibleData),919}920921/// Extended data for create NFT.922#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]923#[derivative(Debug)]924pub struct CreateNftExData<CrossAccountId> {925	/// Properties that wil be assignet to created item.926	#[derivative(Debug(format_with = "bounded::vec_debug"))]927	pub properties: CollectionPropertiesVec,928929	/// Owner of creating item.930	pub owner: CrossAccountId,931}932933/// Extended data for create ReFungible item.934#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]935#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]936pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {937	#[derivative(Debug(format_with = "bounded::map_debug"))]938	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,939	#[derivative(Debug(format_with = "bounded::vec_debug"))]940	pub properties: CollectionPropertiesVec,941}942943/// Extended data for create ReFungible item.944#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]945#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]946pub struct CreateRefungibleExSingleOwner<CrossAccountId> {947	pub user: CrossAccountId,948	pub pieces: u128,949	#[derivative(Debug(format_with = "bounded::vec_debug"))]950	pub properties: CollectionPropertiesVec,951}952953/// Unified extended data for creating item.954#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]955#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]956pub enum CreateItemExData<CrossAccountId> {957	/// Extended data for create NFT.958	NFT(959		#[derivative(Debug(format_with = "bounded::vec_debug"))]960		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,961	),962963	/// Extended data for create Fungible item.964	Fungible(965		#[derivative(Debug(format_with = "bounded::map_debug"))]966		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,967	),968969	/// Extended data for create ReFungible item in case of970	/// many tokens, each may have only one owner971	RefungibleMultipleItems(972		#[derivative(Debug(format_with = "bounded::vec_debug"))]973		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,974	),975976	/// Extended data for create ReFungible item in case of977	/// single token, which may have many owners978	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),979}980981impl From<CreateNftData> for CreateItemData {982	fn from(item: CreateNftData) -> Self {983		CreateItemData::NFT(item)984	}985}986987impl From<CreateReFungibleData> for CreateItemData {988	fn from(item: CreateReFungibleData) -> Self {989		CreateItemData::ReFungible(item)990	}991}992993impl From<CreateFungibleData> for CreateItemData {994	fn from(item: CreateFungibleData) -> Self {995		CreateItemData::Fungible(item)996	}997}998999/// Token's address, dictated by its collection and token IDs.1000#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]1001#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1002// todo possibly rename to be used generally as an address pair1003pub struct TokenChild {1004	/// Token id.1005	pub token: TokenId,10061007	/// Collection id.1008	pub collection: CollectionId,1009}10101011/// Collection statistics.1012#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]1013#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1014pub struct CollectionStats {1015	/// Number of created items.1016	pub created: u32,10171018	/// Number of burned items.1019	pub destroyed: u32,10201021	/// Number of current items.1022	pub alive: u32,1023}10241025/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1026#[derive(Encode, Decode, Clone, Debug)]1027#[cfg_attr(feature = "std", derive(PartialEq))]1028pub struct PhantomType<T>(core::marker::PhantomData<T>);10291030impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1031	type Identity = PhantomType<T>;10321033	fn type_info() -> scale_info::Type {1034		use scale_info::{1035			Type, Path,1036			build::{FieldsBuilder, UnnamedFields},1037			form::MetaForm,1038			type_params,1039		};1040		Type::builder()1041			.path(Path::new("up_data_structs", "PhantomType"))1042			.type_params(type_params!(T))1043			.composite(1044				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1045			)1046	}1047}1048impl<T> MaxEncodedLen for PhantomType<T> {1049	fn max_encoded_len() -> usize {1050		01051	}1052}10531054/// Bounded vector of bytes.1055pub type BoundedBytes<S> = BoundedVec<u8, S>;10561057/// Extra properties for external collections.1058pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;10591060/// Property key.1061pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;10621063/// Property value.1064pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;10651066/// Property permission.1067#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1068#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1069pub struct PropertyPermission {1070	/// Permission to change the property and property permission.1071	///1072	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1073	pub mutable: bool,10741075	/// Change permission for the collection administrator.1076	pub collection_admin: bool,10771078	/// Permission to change the property for the owner of the token.1079	pub token_owner: bool,1080}10811082impl PropertyPermission {1083	/// Creates mutable property permission but changes restricted for collection admin and token owner.1084	pub fn none() -> Self {1085		Self {1086			mutable: true,1087			collection_admin: false,1088			token_owner: false,1089		}1090	}1091}10921093/// Property is simpl key-value record.1094#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1095#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1096pub struct Property {1097	/// Property key.1098	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1099	pub key: PropertyKey,11001101	/// Property value.1102	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1103	pub value: PropertyValue,1104}11051106impl From<Property> for (PropertyKey, PropertyValue) {1107	fn from(value: Property) -> Self {1108		(value.key, value.value)1109	}1110}11111112/// Record for proprty key permission.1113#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1114#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1115pub struct PropertyKeyPermission {1116	/// Key.1117	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1118	pub key: PropertyKey,11191120	/// Permission.1121	pub permission: PropertyPermission,1122}11231124impl From<PropertyKeyPermission> for (PropertyKey, PropertyPermission) {1125	fn from(value: PropertyKeyPermission) -> Self {1126		(value.key, value.permission)1127	}1128}11291130/// Errors for properties actions.1131#[derive(Debug)]1132pub enum PropertiesError {1133	/// The space allocated for properties has run out.1134	///1135	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1136	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1137	NoSpaceForProperty,11381139	/// The property limit has been reached.1140	///1141	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1142	PropertyLimitReached,11431144	/// Property key contains not allowed character.1145	InvalidCharacterInPropertyKey,11461147	/// Property key length is too long.1148	///1149	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1150	PropertyKeyIsTooLong,11511152	/// Property key is empty.1153	EmptyPropertyKey,1154}11551156/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1157#[derive(Debug)]1158pub enum TokenOwnerError {1159	NotFound,1160	MultipleOwners,1161}11621163/// Marker for scope of property.1164///1165/// Scoped property can't be changed by user. Used for external collections.1166#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1167pub enum PropertyScope {1168	None,1169	Rmrk,1170}11711172impl PropertyScope {1173	pub fn prefix(&self) -> &'static [u8] {1174		match self {1175			Self::None => b"",1176			Self::Rmrk => b"rmrk:",1177		}1178	}1179	/// Apply scope to property key.1180	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1181		let prefix = self.prefix();1182		if prefix == b"" {1183			return Ok(key);1184		}1185		[prefix, key.as_slice()]1186			.concat()1187			.try_into()1188			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1189	}1190}11911192/// Trait for operate with properties.1193pub trait TrySetProperty: Sized {1194	type Value;11951196	/// Try to set property with scope.1197	fn try_scoped_set(1198		&mut self,1199		scope: PropertyScope,1200		key: PropertyKey,1201		value: Self::Value,1202	) -> Result<Option<Self::Value>, PropertiesError>;12031204	/// Try to set property with scope from iterator.1205	fn try_scoped_set_from_iter<I, KV>(1206		&mut self,1207		scope: PropertyScope,1208		iter: I,1209	) -> Result<(), PropertiesError>1210	where1211		I: Iterator<Item = KV>,1212		KV: Into<(PropertyKey, Self::Value)>,1213	{1214		for kv in iter {1215			let (key, value) = kv.into();1216			self.try_scoped_set(scope, key, value)?;1217		}12181219		Ok(())1220	}12211222	/// Try to set property.1223	fn try_set(1224		&mut self,1225		key: PropertyKey,1226		value: Self::Value,1227	) -> Result<Option<Self::Value>, PropertiesError> {1228		self.try_scoped_set(PropertyScope::None, key, value)1229	}12301231	/// Try to set property from iterator.1232	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1233	where1234		I: Iterator<Item = KV>,1235		KV: Into<(PropertyKey, Self::Value)>,1236	{1237		self.try_scoped_set_from_iter(PropertyScope::None, iter)1238	}1239}12401241/// Wrapped map for storing properties.1242#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1243#[derivative(Default(bound = ""))]1244pub struct PropertiesMap<Value>(1245	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1246);12471248impl<Value> PropertiesMap<Value> {1249	/// Create new property map.1250	pub fn new() -> Self {1251		Self(BoundedBTreeMap::new())1252	}12531254	/// Remove property from map.1255	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1256		Self::check_property_key(key)?;12571258		Ok(self.0.remove(key))1259	}12601261	/// Get property with appropriate key from map.1262	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1263		self.0.get(key)1264	}12651266	/// Check if map contains key.1267	pub fn contains_key(&self, key: &PropertyKey) -> bool {1268		self.0.contains_key(key)1269	}12701271	/// Check if map contains key with key validation.1272	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1273		if key.is_empty() {1274			return Err(PropertiesError::EmptyPropertyKey);1275		}12761277		for byte in key.as_slice().iter() {1278			let byte = *byte;12791280			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1281				return Err(PropertiesError::InvalidCharacterInPropertyKey);1282			}1283		}12841285		Ok(())1286	}12871288	pub fn values(&self) -> impl Iterator<Item = &Value> {1289		self.0.values()1290	}12911292	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1293		self.0.iter()1294	}1295}12961297impl<Value> IntoIterator for PropertiesMap<Value> {1298	type Item = (PropertyKey, Value);1299	type IntoIter = <1300		BoundedBTreeMap<1301			PropertyKey,1302			Value,1303			ConstU32<MAX_PROPERTIES_PER_ITEM>1304		> as IntoIterator1305	>::IntoIter;13061307	fn into_iter(self) -> Self::IntoIter {1308		self.0.into_iter()1309	}1310}13111312impl<Value> TrySetProperty for PropertiesMap<Value> {1313	type Value = Value;13141315	fn try_scoped_set(1316		&mut self,1317		scope: PropertyScope,1318		key: PropertyKey,1319		value: Self::Value,1320	) -> Result<Option<Self::Value>, PropertiesError> {1321		Self::check_property_key(&key)?;13221323		let key = scope.apply(key)?;1324		self.01325			.try_insert(key, value)1326			.map_err(|_| PropertiesError::PropertyLimitReached)1327	}1328}13291330/// Alias for property permissions map.1331pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;13321333fn slice_size(data: &[u8]) -> u32 {1334	scoped_slice_size(PropertyScope::None, data)1335}1336fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1337	use codec::Compact;1338	let prefix = scope.prefix();1339	<Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321340		+ data.len() as u321341		+ prefix.len() as u321342}13431344/// Wrapper for properties map with consumed space control.1345#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1346pub struct Properties<const S: u32> {1347	map: PropertiesMap<PropertyValue>,1348	consumed_space: u32,1349	// May be not zero, previously served as a current S generic1350	_reserved: u32,1351}13521353impl<const S: u32> MaxEncodedLen for Properties<S> {1354	fn max_encoded_len() -> usize {1355		// len of map + len of consumed_space + len of space_limit1356		u32::max_encoded_len() * 3 + S as usize1357	}1358}13591360impl<const S: u32> Default for Properties<S> {1361	fn default() -> Self {1362		Self::new()1363	}1364}13651366impl<const S: u32> Properties<S> {1367	/// Create new properies container.1368	pub fn new() -> Self {1369		Self {1370			map: PropertiesMap::new(),1371			consumed_space: 0,1372			_reserved: 0,1373		}1374	}13751376	/// Remove propery with appropiate key.1377	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1378		let value = self.map.remove(key)?;13791380		if let Some(ref value) = value {1381			let kv_len = slice_size(key) + slice_size(value);1382			self.consumed_space = self.consumed_space.saturating_sub(kv_len);1383		}13841385		Ok(value)1386	}13871388	/// Get property with appropriate key.1389	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1390		self.map.get(key)1391	}13921393	/// Recomputes the consumed space for the current properties state.1394	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1395	pub fn recompute_consumed_space(&mut self) {1396		self.consumed_space = self1397			.map1398			.iter()1399			.map(|(key, value)| slice_size(key) + slice_size(value))1400			.sum();1401	}1402}14031404impl<const S: u32> IntoIterator for Properties<S> {1405	type Item = (PropertyKey, PropertyValue);1406	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;14071408	fn into_iter(self) -> Self::IntoIter {1409		self.map.into_iter()1410	}1411}14121413impl<const S: u32> TrySetProperty for Properties<S> {1414	type Value = PropertyValue;14151416	fn try_scoped_set(1417		&mut self,1418		scope: PropertyScope,1419		key: PropertyKey,1420		value: Self::Value,1421	) -> Result<Option<Self::Value>, PropertiesError> {1422		let key_size = scoped_slice_size(scope, &key);1423		let value_size = slice_size(&value);14241425		if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1426		{1427			return Err(PropertiesError::NoSpaceForProperty);1428		}14291430		let old_value = self.map.try_scoped_set(scope, key, value)?;14311432		if let Some(old_value) = old_value.as_ref() {1433			let old_value_size = slice_size(old_value);1434			self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1435		} else {1436			self.consumed_space += key_size + value_size;1437		}14381439		Ok(old_value)1440	}1441}14421443pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1444pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;