git.delta.rocks / unique-network / refs/commits / d4f7a1e6b1bd

difftreelog

Merge pull request #427 from UniqueNetwork/doc/architectural-changes

Yaroslav Bolyukin2022-07-22parents: #281e817 #2bb23d8.patch.diff
in: master

19 files changed

modifiedclient/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,16 @@
 		account: CrossAccountId,
 		at: Option<BlockHash>,
 	) -> Result<Vec<TokenId>>;
+
+	/// Get tokens contained within a collection.
 	#[method(name = "unique_collectionTokens")]
 	fn collection_tokens(
 		&self,
 		collection: CollectionId,
 		at: Option<BlockHash>,
 	) -> Result<Vec<TokenId>>;
+
+	/// Check if the token exists.
 	#[method(name = "unique_tokenExists")]
 	fn token_exists(
 		&self,
@@ -63,6 +68,7 @@
 		at: Option<BlockHash>,
 	) -> Result<bool>;
 
+	/// Get the token owner.
 	#[method(name = "unique_tokenOwner")]
 	fn token_owner(
 		&self,
@@ -80,6 +86,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Vec<CrossAccountId>>;
 
+	/// Get the topmost token owner in the hierarchy of a possibly nested token.
 	#[method(name = "unique_topmostTokenOwner")]
 	fn topmost_token_owner(
 		&self,
@@ -87,6 +94,8 @@
 		token: TokenId,
 		at: Option<BlockHash>,
 	) -> Result<Option<CrossAccountId>>;
+
+	/// Get tokens nested directly into the token.
 	#[method(name = "unique_tokenChildren")]
 	fn token_children(
 		&self,
@@ -95,6 +104,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Vec<TokenChild>>;
 
+	/// Get collection properties, optionally limited to the provided keys.
 	#[method(name = "unique_collectionProperties")]
 	fn collection_properties(
 		&self,
@@ -103,6 +113,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Vec<Property>>;
 
+	/// Get token properties, optionally limited to the provided keys.
 	#[method(name = "unique_tokenProperties")]
 	fn token_properties(
 		&self,
@@ -112,6 +123,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Vec<Property>>;
 
+	/// Get property permissions, optionally limited to the provided keys.
 	#[method(name = "unique_propertyPermissions")]
 	fn property_permissions(
 		&self,
@@ -120,6 +132,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Vec<PropertyKeyPermission>>;
 
+	/// Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT.
 	#[method(name = "unique_tokenData")]
 	fn token_data(
 		&self,
@@ -129,8 +142,11 @@
 		at: Option<BlockHash>,
 	) -> Result<TokenData<CrossAccountId>>;
 
+	/// Get the amount of distinctive tokens present in a collection.
 	#[method(name = "unique_totalSupply")]
 	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;
+
+	/// Get the amount of any user tokens owned by an account.
 	#[method(name = "unique_accountBalance")]
 	fn account_balance(
 		&self,
@@ -138,6 +154,8 @@
 		account: CrossAccountId,
 		at: Option<BlockHash>,
 	) -> Result<u32>;
+
+	/// Get the amount of a specific token owned by an account.
 	#[method(name = "unique_balance")]
 	fn balance(
 		&self,
@@ -146,6 +164,8 @@
 		token: TokenId,
 		at: Option<BlockHash>,
 	) -> Result<String>;
+
+	/// Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor.
 	#[method(name = "unique_allowance")]
 	fn allowance(
 		&self,
@@ -156,18 +176,23 @@
 		at: Option<BlockHash>,
 	) -> Result<String>;
 
+	/// Get the list of admin accounts of a collection.
 	#[method(name = "unique_adminlist")]
 	fn adminlist(
 		&self,
 		collection: CollectionId,
 		at: Option<BlockHash>,
 	) -> Result<Vec<CrossAccountId>>;
+
+	/// Get the list of accounts allowed to operate within a collection.
 	#[method(name = "unique_allowlist")]
 	fn allowlist(
 		&self,
 		collection: CollectionId,
 		at: Option<BlockHash>,
 	) -> Result<Vec<CrossAccountId>>;
+
+	/// Check if a user is allowed to operate within a collection.
 	#[method(name = "unique_allowed")]
 	fn allowed(
 		&self,
@@ -175,17 +200,24 @@
 		user: CrossAccountId,
 		at: Option<BlockHash>,
 	) -> Result<bool>;
+
+	/// Get the 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 info by the specified ID.
 	#[method(name = "unique_collectionById")]
 	fn collection_by_id(
 		&self,
 		collection: CollectionId,
 		at: Option<BlockHash>,
 	) -> Result<Option<RpcCollection<AccountId>>>;
+
+	/// Get chain stats about collections.
 	#[method(name = "unique_collectionStats")]
 	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;
 
+	/// Get the number of blocks until sponsoring a transaction is available.
 	#[method(name = "unique_nextSponsored")]
 	fn next_sponsored(
 		&self,
@@ -195,6 +227,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Option<u64>>;
 
+	/// Get effective collection limits. If not explicitly set, get the chain defaults.
 	#[method(name = "unique_effectiveCollectionLimits")]
 	fn effective_collection_limits(
 		&self,
@@ -202,6 +235,7 @@
 		at: Option<BlockHash>,
 	) -> Result<Option<CollectionLimits>>;
 
+	/// Get the total amount of pieces of an RFT.
 	#[method(name = "unique_totalPieces")]
 	fn total_pieces(
 		&self,
@@ -228,20 +262,20 @@
 		Theme,
 	>
 	{
+		/// Get the latest created collection ID.
 		#[method(name = "rmrk_lastCollectionIdx")]
-		/// Get the latest created collection id
 		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;
 
+		/// Get collection info by ID.
 		#[method(name = "rmrk_collectionById")]
-		/// Get collection by id
 		fn collection_by_id(
 			&self,
 			id: RmrkCollectionId,
 			at: Option<BlockHash>,
 		) -> Result<Option<CollectionInfo>>;
 
+		/// Get NFT info by collection and NFT IDs.
 		#[method(name = "rmrk_nftById")]
-		/// Get NFT by collection id and NFT id
 		fn nft_by_id(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -249,8 +283,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Option<NftInfo>>;
 
+		/// Get tokens owned by an account in a collection.
 		#[method(name = "rmrk_accountTokens")]
-		/// Get tokens owned by an account in a collection
 		fn account_tokens(
 			&self,
 			account_id: AccountId,
@@ -258,8 +292,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<RmrkNftId>>;
 
+		/// Get tokens nested in an NFT - its direct children (not the children's children).
 		#[method(name = "rmrk_nftChildren")]
-		/// Get NFT children
 		fn nft_children(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -267,8 +301,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<RmrkNftChild>>;
 
+		/// Get collection properties, created by the user - not the proxy-specific properties.
 		#[method(name = "rmrk_collectionProperties")]
-		/// Get collection properties
 		fn collection_properties(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -276,8 +310,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<PropertyInfo>>;
 
+		/// Get NFT properties, created by the user - not the proxy-specific properties.
 		#[method(name = "rmrk_nftProperties")]
-		/// Get NFT properties
 		fn nft_properties(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -286,8 +320,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<PropertyInfo>>;
 
+		/// Get data of resources of an NFT.
 		#[method(name = "rmrk_nftResources")]
-		/// Get NFT resources
 		fn nft_resources(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -295,8 +329,8 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<ResourceInfo>>;
 
+		/// Get the priority of a resource in an NFT.
 		#[method(name = "rmrk_nftResourcePriority")]
-		/// Get NFT resource priority
 		fn nft_resource_priority(
 			&self,
 			collection_id: RmrkCollectionId,
@@ -305,14 +339,15 @@
 			at: Option<BlockHash>,
 		) -> Result<Option<u32>>;
 
+		/// Get base info by its ID.
 		#[method(name = "rmrk_base")]
-		/// Get base info
 		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;
 
+		/// Get all parts of a base.
 		#[method(name = "rmrk_baseParts")]
-		/// Get all Base's parts
 		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;
 
+		/// Get the theme names belonging to a base.
 		#[method(name = "rmrk_themeNames")]
 		fn theme_names(
 			&self,
@@ -320,6 +355,7 @@
 			at: Option<BlockHash>,
 		) -> Result<Vec<RmrkThemeName>>;
 
+		/// Get theme info, including properties, optionally limited to the provided keys.
 		#[method(name = "rmrk_themes")]
 		fn theme(
 			&self,
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -441,7 +441,7 @@
 			u128,
 		),
 
-		/// The colletion property has been set.
+		/// The colletion property has been added or edited.
 		CollectionPropertySet(
 			/// Id of collection to which property has been set.
 			CollectionId,
@@ -457,7 +457,7 @@
 			PropertyKey,
 		),
 
-		/// The token property has been set.
+		/// The token property has been added or edited.
 		TokenPropertySet(
 			/// Identifier of the collection whose token has the property set.
 			CollectionId,
@@ -477,9 +477,9 @@
 			PropertyKey,
 		),
 
-		/// The colletion property permission has been set.
+		/// The token property permission of a collection has been set.
 		PropertyPermissionSet(
-			/// Id of collection to which property permission has been set.
+			/// ID of collection to which property permission has been set.
 			CollectionId,
 			/// The property permission that was set.
 			PropertyKey,
@@ -524,26 +524,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
@@ -558,7 +558,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
@@ -571,7 +571,7 @@
 		CollectionIsInternal,
 	}
 
-	/// Storage of the count of created collections.
+	/// Storage of the count of created collections. Essentially contains the last collection ID.
 	#[pallet::storage]
 	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
 
@@ -600,7 +600,7 @@
 		OnEmpty = up_data_structs::CollectionProperties,
 	>;
 
-	/// Storage of collection properties permissions.
+	/// Storage of token property permissions of a collection.
 	#[pallet::storage]
 	#[pallet::getter(fn property_permissions)]
 	pub type CollectionPropertyPermissions<T> = StorageMap<
@@ -610,7 +610,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Storage of collection admins count.
+	/// Storage of the amount of collection admins.
 	#[pallet::storage]
 	pub type AdminAmount<T> = StorageMap<
 		Hasher = Blake2_128Concat,
@@ -619,7 +619,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// List of collection admins
+	/// List of collection admins.
 	#[pallet::storage]
 	pub type IsAdmin<T: Config> = StorageNMap<
 		Key = (
@@ -630,7 +630,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Allowlisted collection users
+	/// Allowlisted collection users.
 	#[pallet::storage]
 	pub type Allowlist<T: Config> = StorageNMap<
 		Key = (
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -119,8 +119,7 @@
 	pub enum Error<T> {
 		/// Not Fungible item data used to mint in Fungible collection.
 		NotFungibleDataUsedToMintFungibleCollectionToken,
-		/// Not default id passed as TokenId argument.
-		/// The default value of TokenId for Fungible collection is 0.
+		/// Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.
 		FungibleItemsHaveNoId,
 		/// Tried to set data for fungible item.
 		FungibleItemsDontHaveData,
@@ -157,7 +156,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Storage for delegated assets.
+	/// Storage for assets delegated to a limited extent to other users.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (
@@ -172,7 +171,6 @@
 
 /// Wrapper around untyped collection handle, asserting inner collection is of fungible type.
 /// Required for interaction with Fungible collections, type safety and implementation [`solidity_interface`][`evm_coder::solidity_interface`].
-
 pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
 
 /// Implementation of methods required for dispatching during runtime.
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -21,7 +21,7 @@
 //! - [`Config`]
 //! - [`NonfungibleHandle`]
 //! - [`Pallet`]
-//! - [`CommonWeights`]
+//! - [`CommonWeights`](common::CommonWeights)
 //!
 //! ## Overview
 //!
@@ -130,6 +130,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
+/// for the convenience of database access. Notably contains the owner account address.
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
 pub struct ItemData<CrossAccountId> {
@@ -176,17 +178,17 @@
 	#[pallet::generate_store(pub(super) trait Store)]
 	pub struct Pallet<T>(_);
 
-	/// Amount of tokens minted for collection.
+	/// 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 for collection.
+	/// Amount of burnt tokens in a collection.
 	#[pallet::storage]
 	pub type TokensBurnt<T: Config> =
 		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;
 
-	/// Custom data serialized to bytes for token.
+	/// Token data, used to partially describe a token.
 	#[pallet::storage]
 	pub type TokenData<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -194,7 +196,7 @@
 		QueryKind = OptionQuery,
 	>;
 
-	/// Key-Value map stored for token.
+	/// Map of key-value pairs, describing the metadata of a token.
 	#[pallet::storage]
 	#[pallet::getter(fn token_properties)]
 	pub type TokenProperties<T: Config> = StorageNMap<
@@ -204,7 +206,14 @@
 		OnEmpty = up_data_structs::TokenProperties,
 	>;
 
-	/// Custom data that is serialized to bytes and attached to a token property.
+	/// Custom data of a token that is serialized to bytes,
+	/// primarily reserved for on-chain operations,
+	/// normally obscured from the external users.
+	///
+	/// Auxiliary properties are slightly different from
+	/// usual [`TokenProperties`] due to an unlimited number
+	/// and separately stored and written-to key-value pairs.
+	///
 	/// Currently used to store RMRK data.
 	#[pallet::storage]
 	#[pallet::getter(fn token_aux_property)]
@@ -244,7 +253,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Amount of tokens owned by account.
+	/// Amount of tokens owned by an account in a collection.
 	#[pallet::storage]
 	pub type AccountBalance<T: Config> = StorageNMap<
 		Key = (
@@ -255,7 +264,7 @@
 		QueryKind = ValueQuery,
 	>;
 
-	/// Allowance set by an owner for a spender for a token.
+	/// Allowance set by a token owner for another user to perform one of certain transactions on a token.
 	#[pallet::storage]
 	pub type Allowance<T: Config> = StorageNMap<
 		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),
@@ -263,6 +272,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 {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
before · pallets/refungible/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Refungible Pallet18//!19//! The Refungible pallet provides functionality for handling refungible collections and tokens.20//!21//! - [`Config`]22//! - [`RefungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`]25//!26//! ## Overview27//!28//! The Refungible pallet provides functions for:29//!30//! - RFT collection creation and removal31//! - Minting and burning of RFT tokens32//! - Partition and repartition of RFT tokens33//! - Retrieving number of pieces of RFT token34//! - Retrieving account balances35//! - Transfering RFT token pieces36//! - Burning RFT token pieces37//! - Setting and checking allowance for RFT tokens38//!39//! ### Terminology40//!41//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all42//!   of the RFT token pieces than it owns the RFT token and can repartition it.43//!44//! - **RFT Collection:** A collection of RFT tokens. All RFT tokens are part of a collection.45//!   Each collection has its own settings and set of permissions.46//!47//! - **RFT token piece:** A fungible part of an RFT token.48//!49//! - **Balance:** RFT token pieces owned by an account50//!51//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to52//!   transfer from the balance of another account53//!54//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from55//!   an account balance.56//!57//! ### Implementations58//!59//! The Refungible pallet provides implementations for the following traits. If these traits provide60//! the functionality that you need, then you can avoid coupling with the Refungible pallet.61//!62//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight63//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing64//!   with collections65//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible66//!   collection67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for73//!   some accounts.74//! - `destroy_collection` - Destroy exising RFT collection. There should be no tokens in the collection.75//! - `burn` - Burn some amount of RFT token pieces owned by account. Burns the RFT token if no pieces left.76//! - `transfer` - Transfer some amount of RFT token pieces. Transfers should be enabled for RFT collection.77//!   Nests the RFT token if RFT token pieces are sent to another token.78//! - `create_item` - Mint RFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account to transfer balance from sender's account.80//! - `repartition` - Repartition token to selected number of pieces. Sender should own all existing pieces.81//!82//! ## Assumptions83//!84//! * Total number of pieces for one token shouldn't exceed `up_data_structs::MAX_REFUNGIBLE_PIECES`.85//! * Total number of tokens of all types shouldn't be greater than `up_data_structs::MAX_TOKEN_PREFIX_LENGTH`.86//! * Sender should be in collection's allow list to perform operations on tokens.8788#![cfg_attr(not(feature = "std"), no_std)]8990use crate::erc_token::ERC20Events;9192use codec::{Encode, Decode, MaxEncodedLen};93use core::ops::Deref;94use evm_coder::ToLog;95use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};97use pallet_evm_coder_substrate::WithRecorder;98use pallet_common::{99	CommonCollectionOperations, Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,100};101use pallet_structure::Pallet as PalletStructure;102use scale_info::TypeInfo;103use sp_core::H160;104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};106use up_data_structs::{107	AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData,108	CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId, Property,109	PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,110	TrySetProperty,111};112113pub use pallet::*;114#[cfg(feature = "runtime-benchmarks")]115pub mod benchmarking;116pub mod common;117pub mod erc;118pub mod erc_token;119pub mod weights;120pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;121122#[struct_versioning::versioned(version = 2, upper)]123#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]124pub struct ItemData {125	pub const_data: BoundedVec<u8, CustomDataLimit>,126127	#[version(..2)]128	pub variable_data: BoundedVec<u8, CustomDataLimit>,129}130131#[frame_support::pallet]132pub mod pallet {133	use super::*;134	use frame_support::{135		Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key,136		traits::StorageVersion,137	};138	use frame_system::pallet_prelude::*;139	use up_data_structs::{CollectionId, TokenId};140	use super::weights::WeightInfo;141142	#[pallet::error]143	pub enum Error<T> {144		/// Not Refungible item data used to mint in Refungible collection.145		NotRefungibleDataUsedToMintFungibleCollectionToken,146		/// Maximum refungibility exceeded147		WrongRefungiblePieces,148		/// Refungible token can't be repartitioned by user who isn't owns all pieces149		RepartitionWhileNotOwningAllPieces,150		/// Refungible token can't nest other tokens151		RefungibleDisallowsNesting,152		/// Setting item properties is not allowed153		SettingPropertiesNotAllowed,154	}155156	#[pallet::config]157	pub trait Config:158		frame_system::Config + pallet_common::Config + pallet_structure::Config159	{160		type WeightInfo: WeightInfo;161	}162163	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);164165	#[pallet::pallet]166	#[pallet::storage_version(STORAGE_VERSION)]167	#[pallet::generate_store(pub(super) trait Store)]168	pub struct Pallet<T>(_);169170	/// Amount of tokens minted for collection171	#[pallet::storage]172	pub type TokensMinted<T: Config> =173		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;174175	/// Amount of burnt tokens for collection176	#[pallet::storage]177	pub type TokensBurnt<T: Config> =178		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;179180	/// Custom data serialized to bytes for token181	#[pallet::storage]182	pub type TokenData<T: Config> = StorageNMap<183		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),184		Value = ItemData,185		QueryKind = ValueQuery,186	>;187188	#[pallet::storage]189	#[pallet::getter(fn token_properties)]190	pub type TokenProperties<T: Config> = StorageNMap<191		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),192		Value = up_data_structs::Properties,193		QueryKind = ValueQuery,194		OnEmpty = up_data_structs::TokenProperties,195	>;196197	/// Total amount of pieces for token198	#[pallet::storage]199	pub type TotalSupply<T: Config> = StorageNMap<200		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),201		Value = u128,202		QueryKind = ValueQuery,203	>;204205	/// Used to enumerate tokens owned by account206	#[pallet::storage]207	pub type Owned<T: Config> = StorageNMap<208		Key = (209			Key<Twox64Concat, CollectionId>,210			Key<Blake2_128Concat, T::CrossAccountId>,211			Key<Twox64Concat, TokenId>,212		),213		Value = bool,214		QueryKind = ValueQuery,215	>;216217	/// Amount of tokens owned by account218	#[pallet::storage]219	pub type AccountBalance<T: Config> = StorageNMap<220		Key = (221			Key<Twox64Concat, CollectionId>,222			// Owner223			Key<Blake2_128Concat, T::CrossAccountId>,224		),225		Value = u32,226		QueryKind = ValueQuery,227	>;228229	/// Amount of token pieces owned by account230	#[pallet::storage]231	pub type Balance<T: Config> = StorageNMap<232		Key = (233			Key<Twox64Concat, CollectionId>,234			Key<Twox64Concat, TokenId>,235			// Owner236			Key<Blake2_128Concat, T::CrossAccountId>,237		),238		Value = u128,239		QueryKind = ValueQuery,240	>;241242	/// Allowance set by an owner for a spender for a token243	#[pallet::storage]244	pub type Allowance<T: Config> = StorageNMap<245		Key = (246			Key<Twox64Concat, CollectionId>,247			Key<Twox64Concat, TokenId>,248			// Owner249			Key<Blake2_128, T::CrossAccountId>,250			// Spender251			Key<Blake2_128Concat, T::CrossAccountId>,252		),253		Value = u128,254		QueryKind = ValueQuery,255	>;256257	#[pallet::hooks]258	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {259		fn on_runtime_upgrade() -> Weight {260			if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {261				<TokenData<T>>::translate_values::<ItemDataVersion1, _>(|v| {262					Some(<ItemDataVersion2>::from(v))263				})264			}265266			0267		}268	}269}270271pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);272impl<T: Config> RefungibleHandle<T> {273	pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {274		Self(inner)275	}276	pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {277		self.0278	}279	pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {280		&mut self.0281	}282}283284impl<T: Config> Deref for RefungibleHandle<T> {285	type Target = pallet_common::CollectionHandle<T>;286287	fn deref(&self) -> &Self::Target {288		&self.0289	}290}291292impl<T: Config> WithRecorder<T> for RefungibleHandle<T> {293	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {294		self.0.recorder()295	}296	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {297		self.0.into_recorder()298	}299}300301impl<T: Config> Pallet<T> {302	/// Get number of RFT tokens in collection303	pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {304		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)305	}306307	/// Check that RFT token exists308	///309	/// - `token`: Token ID.310	pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {311		<TotalSupply<T>>::contains_key((collection.id, token))312	}313314	pub fn set_scoped_token_property(315		collection_id: CollectionId,316		token_id: TokenId,317		scope: PropertyScope,318		property: Property,319	) -> DispatchResult {320		TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {321			properties.try_scoped_set(scope, property.key, property.value)322		})323		.map_err(<CommonError<T>>::from)?;324325		Ok(())326	}327328	pub fn set_scoped_token_properties(329		collection_id: CollectionId,330		token_id: TokenId,331		scope: PropertyScope,332		properties: impl Iterator<Item = Property>,333	) -> DispatchResult {334		TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {335			stored_properties.try_scoped_set_from_iter(scope, properties)336		})337		.map_err(<CommonError<T>>::from)?;338339		Ok(())340	}341}342343// unchecked calls skips any permission checks344impl<T: Config> Pallet<T> {345	/// Create RFT collection346	///347	/// `init_collection` will take non-refundable deposit for collection creation.348	///349	/// - `data`: Contains settings for collection limits and permissions.350	pub fn init_collection(351		owner: T::CrossAccountId,352		data: CreateCollectionData<T::AccountId>,353	) -> Result<CollectionId, DispatchError> {354		<PalletCommon<T>>::init_collection(owner, data, false)355	}356357	/// Destroy RFT collection358	///359	/// `destroy_collection` will throw error if collection contains any tokens.360	/// Only owner can destroy collection.361	pub fn destroy_collection(362		collection: RefungibleHandle<T>,363		sender: &T::CrossAccountId,364	) -> DispatchResult {365		let id = collection.id;366367		if Self::collection_has_tokens(id) {368			return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());369		}370371		// =========372373		PalletCommon::destroy_collection(collection.0, sender)?;374375		<TokensMinted<T>>::remove(id);376		<TokensBurnt<T>>::remove(id);377		<TokenData<T>>::remove_prefix((id,), None);378		<TotalSupply<T>>::remove_prefix((id,), None);379		<Balance<T>>::remove_prefix((id,), None);380		<Allowance<T>>::remove_prefix((id,), None);381		<Owned<T>>::remove_prefix((id,), None);382		<AccountBalance<T>>::remove_prefix((id,), None);383		Ok(())384	}385386	fn collection_has_tokens(collection_id: CollectionId) -> bool {387		<TokenData<T>>::iter_prefix((collection_id,))388			.next()389			.is_some()390	}391392	pub fn burn_token_unchecked(393		collection: &RefungibleHandle<T>,394		token_id: TokenId,395	) -> DispatchResult {396		let burnt = <TokensBurnt<T>>::get(collection.id)397			.checked_add(1)398			.ok_or(ArithmeticError::Overflow)?;399400		<TokensBurnt<T>>::insert(collection.id, burnt);401		<TokenData<T>>::remove((collection.id, token_id));402		<TokenProperties<T>>::remove((collection.id, token_id));403		<TotalSupply<T>>::remove((collection.id, token_id));404		<Balance<T>>::remove_prefix((collection.id, token_id), None);405		<Allowance<T>>::remove_prefix((collection.id, token_id), None);406		// TODO: ERC721 transfer event407		Ok(())408	}409410	/// Burn RFT token pieces411	///412	/// `burn` will decrease total amount of token pieces and amount owned by sender.413	/// `burn` can be called even if there are multiple owners of the RFT token.414	/// If sender wouldn't have any pieces left after `burn` than she will stop being415	/// one of the owners of the token. If there is no account that owns any pieces of416	/// the token than token will be burned too.417	///418	/// - `amount`: Amount of token pieces to burn.419	/// - `token`: Token who's pieces should be burned420	/// - `collection`: Collection that contains the token421	pub fn burn(422		collection: &RefungibleHandle<T>,423		owner: &T::CrossAccountId,424		token: TokenId,425		amount: u128,426	) -> DispatchResult {427		let total_supply = <TotalSupply<T>>::get((collection.id, token))428			.checked_sub(amount)429			.ok_or(<CommonError<T>>::TokenValueTooLow)?;430431		// This was probally last owner of this token?432		if total_supply == 0 {433			// Ensure user actually owns this amount434			ensure!(435				<Balance<T>>::get((collection.id, token, owner)) == amount,436				<CommonError<T>>::TokenValueTooLow437			);438			let account_balance = <AccountBalance<T>>::get((collection.id, owner))439				.checked_sub(1)440				// Should not occur441				.ok_or(ArithmeticError::Underflow)?;442443			// =========444445			<Owned<T>>::remove((collection.id, owner, token));446			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);447			<AccountBalance<T>>::insert((collection.id, owner), account_balance);448			Self::burn_token_unchecked(collection, token)?;449			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(450				collection.id,451				token,452				owner.clone(),453				amount,454			));455			return Ok(());456		}457458		let balance = <Balance<T>>::get((collection.id, token, owner))459			.checked_sub(amount)460			.ok_or(<CommonError<T>>::TokenValueTooLow)?;461		let account_balance = if balance == 0 {462			<AccountBalance<T>>::get((collection.id, owner))463				.checked_sub(1)464				// Should not occur465				.ok_or(ArithmeticError::Underflow)?466		} else {467			0468		};469470		// =========471472		if balance == 0 {473			<Owned<T>>::remove((collection.id, owner, token));474			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);475			<Balance<T>>::remove((collection.id, token, owner));476			<AccountBalance<T>>::insert((collection.id, owner), account_balance);477		} else {478			<Balance<T>>::insert((collection.id, token, owner), balance);479		}480		<TotalSupply<T>>::insert((collection.id, token), total_supply);481482		<PalletEvm<T>>::deposit_log(483			ERC20Events::Transfer {484				from: *owner.as_eth(),485				to: H160::default(),486				value: amount.into(),487			}488			.to_log(T::EvmTokenAddressMapping::token_to_address(489				collection.id,490				token,491			)),492		);493		<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(494			collection.id,495			token,496			owner.clone(),497			amount,498		));499		Ok(())500	}501502	#[transactional]503	fn modify_token_properties(504		collection: &RefungibleHandle<T>,505		sender: &T::CrossAccountId,506		token_id: TokenId,507		properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,508		is_token_create: bool,509		nesting_budget: &dyn Budget,510	) -> DispatchResult {511		let is_collection_admin = || collection.is_owner_or_admin(sender);512		let is_token_owner = || -> Result<bool, DispatchError> {513			let balance = collection.balance(sender.clone(), token_id);514			let total_pieces: u128 =515				Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);516			if balance != total_pieces {517				return Ok(false);518			}519520			let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(521				sender.clone(),522				collection.id,523				token_id,524				None,525				nesting_budget,526			)?;527528			Ok(is_bundle_owner)529		};530531		for (key, value) in properties {532			let permission = <PalletCommon<T>>::property_permissions(collection.id)533				.get(&key)534				.cloned()535				.unwrap_or_else(PropertyPermission::none);536537			let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))538				.get(&key)539				.is_some();540541			match permission {542				PropertyPermission { mutable: false, .. } if is_property_exists => {543					return Err(<CommonError<T>>::NoPermission.into());544				}545546				PropertyPermission {547					collection_admin,548					token_owner,549					..550				} => {551					//TODO: investigate threats during public minting.552					let is_token_create =553						is_token_create && (collection_admin || token_owner) && value.is_some();554					if !(is_token_create555						|| (collection_admin && is_collection_admin())556						|| (token_owner && is_token_owner()?))557					{558						fail!(<CommonError<T>>::NoPermission);559					}560				}561			}562563			match value {564				Some(value) => {565					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {566						properties.try_set(key.clone(), value)567					})568					.map_err(<CommonError<T>>::from)?;569570					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(571						collection.id,572						token_id,573						key,574					));575				}576				None => {577					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {578						properties.remove(&key)579					})580					.map_err(<CommonError<T>>::from)?;581582					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(583						collection.id,584						token_id,585						key,586					));587				}588			}589		}590591		Ok(())592	}593594	pub fn set_token_properties(595		collection: &RefungibleHandle<T>,596		sender: &T::CrossAccountId,597		token_id: TokenId,598		properties: impl Iterator<Item = Property>,599		is_token_create: bool,600		nesting_budget: &dyn Budget,601	) -> DispatchResult {602		Self::modify_token_properties(603			collection,604			sender,605			token_id,606			properties.map(|p| (p.key, Some(p.value))),607			is_token_create,608			nesting_budget,609		)610	}611612	pub fn set_token_property(613		collection: &RefungibleHandle<T>,614		sender: &T::CrossAccountId,615		token_id: TokenId,616		property: Property,617		nesting_budget: &dyn Budget,618	) -> DispatchResult {619		let is_token_create = false;620621		Self::set_token_properties(622			collection,623			sender,624			token_id,625			[property].into_iter(),626			is_token_create,627			nesting_budget,628		)629	}630631	pub fn delete_token_properties(632		collection: &RefungibleHandle<T>,633		sender: &T::CrossAccountId,634		token_id: TokenId,635		property_keys: impl Iterator<Item = PropertyKey>,636		nesting_budget: &dyn Budget,637	) -> DispatchResult {638		let is_token_create = false;639640		Self::modify_token_properties(641			collection,642			sender,643			token_id,644			property_keys.into_iter().map(|key| (key, None)),645			is_token_create,646			nesting_budget,647		)648	}649650	pub fn delete_token_property(651		collection: &RefungibleHandle<T>,652		sender: &T::CrossAccountId,653		token_id: TokenId,654		property_key: PropertyKey,655		nesting_budget: &dyn Budget,656	) -> DispatchResult {657		Self::delete_token_properties(658			collection,659			sender,660			token_id,661			[property_key].into_iter(),662			nesting_budget,663		)664	}665666	/// Transfer RFT token pieces from one account to another.667	///668	/// If the sender is no longer owns any pieces after the `transfer` than she stops being an owner of the token.669	///670	/// - `from`: Owner of token pieces to transfer.671	/// - `to`: Recepient of transfered token pieces.672	/// - `amount`: Amount of token pieces to transfer.673	/// - `token`: Token whos pieces should be transfered674	/// - `collection`: Collection that contains the token675	pub fn transfer(676		collection: &RefungibleHandle<T>,677		from: &T::CrossAccountId,678		to: &T::CrossAccountId,679		token: TokenId,680		amount: u128,681		nesting_budget: &dyn Budget,682	) -> DispatchResult {683		ensure!(684			collection.limits.transfers_enabled(),685			<CommonError<T>>::TransferNotAllowed686		);687688		if collection.permissions.access() == AccessMode::AllowList {689			collection.check_allowlist(from)?;690			collection.check_allowlist(to)?;691		}692		<PalletCommon<T>>::ensure_correct_receiver(to)?;693694		let balance_from = <Balance<T>>::get((collection.id, token, from))695			.checked_sub(amount)696			.ok_or(<CommonError<T>>::TokenValueTooLow)?;697		let mut create_target = false;698		let from_to_differ = from != to;699		let balance_to = if from != to {700			let old_balance = <Balance<T>>::get((collection.id, token, to));701			if old_balance == 0 {702				create_target = true;703			}704			Some(705				old_balance706					.checked_add(amount)707					.ok_or(ArithmeticError::Overflow)?,708			)709		} else {710			None711		};712713		let account_balance_from = if balance_from == 0 {714			Some(715				<AccountBalance<T>>::get((collection.id, from))716					.checked_sub(1)717					// Should not occur718					.ok_or(ArithmeticError::Underflow)?,719			)720		} else {721			None722		};723		// Account data is created in token, AccountBalance should be increased724		// But only if from != to as we shouldn't check overflow in this case725		let account_balance_to = if create_target && from_to_differ {726			let account_balance_to = <AccountBalance<T>>::get((collection.id, to))727				.checked_add(1)728				.ok_or(ArithmeticError::Overflow)?;729			ensure!(730				account_balance_to < collection.limits.account_token_ownership_limit(),731				<CommonError<T>>::AccountTokenLimitExceeded,732			);733734			Some(account_balance_to)735		} else {736			None737		};738739		// =========740741		<PalletStructure<T>>::nest_if_sent_to_token(742			from.clone(),743			to,744			collection.id,745			token,746			nesting_budget,747		)?;748749		if let Some(balance_to) = balance_to {750			// from != to751			if balance_from == 0 {752				<Balance<T>>::remove((collection.id, token, from));753				<PalletStructure<T>>::unnest_if_nested(from, collection.id, token);754			} else {755				<Balance<T>>::insert((collection.id, token, from), balance_from);756			}757			<Balance<T>>::insert((collection.id, token, to), balance_to);758			if let Some(account_balance_from) = account_balance_from {759				<AccountBalance<T>>::insert((collection.id, from), account_balance_from);760				<Owned<T>>::remove((collection.id, from, token));761			}762			if let Some(account_balance_to) = account_balance_to {763				<AccountBalance<T>>::insert((collection.id, to), account_balance_to);764				<Owned<T>>::insert((collection.id, to, token), true);765			}766		}767768		<PalletEvm<T>>::deposit_log(769			ERC20Events::Transfer {770				from: *from.as_eth(),771				to: *to.as_eth(),772				value: amount.into(),773			}774			.to_log(T::EvmTokenAddressMapping::token_to_address(775				collection.id,776				token,777			)),778		);779		<PalletCommon<T>>::deposit_event(CommonEvent::Transfer(780			collection.id,781			token,782			from.clone(),783			to.clone(),784			amount,785		));786		Ok(())787	}788789	/// Batched operation to create multiple RFT tokens.790	///791	/// Same as `create_item` but creates multiple tokens.792	///793	/// - `data`: Same as 'data` in `create_item` but contains data for multiple tokens.794	pub fn create_multiple_items(795		collection: &RefungibleHandle<T>,796		sender: &T::CrossAccountId,797		data: Vec<CreateRefungibleExData<T::CrossAccountId>>,798		nesting_budget: &dyn Budget,799	) -> DispatchResult {800		if !collection.is_owner_or_admin(sender) {801			ensure!(802				collection.permissions.mint_mode(),803				<CommonError<T>>::PublicMintingNotAllowed804			);805			collection.check_allowlist(sender)?;806807			for item in data.iter() {808				for user in item.users.keys() {809					collection.check_allowlist(user)?;810				}811			}812		}813814		for item in data.iter() {815			for (owner, _) in item.users.iter() {816				<PalletCommon<T>>::ensure_correct_receiver(owner)?;817			}818		}819820		// Total pieces per tokens821		let totals = data822			.iter()823			.map(|data| {824				Ok(data825					.users826					.iter()827					.map(|u| u.1)828					.try_fold(0u128, |acc, v| acc.checked_add(*v))829					.ok_or(ArithmeticError::Overflow)?)830			})831			.collect::<Result<Vec<_>, DispatchError>>()?;832		for total in &totals {833			ensure!(834				*total <= MAX_REFUNGIBLE_PIECES,835				<Error<T>>::WrongRefungiblePieces836			);837		}838839		let first_token_id = <TokensMinted<T>>::get(collection.id);840		let tokens_minted = first_token_id841			.checked_add(data.len() as u32)842			.ok_or(ArithmeticError::Overflow)?;843		ensure!(844			tokens_minted < collection.limits.token_limit(),845			<CommonError<T>>::CollectionTokenLimitExceeded846		);847848		let mut balances = BTreeMap::new();849		for data in &data {850			for owner in data.users.keys() {851				let balance = balances852					.entry(owner)853					.or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));854				*balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;855856				ensure!(857					*balance <= collection.limits.account_token_ownership_limit(),858					<CommonError<T>>::AccountTokenLimitExceeded,859				);860			}861		}862863		for (i, token) in data.iter().enumerate() {864			let token_id = TokenId(first_token_id + i as u32 + 1);865			for (to, _) in token.users.iter() {866				<PalletStructure<T>>::check_nesting(867					sender.clone(),868					to,869					collection.id,870					token_id,871					nesting_budget,872				)?;873			}874		}875876		// =========877878		with_transaction(|| {879			for (i, data) in data.iter().enumerate() {880				let token_id = first_token_id + i as u32 + 1;881				<TotalSupply<T>>::insert((collection.id, token_id), totals[i]);882883				<TokenData<T>>::insert(884					(collection.id, token_id),885					ItemData {886						const_data: data.const_data.clone(),887					},888				);889890				for (user, amount) in data.users.iter() {891					if *amount == 0 {892						continue;893					}894					<Balance<T>>::insert((collection.id, token_id, &user), amount);895					<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);896					<PalletStructure<T>>::nest_if_sent_to_token_unchecked(897						user,898						collection.id,899						TokenId(token_id),900					);901				}902903				if let Err(e) = Self::set_token_properties(904					collection,905					sender,906					TokenId(token_id),907					data.properties.clone().into_iter(),908					true,909					nesting_budget,910				) {911					return TransactionOutcome::Rollback(Err(e));912				}913			}914			TransactionOutcome::Commit(Ok(()))915		})?;916917		<TokensMinted<T>>::insert(collection.id, tokens_minted);918919		for (account, balance) in balances {920			<AccountBalance<T>>::insert((collection.id, account), balance);921		}922923		for (i, token) in data.into_iter().enumerate() {924			let token_id = first_token_id + i as u32 + 1;925926			for (user, amount) in token.users.into_iter() {927				if amount == 0 {928					continue;929				}930931				<PalletEvm<T>>::deposit_log(932					ERC20Events::Transfer {933						from: H160::default(),934						to: *user.as_eth(),935						value: amount.into(),936					}937					.to_log(T::EvmTokenAddressMapping::token_to_address(938						collection.id,939						TokenId(token_id),940					)),941				);942				<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(943					collection.id,944					TokenId(token_id),945					user,946					amount,947				));948			}949		}950		Ok(())951	}952953	pub fn set_allowance_unchecked(954		collection: &RefungibleHandle<T>,955		sender: &T::CrossAccountId,956		spender: &T::CrossAccountId,957		token: TokenId,958		amount: u128,959	) {960		if amount == 0 {961			<Allowance<T>>::remove((collection.id, token, sender, spender));962		} else {963			<Allowance<T>>::insert((collection.id, token, sender, spender), amount);964		}965966		<PalletEvm<T>>::deposit_log(967			ERC20Events::Approval {968				owner: *sender.as_eth(),969				spender: *spender.as_eth(),970				value: amount.into(),971			}972			.to_log(T::EvmTokenAddressMapping::token_to_address(973				collection.id,974				token,975			)),976		);977		<PalletCommon<T>>::deposit_event(CommonEvent::Approved(978			collection.id,979			token,980			sender.clone(),981			spender.clone(),982			amount,983		))984	}985986	/// Set allowance for the spender to `transfer` or `burn` sender's token pieces.987	///988	/// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.989	pub fn set_allowance(990		collection: &RefungibleHandle<T>,991		sender: &T::CrossAccountId,992		spender: &T::CrossAccountId,993		token: TokenId,994		amount: u128,995	) -> DispatchResult {996		if collection.permissions.access() == AccessMode::AllowList {997			collection.check_allowlist(sender)?;998			collection.check_allowlist(spender)?;999		}10001001		<PalletCommon<T>>::ensure_correct_receiver(spender)?;10021003		if <Balance<T>>::get((collection.id, token, sender)) < amount {1004			ensure!(1005				collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),1006				<CommonError<T>>::CantApproveMoreThanOwned1007			);1008		}10091010		// =========10111012		Self::set_allowance_unchecked(collection, sender, spender, token, amount);1013		Ok(())1014	}10151016	/// Returns allowance, which should be set after transaction1017	fn check_allowed(1018		collection: &RefungibleHandle<T>,1019		spender: &T::CrossAccountId,1020		from: &T::CrossAccountId,1021		token: TokenId,1022		amount: u128,1023		nesting_budget: &dyn Budget,1024	) -> Result<Option<u128>, DispatchError> {1025		if spender.conv_eq(from) {1026			return Ok(None);1027		}1028		if collection.permissions.access() == AccessMode::AllowList {1029			// `from`, `to` checked in [`transfer`]1030			collection.check_allowlist(spender)?;1031		}1032		if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1033			// TODO: should collection owner be allowed to perform this transfer?1034			ensure!(1035				<PalletStructure<T>>::check_indirectly_owned(1036					spender.clone(),1037					source.0,1038					source.1,1039					None,1040					nesting_budget1041				)?,1042				<CommonError<T>>::ApprovedValueTooLow,1043			);1044			return Ok(None);1045		}1046		let allowance =1047			<Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);1048		if allowance.is_none() {1049			ensure!(1050				collection.ignores_allowance(spender),1051				<CommonError<T>>::ApprovedValueTooLow1052			);1053		}1054		Ok(allowance)1055	}10561057	/// Transfer RFT token pieces from one account to another.1058	///1059	/// Same as the [`transfer`] but spender doesn't needs to be an owner of the token pieces.1060	/// The owner should set allowance for the spender to transfer pieces.1061	///1062	/// [`transfer`]: struct.Pallet.html#method.transfer1063	pub fn transfer_from(1064		collection: &RefungibleHandle<T>,1065		spender: &T::CrossAccountId,1066		from: &T::CrossAccountId,1067		to: &T::CrossAccountId,1068		token: TokenId,1069		amount: u128,1070		nesting_budget: &dyn Budget,1071	) -> DispatchResult {1072		let allowance =1073			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;10741075		// =========10761077		Self::transfer(collection, from, to, token, amount, nesting_budget)?;1078		if let Some(allowance) = allowance {1079			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1080		}1081		Ok(())1082	}10831084	/// Burn RFT token pieces from the account.1085	///1086	/// Same as the [`burn`] but spender doesn't need to be an owner of the token pieces. The owner should1087	/// set allowance for the spender to burn pieces1088	///1089	/// [`burn`]: struct.Pallet.html#method.burn1090	pub fn burn_from(1091		collection: &RefungibleHandle<T>,1092		spender: &T::CrossAccountId,1093		from: &T::CrossAccountId,1094		token: TokenId,1095		amount: u128,1096		nesting_budget: &dyn Budget,1097	) -> DispatchResult {1098		let allowance =1099			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;11001101		// =========11021103		Self::burn(collection, from, token, amount)?;1104		if let Some(allowance) = allowance {1105			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1106		}1107		Ok(())1108	}11091110	/// Create RFT token.1111	///1112	/// The sender should be the owner/admin of the collection or collection should be configured1113	/// to allow public minting.1114	///1115	/// - `data`: Contains list of users who will become the owners of the token pieces and amount1116	///   of token pieces they will receive.1117	pub fn create_item(1118		collection: &RefungibleHandle<T>,1119		sender: &T::CrossAccountId,1120		data: CreateRefungibleExData<T::CrossAccountId>,1121		nesting_budget: &dyn Budget,1122	) -> DispatchResult {1123		Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1124	}11251126	/// Repartition RFT token.1127	///1128	/// `repartition` will set token balance of the sender and total amount of token pieces.1129	/// Sender should own all of the token pieces. `repartition' could be done even if some1130	/// token pieces were burned before.1131	///1132	/// - `amount`: Total amount of token pieces that the token will have after `repartition`.1133	pub fn repartition(1134		collection: &RefungibleHandle<T>,1135		owner: &T::CrossAccountId,1136		token: TokenId,1137		amount: u128,1138	) -> DispatchResult {1139		ensure!(1140			amount <= MAX_REFUNGIBLE_PIECES,1141			<Error<T>>::WrongRefungiblePieces1142		);1143		ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1144		// Ensure user owns all pieces1145		let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);1146		let balance = <Balance<T>>::get((collection.id, token, owner));1147		ensure!(1148			total_pieces == balance,1149			<Error<T>>::RepartitionWhileNotOwningAllPieces1150		);11511152		<Balance<T>>::insert((collection.id, token, owner), amount);1153		<TotalSupply<T>>::insert((collection.id, token), amount);11541155		if amount > total_pieces {1156			let mint_amount = amount - total_pieces;1157			<PalletEvm<T>>::deposit_log(1158				ERC20Events::Transfer {1159					from: H160::default(),1160					to: *owner.as_eth(),1161					value: mint_amount.into(),1162				}1163				.to_log(T::EvmTokenAddressMapping::token_to_address(1164					collection.id,1165					token,1166				)),1167			);1168			<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(1169				collection.id,1170				token,1171				owner.clone(),1172				mint_amount,1173			));1174		} else if total_pieces > amount {1175			let burn_amount = total_pieces - amount;1176			<PalletEvm<T>>::deposit_log(1177				ERC20Events::Transfer {1178					from: *owner.as_eth(),1179					to: H160::default(),1180					value: burn_amount.into(),1181				}1182				.to_log(T::EvmTokenAddressMapping::token_to_address(1183					collection.id,1184					token,1185				)),1186			);1187			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(1188				collection.id,1189				token,1190				owner.clone(),1191				burn_amount,1192			));1193		}11941195		Ok(())1196	}11971198	fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {1199		let mut owner = None;1200		let mut count = 0;1201		for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1202			count += 1;1203			if count > 1 {1204				return None;1205			}1206			owner = Some(key);1207		}1208		owner1209	}12101211	fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1212		<TotalSupply<T>>::try_get((collection_id, token_id)).ok()1213	}12141215	pub fn set_collection_properties(1216		collection: &RefungibleHandle<T>,1217		sender: &T::CrossAccountId,1218		properties: Vec<Property>,1219	) -> DispatchResult {1220		<PalletCommon<T>>::set_collection_properties(collection, sender, properties)1221	}12221223	pub fn delete_collection_properties(1224		collection: &RefungibleHandle<T>,1225		sender: &T::CrossAccountId,1226		property_keys: Vec<PropertyKey>,1227	) -> DispatchResult {1228		<PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)1229	}12301231	pub fn set_token_property_permissions(1232		collection: &RefungibleHandle<T>,1233		sender: &T::CrossAccountId,1234		property_permissions: Vec<PropertyKeyPermission>,1235	) -> DispatchResult {1236		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1237	}12381239	/// Returns 10 token in no particular order.1240	///1241	/// There is no direct way to get token holders in ascending order,1242	/// since `iter_prefix` returns values in no particular order.1243	/// Therefore, getting the 10 largest holders with a large value of holders1244	/// can lead to impact memory allocation + sorting with  `n * log (n)`.1245	pub fn token_owners(1246		collection_id: CollectionId,1247		token: TokenId,1248	) -> Option<Vec<T::CrossAccountId>> {1249		let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection_id, token))1250			.map(|(owner, _amount)| owner)1251			.take(10)1252			.collect();12531254		if res.is_empty() {1255			None1256		} else {1257			Some(res)1258		}1259	}1260}
after · pallets/refungible/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Refungible Pallet18//!19//! The Refungible pallet provides functionality for handling refungible collections and tokens.20//!21//! - [`Config`]22//! - [`RefungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`](common::CommonWeights)25//!26//! ## Overview27//!28//! The Refungible pallet provides functions for:29//!30//! - RFT collection creation and removal31//! - Minting and burning of RFT tokens32//! - Partition and repartition of RFT tokens33//! - Retrieving number of pieces of RFT token34//! - Retrieving account balances35//! - Transfering RFT token pieces36//! - Burning RFT token pieces37//! - Setting and checking allowance for RFT tokens38//!39//! ### Terminology40//!41//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all42//!   of the RFT token pieces than it owns the RFT token and can repartition it.43//!44//! - **RFT Collection:** A collection of RFT tokens. All RFT tokens are part of a collection.45//!   Each collection has its own settings and set of permissions.46//!47//! - **RFT token piece:** A fungible part of an RFT token.48//!49//! - **Balance:** RFT token pieces owned by an account50//!51//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to52//!   transfer from the balance of another account53//!54//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from55//!   an account balance.56//!57//! ### Implementations58//!59//! The Refungible pallet provides implementations for the following traits. If these traits provide60//! the functionality that you need, then you can avoid coupling with the Refungible pallet.61//!62//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight63//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing64//!   with collections65//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible66//!   collection67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for73//!   some accounts.74//! - `destroy_collection` - Destroy exising RFT collection. There should be no tokens in the collection.75//! - `burn` - Burn some amount of RFT token pieces owned by account. Burns the RFT token if no pieces left.76//! - `transfer` - Transfer some amount of RFT token pieces. Transfers should be enabled for RFT collection.77//!   Nests the RFT token if RFT token pieces are sent to another token.78//! - `create_item` - Mint RFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account to transfer balance from sender's account.80//! - `repartition` - Repartition token to selected number of pieces. Sender should own all existing pieces.81//!82//! ## Assumptions83//!84//! * Total number of pieces for one token shouldn't exceed `up_data_structs::MAX_REFUNGIBLE_PIECES`.85//! * Total number of tokens of all types shouldn't be greater than `up_data_structs::MAX_TOKEN_PREFIX_LENGTH`.86//! * Sender should be in collection's allow list to perform operations on tokens.8788#![cfg_attr(not(feature = "std"), no_std)]8990use crate::erc_token::ERC20Events;9192use codec::{Encode, Decode, MaxEncodedLen};93use core::ops::Deref;94use evm_coder::ToLog;95use frame_support::{BoundedVec, ensure, fail, storage::with_transaction, transactional};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};97use pallet_evm_coder_substrate::WithRecorder;98use pallet_common::{99	CommonCollectionOperations, Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,100};101use pallet_structure::Pallet as PalletStructure;102use scale_info::TypeInfo;103use sp_core::H160;104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};106use up_data_structs::{107	AccessMode, budget::Budget, CollectionId, CreateCollectionData, CreateRefungibleExData,108	CustomDataLimit, mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, TokenId, Property,109	PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,110	TrySetProperty,111};112113pub use pallet::*;114#[cfg(feature = "runtime-benchmarks")]115pub mod benchmarking;116pub mod common;117pub mod erc;118pub mod erc_token;119pub mod weights;120pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;121122/// Token data, stored independently from other data used to describe it123/// for the convenience of database access. Notably contains the token metadata.124#[struct_versioning::versioned(version = 2, upper)]125#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]126pub struct ItemData {127	pub const_data: BoundedVec<u8, CustomDataLimit>,128129	#[version(..2)]130	pub variable_data: BoundedVec<u8, CustomDataLimit>,131}132133#[frame_support::pallet]134pub mod pallet {135	use super::*;136	use frame_support::{137		Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key,138		traits::StorageVersion,139	};140	use frame_system::pallet_prelude::*;141	use up_data_structs::{CollectionId, TokenId};142	use super::weights::WeightInfo;143144	#[pallet::error]145	pub enum Error<T> {146		/// Not Refungible item data used to mint in Refungible collection.147		NotRefungibleDataUsedToMintFungibleCollectionToken,148		/// Maximum refungibility exceeded.149		WrongRefungiblePieces,150		/// Refungible token can't be repartitioned by user who isn't owns all pieces.151		RepartitionWhileNotOwningAllPieces,152		/// Refungible token can't nest other tokens.153		RefungibleDisallowsNesting,154		/// Setting item properties is not allowed.155		SettingPropertiesNotAllowed,156	}157158	#[pallet::config]159	pub trait Config:160		frame_system::Config + pallet_common::Config + pallet_structure::Config161	{162		type WeightInfo: WeightInfo;163	}164165	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);166167	#[pallet::pallet]168	#[pallet::storage_version(STORAGE_VERSION)]169	#[pallet::generate_store(pub(super) trait Store)]170	pub struct Pallet<T>(_);171172	/// Total amount of minted tokens in a collection.173	#[pallet::storage]174	pub type TokensMinted<T: Config> =175		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;176177	/// Amount of tokens burnt in a collection.178	#[pallet::storage]179	pub type TokensBurnt<T: Config> =180		StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;181182	/// Token data, used to partially describe a token.183	#[pallet::storage]184	pub type TokenData<T: Config> = StorageNMap<185		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),186		Value = ItemData,187		QueryKind = ValueQuery,188	>;189190	/// Amount of pieces a refungible token is split into.191	#[pallet::storage]192	#[pallet::getter(fn token_properties)]193	pub type TokenProperties<T: Config> = StorageNMap<194		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),195		Value = up_data_structs::Properties,196		QueryKind = ValueQuery,197		OnEmpty = up_data_structs::TokenProperties,198	>;199200	/// Total amount of pieces for token201	#[pallet::storage]202	pub type TotalSupply<T: Config> = StorageNMap<203		Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),204		Value = u128,205		QueryKind = ValueQuery,206	>;207208	/// Used to enumerate tokens owned by account.209	#[pallet::storage]210	pub type Owned<T: Config> = StorageNMap<211		Key = (212			Key<Twox64Concat, CollectionId>,213			Key<Blake2_128Concat, T::CrossAccountId>,214			Key<Twox64Concat, TokenId>,215		),216		Value = bool,217		QueryKind = ValueQuery,218	>;219220	/// Amount of tokens (not pieces) partially owned by an account within a collection.221	#[pallet::storage]222	pub type AccountBalance<T: Config> = StorageNMap<223		Key = (224			Key<Twox64Concat, CollectionId>,225			// Owner226			Key<Blake2_128Concat, T::CrossAccountId>,227		),228		Value = u32,229		QueryKind = ValueQuery,230	>;231232	/// Amount of token pieces owned by account.233	#[pallet::storage]234	pub type Balance<T: Config> = StorageNMap<235		Key = (236			Key<Twox64Concat, CollectionId>,237			Key<Twox64Concat, TokenId>,238			// Owner239			Key<Blake2_128Concat, T::CrossAccountId>,240		),241		Value = u128,242		QueryKind = ValueQuery,243	>;244245	/// Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.246	#[pallet::storage]247	pub type Allowance<T: Config> = StorageNMap<248		Key = (249			Key<Twox64Concat, CollectionId>,250			Key<Twox64Concat, TokenId>,251			// Owner252			Key<Blake2_128, T::CrossAccountId>,253			// Spender254			Key<Blake2_128Concat, T::CrossAccountId>,255		),256		Value = u128,257		QueryKind = ValueQuery,258	>;259260	#[pallet::hooks]261	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {262		fn on_runtime_upgrade() -> Weight {263			if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {264				<TokenData<T>>::translate_values::<ItemDataVersion1, _>(|v| {265					Some(<ItemDataVersion2>::from(v))266				})267			}268269			0270		}271	}272}273274pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);275impl<T: Config> RefungibleHandle<T> {276	pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {277		Self(inner)278	}279	pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {280		self.0281	}282	pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {283		&mut self.0284	}285}286287impl<T: Config> Deref for RefungibleHandle<T> {288	type Target = pallet_common::CollectionHandle<T>;289290	fn deref(&self) -> &Self::Target {291		&self.0292	}293}294295impl<T: Config> WithRecorder<T> for RefungibleHandle<T> {296	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {297		self.0.recorder()298	}299	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {300		self.0.into_recorder()301	}302}303304impl<T: Config> Pallet<T> {305	/// Get number of RFT tokens in collection306	pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {307		<TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)308	}309310	/// Check that RFT token exists311	///312	/// - `token`: Token ID.313	pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {314		<TotalSupply<T>>::contains_key((collection.id, token))315	}316317	pub fn set_scoped_token_property(318		collection_id: CollectionId,319		token_id: TokenId,320		scope: PropertyScope,321		property: Property,322	) -> DispatchResult {323		TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {324			properties.try_scoped_set(scope, property.key, property.value)325		})326		.map_err(<CommonError<T>>::from)?;327328		Ok(())329	}330331	pub fn set_scoped_token_properties(332		collection_id: CollectionId,333		token_id: TokenId,334		scope: PropertyScope,335		properties: impl Iterator<Item = Property>,336	) -> DispatchResult {337		TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {338			stored_properties.try_scoped_set_from_iter(scope, properties)339		})340		.map_err(<CommonError<T>>::from)?;341342		Ok(())343	}344}345346// unchecked calls skips any permission checks347impl<T: Config> Pallet<T> {348	/// Create RFT collection349	///350	/// `init_collection` will take non-refundable deposit for collection creation.351	///352	/// - `data`: Contains settings for collection limits and permissions.353	pub fn init_collection(354		owner: T::CrossAccountId,355		data: CreateCollectionData<T::AccountId>,356	) -> Result<CollectionId, DispatchError> {357		<PalletCommon<T>>::init_collection(owner, data, false)358	}359360	/// Destroy RFT collection361	///362	/// `destroy_collection` will throw error if collection contains any tokens.363	/// Only owner can destroy collection.364	pub fn destroy_collection(365		collection: RefungibleHandle<T>,366		sender: &T::CrossAccountId,367	) -> DispatchResult {368		let id = collection.id;369370		if Self::collection_has_tokens(id) {371			return Err(<CommonError<T>>::CantDestroyNotEmptyCollection.into());372		}373374		// =========375376		PalletCommon::destroy_collection(collection.0, sender)?;377378		<TokensMinted<T>>::remove(id);379		<TokensBurnt<T>>::remove(id);380		<TokenData<T>>::remove_prefix((id,), None);381		<TotalSupply<T>>::remove_prefix((id,), None);382		<Balance<T>>::remove_prefix((id,), None);383		<Allowance<T>>::remove_prefix((id,), None);384		<Owned<T>>::remove_prefix((id,), None);385		<AccountBalance<T>>::remove_prefix((id,), None);386		Ok(())387	}388389	fn collection_has_tokens(collection_id: CollectionId) -> bool {390		<TokenData<T>>::iter_prefix((collection_id,))391			.next()392			.is_some()393	}394395	pub fn burn_token_unchecked(396		collection: &RefungibleHandle<T>,397		token_id: TokenId,398	) -> DispatchResult {399		let burnt = <TokensBurnt<T>>::get(collection.id)400			.checked_add(1)401			.ok_or(ArithmeticError::Overflow)?;402403		<TokensBurnt<T>>::insert(collection.id, burnt);404		<TokenData<T>>::remove((collection.id, token_id));405		<TokenProperties<T>>::remove((collection.id, token_id));406		<TotalSupply<T>>::remove((collection.id, token_id));407		<Balance<T>>::remove_prefix((collection.id, token_id), None);408		<Allowance<T>>::remove_prefix((collection.id, token_id), None);409		// TODO: ERC721 transfer event410		Ok(())411	}412413	/// Burn RFT token pieces414	///415	/// `burn` will decrease total amount of token pieces and amount owned by sender.416	/// `burn` can be called even if there are multiple owners of the RFT token.417	/// If sender wouldn't have any pieces left after `burn` than she will stop being418	/// one of the owners of the token. If there is no account that owns any pieces of419	/// the token than token will be burned too.420	///421	/// - `amount`: Amount of token pieces to burn.422	/// - `token`: Token who's pieces should be burned423	/// - `collection`: Collection that contains the token424	pub fn burn(425		collection: &RefungibleHandle<T>,426		owner: &T::CrossAccountId,427		token: TokenId,428		amount: u128,429	) -> DispatchResult {430		let total_supply = <TotalSupply<T>>::get((collection.id, token))431			.checked_sub(amount)432			.ok_or(<CommonError<T>>::TokenValueTooLow)?;433434		// This was probally last owner of this token?435		if total_supply == 0 {436			// Ensure user actually owns this amount437			ensure!(438				<Balance<T>>::get((collection.id, token, owner)) == amount,439				<CommonError<T>>::TokenValueTooLow440			);441			let account_balance = <AccountBalance<T>>::get((collection.id, owner))442				.checked_sub(1)443				// Should not occur444				.ok_or(ArithmeticError::Underflow)?;445446			// =========447448			<Owned<T>>::remove((collection.id, owner, token));449			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);450			<AccountBalance<T>>::insert((collection.id, owner), account_balance);451			Self::burn_token_unchecked(collection, token)?;452			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(453				collection.id,454				token,455				owner.clone(),456				amount,457			));458			return Ok(());459		}460461		let balance = <Balance<T>>::get((collection.id, token, owner))462			.checked_sub(amount)463			.ok_or(<CommonError<T>>::TokenValueTooLow)?;464		let account_balance = if balance == 0 {465			<AccountBalance<T>>::get((collection.id, owner))466				.checked_sub(1)467				// Should not occur468				.ok_or(ArithmeticError::Underflow)?469		} else {470			0471		};472473		// =========474475		if balance == 0 {476			<Owned<T>>::remove((collection.id, owner, token));477			<PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);478			<Balance<T>>::remove((collection.id, token, owner));479			<AccountBalance<T>>::insert((collection.id, owner), account_balance);480		} else {481			<Balance<T>>::insert((collection.id, token, owner), balance);482		}483		<TotalSupply<T>>::insert((collection.id, token), total_supply);484485		<PalletEvm<T>>::deposit_log(486			ERC20Events::Transfer {487				from: *owner.as_eth(),488				to: H160::default(),489				value: amount.into(),490			}491			.to_log(T::EvmTokenAddressMapping::token_to_address(492				collection.id,493				token,494			)),495		);496		<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(497			collection.id,498			token,499			owner.clone(),500			amount,501		));502		Ok(())503	}504505	#[transactional]506	fn modify_token_properties(507		collection: &RefungibleHandle<T>,508		sender: &T::CrossAccountId,509		token_id: TokenId,510		properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,511		is_token_create: bool,512		nesting_budget: &dyn Budget,513	) -> DispatchResult {514		let is_collection_admin = || collection.is_owner_or_admin(sender);515		let is_token_owner = || -> Result<bool, DispatchError> {516			let balance = collection.balance(sender.clone(), token_id);517			let total_pieces: u128 =518				Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);519			if balance != total_pieces {520				return Ok(false);521			}522523			let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(524				sender.clone(),525				collection.id,526				token_id,527				None,528				nesting_budget,529			)?;530531			Ok(is_bundle_owner)532		};533534		for (key, value) in properties {535			let permission = <PalletCommon<T>>::property_permissions(collection.id)536				.get(&key)537				.cloned()538				.unwrap_or_else(PropertyPermission::none);539540			let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))541				.get(&key)542				.is_some();543544			match permission {545				PropertyPermission { mutable: false, .. } if is_property_exists => {546					return Err(<CommonError<T>>::NoPermission.into());547				}548549				PropertyPermission {550					collection_admin,551					token_owner,552					..553				} => {554					//TODO: investigate threats during public minting.555					let is_token_create =556						is_token_create && (collection_admin || token_owner) && value.is_some();557					if !(is_token_create558						|| (collection_admin && is_collection_admin())559						|| (token_owner && is_token_owner()?))560					{561						fail!(<CommonError<T>>::NoPermission);562					}563				}564			}565566			match value {567				Some(value) => {568					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {569						properties.try_set(key.clone(), value)570					})571					.map_err(<CommonError<T>>::from)?;572573					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(574						collection.id,575						token_id,576						key,577					));578				}579				None => {580					<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {581						properties.remove(&key)582					})583					.map_err(<CommonError<T>>::from)?;584585					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(586						collection.id,587						token_id,588						key,589					));590				}591			}592		}593594		Ok(())595	}596597	pub fn set_token_properties(598		collection: &RefungibleHandle<T>,599		sender: &T::CrossAccountId,600		token_id: TokenId,601		properties: impl Iterator<Item = Property>,602		is_token_create: bool,603		nesting_budget: &dyn Budget,604	) -> DispatchResult {605		Self::modify_token_properties(606			collection,607			sender,608			token_id,609			properties.map(|p| (p.key, Some(p.value))),610			is_token_create,611			nesting_budget,612		)613	}614615	pub fn set_token_property(616		collection: &RefungibleHandle<T>,617		sender: &T::CrossAccountId,618		token_id: TokenId,619		property: Property,620		nesting_budget: &dyn Budget,621	) -> DispatchResult {622		let is_token_create = false;623624		Self::set_token_properties(625			collection,626			sender,627			token_id,628			[property].into_iter(),629			is_token_create,630			nesting_budget,631		)632	}633634	pub fn delete_token_properties(635		collection: &RefungibleHandle<T>,636		sender: &T::CrossAccountId,637		token_id: TokenId,638		property_keys: impl Iterator<Item = PropertyKey>,639		nesting_budget: &dyn Budget,640	) -> DispatchResult {641		let is_token_create = false;642643		Self::modify_token_properties(644			collection,645			sender,646			token_id,647			property_keys.into_iter().map(|key| (key, None)),648			is_token_create,649			nesting_budget,650		)651	}652653	pub fn delete_token_property(654		collection: &RefungibleHandle<T>,655		sender: &T::CrossAccountId,656		token_id: TokenId,657		property_key: PropertyKey,658		nesting_budget: &dyn Budget,659	) -> DispatchResult {660		Self::delete_token_properties(661			collection,662			sender,663			token_id,664			[property_key].into_iter(),665			nesting_budget,666		)667	}668669	/// Transfer RFT token pieces from one account to another.670	///671	/// If the sender is no longer owns any pieces after the `transfer` than she stops being an owner of the token.672	///673	/// - `from`: Owner of token pieces to transfer.674	/// - `to`: Recepient of transfered token pieces.675	/// - `amount`: Amount of token pieces to transfer.676	/// - `token`: Token whos pieces should be transfered677	/// - `collection`: Collection that contains the token678	pub fn transfer(679		collection: &RefungibleHandle<T>,680		from: &T::CrossAccountId,681		to: &T::CrossAccountId,682		token: TokenId,683		amount: u128,684		nesting_budget: &dyn Budget,685	) -> DispatchResult {686		ensure!(687			collection.limits.transfers_enabled(),688			<CommonError<T>>::TransferNotAllowed689		);690691		if collection.permissions.access() == AccessMode::AllowList {692			collection.check_allowlist(from)?;693			collection.check_allowlist(to)?;694		}695		<PalletCommon<T>>::ensure_correct_receiver(to)?;696697		let balance_from = <Balance<T>>::get((collection.id, token, from))698			.checked_sub(amount)699			.ok_or(<CommonError<T>>::TokenValueTooLow)?;700		let mut create_target = false;701		let from_to_differ = from != to;702		let balance_to = if from != to {703			let old_balance = <Balance<T>>::get((collection.id, token, to));704			if old_balance == 0 {705				create_target = true;706			}707			Some(708				old_balance709					.checked_add(amount)710					.ok_or(ArithmeticError::Overflow)?,711			)712		} else {713			None714		};715716		let account_balance_from = if balance_from == 0 {717			Some(718				<AccountBalance<T>>::get((collection.id, from))719					.checked_sub(1)720					// Should not occur721					.ok_or(ArithmeticError::Underflow)?,722			)723		} else {724			None725		};726		// Account data is created in token, AccountBalance should be increased727		// But only if from != to as we shouldn't check overflow in this case728		let account_balance_to = if create_target && from_to_differ {729			let account_balance_to = <AccountBalance<T>>::get((collection.id, to))730				.checked_add(1)731				.ok_or(ArithmeticError::Overflow)?;732			ensure!(733				account_balance_to < collection.limits.account_token_ownership_limit(),734				<CommonError<T>>::AccountTokenLimitExceeded,735			);736737			Some(account_balance_to)738		} else {739			None740		};741742		// =========743744		<PalletStructure<T>>::nest_if_sent_to_token(745			from.clone(),746			to,747			collection.id,748			token,749			nesting_budget,750		)?;751752		if let Some(balance_to) = balance_to {753			// from != to754			if balance_from == 0 {755				<Balance<T>>::remove((collection.id, token, from));756				<PalletStructure<T>>::unnest_if_nested(from, collection.id, token);757			} else {758				<Balance<T>>::insert((collection.id, token, from), balance_from);759			}760			<Balance<T>>::insert((collection.id, token, to), balance_to);761			if let Some(account_balance_from) = account_balance_from {762				<AccountBalance<T>>::insert((collection.id, from), account_balance_from);763				<Owned<T>>::remove((collection.id, from, token));764			}765			if let Some(account_balance_to) = account_balance_to {766				<AccountBalance<T>>::insert((collection.id, to), account_balance_to);767				<Owned<T>>::insert((collection.id, to, token), true);768			}769		}770771		<PalletEvm<T>>::deposit_log(772			ERC20Events::Transfer {773				from: *from.as_eth(),774				to: *to.as_eth(),775				value: amount.into(),776			}777			.to_log(T::EvmTokenAddressMapping::token_to_address(778				collection.id,779				token,780			)),781		);782		<PalletCommon<T>>::deposit_event(CommonEvent::Transfer(783			collection.id,784			token,785			from.clone(),786			to.clone(),787			amount,788		));789		Ok(())790	}791792	/// Batched operation to create multiple RFT tokens.793	///794	/// Same as `create_item` but creates multiple tokens.795	///796	/// - `data`: Same as 'data` in `create_item` but contains data for multiple tokens.797	pub fn create_multiple_items(798		collection: &RefungibleHandle<T>,799		sender: &T::CrossAccountId,800		data: Vec<CreateRefungibleExData<T::CrossAccountId>>,801		nesting_budget: &dyn Budget,802	) -> DispatchResult {803		if !collection.is_owner_or_admin(sender) {804			ensure!(805				collection.permissions.mint_mode(),806				<CommonError<T>>::PublicMintingNotAllowed807			);808			collection.check_allowlist(sender)?;809810			for item in data.iter() {811				for user in item.users.keys() {812					collection.check_allowlist(user)?;813				}814			}815		}816817		for item in data.iter() {818			for (owner, _) in item.users.iter() {819				<PalletCommon<T>>::ensure_correct_receiver(owner)?;820			}821		}822823		// Total pieces per tokens824		let totals = data825			.iter()826			.map(|data| {827				Ok(data828					.users829					.iter()830					.map(|u| u.1)831					.try_fold(0u128, |acc, v| acc.checked_add(*v))832					.ok_or(ArithmeticError::Overflow)?)833			})834			.collect::<Result<Vec<_>, DispatchError>>()?;835		for total in &totals {836			ensure!(837				*total <= MAX_REFUNGIBLE_PIECES,838				<Error<T>>::WrongRefungiblePieces839			);840		}841842		let first_token_id = <TokensMinted<T>>::get(collection.id);843		let tokens_minted = first_token_id844			.checked_add(data.len() as u32)845			.ok_or(ArithmeticError::Overflow)?;846		ensure!(847			tokens_minted < collection.limits.token_limit(),848			<CommonError<T>>::CollectionTokenLimitExceeded849		);850851		let mut balances = BTreeMap::new();852		for data in &data {853			for owner in data.users.keys() {854				let balance = balances855					.entry(owner)856					.or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));857				*balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;858859				ensure!(860					*balance <= collection.limits.account_token_ownership_limit(),861					<CommonError<T>>::AccountTokenLimitExceeded,862				);863			}864		}865866		for (i, token) in data.iter().enumerate() {867			let token_id = TokenId(first_token_id + i as u32 + 1);868			for (to, _) in token.users.iter() {869				<PalletStructure<T>>::check_nesting(870					sender.clone(),871					to,872					collection.id,873					token_id,874					nesting_budget,875				)?;876			}877		}878879		// =========880881		with_transaction(|| {882			for (i, data) in data.iter().enumerate() {883				let token_id = first_token_id + i as u32 + 1;884				<TotalSupply<T>>::insert((collection.id, token_id), totals[i]);885886				<TokenData<T>>::insert(887					(collection.id, token_id),888					ItemData {889						const_data: data.const_data.clone(),890					},891				);892893				for (user, amount) in data.users.iter() {894					if *amount == 0 {895						continue;896					}897					<Balance<T>>::insert((collection.id, token_id, &user), amount);898					<Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);899					<PalletStructure<T>>::nest_if_sent_to_token_unchecked(900						user,901						collection.id,902						TokenId(token_id),903					);904				}905906				if let Err(e) = Self::set_token_properties(907					collection,908					sender,909					TokenId(token_id),910					data.properties.clone().into_iter(),911					true,912					nesting_budget,913				) {914					return TransactionOutcome::Rollback(Err(e));915				}916			}917			TransactionOutcome::Commit(Ok(()))918		})?;919920		<TokensMinted<T>>::insert(collection.id, tokens_minted);921922		for (account, balance) in balances {923			<AccountBalance<T>>::insert((collection.id, account), balance);924		}925926		for (i, token) in data.into_iter().enumerate() {927			let token_id = first_token_id + i as u32 + 1;928929			for (user, amount) in token.users.into_iter() {930				if amount == 0 {931					continue;932				}933934				<PalletEvm<T>>::deposit_log(935					ERC20Events::Transfer {936						from: H160::default(),937						to: *user.as_eth(),938						value: amount.into(),939					}940					.to_log(T::EvmTokenAddressMapping::token_to_address(941						collection.id,942						TokenId(token_id),943					)),944				);945				<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(946					collection.id,947					TokenId(token_id),948					user,949					amount,950				));951			}952		}953		Ok(())954	}955956	pub fn set_allowance_unchecked(957		collection: &RefungibleHandle<T>,958		sender: &T::CrossAccountId,959		spender: &T::CrossAccountId,960		token: TokenId,961		amount: u128,962	) {963		if amount == 0 {964			<Allowance<T>>::remove((collection.id, token, sender, spender));965		} else {966			<Allowance<T>>::insert((collection.id, token, sender, spender), amount);967		}968969		<PalletEvm<T>>::deposit_log(970			ERC20Events::Approval {971				owner: *sender.as_eth(),972				spender: *spender.as_eth(),973				value: amount.into(),974			}975			.to_log(T::EvmTokenAddressMapping::token_to_address(976				collection.id,977				token,978			)),979		);980		<PalletCommon<T>>::deposit_event(CommonEvent::Approved(981			collection.id,982			token,983			sender.clone(),984			spender.clone(),985			amount,986		))987	}988989	/// Set allowance for the spender to `transfer` or `burn` sender's token pieces.990	///991	/// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.992	pub fn set_allowance(993		collection: &RefungibleHandle<T>,994		sender: &T::CrossAccountId,995		spender: &T::CrossAccountId,996		token: TokenId,997		amount: u128,998	) -> DispatchResult {999		if collection.permissions.access() == AccessMode::AllowList {1000			collection.check_allowlist(sender)?;1001			collection.check_allowlist(spender)?;1002		}10031004		<PalletCommon<T>>::ensure_correct_receiver(spender)?;10051006		if <Balance<T>>::get((collection.id, token, sender)) < amount {1007			ensure!(1008				collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),1009				<CommonError<T>>::CantApproveMoreThanOwned1010			);1011		}10121013		// =========10141015		Self::set_allowance_unchecked(collection, sender, spender, token, amount);1016		Ok(())1017	}10181019	/// Returns allowance, which should be set after transaction1020	fn check_allowed(1021		collection: &RefungibleHandle<T>,1022		spender: &T::CrossAccountId,1023		from: &T::CrossAccountId,1024		token: TokenId,1025		amount: u128,1026		nesting_budget: &dyn Budget,1027	) -> Result<Option<u128>, DispatchError> {1028		if spender.conv_eq(from) {1029			return Ok(None);1030		}1031		if collection.permissions.access() == AccessMode::AllowList {1032			// `from`, `to` checked in [`transfer`]1033			collection.check_allowlist(spender)?;1034		}1035		if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1036			// TODO: should collection owner be allowed to perform this transfer?1037			ensure!(1038				<PalletStructure<T>>::check_indirectly_owned(1039					spender.clone(),1040					source.0,1041					source.1,1042					None,1043					nesting_budget1044				)?,1045				<CommonError<T>>::ApprovedValueTooLow,1046			);1047			return Ok(None);1048		}1049		let allowance =1050			<Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);1051		if allowance.is_none() {1052			ensure!(1053				collection.ignores_allowance(spender),1054				<CommonError<T>>::ApprovedValueTooLow1055			);1056		}1057		Ok(allowance)1058	}10591060	/// Transfer RFT token pieces from one account to another.1061	///1062	/// Same as the [`transfer`] but spender doesn't needs to be an owner of the token pieces.1063	/// The owner should set allowance for the spender to transfer pieces.1064	///1065	/// [`transfer`]: struct.Pallet.html#method.transfer1066	pub fn transfer_from(1067		collection: &RefungibleHandle<T>,1068		spender: &T::CrossAccountId,1069		from: &T::CrossAccountId,1070		to: &T::CrossAccountId,1071		token: TokenId,1072		amount: u128,1073		nesting_budget: &dyn Budget,1074	) -> DispatchResult {1075		let allowance =1076			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;10771078		// =========10791080		Self::transfer(collection, from, to, token, amount, nesting_budget)?;1081		if let Some(allowance) = allowance {1082			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1083		}1084		Ok(())1085	}10861087	/// Burn RFT token pieces from the account.1088	///1089	/// Same as the [`burn`] but spender doesn't need to be an owner of the token pieces. The owner should1090	/// set allowance for the spender to burn pieces1091	///1092	/// [`burn`]: struct.Pallet.html#method.burn1093	pub fn burn_from(1094		collection: &RefungibleHandle<T>,1095		spender: &T::CrossAccountId,1096		from: &T::CrossAccountId,1097		token: TokenId,1098		amount: u128,1099		nesting_budget: &dyn Budget,1100	) -> DispatchResult {1101		let allowance =1102			Self::check_allowed(collection, spender, from, token, amount, nesting_budget)?;11031104		// =========11051106		Self::burn(collection, from, token, amount)?;1107		if let Some(allowance) = allowance {1108			Self::set_allowance_unchecked(collection, from, spender, token, allowance);1109		}1110		Ok(())1111	}11121113	/// Create RFT token.1114	///1115	/// The sender should be the owner/admin of the collection or collection should be configured1116	/// to allow public minting.1117	///1118	/// - `data`: Contains list of users who will become the owners of the token pieces and amount1119	///   of token pieces they will receive.1120	pub fn create_item(1121		collection: &RefungibleHandle<T>,1122		sender: &T::CrossAccountId,1123		data: CreateRefungibleExData<T::CrossAccountId>,1124		nesting_budget: &dyn Budget,1125	) -> DispatchResult {1126		Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1127	}11281129	/// Repartition RFT token.1130	///1131	/// `repartition` will set token balance of the sender and total amount of token pieces.1132	/// Sender should own all of the token pieces. `repartition' could be done even if some1133	/// token pieces were burned before.1134	///1135	/// - `amount`: Total amount of token pieces that the token will have after `repartition`.1136	pub fn repartition(1137		collection: &RefungibleHandle<T>,1138		owner: &T::CrossAccountId,1139		token: TokenId,1140		amount: u128,1141	) -> DispatchResult {1142		ensure!(1143			amount <= MAX_REFUNGIBLE_PIECES,1144			<Error<T>>::WrongRefungiblePieces1145		);1146		ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1147		// Ensure user owns all pieces1148		let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);1149		let balance = <Balance<T>>::get((collection.id, token, owner));1150		ensure!(1151			total_pieces == balance,1152			<Error<T>>::RepartitionWhileNotOwningAllPieces1153		);11541155		<Balance<T>>::insert((collection.id, token, owner), amount);1156		<TotalSupply<T>>::insert((collection.id, token), amount);11571158		if amount > total_pieces {1159			let mint_amount = amount - total_pieces;1160			<PalletEvm<T>>::deposit_log(1161				ERC20Events::Transfer {1162					from: H160::default(),1163					to: *owner.as_eth(),1164					value: mint_amount.into(),1165				}1166				.to_log(T::EvmTokenAddressMapping::token_to_address(1167					collection.id,1168					token,1169				)),1170			);1171			<PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(1172				collection.id,1173				token,1174				owner.clone(),1175				mint_amount,1176			));1177		} else if total_pieces > amount {1178			let burn_amount = total_pieces - amount;1179			<PalletEvm<T>>::deposit_log(1180				ERC20Events::Transfer {1181					from: *owner.as_eth(),1182					to: H160::default(),1183					value: burn_amount.into(),1184				}1185				.to_log(T::EvmTokenAddressMapping::token_to_address(1186					collection.id,1187					token,1188				)),1189			);1190			<PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(1191				collection.id,1192				token,1193				owner.clone(),1194				burn_amount,1195			));1196		}11971198		Ok(())1199	}12001201	fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {1202		let mut owner = None;1203		let mut count = 0;1204		for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1205			count += 1;1206			if count > 1 {1207				return None;1208			}1209			owner = Some(key);1210		}1211		owner1212	}12131214	fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1215		<TotalSupply<T>>::try_get((collection_id, token_id)).ok()1216	}12171218	pub fn set_collection_properties(1219		collection: &RefungibleHandle<T>,1220		sender: &T::CrossAccountId,1221		properties: Vec<Property>,1222	) -> DispatchResult {1223		<PalletCommon<T>>::set_collection_properties(collection, sender, properties)1224	}12251226	pub fn delete_collection_properties(1227		collection: &RefungibleHandle<T>,1228		sender: &T::CrossAccountId,1229		property_keys: Vec<PropertyKey>,1230	) -> DispatchResult {1231		<PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)1232	}12331234	pub fn set_token_property_permissions(1235		collection: &RefungibleHandle<T>,1236		sender: &T::CrossAccountId,1237		property_permissions: Vec<PropertyKeyPermission>,1238	) -> DispatchResult {1239		<PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1240	}12411242	/// Returns 10 token in no particular order.1243	///1244	/// There is no direct way to get token holders in ascending order,1245	/// since `iter_prefix` returns values in no particular order.1246	/// Therefore, getting the 10 largest holders with a large value of holders1247	/// can lead to impact memory allocation + sorting with  `n * log (n)`.1248	pub fn token_owners(1249		collection_id: CollectionId,1250		token: TokenId,1251	) -> Option<Vec<T::CrossAccountId>> {1252		let res: Vec<T::CrossAccountId> = <Balance<T>>::iter_prefix((collection_id, token))1253			.map(|(owner, _amount)| owner)1254			.take(10)1255			.collect();12561257		if res.is_empty() {1258			None1259		} else {1260			Some(res)1261		}1262	}1263}
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
--- a/pallets/scheduler/src/lib.rs
+++ b/pallets/scheduler/src/lib.rs
@@ -24,7 +24,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-// 	http://www.apache.org/licenses/LICENSE-2.0
+// 	<http://www.apache.org/licenses/LICENSE-2.0>
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -50,7 +50,7 @@
 //! Also possible to book a call with a certain frequency.
 //!
 //! Key differences from the original pallet:
-//! https://crates.io/crates/pallet-scheduler
+//! <https://crates.io/crates/pallet-scheduler>
 //! Schedule Id restricted by 16 bytes. Identificator for booked call.
 //! Priority limited by HARD DEADLINE (<= 63). Calls over maximum weight don't include to block.
 //! The maximum weight that may be scheduled per block for any dispatchables of less priority than `schedule::HARD_DEADLINE`.
@@ -267,6 +267,7 @@
 
 	/// A Scheduler-Runtime interface for finer payment handling.
 	pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {
+		/// Reserve (lock) the maximum spendings on a call, calculated from its weight and the repetition count.
 		fn reserve_balance(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -274,7 +275,7 @@
 			count: u32,
 		) -> Result<(), DispatchError>;
 
-		/// Unlock centain amount from payer
+		/// Unreserve (unlock) a certain amount from the payer's reserved funds, returning the change.
 		fn pay_for_call(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -290,6 +291,7 @@
 			TransactionValidityError,
 		>;
 
+		/// Release unspent reserved funds in case of a schedule cancel.
 		fn cancel_reserve(
 			id: ScheduledId,
 			sponsor: <T as frame_system::Config>::AccountId,
@@ -494,9 +496,8 @@
 					Agenda::<T>::append(wake, Some(s));
 				}
 			}
-			/// Weight should be 0, because transaction already paid
+			// Total weight should be 0, because the transaction is already paid for
 			0
-			//total_weight
 		}
 	}
 
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -78,19 +78,19 @@
 
 	#[pallet::error]
 	pub enum Error<T> {
-		/// While searched for owner, got already checked account
+		/// While nesting, encountered an already checked account, detecting a loop.
 		OuroborosDetected,
-		/// While searched for owner, encountered depth limit
+		/// While nesting, reached the depth limit of nesting, exceeding the provided budget.
 		DepthLimit,
-		/// While iterating over children, encountered breadth limit
+		/// While nesting, reached the breadth limit of nesting, exceeding the provided budget.
 		BreadthLimit,
-		/// While searched for owner, found token owner by not-yet-existing token
+		/// Couldn't find the token owner that is itself a token.
 		TokenNotFound,
 	}
 
 	#[pallet::event]
 	pub enum Event<T> {
-		/// Executed call on behalf of token
+		/// Executed call on behalf of the token.
 		Executed(DispatchResult),
 	}
 
@@ -126,11 +126,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),
 }
 
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! Implementation of CollectionHelpers contract.
+
 use core::marker::PhantomData;
 use evm_coder::{execution::*, generate_stubgen, solidity_interface, weight, types::*};
 use ethereum as _;
@@ -33,7 +35,8 @@
 use sp_std::vec::Vec;
 use alloc::format;
 
-struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);
+/// See [`CollectionHelpersCall`]
+pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);
 impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {
 	fn recorder(&self) -> &SubstrateRecorder<T> {
 		&self.0
@@ -44,8 +47,14 @@
 	}
 }
 
+/// @title Contract, which allows users to operate with collections
 #[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]
 impl<T: Config + pallet_nonfungible::Config> EvmCollectionHelpers<T> {
+	/// Create an NFT collection
+	/// @param name Name of the collection
+	/// @param description Informative description of the collection
+	/// @param token_prefix Token prefix to represent the collection tokens in UI and user applications
+	/// @return address Address of the newly created collection
 	#[weight(<SelfWeightOf<T>>::create_collection())]
 	fn create_nonfungible_collection(
 		&mut self,
@@ -100,6 +109,9 @@
 		Ok(address)
 	}
 
+	/// Check if a collection exists
+	/// @param collection_address Address of the collection in question
+	/// @return bool Does the collection exist?
 	fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {
 		if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {
 			let collection_id = id;
@@ -110,6 +122,7 @@
 	}
 }
 
+/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]
 pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);
 impl<T: Config + pallet_nonfungible::Config> OnMethodCall<T> for CollectionHelpersOnMethodCall<T> {
 	fn is_reserved(contract: &sp_core::H160) -> bool {
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -14,6 +14,55 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! # Unique Pallet
+//!
+//! A pallet governing Unique transactions.
+//!
+//! - [`Config`]
+//! - [`Call`]
+//! - [`Pallet`]
+//!
+//! ## Overview
+//!
+//! The Unique pallet's purpose is to be the primary interface between
+//! external users and the inner structure of the Unique chains.
+//!
+//! It also contains an implementation of [`CollectionHelpers`][`eth`],
+//! an Ethereum contract dealing with collection operations.
+//!
+//! ## Interface
+//!
+//! ### Dispatchables
+//!
+//! - `create_collection` - Create a collection of tokens. **Deprecated**, use `create_collection_ex`.
+//! - `create_collection_ex` - Create a collection of tokens with explicit parameters.
+//! - `destroy_collection` - Destroy a collection if no tokens exist within.
+//! - `add_to_allow_list` - Add an address to allow list.
+//! - `remove_from_allow_list` - Remove an address from allow list.
+//! - `change_collection_owner` - Change the owner of the collection.
+//! - `add_collection_admin` - Add an admin to a collection.
+//! - `remove_collection_admin` - Remove admin of a collection.
+//! - `set_collection_sponsor` - Invite a new collection sponsor.
+//! - `confirm_sponsorship` - Confirm own sponsorship of a collection, becoming the sponsor.
+//! - `remove_collection_sponsor` - Remove a sponsor from a collection.
+//! - `create_item` - Create an item within a collection.
+//! - `create_multiple_items` - Create multiple items within a collection.
+//! - `set_collection_properties` - Add or change collection properties.
+//! - `delete_collection_properties` - Delete specified collection properties.
+//! - `set_token_properties` - Add or change token properties.
+//! - `delete_token_properties` - Delete token properties.
+//! - `set_token_property_permissions` - Add or change token property permissions of a collection.
+//! - `create_multiple_items_ex` - Create multiple items within a collection with explicitly specified initial parameters.
+//! - `set_transfers_enabled_flag` - Completely allow or disallow transfers for a particular collection.
+//! - `burn_item` - Destroy an item.
+//! - `burn_from` - Destroy an item on behalf of the owner as a non-owner account.
+//! - `transfer` - Change ownership of the token.
+//! - `transfer_from` - Change ownership of the token on behalf of the owner as a non-owner account.
+//! - `approve` - Allow a non-permissioned address to transfer or burn an item.
+//! - `set_collection_limits` - Set specific limits of a collection.
+//! - `set_collection_permissions` - Set specific permissions of a collection.
+//! - `repartition` - Re-partition a refungible token, while owning all of its parts.
+
 #![recursion_limit = "1024"]
 #![cfg_attr(not(feature = "std"), no_std)]
 #![allow(
@@ -54,28 +103,35 @@
 pub mod weights;
 use weights::WeightInfo;
 
-const NESTING_BUDGET: u32 = 5;
+/// Maximum number of levels of depth in the token nesting tree.
+pub const NESTING_BUDGET: u32 = 5;
 
 decl_error! {
-	/// Error for non-fungible-token module.
+	/// Errors for the common Unique transactions.
 	pub enum Error for Module<T: Config> {
-		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.
+		/// Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
 		CollectionDecimalPointLimitExceeded,
 		/// This address is not set as sponsor, use setCollectionSponsor first.
 		ConfirmUnsetSponsorFail,
 		/// Length of items properties must be greater than 0.
 		EmptyArgument,
-		/// Repertition is only supported by refungible collection
+		/// Repertition is only supported by refungible collection.
 		RepartitionCalledOnNonRefungibleCollection,
 	}
 }
 
+/// Configuration trait of this pallet.
 pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {
+	/// Overarching event type.
 	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
 
 	/// Weight information for extrinsics in this pallet.
 	type WeightInfo: WeightInfo;
+
+	/// Weight information for common pallet operations.
 	type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;
+
+	/// Weight info information for extra refungible pallet operations.
 	type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo;
 }
 
@@ -88,80 +144,68 @@
 		/// Collection sponsor was removed
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
+		/// * collection_id: ID of the affected collection.
 		CollectionSponsorRemoved(CollectionId),
 
 		/// Collection admin was added
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * admin:  Admin address.
+		/// * collection_id: ID of the affected collection.
+		/// * admin: Admin address.
 		CollectionAdminAdded(CollectionId, CrossAccountId),
 
-		/// Collection owned was change
+		/// Collection owned was changed
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * owner:  New owner address.
+		/// * collection_id: ID of the affected collection.
+		/// * owner: New owner address.
 		CollectionOwnedChanged(CollectionId, AccountId),
 
 		/// Collection sponsor was set
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * owner:  New sponsor address.
+		/// * collection_id: ID of the affected collection.
+		/// * owner: New sponsor address.
 		CollectionSponsorSet(CollectionId, AccountId),
 
 		/// New sponsor was confirm
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * sponsor:  New sponsor address.
+		/// * collection_id: ID of the affected collection.
+		/// * sponsor: New sponsor address.
 		SponsorshipConfirmed(CollectionId, AccountId),
 
 		/// Collection admin was removed
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * admin:  Admin address.
+		/// * collection_id: ID of the affected collection.
+		/// * admin: Removed admin address.
 		CollectionAdminRemoved(CollectionId, CrossAccountId),
 
-		/// Address was remove from allow list
+		/// Address was removed from the allow list
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * user:  Address.
+		/// * collection_id: ID of the affected collection.
+		/// * user: Address of the removed account.
 		AllowListAddressRemoved(CollectionId, CrossAccountId),
 
-		/// Address was add to allow list
+		/// Address was added to the allow list
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
-		///
-		/// * user:  Address.
+		/// * collection_id: ID of the affected collection.
+		/// * user: Address of the added account.
 		AllowListAddressAdded(CollectionId, CrossAccountId),
 
-		/// Collection limits was set
+		/// Collection limits were set
 		///
 		/// # Arguments
-		///
-		/// * collection_id: Globally unique collection identifier.
+		/// * collection_id: ID of the affected collection.
 		CollectionLimitSet(CollectionId),
 
+		/// Collection permissions were set
+		///
+		/// # Arguments
+		/// * collection_id: ID of the affected collection.
 		CollectionPermissionSet(CollectionId),
 	}
 }
@@ -198,7 +242,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,16 +258,20 @@
 		/// 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>;
 	}
 }
 
 decl_module! {
+	/// Type alias to Pallet, to be used by construct_runtime.
 	pub struct Module<T: Config> for enum Call
 	where
 		origin: T::Origin
@@ -244,30 +292,38 @@
 			0
 		}
 
-		/// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.
-		///
-		/// # Permissions
+		/// Create a collection of tokens.
 		///
-		/// * Anyone.
+		/// Each Token may have multiple properties encoded as an array of bytes
+		/// of certain length. The initial owner of the collection is set
+		/// to the address that signed the transaction and can be changed later.
 		///
-		/// # Arguments
+		/// Prefer the more advanced [`create_collection_ex`][`Pallet::create_collection_ex`] instead.
 		///
-		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.
+		/// # Permissions
 		///
-		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.
+		/// * Anyone - becomes the owner of the new collection.
 		///
-		/// * token_prefix: UTF-8 string with token prefix.
+		/// # Arguments
 		///
-		/// * mode: [CollectionMode] collection type and type dependent data.
+		/// * `collection_name`: Wide-character string with collection name
+		/// (limit [`MAX_COLLECTION_NAME_LENGTH`]).
+		/// * `collection_description`: Wide-character string with collection description
+		/// (limit [`MAX_COLLECTION_DESCRIPTION_LENGTH`]).
+		/// * `token_prefix`: Byte string containing the token prefix to mark a collection
+		/// to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).
+		/// * `mode`: Type of items stored in the collection and type dependent data.
 		// returns collection ID
 		#[weight = <SelfWeightOf<T>>::create_collection()]
 		#[transactional]
-		#[deprecated]
-		pub fn create_collection(origin,
-								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
-								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
-								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
-								 mode: CollectionMode) -> DispatchResult  {
+		#[deprecated(note = "`create_collection_ex` is more up-to-date and advanced, prefer it instead")]
+		pub fn create_collection(
+			origin,
+			collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
+			collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
+			token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
+			mode: CollectionMode
+		) -> DispatchResult {
 			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {
 				name: collection_name,
 				description: collection_description,
@@ -278,9 +334,17 @@
 			Self::create_collection_ex(origin, data)
 		}
 
-		/// This method creates a collection
+		/// Create a collection with explicit parameters.
+		///
+		/// Prefer it to the deprecated [`create_collection`][`Pallet::create_collection`] method.
+		///
+		/// # Permissions
+		///
+		/// * Anyone - becomes the owner of the new collection.
 		///
-		/// Prefer it to deprecated [`created_collection`] method
+		/// # Arguments
+		///
+		/// * `data`: Explicit data of a collection used for its creation.
 		#[weight = <SelfWeightOf<T>>::create_collection()]
 		#[transactional]
 		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {
@@ -293,15 +357,15 @@
 			Ok(())
 		}
 
-		/// Destroys collection if no tokens within this collection
+		/// Destroy a collection if no tokens exist within.
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
+		/// * Collection owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id: collection to destroy.
+		/// * `collection_id`: Collection to destroy.
 		#[weight = <SelfWeightOf<T>>::destroy_collection()]
 		#[transactional]
 		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
@@ -328,14 +392,13 @@
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner
-		/// * Collection Admin
+		/// * Collection owner
+		/// * Collection admin
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
-		///
-		/// * address.
+		/// * `collection_id`: ID of the modified collection.
+		/// * `address`: ID of the address to be added to the allowlist.
 		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]
 		#[transactional]
 		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{
@@ -363,14 +426,13 @@
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner
-		/// * Collection Admin
+		/// * Collection owner
+		/// * Collection admin
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
-		///
-		/// * address.
+		/// * `collection_id`: ID of the modified collection.
+		/// * `address`: ID of the address to be removed from the allowlist.
 		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]
 		#[transactional]
 		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{
@@ -398,13 +460,12 @@
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
+		/// * Collection owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
-		///
-		/// * new_owner.
+		/// * `collection_id`: ID of the modified collection.
+		/// * `new_owner`: ID of the account that will become the owner.
 		#[weight = <SelfWeightOf<T>>::change_collection_owner()]
 		#[transactional]
 		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {
@@ -424,46 +485,51 @@
 			target_collection.save()
 		}
 
-		/// 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.
+		/// Add an admin to a 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.
+		/// * `collection_id`: ID of the Collection to add an admin for.
+		/// * `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.
+		/// Remove admin of a 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
 		///
-		/// * collection_id: ID of the Collection to remove admin for.
-		///
-		/// * account_id: Address of admin to remove.
+		/// * `collection_id`: ID of the collection to remove the admin for.
+		/// * `account_id`: Address of the admin to remove.
 		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]
 		#[transactional]
 		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {
@@ -479,15 +545,19 @@
 			<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 owner
+		/// * Collection admin
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
-		///
-		/// * new_sponsor.
+		/// * `collection_id`: ID of the modified collection.
+		/// * `new_sponsor`: ID of the account of the sponsor-to-be.
 		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]
 		#[transactional]
 		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {
@@ -507,13 +577,19 @@
 			target_collection.save()
 		}
 
+		/// Confirm own sponsorship of a collection, becoming the sponsor.
+		///
+		/// An invitation must be pending, see [`set_collection_sponsor`][`Pallet::set_collection_sponsor`].
+		/// Sponsor can pay the fees of a transaction instead of the sender,
+		/// but only within specified limits.
+		///
 		/// # Permissions
 		///
-		/// * Sponsor.
+		/// * Sponsor-to-be
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
+		/// * `collection_id`: ID of the collection with the pending sponsor.
 		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]
 		#[transactional]
 		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {
@@ -534,15 +610,15 @@
 			target_collection.save()
 		}
 
-		/// Switch back to pay-per-own-transaction model.
+		/// Remove a collection's a sponsor, making everyone pay for their own transactions.
 		///
 		/// # Permissions
 		///
-		/// * Collection owner.
+		/// * Collection owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id.
+		/// * `collection_id`: ID of the collection with the sponsor to remove.
 		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]
 		#[transactional]
 		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {
@@ -560,24 +636,24 @@
 			target_collection.save()
 		}
 
-		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.
+		/// Mint an item within a collection.
+		///
+		/// A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
-		/// * Collection Admin.
+		/// * Collection owner
+		/// * Collection admin
 		/// * Anyone if
 		///     * Allow List is enabled, and
 		///     * Address is added to allow list, and
-		///     * MintPermission is enabled (see SetMintPermission method)
+		///     * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
 		///
 		/// # Arguments
-		///
-		/// * collection_id: ID of the collection.
 		///
-		/// * owner: Address, initial owner of the NFT.
-		///
-		/// * data: Token data to store on chain.
+		/// * `collection_id`: ID of the collection to which an item would belong.
+		/// * `owner`: Address of the initial owner of the item.
+		/// * `data`: Token data describing the item to store on chain.
 		#[weight = T::CommonWeightInfo::create_item()]
 		#[transactional]
 		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {
@@ -587,24 +663,24 @@
 			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 within a collection.
 		///
+		/// A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
+		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
-		/// * Collection Admin.
+		/// * Collection owner
+		/// * Collection admin
 		/// * Anyone if
 		///     * Allow List is enabled, and
-		///     * Address is added to allow list, and
-		///     * MintPermission is enabled (see SetMintPermission method)
+		///     * Address is added to the allow list, and
+		///     * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].
-		///
-		/// * owner: Address, initial owner of the NFT.
+		/// * `collection_id`: ID of the collection to which the tokens would belong.
+		/// * `owner`: Address of the initial owner of the tokens.
+		/// * `items_data`: Vector of data describing each item to be created.
 		#[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]
 		#[transactional]
 		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {
@@ -615,6 +691,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`: ID of the modified collection.
+		/// * `properties`: 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 +717,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`: ID of the modified collection.
+		/// * `property_keys`: Vector of keys of the properties to be deleted.
+		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.
 		#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]
 		#[transactional]
 		pub fn delete_collection_properties(
@@ -643,6 +743,24 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))
 		}
 
+		/// Add or change token properties according to collection's permissions.
+		/// Currently properties only work with NFTs.
+		///
+		/// # Permissions
+		///
+		/// * Depends on collection's token property permissions and specified property mutability:
+		/// 	* Collection owner
+		/// 	* Collection admin
+		/// 	* Token owner
+		///
+		/// See [`set_token_property_permissions`][`Pallet::set_token_property_permissions`].
+		///
+		/// # Arguments
+		///
+		/// * `collection_id: ID of the collection to which the token belongs.
+		/// * `token_id`: ID of the modified token.
+		/// * `properties`: 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 +777,21 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties, &budget))
 		}
 
+		/// Delete specified token properties. Currently properties only work with NFTs.
+		///
+		/// # Permissions
+		///
+		/// * Depends on collection's token property permissions and specified property mutability:
+		/// 	* Collection owner
+		/// 	* Collection admin
+		/// 	* Token owner
+		///
+		/// # Arguments
+		///
+		/// * `collection_id`: ID of the collection to which the token belongs.
+		/// * `token_id`: ID of the modified token.
+		/// * `property_keys`: Vector of keys of the properties to be deleted.
+		/// Keys support Latin letters, `-`, `_`, and `.` as symbols.
 		#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]
 		#[transactional]
 		pub fn delete_token_properties(
@@ -675,6 +808,21 @@
 			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.
+		///
+		/// Without a permission for a particular key, a property with that key
+		/// cannot be created in a token.
+		///
+		/// # Permissions
+		///
+		/// * Collection owner
+		/// * Collection admin
+		///
+		/// # Arguments
+		///
+		/// * `collection_id`: ID of the modified collection.
+		/// * `property_permissions`: 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 +837,21 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.set_token_property_permissions(&sender, property_permissions))
 		}
 
+		/// Create multiple items within 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 [`set_collection_permissions`][`Pallet::set_collection_permissions`])
+		///
+		/// # Arguments
+		///
+		/// * `collection_id`: ID of the collection to which the tokens would belong.
+		/// * `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,17 +861,16 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))
 		}
 
-		/// Set transfers_enabled value for particular collection
+		/// Completely allow or disallow transfers for a particular collection.
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
+		/// * Collection owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * value: New flag value.
+		/// * `collection_id`: ID of the collection.
+		/// * `value`: New value of the flag, are transfers allowed?
 		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]
 		#[transactional]
 		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {
@@ -723,19 +885,22 @@
 			target_collection.save()
 		}
 
-		/// Destroys a concrete instance of NFT.
+		/// Destroy an item.
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
-		/// * Collection Admin.
-		/// * Current NFT Owner.
+		/// * Collection owner
+		/// * Collection admin
+		/// * Current item owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * item_id: ID of NFT to burn.
+		/// * `collection_id`: ID of the collection to which the item belongs.
+		/// * `item_id`: ID of item to burn.
+		/// * `value`: Number of pieces of the item to destroy.
+		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+		///     * Fungible Mode: The desired number of pieces to burn.
+		///     * Re-Fungible Mode: The desired number of pieces to burn.
 		#[weight = T::CommonWeightInfo::burn_item()]
 		#[transactional]
 		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
@@ -752,22 +917,29 @@
 			Ok(post_info)
 		}
 
-		/// Destroys a concrete instance of NFT on behalf of the owner
-		/// See also: [`approve`]
+		/// Destroy a token on behalf of the owner as a non-owner account.
+		///
+		/// See also: [`approve`][`Pallet::approve`].
+		///
+		/// After this method executes, one approval is removed from the total so that
+		/// the approved address will not be able to transfer this item again from this owner.
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner.
-		/// * Collection Admin.
-		/// * Current NFT Owner.
+		/// * Collection owner
+		/// * Collection admin
+		/// * Current token owner
+		/// * Address approved by current item owner
 		///
 		/// # Arguments
 		///
-		/// * collection_id: ID of the collection.
-		///
-		/// * item_id: ID of NFT to burn.
-		///
-		/// * from: owner of item
+		/// * `from`: The owner of the burning item.
+		/// * `collection_id`: ID of the collection to which the item belongs.
+		/// * `item_id`: ID of item to burn.
+		/// * `value`: Number of pieces to burn.
+		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+		///     * Fungible Mode: The desired number of pieces to burn.
+		///     * Re-Fungible Mode: The desired number of pieces to burn.
 		#[weight = T::CommonWeightInfo::burn_from()]
 		#[transactional]
 		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
@@ -781,25 +953,23 @@
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner
-		/// * Collection Admin
-		/// * Current NFT owner
+		/// * Collection owner
+		/// * Collection admin
+		/// * Current token owner
 		///
 		/// # Arguments
-		///
-		/// * recipient: Address of token recipient.
 		///
-		/// * collection_id.
-		///
-		/// * item_id: ID of the item
+		/// * `recipient`: Address of token recipient.
+		/// * `collection_id`: ID of the collection the item belongs to.
+		/// * `item_id`: ID of the item.
 		///     * Non-Fungible Mode: Required.
 		///     * Fungible Mode: Ignored.
 		///     * Re-Fungible Mode: Required.
 		///
-		/// * value: Amount to transfer.
-		///     * Non-Fungible Mode: Ignored
-		///     * Fungible Mode: Must specify transferred amount
-		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
+		/// * `value`: Amount to transfer.
+		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+		///     * Fungible Mode: The desired number of pieces to transfer.
+		///     * Re-Fungible Mode: The desired number of pieces to transfer.
 		#[weight = T::CommonWeightInfo::transfer()]
 		#[transactional]
 		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
@@ -809,21 +979,21 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))
 		}
 
-		/// Set, change, or remove approved address to transfer the ownership of the NFT.
+		/// Allow a non-permissioned address to transfer or burn an item.
 		///
 		/// # Permissions
 		///
-		/// * Collection Owner
-		/// * Collection Admin
-		/// * Current NFT owner
+		/// * Collection owner
+		/// * Collection admin
+		/// * Current item owner
 		///
 		/// # Arguments
 		///
-		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).
-		///
-		/// * collection_id.
-		///
-		/// * item_id: ID of the item.
+		/// * `spender`: Account to be approved to make specific transactions on non-owned tokens.
+		/// * `collection_id`: ID of the collection the item belongs to.
+		/// * `item_id`: ID of the item transactions on which are now approved.
+		/// * `amount`: Number of pieces of the item approved for a transaction (maximum of 1 for NFTs).
+		/// Set to 0 to revoke the approval.
 		#[weight = T::CommonWeightInfo::approve()]
 		#[transactional]
 		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {
@@ -832,25 +1002,30 @@
 			dispatch_tx::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))
 		}
 
