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

difftreelog

Merge pull request #910 from UniqueNetwork/fix/versioning-of-rpc-collection

Yaroslav Bolyukin2023-04-09parents: #f7fea33 #13f1ef4.patch.diff
in: master
Fix versioning of RpcCollection

3 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -353,7 +353,7 @@
 			};
 
 			let result = $(if _api_version < $ver {
-				api.$changed_method_name(at, $($changed_name),*).map(|r| r.map($fixer))
+				api.$changed_method_name(at, $($changed_name),*).map(|r| r.and_then($fixer))
 			} else)*
 			{ api.$method_name(at, $($((|$map_arg: $ty| $map))? ($name)),*) };
 
@@ -440,7 +440,7 @@
 			#[map(|keys| string_keys_to_bytes_keys(keys))]
 			keys: Option<Vec<String>>,
 		) -> TokenData<CrossAccountId>, unique_api;
-		changed_in 3, token_data_before_version_3(collection, token_id, string_keys_to_bytes_keys(keys)) => |value| value.into()
+		changed_in 3, token_data_before_version_3(collection, token_id, string_keys_to_bytes_keys(keys)) => |value| Ok(value.into())
 	);
 
 	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);
@@ -449,7 +449,22 @@
 	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);
 	pass_method!(
 		collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api;
-		changed_in 3, collection_by_id_before_version_3(collection) => |value| value.map(|coll| coll.into())
+		changed_in 3, collection_by_id_before_version_3(collection) => |value| {
+			use codec::IoReader;
+			use up_data_structs::RpcCollectionVersion1;
+			use up_data_structs::CollectionVersion1;
+			use sp_runtime::DispatchError;
+
+			if let Some(bytes) = value {
+				let mut reader = IoReader(bytes.as_slice());
+				Ok(Some(RpcCollection::<AccountId>::decode(&mut reader)
+				.or_else(|_| RpcCollectionVersion1::<AccountId>::decode(&mut reader).map(|col| col.into()))
+				.or_else(|_| CollectionVersion1::<AccountId>::decode(&mut reader).map(|col| col.into()))
+				.map_err(|_| DispatchError::Other("API Error: UniqueApi_collection_by_id"))?))
+			} else {
+				Ok(None)
+			}
+		}
 	);
 	pass_method!(collection_stats() -> CollectionStats, unique_api);
 	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
