difftreelog
refactor remove redundant foreign flag, use foreign-assets pallet instead
in: master
8 files changed
pallets/balances-adapter/src/common.rsdiffbeforeafterboth--- a/pallets/balances-adapter/src/common.rs
+++ b/pallets/balances-adapter/src/common.rs
@@ -368,10 +368,6 @@
}
impl<T: Config> pallet_common::XcmExtensions<T> for NativeFungibleHandle<T> {
- fn is_foreign(&self) -> bool {
- false
- }
-
fn create_item_internal(
&self,
_depositor: &<T>::CrossAccountId,
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1088,7 +1088,6 @@
read_only: flags.external,
flags: RpcCollectionFlags {
- foreign: flags.foreign,
erc721metadata: flags.erc721metadata,
},
})
@@ -1128,17 +1127,17 @@
/// Create new collection.
///
/// * `owner` - The owner of the collection.
+ /// * `payer` - If set, the user that will pay a deposit for the collection creation.
/// * `data` - Description of the created collection.
- /// * `flags` - Extra flags to store.
pub fn init_collection(
owner: T::CrossAccountId,
- payer: T::CrossAccountId,
+ payer: Option<T::CrossAccountId>,
data: CreateCollectionData<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
ensure!(data.flags.is_allowed_for_user(), <Error<T>>::NoPermission);
// Take a (non-refundable) deposit of collection creation
- {
+ if let Some(payer) = payer {
let mut imbalance = <Debt<T::AccountId, <T as Config>::Currency>>::zero();
imbalance.subsume(<T as Config>::Currency::deposit(
&T::TreasuryAccountId::get(),
@@ -1153,16 +1152,6 @@
}
Self::init_collection_internal(owner, data)
- }
-
- /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.
- pub fn init_foreign_collection(
- owner: T::CrossAccountId,
- mut data: CreateCollectionData<T::CrossAccountId>,
- ) -> Result<CollectionId, DispatchError> {
- data.flags.foreign = true;
- let id = Self::init_collection_internal(owner, data)?;
- Ok(id)
}
fn init_collection_internal(
@@ -2348,9 +2337,6 @@
where
T: Config,
{
- /// Is the collection a foreign one?
- fn is_foreign(&self) -> bool;
-
/// Does the token have children?
fn token_has_children(&self, _token: TokenId) -> bool {
false
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/lib.rs
+++ b/pallets/foreign-assets/src/lib.rs
@@ -304,11 +304,10 @@
/// If the `asset_instance` is a part of a local collection,
/// the function will return either `Ok(Some(<token ID>))` or an error if the token is not found.
fn asset_instance_to_token_id(
- xcm_ext: &dyn XcmExtensions<T>,
collection_id: CollectionId,
asset_instance: &AssetInstance,
) -> Result<Option<TokenId>, XcmError> {
- if xcm_ext.is_foreign() {
+ if <CollectionToForeignReserveLocation<T>>::contains_key(collection_id) {
Ok(Self::foreign_reserve_asset_instance_to_token_id(
collection_id,
asset_instance,
@@ -363,7 +362,7 @@
to: T::CrossAccountId,
) -> XcmResult {
let deposit_result = if let Some(token_id) =
- Self::asset_instance_to_token_id(xcm_ext, collection_id, asset_instance)?
+ Self::asset_instance_to_token_id(collection_id, asset_instance)?
{
let depositor = &Self::pallet_account();
let from = depositor;
@@ -389,7 +388,7 @@
asset_instance: &AssetInstance,
from: T::CrossAccountId,
) -> XcmResult {
- let token_id = Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?
+ let token_id = Self::asset_instance_to_token_id(collection_id, &asset_instance)?
.ok_or(XcmError::AssetNotFound)?;
if xcm_ext.token_has_children(token_id) {
@@ -517,9 +516,8 @@
}
Fungibility::NonFungible(asset_instance) => {
- token_id =
- Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)?
- .ok_or(XcmError::AssetNotFound)?;
+ token_id = Self::asset_instance_to_token_id(collection_id, &asset_instance)?
+ .ok_or(XcmError::AssetNotFound)?;
amount = 1;
map_error = |_| XcmError::FailedToTransactAsset("nonfungible item transfer failed")
@@ -542,17 +540,11 @@
if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {
Some(Here.into())
} else {
- let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?;
- let collection = dispatch.as_dyn();
- let xcm_ext = collection.xcm_extensions()?;
-
- if xcm_ext.is_foreign() {
- <Pallet<T>>::collection_to_foreign_reserve_location(collection_id)
- } else {
+ <Pallet<T>>::collection_to_foreign_reserve_location(collection_id).or_else(|| {
T::SelfLocation::get()
.pushed_with_interior(GeneralIndex(collection_id.0.into()))
.ok()
- }
+ })
}
}
}
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -459,10 +459,6 @@
}
impl<T: Config> XcmExtensions<T> for FungibleHandle<T> {
- fn is_foreign(&self) -> bool {
- self.flags.foreign
- }
-
fn create_item_internal(
&self,
depositor: &<T>::CrossAccountId,
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -572,10 +572,6 @@
}
impl<T: Config> XcmExtensions<T> for NonfungibleHandle<T> {
- fn is_foreign(&self) -> bool {
- self.flags.foreign
- }
-
fn token_has_children(&self, token: TokenId) -> bool {
<Pallet<T>>::token_has_children(self.id, token)
}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -306,7 +306,7 @@
payer: T::CrossAccountId,
data: CreateCollectionData<T::CrossAccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, payer, data)
+ <PalletCommon<T>>::init_collection(owner, Some(payer), data)
}
/// Destroy RFT collection
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 ops::Deref,27};2829use bondrewd::Bitfields;30use derivative::Derivative;31use evm_coder::AbiCoderFlags;32use frame_support::{33 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},34 traits::ConstU32,35 BoundedVec,36};37use parity_scale_codec::{Decode, Encode, EncodeLike, MaxEncodedLen};38use scale_info::TypeInfo;39use serde::{Deserialize, Serialize};40use sp_core::U256;41use sp_runtime::{sp_std::prelude::Vec, ArithmeticError};42use sp_std::collections::btree_set::BTreeSet;4344mod bondrewd_codec;45mod bounded;46pub mod budget;47pub mod mapping;48mod migration;4950/// Maximum of decimal points.51pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;5253/// Maximum pieces for refungible token.54pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;55pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5657/// Maximum tokens for user.58pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {59 100_000_00060} else {61 1062};6364/// Maximum for collections can be created.65pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {66 100_00067} else {68 1069};7071/// Maximum for various custom data of token.72pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {73 204874} else {75 1076};7778/// Maximum admins per collection.79pub const COLLECTION_ADMINS_LIMIT: u32 = 5;8081/// Maximum tokens per collection.82pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;8384/// Maximum tokens per account.85pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {86 100_000_00087} else {88 1089};9091/// Default timeout for transfer sponsoring NFT item.92pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;93/// Default timeout for transfer sponsoring fungible item.94pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;95/// Default timeout for transfer sponsoring refungible item.96pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;9798/// Default timeout for sponsored approving.99pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;100101// Schema limits102pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;103pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;104pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;105106// TODO: not used. Delete?107pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;108109/// Maximal length of a collection name.110pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;111112/// Maximal length of a collection description.113pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;114115/// Maximal length of a token prefix.116pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;117118/// Maximal length of a property key.119pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;120121/// Maximal length of a property value.122pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;123124/// A maximum number of token properties.125pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;126127/// Maximal lenght of extended property value.128pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;129130/// Maximum size for all collection properties.131pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;132133/// Maximum size of all token properties.134pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;135136/// How much items can be created per single137/// create_many call.138pub const MAX_ITEMS_PER_BATCH: u32 = 120;139140/// Used for limit bounded types of token custom data.141pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;142143/// Collection id.144#[derive(145 Encode,146 Decode,147 PartialEq,148 Eq,149 PartialOrd,150 Ord,151 Clone,152 Copy,153 Debug,154 Default,155 TypeInfo,156 MaxEncodedLen,157 Serialize,158 Deserialize,159)]160pub struct CollectionId(pub u32);161impl EncodeLike<u32> for CollectionId {}162impl EncodeLike<CollectionId> for u32 {}163164impl From<u32> for CollectionId {165 fn from(value: u32) -> Self {166 Self(value)167 }168}169170impl Deref for CollectionId {171 type Target = u32;172173 fn deref(&self) -> &Self::Target {174 &self.0175 }176}177178/// Token id.179#[derive(180 Encode,181 Decode,182 PartialEq,183 Eq,184 PartialOrd,185 Ord,186 Clone,187 Copy,188 Debug,189 Default,190 TypeInfo,191 MaxEncodedLen,192 Serialize,193 Deserialize,194)]195pub struct TokenId(pub u32);196impl EncodeLike<u32> for TokenId {}197impl EncodeLike<TokenId> for u32 {}198199impl TokenId {200 /// Try to get next token id.201 ///202 /// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.203 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {204 self.0205 .checked_add(1)206 .ok_or(ArithmeticError::Overflow)207 .map(Self)208 }209}210211impl From<TokenId> for U256 {212 fn from(t: TokenId) -> Self {213 t.0.into()214 }215}216217impl TryFrom<U256> for TokenId {218 type Error = &'static str;219220 fn try_from(value: U256) -> Result<Self, Self::Error> {221 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))222 }223}224225/// Token data.226#[struct_versioning::versioned(version = 2, upper)]227#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]228pub struct TokenData<CrossAccountId> {229 /// Properties of token.230 pub properties: Vec<Property>,231232 /// Token owner.233 pub owner: Option<CrossAccountId>,234235 /// Token pieces.236 #[version(2.., upper(0))]237 pub pieces: u128,238}239240// TODO: unused type241pub struct OverflowError;242impl From<OverflowError> for &'static str {243 fn from(_: OverflowError) -> Self {244 "overflow occured"245 }246}247248/// Alias for decimal points type.249pub type DecimalPoints = u8;250251/// Collection mode.252///253/// Collection can represent various types of tokens.254/// Each collection can contain only one type of tokens at a time.255/// This type helps to understand which tokens the collection contains.256#[derive(257 Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,258)]259pub enum CollectionMode {260 /// Non fungible tokens.261 NFT,262 /// Fungible tokens.263 Fungible(DecimalPoints),264 /// Refungible tokens.265 ReFungible,266}267268impl CollectionMode {269 /// Get collection mod as number.270 pub fn id(&self) -> u8 {271 match self {272 CollectionMode::NFT => 1,273 CollectionMode::Fungible(_) => 2,274 CollectionMode::ReFungible => 3,275 }276 }277}278279// TODO: unused trait280pub trait SponsoringResolve<AccountId, Call> {281 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;282}283284/// Access mode for some token operations.285#[derive(286 Encode,287 Decode,288 Eq,289 Debug,290 Clone,291 Copy,292 PartialEq,293 TypeInfo,294 MaxEncodedLen,295 Serialize,296 Deserialize,297)]298pub enum AccessMode {299 /// Access grant for owner and admins. Used as default.300 Normal,301 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.302 AllowList,303}304impl Default for AccessMode {305 fn default() -> Self {306 Self::Normal307 }308}309310// TODO: remove in future.311#[derive(312 Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,313)]314pub enum SchemaVersion {315 ImageURL,316 Unique,317}318impl Default for SchemaVersion {319 fn default() -> Self {320 Self::ImageURL321 }322}323324// TODO: unused type325#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]326pub struct Ownership<AccountId> {327 pub owner: AccountId,328 pub fraction: u128,329}330331/// The state of collection sponsorship.332#[derive(333 Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,334)]335pub enum SponsorshipState<AccountId> {336 /// The fees are applied to the transaction sender.337 Disabled,338 /// The sponsor is under consideration. Until the sponsor gives his consent,339 /// the fee will still be charged to sender.340 Unconfirmed(AccountId),341 /// Transactions are sponsored by specified account.342 Confirmed(AccountId),343}344345impl<AccountId> SponsorshipState<AccountId> {346 /// Get a sponsor of the collection who has confirmed his status.347 pub fn sponsor(&self) -> Option<&AccountId> {348 match self {349 Self::Confirmed(sponsor) => Some(sponsor),350 _ => None,351 }352 }353354 /// Get a sponsor of the collection who has pending or confirmed status.355 pub fn pending_sponsor(&self) -> Option<&AccountId> {356 match self {357 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),358 _ => None,359 }360 }361362 /// Whether the sponsorship is confirmed.363 pub fn confirmed(&self) -> bool {364 matches!(self, Self::Confirmed(_))365 }366}367368impl<T> Default for SponsorshipState<T> {369 fn default() -> Self {370 Self::Disabled371 }372}373374pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;375pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;376pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;377378#[derive(AbiCoderFlags, Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]379#[bondrewd(enforce_bytes = 1)]380pub struct CollectionFlags {381 /// Reserved flag382 #[bondrewd(bits = "0..1")]383 pub reserved_0: bool,384 /// Supports ERC721Metadata385 #[bondrewd(bits = "1..2")]386 pub erc721metadata: bool,387 /// External collections can't be managed using `unique` api388 #[bondrewd(bits = "7..8")]389 pub external: bool,390 /// Reserved flags391 #[bondrewd(bits = "2..7")]392 pub reserved: u8,393}394bondrewd_codec!(CollectionFlags);395396impl CollectionFlags {397 pub fn is_allowed_for_user(self) -> bool {398 !self.reserved_0 && !self.external && self.reserved == 0399 }400}401402/// Base structure for represent collection.403///404/// Used to provide basic functionality for all types of collections.405///406/// #### Note407/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).408#[struct_versioning::versioned(version = 2, upper)]409#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]410pub struct Collection<AccountId> {411 /// Collection owner account.412 pub owner: AccountId,413414 /// Collection mode.415 pub mode: CollectionMode,416417 /// Access mode.418 #[version(..2)]419 pub access: AccessMode,420421 /// Collection name.422 pub name: CollectionName,423424 /// Collection description.425 pub description: CollectionDescription,426427 /// Token prefix.428 pub token_prefix: CollectionTokenPrefix,429430 #[version(..2)]431 pub mint_mode: bool,432433 #[version(..2)]434 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,435436 #[version(..2)]437 pub schema_version: SchemaVersion,438439 /// The state of sponsorship of the collection.440 pub sponsorship: SponsorshipState<AccountId>,441442 /// Collection limits.443 pub limits: CollectionLimits,444445 /// Collection permissions.446 #[version(2.., upper(Default::default()))]447 pub permissions: CollectionPermissions,448449 #[version(2.., upper(Default::default()))]450 pub flags: CollectionFlags,451452 #[version(..2)]453 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,454455 #[version(..2)]456 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,457458 #[version(..2)]459 pub meta_update_permission: MetaUpdatePermission,460}461462#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]463pub struct RpcCollectionFlags {464 /// Collection supports ERC721Metadata.465 pub erc721metadata: bool,466}467468/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).469#[struct_versioning::versioned(version = 2, upper)]470#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo, Serialize, Deserialize)]471pub struct RpcCollection<AccountId> {472 /// Collection owner account.473 pub owner: AccountId,474475 /// Collection mode.476 pub mode: CollectionMode,477478 /// Collection name.479 pub name: Vec<u16>,480481 /// Collection description.482 pub description: Vec<u16>,483484 /// Token prefix.485 pub token_prefix: Vec<u8>,486487 /// The state of sponsorship of the collection.488 pub sponsorship: SponsorshipState<AccountId>,489490 /// Collection limits.491 pub limits: CollectionLimits,492493 /// Collection permissions.494 pub permissions: CollectionPermissions,495496 /// Token property permissions.497 pub token_property_permissions: Vec<PropertyKeyPermission>,498499 /// Collection properties.500 pub properties: Vec<Property>,501502 /// Is collection read only.503 pub read_only: bool,504505 /// Extra collection flags506 #[version(2.., upper(RpcCollectionFlags {erc721metadata: false}))]507 pub flags: RpcCollectionFlags,508}509510impl<AccountId> From<CollectionVersion1<AccountId>> for RpcCollection<AccountId> {511 fn from(value: CollectionVersion1<AccountId>) -> Self {512 let CollectionVersion1 {513 name,514 description,515 owner,516 mode,517 access,518 token_prefix,519 mint_mode,520 sponsorship,521 limits,522 ..523 } = value;524525 RpcCollection {526 name: name.into_inner(),527 description: description.into_inner(),528 owner,529 mode,530 token_prefix: token_prefix.into_inner(),531 sponsorship,532 limits,533 permissions: CollectionPermissions {534 access: Some(access),535 mint_mode: Some(mint_mode),536 nesting: None,537 },538 token_property_permissions: Vec::default(),539 properties: Vec::default(),540 read_only: true,541542 flags: RpcCollectionFlags {543 erc721metadata: false,544 },545 }546 }547}548549pub struct RawEncoded(Vec<u8>);550551impl parity_scale_codec::Decode for RawEncoded {552 fn decode<I: parity_scale_codec::Input>(553 input: &mut I,554 ) -> Result<Self, parity_scale_codec::Error> {555 let mut out = Vec::new();556 while let Ok(v) = input.read_byte() {557 out.push(v);558 }559 Ok(Self(out))560 }561}562563impl Deref for RawEncoded {564 type Target = Vec<u8>;565566 fn deref(&self) -> &Self::Target {567 &self.0568 }569}570571/// Data used for create collection.572///573/// All fields are wrapped in [`Option`], where `None` means chain default.574#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]575#[derivative(Debug, Default(bound = ""))]576pub struct CreateCollectionData<CrossAccountId> {577 /// Collection mode.578 #[derivative(Default(value = "CollectionMode::NFT"))]579 pub mode: CollectionMode,580581 /// Access mode.582 pub access: Option<AccessMode>,583584 /// Collection name.585 pub name: CollectionName,586587 /// Collection description.588 pub description: CollectionDescription,589590 /// Token prefix.591 pub token_prefix: CollectionTokenPrefix,592593 /// Collection limits.594 pub limits: Option<CollectionLimits>,595596 /// Collection permissions.597 pub permissions: Option<CollectionPermissions>,598599 /// Token property permissions.600 pub token_property_permissions: CollectionPropertiesPermissionsVec,601602 /// Collection properties.603 pub properties: CollectionPropertiesVec,604605 pub admin_list: Vec<CrossAccountId>,606607 /// Pending collection sponsor.608 pub pending_sponsor: Option<CrossAccountId>,609610 pub flags: CollectionFlags,611}612613/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].614// TODO: maybe rename to PropertiesPermissionsVec615pub type CollectionPropertiesPermissionsVec =616 BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;617618/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].619pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;620621/// Limits and restrictions of a collection.622///623/// All fields are wrapped in [`Option`], where `None` means chain default.624///625/// Update with `pallet_common::Pallet::clamp_limits`.626// IMPORTANT: When adding/removing fields from this struct - don't forget to also627#[derive(628 Encode,629 Decode,630 Debug,631 Default,632 Clone,633 PartialEq,634 TypeInfo,635 MaxEncodedLen,636 Serialize,637 Deserialize,638)]639// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.640// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.641// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.642pub struct CollectionLimits {643 /// How many tokens can a user have on one account.644 /// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].645 /// * Limit - [`MAX_TOKEN_OWNERSHIP`].646 pub account_token_ownership_limit: Option<u32>,647648 /// How many bytes of data are available for sponsorship.649 /// * Default - [`CUSTOM_DATA_LIMIT`].650 /// * Limit - [`CUSTOM_DATA_LIMIT`].651 pub sponsored_data_size: Option<u32>,652653 // FIXME should we delete this or repurpose it?654 /// Times in how many blocks we sponsor data.655 ///656 /// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.657 ///658 /// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).659 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].660 ///661 /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]662 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,663 /// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]664665 /// How many tokens can be mined into this collection.666 ///667 /// * Default - [`COLLECTION_TOKEN_LIMIT`].668 /// * Limit - [`COLLECTION_TOKEN_LIMIT`].669 pub token_limit: Option<u32>,670671 /// Timeouts for transfer sponsoring.672 ///673 /// * Default674 /// - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]675 /// - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]676 /// - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]677 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].678 pub sponsor_transfer_timeout: Option<u32>,679680 /// Timeout for sponsoring an approval in passed blocks.681 ///682 /// * Default - [`SPONSOR_APPROVE_TIMEOUT`].683 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].684 pub sponsor_approve_timeout: Option<u32>,685686 /// Whether the collection owner of the collection can send tokens (which belong to other users).687 ///688 /// * Default - **false**.689 pub owner_can_transfer: Option<bool>,690691 /// Can the collection owner burn other people's tokens.692 ///693 /// * Default - **true**.694 pub owner_can_destroy: Option<bool>,695696 /// Is it possible to send tokens from this collection between users.697 ///698 /// * Default - **true**.699 pub transfers_enabled: Option<bool>,700}701702impl CollectionLimits {703 pub fn with_default_limits(collection_type: CollectionMode) -> Self {704 CollectionLimits {705 account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),706 sponsored_data_size: Some(CUSTOM_DATA_LIMIT),707 sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),708 token_limit: Some(COLLECTION_TOKEN_LIMIT),709 sponsor_transfer_timeout: match collection_type {710 CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),711 CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),712 CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),713 },714 sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),715 owner_can_transfer: Some(false),716 owner_can_destroy: Some(true),717 transfers_enabled: Some(true),718 }719 }720721 /// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).722 pub fn account_token_ownership_limit(&self) -> u32 {723 self.account_token_ownership_limit724 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)725 .min(MAX_TOKEN_OWNERSHIP)726 }727728 /// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).729 pub fn sponsored_data_size(&self) -> u32 {730 self.sponsored_data_size731 .unwrap_or(CUSTOM_DATA_LIMIT)732 .min(CUSTOM_DATA_LIMIT)733 }734735 /// Get effective value for [`token_limit`](self.token_limit).736 pub fn token_limit(&self) -> u32 {737 self.token_limit738 .unwrap_or(COLLECTION_TOKEN_LIMIT)739 .min(COLLECTION_TOKEN_LIMIT)740 }741742 // TODO: may be replace u32 to mode?743 /// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).744 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {745 self.sponsor_transfer_timeout746 .unwrap_or(default)747 .min(MAX_SPONSOR_TIMEOUT)748 }749750 /// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).751 pub fn sponsor_approve_timeout(&self) -> u32 {752 self.sponsor_approve_timeout753 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)754 .min(MAX_SPONSOR_TIMEOUT)755 }756757 /// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).758 pub fn owner_can_transfer(&self) -> bool {759 self.owner_can_transfer.unwrap_or(false)760 }761762 /// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).763 pub fn owner_can_transfer_instaled(&self) -> bool {764 self.owner_can_transfer.is_some()765 }766767 /// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).768 pub fn owner_can_destroy(&self) -> bool {769 self.owner_can_destroy.unwrap_or(true)770 }771772 /// Get effective value for [`transfers_enabled`](self.transfers_enabled).773 pub fn transfers_enabled(&self) -> bool {774 self.transfers_enabled.unwrap_or(true)775 }776777 /// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).778 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {779 match self780 .sponsored_data_rate_limit781 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)782 {783 SponsoringRateLimit::SponsoringDisabled => None,784 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),785 }786 }787}788789/// Permissions on certain operations within a collection.790///791/// Some fields are wrapped in [`Option`], where `None` means chain default.792///793/// Update with `pallet_common::Pallet::clamp_permissions`.794#[derive(795 Encode,796 Decode,797 Debug,798 Default,799 Clone,800 PartialEq,801 TypeInfo,802 MaxEncodedLen,803 Serialize,804 Deserialize,805)]806// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.807// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.808pub struct CollectionPermissions {809 /// Access mode.810 ///811 /// * Default - [`AccessMode::Normal`].812 pub access: Option<AccessMode>,813814 /// Minting allowance.815 ///816 /// * Default - **false**.817 pub mint_mode: Option<bool>,818819 /// Permissions for nesting.820 ///821 /// * Default822 /// - `token_owner` - **false**823 /// - `collection_admin` - **false**824 /// - `restricted` - **None**825 pub nesting: Option<NestingPermissions>,826}827828impl CollectionPermissions {829 /// Get effective value for [`access`](self.access).830 pub fn access(&self) -> AccessMode {831 self.access.unwrap_or(AccessMode::Normal)832 }833834 /// Get effective value for [`mint_mode`](self.mint_mode).835 pub fn mint_mode(&self) -> bool {836 self.mint_mode.unwrap_or(false)837 }838839 /// Get effective value for [`nesting`](self.nesting).840 pub fn nesting(&self) -> &NestingPermissions {841 static DEFAULT: NestingPermissions = NestingPermissions {842 token_owner: false,843 collection_admin: false,844 restricted: None,845 #[cfg(feature = "runtime-benchmarks")]846 permissive: false,847 };848 self.nesting.as_ref().unwrap_or(&DEFAULT)849 }850}851852/// Inner set for collections allowed to nest.853type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;854855/// Wraper for collections set allowing nest.856#[derive(857 Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative, Serialize, Deserialize,858)]859#[derivative(Debug)]860pub struct OwnerRestrictedSet(861 #[serde(with = "bounded::set_serde")]862 #[derivative(Debug(format_with = "bounded::set_debug"))]863 pub OwnerRestrictedSetInner,864);865866impl OwnerRestrictedSet {867 /// Create new set.868 pub fn new() -> Self {869 Self(Default::default())870 }871}872impl Default for OwnerRestrictedSet {873 fn default() -> Self {874 Self::new()875 }876}877impl core::ops::Deref for OwnerRestrictedSet {878 type Target = OwnerRestrictedSetInner;879 fn deref(&self) -> &Self::Target {880 &self.0881 }882}883impl core::ops::DerefMut for OwnerRestrictedSet {884 fn deref_mut(&mut self) -> &mut Self::Target {885 &mut self.0886 }887}888889impl TryFrom<BTreeSet<CollectionId>> for OwnerRestrictedSet {890 type Error = ();891892 fn try_from(value: BTreeSet<CollectionId>) -> Result<Self, Self::Error> {893 Ok(Self(value.try_into()?))894 }895}896897/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.898#[derive(899 Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative, Serialize, Deserialize,900)]901#[derivative(Debug)]902pub struct NestingPermissions {903 /// Owner of token can nest tokens under it.904 pub token_owner: bool,905 /// Admin of token collection can nest tokens under token.906 pub collection_admin: bool,907 /// If set - only tokens from specified collections can be nested.908 pub restricted: Option<OwnerRestrictedSet>,909910 #[cfg(feature = "runtime-benchmarks")]911 /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.912 pub permissive: bool,913}914915/// Enum denominating how often can sponsoring occur if it is enabled.916///917/// Used for [`collection limits`](CollectionLimits).918#[derive(919 Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,920)]921pub enum SponsoringRateLimit {922 /// Sponsoring is disabled, and the collection sponsor will not pay for transactions923 SponsoringDisabled,924 /// Once per how many blocks can sponsorship of a transaction type occur925 Blocks(u32),926}927928/// Data used to describe an NFT at creation.929#[derive(930 Encode,931 Decode,932 MaxEncodedLen,933 Default,934 PartialEq,935 Clone,936 Derivative,937 TypeInfo,938 Serialize,939 Deserialize,940)]941#[derivative(Debug)]942pub struct CreateNftData {943 /// Key-value pairs used to describe the token as metadata944 #[serde(with = "bounded::vec_serde")]945 #[derivative(Debug(format_with = "bounded::vec_debug"))]946 /// Properties that wil be assignet to created item.947 pub properties: CollectionPropertiesVec,948}949950/// Data used to describe a Fungible token at creation.951#[derive(952 Encode,953 Decode,954 MaxEncodedLen,955 Default,956 Debug,957 Clone,958 PartialEq,959 TypeInfo,960 Serialize,961 Deserialize,962)]963pub struct CreateFungibleData {964 /// Number of fungible coins minted965 pub value: u128,966}967968/// Data used to describe a Refungible token at creation.969#[derive(970 Encode,971 Decode,972 MaxEncodedLen,973 Default,974 PartialEq,975 Clone,976 Derivative,977 TypeInfo,978 Serialize,979 Deserialize,980)]981#[derivative(Debug)]982pub struct CreateReFungibleData {983 /// Number of pieces the RFT is split into984 pub pieces: u128,985986 /// Key-value pairs used to describe the token as metadata987 #[serde(with = "bounded::vec_serde")]988 #[derivative(Debug(format_with = "bounded::vec_debug"))]989 pub properties: CollectionPropertiesVec,990}991992// TODO: remove this.993#[derive(994 Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen, Serialize, Deserialize,995)]996pub enum MetaUpdatePermission {997 ItemOwner,998 Admin,999 None,1000}10011002/// Enum holding data used for creation of all three item types.1003/// Unified data for create item.1004#[derive(1005 Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1006)]1007pub enum CreateItemData {1008 /// Data for create NFT.1009 NFT(CreateNftData),1010 /// Data for create Fungible item.1011 Fungible(CreateFungibleData),1012 /// Data for create ReFungible item.1013 ReFungible(CreateReFungibleData),1014}10151016/// Extended data for create NFT.1017#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1018#[derivative(Debug)]1019pub struct CreateNftExData<CrossAccountId> {1020 /// Properties that wil be assignet to created item.1021 #[derivative(Debug(format_with = "bounded::vec_debug"))]1022 pub properties: CollectionPropertiesVec,10231024 /// Owner of creating item.1025 pub owner: CrossAccountId,1026}10271028/// Extended data for create ReFungible item.1029#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1030#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]1031pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {1032 #[derivative(Debug(format_with = "bounded::map_debug"))]1033 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,1034 #[derivative(Debug(format_with = "bounded::vec_debug"))]1035 pub properties: CollectionPropertiesVec,1036}10371038/// Extended data for create ReFungible item.1039#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1040#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]1041pub struct CreateRefungibleExSingleOwner<CrossAccountId> {1042 pub user: CrossAccountId,1043 pub pieces: u128,1044 #[derivative(Debug(format_with = "bounded::vec_debug"))]1045 pub properties: CollectionPropertiesVec,1046}10471048/// Unified extended data for creating item.1049#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]1050#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]1051pub enum CreateItemExData<CrossAccountId> {1052 /// Extended data for create NFT.1053 NFT(1054 #[derivative(Debug(format_with = "bounded::vec_debug"))]1055 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,1056 ),10571058 /// Extended data for create Fungible item.1059 Fungible(1060 #[derivative(Debug(format_with = "bounded::map_debug"))]1061 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,1062 ),10631064 /// Extended data for create ReFungible item in case of1065 /// many tokens, each may have only one owner1066 RefungibleMultipleItems(1067 #[derivative(Debug(format_with = "bounded::vec_debug"))]1068 BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,1069 ),10701071 /// Extended data for create ReFungible item in case of1072 /// single token, which may have many owners1073 RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),1074}10751076impl From<CreateNftData> for CreateItemData {1077 fn from(item: CreateNftData) -> Self {1078 CreateItemData::NFT(item)1079 }1080}10811082impl From<CreateReFungibleData> for CreateItemData {1083 fn from(item: CreateReFungibleData) -> Self {1084 CreateItemData::ReFungible(item)1085 }1086}10871088impl From<CreateFungibleData> for CreateItemData {1089 fn from(item: CreateFungibleData) -> Self {1090 CreateItemData::Fungible(item)1091 }1092}10931094/// Token's address, dictated by its collection and token IDs.1095#[derive(1096 Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1097)]1098// todo possibly rename to be used generally as an address pair1099pub struct TokenChild {1100 /// Token id.1101 pub token: TokenId,11021103 /// Collection id.1104 pub collection: CollectionId,1105}11061107/// Collection statistics.1108#[derive(1109 Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo, Serialize, Deserialize,1110)]1111pub struct CollectionStats {1112 /// Number of created items.1113 pub created: u32,11141115 /// Number of burned items.1116 pub destroyed: u32,11171118 /// Number of current items.1119 pub alive: u32,1120}11211122/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1123#[derive(Encode, Decode, Clone, Debug)]1124#[cfg_attr(feature = "std", derive(PartialEq))]1125pub struct PhantomType<T>(core::marker::PhantomData<T>);11261127impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1128 type Identity = PhantomType<T>;11291130 fn type_info() -> scale_info::Type {1131 use scale_info::{1132 build::{FieldsBuilder, UnnamedFields},1133 form::MetaForm,1134 type_params, Path, Type,1135 };1136 Type::builder()1137 .path(Path::new("up_data_structs", "PhantomType"))1138 .type_params(type_params!(T))1139 .composite(1140 <FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1141 )1142 }1143}1144impl<T> MaxEncodedLen for PhantomType<T> {1145 fn max_encoded_len() -> usize {1146 01147 }1148}11491150/// Bounded vector of bytes.1151pub type BoundedBytes<S> = BoundedVec<u8, S>;11521153/// Extra properties for external collections.1154pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;11551156/// Property key.1157pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;11581159/// Property value.1160pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;11611162/// Property permission.1163#[derive(1164 Encode,1165 Decode,1166 TypeInfo,1167 Debug,1168 MaxEncodedLen,1169 PartialEq,1170 Clone,1171 Default,1172 Serialize,1173 Deserialize,1174)]1175pub struct PropertyPermission {1176 /// Permission to change the property and property permission.1177 ///1178 /// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1179 pub mutable: bool,11801181 /// Change permission for the collection administrator.1182 pub collection_admin: bool,11831184 /// Permission to change the property for the owner of the token.1185 pub token_owner: bool,1186}11871188impl PropertyPermission {1189 /// Creates mutable property permission but changes restricted for collection admin and token owner.1190 pub fn none() -> Self {1191 Self {1192 mutable: true,1193 collection_admin: false,1194 token_owner: false,1195 }1196 }1197}11981199/// Property is simpl key-value record.1200#[derive(1201 Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen, Serialize, Deserialize,1202)]1203pub struct Property {1204 /// Property key.1205 #[serde(with = "bounded::vec_serde")]1206 pub key: PropertyKey,12071208 /// Property value.1209 #[serde(with = "bounded::vec_serde")]1210 pub value: PropertyValue,1211}12121213impl From<Property> for (PropertyKey, PropertyValue) {1214 fn from(value: Property) -> Self {1215 (value.key, value.value)1216 }1217}12181219/// Record for proprty key permission.1220#[derive(1221 Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Serialize, Deserialize,1222)]1223pub struct PropertyKeyPermission {1224 /// Key.1225 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1226 pub key: PropertyKey,12271228 /// Permission.1229 pub permission: PropertyPermission,1230}12311232impl From<PropertyKeyPermission> for (PropertyKey, PropertyPermission) {1233 fn from(value: PropertyKeyPermission) -> Self {1234 (value.key, value.permission)1235 }1236}12371238/// Errors for properties actions.1239#[derive(Debug)]1240pub enum PropertiesError {1241 /// The space allocated for properties has run out.1242 ///1243 /// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1244 /// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1245 NoSpaceForProperty,12461247 /// The property limit has been reached.1248 ///1249 /// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1250 PropertyLimitReached,12511252 /// Property key contains not allowed character.1253 InvalidCharacterInPropertyKey,12541255 /// Property key length is too long.1256 ///1257 /// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1258 PropertyKeyIsTooLong,12591260 /// Property key is empty.1261 EmptyPropertyKey,1262}12631264/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1265#[derive(Debug)]1266pub enum TokenOwnerError {1267 NotFound,1268 MultipleOwners,1269}12701271/// Marker for scope of property.1272///1273/// Scoped property can't be changed by user. Used for external collections.1274#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1275pub enum PropertyScope {1276 None,1277 Rmrk,1278}12791280impl PropertyScope {1281 pub fn prefix(&self) -> &'static [u8] {1282 match self {1283 Self::None => b"",1284 Self::Rmrk => b"rmrk:",1285 }1286 }1287 /// Apply scope to property key.1288 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1289 let prefix = self.prefix();1290 if prefix == b"" {1291 return Ok(key);1292 }1293 [prefix, key.as_slice()]1294 .concat()1295 .try_into()1296 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)1297 }1298}12991300/// Trait for operate with properties.1301pub trait TrySetProperty: Sized {1302 type Value;13031304 /// Try to set property with scope.1305 fn try_scoped_set(1306 &mut self,1307 scope: PropertyScope,1308 key: PropertyKey,1309 value: Self::Value,1310 ) -> Result<Option<Self::Value>, PropertiesError>;13111312 /// Try to set property with scope from iterator.1313 fn try_scoped_set_from_iter<I, KV>(1314 &mut self,1315 scope: PropertyScope,1316 iter: I,1317 ) -> Result<(), PropertiesError>1318 where1319 I: Iterator<Item = KV>,1320 KV: Into<(PropertyKey, Self::Value)>,1321 {1322 for kv in iter {1323 let (key, value) = kv.into();1324 self.try_scoped_set(scope, key, value)?;1325 }13261327 Ok(())1328 }13291330 /// Try to set property.1331 fn try_set(1332 &mut self,1333 key: PropertyKey,1334 value: Self::Value,1335 ) -> Result<Option<Self::Value>, PropertiesError> {1336 self.try_scoped_set(PropertyScope::None, key, value)1337 }13381339 /// Try to set property from iterator.1340 fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1341 where1342 I: Iterator<Item = KV>,1343 KV: Into<(PropertyKey, Self::Value)>,1344 {1345 self.try_scoped_set_from_iter(PropertyScope::None, iter)1346 }1347}13481349/// Wrapped map for storing properties.1350#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1351#[derivative(Default(bound = ""))]1352pub struct PropertiesMap<Value>(1353 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1354);13551356impl<Value> PropertiesMap<Value> {1357 /// Create new property map.1358 pub fn new() -> Self {1359 Self(BoundedBTreeMap::new())1360 }13611362 /// Remove property from map.1363 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1364 Self::check_property_key(key)?;13651366 Ok(self.0.remove(key))1367 }13681369 /// Get property with appropriate key from map.1370 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1371 self.0.get(key)1372 }13731374 /// Check if map contains key.1375 pub fn contains_key(&self, key: &PropertyKey) -> bool {1376 self.0.contains_key(key)1377 }13781379 /// Check if map contains key with key validation.1380 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1381 if key.is_empty() {1382 return Err(PropertiesError::EmptyPropertyKey);1383 }13841385 for byte in key.as_slice().iter() {1386 let byte = *byte;13871388 if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1389 return Err(PropertiesError::InvalidCharacterInPropertyKey);1390 }1391 }13921393 Ok(())1394 }13951396 pub fn values(&self) -> impl Iterator<Item = &Value> {1397 self.0.values()1398 }13991400 pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1401 self.0.iter()1402 }1403}14041405impl<Value> IntoIterator for PropertiesMap<Value> {1406 type Item = (PropertyKey, Value);1407 type IntoIter = <1408 BoundedBTreeMap<1409 PropertyKey,1410 Value,1411 ConstU32<MAX_PROPERTIES_PER_ITEM>1412 > as IntoIterator1413 >::IntoIter;14141415 fn into_iter(self) -> Self::IntoIter {1416 self.0.into_iter()1417 }1418}14191420impl<Value> TrySetProperty for PropertiesMap<Value> {1421 type Value = Value;14221423 fn try_scoped_set(1424 &mut self,1425 scope: PropertyScope,1426 key: PropertyKey,1427 value: Self::Value,1428 ) -> Result<Option<Self::Value>, PropertiesError> {1429 Self::check_property_key(&key)?;14301431 let key = scope.apply(key)?;1432 self.01433 .try_insert(key, value)1434 .map_err(|_| PropertiesError::PropertyLimitReached)1435 }1436}14371438/// Alias for property permissions map.1439pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;14401441fn slice_size(data: &[u8]) -> u32 {1442 scoped_slice_size(PropertyScope::None, data)1443}1444fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1445 use parity_scale_codec::Compact;1446 let prefix = scope.prefix();1447 <Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321448 + data.len() as u321449 + prefix.len() as u321450}14511452/// Wrapper for properties map with consumed space control.1453#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1454pub struct Properties<const S: u32> {1455 map: PropertiesMap<PropertyValue>,1456 consumed_space: u32,1457 // May be not zero, previously served as a current S generic1458 _reserved: u32,1459}14601461impl<const S: u32> MaxEncodedLen for Properties<S> {1462 fn max_encoded_len() -> usize {1463 // len of map + len of consumed_space + len of space_limit1464 u32::max_encoded_len() * 3 + S as usize1465 }1466}14671468impl<const S: u32> Default for Properties<S> {1469 fn default() -> Self {1470 Self::new()1471 }1472}14731474impl<const S: u32> Properties<S> {1475 /// Create new properies container.1476 pub fn new() -> Self {1477 Self {1478 map: PropertiesMap::new(),1479 consumed_space: 0,1480 _reserved: 0,1481 }1482 }14831484 /// Remove propery with appropiate key.1485 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1486 let value = self.map.remove(key)?;14871488 if let Some(ref value) = value {1489 let kv_len = slice_size(key) + slice_size(value);1490 self.consumed_space = self.consumed_space.saturating_sub(kv_len);1491 }14921493 Ok(value)1494 }14951496 /// Get property with appropriate key.1497 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1498 self.map.get(key)1499 }15001501 /// Recomputes the consumed space for the current properties state.1502 /// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1503 pub fn recompute_consumed_space(&mut self) {1504 self.consumed_space = self1505 .map1506 .iter()1507 .map(|(key, value)| slice_size(key) + slice_size(value))1508 .sum();1509 }1510}15111512impl<const S: u32> IntoIterator for Properties<S> {1513 type Item = (PropertyKey, PropertyValue);1514 type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;15151516 fn into_iter(self) -> Self::IntoIter {1517 self.map.into_iter()1518 }1519}15201521impl<const S: u32> TrySetProperty for Properties<S> {1522 type Value = PropertyValue;15231524 fn try_scoped_set(1525 &mut self,1526 scope: PropertyScope,1527 key: PropertyKey,1528 value: Self::Value,1529 ) -> Result<Option<Self::Value>, PropertiesError> {1530 let key_size = scoped_slice_size(scope, &key);1531 let value_size = slice_size(&value);15321533 if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1534 {1535 return Err(PropertiesError::NoSpaceForProperty);1536 }15371538 let old_value = self.map.try_scoped_set(scope, key, value)?;15391540 if let Some(old_value) = old_value.as_ref() {1541 let old_value_size = slice_size(old_value);1542 self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1543 } else {1544 self.consumed_space += key_size + value_size;1545 }15461547 Ok(old_value)1548 }1549}15501551pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1552pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;runtime/common/dispatch.rsdiffbeforeafterboth--- a/runtime/common/dispatch.rs
+++ b/runtime/common/dispatch.rs
@@ -86,7 +86,7 @@
_ => {}
};
- <PalletCommon<T>>::init_collection(sender, payer, data)
+ <PalletCommon<T>>::init_collection(sender, Some(payer), data)
}
fn create_foreign(
@@ -106,7 +106,8 @@
_ => {}
};
- <PalletCommon<T>>::init_foreign_collection(sender, data)
+ let payer = None;
+ <PalletCommon<T>>::init_collection(sender, payer, data)
}
fn destroy(sender: T::CrossAccountId, collection_id: CollectionId) -> DispatchResult {