-		/// 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.
+		/// Change ownership of an item on behalf of the owner as a non-owner account.
 		///
-		/// # Permissions
-		/// * Collection Owner
-		/// * Collection Admin
-		/// * Current NFT owner
-		/// * Address approved by current NFT owner
+		/// See the [`approve`][`Pallet::approve`] method for additional information.
 		///
-		/// # Arguments
+		/// After this method executes, one approval is removed from the total so that
+		/// the approved address will not be able to transfer this item again from this owner.
 		///
-		/// * from: Address that owns token.
+		/// # Permissions
 		///
-		/// * recipient: Address of token recipient.
+		/// * Collection owner
+		/// * Collection admin
+		/// * Current item owner
+		/// * Address approved by current item owner
 		///
-		/// * collection_id.
+		/// # Arguments
 		///
-		/// * item_id: ID of the item.
-		///
-		/// * value: Amount to transfer.
+		/// * `from`: Address that currently owns the token.
+		/// * `recipient`: Address of the new token-owner-to-be.
+		/// * `collection_id`: ID of the collection the item.
+		/// * `item_id`: ID of the item to be transferred.
+		/// * `value`: Amount to transfer.
+		/// 	* Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+		///     * Fungible Mode: The desired number of pieces to transfer.
+		///     * Re-Fungible Mode: The desired number of pieces to transfer.
 		#[weight = T::CommonWeightInfo::transfer_from()]
 		#[transactional]
 		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {
@@ -860,6 +1035,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`: ID of the modified collection.
+		/// * `new_limit`: New limits of the collection. Fields that are not set (None)
+		/// will not overwrite the old ones.
 		#[weight = <SelfWeightOf<T>>::set_collection_limits()]
 		#[transactional]
 		pub fn set_collection_limits(
@@ -882,12 +1069,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`: ID of the modified collection.
+		/// * `new_permission`: New permissions of the collection. Fields that are not set (None)
+		/// will not overwrite the old 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 +1094,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,18 +1103,29 @@
 			target_collection.save()
 		}
 
