difftreelog
doc: architectural changes
in: master
10 files changed
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -42,6 +42,7 @@
#[rpc(server)]
#[async_trait]
pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {
+ /// Get tokens owned by account
#[method(name = "unique_accountTokens")]
fn account_tokens(
&self,
@@ -49,12 +50,14 @@
account: CrossAccountId,
at: Option<BlockHash>,
) -> Result<Vec<TokenId>>;
+ /// Get tokens contained in collection
#[method(name = "unique_collectionTokens")]
fn collection_tokens(
&self,
collection: CollectionId,
at: Option<BlockHash>,
) -> Result<Vec<TokenId>>;
+ /// Check if token exists
#[method(name = "unique_tokenExists")]
fn token_exists(
&self,
@@ -62,7 +65,7 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<bool>;
-
+ /// Get token owner
#[method(name = "unique_tokenOwner")]
fn token_owner(
&self,
@@ -70,6 +73,7 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<CrossAccountId>>;
+ /// Get token owner, in case of nested token - find the parent recursively
#[method(name = "unique_topmostTokenOwner")]
fn topmost_token_owner(
&self,
@@ -77,6 +81,7 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<CrossAccountId>>;
+ /// Get tokens nested directly into the token
#[method(name = "unique_tokenChildren")]
fn token_children(
&self,
@@ -84,7 +89,7 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Vec<TokenChild>>;
-
+ /// Get collection properties
#[method(name = "unique_collectionProperties")]
fn collection_properties(
&self,
@@ -92,7 +97,7 @@
keys: Option<Vec<String>>,
at: Option<BlockHash>,
) -> Result<Vec<Property>>;
-
+ /// Get token properties
#[method(name = "unique_tokenProperties")]
fn token_properties(
&self,
@@ -101,7 +106,7 @@
keys: Option<Vec<String>>,
at: Option<BlockHash>,
) -> Result<Vec<Property>>;
-
+ /// Get property permissions
#[method(name = "unique_propertyPermissions")]
fn property_permissions(
&self,
@@ -109,7 +114,7 @@
keys: Option<Vec<String>>,
at: Option<BlockHash>,
) -> Result<Vec<PropertyKeyPermission>>;
-
+ /// Get token data
#[method(name = "unique_tokenData")]
fn token_data(
&self,
@@ -118,9 +123,10 @@
keys: Option<Vec<String>>,
at: Option<BlockHash>,
) -> Result<TokenData<CrossAccountId>>;
-
+ /// Get amount of unique collection tokens
#[method(name = "unique_totalSupply")]
fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;
+ /// Get owned amount of any user tokens
#[method(name = "unique_accountBalance")]
fn account_balance(
&self,
@@ -128,6 +134,7 @@
account: CrossAccountId,
at: Option<BlockHash>,
) -> Result<u32>;
+ /// Get owned amount of specific account token
#[method(name = "unique_balance")]
fn balance(
&self,
@@ -136,6 +143,7 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<String>;
+ /// Get allowed amount
#[method(name = "unique_allowance")]
fn allowance(
&self,
@@ -145,19 +153,21 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<String>;
-
+ /// Get admin list
#[method(name = "unique_adminlist")]
fn adminlist(
&self,
collection: CollectionId,
at: Option<BlockHash>,
) -> Result<Vec<CrossAccountId>>;
+ /// Get allowlist
#[method(name = "unique_allowlist")]
fn allowlist(
&self,
collection: CollectionId,
at: Option<BlockHash>,
) -> Result<Vec<CrossAccountId>>;
+ /// Check if user is allowed to use collection
#[method(name = "unique_allowed")]
fn allowed(
&self,
@@ -165,17 +175,20 @@
user: CrossAccountId,
at: Option<BlockHash>,
) -> Result<bool>;
+ /// Get last token ID created in a collection
#[method(name = "unique_lastTokenId")]
fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;
+ /// Get collection by specified ID
#[method(name = "unique_collectionById")]
fn collection_by_id(
&self,
collection: CollectionId,
at: Option<BlockHash>,
) -> Result<Option<RpcCollection<AccountId>>>;
+ /// Get collection stats
#[method(name = "unique_collectionStats")]
fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;
-
+ /// Get number of blocks when sponsored transaction is available
#[method(name = "unique_nextSponsored")]
fn next_sponsored(
&self,
@@ -184,14 +197,14 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<u64>>;
-
+ /// Get effective collection limits
#[method(name = "unique_effectiveCollectionLimits")]
fn effective_collection_limits(
&self,
collection_id: CollectionId,
at: Option<BlockHash>,
) -> Result<Option<CollectionLimits>>;
-
+ /// Get total pieces of token
#[method(name = "unique_totalPieces")]
fn total_pieces(
&self,
@@ -304,6 +317,7 @@
fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;
#[method(name = "rmrk_themeNames")]
+ /// Get Base's theme names
fn theme_names(
&self,
base_id: RmrkBaseId,
@@ -311,6 +325,7 @@
) -> Result<Vec<RmrkThemeName>>;
#[method(name = "rmrk_themes")]
+ /// Get Theme info -- name, properties, and inherit flag
fn theme(
&self,
base_id: RmrkBaseId,
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -299,46 +299,48 @@
///
/// # Arguments
///
- /// * collection_id: Globally unique identifier of collection.
+ /// * collection_id: Globally unique identifier of collection that has been destroyed.
CollectionDestroyed(CollectionId),
/// New item was created.
///
/// # Arguments
///
- /// * collection_id: Id of the collection where item was created.
+ /// * collection_id: ID of the collection where the item was created.
///
- /// * item_id: Id of an item. Unique within the collection.
+ /// * item_id: ID of the item. Unique within the collection.
///
- /// * recipient: Owner of newly created item
+ /// * recipient: Owner of the newly created item.
///
- /// * amount: Always 1 for NFT
+ /// * amount: The amount of tokens that were created (always 1 for NFT).
ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),
/// Collection item was burned.
///
/// # Arguments
///
- /// * collection_id.
+ /// * collection_id: Identifier of the collection to which the burned NFT belonged.
///
/// * item_id: Identifier of burned NFT.
///
- /// * owner: which user has destroyed its tokens
+ /// * owner: Which user has destroyed their tokens.
///
- /// * amount: Always 1 for NFT
+ /// * amount: The amount of tokens that were destroyed (always 1 for NFT).
ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),
- /// Item was transferred
+ /// Item was transferred.
+ ///
+ /// # Arguments
///
- /// * collection_id: Id of collection to which item is belong
+ /// * collection_id: ID of the collection to which the item belongs.
///
- /// * item_id: Id of an item
+ /// * item_id: ID of the item trasnferred.
///
- /// * sender: Original owner of item
+ /// * sender: Original owner of the item.
///
- /// * recipient: New owner of item
+ /// * recipient: New owner of the item.
///
- /// * amount: Always 1 for NFT
+ /// * amount: The amount of tokens that were transferred (always 1 for NFT).
Transfer(
CollectionId,
TokenId,
@@ -347,6 +349,10 @@
u128,
),
+ /// Sponsoring allowance was approved.
+ ///
+ /// # Arguments
+ ///
/// * collection_id
///
/// * item_id
@@ -364,14 +370,53 @@
u128,
),
+ /// Collection property was added or edited.
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection, whose property was just set.
+ ///
+ /// * property_key: Key of the property that was just set.
CollectionPropertySet(CollectionId, PropertyKey),
+ /// Collection property was deleted.
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection, whose property was just deleted.
+ ///
+ /// * property_key: Key of the property that was just deleted.
CollectionPropertyDeleted(CollectionId, PropertyKey),
+ /// Item property was added or edited.
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection, whose token's property was just set.
+ ///
+ /// * item_id: ID of the item, whose property was just set.
+ ///
+ /// * property_key: Key of the property that was just set.
TokenPropertySet(CollectionId, TokenId, PropertyKey),
+ /// Item property was deleted.
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection, whose token's property was just deleted.
+ ///
+ /// * item_id: ID of the item, whose property was just deleted.
+ ///
+ /// * property_key: Key of the property that was just deleted.
TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),
+ /// Token property permission was added or updated for a collection.
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection, whose permissions were just set/updated.
+ ///
+ /// * property_key: Key of the property of the set/updated permission.
PropertyPermissionSet(CollectionId, PropertyKey),
}
@@ -413,26 +458,26 @@
/// Metadata flag frozen
MetadataFlagFrozen,
- /// Item not exists.
+ /// Item does not exist
TokenNotFound,
- /// Item balance not enough.
+ /// Item is balance not enough
TokenValueTooLow,
- /// Requested value more than approved.
+ /// Requested value is more than the approved
ApprovedValueTooLow,
/// Tried to approve more than owned
CantApproveMoreThanOwned,
/// Can't transfer tokens to ethereum zero address
AddressIsZero,
- /// Target collection doesn't supports this operation
+ /// Target collection doesn't support this operation
UnsupportedOperation,
- /// Not sufficient funds to perform action
+ /// Insufficient funds to perform an action
NotSufficientFounds,
- /// User not passed nesting rule
+ /// User does not satisfy the nesting rule
UserIsNotAllowedToNest,
- /// Only tokens from specific collections may nest tokens under this
+ /// Only tokens from specific collections may nest tokens under this one
SourceCollectionIsNotAllowedToNest,
/// Tried to store more data than allowed in collection field
@@ -447,7 +492,7 @@
/// Property key is too long
PropertyKeyIsTooLong,
- /// Only ASCII letters, digits, and '_', '-' are allowed
+ /// Only ASCII letters, digits, and symbols '_', '-', and '.' are allowed
InvalidCharacterInPropertyKey,
/// Empty property keys are forbidden
@@ -460,8 +505,11 @@
CollectionIsInternal,
}
+ /// The number of created collections. Essentially contains the last collection ID.
#[pallet::storage]
pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
+
+ /// The number of destroyed collections
#[pallet::storage]
pub type DestroyedCollectionCount<T> =
StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
@@ -486,6 +534,7 @@
OnEmpty = up_data_structs::CollectionProperties,
>;
+ /// Token permissions of a collection
#[pallet::storage]
#[pallet::getter(fn property_permissions)]
pub type CollectionPropertyPermissions<T> = StorageMap<
@@ -495,6 +544,7 @@
QueryKind = ValueQuery,
>;
+ /// Amount of collection admins
#[pallet::storage]
pub type AdminAmount<T> = StorageMap<
Hasher = Blake2_128Concat,
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -44,6 +44,7 @@
pub mod erc;
pub mod weights;
+/// todo:doc?
pub type CreateItemData<T> = (<T as pallet_evm::account::Config>::CrossAccountId, u128);
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
@@ -78,10 +79,12 @@
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
+ /// Total amount of fungible tokens inside a collection.
#[pallet::storage]
pub type TotalSupply<T: Config> =
StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u128, QueryKind = ValueQuery>;
+ /// Amount of tokens owned by an account inside a collection.
#[pallet::storage]
pub type Balance<T: Config> = StorageNMap<
Key = (
@@ -92,6 +95,7 @@
QueryKind = ValueQuery,
>;
+ /// todo:doc
#[pallet::storage]
pub type Allowance<T: Config> = StorageNMap<
Key = (
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -56,6 +56,8 @@
pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
+/// Token data, stored independently from other data used to describe it.
+/// Notably contains the owner account address.
#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct ItemData<CrossAccountId> {
@@ -102,13 +104,17 @@
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
+ /// Total amount of minted tokens in a collection.
#[pallet::storage]
pub type TokensMinted<T: Config> =
StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
+
+ /// Amount of burnt tokens in a collection.
#[pallet::storage]
pub type TokensBurnt<T: Config> =
StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
+ /// Token data, used to partially describe a token.
#[pallet::storage]
pub type TokenData<T: Config> = StorageNMap<
Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -116,6 +122,7 @@
QueryKind = OptionQuery,
>;
+ /// Key-value pairs, describing the metadata of a token.
#[pallet::storage]
#[pallet::getter(fn token_properties)]
pub type TokenProperties<T: Config> = StorageNMap<
@@ -125,6 +132,7 @@
OnEmpty = up_data_structs::TokenProperties,
>;
+ /// Scoped, auxiliary properties of a token, primarily used for on-chain operations.
#[pallet::storage]
#[pallet::getter(fn token_aux_property)]
pub type TokenAuxProperties<T: Config> = StorageNMap<
@@ -138,7 +146,7 @@
QueryKind = OptionQuery,
>;
- /// Used to enumerate tokens owned by account
+ /// Used to enumerate tokens owned by account.
#[pallet::storage]
pub type Owned<T: Config> = StorageNMap<
Key = (
@@ -150,7 +158,7 @@
QueryKind = ValueQuery,
>;
- /// Used to enumerate token's children
+ /// Used to enumerate token's children.
#[pallet::storage]
#[pallet::getter(fn token_children)]
pub type TokenChildren<T: Config> = StorageNMap<
@@ -163,6 +171,7 @@
QueryKind = ValueQuery,
>;
+ /// Amount of tokens owned in a collection.s
#[pallet::storage]
pub type AccountBalance<T: Config> = StorageNMap<
Key = (
@@ -173,6 +182,7 @@
QueryKind = ValueQuery,
>;
+ /// todo doc
#[pallet::storage]
pub type Allowance<T: Config> = StorageNMap<
Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -180,6 +190,7 @@
QueryKind = OptionQuery,
>;
+ /// Upgrade from the old schema to properties.
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_runtime_upgrade() -> Weight {
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -38,6 +38,8 @@
pub mod weights;
pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
+/// Token data, stored independently from other data used to describe it.
+/// Notably contains the token metadata.
#[struct_versioning::versioned(version = 2, upper)]
#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]
pub struct ItemData {
@@ -86,13 +88,17 @@
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
+ /// Total amount of minted tokens in a collection.
#[pallet::storage]
pub type TokensMinted<T: Config> =
StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
+
+ /// Amount of tokens burnt in a collection.
#[pallet::storage]
pub type TokensBurnt<T: Config> =
StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
+ /// Token data, used to partially describe a token.
#[pallet::storage]
pub type TokenData<T: Config> = StorageNMap<
Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -100,6 +106,7 @@
QueryKind = ValueQuery,
>;
+ /// Amount of pieces a refungible token is split into.
#[pallet::storage]
pub type TotalSupply<T: Config> = StorageNMap<
Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -107,7 +114,7 @@
QueryKind = ValueQuery,
>;
- /// Used to enumerate tokens owned by account
+ /// Used to enumerate tokens owned by account.
#[pallet::storage]
pub type Owned<T: Config> = StorageNMap<
Key = (
@@ -119,6 +126,7 @@
QueryKind = ValueQuery,
>;
+ /// Amount of tokens (not pieces) partially owned by an account within a collection.
#[pallet::storage]
pub type AccountBalance<T: Config> = StorageNMap<
Key = (
@@ -130,6 +138,7 @@
QueryKind = ValueQuery,
>;
+ /// Amount of pieces of a token owned by an account.
#[pallet::storage]
pub type Balance<T: Config> = StorageNMap<
Key = (
@@ -142,6 +151,7 @@
QueryKind = ValueQuery,
>;
+ /// todo:doc
#[pallet::storage]
pub type Allowance<T: Config> = StorageNMap<
Key = (
@@ -248,7 +258,7 @@
// TODO: ERC721 transfer event
Ok(())
}
-
+
pub fn burn(
collection: &RefungibleHandle<T>,
owner: &T::CrossAccountId,
@@ -595,6 +605,7 @@
Ok(())
}
+ /// todo:doc oh look, a precedent. not pub, too. but it has an unclear use-case.
/// Returns allowance, which should be set after transaction
fn check_allowed(
collection: &RefungibleHandle<T>,
pallets/scheduler/src/lib.rsdiffbeforeafterboth--- a/pallets/scheduler/src/lib.rs
+++ b/pallets/scheduler/src/lib.rs
@@ -258,6 +258,7 @@
/// A Scheduler-Runtime interface for finer payment handling.
pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {
+ /// Reserve the maximum spendings on a call.
fn reserve_balance(
id: ScheduledId,
sponsor: <T as frame_system::Config>::AccountId,
@@ -265,6 +266,7 @@
count: u32,
) -> Result<(), DispatchError>;
+ /// Pay for call dispatch (un-reserve) from the reserved funds, returning the change.
fn pay_for_call(
id: ScheduledId,
sponsor: <T as frame_system::Config>::AccountId,
@@ -280,6 +282,7 @@
TransactionValidityError,
>;
+ /// Release reserved funds.
fn cancel_reserve(
id: ScheduledId,
sponsor: <T as frame_system::Config>::AccountId,
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -25,19 +25,19 @@
#[pallet::error]
pub enum Error<T> {
- /// While searched for owner, got already checked account
+ /// While searching for the owner, encountered an already checked account, detecting a loop.
OuroborosDetected,
- /// While searched for owner, encountered depth limit
+ /// While searching for the owner, reached the depth limit.
DepthLimit,
- /// While iterating over children, encountered breadth limit
+ /// While iterating over children, reached the breadth limit.
BreadthLimit,
- /// While searched for owner, found token owner by not-yet-existing token
+ /// Couldn't find the token owner that is a token. Perhaps, it does not yet exist. todo:doc? rephrase?
TokenNotFound,
}
#[pallet::event]
pub enum Event<T> {
- /// Executed call on behalf of token
+ /// Executed call on behalf of the token.
Executed(DispatchResult),
}
@@ -73,11 +73,11 @@
#[derive(PartialEq)]
pub enum Parent<CrossAccountId> {
- /// Token owned by normal account
+ /// Token owned by a normal account.
User(CrossAccountId),
- /// Passed token not found
+ /// Could not find the token provided as the owner.
TokenNotFound,
- /// Token owner is another token (target token still may not exist)
+ /// Token owner is another token (still, the target token may not exist).
Token(CollectionId, TokenId),
}
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -101,7 +101,7 @@
/// * admin: Admin address.
CollectionAdminAdded(CollectionId, CrossAccountId),
- /// Collection owned was change
+ /// Collection owned was changed
///
/// # Arguments
///
@@ -137,7 +137,7 @@
/// * admin: Admin address.
CollectionAdminRemoved(CollectionId, CrossAccountId),
- /// Address was remove from allow list
+ /// Address was removed from the allow list
///
/// # Arguments
///
@@ -146,7 +146,7 @@
/// * user: Address.
AllowListAddressRemoved(CollectionId, CrossAccountId),
- /// Address was add to allow list
+ /// Address was added to the allow list
///
/// # Arguments
///
@@ -155,13 +155,18 @@
/// * user: Address.
AllowListAddressAdded(CollectionId, CrossAccountId),
- /// Collection limits was set
+ /// Collection limits were set
///
/// # Arguments
///
/// * collection_id: Globally unique collection identifier.
CollectionLimitSet(CollectionId),
+ /// Collection permissions were set
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: Globally unique collection identifier.
CollectionPermissionSet(CollectionId),
}
}
@@ -198,7 +203,7 @@
ChainVersion: u64;
//#endregion
- //#region Tokens transfer rate limit baskets
+ //#region Tokens transfer sponosoring rate limit baskets
/// (Collection id (controlled?2), who created (real))
/// TODO: Off chain worker should remove from this map when collection gets removed
pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;
@@ -214,11 +219,14 @@
/// Collection id (controlled?2), token id (controlled?2)
#[deprecated]
pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
+ /// Last sponsoring of token property setting // todo:doc rephrase this and the following
pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
- /// Approval sponsoring
+ /// Last sponsoring of NFT approval in a collection
pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
+ /// Last sponsoring of fungible tokens approval in a collection
pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
+ /// Last sponsoring of RFT approval in a collection
pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
}
}
@@ -278,9 +286,16 @@
Self::create_collection_ex(origin, data)
}
- /// This method creates a collection
+ /// Create a collection with explicit parameters.
+ /// Prefer it to the deprecated [`created_collection`] method.
+ ///
+ /// # Permissions
+ ///
+ /// * Anyone.
///
- /// Prefer it to deprecated [`created_collection`] method
+ /// # Arguments
+ ///
+ /// * data: explicit create-collection data.
#[weight = <SelfWeightOf<T>>::create_collection()]
#[transactional]
pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {
@@ -293,11 +308,11 @@
Ok(())
}
- /// Destroys collection if no tokens within this collection
+ /// Destroy the collection if no tokens exist within.
///
/// # Permissions
///
- /// * Collection Owner.
+ /// * Collection Owner
///
/// # Arguments
///
@@ -398,7 +413,7 @@
///
/// # Permissions
///
- /// * Collection Owner.
+ /// * Collection Owner
///
/// # Arguments
///
@@ -424,40 +439,40 @@
target_collection.save()
}
- /// Adds an admin of the Collection.
+ /// Adds an admin of the collection.
/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.
///
/// # Permissions
///
- /// * Collection Owner.
- /// * Collection Admin.
+ /// * Collection Owner
+ /// * Collection Admin
///
/// # Arguments
///
/// * collection_id: ID of the Collection to add admin for.
///
- /// * new_admin_id: Address of new admin to add.
+ /// * new_admin: Address of new admin to add.
#[weight = <SelfWeightOf<T>>::add_collection_admin()]
#[transactional]
- pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {
+ pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin: T::CrossAccountId) -> DispatchResult {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let collection = <CollectionHandle<T>>::try_get(collection_id)?;
collection.check_is_internal()?;
<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(
collection_id,
- new_admin_id.clone()
+ new_admin.clone()
));
- <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)
+ <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin, true)
}
/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.
///
/// # Permissions
///
- /// * Collection Owner.
- /// * Collection Admin.
+ /// * Collection Owner
+ /// * Collection Admin
///
/// # Arguments
///
@@ -479,9 +494,12 @@
<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)
}
+ /// Set (invite) a new collection sponsor. If successful, confirmation from the sponsor-to-be will be pending.
+ ///
/// # Permissions
///
/// * Collection Owner
+ /// * Collection Admin
///
/// # Arguments
///
@@ -507,9 +525,11 @@
target_collection.save()
}
+ /// Confirm own sponsorship of a collection.
+ ///
/// # Permissions
///
- /// * Sponsor.
+ /// * The sponsor to-be
///
/// # Arguments
///
@@ -538,7 +558,7 @@
///
/// # Permissions
///
- /// * Collection owner.
+ /// * Collection Owner
///
/// # Arguments
///
@@ -560,12 +580,12 @@
target_collection.save()
}
- /// This method creates a concrete instance of NFT Collection created with CreateCollection method.
+ /// Create a concrete instance of NFT Collection created with CreateCollection method.
///
/// # Permissions
///
- /// * Collection Owner.
- /// * Collection Admin.
+ /// * Collection Owner
+ /// * Collection Admin
/// * Anyone if
/// * Allow List is enabled, and
/// * Address is added to allow list, and
@@ -587,12 +607,12 @@
dispatch_tx::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))
}
- /// This method creates multiple items in a collection created with CreateCollection method.
+ /// Create multiple items in a collection created with CreateCollection method.
///
/// # Permissions
///
- /// * Collection Owner.
- /// * Collection Admin.
+ /// * Collection Owner
+ /// * Collection Admin
/// * Anyone if
/// * Allow List is enabled, and
/// * Address is added to allow list, and
@@ -615,6 +635,18 @@
dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))
}
+ /// Add or change collection properties.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * properties: a vector of key-value pairs stored as the collection's metadata. Keys support Latin letters, '-', '_', and '.' as symbols.
#[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]
#[transactional]
pub fn set_collection_properties(
@@ -629,6 +661,18 @@
dispatch_tx::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))
}
+ /// Delete specified collection properties.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * property_keys: a vector of keys of the properties to be deleted.
#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]
#[transactional]
pub fn delete_collection_properties(
@@ -643,6 +687,22 @@
dispatch_tx::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))
}
+ /// Add or change token properties according to collection's permissions.
+ ///
+ /// # Permissions
+ ///
+ /// * Depends on collection's token property permissions and specified property mutability:
+ /// * Collection Owner
+ /// * Collection Admin
+ /// * Token Owner
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * token_id.
+ ///
+ /// * properties: a vector of key-value pairs stored as the token's metadata. Keys support Latin letters, '-', '_', and '.' as symbols.
#[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]
#[transactional]
pub fn set_token_properties(
@@ -659,6 +719,22 @@
dispatch_tx::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties, &budget))
}
+ /// Delete specified token properties.
+ ///
+ /// # Permissions
+ ///
+ /// * Depends on collection's token property permissions and specified property mutability:
+ /// * Collection Owner
+ /// * Collection Admin
+ /// * Token Owner
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * token_id.
+ ///
+ /// * property_keys: a vector of keys of the properties to be deleted.
#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]
#[transactional]
pub fn delete_token_properties(
@@ -675,6 +751,18 @@
dispatch_tx::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys, &budget))
}
+ /// Add or change token property permissions of a collection.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * property_permissions: a vector of permissions for property keys. Keys support Latin letters, '-', '_', and '.' as symbols.
#[weight = T::CommonWeightInfo::set_token_property_permissions(property_permissions.len() as u32)]
#[transactional]
pub fn set_token_property_permissions(
@@ -689,6 +777,22 @@
dispatch_tx::<T, _>(collection_id, |d| d.set_token_property_permissions(&sender, property_permissions))
}
+ /// Create multiple items inside a collection with explicitly specified initial parameters.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ /// * Anyone if
+ /// * Allow List is enabled, and
+ /// * Address is added to allow list, and
+ /// * MintPermission is enabled (see SetMintPermission method)
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection.
+ ///
+ /// * data: explicit item creation data.
#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]
#[transactional]
pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {
@@ -698,11 +802,11 @@
dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))
}
- /// Set transfers_enabled value for particular collection
+ /// Set transfers_enabled value for particular collection.
///
/// # Permissions
///
- /// * Collection Owner.
+ /// * Collection Owner
///
/// # Arguments
///
@@ -723,13 +827,13 @@
target_collection.save()
}
- /// Destroys a concrete instance of NFT.
+ /// Destroy a concrete instance of NFT.
///
/// # Permissions
///
- /// * Collection Owner.
- /// * Collection Admin.
- /// * Current NFT Owner.
+ /// * Collection Owner
+ /// * Collection Admin
+ /// * Current NFT Owner
///
/// # Arguments
///
@@ -752,7 +856,7 @@
Ok(post_info)
}
- /// Destroys a concrete instance of NFT on behalf of the owner
+ /// Destroy a concrete instance of NFT on behalf of the owner.
/// See also: [`approve`]
///
/// # Permissions
@@ -835,6 +939,7 @@
/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.
///
/// # Permissions
+ ///
/// * Collection Owner
/// * Collection Admin
/// * Current NFT owner
@@ -860,6 +965,18 @@
dispatch_tx::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))
}
+ /// Set specific limits of a collection. Empty, or None fields mean chain default.
+ ///.
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * new_limit: The new limits of the collection. They will overwrite the current ones.
#[weight = <SelfWeightOf<T>>::set_collection_limits()]
#[transactional]
pub fn set_collection_limits(
@@ -882,12 +999,24 @@
target_collection.save()
}
+ /// Set specific permissions of a collection. Empty, or None fields mean chain default.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner
+ /// * Collection Admin
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * new_permission: The new permissions of the collection. They will overwrite the current ones.
#[weight = <SelfWeightOf<T>>::set_collection_limits()]
#[transactional]
pub fn set_collection_permissions(
origin,
collection_id: CollectionId,
- new_limit: CollectionPermissions,
+ new_permission: CollectionPermissions,
) -> DispatchResult {
let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
@@ -895,7 +1024,7 @@
target_collection.check_is_owner_or_admin(&sender)?;
let old_limit = &target_collection.permissions;
- target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;
+ target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_permission)?;
<Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(
collection_id
@@ -904,6 +1033,19 @@
target_collection.save()
}
+ /// Re-partition a refungible token, while owning all of its parts.
+ ///
+ /// # Permissions
+ ///
+ /// * Token Owner (must own every part)
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id.
+ ///
+ /// * token: the ID of the RFT.
+ ///
+ /// * amount: The new number of parts into which the token shall be partitioned.
#[weight = T::RefungibleExtensionsWeightInfo::repartition()]
#[transactional]
pub fn repartition(
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#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20 convert::{TryFrom, TryInto},21 fmt,22};23use frame_support::{24 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25 traits::Get,26 parameter_types,27};2829#[cfg(feature = "serde")]30use serde::{Serialize, Deserialize};3132use sp_core::U256;33use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};34use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};35use frame_support::{BoundedVec, traits::ConstU32};36use derivative::Derivative;37use scale_info::TypeInfo;3839// RMRK40use rmrk_traits::{41 CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,42 ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,43};44pub use rmrk_traits::{45 primitives::{46 CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,47 SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,48 },49 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,50 FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,51};5253mod bounded;54pub mod budget;55pub mod mapping;56mod migration;5758pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;59pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;60pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;6162pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {63 100_00064} else {65 1066};67pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {68 100_00069} else {70 1071};72pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {73 204874} else {75 1076};77pub const COLLECTION_ADMINS_LIMIT: u32 = 5;78pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;79pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {80 1_000_00081} else {82 1083};8485// Timeouts for item types in passed blocks86pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;87pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;88pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;8990pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9192// Schema limits93pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;94pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;95pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;9697pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;9899pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;100pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;101pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;102103pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;104pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;105pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;106107pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;108109pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;110pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;111112/// How much items can be created per single113/// create_many call114pub const MAX_ITEMS_PER_BATCH: u32 = 200;115116pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;117118#[derive(119 Encode,120 Decode,121 PartialEq,122 Eq,123 PartialOrd,124 Ord,125 Clone,126 Copy,127 Debug,128 Default,129 TypeInfo,130 MaxEncodedLen,131)]132#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]133pub struct CollectionId(pub u32);134impl EncodeLike<u32> for CollectionId {}135impl EncodeLike<CollectionId> for u32 {}136137#[derive(138 Encode,139 Decode,140 PartialEq,141 Eq,142 PartialOrd,143 Ord,144 Clone,145 Copy,146 Debug,147 Default,148 TypeInfo,149 MaxEncodedLen,150)]151#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]152pub struct TokenId(pub u32);153impl EncodeLike<u32> for TokenId {}154impl EncodeLike<TokenId> for u32 {}155156impl TokenId {157 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {158 self.0159 .checked_add(1)160 .ok_or(ArithmeticError::Overflow)161 .map(Self)162 }163}164165impl From<TokenId> for U256 {166 fn from(t: TokenId) -> Self {167 t.0.into()168 }169}170171impl TryFrom<U256> for TokenId {172 type Error = &'static str;173174 fn try_from(value: U256) -> Result<Self, Self::Error> {175 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))176 }177}178179#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]180#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]181pub struct TokenData<CrossAccountId> {182 pub properties: Vec<Property>,183 pub owner: Option<CrossAccountId>,184 pub pieces: u128,185}186187pub struct OverflowError;188impl From<OverflowError> for &'static str {189 fn from(_: OverflowError) -> Self {190 "overflow occured"191 }192}193194pub type DecimalPoints = u8;195196#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]197#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]198pub enum CollectionMode {199 NFT,200 // decimal points201 Fungible(DecimalPoints),202 ReFungible,203}204205impl CollectionMode {206 pub fn id(&self) -> u8 {207 match self {208 CollectionMode::NFT => 1,209 CollectionMode::Fungible(_) => 2,210 CollectionMode::ReFungible => 3,211 }212 }213}214215pub trait SponsoringResolve<AccountId, Call> {216 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;217}218219#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]220#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]221pub enum AccessMode {222 Normal,223 AllowList,224}225impl Default for AccessMode {226 fn default() -> Self {227 Self::Normal228 }229}230231#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]232#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]233pub enum SchemaVersion {234 ImageURL,235 Unique,236}237impl Default for SchemaVersion {238 fn default() -> Self {239 Self::ImageURL240 }241}242243#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]244#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]245pub struct Ownership<AccountId> {246 pub owner: AccountId,247 pub fraction: u128,248}249250#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]251#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]252pub enum SponsorshipState<AccountId> {253 /// The fees are applied to the transaction sender254 Disabled,255 Unconfirmed(AccountId),256 /// Transactions are sponsored by specified account257 Confirmed(AccountId),258}259260impl<AccountId> SponsorshipState<AccountId> {261 pub fn sponsor(&self) -> Option<&AccountId> {262 match self {263 Self::Confirmed(sponsor) => Some(sponsor),264 _ => None,265 }266 }267268 pub fn pending_sponsor(&self) -> Option<&AccountId> {269 match self {270 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),271 _ => None,272 }273 }274275 pub fn confirmed(&self) -> bool {276 matches!(self, Self::Confirmed(_))277 }278}279280impl<T> Default for SponsorshipState<T> {281 fn default() -> Self {282 Self::Disabled283 }284}285286/// Used in storage287#[struct_versioning::versioned(version = 2, upper)]288#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]289pub struct Collection<AccountId> {290 pub owner: AccountId,291 pub mode: CollectionMode,292 #[version(..2)]293 pub access: AccessMode,294 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,295 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,296 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,297298 #[version(..2)]299 pub mint_mode: bool,300301 #[version(..2)]302 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,303304 #[version(..2)]305 pub schema_version: SchemaVersion,306 pub sponsorship: SponsorshipState<AccountId>,307308 pub limits: CollectionLimits,309310 #[version(2.., upper(Default::default()))]311 pub permissions: CollectionPermissions,312313 /// Marks that this collection is not "unique", and managed from external.314 #[version(2.., upper(false))]315 pub external_collection: bool,316317 #[version(..2)]318 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,319320 #[version(..2)]321 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,322323 #[version(..2)]324 pub meta_update_permission: MetaUpdatePermission,325}326327/// Used in RPC calls328#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]329#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]330pub struct RpcCollection<AccountId> {331 pub owner: AccountId,332 pub mode: CollectionMode,333 pub name: Vec<u16>,334 pub description: Vec<u16>,335 pub token_prefix: Vec<u8>,336 pub sponsorship: SponsorshipState<AccountId>,337 pub limits: CollectionLimits,338 pub permissions: CollectionPermissions,339 pub token_property_permissions: Vec<PropertyKeyPermission>,340 pub properties: Vec<Property>,341 pub read_only: bool,342}343344#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]345#[derivative(Debug, Default(bound = ""))]346pub struct CreateCollectionData<AccountId> {347 #[derivative(Default(value = "CollectionMode::NFT"))]348 pub mode: CollectionMode,349 pub access: Option<AccessMode>,350 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,351 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,352 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,353 pub pending_sponsor: Option<AccountId>,354 pub limits: Option<CollectionLimits>,355 pub permissions: Option<CollectionPermissions>,356 pub token_property_permissions: CollectionPropertiesPermissionsVec,357 pub properties: CollectionPropertiesVec,358}359360pub type CollectionPropertiesPermissionsVec =361 BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;362363pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;364365/// All fields are wrapped in `Option`s, where None means chain default366// When adding/removing fields from this struct - don't forget to also update clamp_limits367#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]368#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]369pub struct CollectionLimits {370 pub account_token_ownership_limit: Option<u32>,371 pub sponsored_data_size: Option<u32>,372373 /// FIXME should we delete this or repurpose it?374 /// None - setVariableMetadata is not sponsored375 /// Some(v) - setVariableMetadata is sponsored376 /// if there is v block between txs377 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,378 pub token_limit: Option<u32>,379380 // Timeouts for item types in passed blocks381 pub sponsor_transfer_timeout: Option<u32>,382 pub sponsor_approve_timeout: Option<u32>,383 pub owner_can_transfer: Option<bool>,384 pub owner_can_destroy: Option<bool>,385 pub transfers_enabled: Option<bool>,386}387388impl CollectionLimits {389 pub fn account_token_ownership_limit(&self) -> u32 {390 self.account_token_ownership_limit391 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)392 .min(MAX_TOKEN_OWNERSHIP)393 }394 pub fn sponsored_data_size(&self) -> u32 {395 self.sponsored_data_size396 .unwrap_or(CUSTOM_DATA_LIMIT)397 .min(CUSTOM_DATA_LIMIT)398 }399 pub fn token_limit(&self) -> u32 {400 self.token_limit401 .unwrap_or(COLLECTION_TOKEN_LIMIT)402 .min(COLLECTION_TOKEN_LIMIT)403 }404 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {405 self.sponsor_transfer_timeout406 .unwrap_or(default)407 .min(MAX_SPONSOR_TIMEOUT)408 }409 pub fn sponsor_approve_timeout(&self) -> u32 {410 self.sponsor_approve_timeout411 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)412 .min(MAX_SPONSOR_TIMEOUT)413 }414 pub fn owner_can_transfer(&self) -> bool {415 self.owner_can_transfer.unwrap_or(false)416 }417 pub fn owner_can_transfer_instaled(&self) -> bool {418 self.owner_can_transfer.is_some()419 }420 pub fn owner_can_destroy(&self) -> bool {421 self.owner_can_destroy.unwrap_or(true)422 }423 pub fn transfers_enabled(&self) -> bool {424 self.transfers_enabled.unwrap_or(true)425 }426 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {427 match self428 .sponsored_data_rate_limit429 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)430 {431 SponsoringRateLimit::SponsoringDisabled => None,432 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),433 }434 }435}436437// When adding/removing fields from this struct - don't forget to also update clamp_limits438#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]439#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]440pub struct CollectionPermissions {441 pub access: Option<AccessMode>,442 pub mint_mode: Option<bool>,443 pub nesting: Option<NestingPermissions>,444}445446impl CollectionPermissions {447 pub fn access(&self) -> AccessMode {448 self.access.unwrap_or(AccessMode::Normal)449 }450 pub fn mint_mode(&self) -> bool {451 self.mint_mode.unwrap_or(false)452 }453 pub fn nesting(&self) -> &NestingPermissions {454 static DEFAULT: NestingPermissions = NestingPermissions {455 token_owner: false,456 collection_admin: false,457 restricted: None,458 #[cfg(feature = "runtime-benchmarks")]459 permissive: false,460 };461 self.nesting.as_ref().unwrap_or(&DEFAULT)462 }463}464465type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;466467#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]468#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]469#[derivative(Debug)]470pub struct OwnerRestrictedSet(471 #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]472 #[derivative(Debug(format_with = "bounded::set_debug"))]473 pub OwnerRestrictedSetInner,474);475impl OwnerRestrictedSet {476 pub fn new() -> Self {477 Self(Default::default())478 }479}480impl core::ops::Deref for OwnerRestrictedSet {481 type Target = OwnerRestrictedSetInner;482 fn deref(&self) -> &Self::Target {483 &self.0484 }485}486impl core::ops::DerefMut for OwnerRestrictedSet {487 fn deref_mut(&mut self) -> &mut Self::Target {488 &mut self.0489 }490}491492#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]493#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]494#[derivative(Debug)]495pub struct NestingPermissions {496 /// Owner of token can nest tokens under it497 pub token_owner: bool,498 /// Admin of token collection can nest tokens under token499 pub collection_admin: bool,500 /// If set - only tokens from specified collections can be nested501 pub restricted: Option<OwnerRestrictedSet>,502503 #[cfg(feature = "runtime-benchmarks")]504 /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`505 pub permissive: bool,506}507508#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]509#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]510pub enum SponsoringRateLimit {511 SponsoringDisabled,512 Blocks(u32),513}514515#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]516#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]517#[derivative(Debug)]518pub struct CreateNftData {519 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]520 #[derivative(Debug(format_with = "bounded::vec_debug"))]521 pub properties: CollectionPropertiesVec,522}523524#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]525#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]526pub struct CreateFungibleData {527 pub value: u128,528}529530#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]531#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]532#[derivative(Debug)]533pub struct CreateReFungibleData {534 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]535 #[derivative(Debug(format_with = "bounded::vec_debug"))]536 pub const_data: BoundedVec<u8, CustomDataLimit>,537 pub pieces: u128,538}539540#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]541#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]542pub enum MetaUpdatePermission {543 ItemOwner,544 Admin,545 None,546}547548#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]549#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]550pub enum CreateItemData {551 NFT(CreateNftData),552 Fungible(CreateFungibleData),553 ReFungible(CreateReFungibleData),554}555556#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]557#[derivative(Debug)]558pub struct CreateNftExData<CrossAccountId> {559 #[derivative(Debug(format_with = "bounded::vec_debug"))]560 pub properties: CollectionPropertiesVec,561 pub owner: CrossAccountId,562}563564#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]565#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]566pub struct CreateRefungibleExData<CrossAccountId> {567 #[derivative(Debug(format_with = "bounded::vec_debug"))]568 pub const_data: BoundedVec<u8, CustomDataLimit>,569 #[derivative(Debug(format_with = "bounded::map_debug"))]570 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,571}572573#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]574#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]575pub enum CreateItemExData<CrossAccountId> {576 NFT(577 #[derivative(Debug(format_with = "bounded::vec_debug"))]578 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,579 ),580 Fungible(581 #[derivative(Debug(format_with = "bounded::map_debug"))]582 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,583 ),584 /// Many tokens, each may have only one owner585 RefungibleMultipleItems(586 #[derivative(Debug(format_with = "bounded::vec_debug"))]587 BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,588 ),589 /// Single token, which may have many owners590 RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),591}592593impl CreateItemData {594 pub fn data_size(&self) -> usize {595 match self {596 CreateItemData::ReFungible(data) => data.const_data.len(),597 _ => 0,598 }599 }600}601602impl From<CreateNftData> for CreateItemData {603 fn from(item: CreateNftData) -> Self {604 CreateItemData::NFT(item)605 }606}607608impl From<CreateReFungibleData> for CreateItemData {609 fn from(item: CreateReFungibleData) -> Self {610 CreateItemData::ReFungible(item)611 }612}613614impl From<CreateFungibleData> for CreateItemData {615 fn from(item: CreateFungibleData) -> Self {616 CreateItemData::Fungible(item)617 }618}619620#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]621#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]622// todo possibly rename to be used generally as an address pair623pub struct TokenChild {624 pub token: TokenId,625 pub collection: CollectionId,626}627628#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]629#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]630pub struct CollectionStats {631 pub created: u32,632 pub destroyed: u32,633 pub alive: u32,634}635636#[derive(Encode, Decode, Clone, Debug)]637#[cfg_attr(feature = "std", derive(PartialEq))]638pub struct PhantomType<T>(core::marker::PhantomData<T>);639640impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {641 type Identity = PhantomType<T>;642643 fn type_info() -> scale_info::Type {644 use scale_info::{645 Type, Path,646 build::{FieldsBuilder, UnnamedFields},647 type_params,648 };649 Type::builder()650 .path(Path::new("up_data_structs", "PhantomType"))651 .type_params(type_params!(T))652 .composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))653 }654}655impl<T> MaxEncodedLen for PhantomType<T> {656 fn max_encoded_len() -> usize {657 0658 }659}660661pub type BoundedBytes<S> = BoundedVec<u8, S>;662663pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;664665pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;666pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;667668#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]669#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]670pub struct PropertyPermission {671 pub mutable: bool,672 pub collection_admin: bool,673 pub token_owner: bool,674}675676impl PropertyPermission {677 pub fn none() -> Self {678 Self {679 mutable: true,680 collection_admin: false,681 token_owner: false,682 }683 }684}685686#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]687#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]688pub struct Property {689 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]690 pub key: PropertyKey,691692 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]693 pub value: PropertyValue,694}695696impl Into<(PropertyKey, PropertyValue)> for Property {697 fn into(self) -> (PropertyKey, PropertyValue) {698 (self.key, self.value)699 }700}701702#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]703#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]704pub struct PropertyKeyPermission {705 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]706 pub key: PropertyKey,707708 pub permission: PropertyPermission,709}710711impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {712 fn into(self) -> (PropertyKey, PropertyPermission) {713 (self.key, self.permission)714 }715}716717#[derive(Debug)]718pub enum PropertiesError {719 NoSpaceForProperty,720 PropertyLimitReached,721 InvalidCharacterInPropertyKey,722 PropertyKeyIsTooLong,723 EmptyPropertyKey,724}725726#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]727pub enum PropertyScope {728 None,729 Rmrk,730}731732impl PropertyScope {733 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {734 let scope_str: &[u8] = match self {735 Self::None => return Ok(key),736 Self::Rmrk => b"rmrk",737 };738739 [scope_str, b":", key.as_slice()]740 .concat()741 .try_into()742 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)743 }744}745746pub trait TrySetProperty: Sized {747 type Value;748749 fn try_scoped_set(750 &mut self,751 scope: PropertyScope,752 key: PropertyKey,753 value: Self::Value,754 ) -> Result<(), PropertiesError>;755756 fn try_scoped_set_from_iter<I, KV>(757 &mut self,758 scope: PropertyScope,759 iter: I,760 ) -> Result<(), PropertiesError>761 where762 I: Iterator<Item = KV>,763 KV: Into<(PropertyKey, Self::Value)>,764 {765 for kv in iter {766 let (key, value) = kv.into();767 self.try_scoped_set(scope, key, value)?;768 }769770 Ok(())771 }772773 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {774 self.try_scoped_set(PropertyScope::None, key, value)775 }776777 fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>778 where779 I: Iterator<Item = KV>,780 KV: Into<(PropertyKey, Self::Value)>,781 {782 self.try_scoped_set_from_iter(PropertyScope::None, iter)783 }784}785786#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]787#[derivative(Default(bound = ""))]788pub struct PropertiesMap<Value>(789 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,790);791792impl<Value> PropertiesMap<Value> {793 pub fn new() -> Self {794 Self(BoundedBTreeMap::new())795 }796797 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {798 Self::check_property_key(key)?;799800 Ok(self.0.remove(key))801 }802803 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {804 self.0.get(key)805 }806807 pub fn contains_key(&self, key: &PropertyKey) -> bool {808 self.0.contains_key(key)809 }810811 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {812 if key.is_empty() {813 return Err(PropertiesError::EmptyPropertyKey);814 }815816 for byte in key.as_slice().iter() {817 let byte = *byte;818819 if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {820 return Err(PropertiesError::InvalidCharacterInPropertyKey);821 }822 }823824 Ok(())825 }826}827828impl<Value> IntoIterator for PropertiesMap<Value> {829 type Item = (PropertyKey, Value);830 type IntoIter = <831 BoundedBTreeMap<832 PropertyKey,833 Value,834 ConstU32<MAX_PROPERTIES_PER_ITEM>835 > as IntoIterator836 >::IntoIter;837838 fn into_iter(self) -> Self::IntoIter {839 self.0.into_iter()840 }841}842843impl<Value> TrySetProperty for PropertiesMap<Value> {844 type Value = Value;845846 fn try_scoped_set(847 &mut self,848 scope: PropertyScope,849 key: PropertyKey,850 value: Self::Value,851 ) -> Result<(), PropertiesError> {852 Self::check_property_key(&key)?;853854 let key = scope.apply(key)?;855 self.0856 .try_insert(key, value)857 .map_err(|_| PropertiesError::PropertyLimitReached)?;858859 Ok(())860 }861}862863pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;864865#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]866pub struct Properties {867 map: PropertiesMap<PropertyValue>,868 consumed_space: u32,869 space_limit: u32,870}871872impl Properties {873 pub fn new(space_limit: u32) -> Self {874 Self {875 map: PropertiesMap::new(),876 consumed_space: 0,877 space_limit,878 }879 }880881 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {882 let value = self.map.remove(key)?;883884 if let Some(ref value) = value {885 let value_len = value.len() as u32;886 self.consumed_space -= value_len;887 }888889 Ok(value)890 }891892 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {893 self.map.get(key)894 }895}896897impl IntoIterator for Properties {898 type Item = (PropertyKey, PropertyValue);899 type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;900901 fn into_iter(self) -> Self::IntoIter {902 self.map.into_iter()903 }904}905906impl TrySetProperty for Properties {907 type Value = PropertyValue;908909 fn try_scoped_set(910 &mut self,911 scope: PropertyScope,912 key: PropertyKey,913 value: Self::Value,914 ) -> Result<(), PropertiesError> {915 let value_len = value.len();916917 if self.consumed_space as usize + value_len > self.space_limit as usize918 && !cfg!(feature = "runtime-benchmarks")919 {920 return Err(PropertiesError::NoSpaceForProperty);921 }922923 self.map.try_scoped_set(scope, key, value)?;924925 self.consumed_space += value_len as u32;926927 Ok(())928 }929}930931pub struct CollectionProperties;932933impl Get<Properties> for CollectionProperties {934 fn get() -> Properties {935 Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)936 }937}938939pub struct TokenProperties;940941impl Get<Properties> for TokenProperties {942 fn get() -> Properties {943 Properties::new(MAX_TOKEN_PROPERTIES_SIZE)944 }945}946947// RMRK948// todo document?949parameter_types! {950 #[derive(PartialEq, TypeInfo)]951 pub const RmrkStringLimit: u32 = 128;952 #[derive(PartialEq)]953 pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;954 #[derive(PartialEq)]955 pub const RmrkResourceSymbolLimit: u32 = 10;956 #[derive(PartialEq)]957 pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;958 #[derive(PartialEq)]959 pub const RmrkKeyLimit: u32 = 32;960 #[derive(PartialEq)]961 pub const RmrkValueLimit: u32 = 256;962 #[derive(PartialEq)]963 pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;964 #[derive(PartialEq)]965 pub const MaxPropertiesPerTheme: u32 = 5;966 #[derive(PartialEq)]967 pub const RmrkPartsLimit: u32 = 25;968 #[derive(PartialEq)]969 pub const RmrkMaxPriorities: u32 = 25;970 #[derive(PartialEq)]971 pub const MaxResourcesOnMint: u32 = 100;972}973974impl From<RmrkCollectionId> for CollectionId {975 fn from(id: RmrkCollectionId) -> Self {976 Self(id)977 }978}979980impl From<RmrkNftId> for TokenId {981 fn from(id: RmrkNftId) -> Self {982 Self(id)983 }984}985986pub type RmrkCollectionInfo<AccountId> =987 CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;988pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;989pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;990pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;991pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;992pub type BoundedEquippableCollectionIds =993 BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;994pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;995pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;996pub type RmrkThemeProperty = ThemeProperty<RmrkString>;997pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;998pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;999pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;10001001pub type RmrkBasicResource = BasicResource<RmrkString>;1002pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;1003pub type RmrkSlotResource = SlotResource<RmrkString>;10041005pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;1006pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;1007pub type RmrkBaseSymbol = BoundedVec<u8, RmrkBaseSymbolLimit>;1008pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;1009pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;1010pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;1011pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed10121013pub type RmrkRpcString = Vec<u8>;1014pub type RmrkThemeName = RmrkRpcString;1015pub type RmrkPropertyKey = RmrkRpcString;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#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20 convert::{TryFrom, TryInto},21 fmt,22};23use frame_support::{24 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25 traits::Get,26 parameter_types,27};2829#[cfg(feature = "serde")]30use serde::{Serialize, Deserialize};3132use sp_core::U256;33use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};34use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};35use frame_support::{BoundedVec, traits::ConstU32};36use derivative::Derivative;37use scale_info::TypeInfo;3839// RMRK40use rmrk_traits::{41 CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,42 ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,43};44pub use rmrk_traits::{45 primitives::{46 CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,47 SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,48 },49 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,50 FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,51};5253mod bounded;54pub mod budget;55pub mod mapping;56mod migration;5758pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;59pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;60pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;6162pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {63 100_00064} else {65 1066};67pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {68 100_00069} else {70 1071};72pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {73 204874} else {75 1076};77pub const COLLECTION_ADMINS_LIMIT: u32 = 5;78pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;79pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {80 1_000_00081} else {82 1083};8485// Timeouts for item types in passed blocks86pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;87pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;88pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;8990pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9192// Schema limits93pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;94pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;95pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;9697pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;9899pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;100pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;101pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;102103pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;104pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;105pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;106107pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;108109pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;110pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;111112/// How much items can be created per single113/// create_many call114pub const MAX_ITEMS_PER_BATCH: u32 = 200;115116pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;117118#[derive(119 Encode,120 Decode,121 PartialEq,122 Eq,123 PartialOrd,124 Ord,125 Clone,126 Copy,127 Debug,128 Default,129 TypeInfo,130 MaxEncodedLen,131)]132#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]133pub struct CollectionId(pub u32);134impl EncodeLike<u32> for CollectionId {}135impl EncodeLike<CollectionId> for u32 {}136137#[derive(138 Encode,139 Decode,140 PartialEq,141 Eq,142 PartialOrd,143 Ord,144 Clone,145 Copy,146 Debug,147 Default,148 TypeInfo,149 MaxEncodedLen,150)]151#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]152pub struct TokenId(pub u32);153impl EncodeLike<u32> for TokenId {}154impl EncodeLike<TokenId> for u32 {}155156impl TokenId {157 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {158 self.0159 .checked_add(1)160 .ok_or(ArithmeticError::Overflow)161 .map(Self)162 }163}164165impl From<TokenId> for U256 {166 fn from(t: TokenId) -> Self {167 t.0.into()168 }169}170171impl TryFrom<U256> for TokenId {172 type Error = &'static str;173174 fn try_from(value: U256) -> Result<Self, Self::Error> {175 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))176 }177}178179#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]180#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]181pub struct TokenData<CrossAccountId> {182 pub properties: Vec<Property>,183 pub owner: Option<CrossAccountId>,184 pub pieces: u128,185}186187pub struct OverflowError;188impl From<OverflowError> for &'static str {189 fn from(_: OverflowError) -> Self {190 "overflow occured"191 }192}193194pub type DecimalPoints = u8;195196#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]197#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]198pub enum CollectionMode {199 NFT,200 Fungible(DecimalPoints),201 ReFungible,202}203204impl CollectionMode {205 pub fn id(&self) -> u8 {206 match self {207 CollectionMode::NFT => 1,208 CollectionMode::Fungible(_) => 2,209 CollectionMode::ReFungible => 3,210 }211 }212}213214pub trait SponsoringResolve<AccountId, Call> {215 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;216}217218#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]219#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]220pub enum AccessMode {221 Normal,222 AllowList,223}224impl Default for AccessMode {225 fn default() -> Self {226 Self::Normal227 }228}229230#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]231#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]232pub enum SchemaVersion {233 ImageURL,234 Unique,235}236impl Default for SchemaVersion {237 fn default() -> Self {238 Self::ImageURL239 }240}241242#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]243#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]244pub struct Ownership<AccountId> {245 pub owner: AccountId,246 pub fraction: u128,247}248249#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]250#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]251pub enum SponsorshipState<AccountId> {252 /// The fees are applied to the transaction sender253 Disabled,254 /// Pending confirmation from a sponsor-to-be255 Unconfirmed(AccountId),256 /// Transactions are sponsored by specified account257 Confirmed(AccountId),258}259260impl<AccountId> SponsorshipState<AccountId> {261 /// Get the acting sponsor account, if present262 pub fn sponsor(&self) -> Option<&AccountId> {263 match self {264 Self::Confirmed(sponsor) => Some(sponsor),265 _ => None,266 }267 }268269 /// Get the sponsor account currently pending confirmation, if present270 pub fn pending_sponsor(&self) -> Option<&AccountId> {271 match self {272 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),273 _ => None,274 }275 }276277 /// Is sponsorship set and acting278 pub fn confirmed(&self) -> bool {279 matches!(self, Self::Confirmed(_))280 }281}282283impl<T> Default for SponsorshipState<T> {284 fn default() -> Self {285 Self::Disabled286 }287}288289/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version)290#[struct_versioning::versioned(version = 2, upper)]291#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]292pub struct Collection<AccountId> {293 pub owner: AccountId,294 pub mode: CollectionMode,295 #[version(..2)]296 pub access: AccessMode,297 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,298 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,299 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,300301 #[version(..2)]302 pub mint_mode: bool,303304 #[version(..2)]305 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,306307 #[version(..2)]308 pub schema_version: SchemaVersion,309 pub sponsorship: SponsorshipState<AccountId>,310311 pub limits: CollectionLimits,312313 #[version(2.., upper(Default::default()))]314 pub permissions: CollectionPermissions,315316 /// Marks that this collection is not "unique", and managed from external.317 #[version(2.., upper(false))]318 pub external_collection: bool,319320 #[version(..2)]321 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,322323 #[version(..2)]324 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,325326 #[version(..2)]327 pub meta_update_permission: MetaUpdatePermission,328}329330/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version)331#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]332#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]333pub struct RpcCollection<AccountId> {334 pub owner: AccountId,335 pub mode: CollectionMode,336 pub name: Vec<u16>,337 pub description: Vec<u16>,338 pub token_prefix: Vec<u8>,339 pub sponsorship: SponsorshipState<AccountId>,340 pub limits: CollectionLimits,341 pub permissions: CollectionPermissions,342 pub token_property_permissions: Vec<PropertyKeyPermission>,343 pub properties: Vec<Property>,344 pub read_only: bool,345}346347#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]348#[derivative(Debug, Default(bound = ""))]349pub struct CreateCollectionData<AccountId> {350 #[derivative(Default(value = "CollectionMode::NFT"))]351 pub mode: CollectionMode,352 pub access: Option<AccessMode>,353 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,354 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,355 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,356 pub pending_sponsor: Option<AccountId>,357 pub limits: Option<CollectionLimits>,358 pub permissions: Option<CollectionPermissions>,359 pub token_property_permissions: CollectionPropertiesPermissionsVec,360 pub properties: CollectionPropertiesVec,361}362363pub type CollectionPropertiesPermissionsVec =364 BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;365366pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;367368/// Limits and restrictions of a collection.369/// All fields are wrapped in `Option`s, where None means chain default.370// When adding/removing fields from this struct - don't forget to also update clamp_limits371#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]372#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]373pub struct CollectionLimits {374 /// Maximum number of owned tokens per account375 pub account_token_ownership_limit: Option<u32>,376 /// Maximum size of data of a sponsored transaction377 pub sponsored_data_size: Option<u32>,378379 /// FIXME should we delete this or repurpose it?380 /// None - setVariableMetadata is not sponsored381 /// Some(v) - setVariableMetadata is sponsored382 /// if there is v block between txs383 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,384 /// Maximum amount of tokens inside the collection385 pub token_limit: Option<u32>,386387 /// Timeout for sponsoring a token transfer in passed blocks388 pub sponsor_transfer_timeout: Option<u32>,389 /// Timeout for sponsoring an approval in passed blocks390 pub sponsor_approve_timeout: Option<u32>,391 /// Can a token be transferred by the owner392 pub owner_can_transfer: Option<bool>,393 /// Can a token be burned by the owner394 pub owner_can_destroy: Option<bool>,395 /// Can a token be transferred at all396 pub transfers_enabled: Option<bool>,397}398399impl CollectionLimits {400 pub fn account_token_ownership_limit(&self) -> u32 {401 self.account_token_ownership_limit402 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)403 .min(MAX_TOKEN_OWNERSHIP)404 }405 pub fn sponsored_data_size(&self) -> u32 {406 self.sponsored_data_size407 .unwrap_or(CUSTOM_DATA_LIMIT)408 .min(CUSTOM_DATA_LIMIT)409 }410 pub fn token_limit(&self) -> u32 {411 self.token_limit412 .unwrap_or(COLLECTION_TOKEN_LIMIT)413 .min(COLLECTION_TOKEN_LIMIT)414 }415 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {416 self.sponsor_transfer_timeout417 .unwrap_or(default)418 .min(MAX_SPONSOR_TIMEOUT)419 }420 pub fn sponsor_approve_timeout(&self) -> u32 {421 self.sponsor_approve_timeout422 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)423 .min(MAX_SPONSOR_TIMEOUT)424 }425 pub fn owner_can_transfer(&self) -> bool {426 self.owner_can_transfer.unwrap_or(false)427 }428 pub fn owner_can_transfer_instaled(&self) -> bool {429 self.owner_can_transfer.is_some()430 }431 pub fn owner_can_destroy(&self) -> bool {432 self.owner_can_destroy.unwrap_or(true)433 }434 pub fn transfers_enabled(&self) -> bool {435 self.transfers_enabled.unwrap_or(true)436 }437 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {438 match self439 .sponsored_data_rate_limit440 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)441 {442 SponsoringRateLimit::SponsoringDisabled => None,443 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),444 }445 }446}447448// When adding/removing fields from this struct - don't forget to also update clamp_limits449#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]450#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]451pub struct CollectionPermissions {452 pub access: Option<AccessMode>,453 pub mint_mode: Option<bool>,454 pub nesting: Option<NestingPermissions>,455}456457impl CollectionPermissions {458 pub fn access(&self) -> AccessMode {459 self.access.unwrap_or(AccessMode::Normal)460 }461 pub fn mint_mode(&self) -> bool {462 self.mint_mode.unwrap_or(false)463 }464 pub fn nesting(&self) -> &NestingPermissions {465 static DEFAULT: NestingPermissions = NestingPermissions {466 token_owner: false,467 collection_admin: false,468 restricted: None,469 #[cfg(feature = "runtime-benchmarks")]470 permissive: false,471 };472 self.nesting.as_ref().unwrap_or(&DEFAULT)473 }474}475476type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;477478#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]479#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]480#[derivative(Debug)]481pub struct OwnerRestrictedSet(482 #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]483 #[derivative(Debug(format_with = "bounded::set_debug"))]484 pub OwnerRestrictedSetInner,485);486impl OwnerRestrictedSet {487 pub fn new() -> Self {488 Self(Default::default())489 }490}491impl core::ops::Deref for OwnerRestrictedSet {492 type Target = OwnerRestrictedSetInner;493 fn deref(&self) -> &Self::Target {494 &self.0495 }496}497impl core::ops::DerefMut for OwnerRestrictedSet {498 fn deref_mut(&mut self) -> &mut Self::Target {499 &mut self.0500 }501}502503#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]504#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]505#[derivative(Debug)]506pub struct NestingPermissions {507 /// Owner of token can nest tokens under it508 pub token_owner: bool,509 /// Admin of token collection can nest tokens under token510 pub collection_admin: bool,511 /// If set - only tokens from specified collections can be nested512 pub restricted: Option<OwnerRestrictedSet>,513514 #[cfg(feature = "runtime-benchmarks")]515 /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`516 pub permissive: bool,517}518519#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]520#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]521pub enum SponsoringRateLimit {522 SponsoringDisabled,523 /// Once per how many blocks can sponsorship of a transaction type occur524 Blocks(u32),525}526527#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]528#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]529#[derivative(Debug)]530pub struct CreateNftData {531 /// Key-value pairs used to describe the token as metadata532 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]533 #[derivative(Debug(format_with = "bounded::vec_debug"))]534 pub properties: CollectionPropertiesVec,535}536537#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]538#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]539pub struct CreateFungibleData {540 /// Number of fungible tokens minted541 pub value: u128,542}543544#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]545#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]546#[derivative(Debug)]547pub struct CreateReFungibleData {548 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]549 #[derivative(Debug(format_with = "bounded::vec_debug"))]550 pub const_data: BoundedVec<u8, CustomDataLimit>,551 /// Number of pieces the RFT is split into552 pub pieces: u128,553}554555#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]556#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]557pub enum MetaUpdatePermission {558 ItemOwner,559 Admin,560 None,561}562563#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]564#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]565pub enum CreateItemData {566 NFT(CreateNftData),567 Fungible(CreateFungibleData),568 ReFungible(CreateReFungibleData),569}570571/// Explicit NFT creation data with meta parameters572#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]573#[derivative(Debug)]574pub struct CreateNftExData<CrossAccountId> {575 #[derivative(Debug(format_with = "bounded::vec_debug"))]576 pub properties: CollectionPropertiesVec,577 pub owner: CrossAccountId,578}579580/// Explicit RFT creation data with meta parameters581#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]582#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]583pub struct CreateRefungibleExData<CrossAccountId> {584 #[derivative(Debug(format_with = "bounded::vec_debug"))]585 pub const_data: BoundedVec<u8, CustomDataLimit>,586 #[derivative(Debug(format_with = "bounded::map_debug"))]587 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,588}589590/// Explicit item creation data with meta parameters, namely the owner591#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]592#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]593pub enum CreateItemExData<CrossAccountId> {594 NFT(595 #[derivative(Debug(format_with = "bounded::vec_debug"))]596 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,597 ),598 Fungible(599 #[derivative(Debug(format_with = "bounded::map_debug"))]600 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,601 ),602 /// Many tokens, each may have only one owner603 RefungibleMultipleItems(604 #[derivative(Debug(format_with = "bounded::vec_debug"))]605 BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,606 ),607 /// Single token, which may have many owners608 RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),609}610611impl CreateItemData {612 pub fn data_size(&self) -> usize {613 match self {614 CreateItemData::ReFungible(data) => data.const_data.len(),615 _ => 0,616 }617 }618}619620impl From<CreateNftData> for CreateItemData {621 fn from(item: CreateNftData) -> Self {622 CreateItemData::NFT(item)623 }624}625626impl From<CreateReFungibleData> for CreateItemData {627 fn from(item: CreateReFungibleData) -> Self {628 CreateItemData::ReFungible(item)629 }630}631632impl From<CreateFungibleData> for CreateItemData {633 fn from(item: CreateFungibleData) -> Self {634 CreateItemData::Fungible(item)635 }636}637638/// Token's address, dictated by its collection and token IDs639#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]640#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]641// todo possibly rename to be used generally as an address pair642pub struct TokenChild {643 pub token: TokenId,644 pub collection: CollectionId,645}646647#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]648#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]649pub struct CollectionStats {650 pub created: u32,651 pub destroyed: u32,652 pub alive: u32,653}654655#[derive(Encode, Decode, Clone, Debug)]656#[cfg_attr(feature = "std", derive(PartialEq))]657pub struct PhantomType<T>(core::marker::PhantomData<T>);658659impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {660 type Identity = PhantomType<T>;661662 fn type_info() -> scale_info::Type {663 use scale_info::{664 Type, Path,665 build::{FieldsBuilder, UnnamedFields},666 type_params,667 };668 Type::builder()669 .path(Path::new("up_data_structs", "PhantomType"))670 .type_params(type_params!(T))671 .composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))672 }673}674impl<T> MaxEncodedLen for PhantomType<T> {675 fn max_encoded_len() -> usize {676 0677 }678}679680pub type BoundedBytes<S> = BoundedVec<u8, S>;681682pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;683684pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;685pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;686687#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]688#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]689pub struct PropertyPermission {690 pub mutable: bool,691 pub collection_admin: bool,692 pub token_owner: bool,693}694695impl PropertyPermission {696 pub fn none() -> Self {697 Self {698 mutable: true,699 collection_admin: false,700 token_owner: false,701 }702 }703}704705#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]706#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]707pub struct Property {708 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]709 pub key: PropertyKey,710711 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]712 pub value: PropertyValue,713}714715impl Into<(PropertyKey, PropertyValue)> for Property {716 fn into(self) -> (PropertyKey, PropertyValue) {717 (self.key, self.value)718 }719}720721#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]722#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]723pub struct PropertyKeyPermission {724 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]725 pub key: PropertyKey,726727 pub permission: PropertyPermission,728}729730impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {731 fn into(self) -> (PropertyKey, PropertyPermission) {732 (self.key, self.permission)733 }734}735736#[derive(Debug)]737pub enum PropertiesError {738 NoSpaceForProperty,739 PropertyLimitReached,740 InvalidCharacterInPropertyKey,741 PropertyKeyIsTooLong,742 EmptyPropertyKey,743}744745#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]746pub enum PropertyScope {747 None,748 Rmrk,749}750751impl PropertyScope {752 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {753 let scope_str: &[u8] = match self {754 Self::None => return Ok(key),755 Self::Rmrk => b"rmrk",756 };757758 [scope_str, b":", key.as_slice()]759 .concat()760 .try_into()761 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)762 }763}764765pub trait TrySetProperty: Sized {766 type Value;767768 fn try_scoped_set(769 &mut self,770 scope: PropertyScope,771 key: PropertyKey,772 value: Self::Value,773 ) -> Result<(), PropertiesError>;774775 fn try_scoped_set_from_iter<I, KV>(776 &mut self,777 scope: PropertyScope,778 iter: I,779 ) -> Result<(), PropertiesError>780 where781 I: Iterator<Item = KV>,782 KV: Into<(PropertyKey, Self::Value)>,783 {784 for kv in iter {785 let (key, value) = kv.into();786 self.try_scoped_set(scope, key, value)?;787 }788789 Ok(())790 }791792 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {793 self.try_scoped_set(PropertyScope::None, key, value)794 }795796 fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>797 where798 I: Iterator<Item = KV>,799 KV: Into<(PropertyKey, Self::Value)>,800 {801 self.try_scoped_set_from_iter(PropertyScope::None, iter)802 }803}804805#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]806#[derivative(Default(bound = ""))]807pub struct PropertiesMap<Value>(808 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,809);810811impl<Value> PropertiesMap<Value> {812 pub fn new() -> Self {813 Self(BoundedBTreeMap::new())814 }815816 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {817 Self::check_property_key(key)?;818819 Ok(self.0.remove(key))820 }821822 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {823 self.0.get(key)824 }825826 pub fn contains_key(&self, key: &PropertyKey) -> bool {827 self.0.contains_key(key)828 }829830 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {831 if key.is_empty() {832 return Err(PropertiesError::EmptyPropertyKey);833 }834835 for byte in key.as_slice().iter() {836 let byte = *byte;837838 if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {839 return Err(PropertiesError::InvalidCharacterInPropertyKey);840 }841 }842843 Ok(())844 }845}846847impl<Value> IntoIterator for PropertiesMap<Value> {848 type Item = (PropertyKey, Value);849 type IntoIter = <850 BoundedBTreeMap<851 PropertyKey,852 Value,853 ConstU32<MAX_PROPERTIES_PER_ITEM>854 > as IntoIterator855 >::IntoIter;856857 fn into_iter(self) -> Self::IntoIter {858 self.0.into_iter()859 }860}861862impl<Value> TrySetProperty for PropertiesMap<Value> {863 type Value = Value;864865 fn try_scoped_set(866 &mut self,867 scope: PropertyScope,868 key: PropertyKey,869 value: Self::Value,870 ) -> Result<(), PropertiesError> {871 Self::check_property_key(&key)?;872873 let key = scope.apply(key)?;874 self.0875 .try_insert(key, value)876 .map_err(|_| PropertiesError::PropertyLimitReached)?;877878 Ok(())879 }880}881882pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;883884#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]885pub struct Properties {886 map: PropertiesMap<PropertyValue>,887 consumed_space: u32,888 space_limit: u32,889}890891impl Properties {892 pub fn new(space_limit: u32) -> Self {893 Self {894 map: PropertiesMap::new(),895 consumed_space: 0,896 space_limit,897 }898 }899900 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {901 let value = self.map.remove(key)?;902903 if let Some(ref value) = value {904 let value_len = value.len() as u32;905 self.consumed_space -= value_len;906 }907908 Ok(value)909 }910911 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {912 self.map.get(key)913 }914}915916impl IntoIterator for Properties {917 type Item = (PropertyKey, PropertyValue);918 type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;919920 fn into_iter(self) -> Self::IntoIter {921 self.map.into_iter()922 }923}924925impl TrySetProperty for Properties {926 type Value = PropertyValue;927928 fn try_scoped_set(929 &mut self,930 scope: PropertyScope,931 key: PropertyKey,932 value: Self::Value,933 ) -> Result<(), PropertiesError> {934 let value_len = value.len();935936 if self.consumed_space as usize + value_len > self.space_limit as usize937 && !cfg!(feature = "runtime-benchmarks")938 {939 return Err(PropertiesError::NoSpaceForProperty);940 }941942 self.map.try_scoped_set(scope, key, value)?;943944 self.consumed_space += value_len as u32;945946 Ok(())947 }948}949950pub struct CollectionProperties;951952impl Get<Properties> for CollectionProperties {953 fn get() -> Properties {954 Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)955 }956}957958pub struct TokenProperties;959960impl Get<Properties> for TokenProperties {961 fn get() -> Properties {962 Properties::new(MAX_TOKEN_PROPERTIES_SIZE)963 }964}965966// RMRK967// todo document?968parameter_types! {969 #[derive(PartialEq, TypeInfo)]970 pub const RmrkStringLimit: u32 = 128;971 #[derive(PartialEq)]972 pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;973 #[derive(PartialEq)]974 pub const RmrkResourceSymbolLimit: u32 = 10;975 #[derive(PartialEq)]976 pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;977 #[derive(PartialEq)]978 pub const RmrkKeyLimit: u32 = 32;979 #[derive(PartialEq)]980 pub const RmrkValueLimit: u32 = 256;981 #[derive(PartialEq)]982 pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;983 #[derive(PartialEq)]984 pub const MaxPropertiesPerTheme: u32 = 5;985 #[derive(PartialEq)]986 pub const RmrkPartsLimit: u32 = 25;987 #[derive(PartialEq)]988 pub const RmrkMaxPriorities: u32 = 25;989 #[derive(PartialEq)]990 pub const MaxResourcesOnMint: u32 = 100;991}992993impl From<RmrkCollectionId> for CollectionId {994 fn from(id: RmrkCollectionId) -> Self {995 Self(id)996 }997}998999impl From<RmrkNftId> for TokenId {1000 fn from(id: RmrkNftId) -> Self {1001 Self(id)1002 }1003}10041005pub type RmrkCollectionInfo<AccountId> =1006 CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;1007pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;1008pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;1009pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;1010pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;1011pub type BoundedEquippableCollectionIds =1012 BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;1013pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;1014pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;1015pub type RmrkThemeProperty = ThemeProperty<RmrkString>;1016pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;1017pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;1018pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;10191020pub type RmrkBasicResource = BasicResource<RmrkString>;1021pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;1022pub type RmrkSlotResource = SlotResource<RmrkString>;10231024pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;1025pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;1026pub type RmrkBaseSymbol = BoundedVec<u8, RmrkBaseSymbolLimit>;1027pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;1028pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;1029pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;1030pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; // todo make sure it is needed10311032pub type RmrkRpcString = Vec<u8>;1033pub type RmrkThemeName = RmrkRpcString;1034pub type RmrkPropertyKey = RmrkRpcString;tests/src/interfaces/unique/definitions.tsdiffbeforeafterboth--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -43,13 +43,13 @@
accountTokens: fun('Get tokens owned by account', [collectionParam, crossAccountParam()], 'Vec<u32>'),
collectionTokens: fun('Get tokens contained in collection', [collectionParam], 'Vec<u32>'),
- lastTokenId: fun('Get last token id', [collectionParam], 'u32'),
+ lastTokenId: fun('Get last token ID created in a collection', [collectionParam], 'u32'),
totalSupply: fun('Get amount of unique collection tokens', [collectionParam], 'u32'),
- accountBalance: fun('Get amount of different user tokens', [collectionParam, crossAccountParam()], 'u32'),
- balance: fun('Get amount of specific account token', [collectionParam, crossAccountParam(), tokenParam], 'u128'),
+ accountBalance: fun('Get owned amount of any user tokens', [collectionParam, crossAccountParam()], 'u32'),
+ balance: fun('Get owned amount of specific account token', [collectionParam, crossAccountParam(), tokenParam], 'u128'),
allowance: fun('Get allowed amount', [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 'u128'),
tokenOwner: fun('Get token owner', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
- topmostTokenOwner: fun('Get token owner, in case of nested token - find parent recursive', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
+ topmostTokenOwner: fun('Get token owner, in case of nested token - find the parent recursively', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
tokenChildren: fun('Get tokens nested directly into the token', [collectionParam, tokenParam], 'Vec<UpDataStructsTokenChild>'),
constMetadata: fun('Get token constant metadata', [collectionParam, tokenParam], 'Vec<u8>'),
variableMetadata: fun('Get token variable metadata', [collectionParam, tokenParam], 'Vec<u8>'),
@@ -74,7 +74,7 @@
'UpDataStructsTokenData',
),
tokenExists: fun('Check if token exists', [collectionParam, tokenParam], 'bool'),
- collectionById: fun('Get collection by specified id', [collectionParam], 'Option<UpDataStructsRpcCollection>'),
+ collectionById: fun('Get collection by specified ID', [collectionParam], 'Option<UpDataStructsRpcCollection>'),
collectionStats: fun('Get collection stats', [], 'UpDataStructsCollectionStats'),
allowed: fun('Check if user is allowed to use collection', [collectionParam, crossAccountParam()], 'bool'),
nextSponsored: fun('Get number of blocks when sponsored transaction is available', [collectionParam, crossAccountParam(), tokenParam], 'Option<u64>'),