git.delta.rocks / unique-network / refs/commits / 424362fb52a4

difftreelog

Merge pull request #683 from UniqueNetwork/fix/collection-rpc-runtime-versioning

Yaroslav Bolyukin2022-10-26parents: #778aa39 #6fd4079.patch.diff
in: master

3 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -557,7 +557,10 @@
 	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);
 	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);
 	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);
-	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, 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())
+	);
 	pass_method!(collection_stats() -> CollectionStats, unique_api);
 	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);
 	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
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};27use frame_support::{28	storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},29	traits::Get,30	parameter_types,31};3233#[cfg(feature = "serde")]34use serde::{Serialize, Deserialize};3536use sp_core::U256;37use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};38use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};39use bondrewd::Bitfields;40use frame_support::{BoundedVec, traits::ConstU32};41use derivative::Derivative;42use scale_info::TypeInfo;4344// RMRK45use rmrk_traits::{46	CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,47	ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,48};49pub use rmrk_traits::{50	primitives::{51		CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,52		SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,53	},54	NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,55	FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,56};5758mod bondrewd_codec;59mod bounded;60pub mod budget;61pub mod mapping;62mod migration;6364/// Maximum of decimal points.65pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;6667/// Maximum pieces for refungible token.68pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;69pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;7071/// Maximum tokens for user.72pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {73	100_00074} else {75	1076};7778/// Maximum for collections can be created.79pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {80	100_00081} else {82	1083};8485/// Maximum for various custom data of token.86pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {87	204888} else {89	1090};9192/// Maximum admins per collection.93pub const COLLECTION_ADMINS_LIMIT: u32 = 5;9495/// Maximum tokens per collection.96pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;9798/// Maximum tokens per account.99pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {100	1_000_000101} else {102	10103};104105/// Default timeout for transfer sponsoring NFT item.106pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;107/// Default timeout for transfer sponsoring fungible item.108pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;109/// Default timeout for transfer sponsoring refungible item.110pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;111112/// Default timeout for sponsored approving.113pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;114115// Schema limits116pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;117pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;118pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;119120// TODO: not used. Delete?121pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;122123/// Maximum length for collection name.124pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;125126/// Maximum length for collection description.127pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;128129/// Maximal token prefix length.130pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;131132/// Maximal lenght of property key.133pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;134135/// Maximal lenght of property value.136pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;137138/// Maximum properties that can be assigned to token.139pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;140141/// Maximal lenght of extended property value.142pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;143144/// Maximum size for all collection properties.145pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;146147/// Maximum size for all token properties.148pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;149150/// How much items can be created per single151/// create_many call.152pub const MAX_ITEMS_PER_BATCH: u32 = 200;153154/// Used for limit bounded types of token custom data.155pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;156157/// Collection id.158#[derive(159	Encode,160	Decode,161	PartialEq,162	Eq,163	PartialOrd,164	Ord,165	Clone,166	Copy,167	Debug,168	Default,169	TypeInfo,170	MaxEncodedLen,171)]172#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]173pub struct CollectionId(pub u32);174impl EncodeLike<u32> for CollectionId {}175impl EncodeLike<CollectionId> for u32 {}176177/// Token id.178#[derive(179	Encode,180	Decode,181	PartialEq,182	Eq,183	PartialOrd,184	Ord,185	Clone,186	Copy,187	Debug,188	Default,189	TypeInfo,190	MaxEncodedLen,191)]192#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]193pub struct TokenId(pub u32);194impl EncodeLike<u32> for TokenId {}195impl EncodeLike<TokenId> for u32 {}196197impl TokenId {198	/// Try to get next token id.199	///200	/// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.201	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {202		self.0203			.checked_add(1)204			.ok_or(ArithmeticError::Overflow)205			.map(Self)206	}207}208209impl From<TokenId> for U256 {210	fn from(t: TokenId) -> Self {211		t.0.into()212	}213}214215impl TryFrom<U256> for TokenId {216	type Error = &'static str;217218	fn try_from(value: U256) -> Result<Self, Self::Error> {219		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))220	}221}222223/// Token data.224#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]225#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]226pub struct TokenData<CrossAccountId> {227	/// Properties of token.228	pub properties: Vec<Property>,229230	/// Token owner.231	pub owner: Option<CrossAccountId>,232233	/// Token pieces.234	pub pieces: u128,235}236237// TODO: unused type238pub struct OverflowError;239impl From<OverflowError> for &'static str {240	fn from(_: OverflowError) -> Self {241		"overflow occured"242	}243}244245/// Alias for decimal points type.246pub type DecimalPoints = u8;247248/// Collection mode.249///250/// Collection can represent various types of tokens.251/// Each collection can contain only one type of tokens at a time.252/// This type helps to understand which tokens the collection contains.253#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]254#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]255pub enum CollectionMode {256	/// Non fungible tokens.257	NFT,258	/// Fungible tokens.259	Fungible(DecimalPoints),260	/// Refungible tokens.261	ReFungible,262}263264impl CollectionMode {265	/// Get collection mod as number.266	pub fn id(&self) -> u8 {267		match self {268			CollectionMode::NFT => 1,269			CollectionMode::Fungible(_) => 2,270			CollectionMode::ReFungible => 3,271		}272	}273}274275// TODO: unused trait276pub trait SponsoringResolve<AccountId, Call> {277	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;278}279280/// Access mode for some token operations.281#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]282#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]283pub enum AccessMode {284	/// Access grant for owner and admins. Used as default.285	Normal,286	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.287	AllowList,288}289impl Default for AccessMode {290	fn default() -> Self {291		Self::Normal292	}293}294295// TODO: remove in future.296#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]297#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]298pub enum SchemaVersion {299	ImageURL,300	Unique,301}302impl Default for SchemaVersion {303	fn default() -> Self {304		Self::ImageURL305	}306}307308// TODO: unused type309#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]310#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]311pub struct Ownership<AccountId> {312	pub owner: AccountId,313	pub fraction: u128,314}315316/// The state of collection sponsorship.317#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]318#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]319pub enum SponsorshipState<AccountId> {320	/// The fees are applied to the transaction sender.321	Disabled,322	/// The sponsor is under consideration. Until the sponsor gives his consent,323	/// the fee will still be charged to sender.324	Unconfirmed(AccountId),325	/// Transactions are sponsored by specified account.326	Confirmed(AccountId),327}328329impl<AccountId> SponsorshipState<AccountId> {330	/// Get a sponsor of the collection who has confirmed his status.331	pub fn sponsor(&self) -> Option<&AccountId> {332		match self {333			Self::Confirmed(sponsor) => Some(sponsor),334			_ => None,335		}336	}337338	/// Get a sponsor of the collection who has pending or confirmed status.339	pub fn pending_sponsor(&self) -> Option<&AccountId> {340		match self {341			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),342			_ => None,343		}344	}345346	/// Whether the sponsorship is confirmed.347	pub fn confirmed(&self) -> bool {348		matches!(self, Self::Confirmed(_))349	}350}351352impl<T> Default for SponsorshipState<T> {353	fn default() -> Self {354		Self::Disabled355	}356}357358pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;359pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;360pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;361362#[derive(Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]363#[bondrewd(enforce_bytes = 1)]364pub struct CollectionFlags {365	/// Tokens in foreign collections can be transferred, but not burnt366	#[bondrewd(bits = "0..1")]367	pub foreign: bool,368	/// Supports ERC721Metadata369	#[bondrewd(bits = "1..2")]370	pub erc721metadata: bool,371	/// External collections can't be managed using `unique` api372	#[bondrewd(bits = "7..8")]373	pub external: bool,374375	#[bondrewd(reserve, bits = "2..7")]376	pub reserved: u8,377}378bondrewd_codec!(CollectionFlags);379380/// Base structure for represent collection.381///382/// Used to provide basic functionality for all types of collections.383///384/// #### Note385/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).386#[struct_versioning::versioned(version = 2, upper)]387#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]388pub struct Collection<AccountId> {389	/// Collection owner account.390	pub owner: AccountId,391392	/// Collection mode.393	pub mode: CollectionMode,394395	/// Access mode.396	#[version(..2)]397	pub access: AccessMode,398399	/// Collection name.400	pub name: CollectionName,401402	/// Collection description.403	pub description: CollectionDescription,404405	/// Token prefix.406	pub token_prefix: CollectionTokenPrefix,407408	#[version(..2)]409	pub mint_mode: bool,410411	#[version(..2)]412	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,413414	#[version(..2)]415	pub schema_version: SchemaVersion,416417	/// The state of sponsorship of the collection.418	pub sponsorship: SponsorshipState<AccountId>,419420	/// Collection limits.421	pub limits: CollectionLimits,422423	/// Collection permissions.424	#[version(2.., upper(Default::default()))]425	pub permissions: CollectionPermissions,426427	#[version(2.., upper(Default::default()))]428	pub flags: CollectionFlags,429430	#[version(..2)]431	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,432433	#[version(..2)]434	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,435436	#[version(..2)]437	pub meta_update_permission: MetaUpdatePermission,438}439440#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]441#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]442pub struct RpcCollectionFlags {443	/// Is collection is foreign.444	pub foreign: bool,445	/// Collection supports ERC721Metadata.446	pub erc721metadata: bool,447}448449/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).450#[struct_versioning::versioned(version = 2, upper)]451#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]452#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]453pub struct RpcCollection<AccountId> {454	/// Collection owner account.455	pub owner: AccountId,456457	/// Collection mode.458	pub mode: CollectionMode,459460	/// Collection name.461	pub name: Vec<u16>,462463	/// Collection description.464	pub description: Vec<u16>,465466	/// Token prefix.467	pub token_prefix: Vec<u8>,468469	/// The state of sponsorship of the collection.470	pub sponsorship: SponsorshipState<AccountId>,471472	/// Collection limits.473	pub limits: CollectionLimits,474475	/// Collection permissions.476	pub permissions: CollectionPermissions,477478	/// Token property permissions.479	pub token_property_permissions: Vec<PropertyKeyPermission>,480481	/// Collection properties.482	pub properties: Vec<Property>,483484	/// Is collection read only.485	pub read_only: bool,486487	/// Extra collection flags488	#[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]489	pub flags: RpcCollectionFlags,490}491492/// Data used for create collection.493///494/// All fields are wrapped in [`Option`], where `None` means chain default.495#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]496#[derivative(Debug, Default(bound = ""))]497pub struct CreateCollectionData<AccountId> {498	/// Collection mode.499	#[derivative(Default(value = "CollectionMode::NFT"))]500	pub mode: CollectionMode,501502	/// Access mode.503	pub access: Option<AccessMode>,504505	/// Collection name.506	pub name: CollectionName,507508	/// Collection description.509	pub description: CollectionDescription,510511	/// Token prefix.512	pub token_prefix: CollectionTokenPrefix,513514	/// Pending collection sponsor.515	pub pending_sponsor: Option<AccountId>,516517	/// Collection limits.518	pub limits: Option<CollectionLimits>,519520	/// Collection permissions.521	pub permissions: Option<CollectionPermissions>,522523	/// Token property permissions.524	pub token_property_permissions: CollectionPropertiesPermissionsVec,525526	/// Collection properties.527	pub properties: CollectionPropertiesVec,528}529530/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].531// TODO: maybe rename to PropertiesPermissionsVec532pub type CollectionPropertiesPermissionsVec =533	BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;534535/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].536pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;537538/// Limits and restrictions of a collection.539///540/// All fields are wrapped in [`Option`], where `None` means chain default.541///542/// Update with `pallet_common::Pallet::clamp_limits`.543// IMPORTANT: When adding/removing fields from this struct - don't forget to also544#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]545#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]546// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.547// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.548// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.549pub struct CollectionLimits {550	/// How many tokens can a user have on one account.551	/// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].552	/// * Limit - [`MAX_TOKEN_OWNERSHIP`].553	pub account_token_ownership_limit: Option<u32>,554555	/// How many bytes of data are available for sponsorship.556	/// * Default - [`CUSTOM_DATA_LIMIT`].557	/// * Limit - [`CUSTOM_DATA_LIMIT`].558	pub sponsored_data_size: Option<u32>,559560	// FIXME should we delete this or repurpose it?561	/// Times in how many blocks we sponsor data.562	///563	/// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.564	///565	/// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).566	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].567	///568	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]569	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,570	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]571572	/// How many tokens can be mined into this collection.573	///574	/// * Default - [`COLLECTION_TOKEN_LIMIT`].575	/// * Limit - [`COLLECTION_TOKEN_LIMIT`].576	pub token_limit: Option<u32>,577578	/// Timeouts for transfer sponsoring.579	///580	/// * Default581	///   - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]582	///   - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]583	///   - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]584	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].585	pub sponsor_transfer_timeout: Option<u32>,586587	/// Timeout for sponsoring an approval in passed blocks.588	///589	/// * Default - [`SPONSOR_APPROVE_TIMEOUT`].590	/// * Limit - [`MAX_SPONSOR_TIMEOUT`].591	pub sponsor_approve_timeout: Option<u32>,592593	/// Whether the collection owner of the collection can send tokens (which belong to other users).594	///595	/// * Default - **false**.596	pub owner_can_transfer: Option<bool>,597598	/// Can the collection owner burn other people's tokens.599	///600	/// * Default - **true**.601	pub owner_can_destroy: Option<bool>,602603	/// Is it possible to send tokens from this collection between users.604	///605	/// * Default - **true**.606	pub transfers_enabled: Option<bool>,607}608609impl CollectionLimits {610	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).611	pub fn account_token_ownership_limit(&self) -> u32 {612		self.account_token_ownership_limit613			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)614			.min(MAX_TOKEN_OWNERSHIP)615	}616617	/// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).618	pub fn sponsored_data_size(&self) -> u32 {619		self.sponsored_data_size620			.unwrap_or(CUSTOM_DATA_LIMIT)621			.min(CUSTOM_DATA_LIMIT)622	}623624	/// Get effective value for [`token_limit`](self.token_limit).625	pub fn token_limit(&self) -> u32 {626		self.token_limit627			.unwrap_or(COLLECTION_TOKEN_LIMIT)628			.min(COLLECTION_TOKEN_LIMIT)629	}630631	// TODO: may be replace u32 to mode?632	/// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).633	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {634		self.sponsor_transfer_timeout635			.unwrap_or(default)636			.min(MAX_SPONSOR_TIMEOUT)637	}638639	/// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).640	pub fn sponsor_approve_timeout(&self) -> u32 {641		self.sponsor_approve_timeout642			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)643			.min(MAX_SPONSOR_TIMEOUT)644	}645646	/// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).647	pub fn owner_can_transfer(&self) -> bool {648		self.owner_can_transfer.unwrap_or(false)649	}650651	/// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).652	pub fn owner_can_transfer_instaled(&self) -> bool {653		self.owner_can_transfer.is_some()654	}655656	/// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).657	pub fn owner_can_destroy(&self) -> bool {658		self.owner_can_destroy.unwrap_or(true)659	}660661	/// Get effective value for [`transfers_enabled`](self.transfers_enabled).662	pub fn transfers_enabled(&self) -> bool {663		self.transfers_enabled.unwrap_or(true)664	}665666	/// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).667	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {668		match self669			.sponsored_data_rate_limit670			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)671		{672			SponsoringRateLimit::SponsoringDisabled => None,673			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),674		}675	}676}677678/// Permissions on certain operations within a collection.679///680/// Some fields are wrapped in [`Option`], where `None` means chain default.681///682/// Update with `pallet_common::Pallet::clamp_permissions`.683#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]684#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]685// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.686// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.687pub struct CollectionPermissions {688	/// Access mode.689	///690	/// * Default - [`AccessMode::Normal`].691	pub access: Option<AccessMode>,692693	/// Minting allowance.694	///695	/// * Default - **false**.696	pub mint_mode: Option<bool>,697698	/// Permissions for nesting.699	///700	/// * Default701	///   - `token_owner` - **false**702	///   - `collection_admin` - **false**703	///   - `restricted` - **None**704	pub nesting: Option<NestingPermissions>,705}706707impl CollectionPermissions {708	/// Get effective value for [`access`](self.access).709	pub fn access(&self) -> AccessMode {710		self.access.unwrap_or(AccessMode::Normal)711	}712713	/// Get effective value for [`mint_mode`](self.mint_mode).714	pub fn mint_mode(&self) -> bool {715		self.mint_mode.unwrap_or(false)716	}717718	/// Get effective value for [`nesting`](self.nesting).719	pub fn nesting(&self) -> &NestingPermissions {720		static DEFAULT: NestingPermissions = NestingPermissions {721			token_owner: false,722			collection_admin: false,723			restricted: None,724			#[cfg(feature = "runtime-benchmarks")]725			permissive: false,726		};727		self.nesting.as_ref().unwrap_or(&DEFAULT)728	}729}730731/// Inner set for collections allowed to nest.732type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;733734/// Wraper for collections set allowing nest.735#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]736#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]737#[derivative(Debug)]738pub struct OwnerRestrictedSet(739	#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]740	#[derivative(Debug(format_with = "bounded::set_debug"))]741	pub OwnerRestrictedSetInner,742);743744impl OwnerRestrictedSet {745	/// Create new set.746	pub fn new() -> Self {747		Self(Default::default())748	}749}750impl core::ops::Deref for OwnerRestrictedSet {751	type Target = OwnerRestrictedSetInner;752	fn deref(&self) -> &Self::Target {753		&self.0754	}755}756impl core::ops::DerefMut for OwnerRestrictedSet {757	fn deref_mut(&mut self) -> &mut Self::Target {758		&mut self.0759	}760}761762/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.763#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]764#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]765#[derivative(Debug)]766pub struct NestingPermissions {767	/// Owner of token can nest tokens under it.768	pub token_owner: bool,769	/// Admin of token collection can nest tokens under token.770	pub collection_admin: bool,771	/// If set - only tokens from specified collections can be nested.772	pub restricted: Option<OwnerRestrictedSet>,773774	#[cfg(feature = "runtime-benchmarks")]775	/// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.776	pub permissive: bool,777}778779/// Enum denominating how often can sponsoring occur if it is enabled.780///781/// Used for [`collection limits`](CollectionLimits).782#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]783#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]784pub enum SponsoringRateLimit {785	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions786	SponsoringDisabled,787	/// Once per how many blocks can sponsorship of a transaction type occur788	Blocks(u32),789}790791/// Data used to describe an NFT at creation.792#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]793#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]794#[derivative(Debug)]795pub struct CreateNftData {796	/// Key-value pairs used to describe the token as metadata797	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]798	#[derivative(Debug(format_with = "bounded::vec_debug"))]799	/// Properties that wil be assignet to created item.800	pub properties: CollectionPropertiesVec,801}802803/// Data used to describe a Fungible token at creation.804#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]805#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]806pub struct CreateFungibleData {807	/// Number of fungible coins minted808	pub value: u128,809}810811/// Data used to describe a Refungible token at creation.812#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]813#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]814#[derivative(Debug)]815pub struct CreateReFungibleData {816	/// Number of pieces the RFT is split into817	pub pieces: u128,818819	/// Key-value pairs used to describe the token as metadata820	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]821	#[derivative(Debug(format_with = "bounded::vec_debug"))]822	pub properties: CollectionPropertiesVec,823}824825// TODO: remove this.826#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]827#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]828pub enum MetaUpdatePermission {829	ItemOwner,830	Admin,831	None,832}833834/// Enum holding data used for creation of all three item types.835/// Unified data for create item.836#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]837#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]838pub enum CreateItemData {839	/// Data for create NFT.840	NFT(CreateNftData),841	/// Data for create Fungible item.842	Fungible(CreateFungibleData),843	/// Data for create ReFungible item.844	ReFungible(CreateReFungibleData),845}846847/// Extended data for create NFT.848#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]849#[derivative(Debug)]850pub struct CreateNftExData<CrossAccountId> {851	/// Properties that wil be assignet to created item.852	#[derivative(Debug(format_with = "bounded::vec_debug"))]853	pub properties: CollectionPropertiesVec,854855	/// Owner of creating item.856	pub owner: CrossAccountId,857}858859/// Extended data for create ReFungible item.860#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]861#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]862pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {863	#[derivative(Debug(format_with = "bounded::map_debug"))]864	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,865	#[derivative(Debug(format_with = "bounded::vec_debug"))]866	pub properties: CollectionPropertiesVec,867}868869/// Extended data for create ReFungible item.870#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]871#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]872pub struct CreateRefungibleExSingleOwner<CrossAccountId> {873	pub user: CrossAccountId,874	pub pieces: u128,875	#[derivative(Debug(format_with = "bounded::vec_debug"))]876	pub properties: CollectionPropertiesVec,877}878879/// Unified extended data for creating item.880#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]881#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]882pub enum CreateItemExData<CrossAccountId> {883	/// Extended data for create NFT.884	NFT(885		#[derivative(Debug(format_with = "bounded::vec_debug"))]886		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,887	),888889	/// Extended data for create Fungible item.890	Fungible(891		#[derivative(Debug(format_with = "bounded::map_debug"))]892		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,893	),894895	/// Extended data for create ReFungible item in case of896	/// many tokens, each may have only one owner897	RefungibleMultipleItems(898		#[derivative(Debug(format_with = "bounded::vec_debug"))]899		BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,900	),901902	/// Extended data for create ReFungible item in case of903	/// single token, which may have many owners904	RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),905}906907impl From<CreateNftData> for CreateItemData {908	fn from(item: CreateNftData) -> Self {909		CreateItemData::NFT(item)910	}911}912913impl From<CreateReFungibleData> for CreateItemData {914	fn from(item: CreateReFungibleData) -> Self {915		CreateItemData::ReFungible(item)916	}917}918919impl From<CreateFungibleData> for CreateItemData {920	fn from(item: CreateFungibleData) -> Self {921		CreateItemData::Fungible(item)922	}923}924925/// Token's address, dictated by its collection and token IDs.926#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]927#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]928// todo possibly rename to be used generally as an address pair929pub struct TokenChild {930	/// Token id.931	pub token: TokenId,932933	/// Collection id.934	pub collection: CollectionId,935}936937/// Collection statistics.938#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]939#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]940pub struct CollectionStats {941	/// Number of created items.942	pub created: u32,943944	/// Number of burned items.945	pub destroyed: u32,946947	/// Number of current items.948	pub alive: u32,949}950951/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.952#[derive(Encode, Decode, Clone, Debug)]953#[cfg_attr(feature = "std", derive(PartialEq))]954pub struct PhantomType<T>(core::marker::PhantomData<T>);955956impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {957	type Identity = PhantomType<T>;958959	fn type_info() -> scale_info::Type {960		use scale_info::{961			Type, Path,962			build::{FieldsBuilder, UnnamedFields},963			type_params,964		};965		Type::builder()966			.path(Path::new("up_data_structs", "PhantomType"))967			.type_params(type_params!(T))968			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))969	}970}971impl<T> MaxEncodedLen for PhantomType<T> {972	fn max_encoded_len() -> usize {973		0974	}975}976977/// Bounded vector of bytes.978pub type BoundedBytes<S> = BoundedVec<u8, S>;979980/// Extra properties for external collections.981pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;982983/// Property key.984pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;985986/// Property value.987pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;988989/// Property permission.990#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]991#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]992pub struct PropertyPermission {993	/// Permission to change the property and property permission.994	///995	/// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.996	pub mutable: bool,997998	/// Change permission for the collection administrator.999	pub collection_admin: bool,10001001	/// Permission to change the property for the owner of the token.1002	pub token_owner: bool,1003}10041005impl PropertyPermission {1006	/// Creates mutable property permission but changes restricted for collection admin and token owner.1007	pub fn none() -> Self {1008		Self {1009			mutable: true,1010			collection_admin: false,1011			token_owner: false,1012		}1013	}1014}10151016/// Property is simpl key-value record.1017#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1018#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1019pub struct Property {1020	/// Property key.1021	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1022	pub key: PropertyKey,10231024	/// Property value.1025	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1026	pub value: PropertyValue,1027}10281029impl Into<(PropertyKey, PropertyValue)> for Property {1030	fn into(self) -> (PropertyKey, PropertyValue) {1031		(self.key, self.value)1032	}1033}10341035/// Record for proprty key permission.1036#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1037#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1038pub struct PropertyKeyPermission {1039	/// Key.1040	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1041	pub key: PropertyKey,10421043	/// Permission.1044	pub permission: PropertyPermission,1045}10461047impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1048	fn into(self) -> (PropertyKey, PropertyPermission) {1049		(self.key, self.permission)1050	}1051}10521053/// Errors for properties actions.1054#[derive(Debug)]1055pub enum PropertiesError {1056	/// The space allocated for properties has run out.1057	///1058	/// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1059	/// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1060	NoSpaceForProperty,10611062	/// The property limit has been reached.1063	///1064	/// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1065	PropertyLimitReached,10661067	/// Property key contains not allowed character.1068	InvalidCharacterInPropertyKey,10691070	/// Property key length is too long.1071	///1072	/// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1073	PropertyKeyIsTooLong,10741075	/// Property key is empty.1076	EmptyPropertyKey,1077}10781079/// Marker for scope of property.1080///1081/// Scoped property can't be changed by user. Used for external collections.1082#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1083pub enum PropertyScope {1084	None,1085	Rmrk,1086}10871088impl PropertyScope {1089	/// Apply scope to property key.1090	pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1091		let scope_str: &[u8] = match self {1092			Self::None => return Ok(key),1093			Self::Rmrk => b"rmrk",1094		};10951096		[scope_str, b":", key.as_slice()]1097			.concat()1098			.try_into()1099			.map_err(|_| PropertiesError::PropertyKeyIsTooLong)1100	}1101}11021103/// Trait for operate with properties.1104pub trait TrySetProperty: Sized {1105	type Value;11061107	/// Try to set property with scope.1108	fn try_scoped_set(1109		&mut self,1110		scope: PropertyScope,1111		key: PropertyKey,1112		value: Self::Value,1113	) -> Result<(), PropertiesError>;11141115	/// Try to set property with scope from iterator.1116	fn try_scoped_set_from_iter<I, KV>(1117		&mut self,1118		scope: PropertyScope,1119		iter: I,1120	) -> Result<(), PropertiesError>1121	where1122		I: Iterator<Item = KV>,1123		KV: Into<(PropertyKey, Self::Value)>,1124	{1125		for kv in iter {1126			let (key, value) = kv.into();1127			self.try_scoped_set(scope, key, value)?;1128		}11291130		Ok(())1131	}11321133	/// Try to set property.1134	fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {1135		self.try_scoped_set(PropertyScope::None, key, value)1136	}11371138	/// Try to set property from iterator.1139	fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1140	where1141		I: Iterator<Item = KV>,1142		KV: Into<(PropertyKey, Self::Value)>,1143	{1144		self.try_scoped_set_from_iter(PropertyScope::None, iter)1145	}1146}11471148/// Wrapped map for storing properties.1149#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1150#[derivative(Default(bound = ""))]1151pub struct PropertiesMap<Value>(1152	BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1153);11541155impl<Value> PropertiesMap<Value> {1156	/// Create new property map.1157	pub fn new() -> Self {1158		Self(BoundedBTreeMap::new())1159	}11601161	/// Remove property from map.1162	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1163		Self::check_property_key(key)?;11641165		Ok(self.0.remove(key))1166	}11671168	/// Get property with appropriate key from map.1169	pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1170		self.0.get(key)1171	}11721173	/// Check if map contains key.1174	pub fn contains_key(&self, key: &PropertyKey) -> bool {1175		self.0.contains_key(key)1176	}11771178	/// Check if map contains key with key validation.1179	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1180		if key.is_empty() {1181			return Err(PropertiesError::EmptyPropertyKey);1182		}11831184		for byte in key.as_slice().iter() {1185			let byte = *byte;11861187			if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1188				return Err(PropertiesError::InvalidCharacterInPropertyKey);1189			}1190		}11911192		Ok(())1193	}1194}11951196impl<Value> IntoIterator for PropertiesMap<Value> {1197	type Item = (PropertyKey, Value);1198	type IntoIter = <1199		BoundedBTreeMap<1200			PropertyKey,1201			Value,1202			ConstU32<MAX_PROPERTIES_PER_ITEM>1203		> as IntoIterator1204	>::IntoIter;12051206	fn into_iter(self) -> Self::IntoIter {1207		self.0.into_iter()1208	}1209}12101211impl<Value> TrySetProperty for PropertiesMap<Value> {1212	type Value = Value;12131214	fn try_scoped_set(1215		&mut self,1216		scope: PropertyScope,1217		key: PropertyKey,1218		value: Self::Value,1219	) -> Result<(), PropertiesError> {1220		Self::check_property_key(&key)?;12211222		let key = scope.apply(key)?;1223		self.01224			.try_insert(key, value)1225			.map_err(|_| PropertiesError::PropertyLimitReached)?;12261227		Ok(())1228	}1229}12301231/// Alias for property permissions map.1232pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;12331234/// Wrapper for properties map with consumed space control.1235#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1236pub struct Properties {1237	map: PropertiesMap<PropertyValue>,1238	consumed_space: u32,1239	space_limit: u32,1240}12411242impl Properties {1243	/// Create new properies container.1244	pub fn new(space_limit: u32) -> Self {1245		Self {1246			map: PropertiesMap::new(),1247			consumed_space: 0,1248			space_limit,1249		}1250	}12511252	/// Remove propery with appropiate key.1253	pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1254		let value = self.map.remove(key)?;12551256		if let Some(ref value) = value {1257			let value_len = value.len() as u32;1258			self.consumed_space -= value_len;1259		}12601261		Ok(value)1262	}12631264	/// Get property with appropriate key.1265	pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1266		self.map.get(key)1267	}1268}12691270impl IntoIterator for Properties {1271	type Item = (PropertyKey, PropertyValue);1272	type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;12731274	fn into_iter(self) -> Self::IntoIter {1275		self.map.into_iter()1276	}1277}12781279impl TrySetProperty for Properties {1280	type Value = PropertyValue;12811282	fn try_scoped_set(1283		&mut self,1284		scope: PropertyScope,1285		key: PropertyKey,1286		value: Self::Value,1287	) -> Result<(), PropertiesError> {1288		let value_len = value.len();12891290		if self.consumed_space as usize + value_len > self.space_limit as usize1291			&& !cfg!(feature = "runtime-benchmarks")1292		{1293			return Err(PropertiesError::NoSpaceForProperty);1294		}12951296		self.map.try_scoped_set(scope, key, value)?;12971298		self.consumed_space += value_len as u32;12991300		Ok(())1301	}1302}13031304/// Utility struct for using in `StorageMap`.1305pub struct CollectionProperties;13061307impl Get<Properties> for CollectionProperties {1308	fn get() -> Properties {1309		Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)1310	}1311}13121313/// Utility struct for using in `StorageMap`.1314pub struct TokenProperties;13151316impl Get<Properties> for TokenProperties {1317	fn get() -> Properties {1318		Properties::new(MAX_TOKEN_PROPERTIES_SIZE)1319	}1320}13211322// RMRK1323// todo document?1324parameter_types! {1325	#[derive(PartialEq, TypeInfo)]1326	pub const RmrkStringLimit: u32 = 128;1327	#[derive(PartialEq)]1328	pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;1329	#[derive(PartialEq)]1330	pub const RmrkResourceSymbolLimit: u32 = 10;1331	#[derive(PartialEq)]1332	pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;1333	#[derive(PartialEq)]1334	pub const RmrkKeyLimit: u32 = 32;1335	#[derive(PartialEq)]1336	pub const RmrkValueLimit: u32 = 256;1337	#[derive(PartialEq)]1338	pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;1339	#[derive(PartialEq)]1340	pub const MaxPropertiesPerTheme: u32 = 5;1341	#[derive(PartialEq)]1342	pub const RmrkPartsLimit: u32 = 25;1343	#[derive(PartialEq)]1344	pub const RmrkMaxPriorities: u32 = 25;1345	#[derive(PartialEq)]1346	pub const MaxResourcesOnMint: u32 = 100;1347}13481349impl From<RmrkCollectionId> for CollectionId {1350	fn from(id: RmrkCollectionId) -> Self {1351		Self(id)1352	}1353}13541355impl From<RmrkNftId> for TokenId {1356	fn from(id: RmrkNftId) -> Self {1357		Self(id)1358	}1359}13601361pub type RmrkCollectionInfo<AccountId> =1362	CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;1363pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;1364pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;1365pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;1366pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;1367pub type BoundedEquippableCollectionIds =1368	BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;1369pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;1370pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;1371pub type RmrkThemeProperty = ThemeProperty<RmrkString>;1372pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;1373pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;1374pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;13751376pub type RmrkBasicResource = BasicResource<RmrkString>;1377pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;1378pub type RmrkSlotResource = SlotResource<RmrkString>;13791380pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;1381pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;1382pub type RmrkBaseSymbol = BoundedVec<u8, RmrkBaseSymbolLimit>;1383pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;1384pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;1385pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;1386pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed13871388pub type RmrkRpcString = Vec<u8>;1389pub type RmrkThemeName = RmrkRpcString;1390pub type RmrkPropertyKey = RmrkRpcString;
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -16,9 +16,11 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
+extern crate alloc;
+
 use up_data_structs::{
 	CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,
-	PropertyKeyPermission, TokenData, TokenChild,
+	PropertyKeyPermission, TokenData, TokenChild, RpcCollectionVersion1,
 };
 
 use sp_std::vec::Vec;
@@ -28,15 +30,12 @@
 type Result<T> = core::result::Result<T, DispatchError>;
 
 sp_api::decl_runtime_apis! {
-	#[api_version(2)]
+	#[api_version(3)]
 	/// Trait for generate rpc.
 	pub trait UniqueApi<CrossAccountId, AccountId> where
 		AccountId: Decode,
 		CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
 	{
-		#[changed_in(2)]
-		fn token_owner(collection: CollectionId, token: TokenId) -> Result<CrossAccountId>;
-
 		/// Get number of tokens in collection owned by account.
 		fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;
 
@@ -110,6 +109,9 @@
 		/// Get collection by id.
 		fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;
 
+		#[changed_in(3)]
+		fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollectionVersion1<AccountId>>>;
+
 		/// Get collection stats.
 		fn collection_stats() -> Result<CollectionStats>;