+		/// Re-partition a refungible token, while owning all of its parts/pieces.
+		///
+		/// # Permissions
+		///
+		/// * Token owner (must own every part)
+		///
+		/// # Arguments
+		///
+		/// * `collection_id`: ID of the collection the RFT belongs to.
+		/// * `token_id`: ID of the RFT.
+		/// * `amount`: New number of parts/pieces into which the token shall be partitioned.
 		#[weight = T::RefungibleExtensionsWeightInfo::repartition()]
 		#[transactional]
 		pub fn repartition(
 			origin,
 			collection_id: CollectionId,
-			token: TokenId,
+			token_id: TokenId,
 			amount: u128,
 		) -> DispatchResultWithPostInfo {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			dispatch_tx::<T, _>(collection_id, |d| {
 				if let Some(refungible_extensions) = d.refungible_extensions() {
-					refungible_extensions.repartition(&sender, token, amount)
+					refungible_extensions.repartition(&sender, token_id, amount)
 				} else {
 					fail!(<Error<T>>::RepartitionCalledOnNonRefungibleCollection)
 				}
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -197,7 +197,6 @@
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum CollectionMode {
 	NFT,
-	// decimal points
 	Fungible(DecimalPoints),
 	ReFungible,
 }
@@ -252,12 +251,14 @@
 pub enum SponsorshipState<AccountId> {
 	/// The fees are applied to the transaction sender
 	Disabled,
+	/// Pending confirmation from a sponsor-to-be
 	Unconfirmed(AccountId),
 	/// Transactions are sponsored by specified account
 	Confirmed(AccountId),
 }
 
 impl<AccountId> SponsorshipState<AccountId> {
+	/// Get the acting sponsor account, if present
 	pub fn sponsor(&self) -> Option<&AccountId> {
 		match self {
 			Self::Confirmed(sponsor) => Some(sponsor),
@@ -265,6 +266,7 @@
 		}
 	}
 
+	/// Get the sponsor account currently pending confirmation, if present
 	pub fn pending_sponsor(&self) -> Option<&AccountId> {
 		match self {
 			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),
@@ -272,6 +274,7 @@
 		}
 	}
 
+	/// Is sponsorship set and acting
 	pub fn confirmed(&self) -> bool {
 		matches!(self, Self::Confirmed(_))
 	}
@@ -283,7 +286,7 @@
 	}
 }
 
-/// Used in storage
+/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
 pub struct Collection<AccountId> {
@@ -324,7 +327,7 @@
 	pub meta_update_permission: MetaUpdatePermission,
 }
 
-/// Used in RPC calls
+/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct RpcCollection<AccountId> {
@@ -362,26 +365,41 @@
 
 pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;
 
-/// All fields are wrapped in `Option`s, where None means chain default
-// When adding/removing fields from this struct - don't forget to also update clamp_limits
+/// Limits and restrictions of a collection.
+/// All fields are wrapped in `Option`s, where None means chain default.
+///
+/// todo:doc links to chain defaults
+// IMPORTANT: When adding/removing fields from this struct - don't forget to also
+// update clamp_limits() in pallet-common.
 #[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct CollectionLimits {
+	/// Maximum number of owned tokens per account. Chain default: [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`]
 	pub account_token_ownership_limit: Option<u32>,
+	/// Maximum size of data in bytes of a sponsored transaction. Chain default: [`CUSTOM_DATA_LIMIT`]
 	pub sponsored_data_size: Option<u32>,
 
 	/// FIXME should we delete this or repurpose it?
 	/// None - setVariableMetadata is not sponsored
 	/// Some(v) - setVariableMetadata is sponsored
 	///           if there is v block between txs
+	///
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,
+	/// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]
 	pub token_limit: Option<u32>,
 
-	// Timeouts for item types in passed blocks
+	/// Timeout for sponsoring a token transfer in passed blocks. Chain default:
+	/// either [`NFT_SPONSOR_TRANSFER_TIMEOUT`], [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`], or [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`],
+	/// depending on the collection type.
 	pub sponsor_transfer_timeout: Option<u32>,
+	/// Timeout for sponsoring an approval in passed blocks. Chain default: [`SPONSOR_APPROVE_TIMEOUT`]
 	pub sponsor_approve_timeout: Option<u32>,
+	/// Can a token be transferred by the owner. Chain default: `false`
 	pub owner_can_transfer: Option<bool>,
+	/// Can a token be burned by the owner. Chain default: `true`
 	pub owner_can_destroy: Option<bool>,
+	/// Can a token be transferred at all. Chain default: `true`
 	pub transfers_enabled: Option<bool>,
 }
 
@@ -434,7 +452,10 @@
 	}
 }
 
