difftreelog
docs(pallet_common) Add general documentation.
in: master
4 files changed
pallets/common/src/dispatch.rsdiffbeforeafterboth1//! Module with interfaces for dispatching collections.21use frame_support::{3use frame_support::{2 dispatch::{4 dispatch::{20 // submit_logs is measured as part of collection pallets22 // submit_logs is measured as part of collection pallets21}23}222423/// Helper function to implement substrate calls for common collection methods25/// Helper function to implement substrate calls for common collection methods.26/// 27/// * `collection` - The collection on which to call the method.28/// * `call` - The function in which to call the corresponding method from [CommonCollectionOperations].24pub fn dispatch_tx<29pub fn dispatch_tx<25 T: Config,30 T: Config,26 C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,31 C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,64 result69 result65}70}667172/// Interface for working with different collections through the dispatcher.67pub trait CollectionDispatch<T: Config> {73pub trait CollectionDispatch<T: Config> {74 /// Create a collection. The collection will be created according to the value of [data.mode](CreateCollectionData::mode).75 /// 76 /// * `sender` - The user who will become the owner of the collection.77 /// * `data` - Description of the created collection.68 fn create(78 fn create(69 sender: T::CrossAccountId,79 sender: T::CrossAccountId,70 data: CreateCollectionData<T::AccountId>,80 data: CreateCollectionData<T::AccountId>,71 ) -> DispatchResult;81 ) -> DispatchResult;8283 /// Delete the collection.84 /// 85 /// * `sender` - The owner of the collection.86 /// * `handle` - Collection handle.72 fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;87 fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;738889 /// Get a specialized collection from the handle.90 /// 91 /// * `handle` - Collection handle.74 fn dispatch(handle: CollectionHandle<T>) -> Self;92 fn dispatch(handle: CollectionHandle<T>) -> Self;9394 /// Get the collection handle for the corresponding implementation.75 fn into_inner(self) -> CollectionHandle<T>;95 fn into_inner(self) -> CollectionHandle<T>;769697 /// Получить реализацию [CommonCollectionOperations].77 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;98 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;78}99}79100pallets/common/src/erc.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// 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/>.1617//! This module contains the implementation of pallet methods for evm.161817use evm_coder::{19use evm_coder::{18 solidity_interface, solidity, ToLog,20 solidity_interface, solidity, ToLog,293130use crate::{Pallet, CollectionHandle, Config, CollectionProperties};32use crate::{Pallet, CollectionHandle, Config, CollectionProperties};313334/// Events for etherium collection helper.32#[derive(ToLog)]35#[derive(ToLog)]33pub enum CollectionHelpersEvents {36pub enum CollectionHelpersEvents {37 /// The collection has been created.34 CollectionCreated {38 CollectionCreated {39 /// Collection owner.35 #[indexed]40 #[indexed]36 owner: address,41 owner: address,4243 /// Collection ID.37 #[indexed]44 #[indexed]38 collection_id: address,45 collection_id: address,39 },46 },40}47}414842/// Does not always represent a full collection, for RFT it is either49/// Does not always represent a full collection, for RFT it is either43/// collection (Implementing ERC721), or specific collection token (Implementing ERC20)50/// collection (Implementing ERC721), or specific collection token (Implementing ERC20).44pub trait CommonEvmHandler {51pub trait CommonEvmHandler {45 const CODE: &'static [u8];52 const CODE: &'static [u8];465347 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;54 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;48}55}495657/// @title A contract that allows you to work with collections.50#[solidity_interface(name = "Collection")]58#[solidity_interface(name = "Collection")]51impl<T: Config> CollectionHandle<T>59impl<T: Config> CollectionHandle<T>52where60where53 T::AccountId: From<[u8; 32]>,61 T::AccountId: From<[u8; 32]>,54{62{63 /// Set collection property.64 /// 65 /// @param key Property key.66 /// @param value Propery value.55 fn set_collection_property(67 fn set_collection_property(56 &mut self,68 &mut self,57 caller: caller,69 caller: caller,68 .map_err(dispatch_to_evm::<T>)80 .map_err(dispatch_to_evm::<T>)69 }81 }7082 83 /// Delete collection property.84 /// 85 /// @param key Property key.71 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {86 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {72 let caller = T::CrossAccountId::from_eth(caller);87 let caller = T::CrossAccountId::from_eth(caller);73 let key = <Vec<u8>>::from(key)88 let key = <Vec<u8>>::from(key)77 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)92 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)78 }93 }799495 /// Get collection property.96 /// 80 /// Throws error if key not found97 /// @dev Throws error if key not found.98 /// 99 /// @param key Property key.100 /// @return bytes The property corresponding to the key.81 fn collection_property(&self, key: string) -> Result<bytes> {101 fn collection_property(&self, key: string) -> Result<bytes> {82 let key = <Vec<u8>>::from(key)102 let key = <Vec<u8>>::from(key)83 .try_into()103 .try_into()89 Ok(prop.to_vec())109 Ok(prop.to_vec())90 }110 }91111112 /// Set the sponsor of the collection.113 /// 114 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.115 /// 116 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.92 fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {117 fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {93 check_is_owner_or_admin(caller, self)?;118 check_is_owner_or_admin(caller, self)?;9411998 save(self)123 save(self)99 }124 }100125126 /// Collection sponsorship confirmation.127 /// 128 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.101 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {129 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {102 let caller = T::CrossAccountId::from_eth(caller);130 let caller = T::CrossAccountId::from_eth(caller);103 if !self131 if !self109 save(self)137 save(self)110 }138 }111139140 /// Set limits for the collection.141 /// @dev Throws error if limit not found.142 /// @param limit Name of the limit. Valid names:143 /// "accountTokenOwnershipLimit",144 /// "sponsoredDataSize",145 /// "sponsoredDataRateLimit",146 /// "tokenLimit",147 /// "sponsorTransferTimeout",148 /// "sponsorApproveTimeout"149 /// @param value Value of the limit.112 #[solidity(rename_selector = "setCollectionLimit")]150 #[solidity(rename_selector = "setCollectionLimit")]113 fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {151 fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {114 check_is_owner_or_admin(caller, self)?;152 check_is_owner_or_admin(caller, self)?;145 save(self)183 save(self)146 }184 }147185186 /// Set limits for the collection.187 /// @dev Throws error if limit not found.188 /// @param limit Name of the limit. Valid names:189 /// "ownerCanTransfer",190 /// "ownerCanDestroy",191 /// "transfersEnabled"192 /// @param value Value of the limit.148 #[solidity(rename_selector = "setCollectionLimit")]193 #[solidity(rename_selector = "setCollectionLimit")]149 fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {194 fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {150 check_is_owner_or_admin(caller, self)?;195 check_is_owner_or_admin(caller, self)?;172 save(self)217 save(self)173 }218 }174219220 /// Get contract address.175 fn contract_address(&self, _caller: caller) -> Result<address> {221 fn contract_address(&self, _caller: caller) -> Result<address> {176 Ok(crate::eth::collection_id_to_address(self.id))222 Ok(crate::eth::collection_id_to_address(self.id))177 }223 }178224225 /// Add collection admin by substrate address.226 /// @param new_admin Substrate administrator address.179 fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {227 fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {180 let caller = T::CrossAccountId::from_eth(caller);228 let caller = T::CrossAccountId::from_eth(caller);181 let mut new_admin_arr: [u8; 32] = Default::default();229 let mut new_admin_arr: [u8; 32] = Default::default();186 Ok(())234 Ok(())187 }235 }188236237 /// Remove collection admin by substrate address.238 /// @param admin Substrate administrator address.189 fn remove_collection_admin_substrate(239 fn remove_collection_admin_substrate(190 &self,240 &self,191 caller: caller,241 caller: caller,192 new_admin: uint256,242 admin: uint256,193 ) -> Result<void> {243 ) -> Result<void> {194 let caller = T::CrossAccountId::from_eth(caller);244 let caller = T::CrossAccountId::from_eth(caller);195 let mut new_admin_arr: [u8; 32] = Default::default();245 let mut admin_arr: [u8; 32] = Default::default();196 new_admin.to_big_endian(&mut new_admin_arr);246 admin.to_big_endian(&mut admin_arr);197 let account_id = T::AccountId::from(new_admin_arr);247 let account_id = T::AccountId::from(admin_arr);198 let new_admin = T::CrossAccountId::from_sub(account_id);248 let admin = T::CrossAccountId::from_sub(account_id);199 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)249 <Pallet<T>>::toggle_admin(self, &caller, &admin, false)200 .map_err(dispatch_to_evm::<T>)?;250 .map_err(dispatch_to_evm::<T>)?;201 Ok(())251 Ok(())202 }252 }203253254 /// Add collection admin.255 /// @param new_admin Address of the added administrator.204 fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {256 fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {205 let caller = T::CrossAccountId::from_eth(caller);257 let caller = T::CrossAccountId::from_eth(caller);206 let new_admin = T::CrossAccountId::from_eth(new_admin);258 let new_admin = T::CrossAccountId::from_eth(new_admin);207 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;259 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;208 Ok(())260 Ok(())209 }261 }210262263 /// Remove collection admin.264 /// 265 /// @param new_admin Address of the removed administrator.211 fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {266 fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {212 let caller = T::CrossAccountId::from_eth(caller);267 let caller = T::CrossAccountId::from_eth(caller);213 let admin = T::CrossAccountId::from_eth(admin);268 let admin = T::CrossAccountId::from_eth(admin);214 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;269 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;215 Ok(())270 Ok(())216 }271 }217272273 /// Toggle accessibility of collection nesting.274 /// 275 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'218 #[solidity(rename_selector = "setCollectionNesting")]276 #[solidity(rename_selector = "setCollectionNesting")]219 fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {277 fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {220 check_is_owner_or_admin(caller, self)?;278 check_is_owner_or_admin(caller, self)?;235 save(self)293 save(self)236 }294 }237295296 /// Toggle accessibility of collection nesting.297 /// 298 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'299 /// @param collections Addresses of collections that will be available for nesting.238 #[solidity(rename_selector = "setCollectionNesting")]300 #[solidity(rename_selector = "setCollectionNesting")]239 fn set_nesting(301 fn set_nesting(240 &mut self,302 &mut self,280 save(self)342 save(self)281 }343 }282344345 /// Set the collection access method.346 /// @param mode Access mode347 /// 0 for Normal348 /// 1 for AllowList283 fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {349 fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {284 check_is_owner_or_admin(caller, self)?;350 check_is_owner_or_admin(caller, self)?;285 let permissions = CollectionPermissions {351 let permissions = CollectionPermissions {300 save(self)366 save(self)301 }367 }302368369 /// Add the user to the allowed list.370 /// 371 /// @param user Address of a trusted user.303 fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {372 fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {304 let caller = T::CrossAccountId::from_eth(caller);373 let caller = T::CrossAccountId::from_eth(caller);305 let user = T::CrossAccountId::from_eth(user);374 let user = T::CrossAccountId::from_eth(user);306 <Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;375 <Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;307 Ok(())376 Ok(())308 }377 }309378 379 /// Remove the user from the allowed list.380 /// 381 /// @param user Address of a removed user.310 fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {382 fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {311 let caller = T::CrossAccountId::from_eth(caller);383 let caller = T::CrossAccountId::from_eth(caller);312 let user = T::CrossAccountId::from_eth(user);384 let user = T::CrossAccountId::from_eth(user);313 <Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;385 <Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;314 Ok(())386 Ok(())315 }387 }316388389 /// Switch permission for minting.390 /// 391 /// @param mode Enable if "true".317 fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {392 fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {318 check_is_owner_or_admin(caller, self)?;393 check_is_owner_or_admin(caller, self)?;319 let permissions = CollectionPermissions {394 let permissions = CollectionPermissions {351 Ok(())426 Ok(())352}427}353428429/// Get the "tokenURI" key as [PropertyKey](up_data_structs::PropertyKey).354pub fn token_uri_key() -> up_data_structs::PropertyKey {430pub fn token_uri_key() -> up_data_structs::PropertyKey {355 b"tokenURI"431 b"tokenURI"356 .to_vec()432 .to_vec()pallets/common/src/eth.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// 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/>.1617//! The module contains a number of functions for converting and checking etherium identifiers.161817use up_data_structs::CollectionId;19use up_data_structs::CollectionId;18use sp_core::H160;20use sp_core::H160;23 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,25 0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,24];26];252728/// Maps the etherium address of the collection in substrate.26pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {29pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {27 if eth[0..16] != ETH_COLLECTION_PREFIX {30 if eth[0..16] != ETH_COLLECTION_PREFIX {28 return None;31 return None;32 Some(CollectionId(u32::from_be_bytes(id_bytes)))35 Some(CollectionId(u32::from_be_bytes(id_bytes)))33}36}3738/// Maps the substrate collection id in etherium.34pub fn collection_id_to_address(id: CollectionId) -> H160 {39pub fn collection_id_to_address(id: CollectionId) -> H160 {35 let mut out = [0; 20];40 let mut out = [0; 20];36 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);41 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);37 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));42 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));38 H160(out)43 H160(out)39}44}404546/// Check if the etherium address is a collection.41pub fn is_collection(address: &H160) -> bool {47pub fn is_collection(address: &H160) -> bool {42 address[0..16] == ETH_COLLECTION_PREFIX48 address[0..16] == ETH_COLLECTION_PREFIX43}49}pallets/common/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// 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/>.161617//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//! 21//! ## Overview22//! 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//! ### Terminology37//! **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.535455#![warn(missing_docs)]17#![cfg_attr(not(feature = "std"), no_std)]56#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;57extern crate alloc;205821use core::ops::{Deref, DerefMut};59use core::ops::{Deref, DerefMut};90pub mod eth;128pub mod eth;91pub mod weights;129pub mod weights;92130131/// Weight info.93pub type SelfWeightOf<T> = <T as Config>::WeightInfo;132pub type SelfWeightOf<T> = <T as Config>::WeightInfo;94133134/// 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 id97 pub id: CollectionId,139 pub id: CollectionId,98 collection: Collection<T::AccountId>,140 collection: Collection<T::AccountId>,141 /// Substrate recorder for counting consumed gas99 pub recorder: SubstrateRecorder<T>,142 pub recorder: SubstrateRecorder<T>,100}143}144101impl<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.recorder106 self.recorder150 self.recorder107 }151 }108}152}153109impl<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 }117163164 /// 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 }125172173 /// 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 }129178179 /// 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 }133183184 /// 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.recorder136 .consume_gas(T::GasWeightMapping::weight_to_gas(187 .consume_gas(T::GasWeightMapping::weight_to_gas(140 ))191 ))141 }192 }142193194 /// 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.recorder145 .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 }203204 /// 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 }155209210 /// 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 }160219220 /// Confirm sponsorship221 /// 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 }169232170 /// 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 }179242180 /// 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}204267205impl<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 }274275 /// 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 }279280 /// 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 }285286 /// 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 }290291 /// 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 }295296 /// 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 + TypeInfo250 + account::Config324 + account::Config251 {325 {326 /// Weight info.252 type WeightInfo: WeightInfo;327 type WeightInfo: WeightInfo;328329 /// 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>>;254331332 /// Currency.255 type Currency: Currency<Self::AccountId>;333 type Currency: Currency<Self::AccountId>;256334335 /// 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 >;340341 /// Collection dispatcher.261 type CollectionDispatch: CollectionDispatch<Self>;342 type CollectionDispatch: CollectionDispatch<Self>;262343344 /// Treasury account id getter.263 type TreasuryAccountId: Get<Self::AccountId>;345 type TreasuryAccountId: Get<Self::AccountId>;346347 /// Contract address getter.264 type ContractAddress: Get<H160>;348 type ContractAddress: Get<H160>;265349350 /// Mapper for tokens to Etherium addresses.266 type EvmTokenAddressMapping: TokenAddressMapping<H160>;351 type EvmTokenAddressMapping: TokenAddressMapping<H160>;352353 /// Mapper for tokens to [CrossAccountId].267 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;354 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;268 }355 }269356276363277 #[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_LIMIT281 }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 created288 ///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::AccountId383 ),297384298 /// New collection was destroyed385 /// New collection was destroyed299 ///386 CollectionDestroyed(300 /// # Arguments387 /// Globally unique identifier of collection.301 ///302 /// * collection_id: Globally unique identifier of collection.303 CollectionDestroyed(CollectionId),388 CollectionId389 ),304390305 /// 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 item314 ///398 T::CrossAccountId,315 /// * amount: Always 1 for NFT399 /// Always 1 for NFT316 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),400 u128401 ),317402318 /// 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),330413331 /// Item was transferred414 /// Item was transferred332 ///333 /// * collection_id: Id of collection to which item is belong334 ///335 /// * item_id: Id of an item336 ///337 /// * sender: Original owner of item338 ///339 /// * recipient: New owner of item340 ///341 /// * amount: Always 1 for NFT342 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 ),349427350 /// * collection_id428 /// Amount pieces of token owned by `sender` was approved for `spender`.351 ///352 /// * item_id353 ///354 /// * sender355 ///356 /// * spender357 ///358 /// * amount359 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 ),366441367 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 PropertyKey448 ),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 PropertyKey456 ),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 PropertyKey466 ),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 PropertyKey477 ),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 PropertyKey485 ),376 }486 }377487378 #[pallet::error]488 #[pallet::error]460 CollectionIsInternal,570 CollectionIsInternal,461 }571 }462572573 /// 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>;576577 /// 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>;468581469 /// 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 >;477590478 /// 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 >;488601602 /// 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 >;497611612 /// 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 >;527642528 /// 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}620735621impl<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>>::AddressIsZero627 );744 );628 Ok(())745 Ok(())629 }746 }747748 /// 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 }754755 /// 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 }761762 /// 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 }766767 /// 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 }652777778 /// 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 }685811812 /// 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}759886760impl<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 }860992993 /// 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 }88810241025 /// 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 }90610471048 /// 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 }93210831084 /// 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 }99011611162 /// 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 }102011961197 /// 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 }103312141215 /// 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 }104012221223 /// 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 }105112341235 /// 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 }107812621263 /// 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 }110712921293 /// 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 }112613121313 /// 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 }116113481349 /// 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 }120613941395 /// 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}122014091410/// 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}122714171228/// 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;14221423 /// Weight of items creation.1231 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1424 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;14251426 /// Weight of items creation.1232 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1427 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;14281429 /// The weight of the burning item.1233 fn burn_item() -> Weight;1430 fn burn_item() -> Weight;14311432 /// 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;14361437 /// 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;14411442 /// 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;14461447 /// 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;14571458 /// Transfer price of the token or its parts.1239 fn transfer() -> Weight;1459 fn transfer() -> Weight;14601461 /// The price of setting the permission of the operation from another user.1240 fn approve() -> Weight;1462 fn approve() -> Weight;14631464 /// Transfer price from another user.1241 fn transfer_from() -> Weight;1465 fn transfer_from() -> Weight;14661467 /// 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 burn1245 /// whole users's balance1471 /// whole users's balance1246 ///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) instead1248 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 itself1250 ///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) instead1252 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}126014901491/// 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}126414961497/// Common collection operations.1498/// 1499/// It wraps methods in Fungible, Nonfungible and Refungible pallets1500/// 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;15151516 /// 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;15421543 /// 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;15681569 /// 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;15781579 /// 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;15881589 /// 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;16051606 /// 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;16221623 /// 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;16341635 /// 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;16501651 /// 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;136017021703 /// 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;136817161717 /// 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));137017221723 /// 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));137217281729 /// 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>;17331734 /// Get all the tokens in the collection.1374 fn collection_tokens(&self) -> Vec<TokenId>;1735 fn collection_tokens(&self) -> Vec<TokenId>;17361737 /// 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;17411742 /// Get the id of the last minted token.1376 fn last_token_id(&self) -> TokenId;1743 fn last_token_id(&self) -> TokenId;137717441745 /// 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>;17491750 /// 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>;17551380 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>;17621381 /// Amount of unique collection tokens1763 /// Amount of unique collection tokens1382 fn total_supply(&self) -> u32;1764 fn total_supply(&self) -> u32;17651383 /// 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;17701385 /// 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;17731387 /// Amount of token pieces1774 /// Amount of token pieces1388 fn total_pieces(&self, token: TokenId) -> Option<u128>;1775 fn total_pieces(&self, token: TokenId) -> Option<u128>;17761777 /// 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;17881789 /// 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}139717921793/// Extension for RFT collection.1398pub trait RefungibleExtensions<T>1794pub trait RefungibleExtensions<T>1399where1795where1400 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}140918121410// 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),