difftreelog
Merge branch 'UniqueNetwork:develop' into develop
in: master
4 files changed
primitives/data-structs/src/bounded.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//! This module contins implementations for support bounded structures ([`BoundedVec`], [`BoundedBTreeMap`], [`BoundedBTreeSet`]) in [`serde`].181use core::fmt;19use core::fmt;2use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};20use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};7 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},8};26};92710/// BoundedVec doesn't supports serde28/// [`serde`] implementations for [`BoundedVec`].11#[cfg(feature = "serde1")]29#[cfg(feature = "serde1")]12pub mod vec_serde {30pub mod vec_serde {13 use core::convert::TryFrom;31 use core::convert::TryFrom;39 }57 }40}58}415960/// Format [`BoundedVec`] for debug output.42pub fn vec_debug<V, S>(v: &BoundedVec<V, S>, f: &mut fmt::Formatter) -> Result<(), fmt::Error>61pub fn vec_debug<V, S>(v: &BoundedVec<V, S>, f: &mut fmt::Formatter) -> Result<(), fmt::Error>43where62where44 V: fmt::Debug,63 V: fmt::Debug,496850#[cfg(feature = "serde1")]69#[cfg(feature = "serde1")]51#[allow(dead_code)]70#[allow(dead_code)]71/// [`serde`] implementations for [`BoundedBTreeMap`].52pub mod map_serde {72pub mod map_serde {53 use core::convert::TryFrom;73 use core::convert::TryFrom;54 use sp_std::collections::btree_map::BTreeMap;74 use sp_std::collections::btree_map::BTreeMap;84 }104 }85}105}86106107/// Format [`BoundedBTreeMap`] for debug output.87pub fn map_debug<K, V, S>(108pub fn map_debug<K, V, S>(88 v: &BoundedBTreeMap<K, V, S>,109 v: &BoundedBTreeMap<K, V, S>,89 f: &mut fmt::Formatter,110 f: &mut fmt::Formatter,9811999#[cfg(feature = "serde1")]120#[cfg(feature = "serde1")]100#[allow(dead_code)]121#[allow(dead_code)]122/// [`serde`] implementations for [`BoundedBTreeSet`].101pub mod set_serde {123pub mod set_serde {102 use core::convert::TryFrom;124 use core::convert::TryFrom;103 use sp_std::collections::btree_set::BTreeSet;125 use sp_std::collections::btree_set::BTreeSet;129 }151 }130}152}131153154/// Format [`BoundedBTreeSet`] for debug output.132pub fn set_debug<K, S>(v: &BoundedBTreeSet<K, S>, f: &mut fmt::Formatter) -> Result<(), fmt::Error>155pub fn set_debug<K, S>(v: &BoundedBTreeSet<K, S>, f: &mut fmt::Formatter) -> Result<(), fmt::Error>133where156where134 K: fmt::Debug + Ord,157 K: fmt::Debug + Ord,primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -14,6 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+//! # Primitives crate.
+//!
+//! This crate contains types, traits and constants.
+
#![cfg_attr(not(feature = "std"), no_std)]
use core::{
@@ -55,38 +59,55 @@
pub mod mapping;
mod migration;
+/// Maximum of decimal points.
pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;
+
+/// Maximum pieces for refungible token.
pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;
pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
+/// Maximum tokens for user.
pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {
100_000
} else {
10
};
+
+/// Maximum for collections can be created.
pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {
100_000
} else {
10
};
+
+/// Maximum for various custom data of token.
pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {
2048
} else {
10
};
+
+/// Maximum admins per collection.
pub const COLLECTION_ADMINS_LIMIT: u32 = 5;
+
+/// Maximum tokens per collection.
pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;
+
+/// Maximum tokens per account.
pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {
1_000_000
} else {
10
};
-// Timeouts for item types in passed blocks
+/// Default timeout for transfer sponsoring NFT item.
pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;
+/// Default timeout for transfer sponsoring fungible item.
pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;
+/// Default timeout for transfer sponsoring refungible item.
pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;
+/// Default timeout for sponsored approving.
pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;
// Schema limits
@@ -94,27 +115,44 @@
pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;
pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;
+// TODO: not used. Delete?
pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;
+/// Maximum length for collection name.
pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;
+
+/// Maximum length for collection description.
pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;
+
+/// Maximal token prefix length.
pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;
+/// Maximal lenght of property key.
pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;
+
+/// Maximal lenght of property value.
pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;
+
+/// Maximum properties that can be assigned to token.
pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;
+/// Maximal lenght of extended property value.
pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;
+/// Maximum size for all collection properties.
pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;
+
+/// Maximum size for all token properties.
pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;
/// How much items can be created per single
-/// create_many call
+/// create_many call.
pub const MAX_ITEMS_PER_BATCH: u32 = 200;
+/// Used for limit bounded types of token custom data.
pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;
+/// Collection id.
#[derive(
Encode,
Decode,
@@ -134,6 +172,7 @@
impl EncodeLike<u32> for CollectionId {}
impl EncodeLike<CollectionId> for u32 {}
+/// Token id.
#[derive(
Encode,
Decode,
@@ -154,6 +193,9 @@
impl EncodeLike<TokenId> for u32 {}
impl TokenId {
+ /// Try to get next token id.
+ ///
+ /// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.
pub fn try_next(self) -> Result<TokenId, ArithmeticError> {
self.0
.checked_add(1)
@@ -176,14 +218,21 @@
}
}
+/// Token data.
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TokenData<CrossAccountId> {
+ /// Properties of token.
pub properties: Vec<Property>,
+
+ /// Token owner.
pub owner: Option<CrossAccountId>,
+
+ /// Token pieces.
pub pieces: u128,
}
+// TODO: unused type
pub struct OverflowError;
impl From<OverflowError> for &'static str {
fn from(_: OverflowError) -> Self {
@@ -191,17 +240,27 @@
}
}
+/// Alias for decimal points type.
pub type DecimalPoints = u8;
+/// Collection mode.
+///
+/// Collection can represent various types of tokens.
+/// Each collection can contain only one type of tokens at a time.
+/// This type helps to understand which tokens the collection contains.
#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum CollectionMode {
+ /// Non fungible tokens.
NFT,
+ /// Fungible tokens.
Fungible(DecimalPoints),
+ /// Refungible tokens.
ReFungible,
}
impl CollectionMode {
+ /// Get collection mod as number.
pub fn id(&self) -> u8 {
match self {
CollectionMode::NFT => 1,
@@ -211,14 +270,18 @@
}
}
+// TODO: unused trait
pub trait SponsoringResolve<AccountId, Call> {
fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;
}
+/// Access mode for some token operations.
#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum AccessMode {
+ /// Access grant for owner and admins. Used as default.
Normal,
+ /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
AllowList,
}
impl Default for AccessMode {
@@ -227,6 +290,7 @@
}
}
+// TODO: remove in future.
#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum SchemaVersion {
@@ -239,6 +303,7 @@
}
}
+// TODO: unused type
#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Ownership<AccountId> {
@@ -246,19 +311,21 @@
pub fraction: u128,
}
+/// The state of collection sponsorship.
#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum SponsorshipState<AccountId> {
- /// The fees are applied to the transaction sender
+ /// The fees are applied to the transaction sender.
Disabled,
- /// Pending confirmation from a sponsor-to-be
+ /// The sponsor is under consideration. Until the sponsor gives his consent,
+ /// the fee will still be charged to sender.
Unconfirmed(AccountId),
- /// Transactions are sponsored by specified account
+ /// Transactions are sponsored by specified account.
Confirmed(AccountId),
}
impl<AccountId> SponsorshipState<AccountId> {
- /// Get the acting sponsor account, if present
+ /// Get a sponsor of the collection who has confirmed his status.
pub fn sponsor(&self) -> Option<&AccountId> {
match self {
Self::Confirmed(sponsor) => Some(sponsor),
@@ -266,7 +333,7 @@
}
}
- /// Get the sponsor account currently pending confirmation, if present
+ /// Get a sponsor of the collection who has pending or confirmed status.
pub fn pending_sponsor(&self) -> Option<&AccountId> {
match self {
Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),
@@ -274,7 +341,7 @@
}
}
- /// Is sponsorship set and acting
+ /// Whether the sponsorship is confirmed.
pub fn confirmed(&self) -> bool {
matches!(self, Self::Confirmed(_))
}
@@ -290,16 +357,32 @@
pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;
pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;
+/// Base structure for represent collection.
+///
+/// Used to provide basic functionality for all types of collections.
+///
+/// #### Note
/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).
#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
pub struct Collection<AccountId> {
+ /// Collection owner account.
pub owner: AccountId,
+
+ /// Collection mode.
pub mode: CollectionMode,
+
+ /// Access mode.
#[version(..2)]
pub access: AccessMode,
+
+ /// Collection name.
pub name: CollectionName,
+
+ /// Collection description.
pub description: CollectionDescription,
+
+ /// Token prefix.
pub token_prefix: CollectionTokenPrefix,
#[version(..2)]
@@ -310,10 +393,14 @@
#[version(..2)]
pub schema_version: SchemaVersion,
+
+ /// The state of sponsorship of the collection.
pub sponsorship: SponsorshipState<AccountId>,
+ /// Collection limits.
pub limits: CollectionLimits,
+ /// Collection permissions.
#[version(2.., upper(Default::default()))]
pub permissions: CollectionPermissions,
@@ -335,116 +422,215 @@
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RpcCollection<AccountId> {
+ /// Collection owner account.
pub owner: AccountId,
+
+ /// Collection mode.
pub mode: CollectionMode,
+
+ /// Collection name.
pub name: Vec<u16>,
+
+ /// Collection description.
pub description: Vec<u16>,
+
+ /// Token prefix.
pub token_prefix: Vec<u8>,
+
+ /// The state of sponsorship of the collection.
pub sponsorship: SponsorshipState<AccountId>,
+
+ /// Collection limits.
pub limits: CollectionLimits,
+
+ /// Collection permissions.
pub permissions: CollectionPermissions,
+
+ /// Token property permissions.
pub token_property_permissions: Vec<PropertyKeyPermission>,
+
+ /// Collection properties.
pub properties: Vec<Property>,
+
+ /// Is collection read only.
pub read_only: bool,
}
+/// Data used for create collection.
+///
+/// All fields are wrapped in [`Option`], where `None` means chain default.
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]
#[derivative(Debug, Default(bound = ""))]
pub struct CreateCollectionData<AccountId> {
+ /// Collection mode.
#[derivative(Default(value = "CollectionMode::NFT"))]
pub mode: CollectionMode,
+
+ /// Access mode.
pub access: Option<AccessMode>,
+
+ /// Collection name.
pub name: CollectionName,
+
+ /// Collection description.
pub description: CollectionDescription,
+
+ /// Token prefix.
pub token_prefix: CollectionTokenPrefix,
+
+ /// Pending collection sponsor.
pub pending_sponsor: Option<AccountId>,
+
+ /// Collection limits.
pub limits: Option<CollectionLimits>,
+
+ /// Collection permissions.
pub permissions: Option<CollectionPermissions>,
+
+ /// Token property permissions.
pub token_property_permissions: CollectionPropertiesPermissionsVec,
+
+ /// Collection properties.
pub properties: CollectionPropertiesVec,
}
+/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].
+// TODO: maybe rename to PropertiesPermissionsVec
pub type CollectionPropertiesPermissionsVec =
BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
+/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].
pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
/// Limits and restrictions of a collection.
-/// All fields are wrapped in `Option`s, where None means chain default.
///
-/// todo:doc links to chain defaults
+/// All fields are wrapped in [`Option`], where `None` means chain default.
+///
+/// Update with `pallet_common::Pallet::clamp_limits`.
// IMPORTANT: When adding/removing fields from this struct - don't forget to also
-// update clamp_limits() in pallet-common.
#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.
+// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.
+// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.
pub struct CollectionLimits {
- /// Maximum number of owned tokens per account. Chain default: [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`]
+ /// How many tokens can a user have on one account.
+ /// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].
+ /// * Limit - [`MAX_TOKEN_OWNERSHIP`].
pub account_token_ownership_limit: Option<u32>,
- /// Maximum size of data in bytes of a sponsored transaction. Chain default: [`CUSTOM_DATA_LIMIT`]
+
+ /// How many bytes of data are available for sponsorship.
+ /// * Default - [`CUSTOM_DATA_LIMIT`].
+ /// * Limit - [`CUSTOM_DATA_LIMIT`].
pub sponsored_data_size: Option<u32>,
- /// FIXME should we delete this or repurpose it?
- /// None - setVariableMetadata is not sponsored
- /// Some(v) - setVariableMetadata is sponsored
- /// if there is v block between txs
+ // FIXME should we delete this or repurpose it?
+ /// Times in how many blocks we sponsor data.
+ ///
+ /// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.
+ ///
+ /// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).
+ /// * Limit - [`MAX_SPONSOR_TIMEOUT`].
///
/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,
/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]
+
+ /// How many tokens can be mined into this collection.
+ ///
+ /// * Default - [`COLLECTION_TOKEN_LIMIT`].
+ /// * Limit - [`COLLECTION_TOKEN_LIMIT`].
pub token_limit: Option<u32>,
- /// Timeout for sponsoring a token transfer in passed blocks. Chain default:
- /// either [`NFT_SPONSOR_TRANSFER_TIMEOUT`], [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`], or [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`],
- /// depending on the collection type.
+ /// Timeouts for transfer sponsoring.
+ ///
+ /// * Default
+ /// - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]
+ /// - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]
+ /// - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]
+ /// * Limit - [`MAX_SPONSOR_TIMEOUT`].
pub sponsor_transfer_timeout: Option<u32>,
- /// Timeout for sponsoring an approval in passed blocks. Chain default: [`SPONSOR_APPROVE_TIMEOUT`]
+
+ /// Timeout for sponsoring an approval in passed blocks.
+ ///
+ /// * Default - [`SPONSOR_APPROVE_TIMEOUT`].
+ /// * Limit - [`MAX_SPONSOR_TIMEOUT`].
pub sponsor_approve_timeout: Option<u32>,
- /// Can a token be transferred by the owner. Chain default: `false`
+
+ /// Whether the collection owner of the collection can send tokens (which belong to other users).
+ ///
+ /// * Default - **false**.
pub owner_can_transfer: Option<bool>,
- /// Can a token be burned by the owner. Chain default: `true`
+
+ /// Can the collection owner burn other people's tokens.
+ ///
+ /// * Default - **true**.
pub owner_can_destroy: Option<bool>,
- /// Can a token be transferred at all. Chain default: `true`
+
+ /// Is it possible to send tokens from this collection between users.
+ ///
+ /// * Default - **true**.
pub transfers_enabled: Option<bool>,
}
impl CollectionLimits {
+ /// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).
pub fn account_token_ownership_limit(&self) -> u32 {
self.account_token_ownership_limit
.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)
.min(MAX_TOKEN_OWNERSHIP)
}
+
+ /// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).
pub fn sponsored_data_size(&self) -> u32 {
self.sponsored_data_size
.unwrap_or(CUSTOM_DATA_LIMIT)
.min(CUSTOM_DATA_LIMIT)
}
+
+ /// Get effective value for [`token_limit`](self.token_limit).
pub fn token_limit(&self) -> u32 {
self.token_limit
.unwrap_or(COLLECTION_TOKEN_LIMIT)
.min(COLLECTION_TOKEN_LIMIT)
}
+
+ // TODO: may be replace u32 to mode?
+ /// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).
pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {
self.sponsor_transfer_timeout
.unwrap_or(default)
.min(MAX_SPONSOR_TIMEOUT)
}
+
+ /// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).
pub fn sponsor_approve_timeout(&self) -> u32 {
self.sponsor_approve_timeout
.unwrap_or(SPONSOR_APPROVE_TIMEOUT)
.min(MAX_SPONSOR_TIMEOUT)
}
+
+ /// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).
pub fn owner_can_transfer(&self) -> bool {
self.owner_can_transfer.unwrap_or(false)
}
+
+ /// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).
pub fn owner_can_transfer_instaled(&self) -> bool {
self.owner_can_transfer.is_some()
}
+
+ /// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).
pub fn owner_can_destroy(&self) -> bool {
self.owner_can_destroy.unwrap_or(true)
}
+
+ /// Get effective value for [`transfers_enabled`](self.transfers_enabled).
pub fn transfers_enabled(&self) -> bool {
self.transfers_enabled.unwrap_or(true)
}
+
+ /// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).
pub fn sponsored_data_rate_limit(&self) -> Option<u32> {
match self
.sponsored_data_rate_limit
@@ -457,24 +643,46 @@
}
/// Permissions on certain operations within a collection.
-/// All fields are wrapped in `Option`s, where None means chain default.
-// IMPORTANT: When adding/removing fields from this struct - don't forget to also
-// update clamp_limits() in pallet-common.
+///
+/// Some fields are wrapped in [`Option`], where `None` means chain default.
+///
+/// Update with `pallet_common::Pallet::clamp_permissions`.
#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.
+// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.
pub struct CollectionPermissions {
+ /// Access mode.
+ ///
+ /// * Default - [`AccessMode::Normal`].
pub access: Option<AccessMode>,
+
+ /// Minting allowance.
+ ///
+ /// * Default - **false**.
pub mint_mode: Option<bool>,
+
+ /// Permissions for nesting.
+ ///
+ /// * Default
+ /// - `token_owner` - **false**
+ /// - `collection_admin` - **false**
+ /// - `restricted` - **None**
pub nesting: Option<NestingPermissions>,
}
impl CollectionPermissions {
+ /// Get effective value for [`access`](self.access).
pub fn access(&self) -> AccessMode {
self.access.unwrap_or(AccessMode::Normal)
}
+
+ /// Get effective value for [`mint_mode`](self.mint_mode).
pub fn mint_mode(&self) -> bool {
self.mint_mode.unwrap_or(false)
}
+
+ /// Get effective value for [`nesting`](self.nesting).
pub fn nesting(&self) -> &NestingPermissions {
static DEFAULT: NestingPermissions = NestingPermissions {
token_owner: false,
@@ -487,8 +695,10 @@
}
}
+/// Inner set for collections allowed to nest.
type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;
+/// Wraper for collections set allowing nest.
#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derivative(Debug)]
@@ -497,7 +707,9 @@
#[derivative(Debug(format_with = "bounded::set_debug"))]
pub OwnerRestrictedSetInner,
);
+
impl OwnerRestrictedSet {
+ /// Create new set.
pub fn new() -> Self {
Self(Default::default())
}
@@ -519,19 +731,21 @@
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derivative(Debug)]
pub struct NestingPermissions {
- /// Owner of token can nest tokens under it
+ /// Owner of token can nest tokens under it.
pub token_owner: bool,
- /// Admin of token collection can nest tokens under token
+ /// Admin of token collection can nest tokens under token.
pub collection_admin: bool,
- /// If set - only tokens from specified collections can be nested
+ /// If set - only tokens from specified collections can be nested.
pub restricted: Option<OwnerRestrictedSet>,
#[cfg(feature = "runtime-benchmarks")]
- /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`
+ /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.
pub permissive: bool,
}
/// Enum denominating how often can sponsoring occur if it is enabled.
+///
+/// Used for [`collection limits`](CollectionLimits).
#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum SponsoringRateLimit {
@@ -549,6 +763,7 @@
/// Key-value pairs used to describe the token as metadata
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
#[derivative(Debug(format_with = "bounded::vec_debug"))]
+ /// Properties that wil be assignet to created item.
pub properties: CollectionPropertiesVec,
}
@@ -570,7 +785,7 @@
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
- /// Number of pieces the RFT is split into
+ /// Pieces of created token.
pub pieces: u128,
/// Key-value pairs used to describe the token as metadata
@@ -579,6 +794,7 @@
pub properties: CollectionPropertiesVec,
}
+// TODO: remove this.
#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum MetaUpdatePermission {
@@ -588,57 +804,75 @@
}
/// Enum holding data used for creation of all three item types.
+/// Unified data for create item.
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum CreateItemData {
+ /// Data for create NFT.
NFT(CreateNftData),
+ /// Data for create Fungible item.
Fungible(CreateFungibleData),
+ /// Data for create ReFungible item.
ReFungible(CreateReFungibleData),
}
-/// Explicit NFT creation data with meta parameters.
+/// Extended data for create NFT.
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
#[derivative(Debug)]
pub struct CreateNftExData<CrossAccountId> {
+ /// Properties that wil be assignet to created item.
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub properties: CollectionPropertiesVec,
+
+ /// Owner of creating item.
pub owner: CrossAccountId,
}
-/// Explicit RFT creation data with meta parameters.
+/// Extended data for create ReFungible item.
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
pub struct CreateRefungibleExData<CrossAccountId> {
+ /// Custom data stored in token.
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub const_data: BoundedVec<u8, CustomDataLimit>,
+
+ /// Users who will be assigned the specified number of token parts.
#[derivative(Debug(format_with = "bounded::map_debug"))]
pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
#[derivative(Debug(format_with = "bounded::vec_debug"))]
pub properties: CollectionPropertiesVec,
}
-/// Explicit item creation data with meta parameters, namely the owner.
+/// Unified extended data for creating item.
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
pub enum CreateItemExData<CrossAccountId> {
+ /// Extended data for create NFT.
NFT(
#[derivative(Debug(format_with = "bounded::vec_debug"))]
BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,
),
+
+ /// Extended data for create Fungible item.
Fungible(
#[derivative(Debug(format_with = "bounded::map_debug"))]
BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,
),
- /// Many tokens, each may have only one owner
+
+ /// Extended data for create ReFungible item in case of
+ /// many tokens, each may have only one owner
RefungibleMultipleItems(
#[derivative(Debug(format_with = "bounded::vec_debug"))]
BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,
),
- /// Single token, which may have many owners
+
+ /// Extended data for create ReFungible item in case of
+ /// single token, which may have many owners
RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),
}
impl CreateItemData {
+ /// Get size of custom data.
pub fn data_size(&self) -> usize {
match self {
CreateItemData::ReFungible(data) => data.const_data.len(),
@@ -670,18 +904,28 @@
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
// todo possibly rename to be used generally as an address pair
pub struct TokenChild {
+ /// Token id.
pub token: TokenId,
+
+ /// Collection id.
pub collection: CollectionId,
}
+/// Collection statistics.
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct CollectionStats {
+ /// Number of created items.
pub created: u32,
+
+ /// Number of burned items.
pub destroyed: u32,
+
+ /// Number of current items.
pub alive: u32,
}
+/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.
#[derive(Encode, Decode, Clone, Debug)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct PhantomType<T>(core::marker::PhantomData<T>);
@@ -707,22 +951,36 @@
}
}
+/// Bounded vector of bytes.
pub type BoundedBytes<S> = BoundedVec<u8, S>;
+/// Extra properties for external collections.
pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;
+/// Property key.
pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;
+
+/// Property value.
pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;
+/// Property permission.
#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct PropertyPermission {
+ /// Permission to change the property and property permission.
+ ///
+ /// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.
pub mutable: bool,
+
+ /// Change permission for the collection administrator.
pub collection_admin: bool,
+
+ /// Permission to change the property for the owner of the token.
pub token_owner: bool,
}
impl PropertyPermission {
+ /// Creates mutable property permission but changes restricted for collection admin and token owner.
pub fn none() -> Self {
Self {
mutable: true,
@@ -732,12 +990,15 @@
}
}
+/// Property is simpl key-value record.
#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Property {
+ /// Property key.
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
pub key: PropertyKey,
+ /// Property value.
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
pub value: PropertyValue,
}
@@ -748,12 +1009,15 @@
}
}
+/// Record for proprty key permission.
#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct PropertyKeyPermission {
+ /// Key.
#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
pub key: PropertyKey,
+ /// Permission.
pub permission: PropertyPermission,
}
@@ -763,15 +1027,35 @@
}
}
+/// Errors for properties actions.
#[derive(Debug)]
pub enum PropertiesError {
+ /// The space allocated for properties has run out.
+ ///
+ /// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].
+ /// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].
NoSpaceForProperty,
+
+ /// The property limit has been reached.
+ ///
+ /// * Limit - [`MAX_PROPERTIES_PER_ITEM`].
PropertyLimitReached,
+
+ /// Property key contains not allowed character.
InvalidCharacterInPropertyKey,
+
+ /// Property key length is too long.
+ ///
+ /// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].
PropertyKeyIsTooLong,
+
+ /// Property key is empty.
EmptyPropertyKey,
}
+/// Marker for scope of property.
+///
+/// Scoped property can't be changed by user. Used for external collections.
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]
pub enum PropertyScope {
None,
@@ -779,6 +1063,7 @@
}
impl PropertyScope {
+ /// Apply scope to property key.
pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {
let scope_str: &[u8] = match self {
Self::None => return Ok(key),
@@ -792,9 +1077,11 @@
}
}
+/// Trait for operate with properties.
pub trait TrySetProperty: Sized {
type Value;
+ /// Try to set property with scope.
fn try_scoped_set(
&mut self,
scope: PropertyScope,
@@ -802,6 +1089,7 @@
value: Self::Value,
) -> Result<(), PropertiesError>;
+ /// Try to set property with scope from iterator.
fn try_scoped_set_from_iter<I, KV>(
&mut self,
scope: PropertyScope,
@@ -819,10 +1107,12 @@
Ok(())
}
+ /// Try to set property.
fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {
self.try_scoped_set(PropertyScope::None, key, value)
}
+ /// Try to set property from iterator.
fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>
where
I: Iterator<Item = KV>,
@@ -832,6 +1122,7 @@
}
}
+/// Wrapped map for storing properties.
#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]
#[derivative(Default(bound = ""))]
pub struct PropertiesMap<Value>(
@@ -839,24 +1130,29 @@
);
impl<Value> PropertiesMap<Value> {
+ /// Create new property map.
pub fn new() -> Self {
Self(BoundedBTreeMap::new())
}
+ /// Remove property from map.
pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {
Self::check_property_key(key)?;
Ok(self.0.remove(key))
}
+ /// Get property with appropriate key from map.
pub fn get(&self, key: &PropertyKey) -> Option<&Value> {
self.0.get(key)
}
+ /// Check if map contains key.
pub fn contains_key(&self, key: &PropertyKey) -> bool {
self.0.contains_key(key)
}
+ /// Check if map contains key with key validation.
fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {
if key.is_empty() {
return Err(PropertiesError::EmptyPropertyKey);
@@ -909,8 +1205,10 @@
}
}
+/// Alias for property permissions map.
pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;
+/// Wrapper for properties map with consumed space control.
#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]
pub struct Properties {
map: PropertiesMap<PropertyValue>,
@@ -919,6 +1217,7 @@
}
impl Properties {
+ /// Create new properies container.
pub fn new(space_limit: u32) -> Self {
Self {
map: PropertiesMap::new(),
@@ -927,6 +1226,7 @@
}
}
+ /// Remove propery with appropiate key.
pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {
let value = self.map.remove(key)?;
@@ -938,6 +1238,7 @@
Ok(value)
}
+ /// Get property with appropriate key.
pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {
self.map.get(key)
}
@@ -977,6 +1278,7 @@
}
}
+/// Utility struct for using in `StorageMap`.
pub struct CollectionProperties;
impl Get<Properties> for CollectionProperties {
@@ -985,6 +1287,7 @@
}
}
+/// Utility struct for using in `StorageMap`.
pub struct TokenProperties;
impl Get<Properties> for TokenProperties {
primitives/data-structs/src/mapping.rsdiffbeforeafterboth--- a/primitives/data-structs/src/mapping.rs
+++ b/primitives/data-structs/src/mapping.rs
@@ -1,3 +1,21 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+//! This module contains mapping between different addresses.
+
use core::marker::PhantomData;
use sp_core::H160;
@@ -5,12 +23,19 @@
use crate::{CollectionId, TokenId};
use pallet_evm::account::CrossAccountId;
+/// Trait for mapping between token id and some `Address`.
pub trait TokenAddressMapping<Address> {
+ /// Map token id to `Address`.
fn token_to_address(collection: CollectionId, token: TokenId) -> Address;
+
+ /// Map `Address` to token id.
fn address_to_token(address: &Address) -> Option<(CollectionId, TokenId)>;
+
+ /// Check is address for token.
fn is_token_address(address: &Address) -> bool;
}
+/// Unit struct for mapping token id to/from *Evm address* represented by [`H160`].
pub struct EvmTokenAddressMapping;
/// 0xf8238ccfff8ed887463fd5e00000000100000002 - collection 1, token 2
@@ -46,6 +71,7 @@
}
}
+/// Unit struct for mapping token id to/from [`CrossAccountId`].
pub struct CrossTokenAddressMapping<A>(PhantomData<A>);
impl<A, C: CrossAccountId<A>> TokenAddressMapping<C> for CrossTokenAddressMapping<A> {
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -28,6 +28,7 @@
sp_api::decl_runtime_apis! {
#[api_version(2)]
+ /// Trait for generate rpc.
pub trait UniqueApi<CrossAccountId, AccountId> where
AccountId: Decode,
CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,
@@ -35,36 +36,57 @@
#[changed_in(2)]
fn token_owner(collection: CollectionId, token: TokenId) -> Result<CrossAccountId>;
+ /// Get number of tokens in collection owned by account.
fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;
+
+ /// Number of existing tokens in collection.
fn collection_tokens(collection: CollectionId) -> Result<Vec<TokenId>>;
+
+ /// Check token exist.
fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool>;
+ /// Get token owner.
fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
+
+ /// Get real owner of nested token.
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
+
+ /// Get nested tokens for the specified item.
fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>>;
+ /// Get collection properties.
fn collection_properties(collection: CollectionId, properties: Option<Vec<Vec<u8>>>) -> Result<Vec<Property>>;
+ /// Get token properties.
fn token_properties(
collection: CollectionId,
token_id: TokenId,
properties: Option<Vec<Vec<u8>>>
) -> Result<Vec<Property>>;
+ /// Get permissions for token properties.
fn property_permissions(
collection: CollectionId,
properties: Option<Vec<Vec<u8>>>
) -> Result<Vec<PropertyKeyPermission>>;
+ /// Get token data.
fn token_data(
collection: CollectionId,
token_id: TokenId,
keys: Option<Vec<Vec<u8>>>
) -> Result<TokenData<CrossAccountId>>;
+ /// Total number of tokens in collection.
fn total_supply(collection: CollectionId) -> Result<u32>;
+
+ /// Get account balance for collection (sum of tokens pieces).
fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32>;
+
+ /// Get account balance for specified token.
fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128>;
+
+ /// Amount of token pieces allowed to spend from granded account.
fn allowance(
collection: CollectionId,
sender: CrossAccountId,
@@ -72,14 +94,31 @@
token: TokenId,
) -> Result<u128>;
+ /// Get list of collection admins.
fn adminlist(collection: CollectionId) -> Result<Vec<CrossAccountId>>;
+
+ /// Get list of users that allowet to mint tikens in collection.
fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>>;
+
+ /// Check that user is in allowed list (see [`allowlist`]).
fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool>;
+
+ /// Last minted token id.
fn last_token_id(collection: CollectionId) -> Result<TokenId>;
+
+ /// Get collection by id.
fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;
+
+ /// Get collection stats.
fn collection_stats() -> Result<CollectionStats>;
+
+ /// Get the number of blocks through which sponsorship will be available.
fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>>;
+
+ /// Get effective colletion limits.
fn effective_collection_limits(collection_id: CollectionId) -> Result<Option<CollectionLimits>>;
+
+ /// Get total pieces of token.
fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result<Option<u128>>;
fn token_owners(collection: CollectionId, token: TokenId) -> Result<Vec<CrossAccountId>>;
}