git.delta.rocks / unique-network / refs/commits / 1a56db748b0a

difftreelog

doc: architectural changes

Farhad Hakimov2022-07-11parent: #12c8c8f.patch.diff
in: master

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