difftreelog
Merge pull request #910 from UniqueNetwork/fix/versioning-of-rpc-collection
in: master
Fix versioning of RpcCollection
3 files changed
client/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);
primitives/data-structs/src/lib.rsdiffbeforeafterboth1// 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>;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}primitives/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>;