-// When adding/removing fields from this struct - don't forget to also update clamp_limits
+/// Permissions on certain operations within a collection.
+/// All fields are wrapped in `Option`s, where None means chain default.
+// IMPORTANT: When adding/removing fields from this struct - don't forget to also
+// update clamp_limits() in pallet-common.
 #[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct CollectionPermissions {
@@ -489,6 +510,7 @@
 	}
 }
 
+/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 #[derivative(Debug)]
@@ -505,38 +527,49 @@
 	pub permissive: bool,
 }
 
+/// Enum denominating how often can sponsoring occur if it is enabled.
 #[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum SponsoringRateLimit {
+	/// Sponsoring is disabled, and the collection sponsor will not pay for transactions
 	SponsoringDisabled,
+	/// Once per how many blocks can sponsorship of a transaction type occur
 	Blocks(u32),
 }
 
+/// Data used to describe an NFT at creation.
 #[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 #[derivative(Debug)]
 pub struct CreateNftData {
+	/// Key-value pairs used to describe the token as metadata
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub properties: CollectionPropertiesVec,
 }
 
+/// Data used to describe a Fungible token at creation.
 #[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct CreateFungibleData {
+	/// Number of fungible coins minted
 	pub value: u128,
 }
 
+/// Data used to describe a Refungible token at creation.
 #[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 #[derivative(Debug)]
 pub struct CreateReFungibleData {
+	/// Immutable metadata of the token
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub const_data: BoundedVec<u8, CustomDataLimit>,
 
+	/// Number of pieces the RFT is split into
 	pub pieces: u128,
 
+	/// Key-value pairs used to describe the token as metadata
 	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	#[derivative(Debug(format_with = "bounded::vec_debug"))]
 	pub properties: CollectionPropertiesVec,
@@ -550,6 +583,7 @@
 	None,
 }
 