before · primitives/data-structs/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # 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}481482/// Data used for create collection.483///484/// All fields are wrapped in [`Option`], where `None` means chain default.485#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]486#[derivative(Debug, Default(bound = ""))]487pub struct CreateCollectionData<AccountId> {488	/// Collection mode.489	#[derivative(Default(value = "CollectionMode::NFT"))]490	pub mode: CollectionMode,491492	/// Access mode.493	pub access: Option<AccessMode>,494495	/// Collection name.496	pub name: CollectionName,497498	/// Collection description.499	pub description: CollectionDescription,500501	/// Token prefix.502	pub token_prefix: CollectionTokenPrefix,503504	/// Pending collection sponsor.505	pub pending_sponsor: Option<AccountId>,506507	/// Collection limits.508	pub limits: Option<CollectionLimits>,509510	/// Collection permissions.511	pub permissions: Option<CollectionPermissions>,512513	/// Token property permissions.514	pub token_property_permissions: CollectionPropertiesPermissionsVec,515516	/// Collection properties.517	pub properties: CollectionPropertiesVec,518}519520/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].521// TODO: maybe rename to PropertiesPermissionsVec522pub type CollectionPropertiesPermissionsVec =523	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;524525/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].526pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;527528/// Limits and restrictions of a collection.529///530/// All fields are wrapped in [`Option`], where `None` means chain default.531///532/// Update with `pallet_common::Pallet::clamp_limits`.533// IMPORTANT: When adding/removing fields from this struct - don't forget to also534#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]535#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]536// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.537// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.538// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.539pub struct CollectionLimits {540	/// How many tokens can a user have on one account.541	/// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].542	/// * Limit - [`MAX_TOKEN_OWNERSHIP`].543	pub account_token_ownership_limit: Option<u32>,544545	/// How many bytes of data are available for sponsorship.546	/// * Default - [`CUSTOM_DATA_LIMIT`].547	/// * Limit - [`CUSTOM_DATA_LIMIT`].548	pub sponsored_data_size: Option<u32>,549550	// FIXME should we delete this or repurpose it?551	/// Times in how many blocks we sponsor data.552	///553	/// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.554	///555	/// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).556	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].557	///558	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]559	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,560	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]561562	/// How many tokens can be mined into this collection.563	///564	/// * Default - [`COLLECTION_TOKEN_LIMIT`].565	/// * Limit - [`COLLECTION_TOKEN_LIMIT`].566	pub token_limit: Option<u32>,567568	/// Timeouts for transfer sponsoring.569	///570	/// * Default571	///   - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]572	///   - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]573	///   - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]574	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].575	pub sponsor_transfer_timeout: Option<u32>,576577	/// Timeout for sponsoring an approval in passed blocks.578	///579	/// * Default - [`SPONSOR_APPROVE_TIMEOUT`].580	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].581	pub sponsor_approve_timeout: Option<u32>,582583	/// Whether the collection owner of the collection can send tokens (which belong to other users).584	///585	/// * Default - **false**.586	pub owner_can_transfer: Option<bool>,587588	/// Can the collection owner burn other people's tokens.589	///590	/// * Default - **true**.591	pub owner_can_destroy: Option<bool>,592593	/// Is it possible to send tokens from this collection between users.594	///595	/// * Default - **true**.596	pub transfers_enabled: Option<bool>,597}598599impl CollectionLimits {600	pub fn with_default_limits(collection_type: CollectionMode) -> Self {601		CollectionLimits {602			account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),603			sponsored_data_size: Some(CUSTOM_DATA_LIMIT),604			sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),605			token_limit: Some(COLLECTION_TOKEN_LIMIT),606			sponsor_transfer_timeout: match collection_type {607				CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),608				CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),609				CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),610			},611			sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),612			owner_can_transfer: Some(false),613			owner_can_destroy: Some(true),614			transfers_enabled: Some(true),615		}616	}617618	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).619	pub fn account_token_ownership_limit(&self) -> u32 {620		self.account_token_ownership_limit621			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)622			.min(MAX_TOKEN_OWNERSHIP)623	}624625	/// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).626	pub fn sponsored_data_size(&self) -> u32 {627		self.sponsored_data_size628			.unwrap_or(CUSTOM_DATA_LIMIT)629			.min(CUSTOM_DATA_LIMIT)630	}631632	/// Get effective value for [`token_limit`](self.token_limit).633	pub fn token_limit(&self) -> u32 {634		self.token_limit635			.unwrap_or(COLLECTION_TOKEN_LIMIT)636			.min(COLLECTION_TOKEN_LIMIT)637	}638639	// TODO: may be replace u32 to mode?640	/// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).641	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {642		self.sponsor_transfer_timeout643			.unwrap_or(default)644			.min(MAX_SPONSOR_TIMEOUT)645	}646647	/// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).648	pub fn sponsor_approve_timeout(&self) -> u32 {649		self.sponsor_approve_timeout650			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)651			.min(MAX_SPONSOR_TIMEOUT)652	}653654	/// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).655	pub fn owner_can_transfer(&self) -> bool {656		self.owner_can_transfer.unwrap_or(false)657	}658659	/// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).660	pub fn owner_can_transfer_instaled(&self) -> bool {661		self.owner_can_transfer.is_some()662	}663664	/// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).665	pub fn owner_can_destroy(&self) -> bool {666		self.owner_can_destroy.unwrap_or(true)667	}668669	/// Get effective value for [`transfers_enabled`](self.transfers_enabled).670	pub fn transfers_enabled(&self) -> bool {671		self.transfers_enabled.unwrap_or(true)672	}673674	/// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).675	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {676		match self677			.sponsored_data_rate_limit678			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)679		{680			SponsoringRateLimit::SponsoringDisabled => None,681			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),682		}683	}684}685686/// Permissions on certain operations within a collection.687///688/// Some fields are wrapped in [`Option`], where `None` means chain default.689///690/// Update with `pallet_common::Pallet::clamp_permissions`.691#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]692#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]693// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.694// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.695pub struct CollectionPermissions {696	/// Access mode.697	///698	/// * Default - [`AccessMode::Normal`].699	pub access: Option<AccessMode>,700701	/// Minting allowance.702	///703	/// * Default - **false**.704	pub mint_mode: Option<bool>,705706	/// Permissions for nesting.707	///708	/// * Default709	///   - `token_owner` - **false**710	///   - `collection_admin` - **false**711	///   - `restricted` - **None**712	pub nesting: Option<NestingPermissions>,713}714715impl CollectionPermissions {716	/// Get effective value for [`access`](self.access).717	pub fn access(&self) -> AccessMode {718		self.access.unwrap_or(AccessMode::Normal)719	}720721	/// Get effective value for [`mint_mode`](self.mint_mode).722	pub fn mint_mode(&self) -> bool {723		self.mint_mode.unwrap_or(false)724	}725726	/// Get effective value for [`nesting`](self.nesting).727	pub fn nesting(&self) -> &NestingPermissions {728		static DEFAULT: NestingPermissions = NestingPermissions {729			token_owner: false,730			collection_admin: false,731			restricted: None,732			#[cfg(feature = "runtime-benchmarks")]733			permissive: false,734		};735		self.nesting.as_ref().unwrap_or(&DEFAULT)736	}737}738739/// Inner set for collections allowed to nest.740type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;741742/// Wraper for collections set allowing nest.743#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]744#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]745#[derivative(Debug)]746pub struct OwnerRestrictedSet(747	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]748	#[derivative(Debug(format_with = "bounded::set_debug"))]749	pub OwnerRestrictedSetInner,750);751752impl OwnerRestrictedSet {753	/// Create new set.754	pub fn new() -> Self {755		Self(Default::default())756	}757}758impl core::ops::Deref for OwnerRestrictedSet {759	type Target = OwnerRestrictedSetInner;760	fn deref(&self) -> &Self::Target {761		&self.0762	}763}764impl core::ops::DerefMut for OwnerRestrictedSet {765	fn deref_mut(&mut self) -> &mut Self::Target {766		&mut self.0767	}768}769770/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.771#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]772#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]773#[derivative(Debug)]774pub struct NestingPermissions {775	/// Owner of token can nest tokens under it.776	pub token_owner: bool,777	/// Admin of token collection can nest tokens under token.778	pub collection_admin: bool,779	/// If set - only tokens from specified collections can be nested.780	pub restricted: Option<OwnerRestrictedSet>,781782	#[cfg(feature = "runtime-benchmarks")]783	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.784	pub permissive: bool,785}786787/// Enum denominating how often can sponsoring occur if it is enabled.788///789/// Used for [`collection limits`](CollectionLimits).790#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]791#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]792pub enum SponsoringRateLimit {793	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions794	SponsoringDisabled,795	/// Once per how many blocks can sponsorship of a transaction type occur796	Blocks(u32),797}798799/// Data used to describe an NFT at creation.800#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]801#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]802#[derivative(Debug)]803pub struct CreateNftData {804	/// Key-value pairs used to describe the token as metadata805	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]806	#[derivative(Debug(format_with = "bounded::vec_debug"))]807	/// Properties that wil be assignet to created item.808	pub properties: CollectionPropertiesVec,809}810811/// Data used to describe a Fungible token at creation.812#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]813#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]814pub struct CreateFungibleData {815	/// Number of fungible coins minted816	pub value: u128,817}818819/// Data used to describe a Refungible token at creation.820#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]821#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]822#[derivative(Debug)]823pub struct CreateReFungibleData {824	/// Number of pieces the RFT is split into825	pub pieces: u128,826827	/// Key-value pairs used to describe the token as metadata828	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]829	#[derivative(Debug(format_with = "bounded::vec_debug"))]830	pub properties: CollectionPropertiesVec,831}832833// TODO: remove this.834#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]835#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]836pub enum MetaUpdatePermission {837	ItemOwner,838	Admin,839	None,840}841842/// Enum holding data used for creation of all three item types.843/// Unified data for create item.844#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]845#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]846pub enum CreateItemData {847	/// Data for create NFT.848	NFT(CreateNftData),849	/// Data for create Fungible item.850	Fungible(CreateFungibleData),851	/// Data for create ReFungible item.852	ReFungible(CreateReFungibleData),853}854855/// Extended data for create NFT.856#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]857#[derivative(Debug)]858pub struct CreateNftExData<CrossAccountId> {859	/// Properties that wil be assignet to created item.860	#[derivative(Debug(format_with = "bounded::vec_debug"))]861	pub properties: CollectionPropertiesVec,862863	/// Owner of creating item.864	pub owner: CrossAccountId,865}866867/// Extended data for create ReFungible item.868#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]869#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]870pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {871	#[derivative(Debug(format_with = "bounded::map_debug"))]872	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,873	#[derivative(Debug(format_with = "bounded::vec_debug"))]874	pub properties: CollectionPropertiesVec,875}876877/// Extended data for create ReFungible item.878#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]879#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]880pub struct CreateRefungibleExSingleOwner<CrossAccountId> {881	pub user: CrossAccountId,882	pub pieces: u128,883	#[derivative(Debug(format_with = "bounded::vec_debug"))]884	pub properties: CollectionPropertiesVec,885}886887/// Unified extended data for creating item.888#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]889#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]890pub enum CreateItemExData<CrossAccountId> {891	/// Extended data for create NFT.892	NFT(893		#[derivative(Debug(format_with = "bounded::vec_debug"))]894		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,895	),896897	/// Extended data for create Fungible item.898	Fungible(899		#[derivative(Debug(format_with = "bounded::map_debug"))]900		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,901	),902903	/// Extended data for create ReFungible item in case of904	/// many tokens, each may have only one owner905	RefungibleMultipleItems(906		#[derivative(Debug(format_with = "bounded::vec_debug"))]907		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,908	),909910	/// Extended data for create ReFungible item in case of911	/// single token, which may have many owners912	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),913}914915impl From<CreateNftData> for CreateItemData {916	fn from(item: CreateNftData) -> Self {917		CreateItemData::NFT(item)918	}919}920921impl From<CreateReFungibleData> for CreateItemData {922	fn from(item: CreateReFungibleData) -> Self {923		CreateItemData::ReFungible(item)924	}925}926927impl From<CreateFungibleData> for CreateItemData {928	fn from(item: CreateFungibleData) -> Self {929		CreateItemData::Fungible(item)930	}931}932933/// Token's address, dictated by its collection and token IDs.934#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]935#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]936// todo possibly rename to be used generally as an address pair937pub struct TokenChild {938	/// Token id.939	pub token: TokenId,940941	/// Collection id.942	pub collection: CollectionId,943}944945/// Collection statistics.946#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]947#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]948pub struct CollectionStats {949	/// Number of created items.950	pub created: u32,951952	/// Number of burned items.953	pub destroyed: u32,954955	/// Number of current items.956	pub alive: u32,957}958959/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.960#[derive(Encode, Decode, Clone, Debug)]961#[cfg_attr(feature = "std", derive(PartialEq))]962pub struct PhantomType<T>(core::marker::PhantomData<T>);963964impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {965	type Identity = PhantomType<T>;966967	fn type_info() -> scale_info::Type {968		use scale_info::{969			Type, Path,970			build::{FieldsBuilder, UnnamedFields},971			form::MetaForm,972			type_params,973		};974		Type::builder()975			.path(Path::new("up_data_structs", "PhantomType"))976			.type_params(type_params!(T))977			.composite(978				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),979			)980	}981}982impl<T> MaxEncodedLen for PhantomType<T> {983	fn max_encoded_len() -> usize {984		0985	}986}987988/// Bounded vector of bytes.989pub type BoundedBytes<S> = BoundedVec<u8, S>;990991/// Extra properties for external collections.992pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;993994/// Property key.995pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;996997/// Property value.998pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;9991000/// Property permission.1001#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1002#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1003pub struct PropertyPermission {1004	/// Permission to change the property and property permission.1005	///1006	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1007	pub mutable: bool,10081009	/// Change permission for the collection administrator.1010	pub collection_admin: bool,10111012	/// Permission to change the property for the owner of the token.1013	pub token_owner: bool,1014}10151016impl PropertyPermission {1017	/// Creates mutable property permission but changes restricted for collection admin and token owner.1018	pub fn none() -> Self {1019		Self {1020			mutable: true,1021			collection_admin: false,1022			token_owner: false,1023		}1024	}1025}10261027/// Property is simpl key-value record.1028#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1029#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1030pub struct Property {1031	/// Property key.1032	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1033	pub key: PropertyKey,10341035	/// Property value.1036	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1037	pub value: PropertyValue,1038}10391040impl Into<(PropertyKey, PropertyValue)> for Property {1041	fn into(self) -> (PropertyKey, PropertyValue) {1042		(self.key, self.value)1043	}1044}10451046/// Record for proprty key permission.1047#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1048#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1049pub struct PropertyKeyPermission {1050	/// Key.1051	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1052	pub key: PropertyKey,10531054	/// Permission.1055	pub permission: PropertyPermission,1056}10571058impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1059	fn into(self) -> (PropertyKey, PropertyPermission) {1060		(self.key, self.permission)1061	}1062}10631064/// Errors for properties actions.1065#[derive(Debug)]1066pub enum PropertiesError {1067	/// The space allocated for properties has run out.1068	///1069	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1070	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1071	NoSpaceForProperty,10721073	/// The property limit has been reached.1074	///1075	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1076	PropertyLimitReached,10771078	/// Property key contains not allowed character.1079	InvalidCharacterInPropertyKey,10801081	/// Property key length is too long.1082	///1083	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1084	PropertyKeyIsTooLong,10851086	/// Property key is empty.1087	EmptyPropertyKey,1088}10891090/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1091#[derive(Debug)]1092pub enum TokenOwnerError {1093	NotFound,1094	MultipleOwners,1095}10961097/// Marker for scope of property.1098///1099/// Scoped property can't be changed by user. Used for external collections.1100#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1101pub enum PropertyScope {1102	None,1103	Rmrk,1104}11051106impl PropertyScope {1107	pub fn prefix(&self) -> &'static [u8] {1108		match self {1109			Self::None => b"",1110			Self::Rmrk => b"rmrk:",1111		}1112	}1113	/// Apply scope to property key.1114	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1115		let prefix = self.prefix();1116		if prefix == b"" {1117			return Ok(key);1118		}1119		[prefix, key.as_slice()]1120			.concat()1121			.try_into()1122			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1123	}1124}11251126/// Trait for operate with properties.1127pub trait TrySetProperty: Sized {1128	type Value;11291130	/// Try to set property with scope.1131	fn try_scoped_set(1132		&mut self,1133		scope: PropertyScope,1134		key: PropertyKey,1135		value: Self::Value,1136	) -> Result<Option<Self::Value>, PropertiesError>;11371138	/// Try to set property with scope from iterator.1139	fn try_scoped_set_from_iter<I, KV>(1140		&mut self,1141		scope: PropertyScope,1142		iter: I,1143	) -> Result<(), PropertiesError>1144	where1145		I: Iterator<Item = KV>,1146		KV: Into<(PropertyKey, Self::Value)>,1147	{1148		for kv in iter {1149			let (key, value) = kv.into();1150			self.try_scoped_set(scope, key, value)?;1151		}11521153		Ok(())1154	}11551156	/// Try to set property.1157	fn try_set(1158		&mut self,1159		key: PropertyKey,1160		value: Self::Value,1161	) -> Result<Option<Self::Value>, PropertiesError> {1162		self.try_scoped_set(PropertyScope::None, key, value)1163	}11641165	/// Try to set property from iterator.1166	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1167	where1168		I: Iterator<Item = KV>,1169		KV: Into<(PropertyKey, Self::Value)>,1170	{1171		self.try_scoped_set_from_iter(PropertyScope::None, iter)1172	}1173}11741175/// Wrapped map for storing properties.1176#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1177#[derivative(Default(bound = ""))]1178pub struct PropertiesMap<Value>(1179	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1180);11811182impl<Value> PropertiesMap<Value> {1183	/// Create new property map.1184	pub fn new() -> Self {1185		Self(BoundedBTreeMap::new())1186	}11871188	/// Remove property from map.1189	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1190		Self::check_property_key(key)?;11911192		Ok(self.0.remove(key))1193	}11941195	/// Get property with appropriate key from map.1196	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1197		self.0.get(key)1198	}11991200	/// Check if map contains key.1201	pub fn contains_key(&self, key: &PropertyKey) -> bool {1202		self.0.contains_key(key)1203	}12041205	/// Check if map contains key with key validation.1206	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1207		if key.is_empty() {1208			return Err(PropertiesError::EmptyPropertyKey);1209		}12101211		for byte in key.as_slice().iter() {1212			let byte = *byte;12131214			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1215				return Err(PropertiesError::InvalidCharacterInPropertyKey);1216			}1217		}12181219		Ok(())1220	}12211222	pub fn values(&self) -> impl Iterator<Item = &Value> {1223		self.0.values()1224	}12251226	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1227		self.0.iter()1228	}1229}12301231impl<Value> IntoIterator for PropertiesMap<Value> {1232	type Item = (PropertyKey, Value);1233	type IntoIter = <1234		BoundedBTreeMap<1235			PropertyKey,1236			Value,1237			ConstU32<MAX_PROPERTIES_PER_ITEM>1238		> as IntoIterator1239	>::IntoIter;12401241	fn into_iter(self) -> Self::IntoIter {1242		self.0.into_iter()1243	}1244}12451246impl<Value> TrySetProperty for PropertiesMap<Value> {1247	type Value = Value;12481249	fn try_scoped_set(1250		&mut self,1251		scope: PropertyScope,1252		key: PropertyKey,1253		value: Self::Value,1254	) -> Result<Option<Self::Value>, PropertiesError> {1255		Self::check_property_key(&key)?;12561257		let key = scope.apply(key)?;1258		self.01259			.try_insert(key, value)1260			.map_err(|_| PropertiesError::PropertyLimitReached)1261	}1262}12631264/// Alias for property permissions map.1265pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;12661267fn slice_size(data: &[u8]) -> u32 {1268	scoped_slice_size(PropertyScope::None, data)1269}1270fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1271	use codec::Compact;1272	let prefix = scope.prefix();1273	<Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321274		+ data.len() as u321275		+ prefix.len() as u321276}12771278/// Wrapper for properties map with consumed space control.1279#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1280pub struct Properties<const S: u32> {1281	map: PropertiesMap<PropertyValue>,1282	consumed_space: u32,1283	// May be not zero, previously served as a current S generic1284	_reserved: u32,1285}12861287impl<const S: u32> MaxEncodedLen for Properties<S> {1288	fn max_encoded_len() -> usize {1289		// len of map + len of consumed_space + len of space_limit1290		u32::max_encoded_len() * 3 + S as usize1291	}1292}12931294impl<const S: u32> Default for Properties<S> {1295	fn default() -> Self {1296		Self::new()1297	}1298}12991300impl<const S: u32> Properties<S> {1301	/// Create new properies container.1302	pub fn new() -> Self {1303		Self {1304			map: PropertiesMap::new(),1305			consumed_space: 0,1306			_reserved: 0,1307		}1308	}13091310	/// Remove propery with appropiate key.1311	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1312		let value = self.map.remove(key)?;13131314		if let Some(ref value) = value {1315			let kv_len = slice_size(key) + slice_size(value);1316			self.consumed_space = self.consumed_space.saturating_sub(kv_len);1317		}13181319		Ok(value)1320	}13211322	/// Get property with appropriate key.1323	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1324		self.map.get(key)1325	}13261327	/// Recomputes the consumed space for the current properties state.1328	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1329	pub fn recompute_consumed_space(&mut self) {1330		self.consumed_space = self1331			.map1332			.iter()1333			.map(|(key, value)| slice_size(key) + slice_size(value))1334			.sum();1335	}1336}13371338impl<const S: u32> IntoIterator for Properties<S> {1339	type Item = (PropertyKey, PropertyValue);1340	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;13411342	fn into_iter(self) -> Self::IntoIter {1343		self.map.into_iter()1344	}1345}13461347impl<const S: u32> TrySetProperty for Properties<S> {1348	type Value = PropertyValue;13491350	fn try_scoped_set(1351		&mut self,1352		scope: PropertyScope,1353		key: PropertyKey,1354		value: Self::Value,1355	) -> Result<Option<Self::Value>, PropertiesError> {1356		let key_size = scoped_slice_size(scope, &key);1357		let value_size = slice_size(&value) as u32;13581359		if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1360		{1361			return Err(PropertiesError::NoSpaceForProperty);1362		}13631364		let old_value = self.map.try_scoped_set(scope, key, value)?;13651366		if let Some(old_value) = old_value.as_ref() {1367			let old_value_size = slice_size(&old_value);1368			self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1369		} else {1370			self.consumed_space += key_size + value_size;1371		}13721373		Ok(old_value)1374	}1375}13761377pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1378pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;
after · primitives/data-structs/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # 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		return &self.0;540	}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 core::ops::Deref for OwnerRestrictedSet {820	type Target = OwnerRestrictedSetInner;821	fn deref(&self) -> &Self::Target {822		&self.0823	}824}825impl core::ops::DerefMut for OwnerRestrictedSet {826	fn deref_mut(&mut self) -> &mut Self::Target {827		&mut self.0828	}829}830831/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.832#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]833#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]834#[derivative(Debug)]835pub struct NestingPermissions {836	/// Owner of token can nest tokens under it.837	pub token_owner: bool,838	/// Admin of token collection can nest tokens under token.839	pub collection_admin: bool,840	/// If set - only tokens from specified collections can be nested.841	pub restricted: Option<OwnerRestrictedSet>,842843	#[cfg(feature = "runtime-benchmarks")]844	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.845	pub permissive: bool,846}847848/// Enum denominating how often can sponsoring occur if it is enabled.849///850/// Used for [`collection limits`](CollectionLimits).851#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]852#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]853pub enum SponsoringRateLimit {854	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions855	SponsoringDisabled,856	/// Once per how many blocks can sponsorship of a transaction type occur857	Blocks(u32),858}859860/// Data used to describe an NFT at creation.861#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]862#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]863#[derivative(Debug)]864pub struct CreateNftData {865	/// Key-value pairs used to describe the token as metadata866	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]867	#[derivative(Debug(format_with = "bounded::vec_debug"))]868	/// Properties that wil be assignet to created item.869	pub properties: CollectionPropertiesVec,870}871872/// Data used to describe a Fungible token at creation.873#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]874#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]875pub struct CreateFungibleData {876	/// Number of fungible coins minted877	pub value: u128,878}879880/// Data used to describe a Refungible token at creation.881#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]882#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]883#[derivative(Debug)]884pub struct CreateReFungibleData {885	/// Number of pieces the RFT is split into886	pub pieces: u128,887888	/// Key-value pairs used to describe the token as metadata889	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]890	#[derivative(Debug(format_with = "bounded::vec_debug"))]891	pub properties: CollectionPropertiesVec,892}893894// TODO: remove this.895#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]896#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]897pub enum MetaUpdatePermission {898	ItemOwner,899	Admin,900	None,901}902903/// Enum holding data used for creation of all three item types.904/// Unified data for create item.905#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]906#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]907pub enum CreateItemData {908	/// Data for create NFT.909	NFT(CreateNftData),910	/// Data for create Fungible item.911	Fungible(CreateFungibleData),912	/// Data for create ReFungible item.913	ReFungible(CreateReFungibleData),914}915916/// Extended data for create NFT.917#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]918#[derivative(Debug)]919pub struct CreateNftExData<CrossAccountId> {920	/// Properties that wil be assignet to created item.921	#[derivative(Debug(format_with = "bounded::vec_debug"))]922	pub properties: CollectionPropertiesVec,923924	/// Owner of creating item.925	pub owner: CrossAccountId,926}927928/// Extended data for create ReFungible item.929#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]930#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]931pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {932	#[derivative(Debug(format_with = "bounded::map_debug"))]933	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,934	#[derivative(Debug(format_with = "bounded::vec_debug"))]935	pub properties: CollectionPropertiesVec,936}937938/// Extended data for create ReFungible item.939#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]940#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]941pub struct CreateRefungibleExSingleOwner<CrossAccountId> {942	pub user: CrossAccountId,943	pub pieces: u128,944	#[derivative(Debug(format_with = "bounded::vec_debug"))]945	pub properties: CollectionPropertiesVec,946}947948/// Unified extended data for creating item.949#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]950#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]951pub enum CreateItemExData<CrossAccountId> {952	/// Extended data for create NFT.953	NFT(954		#[derivative(Debug(format_with = "bounded::vec_debug"))]955		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,956	),957958	/// Extended data for create Fungible item.959	Fungible(960		#[derivative(Debug(format_with = "bounded::map_debug"))]961		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,962	),963964	/// Extended data for create ReFungible item in case of965	/// many tokens, each may have only one owner966	RefungibleMultipleItems(967		#[derivative(Debug(format_with = "bounded::vec_debug"))]968		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,969	),970971	/// Extended data for create ReFungible item in case of972	/// single token, which may have many owners973	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),974}975976impl From<CreateNftData> for CreateItemData {977	fn from(item: CreateNftData) -> Self {978		CreateItemData::NFT(item)979	}980}981982impl From<CreateReFungibleData> for CreateItemData {983	fn from(item: CreateReFungibleData) -> Self {984		CreateItemData::ReFungible(item)985	}986}987988impl From<CreateFungibleData> for CreateItemData {989	fn from(item: CreateFungibleData) -> Self {990		CreateItemData::Fungible(item)991	}992}993994/// Token's address, dictated by its collection and token IDs.995#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]996#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]997// todo possibly rename to be used generally as an address pair998pub struct TokenChild {999	/// Token id.1000	pub token: TokenId,10011002	/// Collection id.1003	pub collection: CollectionId,1004}10051006/// Collection statistics.1007#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]1008#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1009pub struct CollectionStats {1010	/// Number of created items.1011	pub created: u32,10121013	/// Number of burned items.1014	pub destroyed: u32,10151016	/// Number of current items.1017	pub alive: u32,1018}10191020/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1021#[derive(Encode, Decode, Clone, Debug)]1022#[cfg_attr(feature = "std", derive(PartialEq))]1023pub struct PhantomType<T>(core::marker::PhantomData<T>);10241025impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1026	type Identity = PhantomType<T>;10271028	fn type_info() -> scale_info::Type {1029		use scale_info::{1030			Type, Path,1031			build::{FieldsBuilder, UnnamedFields},1032			form::MetaForm,1033			type_params,1034		};1035		Type::builder()1036			.path(Path::new("up_data_structs", "PhantomType"))1037			.type_params(type_params!(T))1038			.composite(1039				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1040			)1041	}1042}1043impl<T> MaxEncodedLen for PhantomType<T> {1044	fn max_encoded_len() -> usize {1045		01046	}1047}10481049/// Bounded vector of bytes.1050pub type BoundedBytes<S> = BoundedVec<u8, S>;10511052/// Extra properties for external collections.1053pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;10541055/// Property key.1056pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;10571058/// Property value.1059pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;10601061/// Property permission.1062#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1063#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1064pub struct PropertyPermission {1065	/// Permission to change the property and property permission.1066	///1067	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1068	pub mutable: bool,10691070	/// Change permission for the collection administrator.1071	pub collection_admin: bool,10721073	/// Permission to change the property for the owner of the token.1074	pub token_owner: bool,1075}10761077impl PropertyPermission {1078	/// Creates mutable property permission but changes restricted for collection admin and token owner.1079	pub fn none() -> Self {1080		Self {1081			mutable: true,1082			collection_admin: false,1083			token_owner: false,1084		}1085	}1086}10871088/// Property is simpl key-value record.1089#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1090#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1091pub struct Property {1092	/// Property key.1093	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1094	pub key: PropertyKey,10951096	/// Property value.1097	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1098	pub value: PropertyValue,1099}11001101impl Into<(PropertyKey, PropertyValue)> for Property {1102	fn into(self) -> (PropertyKey, PropertyValue) {1103		(self.key, self.value)1104	}1105}11061107/// Record for proprty key permission.1108#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1109#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1110pub struct PropertyKeyPermission {1111	/// Key.1112	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1113	pub key: PropertyKey,11141115	/// Permission.1116	pub permission: PropertyPermission,1117}11181119impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1120	fn into(self) -> (PropertyKey, PropertyPermission) {1121		(self.key, self.permission)1122	}1123}11241125/// Errors for properties actions.1126#[derive(Debug)]1127pub enum PropertiesError {1128	/// The space allocated for properties has run out.1129	///1130	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1131	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1132	NoSpaceForProperty,11331134	/// The property limit has been reached.1135	///1136	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1137	PropertyLimitReached,11381139	/// Property key contains not allowed character.1140	InvalidCharacterInPropertyKey,11411142	/// Property key length is too long.1143	///1144	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1145	PropertyKeyIsTooLong,11461147	/// Property key is empty.1148	EmptyPropertyKey,1149}11501151/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1152#[derive(Debug)]1153pub enum TokenOwnerError {1154	NotFound,1155	MultipleOwners,1156}11571158/// Marker for scope of property.1159///1160/// Scoped property can't be changed by user. Used for external collections.1161#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1162pub enum PropertyScope {1163	None,1164	Rmrk,1165}11661167impl PropertyScope {1168	pub fn prefix(&self) -> &'static [u8] {1169		match self {1170			Self::None => b"",1171			Self::Rmrk => b"rmrk:",1172		}1173	}1174	/// Apply scope to property key.1175	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1176		let prefix = self.prefix();1177		if prefix == b"" {1178			return Ok(key);1179		}1180		[prefix, key.as_slice()]1181			.concat()1182			.try_into()1183			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1184	}1185}11861187/// Trait for operate with properties.1188pub trait TrySetProperty: Sized {1189	type Value;11901191	/// Try to set property with scope.1192	fn try_scoped_set(1193		&mut self,1194		scope: PropertyScope,1195		key: PropertyKey,1196		value: Self::Value,1197	) -> Result<Option<Self::Value>, PropertiesError>;11981199	/// Try to set property with scope from iterator.1200	fn try_scoped_set_from_iter<I, KV>(1201		&mut self,1202		scope: PropertyScope,1203		iter: I,1204	) -> Result<(), PropertiesError>1205	where1206		I: Iterator<Item = KV>,1207		KV: Into<(PropertyKey, Self::Value)>,1208	{1209		for kv in iter {1210			let (key, value) = kv.into();1211			self.try_scoped_set(scope, key, value)?;1212		}12131214		Ok(())1215	}12161217	/// Try to set property.1218	fn try_set(1219		&mut self,1220		key: PropertyKey,1221		value: Self::Value,1222	) -> Result<Option<Self::Value>, PropertiesError> {1223		self.try_scoped_set(PropertyScope::None, key, value)1224	}12251226	/// Try to set property from iterator.1227	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1228	where1229		I: Iterator<Item = KV>,1230		KV: Into<(PropertyKey, Self::Value)>,1231	{1232		self.try_scoped_set_from_iter(PropertyScope::None, iter)1233	}1234}12351236/// Wrapped map for storing properties.1237#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1238#[derivative(Default(bound = ""))]1239pub struct PropertiesMap<Value>(1240	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1241);12421243impl<Value> PropertiesMap<Value> {1244	/// Create new property map.1245	pub fn new() -> Self {1246		Self(BoundedBTreeMap::new())1247	}12481249	/// Remove property from map.1250	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1251		Self::check_property_key(key)?;12521253		Ok(self.0.remove(key))1254	}12551256	/// Get property with appropriate key from map.1257	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1258		self.0.get(key)1259	}12601261	/// Check if map contains key.1262	pub fn contains_key(&self, key: &PropertyKey) -> bool {1263		self.0.contains_key(key)1264	}12651266	/// Check if map contains key with key validation.1267	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1268		if key.is_empty() {1269			return Err(PropertiesError::EmptyPropertyKey);1270		}12711272		for byte in key.as_slice().iter() {1273			let byte = *byte;12741275			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1276				return Err(PropertiesError::InvalidCharacterInPropertyKey);1277			}1278		}12791280		Ok(())1281	}12821283	pub fn values(&self) -> impl Iterator<Item = &Value> {1284		self.0.values()1285	}12861287	pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1288		self.0.iter()1289	}1290}12911292impl<Value> IntoIterator for PropertiesMap<Value> {1293	type Item = (PropertyKey, Value);1294	type IntoIter = <1295		BoundedBTreeMap<1296			PropertyKey,1297			Value,1298			ConstU32<MAX_PROPERTIES_PER_ITEM>1299		> as IntoIterator1300	>::IntoIter;13011302	fn into_iter(self) -> Self::IntoIter {1303		self.0.into_iter()1304	}1305}13061307impl<Value> TrySetProperty for PropertiesMap<Value> {1308	type Value = Value;13091310	fn try_scoped_set(1311		&mut self,1312		scope: PropertyScope,1313		key: PropertyKey,1314		value: Self::Value,1315	) -> Result<Option<Self::Value>, PropertiesError> {1316		Self::check_property_key(&key)?;13171318		let key = scope.apply(key)?;1319		self.01320			.try_insert(key, value)1321			.map_err(|_| PropertiesError::PropertyLimitReached)1322	}1323}13241325/// Alias for property permissions map.1326pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;13271328fn slice_size(data: &[u8]) -> u32 {1329	scoped_slice_size(PropertyScope::None, data)1330}1331fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1332	use codec::Compact;1333	let prefix = scope.prefix();1334	<Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321335		+ data.len() as u321336		+ prefix.len() as u321337}13381339/// Wrapper for properties map with consumed space control.1340#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1341pub struct Properties<const S: u32> {1342	map: PropertiesMap<PropertyValue>,1343	consumed_space: u32,1344	// May be not zero, previously served as a current S generic1345	_reserved: u32,1346}13471348impl<const S: u32> MaxEncodedLen for Properties<S> {1349	fn max_encoded_len() -> usize {1350		// len of map + len of consumed_space + len of space_limit1351		u32::max_encoded_len() * 3 + S as usize1352	}1353}13541355impl<const S: u32> Default for Properties<S> {1356	fn default() -> Self {1357		Self::new()1358	}1359}13601361impl<const S: u32> Properties<S> {1362	/// Create new properies container.1363	pub fn new() -> Self {1364		Self {1365			map: PropertiesMap::new(),1366			consumed_space: 0,1367			_reserved: 0,1368		}1369	}13701371	/// Remove propery with appropiate key.1372	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1373		let value = self.map.remove(key)?;13741375		if let Some(ref value) = value {1376			let kv_len = slice_size(key) + slice_size(value);1377			self.consumed_space = self.consumed_space.saturating_sub(kv_len);1378		}13791380		Ok(value)1381	}13821383	/// Get property with appropriate key.1384	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1385		self.map.get(key)1386	}13871388	/// Recomputes the consumed space for the current properties state.1389	/// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1390	pub fn recompute_consumed_space(&mut self) {1391		self.consumed_space = self1392			.map1393			.iter()1394			.map(|(key, value)| slice_size(key) + slice_size(value))1395			.sum();1396	}1397}13981399impl<const S: u32> IntoIterator for Properties<S> {1400	type Item = (PropertyKey, PropertyValue);1401	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;14021403	fn into_iter(self) -> Self::IntoIter {1404		self.map.into_iter()1405	}1406}14071408impl<const S: u32> TrySetProperty for Properties<S> {1409	type Value = PropertyValue;14101411	fn try_scoped_set(1412		&mut self,1413		scope: PropertyScope,1414		key: PropertyKey,1415		value: Self::Value,1416	) -> Result<Option<Self::Value>, PropertiesError> {1417		let key_size = scoped_slice_size(scope, &key);1418		let value_size = slice_size(&value) as u32;14191420		if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1421		{1422			return Err(PropertiesError::NoSpaceForProperty);1423		}14241425		let old_value = self.map.try_scoped_set(scope, key, value)?;14261427		if let Some(old_value) = old_value.as_ref() {1428			let old_value_size = slice_size(&old_value);1429			self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1430		} else {1431			self.consumed_space += key_size + value_size;1432		}14331434		Ok(old_value)1435	}1436}14371438pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1439pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;14401441#[cfg(test)]1442mod tests {1443	use super::*;1444	use codec::IoReader;14451446	#[test]1447	fn rpc_collection_supports_decoding_old_versions() {1448		let encoded_rpc_collection: [u8; 1013] = [1449			0, 1, 250, 241, 137, 120, 188, 29, 94, 210, 193, 237, 186, 22, 203, 241, 52, 248, 167,1450			235, 241, 211, 236, 28, 138, 156, 59, 160, 156, 105, 39, 247, 207, 101, 0, 0, 48, 65,1451			0, 73, 0, 32, 0, 67, 0, 114, 0, 101, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 115, 0,1452			252, 65, 0, 32, 0, 112, 0, 105, 0, 101, 0, 99, 0, 101, 0, 32, 0, 111, 0, 102, 0, 32, 0,1453			97, 0, 32, 0, 109, 0, 97, 0, 99, 0, 104, 0, 105, 0, 110, 0, 101, 0, 32, 0, 109, 0, 105,1454			0, 110, 0, 100, 0, 46, 0, 32, 0, 69, 0, 118, 0, 101, 0, 114, 0, 121, 0, 32, 0, 78, 0,1455			70, 0, 84, 0, 32, 0, 105, 0, 115, 0, 32, 0, 109, 0, 97, 0, 100, 0, 101, 0, 32, 0, 101,1456			0, 120, 0, 99, 0, 108, 0, 117, 0, 115, 0, 105, 0, 118, 0, 101, 0, 108, 0, 121, 0, 32,1457			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,1458			0, 0, 0, 0, 0, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111,1459			118, 101, 114, 34, 58, 34, 81, 109, 98, 52, 104, 122, 76, 101, 51, 49, 102, 98, 71, 74,1460			77, 89, 68, 82, 88, 84, 115, 107, 56, 49, 76, 103, 76, 97, 88, 76, 69, 112, 121, 97,1461			122, 102, 66, 85, 103, 111, 110, 118, 49, 118, 84, 85, 34, 125, 125, 11, 123, 34, 110,1462			101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77, 101,1463			116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58, 123,1464			34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115, 34,1465			58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34, 58,1466			49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34,1467			44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44, 34,1468			67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117, 108,1469			101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112,1470			101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 73, 110, 116, 101, 110, 115,1471			105, 111, 110, 115, 34, 58, 123, 34, 105, 100, 34, 58, 51, 44, 34, 114, 117, 108, 101,1472			34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34,1473			58, 34, 73, 110, 116, 101, 110, 115, 105, 111, 110, 115, 34, 125, 44, 34, 77, 111, 111,1474			100, 34, 58, 123, 34, 105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34,1475			114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 77,1476			111, 111, 100, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111,1477			112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1478			123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 67, 111, 108, 111, 114, 101, 100, 92, 34,1479			125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92,1480			34, 58, 92, 34, 66, 108, 97, 99, 107, 38, 87, 104, 105, 116, 101, 92, 34, 125, 34, 125,1481			44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34,1482			58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 73, 110,1483			116, 101, 110, 115, 105, 111, 110, 115, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110,1484			115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110,1485			92, 34, 58, 92, 34, 101, 118, 105, 108, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1486			100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 103, 111, 111, 100, 92,1487			34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1488			92, 34, 58, 92, 34, 110, 101, 117, 116, 114, 97, 108, 92, 34, 125, 34, 125, 44, 34,1489			118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48,1490			44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51,1491			34, 58, 50, 125, 125, 44, 34, 77, 111, 111, 100, 34, 58, 123, 34, 111, 112, 116, 105,1492			111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34,1493			101, 110, 92, 34, 58, 92, 34, 65, 98, 115, 116, 114, 97, 99, 116, 92, 34, 125, 34, 44,1494			34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1495			85, 110, 99, 97, 110, 110, 101, 121, 32, 118, 97, 108, 108, 101, 121, 92, 34, 125, 34,1496			44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1497			34, 83, 117, 114, 114, 101, 97, 108, 105, 115, 116, 92, 34, 125, 34, 125, 44, 34, 118,1498			97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44,1499			34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34,1500			58, 50, 125, 125, 125, 125, 125, 125, 0,1501		];1502		let mut bytes = IoReader(encoded_rpc_collection.as_slice());1503		CollectionVersion1::<[u8; 34]>::decode(&mut bytes).unwrap();1504	}15051506	#[test]1507	fn rpc_collection_supports_decoding_new_versions() {1508		let encoded_rpc_collection: [u8; 1576] = [1509			0, 1, 238, 236, 179, 149, 150, 47, 71, 194, 69, 174, 250, 116, 251, 148, 90, 15, 56,1510			220, 91, 79, 49, 79, 45, 197, 171, 98, 14, 171, 80, 23, 58, 92, 0, 96, 77, 0, 105, 0,1511			110, 0, 116, 0, 70, 0, 101, 0, 115, 0, 116, 0, 32, 0, 83, 0, 121, 0, 109, 0, 109, 0,1512			101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 66, 0, 114, 0, 101, 0, 97, 0, 99, 0, 104, 0,1513			113, 3, 83, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 104, 0,1514			97, 0, 115, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 116, 0, 104, 0, 105, 0, 110, 0,1515			103, 0, 32, 0, 105, 0, 110, 0, 116, 0, 111, 0, 120, 0, 105, 0, 99, 0, 97, 0, 116, 0,1516			105, 0, 110, 0, 103, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 100, 0, 114, 0,1517			97, 0, 119, 0, 115, 0, 32, 0, 121, 0, 111, 0, 117, 0, 32, 0, 105, 0, 110, 0, 46, 0, 10,1518			0, 73, 0, 110, 0, 115, 0, 112, 0, 105, 0, 114, 0, 101, 0, 100, 0, 32, 0, 98, 0, 121, 0,1519			32, 0, 116, 0, 104, 0, 101, 0, 32, 0, 112, 0, 101, 0, 114, 0, 102, 0, 101, 0, 99, 0,1520			116, 0, 105, 0, 111, 0, 110, 0, 32, 0, 111, 0, 102, 0, 32, 0, 116, 0, 104, 0, 101, 0,1521			32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 44, 0, 32, 0,1522			73, 0, 32, 0, 104, 0, 97, 0, 118, 0, 101, 0, 32, 0, 99, 0, 114, 0, 101, 0, 97, 0, 116,1523			0, 101, 0, 100, 0, 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 105,1524			0, 99, 0, 97, 0, 108, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103, 0, 101, 0, 115, 0, 32, 0,1525			111, 0, 102, 0, 32, 0, 115, 0, 101, 0, 118, 0, 101, 0, 114, 0, 97, 0, 108, 0, 32, 0,1526			118, 0, 101, 0, 114, 0, 116, 0, 105, 0, 99, 0, 101, 0, 115, 0, 44, 0, 32, 0, 98, 0,1527			117, 0, 116, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 32, 0, 115, 0, 121, 0, 109, 0,1528			109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 98, 0, 114, 0, 101, 0, 97, 0, 99, 0,1529			104, 0, 101, 0, 115, 0, 32, 0, 97, 0, 110, 0, 100, 0, 32, 0, 99, 0, 111, 0, 108, 0,1530			111, 0, 114, 0, 115, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 109, 0, 97, 0,1531			107, 0, 101, 0, 32, 0, 101, 0, 97, 0, 99, 0, 104, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103,1532			0, 101, 0, 32, 0, 85, 0, 78, 0, 73, 0, 81, 0, 85, 0, 69, 0, 46, 0, 12, 83, 121, 66, 0,1533			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,1534			111, 110, 115, 116, 68, 97, 116, 97, 0, 1, 0, 12, 92, 95, 111, 108, 100, 95, 99, 111,1535			110, 115, 116, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101, 109, 97, 97, 13, 123,1536			34, 110, 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77,1537			101, 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58,1538			123, 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115,1539			34, 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34,1540			58, 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100,1541			34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44,1542			34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117,1543			108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121,1544			112, 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 83, 121, 109, 109, 101,1545			116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 105, 100, 34, 58, 51,1546			44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44,1547			34, 116, 121, 112, 101, 34, 58, 34, 83, 121, 109, 109, 101, 116, 114, 121, 32, 66, 114,1548			101, 97, 99, 104, 34, 125, 44, 34, 86, 101, 114, 116, 105, 99, 101, 34, 58, 123, 34,1549			105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105,1550			114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 86, 101, 114, 116, 105, 99,1551			101, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111, 112, 116,1552			105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92,1553			34, 101, 110, 92, 34, 58, 92, 34, 49, 32, 32, 32, 92, 34, 125, 34, 44, 34, 102, 105,1554			101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 32, 92,1555			34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1556			92, 34, 58, 92, 34, 51, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34,1557			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100,1558			50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 125, 125, 44, 34, 83,1559			121, 109, 109, 101, 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 111,1560			112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1561			123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 92, 34, 125, 34, 44, 34, 102, 105, 101,1562			108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 92, 34, 125,1563			34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100,1564			49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 86,1565			101, 114, 116, 105, 99, 101, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110, 115, 34,1566			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34,1567			58, 92, 34, 54, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123,1568			92, 34, 101, 110, 92, 34, 58, 92, 34, 55, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1569			100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 56, 92, 34, 125, 34,1570			44, 34, 102, 105, 101, 108, 100, 52, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1571			34, 57, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 34, 123, 92, 34,1572			101, 110, 92, 34, 58, 92, 34, 49, 48, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100,1573			54, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 49, 92, 34, 125, 34, 44,1574			34, 102, 105, 101, 108, 100, 55, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1575			49, 50, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34,1576			102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58,1577			49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 44, 34, 102, 105, 101, 108, 100,1578			52, 34, 58, 51, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 52, 44, 34, 102, 105, 101,1579			108, 100, 54, 34, 58, 53, 44, 34, 102, 105, 101, 108, 100, 55, 34, 58, 54, 125, 125,1580			125, 125, 125, 125, 72, 95, 111, 108, 100, 95, 115, 99, 104, 101, 109, 97, 86, 101,1581			114, 115, 105, 111, 110, 24, 85, 110, 105, 113, 117, 101, 104, 95, 111, 108, 100, 95,1582			118, 97, 114, 105, 97, 98, 108, 101, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101,1583			109, 97, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111, 118,1584			101, 114, 34, 58, 34, 81, 109, 82, 67, 77, 84, 109, 57, 118, 81, 107, 76, 89, 86, 65,1585			54, 54, 87, 80, 49, 75, 72, 57, 55, 106, 84, 76, 76, 115, 56, 74, 78, 86, 65, 114, 80,1586			66, 52, 56, 98, 106, 87, 84, 75, 74, 110, 34, 125, 0, 0, 0,1587		];1588		let mut bytes = IoReader(encoded_rpc_collection.as_slice());1589		RpcCollection::<[u8; 34]>::decode(&mut bytes).unwrap();1590	}15911592	#[test]1593	fn rpc_collection_supports_decoding_through_vec() {1594		let encoded_rpc_collection: [u8; 1576] = [1595			0, 1, 238, 236, 179, 149, 150, 47, 71, 194, 69, 174, 250, 116, 251, 148, 90, 15, 56,1596			220, 91, 79, 49, 79, 45, 197, 171, 98, 14, 171, 80, 23, 58, 92, 0, 96, 77, 0, 105, 0,1597			110, 0, 116, 0, 70, 0, 101, 0, 115, 0, 116, 0, 32, 0, 83, 0, 121, 0, 109, 0, 109, 0,1598			101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 66, 0, 114, 0, 101, 0, 97, 0, 99, 0, 104, 0,1599			113, 3, 83, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 104, 0,1600			97, 0, 115, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 116, 0, 104, 0, 105, 0, 110, 0,1601			103, 0, 32, 0, 105, 0, 110, 0, 116, 0, 111, 0, 120, 0, 105, 0, 99, 0, 97, 0, 116, 0,1602			105, 0, 110, 0, 103, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 100, 0, 114, 0,1603			97, 0, 119, 0, 115, 0, 32, 0, 121, 0, 111, 0, 117, 0, 32, 0, 105, 0, 110, 0, 46, 0, 10,1604			0, 73, 0, 110, 0, 115, 0, 112, 0, 105, 0, 114, 0, 101, 0, 100, 0, 32, 0, 98, 0, 121, 0,1605			32, 0, 116, 0, 104, 0, 101, 0, 32, 0, 112, 0, 101, 0, 114, 0, 102, 0, 101, 0, 99, 0,1606			116, 0, 105, 0, 111, 0, 110, 0, 32, 0, 111, 0, 102, 0, 32, 0, 116, 0, 104, 0, 101, 0,1607			32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 44, 0, 32, 0,1608			73, 0, 32, 0, 104, 0, 97, 0, 118, 0, 101, 0, 32, 0, 99, 0, 114, 0, 101, 0, 97, 0, 116,1609			0, 101, 0, 100, 0, 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 105,1610			0, 99, 0, 97, 0, 108, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103, 0, 101, 0, 115, 0, 32, 0,1611			111, 0, 102, 0, 32, 0, 115, 0, 101, 0, 118, 0, 101, 0, 114, 0, 97, 0, 108, 0, 32, 0,1612			118, 0, 101, 0, 114, 0, 116, 0, 105, 0, 99, 0, 101, 0, 115, 0, 44, 0, 32, 0, 98, 0,1613			117, 0, 116, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 32, 0, 115, 0, 121, 0, 109, 0,1614			109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 98, 0, 114, 0, 101, 0, 97, 0, 99, 0,1615			104, 0, 101, 0, 115, 0, 32, 0, 97, 0, 110, 0, 100, 0, 32, 0, 99, 0, 111, 0, 108, 0,1616			111, 0, 114, 0, 115, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 109, 0, 97, 0,1617			107, 0, 101, 0, 32, 0, 101, 0, 97, 0, 99, 0, 104, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103,1618			0, 101, 0, 32, 0, 85, 0, 78, 0, 73, 0, 81, 0, 85, 0, 69, 0, 46, 0, 12, 83, 121, 66, 0,1619			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,1620			111, 110, 115, 116, 68, 97, 116, 97, 0, 1, 0, 12, 92, 95, 111, 108, 100, 95, 99, 111,1621			110, 115, 116, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101, 109, 97, 97, 13, 123,1622			34, 110, 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77,1623			101, 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58,1624			123, 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115,1625			34, 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34,1626			58, 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100,1627			34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44,1628			34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117,1629			108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121,1630			112, 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 83, 121, 109, 109, 101,1631			116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 105, 100, 34, 58, 51,1632			44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44,1633			34, 116, 121, 112, 101, 34, 58, 34, 83, 121, 109, 109, 101, 116, 114, 121, 32, 66, 114,1634			101, 97, 99, 104, 34, 125, 44, 34, 86, 101, 114, 116, 105, 99, 101, 34, 58, 123, 34,1635			105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105,1636			114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 86, 101, 114, 116, 105, 99,1637			101, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111, 112, 116,1638			105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92,1639			34, 101, 110, 92, 34, 58, 92, 34, 49, 32, 32, 32, 92, 34, 125, 34, 44, 34, 102, 105,1640			101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 32, 92,1641			34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1642			92, 34, 58, 92, 34, 51, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34,1643			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100,1644			50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 125, 125, 44, 34, 83,1645			121, 109, 109, 101, 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 111,1646			112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1647			123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 92, 34, 125, 34, 44, 34, 102, 105, 101,1648			108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 92, 34, 125,1649			34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100,1650			49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 86,1651			101, 114, 116, 105, 99, 101, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110, 115, 34,1652			58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34,1653			58, 92, 34, 54, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123,1654			92, 34, 101, 110, 92, 34, 58, 92, 34, 55, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1655			100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 56, 92, 34, 125, 34,1656			44, 34, 102, 105, 101, 108, 100, 52, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1657			34, 57, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 34, 123, 92, 34,1658			101, 110, 92, 34, 58, 92, 34, 49, 48, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100,1659			54, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 49, 92, 34, 125, 34, 44,1660			34, 102, 105, 101, 108, 100, 55, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1661			49, 50, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34,1662			102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58,1663			49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 44, 34, 102, 105, 101, 108, 100,1664			52, 34, 58, 51, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 52, 44, 34, 102, 105, 101,1665			108, 100, 54, 34, 58, 53, 44, 34, 102, 105, 101, 108, 100, 55, 34, 58, 54, 125, 125,1666			125, 125, 125, 125, 72, 95, 111, 108, 100, 95, 115, 99, 104, 101, 109, 97, 86, 101,1667			114, 115, 105, 111, 110, 24, 85, 110, 105, 113, 117, 101, 104, 95, 111, 108, 100, 95,1668			118, 97, 114, 105, 97, 98, 108, 101, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101,1669			109, 97, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111, 118,1670			101, 114, 34, 58, 34, 81, 109, 82, 67, 77, 84, 109, 57, 118, 81, 107, 76, 89, 86, 65,1671			54, 54, 87, 80, 49, 75, 72, 57, 55, 106, 84, 76, 76, 115, 56, 74, 78, 86, 65, 114, 80,1672			66, 52, 56, 98, 106, 87, 84, 75, 74, 110, 34, 125, 0, 0, 0,1673		];1674		let mut bytes = IoReader(encoded_rpc_collection.as_slice());1675		let vec = RawEncoded::decode(&mut bytes).unwrap();1676		let mut bytes = IoReader(vec.as_slice());1677		RpcCollection::<[u8; 34]>::decode(&mut bytes).unwrap();1678	}1679}
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -19,8 +19,8 @@
 extern crate alloc;
 
 use up_data_structs::{
-	CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,
-	PropertyKeyPermission, TokenData, TokenChild, RpcCollectionVersion1, TokenDataVersion1,
+	CollectionId, TokenId, RawEncoded, RpcCollection, CollectionStats, CollectionLimits, Property,
+	PropertyKeyPermission, TokenData, TokenChild, TokenDataVersion1,
 };
 
 use sp_std::vec::Vec;
@@ -117,7 +117,7 @@
 		fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;
 
 		#[changed_in(3)]
-		fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollectionVersion1<AccountId>>>;
+		fn collection_by_id(collection: CollectionId) -> Result<Option<RawEncoded>>;
 
 		/// Get collection stats.
 		fn collection_stats() -> Result<CollectionStats>;