git.delta.rocks / unique-network / refs/commits / 263bc691fe1a

difftreelog

docs(pallet_common) Add general documentation.

Trubnikov Sergey2022-07-15parent: #12c8c8f.patch.diff
in: master

4 files changed

modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -1,3 +1,5 @@
+//! Module with interfaces for dispatching collections.
+
 use frame_support::{
 	dispatch::{
 		DispatchResultWithPostInfo, PostDispatchInfo, Weight, DispatchErrorWithPostInfo,
@@ -20,7 +22,10 @@
 	// submit_logs is measured as part of collection pallets
 }
 
-/// Helper function to implement substrate calls for common collection methods
+/// Helper function to implement substrate calls for common collection methods.
+/// 
+/// * `collection` - The collection on which to call the method.
+/// * `call` - The function in which to call the corresponding method from [CommonCollectionOperations].
 pub fn dispatch_tx<
 	T: Config,
 	C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,
@@ -64,15 +69,31 @@
 	result
 }
 
+/// Interface for working with different collections through the dispatcher.
 pub trait CollectionDispatch<T: Config> {
+	/// Create a collection. The collection will be created according to the value of [data.mode](CreateCollectionData::mode).
+	/// 
+	/// * `sender` - The user who will become the owner of the collection.
+	/// * `data` - Description of the created collection.
 	fn create(
 		sender: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> DispatchResult;
+
+	/// Delete the collection.
+	/// 
+	/// * `sender` - The owner of the collection.
+	/// * `handle` - Collection handle.
 	fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;
 
+	/// Get a specialized collection from the handle.
+	/// 
+	/// * `handle` - Collection handle.
 	fn dispatch(handle: CollectionHandle<T>) -> Self;
+
+	/// Get the collection handle for the corresponding implementation.
 	fn into_inner(self) -> CollectionHandle<T>;
 
+	/// Получить реализацию [CommonCollectionOperations].
 	fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;
 }
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! This module contains the implementation of pallet methods for evm.
+
 use evm_coder::{
 	solidity_interface, solidity, ToLog,
 	types::*,
@@ -29,29 +31,39 @@
 
 use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
 
+/// Events for etherium collection helper.
 #[derive(ToLog)]
 pub enum CollectionHelpersEvents {
+	/// The collection has been created.
 	CollectionCreated {
+		/// Collection owner.
 		#[indexed]
 		owner: address,
+
+		/// Collection ID.
 		#[indexed]
 		collection_id: address,
 	},
 }
 
 /// Does not always represent a full collection, for RFT it is either
-/// collection (Implementing ERC721), or specific collection token (Implementing ERC20)
+/// collection (Implementing ERC721), or specific collection token (Implementing ERC20).
 pub trait CommonEvmHandler {
 	const CODE: &'static [u8];
 
 	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;
 }
 
+/// @title A contract that allows you to work with collections.
 #[solidity_interface(name = "Collection")]
 impl<T: Config> CollectionHandle<T>
 where
 	T::AccountId: From<[u8; 32]>,
 {
+	/// Set collection property.
+	/// 
+	/// @param key Property key.
+	/// @param value Propery value.
 	fn set_collection_property(
 		&mut self,
 		caller: caller,
@@ -60,14 +72,17 @@
 	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let key = <Vec<u8>>::from(key)
-			.try_into()
-			.map_err(|_| "key too large")?;
+		.try_into()
+		.map_err(|_| "key too large")?;
 		let value = value.try_into().map_err(|_| "value too large")?;
-
+		
 		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })
-			.map_err(dispatch_to_evm::<T>)
+		.map_err(dispatch_to_evm::<T>)
 	}
-
+	
+	/// Delete collection property.
+	/// 
+	/// @param key Property key.
 	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let key = <Vec<u8>>::from(key)
@@ -77,7 +92,12 @@
 		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)
 	}
 
-	/// Throws error if key not found
+	/// Get collection property.
+	/// 
+	/// @dev Throws error if key not found.
+	/// 
+	/// @param key Property key.
+	/// @return bytes The property corresponding to the key.
 	fn collection_property(&self, key: string) -> Result<bytes> {
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -89,6 +109,11 @@
 		Ok(prop.to_vec())
 	}
 
+	/// Set the sponsor of the collection.
+	/// 
+	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	/// 
+	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
 	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 
@@ -98,6 +123,9 @@
 		save(self)
 	}
 
+	/// Collection sponsorship confirmation.
+	/// 
+	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
 	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		if !self
@@ -109,6 +137,16 @@
 		save(self)
 	}
 
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Name of the limit. Valid names:
+	/// 	"accountTokenOwnershipLimit",
+	/// 	"sponsoredDataSize",
+	/// 	"sponsoredDataRateLimit",
+	/// 	"tokenLimit",
+	/// 	"sponsorTransferTimeout",
+	/// 	"sponsorApproveTimeout"
+	/// @param value Value of the limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
 	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -145,6 +183,13 @@
 		save(self)
 	}
 
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Name of the limit. Valid names:
+	/// 	"ownerCanTransfer",
+	/// 	"ownerCanDestroy",
+	/// 	"transfersEnabled"
+	/// @param value Value of the limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
 	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -172,10 +217,13 @@
 		save(self)
 	}
 
+	/// Get contract address.
 	fn contract_address(&self, _caller: caller) -> Result<address> {
 		Ok(crate::eth::collection_id_to_address(self.id))
 	}
 
+	/// Add collection admin by substrate address.
+	/// @param new_admin Substrate administrator address.
 	fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let mut new_admin_arr: [u8; 32] = Default::default();
@@ -186,21 +234,25 @@
 		Ok(())
 	}
 
+	/// Remove collection admin by substrate address.
+	/// @param admin Substrate administrator address.
 	fn remove_collection_admin_substrate(
 		&self,
 		caller: caller,
-		new_admin: uint256,
+		admin: uint256,
 	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		let mut new_admin_arr: [u8; 32] = Default::default();
-		new_admin.to_big_endian(&mut new_admin_arr);
-		let account_id = T::AccountId::from(new_admin_arr);
-		let new_admin = T::CrossAccountId::from_sub(account_id);
-		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)
+		let mut admin_arr: [u8; 32] = Default::default();
+		admin.to_big_endian(&mut admin_arr);
+		let account_id = T::AccountId::from(admin_arr);
+		let admin = T::CrossAccountId::from_sub(account_id);
+		<Pallet<T>>::toggle_admin(self, &caller, &admin, false)
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
+	/// Add collection admin.
+	/// @param new_admin Address of the added administrator.
 	fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let new_admin = T::CrossAccountId::from_eth(new_admin);
@@ -208,6 +260,9 @@
 		Ok(())
 	}
 
+	/// Remove collection admin.
+	/// 
+	/// @param new_admin Address of the removed administrator.
 	fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let admin = T::CrossAccountId::from_eth(admin);
@@ -215,6 +270,9 @@
 		Ok(())
 	}
 
+	/// Toggle accessibility of collection nesting.
+	/// 
+	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
 	#[solidity(rename_selector = "setCollectionNesting")]
 	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
@@ -235,6 +293,10 @@
 		save(self)
 	}
 
+	/// Toggle accessibility of collection nesting.
+	/// 
+	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	/// @param collections Addresses of collections that will be available for nesting.
 	#[solidity(rename_selector = "setCollectionNesting")]
 	fn set_nesting(
 		&mut self,
@@ -280,6 +342,10 @@
 		save(self)
 	}
 
+	/// Set the collection access method.
+	/// @param mode Access mode
+	/// 	0 for Normal
+	/// 	1 for AllowList
 	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 		let permissions = CollectionPermissions {
@@ -300,13 +366,19 @@
 		save(self)
 	}
 