+/// Enum holding data used for creation of all three item types.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum CreateItemData {
@@ -558,6 +592,7 @@
 	ReFungible(CreateReFungibleData),
 }
 
+/// Explicit NFT creation data with meta parameters.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
 #[derivative(Debug)]
 pub struct CreateNftExData<CrossAccountId> {
@@ -566,6 +601,7 @@
 	pub owner: CrossAccountId,
 }
 
+/// Explicit RFT creation data with meta parameters.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
 #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
 pub struct CreateRefungibleExData<CrossAccountId> {
@@ -577,6 +613,7 @@
 	pub properties: CollectionPropertiesVec,
 }
 
+/// Explicit item creation data with meta parameters, namely the owner.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
 #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]
 pub enum CreateItemExData<CrossAccountId> {
@@ -624,6 +661,7 @@
 	}
 }
 
+/// Token's address, dictated by its collection and token IDs.
 #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 // todo possibly rename to be used generally as an address pair
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -57,7 +57,7 @@
        **/
       AddressNotInAllowlist: AugmentedError<ApiType>;
       /**
-       * Requested value more than approved.
+       * Requested value is more than the approved
        **/
       ApprovedValueTooLow: AugmentedError<ApiType>;
       /**
@@ -113,7 +113,7 @@
        **/
       EmptyPropertyKey: AugmentedError<ApiType>;
       /**
-       * Only ASCII letters, digits, and '_', '-' are allowed
+       * Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed
        **/
       InvalidCharacterInPropertyKey: AugmentedError<ApiType>;
       /**
@@ -133,7 +133,7 @@
        **/
       NoSpaceForProperty: AugmentedError<ApiType>;
       /**
-       * Not sufficient funds to perform action
+       * Insufficient funds to perform an action
        **/
       NotSufficientFounds: AugmentedError<ApiType>;
       /**
@@ -153,15 +153,15 @@
        **/
       PublicMintingNotAllowed: AugmentedError<ApiType>;
       /**
-       * Only tokens from specific collections may nest tokens under this
+       * Only tokens from specific collections may nest tokens under this one
        **/
       SourceCollectionIsNotAllowedToNest: AugmentedError<ApiType>;
       /**
-       * Item not exists.
+       * Item does not exist
        **/
       TokenNotFound: AugmentedError<ApiType>;
       /**
-       * Item balance not enough.
+       * Item is balance not enough
        **/
       TokenValueTooLow: AugmentedError<ApiType>;
       /**
@@ -173,11 +173,11 @@
        **/
       TransferNotAllowed: AugmentedError<ApiType>;
       /**
-       * Target collection doesn't supports this operation
+       * Target collection doesn't support this operation
        **/
       UnsupportedOperation: AugmentedError<ApiType>;
       /**
-       * User not passed nesting rule
+       * User does not satisfy the nesting rule
        **/
       UserIsNotAllowedToNest: AugmentedError<ApiType>;
       /**
@@ -285,8 +285,7 @@
        **/
       FungibleItemsDontHaveData: AugmentedError<ApiType>;
       /**
-       * Not default id passed as TokenId argument.
-       * The default value of TokenId for Fungible collection is 0.
+       * Fungible tokens hold no ID, and the default value of TokenId for Fungible collection is 0.
        **/
       FungibleItemsHaveNoId: AugmentedError<ApiType>;
       /**
@@ -426,19 +425,19 @@
        **/
       NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
       /**
-       * Refungible token can't nest other tokens
+       * Refungible token can't nest other tokens.
        **/
       RefungibleDisallowsNesting: AugmentedError<ApiType>;
       /**
-       * Refungible token can't be repartitioned by user who isn't owns all pieces
+       * Refungible token can't be repartitioned by user who isn't owns all pieces.
        **/
       RepartitionWhileNotOwningAllPieces: AugmentedError<ApiType>;
       /**
-       * Setting item properties is not allowed
+       * Setting item properties is not allowed.
        **/
       SettingPropertiesNotAllowed: AugmentedError<ApiType>;
       /**
-       * Maximum refungibility exceeded
+       * Maximum refungibility exceeded.
        **/
       WrongRefungiblePieces: AugmentedError<ApiType>;
       /**
@@ -509,19 +508,19 @@
     };
     structure: {
       /**
-       * While iterating over children, encountered breadth limit
+       * While iterating over children, reached the breadth limit.
        **/
       BreadthLimit: AugmentedError<ApiType>;
       /**
-       * While searched for owner, encountered depth limit
+       * While searching for the owner, reached the depth limit.
        **/
       DepthLimit: AugmentedError<ApiType>;
       /**
-       * While searched for owner, got already checked account
+       * While searching for the owner, encountered an already checked account, detecting a loop.
        **/
       OuroborosDetected: AugmentedError<ApiType>;
       /**
-       * While searched for owner, found token owner by not-yet-existing token
+       * Couldn't find the token owner that is itself a token.
        **/
       TokenNotFound: AugmentedError<ApiType>;
       /**
@@ -597,7 +596,7 @@
     };
     unique: {
       /**
-       * Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.
+       * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
        **/
       CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
       /**
@@ -609,7 +608,7 @@
        **/
       EmptyArgument: AugmentedError<ApiType>;
       /**
-       * Repertition is only supported by refungible collection
+       * Repertition is only supported by refungible collection.
        **/
       RepartitionCalledOnNonRefungibleCollection: AugmentedError<ApiType>;
       /**
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -75,7 +75,7 @@
        **/
       CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
