git.delta.rocks / unique-network / refs/commits / 7b3fd6071003

difftreelog

source

primitives/data-structs/src/lib.rs52.2 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};27use frame_support::storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet};2829#[cfg(feature = "serde")]30use serde::{Serialize, Deserialize};3132use sp_core::U256;33use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};34use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};35use bondrewd::Bitfields;36use frame_support::{BoundedVec, traits::ConstU32};37use derivative::Derivative;38use scale_info::TypeInfo;3940mod bondrewd_codec;41mod bounded;42pub mod budget;43pub mod mapping;44mod migration;4546/// Maximum of decimal points.47pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;4849/// Maximum pieces for refungible token.50pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;51pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5253/// Maximum tokens for user.54pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {55	100_00056} else {57	1058};5960/// Maximum for collections can be created.61pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {62	100_00063} else {64	1065};6667/// Maximum for various custom data of token.68pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {69	204870} else {71	1072};7374/// Maximum admins per collection.75pub const COLLECTION_ADMINS_LIMIT: u32 = 5;7677/// Maximum tokens per collection.78pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;7980/// Maximum tokens per account.81pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {82	1_000_00083} else {84	1085};8687/// Default timeout for transfer sponsoring NFT item.88pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;89/// Default timeout for transfer sponsoring fungible item.90pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;91/// Default timeout for transfer sponsoring refungible item.92pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;9394/// Default timeout for sponsored approving.95pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9697// Schema limits98pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;99pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;100pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;101102// TODO: not used. Delete?103pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;104105/// Maximal length of a collection name.106pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;107108/// Maximal length of a collection description.109pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;110111/// Maximal length of a token prefix.112pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;113114/// Maximal length of a property key.115pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;116117/// Maximal length of a property value.118pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;119120/// A maximum number of token properties.121pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;122123/// Maximal lenght of extended property value.124pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;125126/// Maximum size for all collection properties.127pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;128129/// Maximum size of all token properties.130pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;131132/// How much items can be created per single133/// create_many call.134pub const MAX_ITEMS_PER_BATCH: u32 = 200;135136/// Used for limit bounded types of token custom data.137pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;138139/// Collection id.140#[derive(141	Encode,142	Decode,143	PartialEq,144	Eq,145	PartialOrd,146	Ord,147	Clone,148	Copy,149	Debug,150	Default,151	TypeInfo,152	MaxEncodedLen,153)]154#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]155pub struct CollectionId(pub u32);156impl EncodeLike<u32> for CollectionId {}157impl EncodeLike<CollectionId> for u32 {}158159impl From<u32> for CollectionId {160	fn from(value: u32) -> Self {161		Self(value)162	}163}164165/// Token id.166#[derive(167	Encode,168	Decode,169	PartialEq,170	Eq,171	PartialOrd,172	Ord,173	Clone,174	Copy,175	Debug,176	Default,177	TypeInfo,178	MaxEncodedLen,179)]180#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]181pub struct TokenId(pub u32);182impl EncodeLike<u32> for TokenId {}183impl EncodeLike<TokenId> for u32 {}184185impl TokenId {186	/// Try to get next token id.187	///188	/// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.189	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {190		self.0191			.checked_add(1)192			.ok_or(ArithmeticError::Overflow)193			.map(Self)194	}195}196197impl From<TokenId> for U256 {198	fn from(t: TokenId) -> Self {199		t.0.into()200	}201}202203impl TryFrom<U256> for TokenId {204	type Error = &'static str;205206	fn try_from(value: U256) -> Result<Self, Self::Error> {207		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))208	}209}210211/// Token data.212#[struct_versioning::versioned(version = 2, upper)]213#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]214#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]215pub struct TokenData<CrossAccountId> {216	/// Properties of token.217	pub properties: Vec<Property>,218219	/// Token owner.220	pub owner: Option<CrossAccountId>,221222	/// Token pieces.223	#[version(2.., upper(0))]224	pub pieces: u128,225}226227// TODO: unused type228pub struct OverflowError;229impl From<OverflowError> for &'static str {230	fn from(_: OverflowError) -> Self {231		"overflow occured"232	}233}234235/// Alias for decimal points type.236pub type DecimalPoints = u8;237238/// Collection mode.239///240/// Collection can represent various types of tokens.241/// Each collection can contain only one type of tokens at a time.242/// This type helps to understand which tokens the collection contains.243#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]244#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]245pub enum CollectionMode {246	/// Non fungible tokens.247	NFT,248	/// Fungible tokens.249	Fungible(DecimalPoints),250	/// Refungible tokens.251	ReFungible,252}253254impl CollectionMode {255	/// Get collection mod as number.256	pub fn id(&self) -> u8 {257		match self {258			CollectionMode::NFT => 1,259			CollectionMode::Fungible(_) => 2,260			CollectionMode::ReFungible => 3,261		}262	}263}264265// TODO: unused trait266pub trait SponsoringResolve<AccountId, Call> {267	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;268}269270/// Access mode for some token operations.271#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]272#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]273pub enum AccessMode {274	/// Access grant for owner and admins. Used as default.275	Normal,276	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.277	AllowList,278}279impl Default for AccessMode {280	fn default() -> Self {281		Self::Normal282	}283}284285// TODO: remove in future.286#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]287#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]288pub enum SchemaVersion {289	ImageURL,290	Unique,291}292impl Default for SchemaVersion {293	fn default() -> Self {294		Self::ImageURL295	}296}297298// TODO: unused type299#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]300#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]301pub struct Ownership<AccountId> {302	pub owner: AccountId,303	pub fraction: u128,304}305306/// The state of collection sponsorship.307#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]308#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]309pub enum SponsorshipState<AccountId> {310	/// The fees are applied to the transaction sender.311	Disabled,312	/// The sponsor is under consideration. Until the sponsor gives his consent,313	/// the fee will still be charged to sender.314	Unconfirmed(AccountId),315	/// Transactions are sponsored by specified account.316	Confirmed(AccountId),317}318319impl<AccountId> SponsorshipState<AccountId> {320	/// Get a sponsor of the collection who has confirmed his status.321	pub fn sponsor(&self) -> Option<&AccountId> {322		match self {323			Self::Confirmed(sponsor) => Some(sponsor),324			_ => None,325		}326	}327328	/// Get a sponsor of the collection who has pending or confirmed status.329	pub fn pending_sponsor(&self) -> Option<&AccountId> {330		match self {331			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),332			_ => None,333		}334	}335336	/// Whether the sponsorship is confirmed.337	pub fn confirmed(&self) -> bool {338		matches!(self, Self::Confirmed(_))339	}340}341342impl<T> Default for SponsorshipState<T> {343	fn default() -> Self {344		Self::Disabled345	}346}347348pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;349pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;350pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;351352#[derive(Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]353#[bondrewd(enforce_bytes = 1)]354pub struct CollectionFlags {355	/// Tokens in foreign collections can be transferred, but not burnt356	#[bondrewd(bits = "0..1")]357	pub foreign: bool,358	/// Supports ERC721Metadata359	#[bondrewd(bits = "1..2")]360	pub erc721metadata: bool,361	/// External collections can't be managed using `unique` api362	#[bondrewd(bits = "7..8")]363	pub external: bool,364365	#[bondrewd(reserve, bits = "2..7")]366	pub reserved: u8,367}368bondrewd_codec!(CollectionFlags);369370/// Base structure for represent collection.371///372/// Used to provide basic functionality for all types of collections.373///374/// #### Note375/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).376#[struct_versioning::versioned(version = 2, upper)]377#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]378pub struct Collection<AccountId> {379	/// Collection owner account.380	pub owner: AccountId,381382	/// Collection mode.383	pub mode: CollectionMode,384385	/// Access mode.386	#[version(..2)]387	pub access: AccessMode,388389	/// Collection name.390	pub name: CollectionName,391392	/// Collection description.393	pub description: CollectionDescription,394395	/// Token prefix.396	pub token_prefix: CollectionTokenPrefix,397398	#[version(..2)]399	pub mint_mode: bool,400401	#[version(..2)]402	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,403404	#[version(..2)]405	pub schema_version: SchemaVersion,406407	/// The state of sponsorship of the collection.408	pub sponsorship: SponsorshipState<AccountId>,409410	/// Collection limits.411	pub limits: CollectionLimits,412413	/// Collection permissions.414	#[version(2.., upper(Default::default()))]415	pub permissions: CollectionPermissions,416417	#[version(2.., upper(Default::default()))]418	pub flags: CollectionFlags,419420	#[version(..2)]421	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,422423	#[version(..2)]424	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,425426	#[version(..2)]427	pub meta_update_permission: MetaUpdatePermission,428}429430#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]431#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]432pub struct RpcCollectionFlags {433	/// Is collection is foreign.434	pub foreign: bool,435	/// Collection supports ERC721Metadata.436	pub erc721metadata: bool,437}438439/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).440#[struct_versioning::versioned(version = 2, upper)]441#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]442#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]443pub struct RpcCollection<AccountId> {444	/// Collection owner account.445	pub owner: AccountId,446447	/// Collection mode.448	pub mode: CollectionMode,449450	/// Collection name.451	pub name: Vec<u16>,452453	/// Collection description.454	pub description: Vec<u16>,455456	/// Token prefix.457	pub token_prefix: Vec<u8>,458459	/// The state of sponsorship of the collection.460	pub sponsorship: SponsorshipState<AccountId>,461462	/// Collection limits.463	pub limits: CollectionLimits,464465	/// Collection permissions.466	pub permissions: CollectionPermissions,467468	/// Token property permissions.469	pub token_property_permissions: Vec<PropertyKeyPermission>,470471	/// Collection properties.472	pub properties: Vec<Property>,473474	/// Is collection read only.475	pub read_only: bool,476477	/// Extra collection flags478	#[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]479	pub flags: RpcCollectionFlags,480}481482impl<AccountId> From<CollectionVersion1<AccountId>> for RpcCollection<AccountId> {483	fn from(value: CollectionVersion1<AccountId>) -> Self {484		let CollectionVersion1 {485			name,486			description,487			owner,488			mode,489			access,490			token_prefix,491			mint_mode,492			sponsorship,493			limits,494			..495		} = value;496497		RpcCollection {498			name: name.into_inner(),499			description: description.into_inner(),500			owner,501			mode,502			token_prefix: token_prefix.into_inner(),503			sponsorship,504			limits,505			permissions: CollectionPermissions {506				access: Some(access),507				mint_mode: Some(mint_mode),508				nesting: None,509			},510			token_property_permissions: Vec::default(),511			properties: Vec::default(),512			read_only: true,513514			flags: RpcCollectionFlags {515				foreign: false,516				erc721metadata: false,517			},518		}519	}520}521522/// Data used for create collection.523///524/// All fields are wrapped in [`Option`], where `None` means chain default.525#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]526#[derivative(Debug, Default(bound = ""))]527pub struct CreateCollectionData<AccountId> {528	/// Collection mode.529	#[derivative(Default(value = "CollectionMode::NFT"))]530	pub mode: CollectionMode,531532	/// Access mode.533	pub access: Option<AccessMode>,534535	/// Collection name.536	pub name: CollectionName,537538	/// Collection description.539	pub description: CollectionDescription,540541	/// Token prefix.542	pub token_prefix: CollectionTokenPrefix,543544	/// Pending collection sponsor.545	pub pending_sponsor: Option<AccountId>,546547	/// Collection limits.548	pub limits: Option<CollectionLimits>,549550	/// Collection permissions.551	pub permissions: Option<CollectionPermissions>,552553	/// Token property permissions.554	pub token_property_permissions: CollectionPropertiesPermissionsVec,555556	/// Collection properties.557	pub properties: CollectionPropertiesVec,558}559560/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].561// TODO: maybe rename to PropertiesPermissionsVec562pub type CollectionPropertiesPermissionsVec =563	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;564565/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].566pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;567568/// Limits and restrictions of a collection.569///570/// All fields are wrapped in [`Option`], where `None` means chain default.571///572/// Update with `pallet_common::Pallet::clamp_limits`.573// IMPORTANT: When adding/removing fields from this struct - don't forget to also574#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]575#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]576// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.577// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.578// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.579pub struct CollectionLimits {580	/// How many tokens can a user have on one account.581	/// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].582	/// * Limit - [`MAX_TOKEN_OWNERSHIP`].583	pub account_token_ownership_limit: Option<u32>,584585	/// How many bytes of data are available for sponsorship.586	/// * Default - [`CUSTOM_DATA_LIMIT`].587	/// * Limit - [`CUSTOM_DATA_LIMIT`].588	pub sponsored_data_size: Option<u32>,589590	// FIXME should we delete this or repurpose it?591	/// Times in how many blocks we sponsor data.592	///593	/// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.594	///595	/// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).596	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].597	///598	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]599	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,600	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]601602	/// How many tokens can be mined into this collection.603	///604	/// * Default - [`COLLECTION_TOKEN_LIMIT`].605	/// * Limit - [`COLLECTION_TOKEN_LIMIT`].606	pub token_limit: Option<u32>,607608	/// Timeouts for transfer sponsoring.609	///610	/// * Default611	///   - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]612	///   - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]613	///   - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]614	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].615	pub sponsor_transfer_timeout: Option<u32>,616617	/// Timeout for sponsoring an approval in passed blocks.618	///619	/// * Default - [`SPONSOR_APPROVE_TIMEOUT`].620	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].621	pub sponsor_approve_timeout: Option<u32>,622623	/// Whether the collection owner of the collection can send tokens (which belong to other users).624	///625	/// * Default - **false**.626	pub owner_can_transfer: Option<bool>,627628	/// Can the collection owner burn other people's tokens.629	///630	/// * Default - **true**.631	pub owner_can_destroy: Option<bool>,632633	/// Is it possible to send tokens from this collection between users.634	///635	/// * Default - **true**.636	pub transfers_enabled: Option<bool>,637}638639impl CollectionLimits {640	pub fn with_default_limits(collection_type: CollectionMode) -> Self {641		CollectionLimits {642			account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),643			sponsored_data_size: Some(CUSTOM_DATA_LIMIT),644			sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),645			token_limit: Some(COLLECTION_TOKEN_LIMIT),646			sponsor_transfer_timeout: match collection_type {647				CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),648				CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),649				CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),650			},651			sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),652			owner_can_transfer: Some(false),653			owner_can_destroy: Some(true),654			transfers_enabled: Some(true),655		}656	}657658	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).659	pub fn account_token_ownership_limit(&self) -> u32 {660		self.account_token_ownership_limit661			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)662			.min(MAX_TOKEN_OWNERSHIP)663	}664665	/// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).666	pub fn sponsored_data_size(&self) -> u32 {667		self.sponsored_data_size668			.unwrap_or(CUSTOM_DATA_LIMIT)669			.min(CUSTOM_DATA_LIMIT)670	}671672	/// Get effective value for [`token_limit`](self.token_limit).673	pub fn token_limit(&self) -> u32 {674		self.token_limit675			.unwrap_or(COLLECTION_TOKEN_LIMIT)676			.min(COLLECTION_TOKEN_LIMIT)677	}678679	// TODO: may be replace u32 to mode?680	/// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).681	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {682		self.sponsor_transfer_timeout683			.unwrap_or(default)684			.min(MAX_SPONSOR_TIMEOUT)685	}686687	/// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).688	pub fn sponsor_approve_timeout(&self) -> u32 {689		self.sponsor_approve_timeout690			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)691			.min(MAX_SPONSOR_TIMEOUT)692	}693694	/// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).695	pub fn owner_can_transfer(&self) -> bool {696		self.owner_can_transfer.unwrap_or(false)697	}698699	/// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).700	pub fn owner_can_transfer_instaled(&self) -> bool {701		self.owner_can_transfer.is_some()702	}703704	/// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).705	pub fn owner_can_destroy(&self) -> bool {706		self.owner_can_destroy.unwrap_or(true)707	}708709	/// Get effective value for [`transfers_enabled`](self.transfers_enabled).710	pub fn transfers_enabled(&self) -> bool {711		self.transfers_enabled.unwrap_or(true)712	}713714	/// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).715	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {716		match self717			.sponsored_data_rate_limit718			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)719		{720			SponsoringRateLimit::SponsoringDisabled => None,721			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),722		}723	}724}725726/// Permissions on certain operations within a collection.727///728/// Some fields are wrapped in [`Option`], where `None` means chain default.729///730/// Update with `pallet_common::Pallet::clamp_permissions`.731#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]732#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]733// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.734// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.735pub struct CollectionPermissions {736	/// Access mode.737	///738	/// * Default - [`AccessMode::Normal`].739	pub access: Option<AccessMode>,740741	/// Minting allowance.742	///743	/// * Default - **false**.744	pub mint_mode: Option<bool>,745746	/// Permissions for nesting.747	///748	/// * Default749	///   - `token_owner` - **false**750	///   - `collection_admin` - **false**751	///   - `restricted` - **None**752	pub nesting: Option<NestingPermissions>,753}754755impl CollectionPermissions {756	/// Get effective value for [`access`](self.access).757	pub fn access(&self) -> AccessMode {758		self.access.unwrap_or(AccessMode::Normal)759	}760761	/// Get effective value for [`mint_mode`](self.mint_mode).762	pub fn mint_mode(&self) -> bool {763		self.mint_mode.unwrap_or(false)764	}765766	/// Get effective value for [`nesting`](self.nesting).767	pub fn nesting(&self) -> &NestingPermissions {768		static DEFAULT: NestingPermissions = NestingPermissions {769			token_owner: false,770			collection_admin: false,771			restricted: None,772			#[cfg(feature = "runtime-benchmarks")]773			permissive: false,774		};775		self.nesting.as_ref().unwrap_or(&DEFAULT)776	}777}778779/// Inner set for collections allowed to nest.780type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;781782/// Wraper for collections set allowing nest.783#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]784#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]785#[derivative(Debug)]786pub struct OwnerRestrictedSet(787	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]788	#[derivative(Debug(format_with = "bounded::set_debug"))]789	pub OwnerRestrictedSetInner,790);791792impl OwnerRestrictedSet {793	/// Create new set.794	pub fn new() -> Self {795		Self(Default::default())796	}797}798impl core::ops::Deref for OwnerRestrictedSet {799	type Target = OwnerRestrictedSetInner;800	fn deref(&self) -> &Self::Target {801		&self.0802	}803}804impl core::ops::DerefMut for OwnerRestrictedSet {805	fn deref_mut(&mut self) -> &mut Self::Target {806		&mut self.0807	}808}809810/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.811#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]812#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]813#[derivative(Debug)]814pub struct NestingPermissions {815	/// Owner of token can nest tokens under it.816	pub token_owner: bool,817	/// Admin of token collection can nest tokens under token.818	pub collection_admin: bool,819	/// If set - only tokens from specified collections can be nested.820	pub restricted: Option<OwnerRestrictedSet>,821822	#[cfg(feature = "runtime-benchmarks")]823	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.824	pub permissive: bool,825}826827/// Enum denominating how often can sponsoring occur if it is enabled.828///829/// Used for [`collection limits`](CollectionLimits).830#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]831#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]832pub enum SponsoringRateLimit {833	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions834	SponsoringDisabled,835	/// Once per how many blocks can sponsorship of a transaction type occur836	Blocks(u32),837}838839/// Data used to describe an NFT at creation.840#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]841#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]842#[derivative(Debug)]843pub struct CreateNftData {844	/// Key-value pairs used to describe the token as metadata845	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]846	#[derivative(Debug(format_with = "bounded::vec_debug"))]847	/// Properties that wil be assignet to created item.848	pub properties: CollectionPropertiesVec,849}850851/// Data used to describe a Fungible token at creation.852#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]853#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]854pub struct CreateFungibleData {855	/// Number of fungible coins minted856	pub value: u128,857}858859/// Data used to describe a Refungible token at creation.860#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]861#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]862#[derivative(Debug)]863pub struct CreateReFungibleData {864	/// Number of pieces the RFT is split into865	pub pieces: u128,866867	/// Key-value pairs used to describe the token as metadata868	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]869	#[derivative(Debug(format_with = "bounded::vec_debug"))]870	pub properties: CollectionPropertiesVec,871}872873// TODO: remove this.874#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]875#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]876pub enum MetaUpdatePermission {877	ItemOwner,878	Admin,879	None,880}881882/// Enum holding data used for creation of all three item types.883/// Unified data for create item.884#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]885#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]886pub enum CreateItemData {887	/// Data for create NFT.888	NFT(CreateNftData),889	/// Data for create Fungible item.890	Fungible(CreateFungibleData),891	/// Data for create ReFungible item.892	ReFungible(CreateReFungibleData),893}894895/// Extended data for create NFT.896#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]897#[derivative(Debug)]898pub struct CreateNftExData<CrossAccountId> {899	/// Properties that wil be assignet to created item.900	#[derivative(Debug(format_with = "bounded::vec_debug"))]901	pub properties: CollectionPropertiesVec,902903	/// Owner of creating item.904	pub owner: CrossAccountId,905}906907/// Extended data for create ReFungible item.908#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]909#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]910pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {911	#[derivative(Debug(format_with = "bounded::map_debug"))]912	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,913	#[derivative(Debug(format_with = "bounded::vec_debug"))]914	pub properties: CollectionPropertiesVec,915}916917/// Extended data for create ReFungible item.918#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]919#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]920pub struct CreateRefungibleExSingleOwner<CrossAccountId> {921	pub user: CrossAccountId,922	pub pieces: u128,923	#[derivative(Debug(format_with = "bounded::vec_debug"))]924	pub properties: CollectionPropertiesVec,925}926927/// Unified extended data for creating item.928#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]929#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]930pub enum CreateItemExData<CrossAccountId> {931	/// Extended data for create NFT.932	NFT(933		#[derivative(Debug(format_with = "bounded::vec_debug"))]934		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,935	),936937	/// Extended data for create Fungible item.938	Fungible(939		#[derivative(Debug(format_with = "bounded::map_debug"))]940		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,941	),942943	/// Extended data for create ReFungible item in case of944	/// many tokens, each may have only one owner945	RefungibleMultipleItems(946		#[derivative(Debug(format_with = "bounded::vec_debug"))]947		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,948	),949950	/// Extended data for create ReFungible item in case of951	/// single token, which may have many owners952	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),953}954955impl From<CreateNftData> for CreateItemData {956	fn from(item: CreateNftData) -> Self {957		CreateItemData::NFT(item)958	}959}960961impl From<CreateReFungibleData> for CreateItemData {962	fn from(item: CreateReFungibleData) -> Self {963		CreateItemData::ReFungible(item)964	}965}966967impl From<CreateFungibleData> for CreateItemData {968	fn from(item: CreateFungibleData) -> Self {969		CreateItemData::Fungible(item)970	}971}972973/// Token's address, dictated by its collection and token IDs.974#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]975#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]976// todo possibly rename to be used generally as an address pair977pub struct TokenChild {978	/// Token id.979	pub token: TokenId,980981	/// Collection id.982	pub collection: CollectionId,983}984985/// Collection statistics.986#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]987#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]988pub struct CollectionStats {989	/// Number of created items.990	pub created: u32,991992	/// Number of burned items.993	pub destroyed: u32,994995	/// Number of current items.996	pub alive: u32,997}998999/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1000#[derive(Encode, Decode, Clone, Debug)]1001#[cfg_attr(feature = "std", derive(PartialEq))]1002pub struct PhantomType<T>(core::marker::PhantomData<T>);10031004impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1005	type Identity = PhantomType<T>;10061007	fn type_info() -> scale_info::Type {1008		use scale_info::{1009			Type, Path,1010			build::{FieldsBuilder, UnnamedFields},1011			form::MetaForm,1012			type_params,1013		};1014		Type::builder()1015			.path(Path::new("up_data_structs", "PhantomType"))1016			.type_params(type_params!(T))1017			.composite(1018				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1019			)1020	}1021}1022impl<T> MaxEncodedLen for PhantomType<T> {1023	fn max_encoded_len() -> usize {1024		01025	}1026}10271028/// Bounded vector of bytes.1029pub type BoundedBytes<S> = BoundedVec<u8, S>;10301031/// Extra properties for external collections.1032pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;10331034/// Property key.1035pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;10361037/// Property value.1038pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;10391040/// Property permission.1041#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1042#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1043pub struct PropertyPermission {1044	/// Permission to change the property and property permission.1045	///1046	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1047	pub mutable: bool,10481049	/// Change permission for the collection administrator.1050	pub collection_admin: bool,10511052	/// Permission to change the property for the owner of the token.1053	pub token_owner: bool,1054}10551056impl PropertyPermission {1057	/// Creates mutable property permission but changes restricted for collection admin and token owner.1058	pub fn none() -> Self {1059		Self {1060			mutable: true,1061			collection_admin: false,1062			token_owner: false,1063		}1064	}1065}10661067/// Property is simpl key-value record.1068#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1069#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1070pub struct Property {1071	/// Property key.1072	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1073	pub key: PropertyKey,10741075	/// Property value.1076	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1077	pub value: PropertyValue,1078}10791080impl Into<(PropertyKey, PropertyValue)> for Property {1081	fn into(self) -> (PropertyKey, PropertyValue) {1082		(self.key, self.value)1083	}1084}10851086/// Record for proprty key permission.1087#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1088#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1089pub struct PropertyKeyPermission {1090	/// Key.1091	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1092	pub key: PropertyKey,10931094	/// Permission.1095	pub permission: PropertyPermission,1096}10971098impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1099	fn into(self) -> (PropertyKey, PropertyPermission) {1100		(self.key, self.permission)1101	}1102}11031104/// Errors for properties actions.1105#[derive(Debug)]1106pub enum PropertiesError {1107	/// The space allocated for properties has run out.1108	///1109	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1110	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1111	NoSpaceForProperty,11121113	/// The property limit has been reached.1114	///1115	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1116	PropertyLimitReached,11171118	/// Property key contains not allowed character.1119	InvalidCharacterInPropertyKey,11201121	/// Property key length is too long.1122	///1123	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1124	PropertyKeyIsTooLong,11251126	/// Property key is empty.1127	EmptyPropertyKey,1128}11291130/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1131#[derive(Debug)]1132pub enum TokenOwnerError {1133	NotFound,1134	MultipleOwners,1135}11361137/// Marker for scope of property.1138///1139/// Scoped property can't be changed by user. Used for external collections.1140#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1141pub enum PropertyScope {1142	None,1143	Rmrk,1144}11451146impl PropertyScope {1147	pub fn prefix(&self) -> &'static [u8] {1148		match self {1149			Self::None => b"",1150			Self::Rmrk => b"rmrk:",1151		}1152	}1153	/// Apply scope to property key.1154	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1155		let prefix = self.prefix();1156		if prefix == b"" {1157			return Ok(key);1158		}1159		[prefix, key.as_slice()]1160			.concat()1161			.try_into()1162			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1163	}1164}11651166/// Trait for operate with properties.1167pub trait TrySetProperty: Sized {1168	type Value;11691170	/// Try to set property with scope.1171	fn try_scoped_set(1172		&mut self,1173		scope: PropertyScope,1174		key: PropertyKey,1175		value: Self::Value,1176	) -> Result<Option<Self::Value>, PropertiesError>;11771178	/// Try to set property with scope from iterator.1179	fn try_scoped_set_from_iter<I, KV>(1180		&mut self,1181		scope: PropertyScope,1182		iter: I,1183	) -> Result<(), PropertiesError>1184	where1185		I: Iterator<Item = KV>,1186		KV: Into<(PropertyKey, Self::Value)>,1187	{1188		for kv in iter {1189			let (key, value) = kv.into();1190			self.try_scoped_set(scope, key, value)?;1191		}11921193		Ok(())1194	}11951196	/// Try to set property.1197	fn try_set(1198		&mut self,1199		key: PropertyKey,1200		value: Self::Value,1201	) -> Result<Option<Self::Value>, PropertiesError> {1202		self.try_scoped_set(PropertyScope::None, key, value)1203	}12041205	/// Try to set property from iterator.1206	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1207	where1208		I: Iterator<Item = KV>,1209		KV: Into<(PropertyKey, Self::Value)>,1210	{1211		self.try_scoped_set_from_iter(PropertyScope::None, iter)1212	}1213}12141215/// Wrapped map for storing properties.1216#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1217#[derivative(Default(bound = ""))]1218pub struct PropertiesMap<Value>(1219	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1220);12211222impl<Value> PropertiesMap<Value> {1223	/// Create new property map.1224	pub fn new() -> Self {1225		Self(BoundedBTreeMap::new())1226	}12271228	/// Remove property from map.1229	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1230		Self::check_property_key(key)?;12311232		Ok(self.0.remove(key))1233	}12341235	/// Get property with appropriate key from map.1236	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1237		self.0.get(key)1238	}12391240	/// Check if map contains key.1241	pub fn contains_key(&self, key: &PropertyKey) -> bool {1242		self.0.contains_key(key)1243	}12441245	/// Check if map contains key with key validation.1246	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1247		if key.is_empty() {1248			return Err(PropertiesError::EmptyPropertyKey);1249		}12501251		for byte in key.as_slice().iter() {1252			let byte = *byte;12531254			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1255				return Err(PropertiesError::InvalidCharacterInPropertyKey);1256			}1257		}12581259		Ok(())1260	}12611262	pub fn values(&self) -> impl Iterator<Item = &Value> {1263		self.0.values()1264	}12651266	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1267		self.0.iter()1268	}1269}12701271impl<Value> IntoIterator for PropertiesMap<Value> {1272	type Item = (PropertyKey, Value);1273	type IntoIter = <1274		BoundedBTreeMap<1275			PropertyKey,1276			Value,1277			ConstU32<MAX_PROPERTIES_PER_ITEM>1278		> as IntoIterator1279	>::IntoIter;12801281	fn into_iter(self) -> Self::IntoIter {1282		self.0.into_iter()1283	}1284}12851286impl<Value> TrySetProperty for PropertiesMap<Value> {1287	type Value = Value;12881289	fn try_scoped_set(1290		&mut self,1291		scope: PropertyScope,1292		key: PropertyKey,1293		value: Self::Value,1294	) -> Result<Option<Self::Value>, PropertiesError> {1295		Self::check_property_key(&key)?;12961297		let key = scope.apply(key)?;1298		self.01299			.try_insert(key, value)1300			.map_err(|_| PropertiesError::PropertyLimitReached)1301	}1302}13031304/// Alias for property permissions map.1305pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;13061307fn slice_size(data: &[u8]) -> u32 {1308	scoped_slice_size(PropertyScope::None, data)1309}1310fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1311	use codec::Compact;1312	let prefix = scope.prefix();1313	<Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321314		+ data.len() as u321315		+ prefix.len() as u321316}13171318/// Wrapper for properties map with consumed space control.1319#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1320pub struct Properties<const S: u32> {1321	map: PropertiesMap<PropertyValue>,1322	consumed_space: u32,1323	// May be not zero, previously served as a current S generic1324	_reserved: u32,1325}13261327impl<const S: u32> MaxEncodedLen for Properties<S> {1328	fn max_encoded_len() -> usize {1329		// len of map + len of consumed_space + len of space_limit1330		u32::max_encoded_len() * 3 + S as usize1331	}1332}13331334impl<const S: u32> Default for Properties<S> {1335	fn default() -> Self {1336		Self::new()1337	}1338}13391340impl<const S: u32> Properties<S> {1341	/// Create new properies container.1342	pub fn new() -> Self {1343		Self {1344			map: PropertiesMap::new(),1345			consumed_space: 0,1346			_reserved: 0,1347		}1348	}13491350	/// Remove propery with appropiate key.1351	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1352		let value = self.map.remove(key)?;13531354		if let Some(ref value) = value {1355			let kv_len = slice_size(key) + slice_size(value);1356			self.consumed_space = self.consumed_space.saturating_sub(kv_len);1357		}13581359		Ok(value)1360	}13611362	/// Get property with appropriate key.1363	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1364		self.map.get(key)1365	}13661367	/// Recomputes the consumed space for the current properties state.1368	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1369	pub fn recompute_consumed_space(&mut self) {1370		self.consumed_space = self1371			.map1372			.iter()1373			.map(|(key, value)| slice_size(key) + slice_size(value))1374			.sum();1375	}1376}13771378impl<const S: u32> IntoIterator for Properties<S> {1379	type Item = (PropertyKey, PropertyValue);1380	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;13811382	fn into_iter(self) -> Self::IntoIter {1383		self.map.into_iter()1384	}1385}13861387impl<const S: u32> TrySetProperty for Properties<S> {1388	type Value = PropertyValue;13891390	fn try_scoped_set(1391		&mut self,1392		scope: PropertyScope,1393		key: PropertyKey,1394		value: Self::Value,1395	) -> Result<Option<Self::Value>, PropertiesError> {1396		let key_size = scoped_slice_size(scope, &key);1397		let value_size = slice_size(&value) as u32;13981399		if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1400		{1401			return Err(PropertiesError::NoSpaceForProperty);1402		}14031404		let old_value = self.map.try_scoped_set(scope, key, value)?;14051406		if let Some(old_value) = old_value.as_ref() {1407			let old_value_size = slice_size(&old_value);1408			self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1409		} else {1410			self.consumed_space += key_size + value_size;1411		}14121413		Ok(old_value)1414	}1415}14161417pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1418pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;14191420#[cfg(test)]1421mod tests {1422	use super::*;1423	use codec::IoReader;14241425	#[test]1426	fn rpc_collection_supports_decoding_old_versions() {1427		let encoded_rpc_collection: [u8; 1013] = [1428			0, 1, 250, 241, 137, 120, 188, 29, 94, 210, 193, 237, 186, 22, 203, 241, 52, 248, 167,1429			235, 241, 211, 236, 28, 138, 156, 59, 160, 156, 105, 39, 247, 207, 101, 0, 0, 48, 65,1430			0, 73, 0, 32, 0, 67, 0, 114, 0, 101, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 115, 0,1431			252, 65, 0, 32, 0, 112, 0, 105, 0, 101, 0, 99, 0, 101, 0, 32, 0, 111, 0, 102, 0, 32, 0,1432			97, 0, 32, 0, 109, 0, 97, 0, 99, 0, 104, 0, 105, 0, 110, 0, 101, 0, 32, 0, 109, 0, 105,1433			0, 110, 0, 100, 0, 46, 0, 32, 0, 69, 0, 118, 0, 101, 0, 114, 0, 121, 0, 32, 0, 78, 0,1434			70, 0, 84, 0, 32, 0, 105, 0, 115, 0, 32, 0, 109, 0, 97, 0, 100, 0, 101, 0, 32, 0, 101,1435			0, 120, 0, 99, 0, 108, 0, 117, 0, 115, 0, 105, 0, 118, 0, 101, 0, 108, 0, 121, 0, 32,1436			0, 98, 0, 121, 0, 32, 0, 65, 0, 73, 0, 46, 0, 12, 65, 73, 67, 0, 0, 1, 0, 0, 0, 0, 0,1437			0, 0, 0, 0, 0, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111,1438			118, 101, 114, 34, 58, 34, 81, 109, 98, 52, 104, 122, 76, 101, 51, 49, 102, 98, 71, 74,1439			77, 89, 68, 82, 88, 84, 115, 107, 56, 49, 76, 103, 76, 97, 88, 76, 69, 112, 121, 97,1440			122, 102, 66, 85, 103, 111, 110, 118, 49, 118, 84, 85, 34, 125, 125, 11, 123, 34, 110,1441			101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77, 101,1442			116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58, 123,1443			34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115, 34,1444			58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34, 58,1445			49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34,1446			44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44, 34,1447			67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117, 108,1448			101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112,1449			101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 73, 110, 116, 101, 110, 115,1450			105, 111, 110, 115, 34, 58, 123, 34, 105, 100, 34, 58, 51, 44, 34, 114, 117, 108, 101,1451			34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34,1452			58, 34, 73, 110, 116, 101, 110, 115, 105, 111, 110, 115, 34, 125, 44, 34, 77, 111, 111,1453			100, 34, 58, 123, 34, 105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34,1454			114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 77,1455			111, 111, 100, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111,1456			112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1457			123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 67, 111, 108, 111, 114, 101, 100, 92, 34,1458			125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92,1459			34, 58, 92, 34, 66, 108, 97, 99, 107, 38, 87, 104, 105, 116, 101, 92, 34, 125, 34, 125,1460			44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34,1461			58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 73, 110,1462			116, 101, 110, 115, 105, 111, 110, 115, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110,1463			115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110,1464			92, 34, 58, 92, 34, 101, 118, 105, 108, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1465			100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 103, 111, 111, 100, 92,1466			34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1467			92, 34, 58, 92, 34, 110, 101, 117, 116, 114, 97, 108, 92, 34, 125, 34, 125, 44, 34,1468			118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48,1469			44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51,1470			34, 58, 50, 125, 125, 44, 34, 77, 111, 111, 100, 34, 58, 123, 34, 111, 112, 116, 105,1471			111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34,1472			101, 110, 92, 34, 58, 92, 34, 65, 98, 115, 116, 114, 97, 99, 116, 92, 34, 125, 34, 44,1473			34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1474			85, 110, 99, 97, 110, 110, 101, 121, 32, 118, 97, 108, 108, 101, 121, 92, 34, 125, 34,1475			44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1476			34, 83, 117, 114, 114, 101, 97, 108, 105, 115, 116, 92, 34, 125, 34, 125, 44, 34, 118,1477			97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44,1478			34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34,1479			58, 50, 125, 125, 125, 125, 125, 125, 0,1480		];1481		let mut bytes = IoReader(encoded_rpc_collection.as_slice());1482		RpcCollectionVersion1::<[u8; 34]>::decode(&mut bytes).unwrap();1483	}14841485	#[test]1486	fn rpc_collection_supports_decoding_new_versions() {1487		let encoded_rpc_collection: [u8; 1576] = [1488			0, 1, 238, 236, 179, 149, 150, 47, 71, 194, 69, 174, 250, 116, 251, 148, 90, 15, 56,1489			220, 91, 79, 49, 79, 45, 197, 171, 98, 14, 171, 80, 23, 58, 92, 0, 96, 77, 0, 105, 0,1490			110, 0, 116, 0, 70, 0, 101, 0, 115, 0, 116, 0, 32, 0, 83, 0, 121, 0, 109, 0, 109, 0,1491			101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 66, 0, 114, 0, 101, 0, 97, 0, 99, 0, 104, 0,1492			113, 3, 83, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 104, 0,1493			97, 0, 115, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 116, 0, 104, 0, 105, 0, 110, 0,1494			103, 0, 32, 0, 105, 0, 110, 0, 116, 0, 111, 0, 120, 0, 105, 0, 99, 0, 97, 0, 116, 0,1495			105, 0, 110, 0, 103, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 100, 0, 114, 0,1496			97, 0, 119, 0, 115, 0, 32, 0, 121, 0, 111, 0, 117, 0, 32, 0, 105, 0, 110, 0, 46, 0, 10,1497			0, 73, 0, 110, 0, 115, 0, 112, 0, 105, 0, 114, 0, 101, 0, 100, 0, 32, 0, 98, 0, 121, 0,1498			32, 0, 116, 0, 104, 0, 101, 0, 32, 0, 112, 0, 101, 0, 114, 0, 102, 0, 101, 0, 99, 0,1499			116, 0, 105, 0, 111, 0, 110, 0, 32, 0, 111, 0, 102, 0, 32, 0, 116, 0, 104, 0, 101, 0,1500			32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 44, 0, 32, 0,1501			73, 0, 32, 0, 104, 0, 97, 0, 118, 0, 101, 0, 32, 0, 99, 0, 114, 0, 101, 0, 97, 0, 116,1502			0, 101, 0, 100, 0, 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 105,1503			0, 99, 0, 97, 0, 108, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103, 0, 101, 0, 115, 0, 32, 0,1504			111, 0, 102, 0, 32, 0, 115, 0, 101, 0, 118, 0, 101, 0, 114, 0, 97, 0, 108, 0, 32, 0,1505			118, 0, 101, 0, 114, 0, 116, 0, 105, 0, 99, 0, 101, 0, 115, 0, 44, 0, 32, 0, 98, 0,1506			117, 0, 116, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 32, 0, 115, 0, 121, 0, 109, 0,1507			109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 98, 0, 114, 0, 101, 0, 97, 0, 99, 0,1508			104, 0, 101, 0, 115, 0, 32, 0, 97, 0, 110, 0, 100, 0, 32, 0, 99, 0, 111, 0, 108, 0,1509			111, 0, 114, 0, 115, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 109, 0, 97, 0,1510			107, 0, 101, 0, 32, 0, 101, 0, 97, 0, 99, 0, 104, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103,1511			0, 101, 0, 32, 0, 85, 0, 78, 0, 73, 0, 81, 0, 85, 0, 69, 0, 46, 0, 12, 83, 121, 66, 0,1512			0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 4, 56, 95, 111, 108, 100, 95, 99,1513			111, 110, 115, 116, 68, 97, 116, 97, 0, 1, 0, 12, 92, 95, 111, 108, 100, 95, 99, 111,1514			110, 115, 116, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101, 109, 97, 97, 13, 123,1515			34, 110, 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77,1516			101, 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58,1517			123, 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115,1518			34, 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34,1519			58, 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100,1520			34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44,1521			34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117,1522			108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121,1523			112, 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 83, 121, 109, 109, 101,1524			116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 105, 100, 34, 58, 51,1525			44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44,1526			34, 116, 121, 112, 101, 34, 58, 34, 83, 121, 109, 109, 101, 116, 114, 121, 32, 66, 114,1527			101, 97, 99, 104, 34, 125, 44, 34, 86, 101, 114, 116, 105, 99, 101, 34, 58, 123, 34,1528			105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105,1529			114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 86, 101, 114, 116, 105, 99,1530			101, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111, 112, 116,1531			105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92,1532			34, 101, 110, 92, 34, 58, 92, 34, 49, 32, 32, 32, 92, 34, 125, 34, 44, 34, 102, 105,1533			101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 32, 92,1534			34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1535			92, 34, 58, 92, 34, 51, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34,1536			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100,1537			50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 125, 125, 44, 34, 83,1538			121, 109, 109, 101, 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 111,1539			112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1540			123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 92, 34, 125, 34, 44, 34, 102, 105, 101,1541			108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 92, 34, 125,1542			34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100,1543			49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 86,1544			101, 114, 116, 105, 99, 101, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110, 115, 34,1545			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34,1546			58, 92, 34, 54, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123,1547			92, 34, 101, 110, 92, 34, 58, 92, 34, 55, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1548			100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 56, 92, 34, 125, 34,1549			44, 34, 102, 105, 101, 108, 100, 52, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1550			34, 57, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 34, 123, 92, 34,1551			101, 110, 92, 34, 58, 92, 34, 49, 48, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100,1552			54, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 49, 92, 34, 125, 34, 44,1553			34, 102, 105, 101, 108, 100, 55, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1554			49, 50, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34,1555			102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58,1556			49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 44, 34, 102, 105, 101, 108, 100,1557			52, 34, 58, 51, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 52, 44, 34, 102, 105, 101,1558			108, 100, 54, 34, 58, 53, 44, 34, 102, 105, 101, 108, 100, 55, 34, 58, 54, 125, 125,1559			125, 125, 125, 125, 72, 95, 111, 108, 100, 95, 115, 99, 104, 101, 109, 97, 86, 101,1560			114, 115, 105, 111, 110, 24, 85, 110, 105, 113, 117, 101, 104, 95, 111, 108, 100, 95,1561			118, 97, 114, 105, 97, 98, 108, 101, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101,1562			109, 97, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111, 118,1563			101, 114, 34, 58, 34, 81, 109, 82, 67, 77, 84, 109, 57, 118, 81, 107, 76, 89, 86, 65,1564			54, 54, 87, 80, 49, 75, 72, 57, 55, 106, 84, 76, 76, 115, 56, 74, 78, 86, 65, 114, 80,1565			66, 52, 56, 98, 106, 87, 84, 75, 74, 110, 34, 125, 0, 0, 0,1566		];1567		let mut bytes = IoReader(encoded_rpc_collection.as_slice());1568		RpcCollection::<[u8; 34]>::decode(&mut bytes).unwrap();1569	}1570}