+	/// Add the user to the allowed list.
+	/// 
+	/// @param user Address of a trusted user.
 	fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let user = T::CrossAccountId::from_eth(user);
 		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
-
+	
+	/// Remove the user from the allowed list.
+	/// 
+	/// @param user Address of a removed user.
 	fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let user = T::CrossAccountId::from_eth(user);
@@ -314,6 +386,9 @@
 		Ok(())
 	}
 
+	/// Switch permission for minting.
+	/// 
+	/// @param mode Enable if "true".
 	fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {
 		check_is_owner_or_admin(caller, self)?;
 		let permissions = CollectionPermissions {
@@ -351,6 +426,7 @@
 	Ok(())
 }
 
+/// Get the "tokenURI" key as [PropertyKey](up_data_structs::PropertyKey).
 pub fn token_uri_key() -> up_data_structs::PropertyKey {
 	b"tokenURI"
 		.to_vec()
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+//! The module contains a number of functions for converting and checking etherium identifiers.
+
 use up_data_structs::CollectionId;
 use sp_core::H160;
 
@@ -23,6 +25,7 @@
 	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,
 ];
 
+/// Maps the etherium address of the collection in substrate.
 pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {
 	if eth[0..16] != ETH_COLLECTION_PREFIX {
 		return None;
@@ -31,6 +34,8 @@
 	id_bytes.copy_from_slice(&eth[16..20]);
 	Some(CollectionId(u32::from_be_bytes(id_bytes)))
 }
+
+/// Maps the substrate collection id in etherium.
 pub fn collection_id_to_address(id: CollectionId) -> H160 {
 	let mut out = [0; 20];
 	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);
@@ -38,6 +43,7 @@
 	H160(out)
 }
 
+/// Check if the etherium address is a collection.
 pub fn is_collection(address: &H160) -> bool {
 	address[0..16] == ETH_COLLECTION_PREFIX
 }
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17//! # Common pallet
18//!
19//! The Common pallet provides functionality for handling collections.
20//!
21//! ## Overview
22//!
23//! The Common pallet provides functions for:
24//!
25//! - Setting and approving collection soponsor.
26//! - Get\set\delete allow list.
27//! - Get\set\delete collection properties.
28//! - Get\set\delete collection property permissions.
29//! - Get\set\delete token property permissions.
30//! - Get\set\delete collection administrators.
31//! - Checking access permissions.
32//! - Provides an interface for common collection operations for different collection types.
33//! - Provides dispatching for implementations of common collection operations, see [dispatch] module.
34//! - Provides functionality of collection into evm, see [erc] and [eth] module.
35//!
36//! ### Terminology
37//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will
38//! be possible to mint tokens.
39//!
40//! **Allow list** - List of users who have the right to minting tokens.
41//!
42//! **Collection properties** - Collection properties are simply key-value stores where various
43//! metadata can be placed.
44//!
45//! **Collection property permissions** - For each property in the collection can be set permission
46//! to change, see [PropertyPermission].
47//!
48//! **Permissions on token properties** - Similar to _permissions on collection properties_,
49//! only restrictions apply to token properties.
50//!
51//! **Collection administrator** - For a collection, you can set administrators who have the right
52//! to most actions on the collection.
53
54
55#![warn(missing_docs)]
17#![cfg_attr(not(feature = "std"), no_std)]56#![cfg_attr(not(feature = "std"), no_std)]
18
19extern crate alloc;57extern crate alloc;
2058
21use core::ops::{Deref, DerefMut};59use core::ops::{Deref, DerefMut};
90pub mod eth;128pub mod eth;
91pub mod weights;129pub mod weights;
92130
131/// Weight info.
93pub type SelfWeightOf<T> = <T as Config>::WeightInfo;132pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
94133
134/// Collection handle contains information about collection data and id.
135/// Also provides functionality to count consumed gas.
95#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]136#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]
96pub struct CollectionHandle<T: Config> {137pub struct CollectionHandle<T: Config> {
138 /// Collection id
97 pub id: CollectionId,139 pub id: CollectionId,
98 collection: Collection<T::AccountId>,140 collection: Collection<T::AccountId>,
141 /// Substrate recorder for counting consumed gas
99 pub recorder: SubstrateRecorder<T>,142 pub recorder: SubstrateRecorder<T>,
100}143}
144
101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {145impl<T: Config> WithRecorder<T> for CollectionHandle<T> {
102 fn recorder(&self) -> &SubstrateRecorder<T> {146 fn recorder(&self) -> &SubstrateRecorder<T> {
103 &self.recorder147 &self.recorder
106 self.recorder150 self.recorder
107 }151 }
108}152}
153
109impl<T: Config> CollectionHandle<T> {154impl<T: Config> CollectionHandle<T> {
155 /// Same as [CollectionHandle::new] but with an explicit gas limit.
110 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {156 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
111 <CollectionById<T>>::get(id).map(|collection| Self {157 <CollectionById<T>>::get(id).map(|collection| Self {
112 id,158 id,
115 })161 })
116 }162 }
117163
164 /// Same as [CollectionHandle::new] but with an existed [SubstrateRecorder].
118 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {165 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {
119 <CollectionById<T>>::get(id).map(|collection| Self {166 <CollectionById<T>>::get(id).map(|collection| Self {
120 id,167 id,
123 })170 })
124 }171 }
125172
173 /// Retrives collection data from storage and creates collection handle with default parameters.
174 /// If collection not found return `None`
126 pub fn new(id: CollectionId) -> Option<Self> {175 pub fn new(id: CollectionId) -> Option<Self> {
127 Self::new_with_gas_limit(id, u64::MAX)176 Self::new_with_gas_limit(id, u64::MAX)
128 }177 }
129178
179 /// Same as [CollectionHandle::new] but if collection not found [Error::CollectionNotFound] returned.
130 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {180 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {
131 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)181 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)
132 }182 }
133183
184 /// Consume gas for reading.
134 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {185 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {
135 self.recorder186 self.recorder
136 .consume_gas(T::GasWeightMapping::weight_to_gas(187 .consume_gas(T::GasWeightMapping::weight_to_gas(
140 ))191 ))
141 }192 }
142193
194 /// Consume gas for writing.
143 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {195 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {
144 self.recorder196 self.recorder
145 .consume_gas(T::GasWeightMapping::weight_to_gas(197 .consume_gas(T::GasWeightMapping::weight_to_gas(
148 .saturating_mul(writes),200 .saturating_mul(writes),
149 ))201 ))
150 }202 }
203
204 /// Save collection to storage.
151 pub fn save(self) -> DispatchResult {205 pub fn save(self) -> DispatchResult {
152 <CollectionById<T>>::insert(self.id, self.collection);206 <CollectionById<T>>::insert(self.id, self.collection);
153 Ok(())207 Ok(())
154 }208 }
155209
210 /// Set collection sponsor.
211 ///
212 /// Unique collections allows sponsoring for certain actions.
213 /// This method allows you to set the sponsor of the collection.
214 /// In order for sponsorship to become active, it must be confirmed through [Self::confirm_sponsorship].
156 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {215 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {
157 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);216 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
158 Ok(())217 Ok(())
159 }218 }
160219
220 /// Confirm sponsorship
221 ///
222 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.
223 /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [Self::set_sponsor].
161 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {224 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {
162 if self.collection.sponsorship.pending_sponsor() != Some(sender) {225 if self.collection.sponsorship.pending_sponsor() != Some(sender) {
163 return Ok(false);226 return Ok(false);
168 }231 }
169232
170 /// Checks that the collection was created with, and must be operated upon through **Unique API**.233 /// Checks that the collection was created with, and must be operated upon through **Unique API**.
171 /// Now check only the `external_collection` flag and if it's **true**, then return `CollectionIsExternal` error.234 /// Now check only the `external_collection` flag and if it's **true**, then return [Error::CollectionIsExternal] error.
172 pub fn check_is_internal(&self) -> DispatchResult {235 pub fn check_is_internal(&self) -> DispatchResult {
173 if self.external_collection {236 if self.external_collection {
174 return Err(<Error<T>>::CollectionIsExternal)?;237 return Err(<Error<T>>::CollectionIsExternal)?;
178 }241 }
179242
180 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.243 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.
181 /// Now check only the `external_collection` flag and if it's **false**, then return `CollectionIsInternal` error.244 /// Now check only the `external_collection` flag and if it's **false**, then return [Error::CollectionIsInternal] error.
182 pub fn check_is_external(&self) -> DispatchResult {245 pub fn check_is_external(&self) -> DispatchResult {
183 if !self.external_collection {246 if !self.external_collection {
184 return Err(<Error<T>>::CollectionIsInternal)?;247 return Err(<Error<T>>::CollectionIsInternal)?;
203}266}
204267
205impl<T: Config> CollectionHandle<T> {268impl<T: Config> CollectionHandle<T> {
206 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {269 /// Checks if the `user` is the owner of the collection.
270 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {
207 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);271 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);
208 Ok(())272 Ok(())
209 }273 }
274
275 /// Returns **true** if the `user` is the owner or administrator of the collection.
210 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {276 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {
211 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))277 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))
212 }278 }
279
280 /// Checks if the `user` is the owner or administrator of the collection.
213 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {281 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {
214 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);282 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);
215 Ok(())283 Ok(())
216 }284 }
285
286 /// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.
217 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {287 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {
218 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)288 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
219 }289 }
290
291 /// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.
220 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {292 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {
221 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)293 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
222 }294 }
295
296 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.
223 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {297 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {
224 ensure!(298 ensure!(
225 <Allowlist<T>>::get((self.id, user)),299 <Allowlist<T>>::get((self.id, user)),
249 + TypeInfo323 + TypeInfo
250 + account::Config324 + account::Config
251 {325 {
326 /// Weight info.
252 type WeightInfo: WeightInfo;327 type WeightInfo: WeightInfo;
328
329 /// Events compatible with [frame_system::Config::Event].
253 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;330 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
254331
332 /// Currency.
255 type Currency: Currency<Self::AccountId>;333 type Currency: Currency<Self::AccountId>;
256334
335 /// Price getter to create the collection.
257 #[pallet::constant]336 #[pallet::constant]
258 type CollectionCreationPrice: Get<337 type CollectionCreationPrice: Get<
259 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,338 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,
260 >;339 >;
340
341 /// Collection dispatcher.
261 type CollectionDispatch: CollectionDispatch<Self>;342 type CollectionDispatch: CollectionDispatch<Self>;
262343
344 /// Treasury account id getter.
263 type TreasuryAccountId: Get<Self::AccountId>;345 type TreasuryAccountId: Get<Self::AccountId>;
346
347 /// Contract address getter.
264 type ContractAddress: Get<H160>;348 type ContractAddress: Get<H160>;
265349
350 /// Mapper for tokens to Etherium addresses.
266 type EvmTokenAddressMapping: TokenAddressMapping<H160>;351 type EvmTokenAddressMapping: TokenAddressMapping<H160>;
352
353 /// Mapper for tokens to [CrossAccountId].
267 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;354 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;
268 }355 }
269356
276363
277 #[pallet::extra_constants]364 #[pallet::extra_constants]
278 impl<T: Config> Pallet<T> {365 impl<T: Config> Pallet<T> {
366 /// Maximum admins per collection.
279 pub fn collection_admins_limit() -> u32 {367 pub fn collection_admins_limit() -> u32 {
280 COLLECTION_ADMINS_LIMIT368 COLLECTION_ADMINS_LIMIT
281 }369 }
285 #[pallet::generate_deposit(pub fn deposit_event)]373 #[pallet::generate_deposit(pub fn deposit_event)]
286 pub enum Event<T: Config> {374 pub enum Event<T: Config> {
287 /// New collection was created375 /// New collection was created
288 ///376 CollectionCreated(
289 /// # Arguments377 /// Globally unique identifier of newly created collection.
290 ///
291 /// * collection_id: Globally unique identifier of newly created collection.
292 ///378 CollectionId,
293 /// * mode: [CollectionMode] converted into u8.379 /// [CollectionMode] converted into _u8_.
294 ///380 u8,
295 /// * account_id: Collection owner.381 /// Collection owner.
296 CollectionCreated(CollectionId, u8, T::AccountId),382 T::AccountId
383 ),
297384
298 /// New collection was destroyed385 /// New collection was destroyed
299 ///386 CollectionDestroyed(
300 /// # Arguments387 /// Globally unique identifier of collection.
301 ///
302 /// * collection_id: Globally unique identifier of collection.
303 CollectionDestroyed(CollectionId),388 CollectionId
389 ),
304390
305 /// New item was created.391 /// New item was created.
306 ///392 ItemCreated(
307 /// # Arguments393 /// Id of the collection where item was created.
308 ///
309 /// * collection_id: Id of the collection where item was created.
310 ///394 CollectionId,
311 /// * item_id: Id of an item. Unique within the collection.395 /// Id of an item. Unique within the collection.
312 ///396 TokenId,
313 /// * recipient: Owner of newly created item397 /// Owner of newly created item
314 ///398 T::CrossAccountId,
315 /// * amount: Always 1 for NFT399 /// Always 1 for NFT
316 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),400 u128
401 ),
317402
318 /// Collection item was burned.403 /// Collection item was burned.
319 ///404 ItemDestroyed(
320 /// # Arguments405 /// Id of the collection where item was destroyed.
321 ///
322 /// * collection_id.
323 ///406 CollectionId,
324 /// * item_id: Identifier of burned NFT.407 /// Identifier of burned NFT.
325 ///408 TokenId,
326 /// * owner: which user has destroyed its tokens409 /// Which user has destroyed its tokens.
327 ///410 T::CrossAccountId,
328 /// * amount: Always 1 for NFT411 /// Amount of token pieces destroed. Always 1 for NFT.
329 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),412 u128),
330413
331 /// Item was transferred414 /// Item was transferred
332 ///
333 /// * collection_id: Id of collection to which item is belong
334 ///
335 /// * item_id: Id of an item
336 ///
337 /// * sender: Original owner of item
338 ///
339 /// * recipient: New owner of item
340 ///
341 /// * amount: Always 1 for NFT
342 Transfer(415 Transfer(
416 /// Id of collection to which item is belong.
343 CollectionId,417 CollectionId,
418 /// Id of an item.
344 TokenId,419 TokenId,
420 /// Original owner of item.
345 T::CrossAccountId,421 T::CrossAccountId,
422 /// New owner of item.
346 T::CrossAccountId,423 T::CrossAccountId,
424 /// Amount of token pieces transfered. Always 1 for NFT.
347 u128,425 u128,
348 ),426 ),
349427
350 /// * collection_id428 /// Amount pieces of token owned by `sender` was approved for `spender`.
351 ///
352 /// * item_id
353 ///
354 /// * sender
355 ///
356 /// * spender
357 ///
358 /// * amount
359 Approved(429 Approved(
430 /// Id of collection to which item is belong.
360 CollectionId,431 CollectionId,
432 /// Id of an item.
361 TokenId,433 TokenId,
434 /// Original owner of item.
362 T::CrossAccountId,435 T::CrossAccountId,
436 /// Id for which the approval was granted.
363 T::CrossAccountId,437 T::CrossAccountId,
438 /// Amount of token pieces transfered. Always 1 for NFT.
364 u128,439 u128,
365 ),440 ),
366441
367 CollectionPropertySet(CollectionId, PropertyKey),442 /// The colletion property has been set.
368443 CollectionPropertySet(
444 /// Id of collection to which property has been set.
445 CollectionId,
446 /// The property that was set.
447 PropertyKey
448 ),
449
369 CollectionPropertyDeleted(CollectionId, PropertyKey),450 /// The property has been deleted.
370451 CollectionPropertyDeleted(
452 /// Id of collection to which property has been deleted.
453 CollectionId,
454 /// The property that was deleted.
455 PropertyKey
456 ),
457
371 TokenPropertySet(CollectionId, TokenId, PropertyKey),458 /// The token property has been set.
372459 TokenPropertySet(
460 /// Identifier of the collection whose token has the property set.
461 CollectionId,
462 /// The token for which the property was set.
463 TokenId,
464 /// The property that was set.
465 PropertyKey
466 ),
467
373 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),468
374469 /// The token property has been deleted.
470 TokenPropertyDeleted(
471 /// Identifier of the collection whose token has the property deleted.
472 CollectionId,
473 /// The token for which the property was deleted.
474 TokenId,
475 /// The property that was deleted.
476 PropertyKey
477 ),
478
375 PropertyPermissionSet(CollectionId, PropertyKey),479 /// The colletion property permission has been set.
480 PropertyPermissionSet(
481 /// Id of collection to which property permission has been set.
482 CollectionId,
483 /// The property permission that was set.
484 PropertyKey
485 ),
376 }486 }
377487
378 #[pallet::error]488 #[pallet::error]
460 CollectionIsInternal,570 CollectionIsInternal,
461 }571 }
462572
573 /// Storage of the count of created collections.
463 #[pallet::storage]574 #[pallet::storage]
464 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;575 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
576
577 /// Storage of the count of deleted collections.
465 #[pallet::storage]578 #[pallet::storage]
466 pub type DestroyedCollectionCount<T> =579 pub type DestroyedCollectionCount<T> =
467 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;580 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;
468581
469 /// Collection info582 /// Storage of collection info.
470 #[pallet::storage]583 #[pallet::storage]
471 pub type CollectionById<T> = StorageMap<584 pub type CollectionById<T> = StorageMap<
472 Hasher = Blake2_128Concat,585 Hasher = Blake2_128Concat,
475 QueryKind = OptionQuery,588 QueryKind = OptionQuery,
476 >;589 >;
477590
478 /// Collection properties591 /// Storage of collection properties.
479 #[pallet::storage]592 #[pallet::storage]
480 #[pallet::getter(fn collection_properties)]593 #[pallet::getter(fn collection_properties)]
481 pub type CollectionProperties<T> = StorageMap<594 pub type CollectionProperties<T> = StorageMap<
486 OnEmpty = up_data_structs::CollectionProperties,599 OnEmpty = up_data_structs::CollectionProperties,
487 >;600 >;
488601
602 /// Storage of collection properties permissions.
489 #[pallet::storage]603 #[pallet::storage]
490 #[pallet::getter(fn property_permissions)]604 #[pallet::getter(fn property_permissions)]
491 pub type CollectionPropertyPermissions<T> = StorageMap<605 pub type CollectionPropertyPermissions<T> = StorageMap<
495 QueryKind = ValueQuery,609 QueryKind = ValueQuery,
496 >;610 >;
497611
612 /// Storage of collection admins count.
498 #[pallet::storage]613 #[pallet::storage]
499 pub type AdminAmount<T> = StorageMap<614 pub type AdminAmount<T> = StorageMap<
500 Hasher = Blake2_128Concat,615 Hasher = Blake2_128Concat,
525 QueryKind = ValueQuery,640 QueryKind = ValueQuery,
526 >;641 >;
527642
528 /// Not used by code, exists only to provide some types to metadata643 /// Not used by code, exists only to provide some types to metadata.
529 #[pallet::storage]644 #[pallet::storage]
530 pub type DummyStorageValue<T: Config> = StorageValue<645 pub type DummyStorageValue<T: Config> = StorageValue<
531 Value = (646 Value = (
619}734}
620735
621impl<T: Config> Pallet<T> {736impl<T: Config> Pallet<T> {
622 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens737 /// Enshure that receiver address is correct.
738 ///
739 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.
623 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {740 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {
624 ensure!(741 ensure!(
625 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,742 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,
626 <Error<T>>::AddressIsZero743 <Error<T>>::AddressIsZero
627 );744 );
628 Ok(())745 Ok(())
629 }746 }
747
748 /// Get a vector of collection admins.
630 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {749 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {
631 <IsAdmin<T>>::iter_prefix((collection,))750 <IsAdmin<T>>::iter_prefix((collection,))
632 .map(|(a, _)| a)751 .map(|(a, _)| a)
633 .collect()752 .collect()
634 }753 }
754
755 /// Get a vector of users allowed to mint tokens.
635 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {756 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {
636 <Allowlist<T>>::iter_prefix((collection,))757 <Allowlist<T>>::iter_prefix((collection,))
637 .map(|(a, _)| a)758 .map(|(a, _)| a)
638 .collect()759 .collect()
639 }760 }
761
762 /// Is `user` allowed to mint token in `collection`.
640 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {763 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {
641 <Allowlist<T>>::get((collection, user))764 <Allowlist<T>>::get((collection, user))
642 }765 }
766
767 /// Get statistics of collections.
643 pub fn collection_stats() -> CollectionStats {768 pub fn collection_stats() -> CollectionStats {
644 let created = <CreatedCollectionCount<T>>::get();769 let created = <CreatedCollectionCount<T>>::get();
645 let destroyed = <DestroyedCollectionCount<T>>::get();770 let destroyed = <DestroyedCollectionCount<T>>::get();
650 }775 }
651 }776 }
652777
778 /// Get the effective limits for the collection.
653 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {779 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {
654 let collection = <CollectionById<T>>::get(collection);780 let collection = <CollectionById<T>>::get(collection);
655 if collection.is_none() {781 if collection.is_none() {
683 Some(effective_limits)809 Some(effective_limits)
684 }810 }
685811
812 /// Returns information about the `collection` adapted for rpc.
686 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {813 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {
687 let Collection {814 let Collection {
688 name,815 name,
758}885}
759886
760impl<T: Config> Pallet<T> {887impl<T: Config> Pallet<T> {
888 /// Create new collection.
889 ///
890 /// * `owner` - The owner of the collection.
891 /// * `data` - Description of the created collection.
892 /// * `is_external` - Marks that collection managet by not "Unique network".
761 pub fn init_collection(893 pub fn init_collection(
762 owner: T::CrossAccountId,894 owner: T::CrossAccountId,
763 data: CreateCollectionData<T::AccountId>,895 data: CreateCollectionData<T::AccountId>,
764 is_external: bool,896 is_external: bool,
765 ) -> Result<CollectionId, DispatchError> {897 ) -> Result<CollectionId, DispatchError> {
766 {898 {
858 Ok(id)990 Ok(id)
859 }991 }
860992
993 /// Destroy collection.
994 ///
995 /// * `collection` - Collection handler.
996 /// * `sender` - The owner or administrator of the collection.
861 pub fn destroy_collection(997 pub fn destroy_collection(
862 collection: CollectionHandle<T>,998 collection: CollectionHandle<T>,
863 sender: &T::CrossAccountId,999 sender: &T::CrossAccountId,
886 Ok(())1022 Ok(())
887 }1023 }
8881024
1025 /// Set collection property.
1026 ///
1027 /// * `collection` - Collection handler.
1028 /// * `sender` - The owner or administrator of the collection.
1029 /// * `property` - The property to set.
889 pub fn set_collection_property(1030 pub fn set_collection_property(
890 collection: &CollectionHandle<T>,1031 collection: &CollectionHandle<T>,
891 sender: &T::CrossAccountId,1032 sender: &T::CrossAccountId,
904 Ok(())1045 Ok(())
905 }1046 }
9061047
1048 /// Set scouped collection property.
1049 ///
1050 /// * `collection_id` - ID of the collection for which the property is being set.
1051 /// * `scope` - Property scope.
1052 /// * `property` - The property to set.
907 pub fn set_scoped_collection_property(1053 pub fn set_scoped_collection_property(
908 collection_id: CollectionId,1054 collection_id: CollectionId,
909 scope: PropertyScope,1055 scope: PropertyScope,
913 properties.try_scoped_set(scope, property.key, property.value)1059 properties.try_scoped_set(scope, property.key, property.value)
914 })1060 })
915 .map_err(<Error<T>>::from)?;1061 .map_err(<Error<T>>::from)?;
9161062
917 Ok(())1063 Ok(())
918 }1064 }
9191065
1066 /// Set scouped collection properties.
1067 ///
1068 /// * `collection_id` - ID of the collection for which the properties is being set.
1069 /// * `scope` - Property scope.
1070 /// * `properties` - The properties to set.
920 pub fn set_scoped_collection_properties(1071 pub fn set_scoped_collection_properties(
921 collection_id: CollectionId,1072 collection_id: CollectionId,
922 scope: PropertyScope,1073 scope: PropertyScope,
930 Ok(())1081 Ok(())
931 }1082 }
9321083
1084 /// Set collection properties.
1085 ///
1086 /// * `collection` - Collection handler.
1087 /// * `sender` - The owner or administrator of the collection.
1088 /// * `properties` - The properties to set.
933 #[transactional]1089 #[transactional]
934 pub fn set_collection_properties(1090 pub fn set_collection_properties(
935 collection: &CollectionHandle<T>,1091 collection: &CollectionHandle<T>,
939 for property in properties {1095 for property in properties {
940 Self::set_collection_property(collection, sender, property)?;1096 Self::set_collection_property(collection, sender, property)?;
941 }1097 }
9421098
943 Ok(())1099 Ok(())
944 }1100 }
9451101
1102 /// Delete collection property.
1103 ///
1104 /// * `collection` - Collection handler.
1105 /// * `sender` - The owner or administrator of the collection.
1106 /// * `property` - The property to delete.
946 pub fn delete_collection_property(1107 pub fn delete_collection_property(
947 collection: &CollectionHandle<T>,1108 collection: &CollectionHandle<T>,
948 sender: &T::CrossAccountId,1109 sender: &T::CrossAccountId,
949 property_key: PropertyKey,1110 property_key: PropertyKey,
950 ) -> DispatchResult {1111 ) -> DispatchResult {
951 collection.check_is_owner_or_admin(sender)?;1112 collection.check_is_owner_or_admin(sender)?;
9521113
953 CollectionProperties::<T>::try_mutate(collection.id, |properties| {1114 CollectionProperties::<T>::try_mutate(collection.id, |properties| {
954 properties.remove(&property_key)1115 properties.remove(&property_key)
955 })1116 })
956 .map_err(<Error<T>>::from)?;1117 .map_err(<Error<T>>::from)?;
9571118
958 Self::deposit_event(Event::CollectionPropertyDeleted(1119 Self::deposit_event(Event::CollectionPropertyDeleted(
959 collection.id,1120 collection.id,
960 property_key,1121 property_key,
961 ));1122 ));
9621123
963 Ok(())1124 Ok(())
964 }1125 }
9651126
1127 /// Delete collection properties.
1128 ///
1129 /// * `collection` - Collection handler.
1130 /// * `sender` - The owner or administrator of the collection.
1131 /// * `properties` - The properties to delete.
966 #[transactional]1132 #[transactional]
967 pub fn delete_collection_properties(1133 pub fn delete_collection_properties(
968 collection: &CollectionHandle<T>,1134 collection: &CollectionHandle<T>,
972 for key in property_keys {1138 for key in property_keys {
973 Self::delete_collection_property(collection, sender, key)?;1139 Self::delete_collection_property(collection, sender, key)?;
974 }1140 }
9751141
976 Ok(())1142 Ok(())
977 }1143 }
9781144
979 // For migrations1145 /// Set collection propetry permission without any checks.
1146 ///
1147 /// Used for migrations.
1148 ///
1149 /// * `collection` - Collection handler.
1150 /// * `property_permissions` - Property permissions.
980 pub fn set_property_permission_unchecked(1151 pub fn set_property_permission_unchecked(
981 collection: CollectionId,1152 collection: CollectionId,
982 property_permission: PropertyKeyPermission,1153 property_permission: PropertyKeyPermission,
988 Ok(())1159 Ok(())
989 }1160 }
9901161
1162 /// Set collection property permission.
1163 ///
1164 /// * `collection` - Collection handler.
1165 /// * `sender` - The owner or administrator of the collection.
1166 /// * `property_permission` - Property permission.
991 pub fn set_property_permission(1167 pub fn set_property_permission(
992 collection: &CollectionHandle<T>,1168 collection: &CollectionHandle<T>,
993 sender: &T::CrossAccountId,1169 sender: &T::CrossAccountId,
1018 Ok(())1194 Ok(())
1019 }1195 }
10201196
1197 /// Set token property permission.
1198 ///
1199 /// * `collection` - Collection handler.
1200 /// * `sender` - The owner or administrator of the collection.
1201 /// * `property_permissions` - Property permissions.
1021 #[transactional]1202 #[transactional]
1022 pub fn set_token_property_permissions(1203 pub fn set_token_property_permissions(
1023 collection: &CollectionHandle<T>,1204 collection: &CollectionHandle<T>,
1031 Ok(())1212 Ok(())
1032 }1213 }
10331214
1215 /// Get collection property.
1034 pub fn get_collection_property(1216 pub fn get_collection_property(
1035 collection_id: CollectionId,1217 collection_id: CollectionId,
1036 key: &PropertyKey,1218 key: &PropertyKey,
1037 ) -> Option<PropertyValue> {1219 ) -> Option<PropertyValue> {
1038 Self::collection_properties(collection_id).get(key).cloned()1220 Self::collection_properties(collection_id).get(key).cloned()
1039 }1221 }
10401222
1223 /// Convert byte vector to property key vector.
1041 pub fn bytes_keys_to_property_keys(1224 pub fn bytes_keys_to_property_keys(
1042 keys: Vec<Vec<u8>>,1225 keys: Vec<Vec<u8>>,
1043 ) -> Result<Vec<PropertyKey>, DispatchError> {1226 ) -> Result<Vec<PropertyKey>, DispatchError> {
1049 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1232 .collect::<Result<Vec<PropertyKey>, DispatchError>>()
1050 }1233 }
10511234
1235 /// Get properties according to given keys.
1052 pub fn filter_collection_properties(1236 pub fn filter_collection_properties(
1053 collection_id: CollectionId,1237 collection_id: CollectionId,
1054 keys: Option<Vec<PropertyKey>>,1238 keys: Option<Vec<PropertyKey>>,
1076 Ok(properties)1260 Ok(properties)
1077 }1261 }
10781262
1263 /// Get property permissions according to given keys.
1079 pub fn filter_property_permissions(1264 pub fn filter_property_permissions(
1080 collection_id: CollectionId,1265 collection_id: CollectionId,
1081 keys: Option<Vec<PropertyKey>>,1266 keys: Option<Vec<PropertyKey>>,
1105 Ok(key_permissions)1290 Ok(key_permissions)
1106 }1291 }
11071292
1293 /// Toggle `user` participation in the `collection`'s allow list.
1108 pub fn toggle_allowlist(1294 pub fn toggle_allowlist(
1109 collection: &CollectionHandle<T>,1295 collection: &CollectionHandle<T>,
1110 sender: &T::CrossAccountId,1296 sender: &T::CrossAccountId,
1124 Ok(())1310 Ok(())
1125 }1311 }
11261312
1313 /// Toggle `user` participation in the `collection`'s admin list.
1127 pub fn toggle_admin(1314 pub fn toggle_admin(
1128 collection: &CollectionHandle<T>,1315 collection: &CollectionHandle<T>,
1129 sender: &T::CrossAccountId,1316 sender: &T::CrossAccountId,
1159 Ok(())1346 Ok(())
1160 }1347 }
11611348
1349 /// Merge set fields from `new_limit` to `old_limit`.
1162 pub fn clamp_limits(1350 pub fn clamp_limits(
1163 mode: CollectionMode,1351 mode: CollectionMode,
1164 old_limit: &CollectionLimits,1352 old_limit: &CollectionLimits,
1204 Ok(new_limit)1392 Ok(new_limit)
1205 }1393 }
12061394
1395 /// Merge set fields from `new_permission` to `old_permission`.
1207 pub fn clamp_permissions(1396 pub fn clamp_permissions(
1208 _mode: CollectionMode,1397 _mode: CollectionMode,
1209 old_limit: &CollectionPermissions,1398 old_permission: &CollectionPermissions,
1210 mut new_limit: CollectionPermissions,1399 mut new_permission: CollectionPermissions,
1211 ) -> Result<CollectionPermissions, DispatchError> {1400 ) -> Result<CollectionPermissions, DispatchError> {
1212 limit_default_clone!(old_limit, new_limit,1401 limit_default_clone!(old_permission, new_permission,
1213 access => {},1402 access => {},
1214 mint_mode => {},1403 mint_mode => {},
1215 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1404 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },
1216 );1405 );
1217 Ok(new_limit)1406 Ok(new_permission)
1218 }1407 }
1219}1408}
12201409
1410/// Indicates unsupported methods by returning [Error::UnsupportedOperation].
1221#[macro_export]1411#[macro_export]
1222macro_rules! unsupported {1412macro_rules! unsupported {
1223 () => {1413 () => {
1224 Err(<Error<T>>::UnsupportedOperation.into())1414 Err(<Error<T>>::UnsupportedOperation.into())
1225 };1415 };
1226}1416}
12271417
1228/// Worst cases1418/// Return weights for various worst-case operations.
1229pub trait CommonWeightInfo<CrossAccountId> {1419pub trait CommonWeightInfo<CrossAccountId> {
1420 /// Weight of item creation.
1230 fn create_item() -> Weight;1421 fn create_item() -> Weight;
1422
1423 /// Weight of items creation.
1231 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1424 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;
1425
1426 /// Weight of items creation.
1232 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1427 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;
1428
1429 /// The weight of the burning item.
1233 fn burn_item() -> Weight;1430 fn burn_item() -> Weight;
1431
1432 /// Property setting weight.
1433 ///
1434 /// * `amount`- The number of properties to set.
1234 fn set_collection_properties(amount: u32) -> Weight;1435 fn set_collection_properties(amount: u32) -> Weight;
1436
1437 /// Collection property deletion weight.
1438 ///
1439 /// * `amount`- The number of properties to set.
1235 fn delete_collection_properties(amount: u32) -> Weight;1440 fn delete_collection_properties(amount: u32) -> Weight;
1441
1442 /// Token property setting weight.
1443 ///
1444 /// * `amount`- The number of properties to set.
1236 fn set_token_properties(amount: u32) -> Weight;1445 fn set_token_properties(amount: u32) -> Weight;
1446
1447 /// Token property deletion weight.
1448 ///
1449 /// * `amount`- The number of properties to delete.
1237 fn delete_token_properties(amount: u32) -> Weight;1450 fn delete_token_properties(amount: u32) -> Weight;
1451
1452
1453 /// Token property permissions set weight.
1454 ///
1455 /// * `amount`- The number of property permissions to set.
1238 fn set_token_property_permissions(amount: u32) -> Weight;1456 fn set_token_property_permissions(amount: u32) -> Weight;
1457
1458 /// Transfer price of the token or its parts.
1239 fn transfer() -> Weight;1459 fn transfer() -> Weight;
1460
1461 /// The price of setting the permission of the operation from another user.
1240 fn approve() -> Weight;1462 fn approve() -> Weight;
1463
1464 /// Transfer price from another user.
1241 fn transfer_from() -> Weight;1465 fn transfer_from() -> Weight;
1466
1467 /// The price of burning a token from another user.
1242 fn burn_from() -> Weight;1468 fn burn_from() -> Weight;
12431469
1244 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1470 /// Differs from burn_item in case of Fungible and Refungible, as it should burn
1245 /// whole users's balance1471 /// whole users's balance
1246 ///1472 ///
1247 /// This method shouldn't be used directly, as it doesn't count breadth price, use `burn_recursively` instead1473 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
1248 fn burn_recursively_self_raw() -> Weight;1474 fn burn_recursively_self_raw() -> Weight;
1475
1249 /// Cost of iterating over `amount` children while burning, without counting child burning itself1476 /// Cost of iterating over `amount` children while burning, without counting child burning itself
1250 ///1477 ///
1251 /// This method shouldn't be used directly, as it doesn't count depth price, use `burn_recursively` instead1478 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
1252 fn burn_recursively_breadth_raw(amount: u32) -> Weight;1479 fn burn_recursively_breadth_raw(amount: u32) -> Weight;
12531480
1481 /// The price of recursive burning a token.
1482 ///
1483 /// `max_selfs` -
1254 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1484 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {
1255 Self::burn_recursively_self_raw()1485 Self::burn_recursively_self_raw()
1256 .saturating_mul(max_selfs.max(1) as u64)1486 .saturating_mul(max_selfs.max(1) as u64)
1257 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1487 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))
1258 }1488 }
1259}1489}
12601490
1491/// Weight info extension trait for refungible pallet.
1261pub trait RefungibleExtensionsWeightInfo {1492pub trait RefungibleExtensionsWeightInfo {
1493 /// Weight of token repartition.
1262 fn repartition() -> Weight;1494 fn repartition() -> Weight;
1263}1495}
12641496
1497/// Common collection operations.
1498///
1499/// It wraps methods in Fungible, Nonfungible and Refungible pallets
1500/// and adds weight info.
1265pub trait CommonCollectionOperations<T: Config> {1501pub trait CommonCollectionOperations<T: Config> {
1502 /// Create token.
1503 ///
1504 /// * `sender` - The user who mint the token and pays for the transaction.
1505 /// * `to` - The user who will own the token.
1506 /// * `data` - Token data.
1507 /// * `nesting_budget` - A budget that can be spent on nesting tokens.
1266 fn create_item(1508 fn create_item(
1267 &self,1509 &self,
1268 sender: T::CrossAccountId,1510 sender: T::CrossAccountId,
1269 to: T::CrossAccountId,1511 to: T::CrossAccountId,
1270 data: CreateItemData,1512 data: CreateItemData,
1271 nesting_budget: &dyn Budget,1513 nesting_budget: &dyn Budget,
1272 ) -> DispatchResultWithPostInfo;1514 ) -> DispatchResultWithPostInfo;
1515
1516 /// Create multiple tokens.
1517 ///
1518 /// * `sender` - The user who mint the token and pays for the transaction.
1519 /// * `to` - The user who will own the token.
1520 /// * `data` - Token data.
1521 /// * `nesting_budget` - A budget that can be spent on nesting tokens.
1273 fn create_multiple_items(1522 fn create_multiple_items(
1274 &self,1523 &self,
1275 sender: T::CrossAccountId,1524 sender: T::CrossAccountId,
1276 to: T::CrossAccountId,1525 to: T::CrossAccountId,
1277 data: Vec<CreateItemData>,1526 data: Vec<CreateItemData>,
1278 nesting_budget: &dyn Budget,1527 nesting_budget: &dyn Budget,
1279 ) -> DispatchResultWithPostInfo;1528 ) -> DispatchResultWithPostInfo;
1529
1530 /// Create multiple tokens.
1531 ///
1532 /// * `sender` - The user who mint the token and pays for the transaction.
1533 /// * `to` - The user who will own the token.
1534 /// * `data` - Token data.
1535 /// * `nesting_budget` - A budget that can be spent on nesting tokens.
1280 fn create_multiple_items_ex(1536 fn create_multiple_items_ex(
1281 &self,1537 &self,
1282 sender: T::CrossAccountId,1538 sender: T::CrossAccountId,
1283 data: CreateItemExData<T::CrossAccountId>,1539 data: CreateItemExData<T::CrossAccountId>,
1284 nesting_budget: &dyn Budget,1540 nesting_budget: &dyn Budget,
1285 ) -> DispatchResultWithPostInfo;1541 ) -> DispatchResultWithPostInfo;
1542
1543 /// Burn token.
1544 ///
1545 /// * `sender` - The user who owns the token.
1546 /// * `token` - Token id that will burned.
1547 /// * `amount` - The number of parts of the token that will be burned.
1286 fn burn_item(1548 fn burn_item(
1287 &self,1549 &self,
1288 sender: T::CrossAccountId,1550 sender: T::CrossAccountId,
1289 token: TokenId,1551 token: TokenId,
1290 amount: u128,1552 amount: u128,
1291 ) -> DispatchResultWithPostInfo;1553 ) -> DispatchResultWithPostInfo;
1554
1555 /// Burn token and all nested tokens recursievly.
1556 ///
1557 /// * `sender` - The user who owns the token.
1558 /// * `token` - Token id that will burned.
1559 /// * `self_budget` - The budget that can be spent on burning tokens.
1560 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.
1292 fn burn_item_recursively(1561 fn burn_item_recursively(
1293 &self,1562 &self,
1294 sender: T::CrossAccountId,1563 sender: T::CrossAccountId,
1295 token: TokenId,1564 token: TokenId,
1296 self_budget: &dyn Budget,1565 self_budget: &dyn Budget,
1297 breadth_budget: &dyn Budget,1566 breadth_budget: &dyn Budget,
1298 ) -> DispatchResultWithPostInfo;1567 ) -> DispatchResultWithPostInfo;
1568
1569 /// Set collection properties.
1570 ///
1571 /// * `sender` - Must be either the owner of the collection or its admin.
1572 /// * `properties` - Properties to be set.
1299 fn set_collection_properties(1573 fn set_collection_properties(
1300 &self,1574 &self,
1301 sender: T::CrossAccountId,1575 sender: T::CrossAccountId,
1302 properties: Vec<Property>,1576 properties: Vec<Property>,
1303 ) -> DispatchResultWithPostInfo;1577 ) -> DispatchResultWithPostInfo;
1578
1579 /// Delete collection properties.
1580 ///
1581 /// * `sender` - Must be either the owner of the collection or its admin.
1582 /// * `properties` - The properties to be removed.
1304 fn delete_collection_properties(1583 fn delete_collection_properties(
1305 &self,1584 &self,
1306 sender: &T::CrossAccountId,1585 sender: &T::CrossAccountId,
1307 property_keys: Vec<PropertyKey>,1586 property_keys: Vec<PropertyKey>,
1308 ) -> DispatchResultWithPostInfo;1587 ) -> DispatchResultWithPostInfo;
1588
1589 /// Set token properties.
1590 ///
1591 /// The appropriate [PropertyPermission] for the token property
1592 /// must be set with [Self::set_token_property_permissions].
1593 ///
1594 /// * `sender` - Must be either the owner of the token or its admin.
1595 /// * `token_id` - The token for which the properties are being set.
1596 /// * `properties` - Properties to be set.
1597 /// * `budget` - Budget for setting properties.
1309 fn set_token_properties(1598 fn set_token_properties(
1310 &self,1599 &self,
1311 sender: T::CrossAccountId,1600 sender: T::CrossAccountId,
1312 token_id: TokenId,1601 token_id: TokenId,
1313 property: Vec<Property>,1602 properties: Vec<Property>,
1314 nesting_budget: &dyn Budget,1603 budget: &dyn Budget,
1315 ) -> DispatchResultWithPostInfo;1604 ) -> DispatchResultWithPostInfo;
1605
1606 /// Remove token properties.
1607 ///
1608 /// The appropriate [PropertyPermission] for the token property
1609 /// must be set with [Self::set_token_property_permissions].
1610 ///
1611 /// * `sender` - Must be either the owner of the token or its admin.
1612 /// * `token_id` - The token for which the properties are being remove.
1613 /// * `property_keys` - Keys to remove corresponding properties.
1614 /// * `budget` - Budget for removing properties.
1316 fn delete_token_properties(1615 fn delete_token_properties(
1317 &self,1616 &self,
1318 sender: T::CrossAccountId,1617 sender: T::CrossAccountId,
1319 token_id: TokenId,1618 token_id: TokenId,
1320 property_keys: Vec<PropertyKey>,1619 property_keys: Vec<PropertyKey>,
1321 nesting_budget: &dyn Budget,1620 budget: &dyn Budget,
1322 ) -> DispatchResultWithPostInfo;1621 ) -> DispatchResultWithPostInfo;
1622
1623 /// Set token property permissions.
1624 ///
1625 /// * `sender` - Must be either the owner of the token or its admin.
1626 /// * `token_id` - The token for which the properties are being set.
1627 /// * `properties` - Properties to be set.
1628 /// * `budget` - Budget for setting properties.
1323 fn set_token_property_permissions(1629 fn set_token_property_permissions(
1324 &self,1630 &self,
1325 sender: &T::CrossAccountId,1631 sender: &T::CrossAccountId,
1326 property_permissions: Vec<PropertyKeyPermission>,1632 property_permissions: Vec<PropertyKeyPermission>,
1327 ) -> DispatchResultWithPostInfo;1633 ) -> DispatchResultWithPostInfo;
1634
1635 /// Transfer amount of token pieces.
1636 ///
1637 /// * `sender` - Donor user.
1638 /// * `to` - Recepient user.
1639 /// * `token` - The token of which parts are being sent.
1640 /// * `amount` - The number of parts of the token that will be transferred.
1641 /// * `budget` - The maximum budget that can be spent on the transfer.
1328 fn transfer(1642 fn transfer(
1329 &self,1643 &self,
1330 sender: T::CrossAccountId,1644 sender: T::CrossAccountId,
1331 to: T::CrossAccountId,1645 to: T::CrossAccountId,
1332 token: TokenId,1646 token: TokenId,
1333 amount: u128,1647 amount: u128,
1334 nesting_budget: &dyn Budget,1648 budget: &dyn Budget,
1335 ) -> DispatchResultWithPostInfo;1649 ) -> DispatchResultWithPostInfo;
1650
1651 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].
1652 ///
1653 /// * `sender` - The user who grants access to the token.
1654 /// * `spender` - The user to whom the rights are granted.
1655 /// * `token` - The token to which access is granted.
1656 /// * `amount` - The amount of pieces that another user can dispose of.
1336 fn approve(1657 fn approve(
1337 &self,1658 &self,
1338 sender: T::CrossAccountId,1659 sender: T::CrossAccountId,
1339 spender: T::CrossAccountId,1660 spender: T::CrossAccountId,
1340 token: TokenId,1661 token: TokenId,
1341 amount: u128,1662 amount: u128,
1342 ) -> DispatchResultWithPostInfo;1663 ) -> DispatchResultWithPostInfo;
1664
1665 /// Send parts of a token owned by another user.
1666 ///
1667 /// Before calling this method, you must grant rights to the calling user via [Self::approve].
1668 ///
1669 /// * `sender` - The user who has access to the token.
1670 /// * `from` - The user who owns the token.
1671 /// * `to` - Recepient user.
1672 /// * `token` - The token of which parts are being sent.
1673 /// * `amount` - The number of parts of the token that will be transferred.
1674 /// * `budget` - The maximum budget that can be spent on the transfer.
1343 fn transfer_from(1675 fn transfer_from(
1344 &self,1676 &self,
1345 sender: T::CrossAccountId,1677 sender: T::CrossAccountId,
1346 from: T::CrossAccountId,1678 from: T::CrossAccountId,
1347 to: T::CrossAccountId,1679 to: T::CrossAccountId,
1348 token: TokenId,1680 token: TokenId,
1349 amount: u128,1681 amount: u128,
1350 nesting_budget: &dyn Budget,1682 budget: &dyn Budget,
1351 ) -> DispatchResultWithPostInfo;1683 ) -> DispatchResultWithPostInfo;
1684
1685 /// Burn parts of a token owned by another user.
1686 ///
1687 /// Before calling this method, you must grant rights to the calling user via [Self::approve].
1688 ///
1689 /// * `sender` - The user who has access to the token.
1690 /// * `from` - The user who owns the token.
1691 /// * `token` - The token of which parts are being sent.
1692 /// * `amount` - The number of parts of the token that will be transferred.
1693 /// * `budget` - The maximum budget that can be spent on the burn.
1352 fn burn_from(1694 fn burn_from(
1353 &self,1695 &self,
1354 sender: T::CrossAccountId,1696 sender: T::CrossAccountId,
1355 from: T::CrossAccountId,1697 from: T::CrossAccountId,
1356 token: TokenId,1698 token: TokenId,
1357 amount: u128,1699 amount: u128,
1358 nesting_budget: &dyn Budget,1700 budget: &dyn Budget,
1359 ) -> DispatchResultWithPostInfo;1701 ) -> DispatchResultWithPostInfo;
13601702
1703 /// Check permission to nest token.
1704 ///
1705 /// * `sender` - The user who initiated the check.
1706 /// * `from` - The token that is checked for embedding.
1707 /// * `under` - Token under which to check.
1708 /// * `budget` - The maximum budget that can be spent on the check.
1361 fn check_nesting(1709 fn check_nesting(
1362 &self,1710 &self,
1363 sender: T::CrossAccountId,1711 sender: T::CrossAccountId,
1364 from: (CollectionId, TokenId),1712 from: (CollectionId, TokenId),
1365 under: TokenId,1713 under: TokenId,
1366 nesting_budget: &dyn Budget,1714 budget: &dyn Budget,
1367 ) -> DispatchResult;1715 ) -> DispatchResult;
13681716
1717 /// Nest one token into another.
1718 ///
1719 /// * `under` - Token holder.
1720 /// * `to_nest` - Nested token.
1369 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));1721 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));
13701722
1723 /// Unnest token.
1724 ///
1725 /// * `under` - Token holder.
1726 /// * `to_nest` - Token to unnest.
1371 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));1727 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));
13721728
1729 /// Get all user tokens.
1730 ///
1731 /// * `account` - Account for which you need to get tokens.
1373 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1732 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;
1733
1734 /// Get all the tokens in the collection.
1374 fn collection_tokens(&self) -> Vec<TokenId>;1735 fn collection_tokens(&self) -> Vec<TokenId>;
1736
1737 /// Check if the token exists.
1738 ///
1739 /// * `token` - Id token to check.
1375 fn token_exists(&self, token: TokenId) -> bool;1740 fn token_exists(&self, token: TokenId) -> bool;
1741
1742 /// Get the id of the last minted token.
1376 fn last_token_id(&self) -> TokenId;1743 fn last_token_id(&self) -> TokenId;
13771744
1745 /// Get the owner of the token.
1746 ///
1747 /// * `token` - The token for which you need to find out the owner.
1378 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1748 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;
1749
1750 /// Get the value of the token property by key.
1751 ///
1752 /// * `token` - Token property to get.
1753 /// * `key` - Property name.
1379 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1754 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;
1755
1380 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1756 /// Get a set of token properties by key vector.
1757 ///
1758 /// * `token` - Token property to get.
1759 /// * `keys` - Vector of keys. If this parameter is [None](sp_std::result::Result),
1760 /// then all properties are returned.
1761 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;
1762
1381 /// Amount of unique collection tokens1763 /// Amount of unique collection tokens
1382 fn total_supply(&self) -> u32;1764 fn total_supply(&self) -> u32;
1765
1383 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1766 /// Amount of different tokens account has.
1767 ///
1768 /// * `account` - The account for which need to get the balance.
1384 fn account_balance(&self, account: T::CrossAccountId) -> u32;1769 fn account_balance(&self, account: T::CrossAccountId) -> u32;
1770
1385 /// Amount of specific token account have (Applicable to fungible/refungible)1771 /// Amount of specific token account have.
1386 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1772 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;
1773
1387 /// Amount of token pieces1774 /// Amount of token pieces
1388 fn total_pieces(&self, token: TokenId) -> Option<u128>;1775 fn total_pieces(&self, token: TokenId) -> Option<u128>;
1776
1777 /// Get the number of parts of the token that a trusted user can manage.
1778 ///
1779 /// * `sender` - Trusted user.
1780 /// * `spender` - Owner of the token.
1781 /// * `token` - The token for which to get the value.
1389 fn allowance(1782 fn allowance(
1390 &self,1783 &self,
1391 sender: T::CrossAccountId,1784 sender: T::CrossAccountId,
1392 spender: T::CrossAccountId,1785 spender: T::CrossAccountId,
1393 token: TokenId,1786 token: TokenId,
1394 ) -> u128;1787 ) -> u128;
1788
1789 /// Get extension for RFT collection.
1395 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1790 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;
1396}1791}
13971792
1793/// Extension for RFT collection.
1398pub trait RefungibleExtensions<T>1794pub trait RefungibleExtensions<T>
1399where1795where
1400 T: Config,1796 T: Config,
1401{1797{
1798 /// Change the number of parts of the token.
1799 ///
1800 /// When the value changes down, this function is equivalent to burning parts of the token.
1801 ///
1802 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.
1803 /// * `token` - The token for which you want to change the number of parts.
1804 /// * `amount` - The new value of the parts of the token.
1402 fn repartition(1805 fn repartition(
1403 &self,1806 &self,
1404 owner: &T::CrossAccountId,1807 sender: &T::CrossAccountId,
1405 token: TokenId,1808 token: TokenId,
1406 amount: u128,1809 amount: u128,
1407 ) -> DispatchResultWithPostInfo;1810 ) -> DispatchResultWithPostInfo;
1408}1811}
14091812
1410// Flexible enough for implementing CommonCollectionOperations1813/// Merge [DispatchResult] with [Weight] into [DispatchResultWithPostInfo].
1814///
1815/// Used for [CommonCollectionOperations] implementations and flexible enough to do so.
1411pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1816pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {
1412 let post_info = PostDispatchInfo {1817 let post_info = PostDispatchInfo {
1413 actual_weight: Some(weight),1818 actual_weight: Some(weight),