-       * The colletion property has been set.
+       * The colletion property has been added or edited.
        **/
       CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
@@ -87,7 +87,7 @@
        **/
       ItemDestroyed: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
       /**
-       * The colletion property permission has been set.
+       * The token property permission of a collection has been set.
        **/
       PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
@@ -95,7 +95,7 @@
        **/
       TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
       /**
-       * The token property has been set.
+       * The token property has been added or edited.
        **/
       TokenPropertySet: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
       /**
@@ -407,7 +407,7 @@
     };
     structure: {
       /**
-       * Executed call on behalf of token
+       * Executed call on behalf of the token.
        **/
       Executed: AugmentedEvent<ApiType, [Result<Null, SpRuntimeDispatchError>]>;
       /**
@@ -499,90 +499,80 @@
     };
     unique: {
       /**
-       * Address was add to allow list
+       * Address was added to the allow list
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * user:  Address.
+       * * collection_id: ID of the affected collection.
+       * * user: Address of the added account.
        **/
       AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Address was remove from allow list
+       * Address was removed from the allow list
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * user:  Address.
+       * * collection_id: ID of the affected collection.
+       * * user: Address of the removed account.
        **/
       AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Collection admin was added
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * admin:  Admin address.
+       * * collection_id: ID of the affected collection.
+       * * admin: Admin address.
        **/
       CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Collection admin was removed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * admin:  Admin address.
+       * * collection_id: ID of the affected collection.
+       * * admin: Removed admin address.
        **/
       CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Collection limits was set
+       * Collection limits were set
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
+       * * collection_id: ID of the affected collection.
        **/
       CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
       /**
-       * Collection owned was change
+       * Collection owned was changed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * owner:  New owner address.
+       * * collection_id: ID of the affected collection.
+       * * owner: New owner address.
        **/
       CollectionOwnedChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
+      /**
+       * Collection permissions were set
+       * 
+       * # Arguments
+       * * collection_id: ID of the affected collection.
+       **/
       CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
       /**
        * Collection sponsor was removed
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
+       * * collection_id: ID of the affected collection.
        **/
       CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
       /**
        * Collection sponsor was set
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * owner:  New sponsor address.
+       * * collection_id: ID of the affected collection.
+       * * owner: New sponsor address.
        **/
       CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
        * New sponsor was confirm
        * 
        * # Arguments
-       * 
-       * * collection_id: Globally unique collection identifier.
-       * 
-       * * sponsor:  New sponsor address.
+       * * collection_id: ID of the affected collection.
+       * * sponsor: New sponsor address.
        **/
       SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -70,11 +70,11 @@
     };
     common: {
       /**
-       * Storage of collection admins count.
+       * Storage of the amount of collection admins.
        **/
       adminAmount: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Allowlisted collection users
+       * Allowlisted collection users.
        **/
       allowlist: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -86,11 +86,11 @@
        **/
       collectionProperties: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Storage of collection properties permissions.
+       * Storage of token property permissions of a collection.
        **/
       collectionPropertyPermissions: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<BTreeMap<Bytes, UpDataStructsPropertyPermission>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Storage of the count of created collections.
+       * Storage of the count of created collections. Essentially contains the last collection ID.
        **/
       createdCollectionCount: AugmentedQuery<ApiType, () => Observable<u32>, []> & QueryableStorageEntry<ApiType, []>;
       /**
@@ -102,7 +102,7 @@
        **/
       dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
       /**
-       * List of collection admins
+       * List of collection admins.
        **/
       isAdmin: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -200,7 +200,7 @@
     };
     fungible: {
       /**
-       * Storage for delegated assets.
+       * Storage for assets delegated to a limited extent to other users.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
@@ -244,11 +244,11 @@
     };
     nonfungible: {
       /**
-       * Amount of tokens owned by account.
+       * Amount of tokens owned by an account in a collection.
        **/
       accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Allowance set by an owner for a spender for a token.
+       * Allowance set by a token owner for another user to perform one of certain transactions on a token.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
@@ -256,7 +256,14 @@
        **/
       owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
       /**
-       * Custom data that is serialized to bytes and attached to a token property.
+       * Custom data of a token that is serialized to bytes,
+       * primarily reserved for on-chain operations,
+       * normally obscured from the external users.
+       * 
+       * Auxiliary properties are slightly different from
+       * usual [`TokenProperties`] due to an unlimited number
+       * and separately stored and written-to key-value pairs.
+       * 
        * Currently used to store RMRK data.
        **/
       tokenAuxProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: UpDataStructsPropertyScope | 'None' | 'Rmrk' | number | Uint8Array, arg4: Bytes | string | Uint8Array) => Observable<Option<Bytes>>, [u32, u32, UpDataStructsPropertyScope, Bytes]> & QueryableStorageEntry<ApiType, [u32, u32, UpDataStructsPropertyScope, Bytes]>;
@@ -265,19 +272,19 @@
        **/
       tokenChildren: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array]) => Observable<bool>, [u32, u32, ITuple<[u32, u32]>]> & QueryableStorageEntry<ApiType, [u32, u32, ITuple<[u32, u32]>]>;
       /**
-       * Custom data serialized to bytes for token.
+       * Token data, used to partially describe a token.
        **/
       tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<PalletNonfungibleItemData>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
-       * Key-Value map stored for token.
+       * Map of key-value pairs, describing the metadata of a token.
        **/
       tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
-       * Amount of burnt tokens for collection.
+       * Amount of burnt tokens in a collection.
        **/
       tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Amount of tokens minted for collection.
+       * Total amount of minted tokens in a collection.
        **/
       tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
@@ -444,32 +451,35 @@
     };
     refungible: {
       /**
-       * Amount of tokens owned by account
+       * Amount of tokens (not pieces) partially owned by an account within a collection.
        **/
       accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Allowance set by an owner for a spender for a token
+       * Allowance set by a token owner for another user to perform one of certain transactions on a number of pieces of a token.
        **/
       allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Amount of token pieces owned by account
+       * Amount of token pieces owned by account.
        **/
       balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Used to enumerate tokens owned by account
+       * Used to enumerate tokens owned by account.
        **/
       owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;
       /**
-       * Custom data serialized to bytes for token
+       * Token data, used to partially describe a token.
        **/
       tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+      /**
+       * Amount of pieces a refungible token is split into.
+       **/
       tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
-       * Amount of burnt tokens for collection
+       * Amount of tokens burnt in a collection.
        **/
       tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Amount of tokens minted for collection
+       * Total amount of minted tokens in a collection.
        **/
       tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
@@ -663,24 +673,33 @@
        * TODO: Off chain worker should remove from this map when collection gets removed
        **/
       createItemBasket: AugmentedQuery<ApiType, (arg: ITuple<[u32, AccountId32]> | [u32 | AnyNumber | Uint8Array, AccountId32 | string | Uint8Array]) => Observable<Option<u32>>, [ITuple<[u32, AccountId32]>]> & QueryableStorageEntry<ApiType, [ITuple<[u32, AccountId32]>]>;
+      /**
+       * Last sponsoring of fungible tokens approval in a collection
+       **/
       fungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
       /**
        * Collection id (controlled?2), owning user (real)
        **/
       fungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, AccountId32]>;
       /**
-       * Approval sponsoring
+       * Last sponsoring of NFT approval in a collection
        **/
       nftApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
        * Collection id (controlled?2), token id (controlled?2)
        **/
       nftTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
+      /**
+       * Last sponsoring of RFT approval in a collection
+       **/
       refungibleApproveBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
       /**
        * Collection id (controlled?2), token id (controlled?2)
        **/
       reFungibleTransferBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: AccountId32 | string | Uint8Array) => Observable<Option<u32>>, [u32, u32, AccountId32]> & QueryableStorageEntry<ApiType, [u32, u32, AccountId32]>;
+      /**
+       * Last sponsoring of token property setting // todo:doc rephrase this and the following
+       **/
       tokenPropertyBasket: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<Option<u32>>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;
       /**
        * Variable metadata sponsoring
modifiedtests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -629,47 +629,47 @@
     };
     unique: {
       /**
-       * Get amount of different user tokens
+       * Get the amount of any user tokens owned by an account
        **/
       accountBalance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
       /**
-       * Get tokens owned by account
+       * Get tokens owned by an account in a collection
        **/
       accountTokens: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
       /**
-       * Get admin list
+       * Get the list of admin accounts of a collection
        **/
       adminlist: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
-       * Get allowed amount
+       * Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor
        **/
       allowance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, sender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
       /**
-       * Check if user is allowed to use collection
+       * Check if a user is allowed to operate within a collection
        **/
       allowed: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable<bool>>;
       /**
-       * Get allowlist
+       * Get the list of accounts allowed to operate within a collection
        **/
       allowlist: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
-       * Get amount of specific account token
+       * Get the amount of a specific token owned by an account
        **/
       balance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u128>>;
       /**
-       * Get collection by specified id
+       * Get a collection by the specified ID
        **/
       collectionById: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsRpcCollection>>>;
       /**
-       * Get collection properties
+       * Get collection properties, optionally limited to the provided keys
        **/
       collectionProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
       /**
-       * Get collection stats
+       * Get chain stats about collections
        **/
       collectionStats: AugmentedRpc<(at?: Hash | string | Uint8Array) => Observable<UpDataStructsCollectionStats>>;
       /**
-       * Get tokens contained in collection
+       * Get tokens contained within a collection
        **/
       collectionTokens: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<u32>>>;
       /**
@@ -681,15 +681,15 @@
        **/
       effectiveCollectionLimits: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<UpDataStructsCollectionLimits>>>;
       /**
-       * Get last token id
+       * Get the last token ID created in a collection
        **/
       lastTokenId: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
       /**
-       * Get number of blocks when sponsored transaction is available
+       * Get the number of blocks until sponsoring a transaction is available
        **/
       nextSponsored: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<u64>>>;
       /**
-       * Get property permissions
+       * Get property permissions, optionally limited to the provided keys
        **/
       propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
       /**
@@ -697,15 +697,15 @@
        **/
       tokenChildren: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsTokenChild>>>;
       /**
-       * Get token data
+       * Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT
        **/
       tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
       /**
-       * Check if token exists
+       * Check if the token exists
        **/
       tokenExists: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<bool>>;
       /**
-       * Get token owner
+       * Get the token owner
        **/
       tokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
@@ -713,19 +713,19 @@
        **/
       tokenOwners: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
-       * Get token properties
+       * Get token properties, optionally limited to the provided keys
        **/
       tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
       /**
-       * Get token owner, in case of nested token - find parent recursive
+       * Get the topmost token owner in the hierarchy of a possibly nested token
        **/
       topmostTokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
-       * Get total pieces of token
+       * Get the total amount of pieces of an RFT
        **/
       totalPieces: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<u128>>>;
       /**
-       * Get amount of unique collection tokens
+       * Get the amount of distinctive tokens present in a collection
        **/
       totalSupply: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<u32>>;
       /**
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -730,87 +730,99 @@
     };
     unique: {
       /**
-       * 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.
+       * Add an admin to a 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.
+       * * `collection_id`: ID of the Collection to add an admin for.
+       * * `new_admin`: Address of new admin to add.
        **/
-      addCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newAdminId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      addCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newAdmin: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
        * Add an address to allow list.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * 
-       * * address.
+       * * `collection_id`: ID of the modified collection.
+       * * `address`: ID of the address to be added to the allowlist.
        **/
       addToAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Set, change, or remove approved address to transfer the ownership of the NFT.
+       * Allow a non-permissioned address to transfer or burn an item.
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT owner
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
        * 
        * # Arguments
-       * 
-       * * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).
        * 
-       * * collection_id.
-       * 
-       * * item_id: ID of the item.
+       * * `spender`: Account to be approved to make specific transactions on non-owned tokens.
+       * * `collection_id`: ID of the collection the item belongs to.
+       * * `item_id`: ID of the item transactions on which are now approved.
+       * * `amount`: Number of pieces of the item approved for a transaction (maximum of 1 for NFTs).
+       * Set to 0 to revoke the approval.
        **/
       approve: AugmentedSubmittable<(spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
-       * Destroys a concrete instance of NFT on behalf of the owner
-       * See also: [`approve`]
+       * Destroy a token on behalf of the owner as a non-owner account.
+       * 
+       * See also: [`approve`][`Pallet::approve`].
+       * 
+       * After this method executes, one approval is removed from the total so that
+       * the approved address will not be able to transfer this item again from this owner.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
-       * * Collection Admin.
-       * * Current NFT Owner.
+       * * Collection owner
+       * * Collection admin
+       * * Current token owner
+       * * Address approved by current item owner
        * 
        * # Arguments
        * 
-       * * collection_id: ID of the collection.
-       * 
-       * * item_id: ID of NFT to burn.
-       * 
-       * * from: owner of item
+       * * `from`: The owner of the burning item.
+       * * `collection_id`: ID of the collection to which the item belongs.
+       * * `item_id`: ID of item to burn.
+       * * `value`: Number of pieces to burn.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to burn.
+       * * Re-Fungible Mode: The desired number of pieces to burn.
        **/
       burnFrom: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32, u128]>;
       /**
-       * Destroys a concrete instance of NFT.
+       * Destroy an item.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
-       * * Collection Admin.
-       * * Current NFT Owner.
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
        * 
        * # Arguments
        * 
-       * * collection_id: ID of the collection.
-       * 
-       * * item_id: ID of NFT to burn.
+       * * `collection_id`: ID of the collection to which the item belongs.
+       * * `item_id`: ID of item to burn.
+       * * `value`: Number of pieces of the item to destroy.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to burn.
+       * * Re-Fungible Mode: The desired number of pieces to burn.
        **/
       burnItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
       /**
@@ -818,131 +830,200 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner.
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id.
-       * 
-       * * new_owner.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_owner`: ID of the account that will become the owner.
        **/
       changeCollectionOwner: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newOwner: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
       /**
+       * Confirm own sponsorship of a collection, becoming the sponsor.
+       * 
+       * An invitation must be pending, see [`set_collection_sponsor`][`Pallet::set_collection_sponsor`].
+       * Sponsor can pay the fees of a transaction instead of the sender,
+       * but only within specified limits.
+       * 
        * # Permissions
        * 
-       * * Sponsor.
+       * * Sponsor-to-be
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the collection with the pending sponsor.
        **/
       confirmSponsorship: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
-       * This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.
+       * Create a collection of tokens.
+       * 
+       * Each Token may have multiple properties encoded as an array of bytes
+       * of certain length. The initial owner of the collection is set
+       * to the address that signed the transaction and can be changed later.
+       * 
+       * Prefer the more advanced [`create_collection_ex`][`Pallet::create_collection_ex`] instead.
        * 
        * # Permissions
        * 
-       * * Anyone.
+       * * Anyone - becomes the owner of the new collection.
        * 
        * # Arguments
        * 
-       * * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.
+       * * `collection_name`: Wide-character string with collection name
+       * (limit [`MAX_COLLECTION_NAME_LENGTH`]).
+       * * `collection_description`: Wide-character string with collection description
+       * (limit [`MAX_COLLECTION_DESCRIPTION_LENGTH`]).
+       * * `token_prefix`: Byte string containing the token prefix to mark a collection
+       * to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).
+       * * `mode`: Type of items stored in the collection and type dependent data.
+       **/
+      createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
+      /**
+       * Create a collection with explicit parameters.
        * 
-       * * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.
+       * Prefer it to the deprecated [`create_collection`][`Pallet::create_collection`] method.
+       * 
+       * # Permissions
        * 
-       * * token_prefix: UTF-8 string with token prefix.
+       * * Anyone - becomes the owner of the new collection.
        * 
-       * * mode: [CollectionMode] collection type and type dependent data.
-       **/
-      createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
-      /**
-       * This method creates a collection
+       * # Arguments
        * 
-       * Prefer it to deprecated [`created_collection`] method
+       * * `data`: Explicit data of a collection used for its creation.
        **/
       createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; pendingSponsor?: any; limits?: any; permissions?: any; tokenPropertyPermissions?: any; properties?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
       /**
-       * This method creates a concrete instance of NFT Collection created with CreateCollection method.
+       * Mint an item within a collection.
        * 
+       * A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
+       * 
        * # Permissions
        * 
-       * * Collection Owner.
-       * * Collection Admin.
+       * * Collection owner
+       * * Collection admin
        * * Anyone if
        * * Allow List is enabled, and
        * * Address is added to allow list, and
-       * * MintPermission is enabled (see SetMintPermission method)
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
        * # Arguments
        * 
-       * * collection_id: ID of the collection.
+       * * `collection_id`: ID of the collection to which an item would belong.
+       * * `owner`: Address of the initial owner of the item.
+       * * `data`: Token data describing the item to store on chain.
+       **/
+      createItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, data: UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCreateItemData]>;
+      /**
+       * Create multiple items within a collection.
        * 
-       * * owner: Address, initial owner of the NFT.
+       * A collection must exist first, see [`create_collection_ex`][`Pallet::create_collection_ex`].
+       * 
+       * # Permissions
+       * 
+       * * Collection owner
+       * * Collection admin
+       * * Anyone if
+       * * Allow List is enabled, and
+       * * Address is added to the allow list, and
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
-       * * data: Token data to store on chain.
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection to which the tokens would belong.
+       * * `owner`: Address of the initial owner of the tokens.
+       * * `items_data`: Vector of data describing each item to be created.
        **/
-      createItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, data: UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCreateItemData]>;
+      createMultipleItems: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemsData: Vec<UpDataStructsCreateItemData> | (UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, Vec<UpDataStructsCreateItemData>]>;
       /**
-       * This method creates multiple items in a collection created with CreateCollection method.
+       * Create multiple items within a collection with explicitly specified initial parameters.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
-       * * Collection Admin.
+       * * Collection owner
+       * * Collection admin
        * * Anyone if
        * * Allow List is enabled, and
        * * Address is added to allow list, and
-       * * MintPermission is enabled (see SetMintPermission method)
+       * * MintPermission is enabled (see [`set_collection_permissions`][`Pallet::set_collection_permissions`])
        * 
        * # Arguments
        * 
-       * * collection_id: ID of the collection.
+       * * `collection_id`: ID of the collection to which the tokens would belong.
+       * * `data`: Explicit item creation data.
+       **/
+      createMultipleItemsEx: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, data: UpDataStructsCreateItemExData | { NFT: any } | { Fungible: any } | { RefungibleMultipleItems: any } | { RefungibleMultipleOwners: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCreateItemExData]>;
+      /**
+       * Delete specified collection properties.
        * 
-       * * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].
+       * # Permissions
+       * 
+       * * Collection Owner
+       * * Collection Admin
+       * 
+       * # Arguments
        * 
-       * * owner: Address, initial owner of the NFT.
+       * * `collection_id`: ID of the modified collection.
+       * * `property_keys`: Vector of keys of the properties to be deleted.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
-      createMultipleItems: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, itemsData: Vec<UpDataStructsCreateItemData> | (UpDataStructsCreateItemData | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, Vec<UpDataStructsCreateItemData>]>;
-      createMultipleItemsEx: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, data: UpDataStructsCreateItemExData | { NFT: any } | { Fungible: any } | { RefungibleMultipleItems: any } | { RefungibleMultipleOwners: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCreateItemExData]>;
       deleteCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<Bytes>]>;
+      /**
+       * Delete specified token properties. Currently properties only work with NFTs.
+       * 
+       * # Permissions
+       * 
+       * * Depends on collection's token property permissions and specified property mutability:
+       * * Collection owner
+       * * Collection admin
+       * * Token owner
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection to which the token belongs.
+       * * `token_id`: ID of the modified token.
+       * * `property_keys`: Vector of keys of the properties to be deleted.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       **/
       deleteTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<Bytes>]>;
       /**
-       * Destroys collection if no tokens within this collection
+       * Destroy a collection if no tokens exist within.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id: collection to destroy.
+       * * `collection_id`: Collection to destroy.
        **/
       destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
-       * 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.
+       * Remove admin of a 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
        * 
-       * * collection_id: ID of the Collection to remove admin for.
-       * 
-       * * account_id: Address of admin to remove.
+       * * `collection_id`: ID of the collection to remove the admin for.
+       * * `account_id`: Address of the admin to remove.
        **/
       removeCollectionAdmin: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, accountId: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
       /**
-       * Switch back to pay-per-own-transaction model.
+       * Remove a collection's a sponsor, making everyone pay for their own transactions.
        * 
        * # Permissions
        * 
-       * * Collection owner.
+       * * Collection owner
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the collection with the sponsor to remove.
        **/
       removeCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32]>;
       /**
@@ -950,46 +1031,140 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the modified collection.
+       * * `address`: ID of the address to be removed from the allowlist.
+       **/
+      removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      /**
+       * Re-partition a refungible token, while owning all of its parts/pieces.
+       * 
+       * # Permissions
+       * 
+       * * Token owner (must own every part)
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection the RFT belongs to.
+       * * `token_id`: ID of the RFT.
+       * * `amount`: New number of parts/pieces into which the token shall be partitioned.
+       **/
+      repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
+      /**
+       * Set specific limits of a collection. Empty, or None fields mean chain default.
+       * 
+       * # Permissions
        * 
-       * * address.
+       * * Collection owner
+       * * Collection admin
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the modified collection.
+       * * `new_limit`: New limits of the collection. Fields that are not set (None)
+       * will not overwrite the old ones.
        **/
-      removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, token: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32, u128]>;
       setCollectionLimits: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newLimit: UpDataStructsCollectionLimits | { accountTokenOwnershipLimit?: any; sponsoredDataSize?: any; sponsoredDataRateLimit?: any; tokenLimit?: any; sponsorTransferTimeout?: any; sponsorApproveTimeout?: any; ownerCanTransfer?: any; ownerCanDestroy?: any; transfersEnabled?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionLimits]>;
-      setCollectionPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newLimit: UpDataStructsCollectionPermissions | { access?: any; mintMode?: any; nesting?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionPermissions]>;
-      setCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsProperty>]>;
       /**
+       * Set specific permissions of a collection. Empty, or None fields mean chain default.
+       * 
        * # Permissions
        * 
-       * * Collection Owner
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id.
+       * * `collection_id`: ID of the modified collection.
+       * * `new_permission`: New permissions of the collection. Fields that are not set (None)
+       * will not overwrite the old ones.
+       **/
+      setCollectionPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newPermission: UpDataStructsCollectionPermissions | { access?: any; mintMode?: any; nesting?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, UpDataStructsCollectionPermissions]>;
+      /**
+       * Add or change collection properties.
+       * 
+       * # Permissions
+       * 
+       * * Collection owner
+       * * Collection admin
        * 
-       * * new_sponsor.
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the modified collection.
+       * * `properties`: Vector of key-value pairs stored as the collection's metadata.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
        **/
+      setCollectionProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsProperty>]>;
+      /**
+       * Set (invite) a new collection sponsor.
+       * 
+       * If successful, confirmation from the sponsor-to-be will be pending.
+       * 
+       * # Permissions
+       * 
+       * * Collection owner
+       * * Collection admin
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the modified collection.
+       * * `new_sponsor`: ID of the account of the sponsor-to-be.
+       **/
       setCollectionSponsor: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newSponsor: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, AccountId32]>;
+      /**
+       * Add or change token properties according to collection's permissions.
+       * Currently properties only work with NFTs.
+       * 
+       * # Permissions
+       * 
+       * * Depends on collection's token property permissions and specified property mutability:
+       * * Collection owner
+       * * Collection admin
+       * * Token owner
+       * 
+       * See [`set_token_property_permissions`][`Pallet::set_token_property_permissions`].
+       * 
+       * # Arguments
+       * 
+       * * `collection_id: ID of the collection to which the token belongs.
+       * * `token_id`: ID of the modified token.
+       * * `properties`: Vector of key-value pairs stored as the token's metadata.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       **/
       setTokenProperties: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, properties: Vec<UpDataStructsProperty> | (UpDataStructsProperty | { key?: any; value?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, u32, Vec<UpDataStructsProperty>]>;
-      setTokenPropertyPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyPermissions: Vec<UpDataStructsPropertyKeyPermission> | (UpDataStructsPropertyKeyPermission | { key?: any; permission?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsPropertyKeyPermission>]>;
       /**
-       * Set transfers_enabled value for particular collection
+       * Add or change token property permissions of a collection.
+       * 
+       * Without a permission for a particular key, a property with that key
+       * cannot be created in a token.
        * 
        * # Permissions
        * 
-       * * Collection Owner.
+       * * Collection owner
+       * * Collection admin
        * 
        * # Arguments
        * 
-       * * collection_id: ID of the collection.
+       * * `collection_id`: ID of the modified collection.
+       * * `property_permissions`: Vector of permissions for property keys.
+       * Keys support Latin letters, `-`, `_`, and `.` as symbols.
+       **/
+      setTokenPropertyPermissions: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, propertyPermissions: Vec<UpDataStructsPropertyKeyPermission> | (UpDataStructsPropertyKeyPermission | { key?: any; permission?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [u32, Vec<UpDataStructsPropertyKeyPermission>]>;
+      /**
+       * Completely allow or disallow transfers for a particular collection.
        * 
-       * * value: New flag value.
+       * # Permissions
+       * 
+       * * Collection owner
+       * 
+       * # Arguments
+       * 
+       * * `collection_id`: ID of the collection.
+       * * `value`: New value of the flag, are transfers allowed?
        **/
       setTransfersEnabledFlag: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, value: bool | boolean | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, bool]>;
       /**
@@ -997,47 +1172,50 @@
        * 
        * # Permissions
        * 
-       * * Collection Owner
-       * * Collection Admin
-       * * Current NFT owner
+       * * Collection owner
+       * * Collection admin
+       * * Current token owner
        * 
        * # Arguments
        * 
-       * * recipient: Address of token recipient.
-       * 
-       * * collection_id.
-       * 
-       * * item_id: ID of the item
+       * * `recipient`: Address of token recipient.
+       * * `collection_id`: ID of the collection the item belongs to.
+       * * `item_id`: ID of the item.
        * * Non-Fungible Mode: Required.
        * * Fungible Mode: Ignored.
        * * Re-Fungible Mode: Required.
        * 
-       * * value: Amount to transfer.
-       * * Non-Fungible Mode: Ignored
-       * * Fungible Mode: Must specify transferred amount
-       * * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)
+       * * `value`: Amount to transfer.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to transfer.
+       * * Re-Fungible Mode: The desired number of pieces to transfer.
        **/
       transfer: AugmentedSubmittable<(recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
-       * 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
-       * * Address approved by current NFT owner
+       * Change ownership of an item on behalf of the owner as a non-owner account.
        * 
-       * # Arguments
+       * See the [`approve`][`Pallet::approve`] method for additional information.
        * 
-       * * from: Address that owns token.
+       * After this method executes, one approval is removed from the total so that
+       * the approved address will not be able to transfer this item again from this owner.
        * 
-       * * recipient: Address of token recipient.
+       * # Permissions
        * 
-       * * collection_id.
+       * * Collection owner
+       * * Collection admin
+       * * Current item owner
+       * * Address approved by current item owner
        * 
-       * * item_id: ID of the item.
+       * # Arguments
        * 
-       * * value: Amount to transfer.
+       * * `from`: Address that currently owns the token.
+       * * `recipient`: Address of the new token-owner-to-be.
+       * * `collection_id`: ID of the collection the item.
+       * * `item_id`: ID of the item to be transferred.
+       * * `value`: Amount to transfer.
+       * * Non-Fungible Mode: An NFT is indivisible, there is always 1 corresponding to an ID.
+       * * Fungible Mode: The desired number of pieces to transfer.
+       * * Re-Fungible Mode: The desired number of pieces to transfer.
        **/
       transferFrom: AugmentedSubmittable<(from: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, recipient: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array, value: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u32, u32, u128]>;
       /**
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1672,7 +1672,7 @@
   readonly isAddCollectionAdmin: boolean;
   readonly asAddCollectionAdmin: {
     readonly collectionId: u32;
-    readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
+    readonly newAdmin: PalletEvmAccountBasicCrossAccountIdRepr;
   } & Struct;
   readonly isRemoveCollectionAdmin: boolean;
   readonly asRemoveCollectionAdmin: {
@@ -1784,12 +1784,12 @@
   readonly isSetCollectionPermissions: boolean;
   readonly asSetCollectionPermissions: {
     readonly collectionId: u32;
-    readonly newLimit: UpDataStructsCollectionPermissions;
+    readonly newPermission: UpDataStructsCollectionPermissions;
   } & Struct;
   readonly isRepartition: boolean;
   readonly asRepartition: {
     readonly collectionId: u32;
-    readonly token: u32;
+    readonly tokenId: u32;
     readonly amount: u128;
   } & Struct;
   readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1269,7 +1269,7 @@
       },
       add_collection_admin: {
         collectionId: 'u32',
-        newAdminId: 'PalletEvmAccountBasicCrossAccountIdRepr',
+        newAdmin: 'PalletEvmAccountBasicCrossAccountIdRepr',
       },
       remove_collection_admin: {
         collectionId: 'u32',
@@ -1361,11 +1361,11 @@
       },
       set_collection_permissions: {
         collectionId: 'u32',
-        newLimit: 'UpDataStructsCollectionPermissions',
+        newPermission: 'UpDataStructsCollectionPermissions',
       },
       repartition: {
         collectionId: 'u32',
-        token: 'u32',
+        tokenId: 'u32',
         amount: 'u128'
       }
     }
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1385,7 +1385,7 @@
     readonly isAddCollectionAdmin: boolean;
     readonly asAddCollectionAdmin: {
       readonly collectionId: u32;
-      readonly newAdminId: PalletEvmAccountBasicCrossAccountIdRepr;
+      readonly newAdmin: PalletEvmAccountBasicCrossAccountIdRepr;
     } & Struct;
     readonly isRemoveCollectionAdmin: boolean;
     readonly asRemoveCollectionAdmin: {
@@ -1497,12 +1497,12 @@
     readonly isSetCollectionPermissions: boolean;
     readonly asSetCollectionPermissions: {
       readonly collectionId: u32;
-      readonly newLimit: UpDataStructsCollectionPermissions;
+      readonly newPermission: UpDataStructsCollectionPermissions;
     } & Struct;
     readonly isRepartition: boolean;
     readonly asRepartition: {
       readonly collectionId: u32;
-      readonly token: u32;
+      readonly tokenId: u32;
       readonly amount: u128;
     } & Struct;
     readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -37,49 +37,143 @@
 export default {
   types: {},
   rpc: {
-    adminlist: fun('Get admin list', [collectionParam], 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>'),
-    allowlist: fun('Get allowlist', [collectionParam], 'Vec<PalletEvmAccountBasicCrossAccountIdRepr>'),
+    accountTokens: fun(
+      'Get tokens owned by an account in a collection', 
+      [collectionParam, crossAccountParam()], 
+      'Vec<u32>',
+    ),
+    collectionTokens: fun(
+      'Get tokens contained within a collection', 
+      [collectionParam], 
+      'Vec<u32>',
+    ),
+    tokenExists: fun(
+      'Check if the token exists', 
+      [collectionParam, tokenParam], 
+      'bool',
+    ),
 
-    accountTokens: fun('Get tokens owned by account', [collectionParam, crossAccountParam()], 'Vec<u32>'),
-    collectionTokens: fun('Get tokens contained in collection', [collectionParam], 'Vec<u32>'),
+    tokenOwner: fun(
+      'Get the token owner', 
+      [collectionParam, tokenParam], 
+      `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
+    ),
+    topmostTokenOwner: fun(
+      'Get the topmost token owner in the hierarchy of a possibly nested token', 
+      [collectionParam, tokenParam], 
+      `Option<${CROSS_ACCOUNT_ID_TYPE}>`,
+    ),
+    tokenOwners: fun(
+      'Returns 10 tokens owners in no particular order', 
+      [collectionParam, tokenParam], 
+      `Vec<${CROSS_ACCOUNT_ID_TYPE}>`,
+    ),
+    tokenChildren: fun(
+      'Get tokens nested directly into the token', 
+      [collectionParam, tokenParam], 
+      'Vec<UpDataStructsTokenChild>',
+    ),
 
-    lastTokenId: fun('Get last token id', [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'),
-    allowance: fun('Get allowed amount', [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 'u128'),
-    tokenOwner: fun('Get token owner', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
-    tokenOwners: fun('Returns 10 tokens owners in no particular order', [collectionParam, tokenParam], `Vec<${CROSS_ACCOUNT_ID_TYPE}>`),
-    topmostTokenOwner: fun('Get token owner, in case of nested token - find parent recursive', [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>'),
     collectionProperties: fun(
-      'Get collection properties',
+      'Get collection properties, optionally limited to the provided keys',
       [collectionParam, propertyKeysParam],
       'Vec<UpDataStructsProperty>',
     ),
     tokenProperties: fun(
-      'Get token properties',
+      'Get token properties, optionally limited to the provided keys',
       [collectionParam, tokenParam, propertyKeysParam],
       'Vec<UpDataStructsProperty>',
     ),
     propertyPermissions: fun(
-      'Get property permissions',
+      'Get property permissions, optionally limited to the provided keys',
       [collectionParam, propertyKeysParam],
       'Vec<UpDataStructsPropertyKeyPermission>',
     ),
+
+    constMetadata: fun(
+      'Get token constant metadata', 
+      [collectionParam, tokenParam], 
+      'Vec<u8>',
+    ),
+    variableMetadata: fun(
+      'Get token variable metadata', 
+      [collectionParam, tokenParam], 
+      'Vec<u8>',
+    ),
+
     tokenData: fun(
-      'Get token data',
+      'Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT',
       [collectionParam, tokenParam, propertyKeysParam],
       'UpDataStructsTokenData',
     ),
-    tokenExists: fun('Check if token exists', [collectionParam, tokenParam], 'bool'),
-    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>'),
-    effectiveCollectionLimits: fun('Get effective collection limits', [collectionParam], 'Option<UpDataStructsCollectionLimits>'),
-    totalPieces: fun('Get total pieces of token', [collectionParam, tokenParam], 'Option<u128>'),
+    totalSupply: fun(
+      'Get the amount of distinctive tokens present in a collection', 
+      [collectionParam], 
+      'u32',
+    ),
+
+    accountBalance: fun(
+      'Get the amount of any user tokens owned by an account', 
+      [collectionParam, crossAccountParam()], 
+      'u32',
+    ),
+    balance: fun(
+      'Get the amount of a specific token owned by an account', 
+      [collectionParam, crossAccountParam(), tokenParam], 
+      'u128',
+    ),
+    allowance: fun(
+      'Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor', 
+      [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 
+      'u128',
+    ),
+
+    adminlist: fun(
+      'Get the list of admin accounts of a collection', 
+      [collectionParam], 
+      'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
+    ),
+    allowlist: fun(
+      'Get the list of accounts allowed to operate within a collection', 
+      [collectionParam], 
+      'Vec<PalletEvmAccountBasicCrossAccountIdRepr>',
+    ),
+    allowed: fun(
+      'Check if a user is allowed to operate within a collection', 
+      [collectionParam, crossAccountParam()], 
+      'bool',
+    ),
+
+    lastTokenId: fun(
+      'Get the last token ID created in a collection', 
+      [collectionParam], 
+      'u32',
+    ),
+    collectionById: fun(
+      'Get a collection by the specified ID', 
+      [collectionParam], 
+      'Option<UpDataStructsRpcCollection>',
+    ),
+    collectionStats: fun(
+      'Get chain stats about collections', 
+      [], 
+      'UpDataStructsCollectionStats',
+    ),
+
+    nextSponsored: fun(
+      'Get the number of blocks until sponsoring a transaction is available', 
+      [collectionParam, crossAccountParam(), tokenParam], 
+      'Option<u64>',
+    ),
+    effectiveCollectionLimits: fun(
+      'Get effective collection limits', 
+      [collectionParam], 
+      'Option<UpDataStructsCollectionLimits>',
+    ),
+    totalPieces: fun(
+      'Get the total amount of pieces of an RFT', 
+      [collectionParam, tokenParam], 
+      'Option<u128>',
+    ),
   },
 };