difftreelog
Merge branch 'develop' into doc/scheduler
in: master
51 files changed
Cargo.lockdiffbeforeafterboth573157315732[[package]]5732[[package]]5733name = "pallet-common"5733name = "pallet-common"5734version = "0.1.0"5734version = "0.1.2"5735dependencies = [5735dependencies = [5736 "ethereum",5736 "ethereum",5737 "evm-coder",5737 "evm-coder",632063206321[[package]]6321[[package]]6322name = "pallet-refungible"6322name = "pallet-refungible"6323version = "0.1.0"6323version = "0.1.1"6324dependencies = [6324dependencies = [6325 "frame-benchmarking",6325 "frame-benchmarking",6326 "frame-support",6326 "frame-support",127331273312734[[package]]12734[[package]]12735name = "up-data-structs"12735name = "up-data-structs"12736version = "0.1.0"12736version = "0.1.1"12737dependencies = [12737dependencies = [12738 "derivative",12738 "derivative",12739 "frame-support",12739 "frame-support",pallets/common/CHANGELOG.MDdiffbeforeafterbothno changes
pallets/common/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-common"2name = "pallet-common"3version = "0.1.0"3version = "0.1.2"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/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 /// Get the implementation of [`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 ethereum 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];465354 /// Call precompiled handle.47 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;55 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;48}56}495758/// @title A contract that allows you to work with collections.50#[solidity_interface(name = "Collection")]59#[solidity_interface(name = "Collection")]51impl<T: Config> CollectionHandle<T>60impl<T: Config> CollectionHandle<T>52where61where53 T::AccountId: From<[u8; 32]>,62 T::AccountId: From<[u8; 32]>,54{63{64 /// Set collection property.65 ///66 /// @param key Property key.67 /// @param value Propery value.55 fn set_collection_property(68 fn set_collection_property(56 &mut self,69 &mut self,57 caller: caller,70 caller: caller,68 .map_err(dispatch_to_evm::<T>)81 .map_err(dispatch_to_evm::<T>)69 }82 }708384 /// Delete collection property.85 ///86 /// @param key Property key.71 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {87 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {72 let caller = T::CrossAccountId::from_eth(caller);88 let caller = T::CrossAccountId::from_eth(caller);73 let key = <Vec<u8>>::from(key)89 let key = <Vec<u8>>::from(key)77 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)93 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)78 }94 }799596 /// Get collection property.97 ///80 /// Throws error if key not found98 /// @dev Throws error if key not found.99 ///100 /// @param key Property key.101 /// @return bytes The property corresponding to the key.81 fn collection_property(&self, key: string) -> Result<bytes> {102 fn collection_property(&self, key: string) -> Result<bytes> {82 let key = <Vec<u8>>::from(key)103 let key = <Vec<u8>>::from(key)83 .try_into()104 .try_into()89 Ok(prop.to_vec())110 Ok(prop.to_vec())90 }111 }91112113 /// Set the sponsor of the collection.114 ///115 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.116 ///117 /// @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> {118 fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {93 check_is_owner_or_admin(caller, self)?;119 check_is_owner_or_admin(caller, self)?;9412098 save(self)124 save(self)99 }125 }100126127 /// Collection sponsorship confirmation.128 ///129 /// @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> {130 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {102 let caller = T::CrossAccountId::from_eth(caller);131 let caller = T::CrossAccountId::from_eth(caller);103 if !self132 if !self109 save(self)138 save(self)110 }139 }111140141 /// Set limits for the collection.142 /// @dev Throws error if limit not found.143 /// @param limit Name of the limit. Valid names:144 /// "accountTokenOwnershipLimit",145 /// "sponsoredDataSize",146 /// "sponsoredDataRateLimit",147 /// "tokenLimit",148 /// "sponsorTransferTimeout",149 /// "sponsorApproveTimeout"150 /// @param value Value of the limit.112 #[solidity(rename_selector = "setCollectionLimit")]151 #[solidity(rename_selector = "setCollectionLimit")]113 fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {152 fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {114 check_is_owner_or_admin(caller, self)?;153 check_is_owner_or_admin(caller, self)?;145 save(self)184 save(self)146 }185 }147186187 /// Set limits for the collection.188 /// @dev Throws error if limit not found.189 /// @param limit Name of the limit. Valid names:190 /// "ownerCanTransfer",191 /// "ownerCanDestroy",192 /// "transfersEnabled"193 /// @param value Value of the limit.148 #[solidity(rename_selector = "setCollectionLimit")]194 #[solidity(rename_selector = "setCollectionLimit")]149 fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {195 fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {150 check_is_owner_or_admin(caller, self)?;196 check_is_owner_or_admin(caller, self)?;172 save(self)218 save(self)173 }219 }174220221 /// Get contract address.175 fn contract_address(&self, _caller: caller) -> Result<address> {222 fn contract_address(&self, _caller: caller) -> Result<address> {176 Ok(crate::eth::collection_id_to_address(self.id))223 Ok(crate::eth::collection_id_to_address(self.id))177 }224 }178225226 /// Add collection admin by substrate address.227 /// @param new_admin Substrate administrator address.179 fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {228 fn add_collection_admin_substrate(229 &mut self,230 caller: caller,231 new_admin: uint256,232 ) -> Result<void> {180 let caller = T::CrossAccountId::from_eth(caller);233 let caller = T::CrossAccountId::from_eth(caller);181 let mut new_admin_arr: [u8; 32] = Default::default();234 let mut new_admin_arr: [u8; 32] = Default::default();186 Ok(())239 Ok(())187 }240 }188241242 /// Remove collection admin by substrate address.243 /// @param admin Substrate administrator address.189 fn remove_collection_admin_substrate(244 fn remove_collection_admin_substrate(190 &self,245 &mut self,191 caller: caller,246 caller: caller,192 new_admin: uint256,247 admin: uint256,193 ) -> Result<void> {248 ) -> Result<void> {194 let caller = T::CrossAccountId::from_eth(caller);249 let caller = T::CrossAccountId::from_eth(caller);195 let mut new_admin_arr: [u8; 32] = Default::default();250 let mut admin_arr: [u8; 32] = Default::default();196 new_admin.to_big_endian(&mut new_admin_arr);251 admin.to_big_endian(&mut admin_arr);197 let account_id = T::AccountId::from(new_admin_arr);252 let account_id = T::AccountId::from(admin_arr);198 let new_admin = T::CrossAccountId::from_sub(account_id);253 let admin = T::CrossAccountId::from_sub(account_id);199 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)254 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;200 .map_err(dispatch_to_evm::<T>)?;201 Ok(())255 Ok(())202 }256 }203257258 /// Add collection admin.259 /// @param new_admin Address of the added administrator.204 fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {260 fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {205 let caller = T::CrossAccountId::from_eth(caller);261 let caller = T::CrossAccountId::from_eth(caller);206 let new_admin = T::CrossAccountId::from_eth(new_admin);262 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>)?;263 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;208 Ok(())264 Ok(())209 }265 }210266267 /// Remove collection admin.268 ///269 /// @param new_admin Address of the removed administrator.211 fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {270 fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {212 let caller = T::CrossAccountId::from_eth(caller);271 let caller = T::CrossAccountId::from_eth(caller);213 let admin = T::CrossAccountId::from_eth(admin);272 let admin = T::CrossAccountId::from_eth(admin);214 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;273 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;215 Ok(())274 Ok(())216 }275 }217276277 /// Toggle accessibility of collection nesting.278 ///279 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'218 #[solidity(rename_selector = "setCollectionNesting")]280 #[solidity(rename_selector = "setCollectionNesting")]219 fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {281 fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {220 check_is_owner_or_admin(caller, self)?;282 check_is_owner_or_admin(caller, self)?;235 save(self)297 save(self)236 }298 }237299300 /// Toggle accessibility of collection nesting.301 ///302 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'303 /// @param collections Addresses of collections that will be available for nesting.238 #[solidity(rename_selector = "setCollectionNesting")]304 #[solidity(rename_selector = "setCollectionNesting")]239 fn set_nesting(305 fn set_nesting(240 &mut self,306 &mut self,280 save(self)346 save(self)281 }347 }282348349 /// Set the collection access method.350 /// @param mode Access mode351 /// 0 for Normal352 /// 1 for AllowList283 fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {353 fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {284 check_is_owner_or_admin(caller, self)?;354 check_is_owner_or_admin(caller, self)?;285 let permissions = CollectionPermissions {355 let permissions = CollectionPermissions {300 save(self)370 save(self)301 }371 }302372373 /// Add the user to the allowed list.374 ///375 /// @param user Address of a trusted user.303 fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {376 fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {304 let caller = T::CrossAccountId::from_eth(caller);377 let caller = T::CrossAccountId::from_eth(caller);305 let user = T::CrossAccountId::from_eth(user);378 let user = T::CrossAccountId::from_eth(user);306 <Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;379 <Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;307 Ok(())380 Ok(())308 }381 }309382383 /// Remove the user from the allowed list.384 ///385 /// @param user Address of a removed user.310 fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {386 fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {311 let caller = T::CrossAccountId::from_eth(caller);387 let caller = T::CrossAccountId::from_eth(caller);312 let user = T::CrossAccountId::from_eth(user);388 let user = T::CrossAccountId::from_eth(user);313 <Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;389 <Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;314 Ok(())390 Ok(())315 }391 }316392393 /// Switch permission for minting.394 ///395 /// @param mode Enable if "true".317 fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {396 fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {318 check_is_owner_or_admin(caller, self)?;397 check_is_owner_or_admin(caller, self)?;319 let permissions = CollectionPermissions {398 let permissions = CollectionPermissions {351 Ok(())430 Ok(())352}431}353432433/// Get the "tokenURI" key as [PropertyKey](up_data_structs::PropertyKey).354pub fn token_uri_key() -> up_data_structs::PropertyKey {434pub fn token_uri_key() -> up_data_structs::PropertyKey {355 b"tokenURI"435 b"tokenURI"356 .to_vec()436 .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 ethereum 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 ethereum 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 ethereum.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 ethereum 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 an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]17#![cfg_attr(not(feature = "std"), no_std)]53#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;54extern crate alloc;205521use core::ops::{Deref, DerefMut};56use core::ops::{Deref, DerefMut};90pub mod eth;125pub mod eth;91pub mod weights;126pub mod weights;92127128/// Weight info.93pub type SelfWeightOf<T> = <T as Config>::WeightInfo;129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;94130131/// Collection handle contains information about collection data and id.132/// Also provides functionality to count consumed gas.133///134/// CollectionHandle is used as a generic wrapper for collections of all types.135/// It allows to perform common operations and queries on any collection type,136/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].95#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]137#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]96pub struct CollectionHandle<T: Config> {138pub struct CollectionHandle<T: Config> {139 /// Collection id97 pub id: CollectionId,140 pub id: CollectionId,98 collection: Collection<T::AccountId>,141 collection: Collection<T::AccountId>,142 /// Substrate recorder for counting consumed gas99 pub recorder: SubstrateRecorder<T>,143 pub recorder: SubstrateRecorder<T>,100}144}145101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {146impl<T: Config> WithRecorder<T> for CollectionHandle<T> {102 fn recorder(&self) -> &SubstrateRecorder<T> {147 fn recorder(&self) -> &SubstrateRecorder<T> {103 &self.recorder148 &self.recorder106 self.recorder151 self.recorder107 }152 }108}153}154109impl<T: Config> CollectionHandle<T> {155impl<T: Config> CollectionHandle<T> {156 /// Same as [CollectionHandle::new] but with an explicit gas limit.110 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {157 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {111 <CollectionById<T>>::get(id).map(|collection| Self {158 <CollectionById<T>>::get(id).map(|collection| Self {112 id,159 id,115 })162 })116 }163 }117164165 /// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].118 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {166 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {119 <CollectionById<T>>::get(id).map(|collection| Self {167 <CollectionById<T>>::get(id).map(|collection| Self {120 id,168 id,123 })171 })124 }172 }125173174 /// Retrives collection data from storage and creates collection handle with default parameters.175 /// If collection not found return `None`126 pub fn new(id: CollectionId) -> Option<Self> {176 pub fn new(id: CollectionId) -> Option<Self> {127 Self::new_with_gas_limit(id, u64::MAX)177 Self::new_with_gas_limit(id, u64::MAX)128 }178 }129179180 /// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.130 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {181 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {131 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)182 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)132 }183 }133184185 /// Consume gas for reading.134 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {186 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {135 self.recorder187 self.recorder136 .consume_gas(T::GasWeightMapping::weight_to_gas(188 .consume_gas(T::GasWeightMapping::weight_to_gas(140 ))192 ))141 }193 }142194195 /// Consume gas for writing.143 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {196 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {144 self.recorder197 self.recorder145 .consume_gas(T::GasWeightMapping::weight_to_gas(198 .consume_gas(T::GasWeightMapping::weight_to_gas(148 .saturating_mul(writes),201 .saturating_mul(writes),149 ))202 ))150 }203 }204205 /// Save collection to storage.151 pub fn save(self) -> DispatchResult {206 pub fn save(self) -> DispatchResult {152 <CollectionById<T>>::insert(self.id, self.collection);207 <CollectionById<T>>::insert(self.id, self.collection);153 Ok(())208 Ok(())154 }209 }155210211 /// Set collection sponsor.212 ///213 /// Unique collections allows sponsoring for certain actions.214 /// This method allows you to set the sponsor of the collection.215 /// 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 {216 pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {157 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);217 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);158 Ok(())218 Ok(())159 }219 }160220221 /// Confirm sponsorship222 ///223 /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.224 /// 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> {225 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result<bool, DispatchError> {162 if self.collection.sponsorship.pending_sponsor() != Some(sender) {226 if self.collection.sponsorship.pending_sponsor() != Some(sender) {163 return Ok(false);227 return Ok(false);168 }232 }169233170 /// Checks that the collection was created with, and must be operated upon through **Unique API**.234 /// 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.235 /// 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 {236 pub fn check_is_internal(&self) -> DispatchResult {173 if self.external_collection {237 if self.external_collection {174 return Err(<Error<T>>::CollectionIsExternal)?;238 return Err(<Error<T>>::CollectionIsExternal)?;178 }242 }179243180 /// Checks that the collection was created with, and must be operated upon through an **assimilated API**.244 /// 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.245 /// 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 {246 pub fn check_is_external(&self) -> DispatchResult {183 if !self.external_collection {247 if !self.external_collection {184 return Err(<Error<T>>::CollectionIsInternal)?;248 return Err(<Error<T>>::CollectionIsInternal)?;203}267}204268205impl<T: Config> CollectionHandle<T> {269impl<T: Config> CollectionHandle<T> {206 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {270 /// Checks if the `user` is the owner of the collection.271 pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {207 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);272 ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);208 Ok(())273 Ok(())209 }274 }275276 /// 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 {277 pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {211 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))278 *user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))212 }279 }280281 /// 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 {282 pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {214 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);283 ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);215 Ok(())284 Ok(())216 }285 }286287 /// 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 {288 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {218 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)289 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)219 }290 }291292 /// 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 {293 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {221 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)294 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)222 }295 }296297 /// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.223 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {298 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {224 ensure!(299 ensure!(225 <Allowlist<T>>::get((self.id, user)),300 <Allowlist<T>>::get((self.id, user)),249 + TypeInfo324 + TypeInfo250 + account::Config325 + account::Config251 {326 {327 /// Weight information for functions of this pallet.252 type WeightInfo: WeightInfo;328 type WeightInfo: WeightInfo;329330 /// Events compatible with [`frame_system::Config::Event`].253 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;331 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;254332333 /// Handler of accounts and payment.255 type Currency: Currency<Self::AccountId>;334 type Currency: Currency<Self::AccountId>;256335336 /// Set price to create a collection.257 #[pallet::constant]337 #[pallet::constant]258 type CollectionCreationPrice: Get<338 type CollectionCreationPrice: Get<259 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,339 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,260 >;340 >;341342 /// Dispatcher of operations on collections.261 type CollectionDispatch: CollectionDispatch<Self>;343 type CollectionDispatch: CollectionDispatch<Self>;262344345 /// Account which holds the chain's treasury.263 type TreasuryAccountId: Get<Self::AccountId>;346 type TreasuryAccountId: Get<Self::AccountId>;347348 /// Address under which the CollectionHelper contract would be available.264 type ContractAddress: Get<H160>;349 type ContractAddress: Get<H160>;265350351 /// Mapper for token addresses to Ethereum addresses.266 type EvmTokenAddressMapping: TokenAddressMapping<H160>;352 type EvmTokenAddressMapping: TokenAddressMapping<H160>;353354 /// Mapper for token addresses to [`CrossAccountId`].267 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;355 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;268 }356 }269357276364277 #[pallet::extra_constants]365 #[pallet::extra_constants]278 impl<T: Config> Pallet<T> {366 impl<T: Config> Pallet<T> {367 /// Maximum admins per collection.279 pub fn collection_admins_limit() -> u32 {368 pub fn collection_admins_limit() -> u32 {280 COLLECTION_ADMINS_LIMIT369 COLLECTION_ADMINS_LIMIT281 }370 }285 #[pallet::generate_deposit(pub fn deposit_event)]374 #[pallet::generate_deposit(pub fn deposit_event)]286 pub enum Event<T: Config> {375 pub enum Event<T: Config> {287 /// New collection was created376 /// New collection was created288 ///377 CollectionCreated(289 /// # Arguments378 /// Globally unique identifier of newly created collection.290 ///291 /// * collection_id: Globally unique identifier of newly created collection.292 ///379 CollectionId,293 /// * mode: [CollectionMode] converted into u8.380 /// [`CollectionMode`] converted into _u8_.294 ///381 u8,295 /// * account_id: Collection owner.382 /// Collection owner.296 CollectionCreated(CollectionId, u8, T::AccountId),383 T::AccountId,384 ),297385298 /// New collection was destroyed386 /// New collection was destroyed299 ///387 CollectionDestroyed(300 /// # Arguments388 /// Globally unique identifier of collection.301 ///302 /// * collection_id: Globally unique identifier of collection.303 CollectionDestroyed(CollectionId),389 CollectionId,390 ),304391305 /// New item was created.392 /// New item was created.306 ///393 ItemCreated(307 /// # Arguments394 /// Id of the collection where item was created.308 ///309 /// * collection_id: Id of the collection where item was created.310 ///395 CollectionId,311 /// * item_id: Id of an item. Unique within the collection.396 /// Id of an item. Unique within the collection.312 ///397 TokenId,313 /// * recipient: Owner of newly created item398 /// Owner of newly created item314 ///399 T::CrossAccountId,315 /// * amount: Always 1 for NFT400 /// Always 1 for NFT316 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),401 u128,402 ),317403318 /// Collection item was burned.404 /// Collection item was burned.319 ///405 ItemDestroyed(320 /// # Arguments406 /// Id of the collection where item was destroyed.321 ///322 /// * collection_id.323 ///407 CollectionId,324 /// * item_id: Identifier of burned NFT.408 /// Identifier of burned NFT.325 ///409 TokenId,326 /// * owner: which user has destroyed its tokens410 /// Which user has destroyed its tokens.327 ///411 T::CrossAccountId,328 /// * amount: Always 1 for NFT412 /// Amount of token pieces destroed. Always 1 for NFT.329 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),413 u128,414 ),330415331 /// Item was transferred416 /// 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(417 Transfer(418 /// Id of collection to which item is belong.343 CollectionId,419 CollectionId,420 /// Id of an item.344 TokenId,421 TokenId,422 /// Original owner of item.345 T::CrossAccountId,423 T::CrossAccountId,424 /// New owner of item.346 T::CrossAccountId,425 T::CrossAccountId,426 /// Amount of token pieces transfered. Always 1 for NFT.347 u128,427 u128,348 ),428 ),349429350 /// * collection_id430 /// Amount pieces of token owned by `sender` was approved for `spender`.351 ///352 /// * item_id353 ///354 /// * sender355 ///356 /// * spender357 ///358 /// * amount359 Approved(431 Approved(432 /// Id of collection to which item is belong.360 CollectionId,433 CollectionId,434 /// Id of an item.361 TokenId,435 TokenId,436 /// Original owner of item.362 T::CrossAccountId,437 T::CrossAccountId,438 /// Id for which the approval was granted.363 T::CrossAccountId,439 T::CrossAccountId,440 /// Amount of token pieces transfered. Always 1 for NFT.364 u128,441 u128,365 ),442 ),366443367 CollectionPropertySet(CollectionId, PropertyKey),444 /// The colletion property has been set.445 CollectionPropertySet(446 /// Id of collection to which property has been set.447 CollectionId,448 /// The property that was set.449 PropertyKey,450 ),368451369 CollectionPropertyDeleted(CollectionId, PropertyKey),452 /// The property has been deleted.453 CollectionPropertyDeleted(454 /// Id of collection to which property has been deleted.455 CollectionId,456 /// The property that was deleted.457 PropertyKey,458 ),370459371 TokenPropertySet(CollectionId, TokenId, PropertyKey),460 /// The token property has been set.461 TokenPropertySet(462 /// Identifier of the collection whose token has the property set.463 CollectionId,464 /// The token for which the property was set.465 TokenId,466 /// The property that was set.467 PropertyKey,468 ),372469373 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),470 /// The token property has been deleted.471 TokenPropertyDeleted(472 /// Identifier of the collection whose token has the property deleted.473 CollectionId,474 /// The token for which the property was deleted.475 TokenId,476 /// The property that was deleted.477 PropertyKey,478 ),374479375 PropertyPermissionSet(CollectionId, PropertyKey),480 /// The colletion property permission has been set.481 PropertyPermissionSet(482 /// Id of collection to which property permission has been set.483 CollectionId,484 /// The property permission that was set.485 PropertyKey,486 ),376 }487 }377488378 #[pallet::error]489 #[pallet::error]460 CollectionIsInternal,571 CollectionIsInternal,461 }572 }462573574 /// Storage of the count of created collections.463 #[pallet::storage]575 #[pallet::storage]464 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;576 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;577578 /// Storage of the count of deleted collections.465 #[pallet::storage]579 #[pallet::storage]466 pub type DestroyedCollectionCount<T> =580 pub type DestroyedCollectionCount<T> =467 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;581 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;468582469 /// Collection info583 /// Storage of collection info.470 #[pallet::storage]584 #[pallet::storage]471 pub type CollectionById<T> = StorageMap<585 pub type CollectionById<T> = StorageMap<472 Hasher = Blake2_128Concat,586 Hasher = Blake2_128Concat,475 QueryKind = OptionQuery,589 QueryKind = OptionQuery,476 >;590 >;477591478 /// Collection properties592 /// Storage of collection properties.479 #[pallet::storage]593 #[pallet::storage]480 #[pallet::getter(fn collection_properties)]594 #[pallet::getter(fn collection_properties)]481 pub type CollectionProperties<T> = StorageMap<595 pub type CollectionProperties<T> = StorageMap<486 OnEmpty = up_data_structs::CollectionProperties,600 OnEmpty = up_data_structs::CollectionProperties,487 >;601 >;488602603 /// Storage of collection properties permissions.489 #[pallet::storage]604 #[pallet::storage]490 #[pallet::getter(fn property_permissions)]605 #[pallet::getter(fn property_permissions)]491 pub type CollectionPropertyPermissions<T> = StorageMap<606 pub type CollectionPropertyPermissions<T> = StorageMap<495 QueryKind = ValueQuery,610 QueryKind = ValueQuery,496 >;611 >;497612613 /// Storage of collection admins count.498 #[pallet::storage]614 #[pallet::storage]499 pub type AdminAmount<T> = StorageMap<615 pub type AdminAmount<T> = StorageMap<500 Hasher = Blake2_128Concat,616 Hasher = Blake2_128Concat,525 QueryKind = ValueQuery,641 QueryKind = ValueQuery,526 >;642 >;527643528 /// Not used by code, exists only to provide some types to metadata644 /// Not used by code, exists only to provide some types to metadata.529 #[pallet::storage]645 #[pallet::storage]530 pub type DummyStorageValue<T: Config> = StorageValue<646 pub type DummyStorageValue<T: Config> = StorageValue<531 Value = (647 Value = (619}735}620736621impl<T: Config> Pallet<T> {737impl<T: Config> Pallet<T> {622 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens738 /// Enshure that receiver address is correct.739 ///740 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.623 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {741 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {624 ensure!(742 ensure!(625 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,743 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,626 <Error<T>>::AddressIsZero744 <Error<T>>::AddressIsZero627 );745 );628 Ok(())746 Ok(())629 }747 }748749 /// Get a vector of collection admins.630 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {750 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {631 <IsAdmin<T>>::iter_prefix((collection,))751 <IsAdmin<T>>::iter_prefix((collection,))632 .map(|(a, _)| a)752 .map(|(a, _)| a)633 .collect()753 .collect()634 }754 }755756 /// Get a vector of users allowed to mint tokens.635 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {757 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {636 <Allowlist<T>>::iter_prefix((collection,))758 <Allowlist<T>>::iter_prefix((collection,))637 .map(|(a, _)| a)759 .map(|(a, _)| a)638 .collect()760 .collect()639 }761 }762763 /// Is `user` allowed to mint token in `collection`.640 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {764 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {641 <Allowlist<T>>::get((collection, user))765 <Allowlist<T>>::get((collection, user))642 }766 }767768 /// Get statistics of collections.643 pub fn collection_stats() -> CollectionStats {769 pub fn collection_stats() -> CollectionStats {644 let created = <CreatedCollectionCount<T>>::get();770 let created = <CreatedCollectionCount<T>>::get();645 let destroyed = <DestroyedCollectionCount<T>>::get();771 let destroyed = <DestroyedCollectionCount<T>>::get();650 }776 }651 }777 }652778779 /// Get the effective limits for the collection.653 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {780 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {654 let collection = <CollectionById<T>>::get(collection);781 let collection = <CollectionById<T>>::get(collection);655 if collection.is_none() {782 if collection.is_none() {683 Some(effective_limits)810 Some(effective_limits)684 }811 }685812813 /// Returns information about the `collection` adapted for rpc.686 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {814 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {687 let Collection {815 let Collection {688 name,816 name,758}886}759887760impl<T: Config> Pallet<T> {888impl<T: Config> Pallet<T> {889 /// Create new collection.890 ///891 /// * `owner` - The owner of the collection.892 /// * `data` - Description of the created collection.893 /// * `is_external` - Marks that collection managet by not "Unique network".761 pub fn init_collection(894 pub fn init_collection(762 owner: T::CrossAccountId,895 owner: T::CrossAccountId,763 data: CreateCollectionData<T::AccountId>,896 data: CreateCollectionData<T::AccountId>,833 ),966 ),834 );967 );835 <T as Config>::Currency::settle(968 <T as Config>::Currency::settle(836 &owner.as_sub(),969 owner.as_sub(),837 imbalance,970 imbalance,838 WithdrawReasons::TRANSFER,971 WithdrawReasons::TRANSFER,839 ExistenceRequirement::KeepAlive,972 ExistenceRequirement::KeepAlive,858 Ok(id)991 Ok(id)859 }992 }860993994 /// Destroy collection.995 ///996 /// * `collection` - Collection handler.997 /// * `sender` - The owner or administrator of the collection.861 pub fn destroy_collection(998 pub fn destroy_collection(862 collection: CollectionHandle<T>,999 collection: CollectionHandle<T>,863 sender: &T::CrossAccountId,1000 sender: &T::CrossAccountId,886 Ok(())1023 Ok(())887 }1024 }88810251026 /// Set collection property.1027 ///1028 /// * `collection` - Collection handler.1029 /// * `sender` - The owner or administrator of the collection.1030 /// * `property` - The property to set.889 pub fn set_collection_property(1031 pub fn set_collection_property(890 collection: &CollectionHandle<T>,1032 collection: &CollectionHandle<T>,891 sender: &T::CrossAccountId,1033 sender: &T::CrossAccountId,904 Ok(())1046 Ok(())905 }1047 }90610481049 /// Set scouped collection property.1050 ///1051 /// * `collection_id` - ID of the collection for which the property is being set.1052 /// * `scope` - Property scope.1053 /// * `property` - The property to set.907 pub fn set_scoped_collection_property(1054 pub fn set_scoped_collection_property(908 collection_id: CollectionId,1055 collection_id: CollectionId,909 scope: PropertyScope,1056 scope: PropertyScope,917 Ok(())1064 Ok(())918 }1065 }91910661067 /// Set scouped collection properties.1068 ///1069 /// * `collection_id` - ID of the collection for which the properties is being set.1070 /// * `scope` - Property scope.1071 /// * `properties` - The properties to set.920 pub fn set_scoped_collection_properties(1072 pub fn set_scoped_collection_properties(921 collection_id: CollectionId,1073 collection_id: CollectionId,922 scope: PropertyScope,1074 scope: PropertyScope,930 Ok(())1082 Ok(())931 }1083 }93210841085 /// Set collection properties.1086 ///1087 /// * `collection` - Collection handler.1088 /// * `sender` - The owner or administrator of the collection.1089 /// * `properties` - The properties to set.933 #[transactional]1090 #[transactional]934 pub fn set_collection_properties(1091 pub fn set_collection_properties(935 collection: &CollectionHandle<T>,1092 collection: &CollectionHandle<T>,943 Ok(())1100 Ok(())944 }1101 }94511021103 /// Delete collection property.1104 ///1105 /// * `collection` - Collection handler.1106 /// * `sender` - The owner or administrator of the collection.1107 /// * `property` - The property to delete.946 pub fn delete_collection_property(1108 pub fn delete_collection_property(947 collection: &CollectionHandle<T>,1109 collection: &CollectionHandle<T>,948 sender: &T::CrossAccountId,1110 sender: &T::CrossAccountId,963 Ok(())1125 Ok(())964 }1126 }96511271128 /// Delete collection properties.1129 ///1130 /// * `collection` - Collection handler.1131 /// * `sender` - The owner or administrator of the collection.1132 /// * `properties` - The properties to delete.966 #[transactional]1133 #[transactional]967 pub fn delete_collection_properties(1134 pub fn delete_collection_properties(968 collection: &CollectionHandle<T>,1135 collection: &CollectionHandle<T>,976 Ok(())1143 Ok(())977 }1144 }9781145979 // For migrations1146 /// Set collection propetry permission without any checks.1147 ///1148 /// Used for migrations.1149 ///1150 /// * `collection` - Collection handler.1151 /// * `property_permissions` - Property permissions.980 pub fn set_property_permission_unchecked(1152 pub fn set_property_permission_unchecked(981 collection: CollectionId,1153 collection: CollectionId,982 property_permission: PropertyKeyPermission,1154 property_permission: PropertyKeyPermission,988 Ok(())1160 Ok(())989 }1161 }99011621163 /// Set collection property permission.1164 ///1165 /// * `collection` - Collection handler.1166 /// * `sender` - The owner or administrator of the collection.1167 /// * `property_permission` - Property permission.991 pub fn set_property_permission(1168 pub fn set_property_permission(992 collection: &CollectionHandle<T>,1169 collection: &CollectionHandle<T>,993 sender: &T::CrossAccountId,1170 sender: &T::CrossAccountId,1018 Ok(())1195 Ok(())1019 }1196 }102011971198 /// Set token property permission.1199 ///1200 /// * `collection` - Collection handler.1201 /// * `sender` - The owner or administrator of the collection.1202 /// * `property_permissions` - Property permissions.1021 #[transactional]1203 #[transactional]1022 pub fn set_token_property_permissions(1204 pub fn set_token_property_permissions(1023 collection: &CollectionHandle<T>,1205 collection: &CollectionHandle<T>,1031 Ok(())1213 Ok(())1032 }1214 }103312151216 /// Get collection property.1034 pub fn get_collection_property(1217 pub fn get_collection_property(1035 collection_id: CollectionId,1218 collection_id: CollectionId,1036 key: &PropertyKey,1219 key: &PropertyKey,1037 ) -> Option<PropertyValue> {1220 ) -> Option<PropertyValue> {1038 Self::collection_properties(collection_id).get(key).cloned()1221 Self::collection_properties(collection_id).get(key).cloned()1039 }1222 }104012231224 /// Convert byte vector to property key vector.1041 pub fn bytes_keys_to_property_keys(1225 pub fn bytes_keys_to_property_keys(1042 keys: Vec<Vec<u8>>,1226 keys: Vec<Vec<u8>>,1043 ) -> Result<Vec<PropertyKey>, DispatchError> {1227 ) -> Result<Vec<PropertyKey>, DispatchError> {1049 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1233 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1050 }1234 }105112351236 /// Get properties according to given keys.1052 pub fn filter_collection_properties(1237 pub fn filter_collection_properties(1053 collection_id: CollectionId,1238 collection_id: CollectionId,1054 keys: Option<Vec<PropertyKey>>,1239 keys: Option<Vec<PropertyKey>>,1076 Ok(properties)1261 Ok(properties)1077 }1262 }107812631264 /// Get property permissions according to given keys.1079 pub fn filter_property_permissions(1265 pub fn filter_property_permissions(1080 collection_id: CollectionId,1266 collection_id: CollectionId,1081 keys: Option<Vec<PropertyKey>>,1267 keys: Option<Vec<PropertyKey>>,1105 Ok(key_permissions)1291 Ok(key_permissions)1106 }1292 }110712931294 /// Toggle `user` participation in the `collection`'s allow list.1108 pub fn toggle_allowlist(1295 pub fn toggle_allowlist(1109 collection: &CollectionHandle<T>,1296 collection: &CollectionHandle<T>,1110 sender: &T::CrossAccountId,1297 sender: &T::CrossAccountId,1124 Ok(())1311 Ok(())1125 }1312 }112613131314 /// Toggle `user` participation in the `collection`'s admin list.1127 pub fn toggle_admin(1315 pub fn toggle_admin(1128 collection: &CollectionHandle<T>,1316 collection: &CollectionHandle<T>,1129 sender: &T::CrossAccountId,1317 sender: &T::CrossAccountId,1159 Ok(())1347 Ok(())1160 }1348 }116113491350 /// Merge set fields from `new_limit` to `old_limit`.1162 pub fn clamp_limits(1351 pub fn clamp_limits(1163 mode: CollectionMode,1352 mode: CollectionMode,1164 old_limit: &CollectionLimits,1353 old_limit: &CollectionLimits,1204 Ok(new_limit)1393 Ok(new_limit)1205 }1394 }120613951396 /// Merge set fields from `new_permission` to `old_permission`.1207 pub fn clamp_permissions(1397 pub fn clamp_permissions(1208 _mode: CollectionMode,1398 _mode: CollectionMode,1209 old_limit: &CollectionPermissions,1399 old_permission: &CollectionPermissions,1210 mut new_limit: CollectionPermissions,1400 mut new_permission: CollectionPermissions,1211 ) -> Result<CollectionPermissions, DispatchError> {1401 ) -> Result<CollectionPermissions, DispatchError> {1212 limit_default_clone!(old_limit, new_limit,1402 limit_default_clone!(old_permission, new_permission,1213 access => {},1403 access => {},1214 mint_mode => {},1404 mint_mode => {},1215 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1405 nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1216 );1406 );1217 Ok(new_limit)1407 Ok(new_permission)1218 }1408 }1219}1409}122014101411/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1221#[macro_export]1412#[macro_export]1222macro_rules! unsupported {1413macro_rules! unsupported {1223 () => {1414 () => {1224 Err(<Error<T>>::UnsupportedOperation.into())1415 Err(<Error<T>>::UnsupportedOperation.into())1225 };1416 };1226}1417}122714181228/// Worst cases1419/// Return weights for various worst-case operations.1229pub trait CommonWeightInfo<CrossAccountId> {1420pub trait CommonWeightInfo<CrossAccountId> {1421 /// Weight of item creation.1230 fn create_item() -> Weight;1422 fn create_item() -> Weight;14231424 /// Weight of items creation.1231 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1425 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;14261427 /// Weight of items creation.1232 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1428 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;14291430 /// The weight of the burning item.1233 fn burn_item() -> Weight;1431 fn burn_item() -> Weight;14321433 /// Property setting weight.1434 ///1435 /// * `amount`- The number of properties to set.1234 fn set_collection_properties(amount: u32) -> Weight;1436 fn set_collection_properties(amount: u32) -> Weight;14371438 /// Collection property deletion weight.1439 ///1440 /// * `amount`- The number of properties to set.1235 fn delete_collection_properties(amount: u32) -> Weight;1441 fn delete_collection_properties(amount: u32) -> Weight;14421443 /// Token property setting weight.1444 ///1445 /// * `amount`- The number of properties to set.1236 fn set_token_properties(amount: u32) -> Weight;1446 fn set_token_properties(amount: u32) -> Weight;14471448 /// Token property deletion weight.1449 ///1450 /// * `amount`- The number of properties to delete.1237 fn delete_token_properties(amount: u32) -> Weight;1451 fn delete_token_properties(amount: u32) -> Weight;14521453 /// 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;124314691244 /// 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 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) instead1248 fn burn_recursively_self_raw() -> Weight;1474 fn burn_recursively_self_raw() -> Weight;14751249 /// 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) instead1252 fn burn_recursively_breadth_raw(amount: u32) -> Weight;1479 fn burn_recursively_breadth_raw(amount: u32) -> Weight;125314801481 /// The price of recursive burning a token.1482 ///1483 /// `max_selfs` - The maximum burning weight of the token itself.1484 /// `max_breadth` - The maximum number of nested tokens to burn.1254 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1485 fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1255 Self::burn_recursively_self_raw()1486 Self::burn_recursively_self_raw()1256 .saturating_mul(max_selfs.max(1) as u64)1487 .saturating_mul(max_selfs.max(1) as u64)1257 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1488 .saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1258 }1489 }1259}1490}126014911492/// Weight info extension trait for refungible pallet.1261pub trait RefungibleExtensionsWeightInfo {1493pub trait RefungibleExtensionsWeightInfo {1494 /// Weight of token repartition.1262 fn repartition() -> Weight;1495 fn repartition() -> Weight;1263}1496}126414971498/// Common collection operations.1499///1500/// It wraps methods in Fungible, Nonfungible and Refungible pallets1501/// and adds weight info.1265pub trait CommonCollectionOperations<T: Config> {1502pub trait CommonCollectionOperations<T: Config> {1503 /// Create token.1504 ///1505 /// * `sender` - The user who mint the token and pays for the transaction.1506 /// * `to` - The user who will own the token.1507 /// * `data` - Token data.1508 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1266 fn create_item(1509 fn create_item(1267 &self,1510 &self,1268 sender: T::CrossAccountId,1511 sender: T::CrossAccountId,1269 to: T::CrossAccountId,1512 to: T::CrossAccountId,1270 data: CreateItemData,1513 data: CreateItemData,1271 nesting_budget: &dyn Budget,1514 nesting_budget: &dyn Budget,1272 ) -> DispatchResultWithPostInfo;1515 ) -> DispatchResultWithPostInfo;15161517 /// Create multiple tokens.1518 ///1519 /// * `sender` - The user who mint the token and pays for the transaction.1520 /// * `to` - The user who will own the token.1521 /// * `data` - Token data.1522 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1273 fn create_multiple_items(1523 fn create_multiple_items(1274 &self,1524 &self,1275 sender: T::CrossAccountId,1525 sender: T::CrossAccountId,1276 to: T::CrossAccountId,1526 to: T::CrossAccountId,1277 data: Vec<CreateItemData>,1527 data: Vec<CreateItemData>,1278 nesting_budget: &dyn Budget,1528 nesting_budget: &dyn Budget,1279 ) -> DispatchResultWithPostInfo;1529 ) -> DispatchResultWithPostInfo;15301531 /// Create multiple tokens.1532 ///1533 /// * `sender` - The user who mint the token and pays for the transaction.1534 /// * `to` - The user who will own the token.1535 /// * `data` - Token data.1536 /// * `nesting_budget` - A budget that can be spent on nesting tokens.1280 fn create_multiple_items_ex(1537 fn create_multiple_items_ex(1281 &self,1538 &self,1282 sender: T::CrossAccountId,1539 sender: T::CrossAccountId,1283 data: CreateItemExData<T::CrossAccountId>,1540 data: CreateItemExData<T::CrossAccountId>,1284 nesting_budget: &dyn Budget,1541 nesting_budget: &dyn Budget,1285 ) -> DispatchResultWithPostInfo;1542 ) -> DispatchResultWithPostInfo;15431544 /// Burn token.1545 ///1546 /// * `sender` - The user who owns the token.1547 /// * `token` - Token id that will burned.1548 /// * `amount` - The number of parts of the token that will be burned.1286 fn burn_item(1549 fn burn_item(1287 &self,1550 &self,1288 sender: T::CrossAccountId,1551 sender: T::CrossAccountId,1289 token: TokenId,1552 token: TokenId,1290 amount: u128,1553 amount: u128,1291 ) -> DispatchResultWithPostInfo;1554 ) -> DispatchResultWithPostInfo;15551556 /// Burn token and all nested tokens recursievly.1557 ///1558 /// * `sender` - The user who owns the token.1559 /// * `token` - Token id that will burned.1560 /// * `self_budget` - The budget that can be spent on burning tokens.1561 /// * `breadth_budget` - The budget that can be spent on burning nested tokens.1292 fn burn_item_recursively(1562 fn burn_item_recursively(1293 &self,1563 &self,1294 sender: T::CrossAccountId,1564 sender: T::CrossAccountId,1295 token: TokenId,1565 token: TokenId,1296 self_budget: &dyn Budget,1566 self_budget: &dyn Budget,1297 breadth_budget: &dyn Budget,1567 breadth_budget: &dyn Budget,1298 ) -> DispatchResultWithPostInfo;1568 ) -> DispatchResultWithPostInfo;15691570 /// Set collection properties.1571 ///1572 /// * `sender` - Must be either the owner of the collection or its admin.1573 /// * `properties` - Properties to be set.1299 fn set_collection_properties(1574 fn set_collection_properties(1300 &self,1575 &self,1301 sender: T::CrossAccountId,1576 sender: T::CrossAccountId,1302 properties: Vec<Property>,1577 properties: Vec<Property>,1303 ) -> DispatchResultWithPostInfo;1578 ) -> DispatchResultWithPostInfo;15791580 /// Delete collection properties.1581 ///1582 /// * `sender` - Must be either the owner of the collection or its admin.1583 /// * `properties` - The properties to be removed.1304 fn delete_collection_properties(1584 fn delete_collection_properties(1305 &self,1585 &self,1306 sender: &T::CrossAccountId,1586 sender: &T::CrossAccountId,1307 property_keys: Vec<PropertyKey>,1587 property_keys: Vec<PropertyKey>,1308 ) -> DispatchResultWithPostInfo;1588 ) -> DispatchResultWithPostInfo;15891590 /// Set token properties.1591 ///1592 /// The appropriate [`PropertyPermission`] for the token property1593 /// must be set with [`Self::set_token_property_permissions`].1594 ///1595 /// * `sender` - Must be either the owner of the token or its admin.1596 /// * `token_id` - The token for which the properties are being set.1597 /// * `properties` - Properties to be set.1598 /// * `budget` - Budget for setting properties.1309 fn set_token_properties(1599 fn set_token_properties(1310 &self,1600 &self,1311 sender: T::CrossAccountId,1601 sender: T::CrossAccountId,1312 token_id: TokenId,1602 token_id: TokenId,1313 property: Vec<Property>,1603 properties: Vec<Property>,1314 nesting_budget: &dyn Budget,1604 budget: &dyn Budget,1315 ) -> DispatchResultWithPostInfo;1605 ) -> DispatchResultWithPostInfo;16061607 /// Remove token properties.1608 ///1609 /// The appropriate [`PropertyPermission`] for the token property1610 /// must be set with [`Self::set_token_property_permissions`].1611 ///1612 /// * `sender` - Must be either the owner of the token or its admin.1613 /// * `token_id` - The token for which the properties are being remove.1614 /// * `property_keys` - Keys to remove corresponding properties.1615 /// * `budget` - Budget for removing properties.1316 fn delete_token_properties(1616 fn delete_token_properties(1317 &self,1617 &self,1318 sender: T::CrossAccountId,1618 sender: T::CrossAccountId,1319 token_id: TokenId,1619 token_id: TokenId,1320 property_keys: Vec<PropertyKey>,1620 property_keys: Vec<PropertyKey>,1321 nesting_budget: &dyn Budget,1621 budget: &dyn Budget,1322 ) -> DispatchResultWithPostInfo;1622 ) -> DispatchResultWithPostInfo;16231624 /// Set token property permissions.1625 ///1626 /// * `sender` - Must be either the owner of the token or its admin.1627 /// * `token_id` - The token for which the properties are being set.1628 /// * `properties` - Properties to be set.1629 /// * `budget` - Budget for setting properties.1323 fn set_token_property_permissions(1630 fn set_token_property_permissions(1324 &self,1631 &self,1325 sender: &T::CrossAccountId,1632 sender: &T::CrossAccountId,1326 property_permissions: Vec<PropertyKeyPermission>,1633 property_permissions: Vec<PropertyKeyPermission>,1327 ) -> DispatchResultWithPostInfo;1634 ) -> DispatchResultWithPostInfo;16351636 /// Transfer amount of token pieces.1637 ///1638 /// * `sender` - Donor user.1639 /// * `to` - Recepient user.1640 /// * `token` - The token of which parts are being sent.1641 /// * `amount` - The number of parts of the token that will be transferred.1642 /// * `budget` - The maximum budget that can be spent on the transfer.1328 fn transfer(1643 fn transfer(1329 &self,1644 &self,1330 sender: T::CrossAccountId,1645 sender: T::CrossAccountId,1331 to: T::CrossAccountId,1646 to: T::CrossAccountId,1332 token: TokenId,1647 token: TokenId,1333 amount: u128,1648 amount: u128,1334 nesting_budget: &dyn Budget,1649 budget: &dyn Budget,1335 ) -> DispatchResultWithPostInfo;1650 ) -> DispatchResultWithPostInfo;16511652 /// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].1653 ///1654 /// * `sender` - The user who grants access to the token.1655 /// * `spender` - The user to whom the rights are granted.1656 /// * `token` - The token to which access is granted.1657 /// * `amount` - The amount of pieces that another user can dispose of.1336 fn approve(1658 fn approve(1337 &self,1659 &self,1338 sender: T::CrossAccountId,1660 sender: T::CrossAccountId,1339 spender: T::CrossAccountId,1661 spender: T::CrossAccountId,1340 token: TokenId,1662 token: TokenId,1341 amount: u128,1663 amount: u128,1342 ) -> DispatchResultWithPostInfo;1664 ) -> DispatchResultWithPostInfo;16651666 /// Send parts of a token owned by another user.1667 ///1668 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1669 ///1670 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1671 /// * `from` - The user who owns the token.1672 /// * `to` - Recepient user.1673 /// * `token` - The token of which parts are being sent.1674 /// * `amount` - The number of parts of the token that will be transferred.1675 /// * `budget` - The maximum budget that can be spent on the transfer.1343 fn transfer_from(1676 fn transfer_from(1344 &self,1677 &self,1345 sender: T::CrossAccountId,1678 sender: T::CrossAccountId,1346 from: T::CrossAccountId,1679 from: T::CrossAccountId,1347 to: T::CrossAccountId,1680 to: T::CrossAccountId,1348 token: TokenId,1681 token: TokenId,1349 amount: u128,1682 amount: u128,1350 nesting_budget: &dyn Budget,1683 budget: &dyn Budget,1351 ) -> DispatchResultWithPostInfo;1684 ) -> DispatchResultWithPostInfo;16851686 /// Burn parts of a token owned by another user.1687 ///1688 /// Before calling this method, you must grant rights to the calling user via [`Self::approve`].1689 ///1690 /// * `sender` - The user who must have access to the token (see [`Self::approve`]).1691 /// * `from` - The user who owns the token.1692 /// * `token` - The token of which parts are being sent.1693 /// * `amount` - The number of parts of the token that will be transferred.1694 /// * `budget` - The maximum budget that can be spent on the burn.1352 fn burn_from(1695 fn burn_from(1353 &self,1696 &self,1354 sender: T::CrossAccountId,1697 sender: T::CrossAccountId,1355 from: T::CrossAccountId,1698 from: T::CrossAccountId,1356 token: TokenId,1699 token: TokenId,1357 amount: u128,1700 amount: u128,1358 nesting_budget: &dyn Budget,1701 budget: &dyn Budget,1359 ) -> DispatchResultWithPostInfo;1702 ) -> DispatchResultWithPostInfo;136017031704 /// Check permission to nest token.1705 ///1706 /// * `sender` - The user who initiated the check.1707 /// * `from` - The token that is checked for embedding.1708 /// * `under` - Token under which to check.1709 /// * `budget` - The maximum budget that can be spent on the check.1361 fn check_nesting(1710 fn check_nesting(1362 &self,1711 &self,1363 sender: T::CrossAccountId,1712 sender: T::CrossAccountId,1364 from: (CollectionId, TokenId),1713 from: (CollectionId, TokenId),1365 under: TokenId,1714 under: TokenId,1366 nesting_budget: &dyn Budget,1715 budget: &dyn Budget,1367 ) -> DispatchResult;1716 ) -> DispatchResult;136817171718 /// Nest one token into another.1719 ///1720 /// * `under` - Token holder.1721 /// * `to_nest` - Nested token.1369 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));1722 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));137017231724 /// Unnest token.1725 ///1726 /// * `under` - Token holder.1727 /// * `to_nest` - Token to unnest.1371 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));1728 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));137217291730 /// Get all user tokens.1731 ///1732 /// * `account` - Account for which you need to get tokens.1373 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1733 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;17341735 /// Get all the tokens in the collection.1374 fn collection_tokens(&self) -> Vec<TokenId>;1736 fn collection_tokens(&self) -> Vec<TokenId>;17371738 /// Check if the token exists.1739 ///1740 /// * `token` - Id token to check.1375 fn token_exists(&self, token: TokenId) -> bool;1741 fn token_exists(&self, token: TokenId) -> bool;17421743 /// Get the id of the last minted token.1376 fn last_token_id(&self) -> TokenId;1744 fn last_token_id(&self) -> TokenId;137717451746 /// Get the owner of the token.1747 ///1748 /// * `token` - The token for which you need to find out the owner.1378 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1749 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;17501751 /// Get the value of the token property by key.1752 ///1753 /// * `token` - Token with the property to get.1754 /// * `key` - Property name.1379 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1755 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;17561380 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1757 /// Get a set of token properties by key vector.1758 ///1759 /// * `token` - Token with the property to get.1760 /// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),1761 /// then all properties are returned.1762 fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;17631381 /// Amount of unique collection tokens1764 /// Amount of unique collection tokens1382 fn total_supply(&self) -> u32;1765 fn total_supply(&self) -> u32;17661383 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1767 /// Amount of different tokens account has.1768 ///1769 /// * `account` - The account for which need to get the balance.1384 fn account_balance(&self, account: T::CrossAccountId) -> u32;1770 fn account_balance(&self, account: T::CrossAccountId) -> u32;17711385 /// Amount of specific token account have (Applicable to fungible/refungible)1772 /// Amount of specific token account have.1386 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1773 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;17741387 /// Amount of token pieces1775 /// Amount of token pieces1388 fn total_pieces(&self, token: TokenId) -> Option<u128>;1776 fn total_pieces(&self, token: TokenId) -> Option<u128>;17771778 /// Get the number of parts of the token that a trusted user can manage.1779 ///1780 /// * `sender` - Trusted user.1781 /// * `spender` - Owner of the token.1782 /// * `token` - The token for which to get the value.1389 fn allowance(1783 fn allowance(1390 &self,1784 &self,1391 sender: T::CrossAccountId,1785 sender: T::CrossAccountId,1392 spender: T::CrossAccountId,1786 spender: T::CrossAccountId,1393 token: TokenId,1787 token: TokenId,1394 ) -> u128;1788 ) -> u128;17891790 /// Get extension for RFT collection.1395 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1791 fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;1396}1792}139717931794/// Extension for RFT collection.1398pub trait RefungibleExtensions<T>1795pub trait RefungibleExtensions<T>1399where1796where1400 T: Config,1797 T: Config,1401{1798{1799 /// Change the number of parts of the token.1800 ///1801 /// When the value changes down, this function is equivalent to burning parts of the token.1802 ///1803 /// * `sender` - The user calling the repartition operation. Must be the owner of the token.1804 /// * `token` - The token for which you want to change the number of parts.1805 /// * `amount` - The new value of the parts of the token.1402 fn repartition(1806 fn repartition(1403 &self,1807 &self,1404 owner: &T::CrossAccountId,1808 sender: &T::CrossAccountId,1405 token: TokenId,1809 token: TokenId,1406 amount: u128,1810 amount: u128,1407 ) -> DispatchResultWithPostInfo;1811 ) -> DispatchResultWithPostInfo;1408}1812}140918131410// Flexible enough for implementing CommonCollectionOperations1814/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].1815///1816/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.1411pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1817pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1412 let post_info = PostDispatchInfo {1818 let post_info = PostDispatchInfo {1413 actual_weight: Some(weight),1819 actual_weight: Some(weight),pallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/common.rsdiffbeforeafterboth105 }105 }106}106}107107108/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete109/// methods and adds weight info.108impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {110impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {109 fn create_item(111 fn create_item(110 &self,112 &self,pallets/fungible/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//! ERC-20 standart support implementation.161817use core::char::{REPLACEMENT_CHARACTER, decode_utf16};19use core::char::{REPLACEMENT_CHARACTER, decode_utf16};18use core::convert::TryInto;20use core::convert::TryInto;pallets/fungible/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/>.1617//! # Fungible Pallet18//!19//! The Fungible pallet provides functionality for dealing with fungible assets.20//!21//! - [`CreateItemData`]22//! - [`Config`]23//! - [`FungibleHandle`]24//! - [`Pallet`]25//! - [`TotalSupply`]26//! - [`Balance`]27//! - [`Allowance`]28//! - [`Error`]29//!30//! ## Fungible tokens31//!32//! Fungible tokens or assets are divisible and non-unique. For instance,33//! fiat currencies like the dollar are fungible: A $1 bill34//! in New York City has the same value as a $1 bill in Miami.35//! A fungible token can also be a cryptocurrency like Bitcoin: 1 BTC is worth 1 BTC,36//! no matter where it is issued. Thus, the fungibility refers to a specific currency’s37//! ability to maintain one standard value. As well, it needs to have uniform acceptance.38//! This means that a currency’s history should not be able to affect its value,39//! and this is due to the fact that each piece that is a part of the currency is equal40//! in value when compared to every other piece of that exact same currency.41//! In the world of cryptocurrencies, this is essentially a coin or a token42//! that can be replaced by another identical coin or token, and they are43//! both mutually interchangeable. A popular implementation of fungible tokens is44//! the ERC-20 token standard.45//!46//! ### ERC-2047//!48//! The [ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) (Ethereum Request for Comments 20), proposed by Fabian Vogelsteller in November 2015,49//! is a Token Standard that implements an API for tokens within Smart Contracts.50//!51//! Example functionalities ERC-20 provides:52//!53//! * transfer tokens from one account to another54//! * get the current token balance of an account55//! * get the total supply of the token available on the network56//! * approve whether an amount of token from an account can be spent by a third-party account57//!58//! ## Overview59//!60//! The module provides functionality for asset management of fungible asset, supports ERC-20 standart, includes:61//!62//! * Asset Issuance63//! * Asset Transferal64//! * Asset Destruction65//! * Delegated Asset Transfers66//!67//! **NOTE:** The created fungible asset always has `token_id` = 0.68//! So `tokenA` and `tokenB` will have different `collection_id`.69//!70//! ### Implementations71//!72//! The Fungible pallet provides implementations for the following traits.73//!74//! - [`WithRecorder`](pallet_evm_coder_substrate::WithRecorder): Trait for EVM support75//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing with collections76//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight77//! - [`CommonEvmHandler`](pallet_common::erc::CommonEvmHandler): Function for handling EVM runtime calls167817#![cfg_attr(not(feature = "std"), no_std)]79#![cfg_attr(not(feature = "std"), no_std)]188057 pub enum Error<T> {119 pub enum Error<T> {58 /// Not Fungible item data used to mint in Fungible collection.120 /// Not Fungible item data used to mint in Fungible collection.59 NotFungibleDataUsedToMintFungibleCollectionToken,121 NotFungibleDataUsedToMintFungibleCollectionToken,60 /// Not default id passed as TokenId argument122 /// Not default id passed as TokenId argument.123 /// The default value of TokenId for Fungible collection is 0.61 FungibleItemsHaveNoId,124 FungibleItemsHaveNoId,62 /// Tried to set data for fungible item125 /// Tried to set data for fungible item.63 FungibleItemsDontHaveData,126 FungibleItemsDontHaveData,64 /// Fungible token does not support nested127 /// Fungible token does not support nesting.65 FungibleDisallowsNesting,128 FungibleDisallowsNesting,66 /// Setting item properties is not allowed129 /// Setting item properties is not allowed.67 SettingPropertiesNotAllowed,130 SettingPropertiesNotAllowed,68 }131 }6913278 #[pallet::generate_store(pub(super) trait Store)]141 #[pallet::generate_store(pub(super) trait Store)]79 pub struct Pallet<T>(_);142 pub struct Pallet<T>(_);80143144 /// Total amount of fungible tokens inside a collection.81 #[pallet::storage]145 #[pallet::storage]82 pub type TotalSupply<T: Config> =146 pub type TotalSupply<T: Config> =83 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u128, QueryKind = ValueQuery>;147 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u128, QueryKind = ValueQuery>;84148149 /// Amount of tokens owned by an account inside a collection.85 #[pallet::storage]150 #[pallet::storage]86 pub type Balance<T: Config> = StorageNMap<151 pub type Balance<T: Config> = StorageNMap<87 Key = (152 Key = (92 QueryKind = ValueQuery,157 QueryKind = ValueQuery,93 >;158 >;94159160 /// Storage for delegated assets.95 #[pallet::storage]161 #[pallet::storage]96 pub type Allowance<T: Config> = StorageNMap<162 pub type Allowance<T: Config> = StorageNMap<97 Key = (163 Key = (104 >;170 >;105}171}172173/// Wrapper around untyped collection handle, asserting inner collection is of fungible type.174/// Required for interaction with Fungible collections, type safety and implementation [`solidity_interface`][`evm_coder::solidity_interface`].106175107pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);176pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);177178/// Implementation of methods required for dispatching during runtime.108impl<T: Config> FungibleHandle<T> {179impl<T: Config> FungibleHandle<T> {180 /// Casts [`CollectionHandle`][`pallet_common::CollectionHandle`] into [`FungibleHandle`].109 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {181 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {110 Self(inner)182 Self(inner)111 }183 }184185 /// Casts [`FungibleHandle`] into [`CollectionHandle`][`pallet_common::CollectionHandle`].112 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {186 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {113 self.0187 self.0114 }188 }189 /// Returns a mutable reference to the internal [`CollectionHandle`][`pallet_common::CollectionHandle`].115 pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {190 pub fn common_mut(&mut self) -> &mut pallet_common::CollectionHandle<T> {116 &mut self.0191 &mut self.0117 }192 }132 }207 }133}208}134209210/// Pallet implementation for fungible assets135impl<T: Config> Pallet<T> {211impl<T: Config> Pallet<T> {212 /// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.136 pub fn init_collection(213 pub fn init_collection(137 owner: T::CrossAccountId,214 owner: T::CrossAccountId,138 data: CreateCollectionData<T::AccountId>,215 data: CreateCollectionData<T::AccountId>,139 ) -> Result<CollectionId, DispatchError> {216 ) -> Result<CollectionId, DispatchError> {140 <PalletCommon<T>>::init_collection(owner, data, false)217 <PalletCommon<T>>::init_collection(owner, data, false)141 }218 }219220 /// Destroys a collection.142 pub fn destroy_collection(221 pub fn destroy_collection(143 collection: FungibleHandle<T>,222 collection: FungibleHandle<T>,144 sender: &T::CrossAccountId,223 sender: &T::CrossAccountId,159 Ok(())238 Ok(())160 }239 }161240241 ///Checks if collection has tokens. Return `true` if it has.162 fn collection_has_tokens(collection_id: CollectionId) -> bool {242 fn collection_has_tokens(collection_id: CollectionId) -> bool {163 <TotalSupply<T>>::get(collection_id) != 0243 <TotalSupply<T>>::get(collection_id) != 0164 }244 }165245246 /// Burns the specified amount of the token. If the token balance247 /// or total supply is less than the given value,248 /// it will return [DispatchError].166 pub fn burn(249 pub fn burn(167 collection: &FungibleHandle<T>,250 collection: &FungibleHandle<T>,168 owner: &T::CrossAccountId,251 owner: &T::CrossAccountId,207 Ok(())290 Ok(())208 }291 }209292293 /// Transfers the specified amount of tokens. Will check that294 /// the transfer is allowed for the token.295 ///296 /// - `from`: Owner of tokens to transfer.297 /// - `to`: Recepient of transfered tokens.298 /// - `amount`: Amount of tokens to transfer.299 /// - `collection`: Collection that contains the token210 pub fn transfer(300 pub fn transfer(211 collection: &FungibleHandle<T>,301 collection: &FungibleHandle<T>,212 from: &T::CrossAccountId,302 from: &T::CrossAccountId,277 Ok(())367 Ok(())278 }368 }279369370 /// Minting tokens for multiple IDs.371 /// See [`create_item`][`Pallet::create_item`] for more details.280 pub fn create_multiple_items(372 pub fn create_multiple_items(281 collection: &FungibleHandle<T>,373 collection: &FungibleHandle<T>,282 sender: &T::CrossAccountId,374 sender: &T::CrossAccountId,378 ));470 ));379 }471 }380472473 /// Set allowance for the spender to `transfer` or `burn` owner's tokens.474 ///475 /// - `collection`: Collection that contains the token476 /// - `owner`: Owner of tokens that sets the allowance.477 /// - `spender`: Recipient of the allowance rights.478 /// - `amount`: Amount of tokens the spender is allowed to `transfer` or `burn`.381 pub fn set_allowance(479 pub fn set_allowance(382 collection: &FungibleHandle<T>,480 collection: &FungibleHandle<T>,383 owner: &T::CrossAccountId,481 owner: &T::CrossAccountId,402 Ok(())500 Ok(())403 }501 }404502503 /// Checks if a non-owner has (enough) allowance from the owner to perform operations on the tokens.504 /// Returns the expected remaining allowance - it should be set manually if the transaction proceeds.505 ///506 /// - `collection`: Collection that contains the token.507 /// - `spender`: CrossAccountId who has the allowance rights.508 /// - `from`: The owner of the tokens who sets the allowance.509 /// - `amount`: Amount of tokens by which the allowance sholud be reduced.405 fn check_allowed(510 fn check_allowed(406 collection: &FungibleHandle<T>,511 collection: &FungibleHandle<T>,407 spender: &T::CrossAccountId,512 spender: &T::CrossAccountId,441 Ok(allowance)546 Ok(allowance)442 }547 }548549 /// Transfer fungible tokens from one account to another.550 /// Same as the [`transfer`][`Pallet::transfer`] but spender doesn't needs to be an owner of the token pieces.551 /// The owner should set allowance for the spender to transfer pieces.552 /// See [`set_allowance`][`Pallet::set_allowance`] for more details.443553444 pub fn transfer_from(554 pub fn transfer_from(445 collection: &FungibleHandle<T>,555 collection: &FungibleHandle<T>,460 Ok(())570 Ok(())461 }571 }462572573 /// Burn fungible tokens from the account.574 ///575 /// Same as the [`burn`][`Pallet::burn`] but spender doesn't need to be an owner of the tokens. The `from` should576 /// set allowance for the spender to burn tokens.577 /// See [`set_allowance`][`Pallet::set_allowance`] for more details.463 pub fn burn_from(578 pub fn burn_from(464 collection: &FungibleHandle<T>,579 collection: &FungibleHandle<T>,465 spender: &T::CrossAccountId,580 spender: &T::CrossAccountId,478 Ok(())593 Ok(())479 }594 }480595481 /// Delegated to `create_multiple_items`596 /// Creates fungible token.597 ///598 /// The sender should be the owner/admin of the collection or collection should be configured599 /// to allow public minting.600 ///601 /// - `data`: Contains user who will become the owners of the tokens and amount602 /// of tokens he will receive.482 pub fn create_item(603 pub fn create_item(483 collection: &FungibleHandle<T>,604 collection: &FungibleHandle<T>,484 sender: &T::CrossAccountId,605 sender: &T::CrossAccountId,pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth43 }43 }44}44}4546// Selector: 7d9262e647contract Collection is Dummy, ERC165 {48 // Set collection property.49 //50 // @param key Property key.51 // @param value Propery value.52 //53 // Selector: setCollectionProperty(string,bytes) 2f073f6654 function setCollectionProperty(string memory key, bytes memory value)55 public56 {57 require(false, stub_error);58 key;59 value;60 dummy = 0;61 }6263 // Delete collection property.64 //65 // @param key Property key.66 //67 // Selector: deleteCollectionProperty(string) 7b7debce68 function deleteCollectionProperty(string memory key) public {69 require(false, stub_error);70 key;71 dummy = 0;72 }7374 // Get collection property.75 //76 // @dev Throws error if key not found.77 //78 // @param key Property key.79 // @return bytes The property corresponding to the key.80 //81 // Selector: collectionProperty(string) cf24fd6d82 function collectionProperty(string memory key)83 public84 view85 returns (bytes memory)86 {87 require(false, stub_error);88 key;89 dummy;90 return hex"";91 }9293 // Set the sponsor of the collection.94 //95 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.96 //97 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.98 //99 // Selector: setCollectionSponsor(address) 7623402e100 function setCollectionSponsor(address sponsor) public {101 require(false, stub_error);102 sponsor;103 dummy = 0;104 }105106 // Collection sponsorship confirmation.107 //108 // @dev After setting the sponsor for the collection, it must be confirmed with this function.109 //110 // Selector: confirmCollectionSponsorship() 3c50e97a111 function confirmCollectionSponsorship() public {112 require(false, stub_error);113 dummy = 0;114 }115116 // Set limits for the collection.117 // @dev Throws error if limit not found.118 // @param limit Name of the limit. Valid names:119 // "accountTokenOwnershipLimit",120 // "sponsoredDataSize",121 // "sponsoredDataRateLimit",122 // "tokenLimit",123 // "sponsorTransferTimeout",124 // "sponsorApproveTimeout"125 // @param value Value of the limit.126 //127 // Selector: setCollectionLimit(string,uint32) 6a3841db128 function setCollectionLimit(string memory limit, uint32 value) public {129 require(false, stub_error);130 limit;131 value;132 dummy = 0;133 }134135 // Set limits for the collection.136 // @dev Throws error if limit not found.137 // @param limit Name of the limit. Valid names:138 // "ownerCanTransfer",139 // "ownerCanDestroy",140 // "transfersEnabled"141 // @param value Value of the limit.142 //143 // Selector: setCollectionLimit(string,bool) 993b7fba144 function setCollectionLimit(string memory limit, bool value) public {145 require(false, stub_error);146 limit;147 value;148 dummy = 0;149 }150151 // Get contract address.152 //153 // Selector: contractAddress() f6b4dfb4154 function contractAddress() public view returns (address) {155 require(false, stub_error);156 dummy;157 return 0x0000000000000000000000000000000000000000;158 }159160 // Add collection admin by substrate address.161 // @param new_admin Substrate administrator address.162 //163 // Selector: addCollectionAdminSubstrate(uint256) 5730062b164 function addCollectionAdminSubstrate(uint256 newAdmin) public {165 require(false, stub_error);166 newAdmin;167 dummy = 0;168 }169170 // Remove collection admin by substrate address.171 // @param admin Substrate administrator address.172 //173 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9174 function removeCollectionAdminSubstrate(uint256 admin) public {175 require(false, stub_error);176 admin;177 dummy = 0;178 }179180 // Add collection admin.181 // @param new_admin Address of the added administrator.182 //183 // Selector: addCollectionAdmin(address) 92e462c7184 function addCollectionAdmin(address newAdmin) public {185 require(false, stub_error);186 newAdmin;187 dummy = 0;188 }189190 // Remove collection admin.191 //192 // @param new_admin Address of the removed administrator.193 //194 // Selector: removeCollectionAdmin(address) fafd7b42195 function removeCollectionAdmin(address admin) public {196 require(false, stub_error);197 admin;198 dummy = 0;199 }200201 // Toggle accessibility of collection nesting.202 //203 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'204 //205 // Selector: setCollectionNesting(bool) 112d4586206 function setCollectionNesting(bool enable) public {207 require(false, stub_error);208 enable;209 dummy = 0;210 }211212 // Toggle accessibility of collection nesting.213 //214 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'215 // @param collections Addresses of collections that will be available for nesting.216 //217 // Selector: setCollectionNesting(bool,address[]) 64872396218 function setCollectionNesting(bool enable, address[] memory collections)219 public220 {221 require(false, stub_error);222 enable;223 collections;224 dummy = 0;225 }226227 // Set the collection access method.228 // @param mode Access mode229 // 0 for Normal230 // 1 for AllowList231 //232 // Selector: setCollectionAccess(uint8) 41835d4c233 function setCollectionAccess(uint8 mode) public {234 require(false, stub_error);235 mode;236 dummy = 0;237 }238239 // Add the user to the allowed list.240 //241 // @param user Address of a trusted user.242 //243 // Selector: addToCollectionAllowList(address) 67844fe6244 function addToCollectionAllowList(address user) public {245 require(false, stub_error);246 user;247 dummy = 0;248 }249250 // Remove the user from the allowed list.251 //252 // @param user Address of a removed user.253 //254 // Selector: removeFromCollectionAllowList(address) 85c51acb255 function removeFromCollectionAllowList(address user) public {256 require(false, stub_error);257 user;258 dummy = 0;259 }260261 // Switch permission for minting.262 //263 // @param mode Enable if "true".264 //265 // Selector: setCollectionMintMode(bool) 00018e84266 function setCollectionMintMode(bool mode) public {267 require(false, stub_error);268 mode;269 dummy = 0;270 }271}4527246// Selector: 942e8b22273// Selector: 942e8b2247contract ERC20 is Dummy, ERC165, ERC20Events {274contract ERC20 is Dummy, ERC165, ERC20Events {127 }354 }128}355}129130// Selector: c894dc35131contract Collection is Dummy, ERC165 {132 // Selector: setCollectionProperty(string,bytes) 2f073f66133 function setCollectionProperty(string memory key, bytes memory value)134 public135 {136 require(false, stub_error);137 key;138 value;139 dummy = 0;140 }141142 // Selector: deleteCollectionProperty(string) 7b7debce143 function deleteCollectionProperty(string memory key) public {144 require(false, stub_error);145 key;146 dummy = 0;147 }148149 // Throws error if key not found150 //151 // Selector: collectionProperty(string) cf24fd6d152 function collectionProperty(string memory key)153 public154 view155 returns (bytes memory)156 {157 require(false, stub_error);158 key;159 dummy;160 return hex"";161 }162163 // Selector: ethSetSponsor(address) 8f9af356164 function ethSetSponsor(address sponsor) public {165 require(false, stub_error);166 sponsor;167 dummy = 0;168 }169170 // Selector: ethConfirmSponsorship() a8580d1a171 function ethConfirmSponsorship() public {172 require(false, stub_error);173 dummy = 0;174 }175176 // Selector: setLimit(string,uint32) 68db30ca177 function setLimit(string memory limit, uint32 value) public {178 require(false, stub_error);179 limit;180 value;181 dummy = 0;182 }183184 // Selector: setLimit(string,bool) ea67e4c2185 function setLimit(string memory limit, bool value) public {186 require(false, stub_error);187 limit;188 value;189 dummy = 0;190 }191192 // Selector: contractAddress() f6b4dfb4193 function contractAddress() public view returns (address) {194 require(false, stub_error);195 dummy;196 return 0x0000000000000000000000000000000000000000;197 }198}199356200contract UniqueFungible is357contract UniqueFungible is201 Dummy,358 Dummy,pallets/inflation/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/>.1617//! # Inflation18//!19//! The inflation pallet is designed to increase the number of tokens at certain intervals.20//! With each iteration, increases the `total_issuance` value for the native token.21//! Executing an `on_initialize` hook at the beginning of each block, causing inflation to begin.22//!23//! ## Interface24//!25//! ### Dispatchable Functions26//!27//! * `start_inflation` - This method sets the inflation start date. Can be only called once.28//! Inflation start block can be backdated and will catch up. The method will create Treasury29//! account if it does not exist and perform the first inflation deposit.163017// #![recursion_limit = "1024"]31// #![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]32#![cfg_attr(not(feature = "std"), no_std)]pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth183 value: property_value(),183 value: property_value(),184 }).collect::<Vec<_>>();184 }).collect::<Vec<_>>();185 let item = create_max_item(&collection, &owner, owner.clone())?;185 let item = create_max_item(&collection, &owner, owner.clone())?;186 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?}186 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}187187188 delete_token_properties {188 delete_token_properties {189 let b in 0..MAX_PROPERTIES_PER_ITEM;189 let b in 0..MAX_PROPERTIES_PER_ITEM;205 value: property_value(),205 value: property_value(),206 }).collect::<Vec<_>>();206 }).collect::<Vec<_>>();207 let item = create_max_item(&collection, &owner, owner.clone())?;207 let item = create_max_item(&collection, &owner, owner.clone())?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props, false, &Unlimited)?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;209 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();209 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();210 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete, &Unlimited)?}210 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}211}211}212212pallets/nonfungible/src/common.rsdiffbeforeafterboth133 }133 }134}134}135135136/// Implementation of `CommonCollectionOperations` for `NonfungibleHandle`. It wraps Nonfungible Pallete137/// methods and adds weight info.136impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {138impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {137 fn create_item(139 fn create_item(138 &self,140 &self,pallets/nonfungible/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//! # Nonfungible Pallet EVM API18//!19//! Provides ERC-721 standart support implementation and EVM API for unique extensions for Nonfungible Pallet.20//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.162117extern crate alloc;22extern crate alloc;18use core::{23use core::{40 SelfWeightOf, weights::WeightInfo, TokenProperties,45 SelfWeightOf, weights::WeightInfo, TokenProperties,41};46};424748/// @title A contract that allows to set and delete token properties and change token property permissions.43#[solidity_interface(name = "TokenProperties")]49#[solidity_interface(name = "TokenProperties")]44impl<T: Config> NonfungibleHandle<T> {50impl<T: Config> NonfungibleHandle<T> {51 /// @notice Set permissions for token property.52 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.53 /// @param key Property key.54 /// @param is_mutable Permission to mutate property.55 /// @param collection_admin Permission to mutate property by collection admin if property is mutable.56 /// @param token_owner Permission to mutate property by token owner if property is mutable.45 fn set_token_property_permission(57 fn set_token_property_permission(46 &mut self,58 &mut self,47 caller: caller,59 caller: caller,68 .map_err(dispatch_to_evm::<T>)80 .map_err(dispatch_to_evm::<T>)69 }81 }708283 /// @notice Set token property value.84 /// @dev Throws error if `msg.sender` has no permission to edit the property.85 /// @param tokenId ID of the token.86 /// @param key Property key.87 /// @param value Property value.71 fn set_property(88 fn set_property(72 &mut self,89 &mut self,73 caller: caller,90 caller: caller,96 .map_err(dispatch_to_evm::<T>)113 .map_err(dispatch_to_evm::<T>)97 }114 }98115116 /// @notice Delete token property value.117 /// @dev Throws error if `msg.sender` has no permission to edit the property.118 /// @param tokenId ID of the token.119 /// @param key Property key.99 fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {120 fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {100 let caller = T::CrossAccountId::from_eth(caller);121 let caller = T::CrossAccountId::from_eth(caller);101 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;122 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;111 .map_err(dispatch_to_evm::<T>)132 .map_err(dispatch_to_evm::<T>)112 }133 }113134135 /// @notice Get token property value.114 /// Throws error if key not found136 /// @dev Throws error if key not found137 /// @param tokenId ID of the token.138 /// @param key Property key.139 /// @return Property value bytes115 fn property(&self, token_id: uint256, key: string) -> Result<bytes> {140 fn property(&self, token_id: uint256, key: string) -> Result<bytes> {116 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;141 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;117 let key = <Vec<u8>>::from(key)142 let key = <Vec<u8>>::from(key)127152128#[derive(ToLog)]153#[derive(ToLog)]129pub enum ERC721Events {154pub enum ERC721Events {155 /// @dev This emits when ownership of any NFT changes by any mechanism.156 /// This event emits when NFTs are created (`from` == 0) and destroyed157 /// (`to` == 0). Exception: during contract creation, any number of NFTs158 /// may be created and assigned without emitting Transfer. At the time of159 /// any transfer, the approved address for that NFT (if any) is reset to none.130 Transfer {160 Transfer {131 #[indexed]161 #[indexed]132 from: address,162 from: address,135 #[indexed]165 #[indexed]136 token_id: uint256,166 token_id: uint256,137 },167 },168 /// @dev This emits when the approved address for an NFT is changed or169 /// reaffirmed. The zero address indicates there is no approved address.170 /// When a Transfer event emits, this also indicates that the approved171 /// address for that NFT (if any) is reset to none.138 Approval {172 Approval {139 #[indexed]173 #[indexed]140 owner: address,174 owner: address,143 #[indexed]177 #[indexed]144 token_id: uint256,178 token_id: uint256,145 },179 },180 /// @dev This emits when an operator is enabled or disabled for an owner.181 /// The operator can manage all NFTs of the owner.146 #[allow(dead_code)]182 #[allow(dead_code)]147 ApprovalForAll {183 ApprovalForAll {148 #[indexed]184 #[indexed]159 MintingFinished {},195 MintingFinished {},160}196}161197198/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension199/// @dev See https://eips.ethereum.org/EIPS/eip-721162#[solidity_interface(name = "ERC721Metadata")]200#[solidity_interface(name = "ERC721Metadata")]163impl<T: Config> NonfungibleHandle<T> {201impl<T: Config> NonfungibleHandle<T> {202 /// @notice A descriptive name for a collection of NFTs in this contract164 fn name(&self) -> Result<string> {203 fn name(&self) -> Result<string> {165 Ok(decode_utf16(self.name.iter().copied())204 Ok(decode_utf16(self.name.iter().copied())166 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))205 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))167 .collect::<string>())206 .collect::<string>())168 }207 }169208209 /// @notice An abbreviated name for NFTs in this contract170 fn symbol(&self) -> Result<string> {210 fn symbol(&self) -> Result<string> {171 Ok(string::from_utf8_lossy(&self.token_prefix).into())211 Ok(string::from_utf8_lossy(&self.token_prefix).into())172 }212 }173213214 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.215 /// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC216 /// 3986. The URI may point to a JSON file that conforms to the "ERC721217 /// Metadata JSON Schema".174 /// Returns token's const_metadata218 /// @return token's const_metadata175 #[solidity(rename_selector = "tokenURI")]219 #[solidity(rename_selector = "tokenURI")]176 fn token_uri(&self, token_id: uint256) -> Result<string> {220 fn token_uri(&self, token_id: uint256) -> Result<string> {177 let key = token_uri_key();221 let key = token_uri_key();192 }236 }193}237}194238239/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension240/// @dev See https://eips.ethereum.org/EIPS/eip-721195#[solidity_interface(name = "ERC721Enumerable")]241#[solidity_interface(name = "ERC721Enumerable")]196impl<T: Config> NonfungibleHandle<T> {242impl<T: Config> NonfungibleHandle<T> {243 /// @notice Enumerate valid NFTs244 /// @param index A counter less than `totalSupply()`245 /// @return The token identifier for the `index`th NFT,246 /// (sort order not specified)197 fn token_by_index(&self, index: uint256) -> Result<uint256> {247 fn token_by_index(&self, index: uint256) -> Result<uint256> {198 Ok(index)248 Ok(index)199 }249 }200250201 /// Not implemented251 /// @dev Not implemented202 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {252 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {203 // TODO: Not implemetable253 // TODO: Not implemetable204 Err("not implemented".into())254 Err("not implemented".into())205 }255 }206256257 /// @notice Count NFTs tracked by this contract258 /// @return A count of valid NFTs tracked by this contract, where each one of259 /// them has an assigned and queryable owner not equal to the zero address207 fn total_supply(&self) -> Result<uint256> {260 fn total_supply(&self) -> Result<uint256> {208 self.consume_store_reads(1)?;261 self.consume_store_reads(1)?;209 Ok(<Pallet<T>>::total_supply(self).into())262 Ok(<Pallet<T>>::total_supply(self).into())210 }263 }211}264}212265266/// @title ERC-721 Non-Fungible Token Standard267/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md213#[solidity_interface(name = "ERC721", events(ERC721Events))]268#[solidity_interface(name = "ERC721", events(ERC721Events))]214impl<T: Config> NonfungibleHandle<T> {269impl<T: Config> NonfungibleHandle<T> {270 /// @notice Count all NFTs assigned to an owner271 /// @dev NFTs assigned to the zero address are considered invalid, and this272 /// function throws for queries about the zero address.273 /// @param owner An address for whom to query the balance274 /// @return The number of NFTs owned by `owner`, possibly zero215 fn balance_of(&self, owner: address) -> Result<uint256> {275 fn balance_of(&self, owner: address) -> Result<uint256> {216 self.consume_store_reads(1)?;276 self.consume_store_reads(1)?;217 let owner = T::CrossAccountId::from_eth(owner);277 let owner = T::CrossAccountId::from_eth(owner);218 let balance = <AccountBalance<T>>::get((self.id, owner));278 let balance = <AccountBalance<T>>::get((self.id, owner));219 Ok(balance.into())279 Ok(balance.into())220 }280 }281 /// @notice Find the owner of an NFT282 /// @dev NFTs assigned to zero address are considered invalid, and queries283 /// about them do throw.284 /// @param tokenId The identifier for an NFT285 /// @return The address of the owner of the NFT221 fn owner_of(&self, token_id: uint256) -> Result<address> {286 fn owner_of(&self, token_id: uint256) -> Result<address> {222 self.consume_store_reads(1)?;287 self.consume_store_reads(1)?;223 let token: TokenId = token_id.try_into()?;288 let token: TokenId = token_id.try_into()?;226 .owner291 .owner227 .as_eth())292 .as_eth())228 }293 }229 /// Not implemented294 /// @dev Not implemented230 fn safe_transfer_from_with_data(295 fn safe_transfer_from_with_data(231 &mut self,296 &mut self,232 _from: address,297 _from: address,238 // TODO: Not implemetable303 // TODO: Not implemetable239 Err("not implemented".into())304 Err("not implemented".into())240 }305 }241 /// Not implemented306 /// @dev Not implemented242 fn safe_transfer_from(307 fn safe_transfer_from(243 &mut self,308 &mut self,244 _from: address,309 _from: address,250 Err("not implemented".into())315 Err("not implemented".into())251 }316 }252317318 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE319 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE320 /// THEY MAY BE PERMANENTLY LOST321 /// @dev Throws unless `msg.sender` is the current owner or an authorized322 /// operator for this NFT. Throws if `from` is not the current owner. Throws323 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.324 /// @param from The current owner of the NFT325 /// @param to The new owner326 /// @param tokenId The NFT to transfer327 /// @param _value Not used for an NFT253 #[weight(<SelfWeightOf<T>>::transfer_from())]328 #[weight(<SelfWeightOf<T>>::transfer_from())]254 fn transfer_from(329 fn transfer_from(255 &mut self,330 &mut self,272 Ok(())347 Ok(())273 }348 }274349350 /// @notice Set or reaffirm the approved address for an NFT351 /// @dev The zero address indicates there is no approved address.352 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized353 /// operator of the current owner.354 /// @param approved The new approved NFT controller355 /// @param tokenId The NFT to approve275 #[weight(<SelfWeightOf<T>>::approve())]356 #[weight(<SelfWeightOf<T>>::approve())]276 fn approve(357 fn approve(277 &mut self,358 &mut self,289 Ok(())370 Ok(())290 }371 }291372292 /// Not implemented373 /// @dev Not implemented293 fn set_approval_for_all(374 fn set_approval_for_all(294 &mut self,375 &mut self,295 _caller: caller,376 _caller: caller,300 Err("not implemented".into())381 Err("not implemented".into())301 }382 }302383303 /// Not implemented384 /// @dev Not implemented304 fn get_approved(&self, _token_id: uint256) -> Result<address> {385 fn get_approved(&self, _token_id: uint256) -> Result<address> {305 // TODO: Not implemetable386 // TODO: Not implemetable306 Err("not implemented".into())387 Err("not implemented".into())307 }388 }308389309 /// Not implemented390 /// @dev Not implemented310 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {391 fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {311 // TODO: Not implemetable392 // TODO: Not implemetable312 Err("not implemented".into())393 Err("not implemented".into())313 }394 }314}395}315396397/// @title ERC721 Token that can be irreversibly burned (destroyed).316#[solidity_interface(name = "ERC721Burnable")]398#[solidity_interface(name = "ERC721Burnable")]317impl<T: Config> NonfungibleHandle<T> {399impl<T: Config> NonfungibleHandle<T> {400 /// @notice Burns a specific ERC721 token.401 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized402 /// operator of the current owner.403 /// @param tokenId The NFT to approve318 #[weight(<SelfWeightOf<T>>::burn_item())]404 #[weight(<SelfWeightOf<T>>::burn_item())]319 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {405 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {320 let caller = T::CrossAccountId::from_eth(caller);406 let caller = T::CrossAccountId::from_eth(caller);325 }411 }326}412}327413414/// @title ERC721 minting logic.328#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]415#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]329impl<T: Config> NonfungibleHandle<T> {416impl<T: Config> NonfungibleHandle<T> {330 fn minting_finished(&self) -> Result<bool> {417 fn minting_finished(&self) -> Result<bool> {331 Ok(false)418 Ok(false)332 }419 }333420421 /// @notice Function to mint token.334 /// `token_id` should be obtained with `next_token_id` method,422 /// @dev `tokenId` should be obtained with `nextTokenId` method,335 /// unlike standard, you can't specify it manually423 /// unlike standard, you can't specify it manually424 /// @param to The new owner425 /// @param tokenId ID of the minted NFT336 #[weight(<SelfWeightOf<T>>::create_item())]426 #[weight(<SelfWeightOf<T>>::create_item())]337 fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {427 fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {338 let caller = T::CrossAccountId::from_eth(caller);428 let caller = T::CrossAccountId::from_eth(caller);364 Ok(true)454 Ok(true)365 }455 }366456457 /// @notice Function to mint token with the given tokenUri.367 /// `token_id` should be obtained with `next_token_id` method,458 /// @dev `tokenId` should be obtained with `nextTokenId` method,368 /// unlike standard, you can't specify it manually459 /// unlike standard, you can't specify it manually460 /// @param to The new owner461 /// @param tokenId ID of the minted NFT462 /// @param tokenUri Token URI that would be stored in the NFT properties369 #[solidity(rename_selector = "mintWithTokenURI")]463 #[solidity(rename_selector = "mintWithTokenURI")]370 #[weight(<SelfWeightOf<T>>::create_item())]464 #[weight(<SelfWeightOf<T>>::create_item())]371 fn mint_with_token_uri(465 fn mint_with_token_uri(420 Ok(true)514 Ok(true)421 }515 }422516423 /// Not implemented517 /// @dev Not implemented424 fn finish_minting(&mut self, _caller: caller) -> Result<bool> {518 fn finish_minting(&mut self, _caller: caller) -> Result<bool> {425 Err("not implementable".into())519 Err("not implementable".into())426 }520 }449 false543 false450}544}451545546/// @title Unique extensions for ERC721.452#[solidity_interface(name = "ERC721UniqueExtensions")]547#[solidity_interface(name = "ERC721UniqueExtensions")]453impl<T: Config> NonfungibleHandle<T> {548impl<T: Config> NonfungibleHandle<T> {549 /// @notice Transfer ownership of an NFT550 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`551 /// is the zero address. Throws if `tokenId` is not a valid NFT.552 /// @param to The new owner553 /// @param tokenId The NFT to transfer554 /// @param _value Not used for an NFT454 #[weight(<SelfWeightOf<T>>::transfer())]555 #[weight(<SelfWeightOf<T>>::transfer())]455 fn transfer(556 fn transfer(456 &mut self,557 &mut self,470 Ok(())571 Ok(())471 }572 }472573574 /// @notice Burns a specific ERC721 token.575 /// @dev Throws unless `msg.sender` is the current owner or an authorized576 /// operator for this NFT. Throws if `from` is not the current owner. Throws577 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.578 /// @param from The current owner of the NFT579 /// @param tokenId The NFT to transfer580 /// @param _value Not used for an NFT473 #[weight(<SelfWeightOf<T>>::burn_from())]581 #[weight(<SelfWeightOf<T>>::burn_from())]474 fn burn_from(582 fn burn_from(475 &mut self,583 &mut self,490 Ok(())598 Ok(())491 }599 }492600601 /// @notice Returns next free NFT ID.493 fn next_token_id(&self) -> Result<uint256> {602 fn next_token_id(&self) -> Result<uint256> {494 self.consume_store_reads(1)?;603 self.consume_store_reads(1)?;495 Ok(<TokensMinted<T>>::get(self.id)604 Ok(<TokensMinted<T>>::get(self.id)498 .into())607 .into())499 }608 }500609610 /// @notice Function to mint multiple tokens.611 /// @dev `tokenIds` should be an array of consecutive numbers and first number612 /// should be obtained with `nextTokenId` method613 /// @param to The new owner614 /// @param tokenIds IDs of the minted NFTs501 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]615 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]502 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {616 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {503 let caller = T::CrossAccountId::from_eth(caller);617 let caller = T::CrossAccountId::from_eth(caller);529 Ok(true)643 Ok(true)530 }644 }531645646 /// @notice Function to mint multiple tokens with the given tokenUris.647 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive648 /// numbers and first number should be obtained with `nextTokenId` method649 /// @param to The new owner650 /// @param tokens array of pairs of token ID and token URI for minted tokens532 #[solidity(rename_selector = "mintBulkWithTokenURI")]651 #[solidity(rename_selector = "mintBulkWithTokenURI")]533 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]652 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]534 fn mint_bulk_with_token_uri(653 fn mint_bulk_with_token_uri(pallets/nonfungible/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/>.1617//! # Nonfungible Pallet18//!19//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.20//!21//! - [`Config`]22//! - [`NonfungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`]25//!26//! ## Overview27//!28//! The Nonfungible pallet provides functions for:29//!30//! - NFT collection creation and removal31//! - Minting and burning of NFT tokens32//! - Retrieving account balances33//! - Transfering NFT tokens34//! - Setting and checking allowance for NFT tokens35//! - Setting properties and permissions for NFT collections and tokens36//! - Nesting and unnesting tokens37//!38//! ### Terminology39//!40//! - **NFT token:** Non fungible token.41//!42//! - **NFT Collection:** A collection of NFT tokens. All NFT tokens are part of a collection.43//! Each collection can define it's own properties, properties for it's tokens and set of permissions.44//!45//! - **Balance:** Number of NFT tokens owned by an account46//!47//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on48//!49//! - **Burning:** The process of “deleting” a token from a collection and from50//! an account balance of the owner.51//!52//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting53//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in54//! it's child token i.e. parent-child relationship graph shouldn't have cycles.55//!56//! - **Properties:** Key-Values pairs. Token properties are attached to a token. Collection properties are57//! attached to a collection. Set of permissions could be defined for each property.58//!59//! ### Implementations60//!61//! The Nonfungible pallet provides implementations for the following traits. If these traits provide62//! the functionality that you need, then you can avoid coupling with the Nonfungible pallet.63//!64//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight65//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing66//! with collections67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for73//! some accounts.74//! - `destroy_collection` - Destroy exising NFT collection. There should be no tokens in the collection.75//! - `burn` - Burn NFT token owned by account.76//! - `transfer` - Transfer NFT token. Transfers should be enabled for NFT collection.77//! Nests the NFT token if it is sent to another token.78//! - `create_item` - Mint NFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account.80//! - `set_token_property` - Set token property value.81//! - `delete_token_property` - Remove property from the token.82//! - `set_collection_properties` - Set collection properties.83//! - `delete_collection_properties` - Remove properties from the collection.84//! - `set_property_permission` - Set collection property permission.85//! - `set_token_property_permissions` - Set token property permissions.86//!87//! ## Assumptions88//!89//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.169017#![cfg_attr(not(feature = "std"), no_std)]91#![cfg_attr(not(feature = "std"), no_std)]1892102 #[pallet::generate_store(pub(super) trait Store)]176 #[pallet::generate_store(pub(super) trait Store)]103 pub struct Pallet<T>(_);177 pub struct Pallet<T>(_);104178179 /// Amount of tokens minted for collection.105 #[pallet::storage]180 #[pallet::storage]106 pub type TokensMinted<T: Config> =181 pub type TokensMinted<T: Config> =107 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;182 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;183184 /// Amount of burnt tokens for collection.108 #[pallet::storage]185 #[pallet::storage]109 pub type TokensBurnt<T: Config> =186 pub type TokensBurnt<T: Config> =110 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;187 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;111188189 /// Custom data serialized to bytes for token.112 #[pallet::storage]190 #[pallet::storage]113 pub type TokenData<T: Config> = StorageNMap<191 pub type TokenData<T: Config> = StorageNMap<114 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),192 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),115 Value = ItemData<T::CrossAccountId>,193 Value = ItemData<T::CrossAccountId>,116 QueryKind = OptionQuery,194 QueryKind = OptionQuery,117 >;195 >;118196197 /// Key-Value map stored for token.119 #[pallet::storage]198 #[pallet::storage]120 #[pallet::getter(fn token_properties)]199 #[pallet::getter(fn token_properties)]121 pub type TokenProperties<T: Config> = StorageNMap<200 pub type TokenProperties<T: Config> = StorageNMap<125 OnEmpty = up_data_structs::TokenProperties,204 OnEmpty = up_data_structs::TokenProperties,126 >;205 >;127206207 /// Custom data that is serialized to bytes and attached to a token property.208 /// Currently used to store RMRK data.128 #[pallet::storage]209 #[pallet::storage]129 #[pallet::getter(fn token_aux_property)]210 #[pallet::getter(fn token_aux_property)]130 pub type TokenAuxProperties<T: Config> = StorageNMap<211 pub type TokenAuxProperties<T: Config> = StorageNMap<138 QueryKind = OptionQuery,219 QueryKind = OptionQuery,139 >;220 >;140221141 /// Used to enumerate tokens owned by account222 /// Used to enumerate tokens owned by account.142 #[pallet::storage]223 #[pallet::storage]143 pub type Owned<T: Config> = StorageNMap<224 pub type Owned<T: Config> = StorageNMap<144 Key = (225 Key = (150 QueryKind = ValueQuery,231 QueryKind = ValueQuery,151 >;232 >;152233153 /// Used to enumerate token's children234 /// Used to enumerate token's children.154 #[pallet::storage]235 #[pallet::storage]155 #[pallet::getter(fn token_children)]236 #[pallet::getter(fn token_children)]156 pub type TokenChildren<T: Config> = StorageNMap<237 pub type TokenChildren<T: Config> = StorageNMap<163 QueryKind = ValueQuery,244 QueryKind = ValueQuery,164 >;245 >;165246247 /// Amount of tokens owned by account.166 #[pallet::storage]248 #[pallet::storage]167 pub type AccountBalance<T: Config> = StorageNMap<249 pub type AccountBalance<T: Config> = StorageNMap<168 Key = (250 Key = (173 QueryKind = ValueQuery,255 QueryKind = ValueQuery,174 >;256 >;175257258 /// Allowance set by an owner for a spender for a token.176 #[pallet::storage]259 #[pallet::storage]177 pub type Allowance<T: Config> = StorageNMap<260 pub type Allowance<T: Config> = StorageNMap<178 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),261 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),273}356}274357275impl<T: Config> Pallet<T> {358impl<T: Config> Pallet<T> {359 /// Get number of NFT tokens in collection.276 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {360 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {277 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)361 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)278 }362 }363364 /// Check that NFT token exists.365 ///366 /// - `token`: Token ID.279 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {367 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {280 <TokenData<T>>::contains_key((collection.id, token))368 <TokenData<T>>::contains_key((collection.id, token))281 }369 }282370371 /// Set the token property with the scope.372 ///373 /// - `property`: Contains key-value pair.283 pub fn set_scoped_token_property(374 pub fn set_scoped_token_property(284 collection_id: CollectionId,375 collection_id: CollectionId,285 token_id: TokenId,376 token_id: TokenId,294 Ok(())385 Ok(())295 }386 }296387388 /// Batch operation to set multiple properties with the same scope.297 pub fn set_scoped_token_properties(389 pub fn set_scoped_token_properties(298 collection_id: CollectionId,390 collection_id: CollectionId,299 token_id: TokenId,391 token_id: TokenId,308 Ok(())400 Ok(())309 }401 }310402403 /// Add or edit auxiliary data for the property.404 ///405 /// - `f`: function that adds or edits auxiliary data.311 pub fn try_mutate_token_aux_property<R, E>(406 pub fn try_mutate_token_aux_property<R, E>(312 collection_id: CollectionId,407 collection_id: CollectionId,313 token_id: TokenId,408 token_id: TokenId,318 <TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)413 <TokenAuxProperties<T>>::try_mutate((collection_id, token_id, scope, key), f)319 }414 }320415416 /// Remove auxiliary data for the property.321 pub fn remove_token_aux_property(417 pub fn remove_token_aux_property(322 collection_id: CollectionId,418 collection_id: CollectionId,323 token_id: TokenId,419 token_id: TokenId,327 <TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));423 <TokenAuxProperties<T>>::remove((collection_id, token_id, scope, key));328 }424 }329425426 /// Get all auxiliary data in a given scope.427 ///428 /// Returns iterator over Property Key - Data pairs.330 pub fn iterate_token_aux_properties(429 pub fn iterate_token_aux_properties(331 collection_id: CollectionId,430 collection_id: CollectionId,332 token_id: TokenId,431 token_id: TokenId,335 <TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))434 <TokenAuxProperties<T>>::iter_prefix((collection_id, token_id, scope))336 }435 }337436437 /// Get ID of the last minted token338 pub fn current_token_id(collection_id: CollectionId) -> TokenId {438 pub fn current_token_id(collection_id: CollectionId) -> TokenId {339 TokenId(<TokensMinted<T>>::get(collection_id))439 TokenId(<TokensMinted<T>>::get(collection_id))340 }440 }341}441}342442343// unchecked calls skips any permission checks443// unchecked calls skips any permission checks344impl<T: Config> Pallet<T> {444impl<T: Config> Pallet<T> {445 /// Create NFT collection446 ///447 /// `init_collection` will take non-refundable deposit for collection creation.448 ///449 /// - `data`: Contains settings for collection limits and permissions.345 pub fn init_collection(450 pub fn init_collection(346 owner: T::CrossAccountId,451 owner: T::CrossAccountId,347 data: CreateCollectionData<T::AccountId>,452 data: CreateCollectionData<T::AccountId>,350 <PalletCommon<T>>::init_collection(owner, data, is_external)455 <PalletCommon<T>>::init_collection(owner, data, is_external)351 }456 }457458 /// Destroy NFT collection459 ///460 /// `destroy_collection` will throw error if collection contains any tokens.461 /// Only owner can destroy collection.352 pub fn destroy_collection(462 pub fn destroy_collection(353 collection: NonfungibleHandle<T>,463 collection: NonfungibleHandle<T>,354 sender: &T::CrossAccountId,464 sender: &T::CrossAccountId,373 Ok(())483 Ok(())374 }484 }375485486 /// Burn NFT token487 ///488 /// `burn` removes `token` from the `collection`, from it's owner and from the parent token489 /// if the token is nested.490 /// Only the owner can `burn` the token. The `token` shouldn't have any nested tokens.491 /// Also removes all corresponding properties and auxiliary properties.492 ///493 /// - `token`: Token that should be burned494 /// - `collection`: Collection that contains the token376 pub fn burn(495 pub fn burn(377 collection: &NonfungibleHandle<T>,496 collection: &NonfungibleHandle<T>,378 sender: &T::CrossAccountId,497 sender: &T::CrossAccountId,442 Ok(())561 Ok(())443 }562 }444563564 /// Same as [`burn`] but burns all the tokens that are nested in the token first565 ///566 /// - `self_budget`: Limit for searching children in depth.567 /// - `breadth_budget`: Limit of breadth of searching children.568 ///569 /// [`burn`]: struct.Pallet.html#method.burn445 #[transactional]570 #[transactional]446 pub fn burn_recursively(571 pub fn burn_recursively(447 collection: &NonfungibleHandle<T>,572 collection: &NonfungibleHandle<T>,481 })606 })482 }607 }483608609 /// Batch operation to add, edit or remove properties for the token610 ///611 /// All affected properties should have mutable permission and sender should have612 /// permission to edit those properties.613 ///614 /// - `nesting_budget`: Limit for searching parents in depth to check ownership.615 /// - `is_token_create`: Indicates that method is called during token initialization.616 /// Allows to bypass ownership check.484 #[transactional]617 #[transactional]485 fn modify_token_properties(618 fn modify_token_properties(486 collection: &NonfungibleHandle<T>,619 collection: &NonfungibleHandle<T>,574 Ok(())707 Ok(())575 }708 }576709710 /// Batch operation to add or edit properties for the token711 ///712 /// Same as [`modify_token_properties`] but doesn't allow to remove properties713 ///714 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties577 pub fn set_token_properties(715 pub fn set_token_properties(578 collection: &NonfungibleHandle<T>,716 collection: &NonfungibleHandle<T>,579 sender: &T::CrossAccountId,717 sender: &T::CrossAccountId,592 )730 )593 }731 }594732733 /// Add or edit single property for the token734 ///735 /// Calls [`set_token_properties`] internally736 ///737 /// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties595 pub fn set_token_property(738 pub fn set_token_property(596 collection: &NonfungibleHandle<T>,739 collection: &NonfungibleHandle<T>,597 sender: &T::CrossAccountId,740 sender: &T::CrossAccountId,611 )754 )612 }755 }613756757 /// Batch operation to remove properties from the token758 ///759 /// Same as [`modify_token_properties`] but doesn't allow to add or edit properties760 ///761 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties614 pub fn delete_token_properties(762 pub fn delete_token_properties(615 collection: &NonfungibleHandle<T>,763 collection: &NonfungibleHandle<T>,616 sender: &T::CrossAccountId,764 sender: &T::CrossAccountId,630 )778 )631 }779 }632780781 /// Remove single property from the token782 ///783 /// Calls [`delete_token_properties`] internally784 ///785 /// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties633 pub fn delete_token_property(786 pub fn delete_token_property(634 collection: &NonfungibleHandle<T>,787 collection: &NonfungibleHandle<T>,635 sender: &T::CrossAccountId,788 sender: &T::CrossAccountId,646 )799 )647 }800 }648801802 /// Add or edit properties for the collection649 pub fn set_collection_properties(803 pub fn set_collection_properties(650 collection: &NonfungibleHandle<T>,804 collection: &NonfungibleHandle<T>,651 sender: &T::CrossAccountId,805 sender: &T::CrossAccountId,654 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)808 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)655 }809 }656810811 /// Remove properties from the collection657 pub fn delete_collection_properties(812 pub fn delete_collection_properties(658 collection: &CollectionHandle<T>,813 collection: &CollectionHandle<T>,659 sender: &T::CrossAccountId,814 sender: &T::CrossAccountId,662 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)817 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)663 }818 }664819820 /// Set property permissions for the token.821 ///822 /// Sender should be the owner or admin of token's collection.665 pub fn set_token_property_permissions(823 pub fn set_token_property_permissions(666 collection: &CollectionHandle<T>,824 collection: &CollectionHandle<T>,667 sender: &T::CrossAccountId,825 sender: &T::CrossAccountId,670 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)828 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)671 }829 }672830831 /// Set property permissions for the collection.832 ///833 /// Sender should be the owner or admin of the collection.673 pub fn set_property_permission(834 pub fn set_property_permission(674 collection: &CollectionHandle<T>,835 collection: &CollectionHandle<T>,675 sender: &T::CrossAccountId,836 sender: &T::CrossAccountId,678 <PalletCommon<T>>::set_property_permission(collection, sender, permission)839 <PalletCommon<T>>::set_property_permission(collection, sender, permission)679 }840 }680841842 /// Transfer NFT token from one account to another.843 ///844 /// `from` account stops being the owner and `to` account becomes the owner of the token.845 /// If `to` is token than `to` becomes owner of the token and the token become nested.846 /// Unnests token from previous parent if it was nested before.847 /// Removes allowance for the token if there was any.848 /// Throws if transfers aren't allowed for collection or if receiver reached token ownership limit.849 ///850 /// - `nesting_budget`: Limit for token nesting depth681 pub fn transfer(851 pub fn transfer(682 collection: &NonfungibleHandle<T>,852 collection: &NonfungibleHandle<T>,683 from: &T::CrossAccountId,853 from: &T::CrossAccountId,769 Ok(())939 Ok(())770 }940 }771941942 /// Batch operation to mint multiple NFT tokens.943 ///944 /// The sender should be the owner/admin of the collection or collection should be configured945 /// to allow public minting.946 /// Throws if amount of tokens reached it's limit for the collection or if caller reached947 /// token ownership limit.948 ///949 /// - `data`: Contains list of token properties and users who will become the owners of the950 /// corresponging tokens.951 /// - `nesting_budget`: Limit for token nesting depth772 pub fn create_multiple_items(952 pub fn create_multiple_items(773 collection: &NonfungibleHandle<T>,953 collection: &NonfungibleHandle<T>,774 sender: &T::CrossAccountId,954 sender: &T::CrossAccountId,953 }1133 }954 }1134 }95511351136 /// Set allowance for the spender to `transfer` or `burn` sender's token.1137 ///1138 /// - `token`: Token the spender is allowed to `transfer` or `burn`.956 pub fn set_allowance(1139 pub fn set_allowance(957 collection: &NonfungibleHandle<T>,1140 collection: &NonfungibleHandle<T>,958 sender: &T::CrossAccountId,1141 sender: &T::CrossAccountId,985 Ok(())1168 Ok(())986 }1169 }98711701171 /// Checks allowance for the spender to use the token.988 fn check_allowed(1172 fn check_allowed(989 collection: &NonfungibleHandle<T>,1173 collection: &NonfungibleHandle<T>,990 spender: &T::CrossAccountId,1174 spender: &T::CrossAccountId,1027 Ok(())1211 Ok(())1028 }1212 }102912131214 /// Transfer NFT token from one account to another.1215 ///1216 /// Same as the [`transfer`] but spender doesn't needs to be the owner of the token.1217 /// The owner should set allowance for the spender to transfer token.1218 ///1219 /// [`transfer`]: struct.Pallet.html#method.transfer1030 pub fn transfer_from(1220 pub fn transfer_from(1031 collection: &NonfungibleHandle<T>,1221 collection: &NonfungibleHandle<T>,1032 spender: &T::CrossAccountId,1222 spender: &T::CrossAccountId,1043 Self::transfer(collection, from, to, token, nesting_budget)1233 Self::transfer(collection, from, to, token, nesting_budget)1044 }1234 }104512351236 /// Burn NFT token for `from` account.1237 ///1238 /// Same as the [`burn`] but spender doesn't need to be an owner of the token. The owner should1239 /// set allowance for the spender to burn token.1240 ///1241 /// [`burn`]: struct.Pallet.html#method.burn1046 pub fn burn_from(1242 pub fn burn_from(1047 collection: &NonfungibleHandle<T>,1243 collection: &NonfungibleHandle<T>,1048 spender: &T::CrossAccountId,1244 spender: &T::CrossAccountId,1057 Self::burn(collection, from, token)1253 Self::burn(collection, from, token)1058 }1254 }105912551256 /// Check that `from` token could be nested in `under` token.1257 ///1060 pub fn check_nesting(1258 pub fn check_nesting(1061 handle: &NonfungibleHandle<T>,1259 handle: &NonfungibleHandle<T>,1062 sender: T::CrossAccountId,1260 sender: T::CrossAccountId,1126 .collect()1324 .collect()1127 }1325 }112813261327 /// Mint single NFT token.1328 ///1129 /// Delegated to `create_multiple_items`1329 /// Delegated to [`create_multiple_items`]1330 ///1331 /// [`create_multiple_items`]: struct.Pallet.html#method.create_multiple_items1130 pub fn create_item(1332 pub fn create_item(1131 collection: &NonfungibleHandle<T>,1333 collection: &NonfungibleHandle<T>,1132 sender: &T::CrossAccountId,1334 sender: &T::CrossAccountId,pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth535354// Selector: 4136937754// Selector: 4136937755contract TokenProperties is Dummy, ERC165 {55contract TokenProperties is Dummy, ERC165 {56 // @notice Set permissions for token property.57 // @dev Throws error if `msg.sender` is not admin or owner of the collection.58 // @param key Property key.59 // @param is_mutable Permission to mutate property.60 // @param collection_admin Permission to mutate property by collection admin if property is mutable.61 // @param token_owner Permission to mutate property by token owner if property is mutable.62 //56 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa63 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa57 function setTokenPropertyPermission(64 function setTokenPropertyPermission(58 string memory key,65 string memory key,68 dummy = 0;75 dummy = 0;69 }76 }707778 // @notice Set token property value.79 // @dev Throws error if `msg.sender` has no permission to edit the property.80 // @param tokenId ID of the token.81 // @param key Property key.82 // @param value Property value.83 //71 // Selector: setProperty(uint256,string,bytes) 1752d67b84 // Selector: setProperty(uint256,string,bytes) 1752d67b72 function setProperty(85 function setProperty(73 uint256 tokenId,86 uint256 tokenId,81 dummy = 0;94 dummy = 0;82 }95 }839697 // @notice Delete token property value.98 // @dev Throws error if `msg.sender` has no permission to edit the property.99 // @param tokenId ID of the token.100 // @param key Property key.101 //84 // Selector: deleteProperty(uint256,string) 066111d1102 // Selector: deleteProperty(uint256,string) 066111d185 function deleteProperty(uint256 tokenId, string memory key) public {103 function deleteProperty(uint256 tokenId, string memory key) public {86 require(false, stub_error);104 require(false, stub_error);89 dummy = 0;107 dummy = 0;90 }108 }91109110 // @notice Get token property value.92 // Throws error if key not found111 // @dev Throws error if key not found112 // @param tokenId ID of the token.113 // @param key Property key.114 // @return Property value bytes93 //115 //94 // Selector: property(uint256,string) 7228c327116 // Selector: property(uint256,string) 7228c32795 function property(uint256 tokenId, string memory key)117 function property(uint256 tokenId, string memory key)107129108// Selector: 42966c68130// Selector: 42966c68109contract ERC721Burnable is Dummy, ERC165 {131contract ERC721Burnable is Dummy, ERC165 {132 // @notice Burns a specific ERC721 token.133 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized134 // operator of the current owner.135 // @param tokenId The NFT to approve136 //110 // Selector: burn(uint256) 42966c68137 // Selector: burn(uint256) 42966c68111 function burn(uint256 tokenId) public {138 function burn(uint256 tokenId) public {112 require(false, stub_error);139 require(false, stub_error);117144118// Selector: 58800161145// Selector: 58800161119contract ERC721 is Dummy, ERC165, ERC721Events {146contract ERC721 is Dummy, ERC165, ERC721Events {147 // @notice Count all NFTs assigned to an owner148 // @dev NFTs assigned to the zero address are considered invalid, and this149 // function throws for queries about the zero address.150 // @param owner An address for whom to query the balance151 // @return The number of NFTs owned by `owner`, possibly zero152 //120 // Selector: balanceOf(address) 70a08231153 // Selector: balanceOf(address) 70a08231121 function balanceOf(address owner) public view returns (uint256) {154 function balanceOf(address owner) public view returns (uint256) {122 require(false, stub_error);155 require(false, stub_error);125 return 0;158 return 0;126 }159 }127160161 // @notice Find the owner of an NFT162 // @dev NFTs assigned to zero address are considered invalid, and queries163 // about them do throw.164 // @param tokenId The identifier for an NFT165 // @return The address of the owner of the NFT166 //128 // Selector: ownerOf(uint256) 6352211e167 // Selector: ownerOf(uint256) 6352211e129 function ownerOf(uint256 tokenId) public view returns (address) {168 function ownerOf(uint256 tokenId) public view returns (address) {130 require(false, stub_error);169 require(false, stub_error);133 return 0x0000000000000000000000000000000000000000;172 return 0x0000000000000000000000000000000000000000;134 }173 }135174136 // Not implemented175 // @dev Not implemented137 //176 //138 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672177 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672139 function safeTransferFromWithData(178 function safeTransferFromWithData(150 dummy = 0;189 dummy = 0;151 }190 }152191153 // Not implemented192 // @dev Not implemented154 //193 //155 // Selector: safeTransferFrom(address,address,uint256) 42842e0e194 // Selector: safeTransferFrom(address,address,uint256) 42842e0e156 function safeTransferFrom(195 function safeTransferFrom(165 dummy = 0;204 dummy = 0;166 }205 }167206207 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE208 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE209 // THEY MAY BE PERMANENTLY LOST210 // @dev Throws unless `msg.sender` is the current owner or an authorized211 // operator for this NFT. Throws if `from` is not the current owner. Throws212 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.213 // @param from The current owner of the NFT214 // @param to The new owner215 // @param tokenId The NFT to transfer216 // @param _value Not used for an NFT217 //168 // Selector: transferFrom(address,address,uint256) 23b872dd218 // Selector: transferFrom(address,address,uint256) 23b872dd169 function transferFrom(219 function transferFrom(170 address from,220 address from,178 dummy = 0;228 dummy = 0;179 }229 }180230231 // @notice Set or reaffirm the approved address for an NFT232 // @dev The zero address indicates there is no approved address.233 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized234 // operator of the current owner.235 // @param approved The new approved NFT controller236 // @param tokenId The NFT to approve237 //181 // Selector: approve(address,uint256) 095ea7b3238 // Selector: approve(address,uint256) 095ea7b3182 function approve(address approved, uint256 tokenId) public {239 function approve(address approved, uint256 tokenId) public {183 require(false, stub_error);240 require(false, stub_error);186 dummy = 0;243 dummy = 0;187 }244 }188245189 // Not implemented246 // @dev Not implemented190 //247 //191 // Selector: setApprovalForAll(address,bool) a22cb465248 // Selector: setApprovalForAll(address,bool) a22cb465192 function setApprovalForAll(address operator, bool approved) public {249 function setApprovalForAll(address operator, bool approved) public {196 dummy = 0;253 dummy = 0;197 }254 }198255199 // Not implemented256 // @dev Not implemented200 //257 //201 // Selector: getApproved(uint256) 081812fc258 // Selector: getApproved(uint256) 081812fc202 function getApproved(uint256 tokenId) public view returns (address) {259 function getApproved(uint256 tokenId) public view returns (address) {206 return 0x0000000000000000000000000000000000000000;263 return 0x0000000000000000000000000000000000000000;207 }264 }208265209 // Not implemented266 // @dev Not implemented210 //267 //211 // Selector: isApprovedForAll(address,address) e985e9c5268 // Selector: isApprovedForAll(address,address) e985e9c5212 function isApprovedForAll(address owner, address operator)269 function isApprovedForAll(address owner, address operator)224281225// Selector: 5b5e139f282// Selector: 5b5e139f226contract ERC721Metadata is Dummy, ERC165 {283contract ERC721Metadata is Dummy, ERC165 {284 // @notice A descriptive name for a collection of NFTs in this contract285 //227 // Selector: name() 06fdde03286 // Selector: name() 06fdde03228 function name() public view returns (string memory) {287 function name() public view returns (string memory) {229 require(false, stub_error);288 require(false, stub_error);230 dummy;289 dummy;231 return "";290 return "";232 }291 }233292293 // @notice An abbreviated name for NFTs in this contract294 //234 // Selector: symbol() 95d89b41295 // Selector: symbol() 95d89b41235 function symbol() public view returns (string memory) {296 function symbol() public view returns (string memory) {236 require(false, stub_error);297 require(false, stub_error);237 dummy;298 dummy;238 return "";299 return "";239 }300 }240301302 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.303 // @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC304 // 3986. The URI may point to a JSON file that conforms to the "ERC721305 // Metadata JSON Schema".241 // Returns token's const_metadata306 // @return token's const_metadata242 //307 //243 // Selector: tokenURI(uint256) c87b56dd308 // Selector: tokenURI(uint256) c87b56dd244 function tokenURI(uint256 tokenId) public view returns (string memory) {309 function tokenURI(uint256 tokenId) public view returns (string memory) {258 return false;323 return false;259 }324 }260325326 // @notice Function to mint token.261 // `token_id` should be obtained with `next_token_id` method,327 // @dev `tokenId` should be obtained with `nextTokenId` method,262 // unlike standard, you can't specify it manually328 // unlike standard, you can't specify it manually329 // @param to The new owner330 // @param tokenId ID of the minted NFT263 //331 //264 // Selector: mint(address,uint256) 40c10f19332 // Selector: mint(address,uint256) 40c10f19265 function mint(address to, uint256 tokenId) public returns (bool) {333 function mint(address to, uint256 tokenId) public returns (bool) {270 return false;338 return false;271 }339 }272340341 // @notice Function to mint token with the given tokenUri.273 // `token_id` should be obtained with `next_token_id` method,342 // @dev `tokenId` should be obtained with `nextTokenId` method,274 // unlike standard, you can't specify it manually343 // unlike standard, you can't specify it manually344 // @param to The new owner345 // @param tokenId ID of the minted NFT346 // @param tokenUri Token URI that would be stored in the NFT properties275 //347 //276 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f348 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f277 function mintWithTokenURI(349 function mintWithTokenURI(287 return false;359 return false;288 }360 }289361290 // Not implemented362 // @dev Not implemented291 //363 //292 // Selector: finishMinting() 7d64bcb4364 // Selector: finishMinting() 7d64bcb4293 function finishMinting() public returns (bool) {365 function finishMinting() public returns (bool) {299371300// Selector: 780e9d63372// Selector: 780e9d63301contract ERC721Enumerable is Dummy, ERC165 {373contract ERC721Enumerable is Dummy, ERC165 {374 // @notice Enumerate valid NFTs375 // @param index A counter less than `totalSupply()`376 // @return The token identifier for the `index`th NFT,377 // (sort order not specified)378 //302 // Selector: tokenByIndex(uint256) 4f6ccce7379 // Selector: tokenByIndex(uint256) 4f6ccce7303 function tokenByIndex(uint256 index) public view returns (uint256) {380 function tokenByIndex(uint256 index) public view returns (uint256) {304 require(false, stub_error);381 require(false, stub_error);307 return 0;384 return 0;308 }385 }309386310 // Not implemented387 // @dev Not implemented311 //388 //312 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59389 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59313 function tokenOfOwnerByIndex(address owner, uint256 index)390 function tokenOfOwnerByIndex(address owner, uint256 index)322 return 0;399 return 0;323 }400 }324401402 // @notice Count NFTs tracked by this contract403 // @return A count of valid NFTs tracked by this contract, where each one of404 // them has an assigned and queryable owner not equal to the zero address405 //325 // Selector: totalSupply() 18160ddd406 // Selector: totalSupply() 18160ddd326 function totalSupply() public view returns (uint256) {407 function totalSupply() public view returns (uint256) {327 require(false, stub_error);408 require(false, stub_error);332413333// Selector: 7d9262e6414// Selector: 7d9262e6334contract Collection is Dummy, ERC165 {415contract Collection is Dummy, ERC165 {416 // Set collection property.417 //418 // @param key Property key.419 // @param value Propery value.420 //335 // Selector: setCollectionProperty(string,bytes) 2f073f66421 // Selector: setCollectionProperty(string,bytes) 2f073f66336 function setCollectionProperty(string memory key, bytes memory value)422 function setCollectionProperty(string memory key, bytes memory value)337 public423 public342 dummy = 0;428 dummy = 0;343 }429 }344430431 // Delete collection property.432 //433 // @param key Property key.434 //345 // Selector: deleteCollectionProperty(string) 7b7debce435 // Selector: deleteCollectionProperty(string) 7b7debce346 function deleteCollectionProperty(string memory key) public {436 function deleteCollectionProperty(string memory key) public {347 require(false, stub_error);437 require(false, stub_error);348 key;438 key;349 dummy = 0;439 dummy = 0;350 }440 }351441442 // Get collection property.443 //352 // Throws error if key not found444 // @dev Throws error if key not found.445 //446 // @param key Property key.447 // @return bytes The property corresponding to the key.353 //448 //354 // Selector: collectionProperty(string) cf24fd6d449 // Selector: collectionProperty(string) cf24fd6d355 function collectionProperty(string memory key)450 function collectionProperty(string memory key)363 return hex"";458 return hex"";364 }459 }365460461 // Set the sponsor of the collection.462 //463 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.464 //465 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.466 //366 // Selector: setCollectionSponsor(address) 7623402e467 // Selector: setCollectionSponsor(address) 7623402e367 function setCollectionSponsor(address sponsor) public {468 function setCollectionSponsor(address sponsor) public {368 require(false, stub_error);469 require(false, stub_error);369 sponsor;470 sponsor;370 dummy = 0;471 dummy = 0;371 }472 }372473474 // Collection sponsorship confirmation.475 //476 // @dev After setting the sponsor for the collection, it must be confirmed with this function.477 //373 // Selector: confirmCollectionSponsorship() 3c50e97a478 // Selector: confirmCollectionSponsorship() 3c50e97a374 function confirmCollectionSponsorship() public {479 function confirmCollectionSponsorship() public {375 require(false, stub_error);480 require(false, stub_error);376 dummy = 0;481 dummy = 0;377 }482 }378483484 // Set limits for the collection.485 // @dev Throws error if limit not found.486 // @param limit Name of the limit. Valid names:487 // "accountTokenOwnershipLimit",488 // "sponsoredDataSize",489 // "sponsoredDataRateLimit",490 // "tokenLimit",491 // "sponsorTransferTimeout",492 // "sponsorApproveTimeout"493 // @param value Value of the limit.494 //379 // Selector: setCollectionLimit(string,uint32) 6a3841db495 // Selector: setCollectionLimit(string,uint32) 6a3841db380 function setCollectionLimit(string memory limit, uint32 value) public {496 function setCollectionLimit(string memory limit, uint32 value) public {381 require(false, stub_error);497 require(false, stub_error);384 dummy = 0;500 dummy = 0;385 }501 }386502503 // Set limits for the collection.504 // @dev Throws error if limit not found.505 // @param limit Name of the limit. Valid names:506 // "ownerCanTransfer",507 // "ownerCanDestroy",508 // "transfersEnabled"509 // @param value Value of the limit.510 //387 // Selector: setCollectionLimit(string,bool) 993b7fba511 // Selector: setCollectionLimit(string,bool) 993b7fba388 function setCollectionLimit(string memory limit, bool value) public {512 function setCollectionLimit(string memory limit, bool value) public {389 require(false, stub_error);513 require(false, stub_error);392 dummy = 0;516 dummy = 0;393 }517 }394518519 // Get contract address.520 //395 // Selector: contractAddress() f6b4dfb4521 // Selector: contractAddress() f6b4dfb4396 function contractAddress() public view returns (address) {522 function contractAddress() public view returns (address) {397 require(false, stub_error);523 require(false, stub_error);398 dummy;524 dummy;399 return 0x0000000000000000000000000000000000000000;525 return 0x0000000000000000000000000000000000000000;400 }526 }401527528 // Add collection admin by substrate address.529 // @param new_admin Substrate administrator address.530 //402 // Selector: addCollectionAdminSubstrate(uint256) 5730062b531 // Selector: addCollectionAdminSubstrate(uint256) 5730062b403 function addCollectionAdminSubstrate(uint256 newAdmin) public view {532 function addCollectionAdminSubstrate(uint256 newAdmin) public {404 require(false, stub_error);533 require(false, stub_error);405 newAdmin;534 newAdmin;406 dummy;535 dummy = 0;407 }536 }408537538 // Remove collection admin by substrate address.539 // @param admin Substrate administrator address.540 //409 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9541 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9410 function removeCollectionAdminSubstrate(uint256 newAdmin) public view {542 function removeCollectionAdminSubstrate(uint256 admin) public {411 require(false, stub_error);543 require(false, stub_error);412 newAdmin;544 admin;413 dummy;545 dummy = 0;414 }546 }415547548 // Add collection admin.549 // @param new_admin Address of the added administrator.550 //416 // Selector: addCollectionAdmin(address) 92e462c7551 // Selector: addCollectionAdmin(address) 92e462c7417 function addCollectionAdmin(address newAdmin) public view {552 function addCollectionAdmin(address newAdmin) public {418 require(false, stub_error);553 require(false, stub_error);419 newAdmin;554 newAdmin;420 dummy;555 dummy = 0;421 }556 }422557558 // Remove collection admin.559 //560 // @param new_admin Address of the removed administrator.561 //423 // Selector: removeCollectionAdmin(address) fafd7b42562 // Selector: removeCollectionAdmin(address) fafd7b42424 function removeCollectionAdmin(address admin) public view {563 function removeCollectionAdmin(address admin) public {425 require(false, stub_error);564 require(false, stub_error);426 admin;565 admin;427 dummy;566 dummy = 0;428 }567 }429568569 // Toggle accessibility of collection nesting.570 //571 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'572 //430 // Selector: setCollectionNesting(bool) 112d4586573 // Selector: setCollectionNesting(bool) 112d4586431 function setCollectionNesting(bool enable) public {574 function setCollectionNesting(bool enable) public {432 require(false, stub_error);575 require(false, stub_error);433 enable;576 enable;434 dummy = 0;577 dummy = 0;435 }578 }436579580 // Toggle accessibility of collection nesting.581 //582 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'583 // @param collections Addresses of collections that will be available for nesting.584 //437 // Selector: setCollectionNesting(bool,address[]) 64872396585 // Selector: setCollectionNesting(bool,address[]) 64872396438 function setCollectionNesting(bool enable, address[] memory collections)586 function setCollectionNesting(bool enable, address[] memory collections)439 public587 public444 dummy = 0;592 dummy = 0;445 }593 }446594595 // Set the collection access method.596 // @param mode Access mode597 // 0 for Normal598 // 1 for AllowList599 //447 // Selector: setCollectionAccess(uint8) 41835d4c600 // Selector: setCollectionAccess(uint8) 41835d4c448 function setCollectionAccess(uint8 mode) public {601 function setCollectionAccess(uint8 mode) public {449 require(false, stub_error);602 require(false, stub_error);450 mode;603 mode;451 dummy = 0;604 dummy = 0;452 }605 }453606607 // Add the user to the allowed list.608 //609 // @param user Address of a trusted user.610 //454 // Selector: addToCollectionAllowList(address) 67844fe6611 // Selector: addToCollectionAllowList(address) 67844fe6455 function addToCollectionAllowList(address user) public view {612 function addToCollectionAllowList(address user) public {456 require(false, stub_error);613 require(false, stub_error);457 user;614 user;458 dummy;615 dummy = 0;459 }616 }460617618 // Remove the user from the allowed list.619 //620 // @param user Address of a removed user.621 //461 // Selector: removeFromCollectionAllowList(address) 85c51acb622 // Selector: removeFromCollectionAllowList(address) 85c51acb462 function removeFromCollectionAllowList(address user) public view {623 function removeFromCollectionAllowList(address user) public {463 require(false, stub_error);624 require(false, stub_error);464 user;625 user;465 dummy;626 dummy = 0;466 }627 }467628629 // Switch permission for minting.630 //631 // @param mode Enable if "true".632 //468 // Selector: setCollectionMintMode(bool) 00018e84633 // Selector: setCollectionMintMode(bool) 00018e84469 function setCollectionMintMode(bool mode) public {634 function setCollectionMintMode(bool mode) public {470 require(false, stub_error);635 require(false, stub_error);475640476// Selector: d74d154f641// Selector: d74d154f477contract ERC721UniqueExtensions is Dummy, ERC165 {642contract ERC721UniqueExtensions is Dummy, ERC165 {643 // @notice Transfer ownership of an NFT644 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`645 // is the zero address. Throws if `tokenId` is not a valid NFT.646 // @param to The new owner647 // @param tokenId The NFT to transfer648 // @param _value Not used for an NFT649 //478 // Selector: transfer(address,uint256) a9059cbb650 // Selector: transfer(address,uint256) a9059cbb479 function transfer(address to, uint256 tokenId) public {651 function transfer(address to, uint256 tokenId) public {480 require(false, stub_error);652 require(false, stub_error);483 dummy = 0;655 dummy = 0;484 }656 }485657658 // @notice Burns a specific ERC721 token.659 // @dev Throws unless `msg.sender` is the current owner or an authorized660 // operator for this NFT. Throws if `from` is not the current owner. Throws661 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.662 // @param from The current owner of the NFT663 // @param tokenId The NFT to transfer664 // @param _value Not used for an NFT665 //486 // Selector: burnFrom(address,uint256) 79cc6790666 // Selector: burnFrom(address,uint256) 79cc6790487 function burnFrom(address from, uint256 tokenId) public {667 function burnFrom(address from, uint256 tokenId) public {488 require(false, stub_error);668 require(false, stub_error);491 dummy = 0;671 dummy = 0;492 }672 }493673674 // @notice Returns next free NFT ID.675 //494 // Selector: nextTokenId() 75794a3c676 // Selector: nextTokenId() 75794a3c495 function nextTokenId() public view returns (uint256) {677 function nextTokenId() public view returns (uint256) {496 require(false, stub_error);678 require(false, stub_error);497 dummy;679 dummy;498 return 0;680 return 0;499 }681 }500682683 // @notice Function to mint multiple tokens.684 // @dev `tokenIds` should be an array of consecutive numbers and first number685 // should be obtained with `nextTokenId` method686 // @param to The new owner687 // @param tokenIds IDs of the minted NFTs688 //501 // Selector: mintBulk(address,uint256[]) 44a9945e689 // Selector: mintBulk(address,uint256[]) 44a9945e502 function mintBulk(address to, uint256[] memory tokenIds)690 function mintBulk(address to, uint256[] memory tokenIds)503 public691 public510 return false;698 return false;511 }699 }512700701 // @notice Function to mint multiple tokens with the given tokenUris.702 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive703 // numbers and first number should be obtained with `nextTokenId` method704 // @param to The new owner705 // @param tokens array of pairs of token ID and token URI for minted tokens706 //513 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006707 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006514 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)708 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)515 public709 publicpallets/nonfungible/src/weights.rsdiffbeforeafterboth3//! Autogenerated weights for pallet_nonfungible3//! Autogenerated weights for pallet_nonfungible4//!4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-06-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024889// Executed Command:9// Executed Command:56 // Storage: Nonfungible TokenData (r:0 w:1)56 // Storage: Nonfungible TokenData (r:0 w:1)57 // Storage: Nonfungible Owned (r:0 w:1)57 // Storage: Nonfungible Owned (r:0 w:1)58 fn create_item() -> Weight {58 fn create_item() -> Weight {59 (24_135_000 as Weight)59 (20_328_000 as Weight)60 .saturating_add(T::DbWeight::get().reads(2 as Weight))60 .saturating_add(T::DbWeight::get().reads(2 as Weight))61 .saturating_add(T::DbWeight::get().writes(4 as Weight))61 .saturating_add(T::DbWeight::get().writes(4 as Weight))62 }62 }65 // Storage: Nonfungible TokenData (r:0 w:4)65 // Storage: Nonfungible TokenData (r:0 w:4)66 // Storage: Nonfungible Owned (r:0 w:4)66 // Storage: Nonfungible Owned (r:0 w:4)67 fn create_multiple_items(b: u32, ) -> Weight {67 fn create_multiple_items(b: u32, ) -> Weight {68 (21_952_000 as Weight)68 (10_134_000 as Weight)69 // Standard Error: 5_00069 // Standard Error: 3_00070 .saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))70 .saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))71 .saturating_add(T::DbWeight::get().reads(2 as Weight))71 .saturating_add(T::DbWeight::get().reads(2 as Weight))72 .saturating_add(T::DbWeight::get().writes(2 as Weight))72 .saturating_add(T::DbWeight::get().writes(2 as Weight))73 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))73 .saturating_add(T::DbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))77 // Storage: Nonfungible TokenData (r:0 w:4)77 // Storage: Nonfungible TokenData (r:0 w:4)78 // Storage: Nonfungible Owned (r:0 w:4)78 // Storage: Nonfungible Owned (r:0 w:4)79 fn create_multiple_items_ex(b: u32, ) -> Weight {79 fn create_multiple_items_ex(b: u32, ) -> Weight {80 (10_432_000 as Weight)80 (5_710_000 as Weight)81 // Standard Error: 6_00081 // Standard Error: 4_00082 .saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))82 .saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))83 .saturating_add(T::DbWeight::get().reads(1 as Weight))83 .saturating_add(T::DbWeight::get().reads(1 as Weight))84 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))84 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))85 .saturating_add(T::DbWeight::get().writes(1 as Weight))85 .saturating_add(T::DbWeight::get().writes(1 as Weight))93 // Storage: Nonfungible Owned (r:0 w:1)93 // Storage: Nonfungible Owned (r:0 w:1)94 // Storage: Nonfungible TokenProperties (r:0 w:1)94 // Storage: Nonfungible TokenProperties (r:0 w:1)95 fn burn_item() -> Weight {95 fn burn_item() -> Weight {96 (29_798_000 as Weight)96 (28_433_000 as Weight)97 .saturating_add(T::DbWeight::get().reads(5 as Weight))97 .saturating_add(T::DbWeight::get().reads(5 as Weight))98 .saturating_add(T::DbWeight::get().writes(5 as Weight))98 .saturating_add(T::DbWeight::get().writes(5 as Weight))99 }99 }105 // Storage: Nonfungible Owned (r:0 w:1)105 // Storage: Nonfungible Owned (r:0 w:1)106 // Storage: Nonfungible TokenProperties (r:0 w:1)106 // Storage: Nonfungible TokenProperties (r:0 w:1)107 fn burn_recursively_self_raw() -> Weight {107 fn burn_recursively_self_raw() -> Weight {108 (37_955_000 as Weight)108 (34_435_000 as Weight)109 .saturating_add(T::DbWeight::get().reads(5 as Weight))109 .saturating_add(T::DbWeight::get().reads(5 as Weight))110 .saturating_add(T::DbWeight::get().writes(5 as Weight))110 .saturating_add(T::DbWeight::get().writes(5 as Weight))111 }111 }119 // Storage: Common CollectionById (r:1 w:0)119 // Storage: Common CollectionById (r:1 w:0)120 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {120 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {121 (0 as Weight)121 (0 as Weight)122 // Standard Error: 1_349_000122 // Standard Error: 1_539_000123 .saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))123 .saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))124 .saturating_add(T::DbWeight::get().reads(7 as Weight))124 .saturating_add(T::DbWeight::get().reads(7 as Weight))125 .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))125 .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))126 .saturating_add(T::DbWeight::get().writes(6 as Weight))126 .saturating_add(T::DbWeight::get().writes(6 as Weight))131 // Storage: Nonfungible Allowance (r:1 w:0)131 // Storage: Nonfungible Allowance (r:1 w:0)132 // Storage: Nonfungible Owned (r:0 w:2)132 // Storage: Nonfungible Owned (r:0 w:2)133 fn transfer() -> Weight {133 fn transfer() -> Weight {134 (27_867_000 as Weight)134 (24_376_000 as Weight)135 .saturating_add(T::DbWeight::get().reads(4 as Weight))135 .saturating_add(T::DbWeight::get().reads(4 as Weight))136 .saturating_add(T::DbWeight::get().writes(5 as Weight))136 .saturating_add(T::DbWeight::get().writes(5 as Weight))137 }137 }138 // Storage: Nonfungible TokenData (r:1 w:0)138 // Storage: Nonfungible TokenData (r:1 w:0)139 // Storage: Nonfungible Allowance (r:1 w:1)139 // Storage: Nonfungible Allowance (r:1 w:1)140 fn approve() -> Weight {140 fn approve() -> Weight {141 (18_824_000 as Weight)141 (15_890_000 as Weight)142 .saturating_add(T::DbWeight::get().reads(2 as Weight))142 .saturating_add(T::DbWeight::get().reads(2 as Weight))143 .saturating_add(T::DbWeight::get().writes(1 as Weight))143 .saturating_add(T::DbWeight::get().writes(1 as Weight))144 }144 }147 // Storage: Nonfungible AccountBalance (r:2 w:2)147 // Storage: Nonfungible AccountBalance (r:2 w:2)148 // Storage: Nonfungible Owned (r:0 w:2)148 // Storage: Nonfungible Owned (r:0 w:2)149 fn transfer_from() -> Weight {149 fn transfer_from() -> Weight {150 (32_879_000 as Weight)150 (28_634_000 as Weight)151 .saturating_add(T::DbWeight::get().reads(4 as Weight))151 .saturating_add(T::DbWeight::get().reads(4 as Weight))152 .saturating_add(T::DbWeight::get().writes(6 as Weight))152 .saturating_add(T::DbWeight::get().writes(6 as Weight))153 }153 }159 // Storage: Nonfungible Owned (r:0 w:1)159 // Storage: Nonfungible Owned (r:0 w:1)160 // Storage: Nonfungible TokenProperties (r:0 w:1)160 // Storage: Nonfungible TokenProperties (r:0 w:1)161 fn burn_from() -> Weight {161 fn burn_from() -> Weight {162 (37_061_000 as Weight)162 (32_201_000 as Weight)163 .saturating_add(T::DbWeight::get().reads(5 as Weight))163 .saturating_add(T::DbWeight::get().reads(5 as Weight))164 .saturating_add(T::DbWeight::get().writes(6 as Weight))164 .saturating_add(T::DbWeight::get().writes(6 as Weight))165 }165 }166 // Storage: Common CollectionPropertyPermissions (r:1 w:1)166 // Storage: Common CollectionPropertyPermissions (r:1 w:1)167 fn set_token_property_permissions(b: u32, ) -> Weight {167 fn set_token_property_permissions(b: u32, ) -> Weight {168 (0 as Weight)168 (0 as Weight)169 // Standard Error: 57_000169 // Standard Error: 57_000170 .saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))170 .saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))173 }173 }174 // Storage: Common CollectionPropertyPermissions (r:1 w:0)174 // Storage: Common CollectionPropertyPermissions (r:1 w:0)175 // Storage: Nonfungible TokenData (r:1 w:0)176 // Storage: Nonfungible TokenProperties (r:1 w:1)175 // Storage: Nonfungible TokenProperties (r:1 w:1)177 fn set_token_properties(b: u32, ) -> Weight {176 fn set_token_properties(b: u32, ) -> Weight {178 (0 as Weight)177 (0 as Weight)179 // Standard Error: 2_278_000178 // Standard Error: 1_648_000180 .saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))179 .saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))181 .saturating_add(T::DbWeight::get().reads(3 as Weight))180 .saturating_add(T::DbWeight::get().reads(2 as Weight))182 .saturating_add(T::DbWeight::get().writes(1 as Weight))181 .saturating_add(T::DbWeight::get().writes(1 as Weight))183 }182 }184 // Storage: Common CollectionPropertyPermissions (r:1 w:0)183 // Storage: Common CollectionPropertyPermissions (r:1 w:0)185 // Storage: Nonfungible TokenData (r:1 w:0)186 // Storage: Nonfungible TokenProperties (r:1 w:1)184 // Storage: Nonfungible TokenProperties (r:1 w:1)187 fn delete_token_properties(b: u32, ) -> Weight {185 fn delete_token_properties(b: u32, ) -> Weight {188 (0 as Weight)186 (0 as Weight)189 // Standard Error: 2_234_000187 // Standard Error: 1_632_000190 .saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))188 .saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))191 .saturating_add(T::DbWeight::get().reads(3 as Weight))189 .saturating_add(T::DbWeight::get().reads(2 as Weight))192 .saturating_add(T::DbWeight::get().writes(1 as Weight))190 .saturating_add(T::DbWeight::get().writes(1 as Weight))193 }191 }194}192}200 // Storage: Nonfungible TokenData (r:0 w:1)198 // Storage: Nonfungible TokenData (r:0 w:1)201 // Storage: Nonfungible Owned (r:0 w:1)199 // Storage: Nonfungible Owned (r:0 w:1)202 fn create_item() -> Weight {200 fn create_item() -> Weight {203 (24_135_000 as Weight)201 (20_328_000 as Weight)204 .saturating_add(RocksDbWeight::get().reads(2 as Weight))202 .saturating_add(RocksDbWeight::get().reads(2 as Weight))205 .saturating_add(RocksDbWeight::get().writes(4 as Weight))203 .saturating_add(RocksDbWeight::get().writes(4 as Weight))206 }204 }209 // Storage: Nonfungible TokenData (r:0 w:4)207 // Storage: Nonfungible TokenData (r:0 w:4)210 // Storage: Nonfungible Owned (r:0 w:4)208 // Storage: Nonfungible Owned (r:0 w:4)211 fn create_multiple_items(b: u32, ) -> Weight {209 fn create_multiple_items(b: u32, ) -> Weight {212 (21_952_000 as Weight)210 (10_134_000 as Weight)213 // Standard Error: 5_000211 // Standard Error: 3_000214 .saturating_add((4_727_000 as Weight).saturating_mul(b as Weight))212 .saturating_add((4_927_000 as Weight).saturating_mul(b as Weight))215 .saturating_add(RocksDbWeight::get().reads(2 as Weight))213 .saturating_add(RocksDbWeight::get().reads(2 as Weight))216 .saturating_add(RocksDbWeight::get().writes(2 as Weight))214 .saturating_add(RocksDbWeight::get().writes(2 as Weight))217 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))215 .saturating_add(RocksDbWeight::get().writes((2 as Weight).saturating_mul(b as Weight)))221 // Storage: Nonfungible TokenData (r:0 w:4)219 // Storage: Nonfungible TokenData (r:0 w:4)222 // Storage: Nonfungible Owned (r:0 w:4)220 // Storage: Nonfungible Owned (r:0 w:4)223 fn create_multiple_items_ex(b: u32, ) -> Weight {221 fn create_multiple_items_ex(b: u32, ) -> Weight {224 (10_432_000 as Weight)222 (5_710_000 as Weight)225 // Standard Error: 6_000223 // Standard Error: 4_000226 .saturating_add((7_383_000 as Weight).saturating_mul(b as Weight))224 .saturating_add((7_578_000 as Weight).saturating_mul(b as Weight))227 .saturating_add(RocksDbWeight::get().reads(1 as Weight))225 .saturating_add(RocksDbWeight::get().reads(1 as Weight))228 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))226 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))229 .saturating_add(RocksDbWeight::get().writes(1 as Weight))227 .saturating_add(RocksDbWeight::get().writes(1 as Weight))237 // Storage: Nonfungible Owned (r:0 w:1)235 // Storage: Nonfungible Owned (r:0 w:1)238 // Storage: Nonfungible TokenProperties (r:0 w:1)236 // Storage: Nonfungible TokenProperties (r:0 w:1)239 fn burn_item() -> Weight {237 fn burn_item() -> Weight {240 (29_798_000 as Weight)238 (28_433_000 as Weight)241 .saturating_add(RocksDbWeight::get().reads(5 as Weight))239 .saturating_add(RocksDbWeight::get().reads(5 as Weight))242 .saturating_add(RocksDbWeight::get().writes(5 as Weight))240 .saturating_add(RocksDbWeight::get().writes(5 as Weight))243 }241 }249 // Storage: Nonfungible Owned (r:0 w:1)247 // Storage: Nonfungible Owned (r:0 w:1)250 // Storage: Nonfungible TokenProperties (r:0 w:1)248 // Storage: Nonfungible TokenProperties (r:0 w:1)251 fn burn_recursively_self_raw() -> Weight {249 fn burn_recursively_self_raw() -> Weight {252 (37_955_000 as Weight)250 (34_435_000 as Weight)253 .saturating_add(RocksDbWeight::get().reads(5 as Weight))251 .saturating_add(RocksDbWeight::get().reads(5 as Weight))254 .saturating_add(RocksDbWeight::get().writes(5 as Weight))252 .saturating_add(RocksDbWeight::get().writes(5 as Weight))255 }253 }263 // Storage: Common CollectionById (r:1 w:0)261 // Storage: Common CollectionById (r:1 w:0)264 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {262 fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(b: u32, ) -> Weight {265 (0 as Weight)263 (0 as Weight)266 // Standard Error: 1_349_000264 // Standard Error: 1_539_000267 .saturating_add((275_145_000 as Weight).saturating_mul(b as Weight))265 .saturating_add((304_456_000 as Weight).saturating_mul(b as Weight))268 .saturating_add(RocksDbWeight::get().reads(7 as Weight))266 .saturating_add(RocksDbWeight::get().reads(7 as Weight))269 .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))267 .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(b as Weight)))270 .saturating_add(RocksDbWeight::get().writes(6 as Weight))268 .saturating_add(RocksDbWeight::get().writes(6 as Weight))275 // Storage: Nonfungible Allowance (r:1 w:0)273 // Storage: Nonfungible Allowance (r:1 w:0)276 // Storage: Nonfungible Owned (r:0 w:2)274 // Storage: Nonfungible Owned (r:0 w:2)277 fn transfer() -> Weight {275 fn transfer() -> Weight {278 (27_867_000 as Weight)276 (24_376_000 as Weight)279 .saturating_add(RocksDbWeight::get().reads(4 as Weight))277 .saturating_add(RocksDbWeight::get().reads(4 as Weight))280 .saturating_add(RocksDbWeight::get().writes(5 as Weight))278 .saturating_add(RocksDbWeight::get().writes(5 as Weight))281 }279 }282 // Storage: Nonfungible TokenData (r:1 w:0)280 // Storage: Nonfungible TokenData (r:1 w:0)283 // Storage: Nonfungible Allowance (r:1 w:1)281 // Storage: Nonfungible Allowance (r:1 w:1)284 fn approve() -> Weight {282 fn approve() -> Weight {285 (18_824_000 as Weight)283 (15_890_000 as Weight)286 .saturating_add(RocksDbWeight::get().reads(2 as Weight))284 .saturating_add(RocksDbWeight::get().reads(2 as Weight))287 .saturating_add(RocksDbWeight::get().writes(1 as Weight))285 .saturating_add(RocksDbWeight::get().writes(1 as Weight))288 }286 }291 // Storage: Nonfungible AccountBalance (r:2 w:2)289 // Storage: Nonfungible AccountBalance (r:2 w:2)292 // Storage: Nonfungible Owned (r:0 w:2)290 // Storage: Nonfungible Owned (r:0 w:2)293 fn transfer_from() -> Weight {291 fn transfer_from() -> Weight {294 (32_879_000 as Weight)292 (28_634_000 as Weight)295 .saturating_add(RocksDbWeight::get().reads(4 as Weight))293 .saturating_add(RocksDbWeight::get().reads(4 as Weight))296 .saturating_add(RocksDbWeight::get().writes(6 as Weight))294 .saturating_add(RocksDbWeight::get().writes(6 as Weight))297 }295 }303 // Storage: Nonfungible Owned (r:0 w:1)301 // Storage: Nonfungible Owned (r:0 w:1)304 // Storage: Nonfungible TokenProperties (r:0 w:1)302 // Storage: Nonfungible TokenProperties (r:0 w:1)305 fn burn_from() -> Weight {303 fn burn_from() -> Weight {306 (37_061_000 as Weight)304 (32_201_000 as Weight)307 .saturating_add(RocksDbWeight::get().reads(5 as Weight))305 .saturating_add(RocksDbWeight::get().reads(5 as Weight))308 .saturating_add(RocksDbWeight::get().writes(6 as Weight))306 .saturating_add(RocksDbWeight::get().writes(6 as Weight))309 }307 }310 // Storage: Common CollectionPropertyPermissions (r:1 w:1)308 // Storage: Common CollectionPropertyPermissions (r:1 w:1)311 fn set_token_property_permissions(b: u32, ) -> Weight {309 fn set_token_property_permissions(b: u32, ) -> Weight {312 (0 as Weight)310 (0 as Weight)313 // Standard Error: 57_000311 // Standard Error: 57_000314 .saturating_add((15_149_000 as Weight).saturating_mul(b as Weight))312 .saturating_add((15_232_000 as Weight).saturating_mul(b as Weight))315 .saturating_add(RocksDbWeight::get().reads(1 as Weight))313 .saturating_add(RocksDbWeight::get().reads(1 as Weight))316 .saturating_add(RocksDbWeight::get().writes(1 as Weight))314 .saturating_add(RocksDbWeight::get().writes(1 as Weight))317 }315 }318 // Storage: Common CollectionPropertyPermissions (r:1 w:0)316 // Storage: Common CollectionPropertyPermissions (r:1 w:0)319 // Storage: Nonfungible TokenData (r:1 w:0)320 // Storage: Nonfungible TokenProperties (r:1 w:1)317 // Storage: Nonfungible TokenProperties (r:1 w:1)321 fn set_token_properties(b: u32, ) -> Weight {318 fn set_token_properties(b: u32, ) -> Weight {322 (0 as Weight)319 (0 as Weight)323 // Standard Error: 2_278_000320 // Standard Error: 1_648_000324 .saturating_add((409_613_000 as Weight).saturating_mul(b as Weight))321 .saturating_add((288_654_000 as Weight).saturating_mul(b as Weight))325 .saturating_add(RocksDbWeight::get().reads(3 as Weight))322 .saturating_add(RocksDbWeight::get().reads(2 as Weight))326 .saturating_add(RocksDbWeight::get().writes(1 as Weight))323 .saturating_add(RocksDbWeight::get().writes(1 as Weight))327 }324 }328 // Storage: Common CollectionPropertyPermissions (r:1 w:0)325 // Storage: Common CollectionPropertyPermissions (r:1 w:0)329 // Storage: Nonfungible TokenData (r:1 w:0)330 // Storage: Nonfungible TokenProperties (r:1 w:1)326 // Storage: Nonfungible TokenProperties (r:1 w:1)331 fn delete_token_properties(b: u32, ) -> Weight {327 fn delete_token_properties(b: u32, ) -> Weight {332 (0 as Weight)328 (0 as Weight)333 // Standard Error: 2_234_000329 // Standard Error: 1_632_000334 .saturating_add((408_185_000 as Weight).saturating_mul(b as Weight))330 .saturating_add((289_190_000 as Weight).saturating_mul(b as Weight))335 .saturating_add(RocksDbWeight::get().reads(3 as Weight))331 .saturating_add(RocksDbWeight::get().reads(2 as Weight))336 .saturating_add(RocksDbWeight::get().writes(1 as Weight))332 .saturating_add(RocksDbWeight::get().writes(1 as Weight))337 }333 }338}334}pallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.1.0"3version = "0.1.1"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/Changelog.mddiffbeforeafterbothno changes
pallets/refungible/src/benchmarking.rsdiffbeforeafterboth18use crate::{Pallet, Config, RefungibleHandle};18use crate::{Pallet, Config, RefungibleHandle};191920use sp_std::prelude::*;20use sp_std::prelude::*;21use pallet_common::benchmarking::{create_collection_raw, create_data};21use pallet_common::benchmarking::{create_collection_raw, property_key, property_value, create_data};22use frame_benchmarking::{benchmarks, account};22use frame_benchmarking::{benchmarks, account};23use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, CUSTOM_DATA_LIMIT, budget::Unlimited};23use up_data_structs::{24 CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT,25 budget::Unlimited,26};24use pallet_common::bench_init;27use pallet_common::bench_init;25use core::convert::TryInto;28use core::convert::TryInto;38 .collect::<BTreeMap<_, _>>()41 .collect::<BTreeMap<_, _>>()39 .try_into()42 .try_into()40 .unwrap(),43 .unwrap(),44 properties: Default::default(),41 }45 }42}46}43fn create_max_item<T: Config>(47fn create_max_item<T: Config>(204 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;208 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;205 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}209 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}210211 set_token_property_permissions {212 let b in 0..MAX_PROPERTIES_PER_ITEM;213 bench_init!{214 owner: sub; collection: collection(owner);215 owner: cross_from_sub;216 };217 let perms = (0..b).map(|k| PropertyKeyPermission {218 key: property_key(k as usize),219 permission: PropertyPermission {220 mutable: false,221 collection_admin: false,222 token_owner: false,223 },224 }).collect::<Vec<_>>();225 }: {<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?}226227 set_token_properties {228 let b in 0..MAX_PROPERTIES_PER_ITEM;229 bench_init!{230 owner: sub; collection: collection(owner);231 owner: cross_from_sub;232 };233 let perms = (0..b).map(|k| PropertyKeyPermission {234 key: property_key(k as usize),235 permission: PropertyPermission {236 mutable: false,237 collection_admin: true,238 token_owner: true,239 },240 }).collect::<Vec<_>>();241 <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;242 let props = (0..b).map(|k| Property {243 key: property_key(k as usize),244 value: property_value(),245 }).collect::<Vec<_>>();246 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;247 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?}248249 delete_token_properties {250 let b in 0..MAX_PROPERTIES_PER_ITEM;251 bench_init!{252 owner: sub; collection: collection(owner);253 owner: cross_from_sub;254 };255 let perms = (0..b).map(|k| PropertyKeyPermission {256 key: property_key(k as usize),257 permission: PropertyPermission {258 mutable: true,259 collection_admin: true,260 token_owner: true,261 },262 }).collect::<Vec<_>>();263 <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;264 let props = (0..b).map(|k| Property {265 key: property_key(k as usize),266 value: property_value(),267 }).collect::<Vec<_>>();268 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;269 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), false, &Unlimited)?;270 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();271 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}206272207 repartition_item {273 repartition_item {208 bench_init!{274 bench_init!{pallets/refungible/src/common.rsdiffbeforeafterboth20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};21use up_data_structs::{21use up_data_structs::{22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData, budget::Budget, Property,23 PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData,23 PropertyKey, PropertyValue, PropertyKeyPermission, CreateItemData, CollectionPropertiesVec,24};24};25use pallet_common::{CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight};25use pallet_common::{26 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,27 weights::WeightInfo as _,28};26use pallet_structure::Error as StructureError;29use pallet_structure::Error as StructureError;27use sp_runtime::{DispatchError};30use sp_runtime::{DispatchError};41 };44 };42}45}4647fn properties_weight<T: Config>(properties: &CollectionPropertiesVec) -> u64 {48 if properties.len() > 0 {49 <CommonWeights<T>>::set_token_properties(properties.len() as u32)50 } else {51 052 }53}435444pub struct CommonWeights<T: Config>(PhantomData<T>);55pub struct CommonWeights<T: Config>(PhantomData<T>);45impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {56impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {48 }59 }496050 fn create_multiple_items(data: &[CreateItemData]) -> Weight {61 fn create_multiple_items(data: &[CreateItemData]) -> Weight {51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)62 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(63 data.iter()64 .map(|data| match data {65 CreateItemData::ReFungible(rft_data) => {66 properties_weight::<T>(&rft_data.properties)67 }68 _ => 0,69 })70 .fold(0, |a, b| a.saturating_add(b)),71 )52 }72 }537354 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {74 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {55 match call {75 match call {56 CreateItemExData::RefungibleMultipleOwners(i) => {76 CreateItemExData::RefungibleMultipleOwners(i) => {57 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)77 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)78 .saturating_add(properties_weight::<T>(&i.properties))58 }79 }59 CreateItemExData::RefungibleMultipleItems(i) => {80 CreateItemExData::RefungibleMultipleItems(i) => {60 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)81 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)82 .saturating_add(83 i.iter()84 .map(|d| properties_weight::<T>(&d.properties))85 .fold(0, |a, b| a.saturating_add(b)),86 )61 }87 }62 _ => 0,88 _ => 0,63 }89 }67 max_weight_of!(burn_item_partial(), burn_item_fully())93 max_weight_of!(burn_item_partial(), burn_item_fully())68 }94 }699570 fn set_collection_properties(_amount: u32) -> Weight {96 fn set_collection_properties(amount: u32) -> Weight {71 // Error97 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)72 073 }98 }749975 fn delete_collection_properties(_amount: u32) -> Weight {100 fn delete_collection_properties(amount: u32) -> Weight {76 // Error101 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)77 078 }102 }7910380 fn set_token_properties(_amount: u32) -> Weight {104 fn set_token_properties(amount: u32) -> Weight {81 // Error105 <SelfWeightOf<T>>::set_token_properties(amount)82 083 }106 }8410785 fn delete_token_properties(_amount: u32) -> Weight {108 fn delete_token_properties(amount: u32) -> Weight {86 // Error109 <SelfWeightOf<T>>::delete_token_properties(amount)87 088 }110 }8911190 fn set_token_property_permissions(_amount: u32) -> Weight {112 fn set_token_property_permissions(amount: u32) -> Weight {91 // Error113 <SelfWeightOf<T>>::set_token_property_permissions(amount)92 093 }114 }9411595 fn transfer() -> Weight {116 fn transfer() -> Weight {140 out.insert(to.clone(), data.pieces);161 out.insert(to.clone(), data.pieces);141 out.try_into().expect("limit > 0")162 out.try_into().expect("limit > 0")142 },163 },164 properties: data.properties,143 }),165 }),144 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),166 _ => fail!(<Error<T>>::NotRefungibleDataUsedToMintFungibleCollectionToken),145 }167 }146}168}147169170/// Implementation of `CommonCollectionOperations` for `RefungibleHandle`. It wraps Refungible Pallete171/// methods and adds weight info.148impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {172impl<T: Config> CommonCollectionOperations<T> for RefungibleHandle<T> {149 fn create_item(173 fn create_item(150 &self,174 &self,295319296 fn set_collection_properties(320 fn set_collection_properties(297 &self,321 &self,298 _sender: T::CrossAccountId,322 sender: T::CrossAccountId,299 _property: Vec<Property>,323 properties: Vec<Property>,300 ) -> DispatchResultWithPostInfo {324 ) -> DispatchResultWithPostInfo {325 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);326301 fail!(<Error<T>>::SettingPropertiesNotAllowed)327 with_weight(328 <Pallet<T>>::set_collection_properties(self, &sender, properties),329 weight,330 )302 }331 }303332304 fn delete_collection_properties(333 fn delete_collection_properties(305 &self,334 &self,306 _sender: &T::CrossAccountId,335 sender: &T::CrossAccountId,307 _property_keys: Vec<PropertyKey>,336 property_keys: Vec<PropertyKey>,308 ) -> DispatchResultWithPostInfo {337 ) -> DispatchResultWithPostInfo {338 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);339309 fail!(<Error<T>>::SettingPropertiesNotAllowed)340 with_weight(341 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),342 weight,343 )310 }344 }311345312 fn set_token_properties(346 fn set_token_properties(313 &self,347 &self,314 _sender: T::CrossAccountId,348 sender: T::CrossAccountId,315 _token_id: TokenId,349 token_id: TokenId,316 _property: Vec<Property>,350 properties: Vec<Property>,317 _nesting_budget: &dyn Budget,351 nesting_budget: &dyn Budget,318 ) -> DispatchResultWithPostInfo {352 ) -> DispatchResultWithPostInfo {353 let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);354319 fail!(<Error<T>>::SettingPropertiesNotAllowed)355 with_weight(356 <Pallet<T>>::set_token_properties(357 self,358 &sender,359 token_id,360 properties.into_iter(),361 false,362 nesting_budget,363 ),364 weight,365 )320 }366 }321367322 fn set_token_property_permissions(368 fn set_token_property_permissions(323 &self,369 &self,324 _sender: &T::CrossAccountId,370 sender: &T::CrossAccountId,325 _property_permissions: Vec<PropertyKeyPermission>,371 property_permissions: Vec<PropertyKeyPermission>,326 ) -> DispatchResultWithPostInfo {372 ) -> DispatchResultWithPostInfo {373 let weight =374 <CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);375327 fail!(<Error<T>>::SettingPropertiesNotAllowed)376 with_weight(377 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),378 weight,379 )328 }380 }329381330 fn delete_token_properties(382 fn delete_token_properties(331 &self,383 &self,332 _sender: T::CrossAccountId,384 sender: T::CrossAccountId,333 _token_id: TokenId,385 token_id: TokenId,334 _property_keys: Vec<PropertyKey>,386 property_keys: Vec<PropertyKey>,335 _nesting_budget: &dyn Budget,387 nesting_budget: &dyn Budget,336 ) -> DispatchResultWithPostInfo {388 ) -> DispatchResultWithPostInfo {389 let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);390337 fail!(<Error<T>>::SettingPropertiesNotAllowed)391 with_weight(392 <Pallet<T>>::delete_token_properties(393 self,394 &sender,395 token_id,396 property_keys.into_iter(),397 nesting_budget,398 ),399 weight,400 )338 }401 }339402371 TokenId(<TokensMinted<T>>::get(self.id))434 TokenId(<TokensMinted<T>>::get(self.id))372 }435 }373436374 fn token_owner(&self, _token: TokenId) -> Option<T::CrossAccountId> {437 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {375 None438 <Pallet<T>>::token_owner(self.id, token)376 }439 }377440378 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {441 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {pallets/refungible/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//! # Refungible Pallet18//!19//! The Refungible pallet provides functionality for handling refungible collections and tokens.20//!21//! - [`Config`]22//! - [`RefungibleHandle`]23//! - [`Pallet`]24//! - [`CommonWeights`]25//!26//! ## Overview27//!28//! The Refungible pallet provides functions for:29//!30//! - RFT collection creation and removal31//! - Minting and burning of RFT tokens32//! - Partition and repartition of RFT tokens33//! - Retrieving number of pieces of RFT token34//! - Retrieving account balances35//! - Transfering RFT token pieces36//! - Burning RFT token pieces37//! - Setting and checking allowance for RFT tokens38//!39//! ### Terminology40//!41//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all42//! of the RFT token pieces than it owns the RFT token and can repartition it.43//!44//! - **RFT Collection:** A collection of RFT tokens. All RFT tokens are part of a collection.45//! Each collection has its own settings and set of permissions.46//!47//! - **RFT token piece:** A fungible part of an RFT token.48//!49//! - **Balance:** RFT token pieces owned by an account50//!51//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to52//! transfer from the balance of another account53//!54//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from55//! an account balance.56//!57//! ### Implementations58//!59//! The Refungible pallet provides implementations for the following traits. If these traits provide60//! the functionality that you need, then you can avoid coupling with the Refungible pallet.61//!62//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight63//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing64//! with collections65//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible66//! collection67//!68//! ## Interface69//!70//! ### Dispatchable Functions71//!72//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for73//! some accounts.74//! - `destroy_collection` - Destroy exising RFT collection. There should be no tokens in the collection.75//! - `burn` - Burn some amount of RFT token pieces owned by account. Burns the RFT token if no pieces left.76//! - `transfer` - Transfer some amount of RFT token pieces. Transfers should be enabled for RFT collection.77//! Nests the RFT token if RFT token pieces are sent to another token.78//! - `create_item` - Mint RFT token in collection. Sender should have permission to mint tokens.79//! - `set_allowance` - Set allowance for another account to transfer balance from sender's account.80//! - `repartition` - Repartition token to selected number of pieces. Sender should own all existing pieces.81//!82//! ## Assumptions83//!84//! * Total number of pieces for one token shouldn't exceed `up_data_structs::MAX_REFUNGIBLE_PIECES`.85//! * Total number of tokens of all types shouldn't be greater than `up_data_structs::MAX_TOKEN_PREFIX_LENGTH`.86//! * Sender should be in collection's allow list to perform operations on tokens.8717#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]188919use frame_support::{ensure, BoundedVec};90use frame_support::{ensure, fail, BoundedVec, transactional, storage::with_transaction};20use up_data_structs::{91use up_data_structs::{21 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,92 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,22 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,93 CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, budget::Budget,94 Property, PropertyScope, TrySetProperty, PropertyKey, PropertyValue, PropertyPermission,95 PropertyKeyPermission,23};96};24use pallet_evm::account::CrossAccountId;97use pallet_evm::account::CrossAccountId;25use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon};98use pallet_common::{99 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,100 CommonCollectionOperations as _,101};26use pallet_structure::Pallet as PalletStructure;102use pallet_structure::Pallet as PalletStructure;27use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};103use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};28use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};104use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};29use core::ops::Deref;105use core::ops::Deref;30use codec::{Encode, Decode, MaxEncodedLen};106use codec::{Encode, Decode, MaxEncodedLen};86 #[pallet::generate_store(pub(super) trait Store)]162 #[pallet::generate_store(pub(super) trait Store)]87 pub struct Pallet<T>(_);163 pub struct Pallet<T>(_);88164165 /// Amount of tokens minted for collection89 #[pallet::storage]166 #[pallet::storage]90 pub type TokensMinted<T: Config> =167 pub type TokensMinted<T: Config> =91 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;168 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;169170 /// Amount of burnt tokens for collection92 #[pallet::storage]171 #[pallet::storage]93 pub type TokensBurnt<T: Config> =172 pub type TokensBurnt<T: Config> =94 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;173 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;95174175 /// Custom data serialized to bytes for token96 #[pallet::storage]176 #[pallet::storage]97 pub type TokenData<T: Config> = StorageNMap<177 pub type TokenData<T: Config> = StorageNMap<98 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),178 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),101 >;181 >;102182103 #[pallet::storage]183 #[pallet::storage]184 #[pallet::getter(fn token_properties)]185 pub type TokenProperties<T: Config> = StorageNMap<186 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),187 Value = up_data_structs::Properties,188 QueryKind = ValueQuery,189 OnEmpty = up_data_structs::TokenProperties,190 >;191192 /// Total amount of pieces for token193 #[pallet::storage]104 pub type TotalSupply<T: Config> = StorageNMap<194 pub type TotalSupply<T: Config> = StorageNMap<105 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),195 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),106 Value = u128,196 Value = u128,119 QueryKind = ValueQuery,209 QueryKind = ValueQuery,120 >;210 >;121211212 /// Amount of tokens owned by account122 #[pallet::storage]213 #[pallet::storage]123 pub type AccountBalance<T: Config> = StorageNMap<214 pub type AccountBalance<T: Config> = StorageNMap<124 Key = (215 Key = (130 QueryKind = ValueQuery,221 QueryKind = ValueQuery,131 >;222 >;132223224 /// Amount of token pieces owned by account133 #[pallet::storage]225 #[pallet::storage]134 pub type Balance<T: Config> = StorageNMap<226 pub type Balance<T: Config> = StorageNMap<135 Key = (227 Key = (142 QueryKind = ValueQuery,234 QueryKind = ValueQuery,143 >;235 >;144236237 /// Allowance set by an owner for a spender for a token145 #[pallet::storage]238 #[pallet::storage]146 pub type Allowance<T: Config> = StorageNMap<239 pub type Allowance<T: Config> = StorageNMap<147 Key = (240 Key = (188}281}189282190impl<T: Config> Pallet<T> {283impl<T: Config> Pallet<T> {284 /// Get number of RFT tokens in collection191 pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {285 pub fn total_supply(collection: &RefungibleHandle<T>) -> u32 {192 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)286 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)193 }287 }288289 /// Check that RFT token exists290 ///291 /// - `token`: Token ID.194 pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {292 pub fn token_exists(collection: &RefungibleHandle<T>, token: TokenId) -> bool {195 <TotalSupply<T>>::contains_key((collection.id, token))293 <TotalSupply<T>>::contains_key((collection.id, token))196 }294 }295296 pub fn set_scoped_token_property(297 collection_id: CollectionId,298 token_id: TokenId,299 scope: PropertyScope,300 property: Property,301 ) -> DispatchResult {302 TokenProperties::<T>::try_mutate((collection_id, token_id), |properties| {303 properties.try_scoped_set(scope, property.key, property.value)304 })305 .map_err(<CommonError<T>>::from)?;306307 Ok(())308 }309310 pub fn set_scoped_token_properties(311 collection_id: CollectionId,312 token_id: TokenId,313 scope: PropertyScope,314 properties: impl Iterator<Item = Property>,315 ) -> DispatchResult {316 TokenProperties::<T>::try_mutate((collection_id, token_id), |stored_properties| {317 stored_properties.try_scoped_set_from_iter(scope, properties)318 })319 .map_err(<CommonError<T>>::from)?;320321 Ok(())322 }197}323}198324199// unchecked calls skips any permission checks325// unchecked calls skips any permission checks200impl<T: Config> Pallet<T> {326impl<T: Config> Pallet<T> {327 /// Create RFT collection328 ///329 /// `init_collection` will take non-refundable deposit for collection creation.330 ///331 /// - `data`: Contains settings for collection limits and permissions.201 pub fn init_collection(332 pub fn init_collection(202 owner: T::CrossAccountId,333 owner: T::CrossAccountId,203 data: CreateCollectionData<T::AccountId>,334 data: CreateCollectionData<T::AccountId>,204 ) -> Result<CollectionId, DispatchError> {335 ) -> Result<CollectionId, DispatchError> {205 <PalletCommon<T>>::init_collection(owner, data, false)336 <PalletCommon<T>>::init_collection(owner, data, false)206 }337 }338339 /// Destroy RFT collection340 ///341 /// `destroy_collection` will throw error if collection contains any tokens.342 /// Only owner can destroy collection.207 pub fn destroy_collection(343 pub fn destroy_collection(208 collection: RefungibleHandle<T>,344 collection: RefungibleHandle<T>,209 sender: &T::CrossAccountId,345 sender: &T::CrossAccountId,235 .is_some()371 .is_some()236 }372 }237373238 pub fn burn_token(collection: &RefungibleHandle<T>, token_id: TokenId) -> DispatchResult {374 pub fn burn_token_unchecked(375 collection: &RefungibleHandle<T>,376 token_id: TokenId,377 ) -> DispatchResult {239 let burnt = <TokensBurnt<T>>::get(collection.id)378 let burnt = <TokensBurnt<T>>::get(collection.id)240 .checked_add(1)379 .checked_add(1)241 .ok_or(ArithmeticError::Overflow)?;380 .ok_or(ArithmeticError::Overflow)?;242381243 <TokensBurnt<T>>::insert(collection.id, burnt);382 <TokensBurnt<T>>::insert(collection.id, burnt);244 <TokenData<T>>::remove((collection.id, token_id));383 <TokenData<T>>::remove((collection.id, token_id));384 <TokenProperties<T>>::remove((collection.id, token_id));245 <TotalSupply<T>>::remove((collection.id, token_id));385 <TotalSupply<T>>::remove((collection.id, token_id));246 <Balance<T>>::remove_prefix((collection.id, token_id), None);386 <Balance<T>>::remove_prefix((collection.id, token_id), None);247 <Allowance<T>>::remove_prefix((collection.id, token_id), None);387 <Allowance<T>>::remove_prefix((collection.id, token_id), None);248 // TODO: ERC721 transfer event388 // TODO: ERC721 transfer event249 Ok(())389 Ok(())250 }390 }251391392 /// Burn RFT token pieces393 ///394 /// `burn` will decrease total amount of token pieces and amount owned by sender.395 /// `burn` can be called even if there are multiple owners of the RFT token.396 /// If sender wouldn't have any pieces left after `burn` than she will stop being397 /// one of the owners of the token. If there is no account that owns any pieces of398 /// the token than token will be burned too.399 ///400 /// - `amount`: Amount of token pieces to burn.401 /// - `token`: Token who's pieces should be burned402 /// - `collection`: Collection that contains the token252 pub fn burn(403 pub fn burn(253 collection: &RefungibleHandle<T>,404 collection: &RefungibleHandle<T>,254 owner: &T::CrossAccountId,405 owner: &T::CrossAccountId,276 <Owned<T>>::remove((collection.id, owner, token));427 <Owned<T>>::remove((collection.id, owner, token));277 <PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);428 <PalletStructure<T>>::unnest_if_nested(owner, collection.id, token);278 <AccountBalance<T>>::insert((collection.id, owner), account_balance);429 <AccountBalance<T>>::insert((collection.id, owner), account_balance);279 Self::burn_token(collection, token)?;430 Self::burn_token_unchecked(collection, token)?;280 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(431 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(281 collection.id,432 collection.id,282 token,433 token,319 Ok(())470 Ok(())320 }471 }321472473 #[transactional]474 fn modify_token_properties(475 collection: &RefungibleHandle<T>,476 sender: &T::CrossAccountId,477 token_id: TokenId,478 properties: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,479 is_token_create: bool,480 nesting_budget: &dyn Budget,481 ) -> DispatchResult {482 let is_collection_admin = || collection.is_owner_or_admin(sender);483 let is_token_owner = || -> Result<bool, DispatchError> {484 let balance = collection.balance(sender.clone(), token_id);485 let total_pieces: u128 =486 Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);487 if balance != total_pieces {488 return Ok(false);489 }490491 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(492 sender.clone(),493 collection.id,494 token_id,495 None,496 nesting_budget,497 )?;498499 Ok(is_bundle_owner)500 };501502 for (key, value) in properties {503 let permission = <PalletCommon<T>>::property_permissions(collection.id)504 .get(&key)505 .cloned()506 .unwrap_or_else(PropertyPermission::none);507508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))509 .get(&key)510 .is_some();511512 match permission {513 PropertyPermission { mutable: false, .. } if is_property_exists => {514 return Err(<CommonError<T>>::NoPermission.into());515 }516517 PropertyPermission {518 collection_admin,519 token_owner,520 ..521 } => {522 //TODO: investigate threats during public minting.523 let is_token_create =524 is_token_create && (collection_admin || token_owner) && value.is_some();525 if !(is_token_create526 || (collection_admin && is_collection_admin())527 || (token_owner && is_token_owner()?))528 {529 fail!(<CommonError<T>>::NoPermission);530 }531 }532 }533534 match value {535 Some(value) => {536 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {537 properties.try_set(key.clone(), value)538 })539 .map_err(<CommonError<T>>::from)?;540541 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(542 collection.id,543 token_id,544 key,545 ));546 }547 None => {548 <TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {549 properties.remove(&key)550 })551 .map_err(<CommonError<T>>::from)?;552553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(554 collection.id,555 token_id,556 key,557 ));558 }559 }560 }561562 Ok(())563 }564565 pub fn set_token_properties(566 collection: &RefungibleHandle<T>,567 sender: &T::CrossAccountId,568 token_id: TokenId,569 properties: impl Iterator<Item = Property>,570 is_token_create: bool,571 nesting_budget: &dyn Budget,572 ) -> DispatchResult {573 Self::modify_token_properties(574 collection,575 sender,576 token_id,577 properties.map(|p| (p.key, Some(p.value))),578 is_token_create,579 nesting_budget,580 )581 }582583 pub fn set_token_property(584 collection: &RefungibleHandle<T>,585 sender: &T::CrossAccountId,586 token_id: TokenId,587 property: Property,588 nesting_budget: &dyn Budget,589 ) -> DispatchResult {590 let is_token_create = false;591592 Self::set_token_properties(593 collection,594 sender,595 token_id,596 [property].into_iter(),597 is_token_create,598 nesting_budget,599 )600 }601602 pub fn delete_token_properties(603 collection: &RefungibleHandle<T>,604 sender: &T::CrossAccountId,605 token_id: TokenId,606 property_keys: impl Iterator<Item = PropertyKey>,607 nesting_budget: &dyn Budget,608 ) -> DispatchResult {609 let is_token_create = false;610611 Self::modify_token_properties(612 collection,613 sender,614 token_id,615 property_keys.into_iter().map(|key| (key, None)),616 is_token_create,617 nesting_budget,618 )619 }620621 pub fn delete_token_property(622 collection: &RefungibleHandle<T>,623 sender: &T::CrossAccountId,624 token_id: TokenId,625 property_key: PropertyKey,626 nesting_budget: &dyn Budget,627 ) -> DispatchResult {628 Self::delete_token_properties(629 collection,630 sender,631 token_id,632 [property_key].into_iter(),633 nesting_budget,634 )635 }636637 /// Transfer RFT token pieces from one account to another.638 ///639 /// If the sender is no longer owns any pieces after the `transfer` than she stops being an owner of the token.640 ///641 /// - `from`: Owner of token pieces to transfer.642 /// - `to`: Recepient of transfered token pieces.643 /// - `amount`: Amount of token pieces to transfer.644 /// - `token`: Token whos pieces should be transfered645 /// - `collection`: Collection that contains the token322 pub fn transfer(646 pub fn transfer(323 collection: &RefungibleHandle<T>,647 collection: &RefungibleHandle<T>,324 from: &T::CrossAccountId,648 from: &T::CrossAccountId,423 Ok(())747 Ok(())424 }748 }425749750 /// Batched operation to create multiple RFT tokens.751 ///752 /// Same as `create_item` but creates multiple tokens.753 ///754 /// - `data`: Same as 'data` in `create_item` but contains data for multiple tokens.426 pub fn create_multiple_items(755 pub fn create_multiple_items(427 collection: &RefungibleHandle<T>,756 collection: &RefungibleHandle<T>,428 sender: &T::CrossAccountId,757 sender: &T::CrossAccountId,507836508 // =========837 // =========509838839 with_transaction(|| {840 for (i, data) in data.iter().enumerate() {841 let token_id = first_token_id + i as u32 + 1;842 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);843844 <TokenData<T>>::insert(845 (collection.id, token_id),846 ItemData {847 const_data: data.const_data.clone(),848 },849 );850851 for (user, amount) in data.users.iter() {852 if *amount == 0 {853 continue;854 }855 <Balance<T>>::insert((collection.id, token_id, &user), amount);856 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);857 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(858 user,859 collection.id,860 TokenId(token_id),861 );862 }863864 if let Err(e) = Self::set_token_properties(865 collection,866 sender,867 TokenId(token_id),868 data.properties.clone().into_iter(),869 true,870 nesting_budget,871 ) {872 return TransactionOutcome::Rollback(Err(e));873 }874 }875 TransactionOutcome::Commit(Ok(()))876 })?;877510 <TokensMinted<T>>::insert(collection.id, tokens_minted);878 <TokensMinted<T>>::insert(collection.id, tokens_minted);879511 for (account, balance) in balances {880 for (account, balance) in balances {512 <AccountBalance<T>>::insert((collection.id, account), balance);881 <AccountBalance<T>>::insert((collection.id, account), balance);513 }882 }883514 for (i, token) in data.into_iter().enumerate() {884 for (i, token) in data.into_iter().enumerate() {515 let token_id = first_token_id + i as u32 + 1;885 let token_id = first_token_id + i as u32 + 1;516 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);517886518 <TokenData<T>>::insert(519 (collection.id, token_id),520 ItemData {521 const_data: token.const_data,522 },523 );524525 for (user, amount) in token.users.into_iter() {887 for (user, amount) in token.users.into_iter() {526 if amount == 0 {888 if amount == 0 {527 continue;889 continue;528 }890 }529 <Balance<T>>::insert((collection.id, token_id, &user), amount);530 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);531 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(532 &user,533 collection.id,534 TokenId(token_id),535 );536891537 // TODO: ERC20 transfer event892 // TODO: ERC20 transfer event538 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(893 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(568 ))923 ))569 }924 }570925926 /// Set allowance for the spender to `transfer` or `burn` sender's token pieces.927 ///928 /// - `amount`: Amount of token pieces the spender is allowed to `transfer` or `burn.571 pub fn set_allowance(929 pub fn set_allowance(572 collection: &RefungibleHandle<T>,930 collection: &RefungibleHandle<T>,573 sender: &T::CrossAccountId,931 sender: &T::CrossAccountId,636 Ok(allowance)994 Ok(allowance)637 }995 }638996997 /// Transfer RFT token pieces from one account to another.998 ///999 /// Same as the [`transfer`] but spender doesn't needs to be an owner of the token pieces.1000 /// The owner should set allowance for the spender to transfer pieces.1001 ///1002 /// [`transfer`]: struct.Pallet.html#method.transfer639 pub fn transfer_from(1003 pub fn transfer_from(640 collection: &RefungibleHandle<T>,1004 collection: &RefungibleHandle<T>,641 spender: &T::CrossAccountId,1005 spender: &T::CrossAccountId,657 Ok(())1021 Ok(())658 }1022 }65910231024 /// Burn RFT token pieces from the account.1025 ///1026 /// Same as the [`burn`] but spender doesn't need to be an owner of the token pieces. The owner should1027 /// set allowance for the spender to burn pieces1028 ///1029 /// [`burn`]: struct.Pallet.html#method.burn660 pub fn burn_from(1030 pub fn burn_from(661 collection: &RefungibleHandle<T>,1031 collection: &RefungibleHandle<T>,662 spender: &T::CrossAccountId,1032 spender: &T::CrossAccountId,677 Ok(())1047 Ok(())678 }1048 }6791049680 /// Delegated to `create_multiple_items`1050 /// Create RFT token.1051 ///1052 /// The sender should be the owner/admin of the collection or collection should be configured1053 /// to allow public minting.1054 ///1055 /// - `data`: Contains list of users who will become the owners of the token pieces and amount1056 /// of token pieces they will receive.681 pub fn create_item(1057 pub fn create_item(682 collection: &RefungibleHandle<T>,1058 collection: &RefungibleHandle<T>,683 sender: &T::CrossAccountId,1059 sender: &T::CrossAccountId,687 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)1063 Self::create_multiple_items(collection, sender, vec![data], nesting_budget)688 }1064 }68910651066 /// Repartition RFT token.1067 ///1068 /// `repartition` will set token balance of the sender and total amount of token pieces.1069 /// Sender should own all of the token pieces. `repartition' could be done even if some1070 /// token pieces were burned before.1071 ///1072 /// - `amount`: Total amount of token pieces that the token will have after `repartition`.690 pub fn repartition(1073 pub fn repartition(691 collection: &RefungibleHandle<T>,1074 collection: &RefungibleHandle<T>,692 owner: &T::CrossAccountId,1075 owner: &T::CrossAccountId,699 );1082 );700 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);1083 ensure!(amount > 0, <CommonError<T>>::TokenValueTooLow);701 // Ensure user owns all pieces1084 // Ensure user owns all pieces702 let total_supply = <TotalSupply<T>>::get((collection.id, token));1085 let total_pieces = Self::total_pieces(collection.id, token).unwrap_or(u128::MAX);703 let balance = <Balance<T>>::get((collection.id, token, owner));1086 let balance = <Balance<T>>::get((collection.id, token, owner));704 ensure!(1087 ensure!(705 total_supply == balance,1088 total_pieces == balance,706 <Error<T>>::RepartitionWhileNotOwningAllPieces1089 <Error<T>>::RepartitionWhileNotOwningAllPieces707 );1090 );7081091711 Ok(())1094 Ok(())712 }1095 }71310961097 fn token_owner(collection_id: CollectionId, token_id: TokenId) -> Option<T::CrossAccountId> {1098 let mut owner = None;1099 let mut count = 0;1100 for key in Balance::<T>::iter_key_prefix((collection_id, token_id)) {1101 count += 1;1102 if count > 1 {1103 return None;1104 }1105 owner = Some(key);1106 }1107 owner1108 }1109714 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {1110 fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128> {715 <TotalSupply<T>>::try_get((collection_id, token_id)).ok()1111 <TotalSupply<T>>::try_get((collection_id, token_id)).ok()1112 }11131114 pub fn set_collection_properties(1115 collection: &RefungibleHandle<T>,1116 sender: &T::CrossAccountId,1117 properties: Vec<Property>,1118 ) -> DispatchResult {1119 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)1120 }11211122 pub fn delete_collection_properties(1123 collection: &RefungibleHandle<T>,1124 sender: &T::CrossAccountId,1125 property_keys: Vec<PropertyKey>,1126 ) -> DispatchResult {1127 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)1128 }11291130 pub fn set_token_property_permissions(1131 collection: &RefungibleHandle<T>,1132 sender: &T::CrossAccountId,1133 property_permissions: Vec<PropertyKeyPermission>,1134 ) -> DispatchResult {1135 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)716 }1136 }717}1137}7181138pallets/refungible/src/weights.rsdiffbeforeafterboth3//! Autogenerated weights for pallet_refungible3//! Autogenerated weights for pallet_refungible4//!4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-06-27, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-07-20, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024889// Executed Command:9// Executed Command:49 fn transfer_from_removing() -> Weight;49 fn transfer_from_removing() -> Weight;50 fn transfer_from_creating_removing() -> Weight;50 fn transfer_from_creating_removing() -> Weight;51 fn burn_from() -> Weight;51 fn burn_from() -> Weight;52 fn set_token_property_permissions(b: u32, ) -> Weight;53 fn set_token_properties(b: u32, ) -> Weight;54 fn delete_token_properties(b: u32, ) -> Weight;52 fn repartition_item() -> Weight;55 fn repartition_item() -> Weight;53}56}545762 // Storage: Refungible TokenData (r:0 w:1)65 // Storage: Refungible TokenData (r:0 w:1)63 // Storage: Refungible Owned (r:0 w:1)66 // Storage: Refungible Owned (r:0 w:1)64 fn create_item() -> Weight {67 fn create_item() -> Weight {65 (17_553_000 as Weight)68 (21_310_000 as Weight)66 .saturating_add(T::DbWeight::get().reads(2 as Weight))69 .saturating_add(T::DbWeight::get().reads(2 as Weight))67 .saturating_add(T::DbWeight::get().writes(6 as Weight))70 .saturating_add(T::DbWeight::get().writes(6 as Weight))68 }71 }73 // Storage: Refungible TokenData (r:0 w:4)76 // Storage: Refungible TokenData (r:0 w:4)74 // Storage: Refungible Owned (r:0 w:4)77 // Storage: Refungible Owned (r:0 w:4)75 fn create_multiple_items(b: u32, ) -> Weight {78 fn create_multiple_items(b: u32, ) -> Weight {76 (10_654_000 as Weight)79 (9_552_000 as Weight)77 // Standard Error: 1_00080 // Standard Error: 2_00078 .saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))81 .saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))79 .saturating_add(T::DbWeight::get().reads(2 as Weight))82 .saturating_add(T::DbWeight::get().reads(2 as Weight))80 .saturating_add(T::DbWeight::get().writes(2 as Weight))83 .saturating_add(T::DbWeight::get().writes(2 as Weight))81 .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))84 .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))87 // Storage: Refungible TokenData (r:0 w:4)90 // Storage: Refungible TokenData (r:0 w:4)88 // Storage: Refungible Owned (r:0 w:4)91 // Storage: Refungible Owned (r:0 w:4)89 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {92 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {90 (3_587_000 as Weight)93 (4_857_000 as Weight)91 // Standard Error: 2_00094 // Standard Error: 2_00092 .saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))95 .saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))93 .saturating_add(T::DbWeight::get().reads(1 as Weight))96 .saturating_add(T::DbWeight::get().reads(1 as Weight))94 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))97 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))95 .saturating_add(T::DbWeight::get().writes(1 as Weight))98 .saturating_add(T::DbWeight::get().writes(1 as Weight))102 // Storage: Refungible Balance (r:0 w:4)105 // Storage: Refungible Balance (r:0 w:4)103 // Storage: Refungible Owned (r:0 w:4)106 // Storage: Refungible Owned (r:0 w:4)104 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {107 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {105 (1_980_000 as Weight)108 (11_335_000 as Weight)106 // Standard Error: 2_000109 // Standard Error: 2_000107 .saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))110 .saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))108 .saturating_add(T::DbWeight::get().reads(1 as Weight))111 .saturating_add(T::DbWeight::get().reads(1 as Weight))109 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))112 .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))110 .saturating_add(T::DbWeight::get().writes(3 as Weight))113 .saturating_add(T::DbWeight::get().writes(3 as Weight))115 // Storage: Refungible AccountBalance (r:1 w:1)118 // Storage: Refungible AccountBalance (r:1 w:1)116 // Storage: Refungible Owned (r:0 w:1)119 // Storage: Refungible Owned (r:0 w:1)117 fn burn_item_partial() -> Weight {120 fn burn_item_partial() -> Weight {118 (21_010_000 as Weight)121 (21_239_000 as Weight)119 .saturating_add(T::DbWeight::get().reads(3 as Weight))122 .saturating_add(T::DbWeight::get().reads(3 as Weight))120 .saturating_add(T::DbWeight::get().writes(4 as Weight))123 .saturating_add(T::DbWeight::get().writes(4 as Weight))121 }124 }125 // Storage: Refungible TokensBurnt (r:1 w:1)128 // Storage: Refungible TokensBurnt (r:1 w:1)126 // Storage: Refungible TokenData (r:0 w:1)129 // Storage: Refungible TokenData (r:0 w:1)127 // Storage: Refungible Owned (r:0 w:1)130 // Storage: Refungible Owned (r:0 w:1)131 // Storage: Refungible TokenProperties (r:0 w:1)128 fn burn_item_fully() -> Weight {132 fn burn_item_fully() -> Weight {129 (28_413_000 as Weight)133 (29_426_000 as Weight)130 .saturating_add(T::DbWeight::get().reads(4 as Weight))134 .saturating_add(T::DbWeight::get().reads(4 as Weight))131 .saturating_add(T::DbWeight::get().writes(6 as Weight))135 .saturating_add(T::DbWeight::get().writes(7 as Weight))132 }136 }133 // Storage: Refungible Balance (r:2 w:2)137 // Storage: Refungible Balance (r:2 w:2)134 fn transfer_normal() -> Weight {138 fn transfer_normal() -> Weight {135 (17_513_000 as Weight)139 (17_743_000 as Weight)136 .saturating_add(T::DbWeight::get().reads(2 as Weight))140 .saturating_add(T::DbWeight::get().reads(2 as Weight))137 .saturating_add(T::DbWeight::get().writes(2 as Weight))141 .saturating_add(T::DbWeight::get().writes(2 as Weight))138 }142 }139 // Storage: Refungible Balance (r:2 w:2)143 // Storage: Refungible Balance (r:2 w:2)140 // Storage: Refungible AccountBalance (r:1 w:1)144 // Storage: Refungible AccountBalance (r:1 w:1)141 // Storage: Refungible Owned (r:0 w:1)145 // Storage: Refungible Owned (r:0 w:1)142 fn transfer_creating() -> Weight {146 fn transfer_creating() -> Weight {143 (20_469_000 as Weight)147 (20_699_000 as Weight)144 .saturating_add(T::DbWeight::get().reads(3 as Weight))148 .saturating_add(T::DbWeight::get().reads(3 as Weight))145 .saturating_add(T::DbWeight::get().writes(4 as Weight))149 .saturating_add(T::DbWeight::get().writes(4 as Weight))146 }150 }147 // Storage: Refungible Balance (r:2 w:2)151 // Storage: Refungible Balance (r:2 w:2)148 // Storage: Refungible AccountBalance (r:1 w:1)152 // Storage: Refungible AccountBalance (r:1 w:1)149 // Storage: Refungible Owned (r:0 w:1)153 // Storage: Refungible Owned (r:0 w:1)150 fn transfer_removing() -> Weight {154 fn transfer_removing() -> Weight {151 (22_472_000 as Weight)155 (22_833_000 as Weight)152 .saturating_add(T::DbWeight::get().reads(3 as Weight))156 .saturating_add(T::DbWeight::get().reads(3 as Weight))153 .saturating_add(T::DbWeight::get().writes(4 as Weight))157 .saturating_add(T::DbWeight::get().writes(4 as Weight))154 }158 }155 // Storage: Refungible Balance (r:2 w:2)159 // Storage: Refungible Balance (r:2 w:2)156 // Storage: Refungible AccountBalance (r:2 w:2)160 // Storage: Refungible AccountBalance (r:2 w:2)157 // Storage: Refungible Owned (r:0 w:2)161 // Storage: Refungible Owned (r:0 w:2)158 fn transfer_creating_removing() -> Weight {162 fn transfer_creating_removing() -> Weight {159 (24_866_000 as Weight)163 (24_936_000 as Weight)160 .saturating_add(T::DbWeight::get().reads(4 as Weight))164 .saturating_add(T::DbWeight::get().reads(4 as Weight))161 .saturating_add(T::DbWeight::get().writes(6 as Weight))165 .saturating_add(T::DbWeight::get().writes(6 as Weight))162 }166 }163 // Storage: Refungible Balance (r:1 w:0)167 // Storage: Refungible Balance (r:1 w:0)164 // Storage: Refungible Allowance (r:0 w:1)168 // Storage: Refungible Allowance (r:0 w:1)165 fn approve() -> Weight {169 fn approve() -> Weight {166 (13_475_000 as Weight)170 (13_446_000 as Weight)167 .saturating_add(T::DbWeight::get().reads(1 as Weight))171 .saturating_add(T::DbWeight::get().reads(1 as Weight))168 .saturating_add(T::DbWeight::get().writes(1 as Weight))172 .saturating_add(T::DbWeight::get().writes(1 as Weight))169 }173 }170 // Storage: Refungible Allowance (r:1 w:1)174 // Storage: Refungible Allowance (r:1 w:1)171 // Storage: Refungible Balance (r:2 w:2)175 // Storage: Refungible Balance (r:2 w:2)172 fn transfer_from_normal() -> Weight {176 fn transfer_from_normal() -> Weight {173 (24_707_000 as Weight)177 (24_777_000 as Weight)174 .saturating_add(T::DbWeight::get().reads(3 as Weight))178 .saturating_add(T::DbWeight::get().reads(3 as Weight))175 .saturating_add(T::DbWeight::get().writes(3 as Weight))179 .saturating_add(T::DbWeight::get().writes(3 as Weight))176 }180 }179 // Storage: Refungible AccountBalance (r:1 w:1)183 // Storage: Refungible AccountBalance (r:1 w:1)180 // Storage: Refungible Owned (r:0 w:1)184 // Storage: Refungible Owned (r:0 w:1)181 fn transfer_from_creating() -> Weight {185 fn transfer_from_creating() -> Weight {182 (27_812_000 as Weight)186 (28_483_000 as Weight)183 .saturating_add(T::DbWeight::get().reads(4 as Weight))187 .saturating_add(T::DbWeight::get().reads(4 as Weight))184 .saturating_add(T::DbWeight::get().writes(5 as Weight))188 .saturating_add(T::DbWeight::get().writes(5 as Weight))185 }189 }188 // Storage: Refungible AccountBalance (r:1 w:1)192 // Storage: Refungible AccountBalance (r:1 w:1)189 // Storage: Refungible Owned (r:0 w:1)193 // Storage: Refungible Owned (r:0 w:1)190 fn transfer_from_removing() -> Weight {194 fn transfer_from_removing() -> Weight {191 (29_966_000 as Weight)195 (29_896_000 as Weight)192 .saturating_add(T::DbWeight::get().reads(4 as Weight))196 .saturating_add(T::DbWeight::get().reads(4 as Weight))193 .saturating_add(T::DbWeight::get().writes(5 as Weight))197 .saturating_add(T::DbWeight::get().writes(5 as Weight))194 }198 }197 // Storage: Refungible AccountBalance (r:2 w:2)201 // Storage: Refungible AccountBalance (r:2 w:2)198 // Storage: Refungible Owned (r:0 w:2)202 // Storage: Refungible Owned (r:0 w:2)199 fn transfer_from_creating_removing() -> Weight {203 fn transfer_from_creating_removing() -> Weight {200 (31_660_000 as Weight)204 (32_070_000 as Weight)201 .saturating_add(T::DbWeight::get().reads(5 as Weight))205 .saturating_add(T::DbWeight::get().reads(5 as Weight))202 .saturating_add(T::DbWeight::get().writes(7 as Weight))206 .saturating_add(T::DbWeight::get().writes(7 as Weight))203 }207 }208 // Storage: Refungible TokensBurnt (r:1 w:1)212 // Storage: Refungible TokensBurnt (r:1 w:1)209 // Storage: Refungible TokenData (r:0 w:1)213 // Storage: Refungible TokenData (r:0 w:1)210 // Storage: Refungible Owned (r:0 w:1)214 // Storage: Refungible Owned (r:0 w:1)215 // Storage: Refungible TokenProperties (r:0 w:1)211 fn burn_from() -> Weight {216 fn burn_from() -> Weight {212 (36_248_000 as Weight)217 (36_789_000 as Weight)213 .saturating_add(T::DbWeight::get().reads(5 as Weight))218 .saturating_add(T::DbWeight::get().reads(5 as Weight))214 .saturating_add(T::DbWeight::get().writes(7 as Weight))219 .saturating_add(T::DbWeight::get().writes(8 as Weight))215 }220 }221 // Storage: Common CollectionPropertyPermissions (r:1 w:1)222 fn set_token_property_permissions(b: u32, ) -> Weight {223 (0 as Weight)224 // Standard Error: 62_000225 .saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))226 .saturating_add(T::DbWeight::get().reads(1 as Weight))227 .saturating_add(T::DbWeight::get().writes(1 as Weight))228 }229 // Storage: Common CollectionPropertyPermissions (r:1 w:0)230 // Storage: Refungible TokenProperties (r:1 w:1)231 fn set_token_properties(b: u32, ) -> Weight {232 (0 as Weight)233 // Standard Error: 1_668_000234 .saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))235 .saturating_add(T::DbWeight::get().reads(2 as Weight))236 .saturating_add(T::DbWeight::get().writes(1 as Weight))237 }238 // Storage: Common CollectionPropertyPermissions (r:1 w:0)239 // Storage: Refungible TokenProperties (r:1 w:1)240 fn delete_token_properties(b: u32, ) -> Weight {241 (0 as Weight)242 // Standard Error: 1_619_000243 .saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))244 .saturating_add(T::DbWeight::get().reads(2 as Weight))245 .saturating_add(T::DbWeight::get().writes(1 as Weight))246 }216 // Storage: Refungible TotalSupply (r:1 w:1)247 // Storage: Refungible TotalSupply (r:1 w:1)217 // Storage: Refungible Balance (r:1 w:1)248 // Storage: Refungible Balance (r:1 w:1)218 fn repartition_item() -> Weight {249 fn repartition_item() -> Weight {219 (8_226_000 as Weight)250 (8_325_000 as Weight)220 .saturating_add(T::DbWeight::get().reads(2 as Weight))251 .saturating_add(T::DbWeight::get().reads(2 as Weight))221 .saturating_add(T::DbWeight::get().writes(2 as Weight))252 .saturating_add(T::DbWeight::get().writes(2 as Weight))222 }253 }231 // Storage: Refungible TokenData (r:0 w:1)262 // Storage: Refungible TokenData (r:0 w:1)232 // Storage: Refungible Owned (r:0 w:1)263 // Storage: Refungible Owned (r:0 w:1)233 fn create_item() -> Weight {264 fn create_item() -> Weight {234 (17_553_000 as Weight)265 (21_310_000 as Weight)235 .saturating_add(RocksDbWeight::get().reads(2 as Weight))266 .saturating_add(RocksDbWeight::get().reads(2 as Weight))236 .saturating_add(RocksDbWeight::get().writes(6 as Weight))267 .saturating_add(RocksDbWeight::get().writes(6 as Weight))237 }268 }242 // Storage: Refungible TokenData (r:0 w:4)273 // Storage: Refungible TokenData (r:0 w:4)243 // Storage: Refungible Owned (r:0 w:4)274 // Storage: Refungible Owned (r:0 w:4)244 fn create_multiple_items(b: u32, ) -> Weight {275 fn create_multiple_items(b: u32, ) -> Weight {245 (10_654_000 as Weight)276 (9_552_000 as Weight)246 // Standard Error: 1_000277 // Standard Error: 2_000247 .saturating_add((5_114_000 as Weight).saturating_mul(b as Weight))278 .saturating_add((7_056_000 as Weight).saturating_mul(b as Weight))248 .saturating_add(RocksDbWeight::get().reads(2 as Weight))279 .saturating_add(RocksDbWeight::get().reads(2 as Weight))249 .saturating_add(RocksDbWeight::get().writes(2 as Weight))280 .saturating_add(RocksDbWeight::get().writes(2 as Weight))250 .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))281 .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(b as Weight)))256 // Storage: Refungible TokenData (r:0 w:4)287 // Storage: Refungible TokenData (r:0 w:4)257 // Storage: Refungible Owned (r:0 w:4)288 // Storage: Refungible Owned (r:0 w:4)258 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {289 fn create_multiple_items_ex_multiple_items(b: u32, ) -> Weight {259 (3_587_000 as Weight)290 (4_857_000 as Weight)260 // Standard Error: 2_000291 // Standard Error: 2_000261 .saturating_add((7_931_000 as Weight).saturating_mul(b as Weight))292 .saturating_add((9_838_000 as Weight).saturating_mul(b as Weight))262 .saturating_add(RocksDbWeight::get().reads(1 as Weight))293 .saturating_add(RocksDbWeight::get().reads(1 as Weight))263 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))294 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))264 .saturating_add(RocksDbWeight::get().writes(1 as Weight))295 .saturating_add(RocksDbWeight::get().writes(1 as Weight))271 // Storage: Refungible Balance (r:0 w:4)302 // Storage: Refungible Balance (r:0 w:4)272 // Storage: Refungible Owned (r:0 w:4)303 // Storage: Refungible Owned (r:0 w:4)273 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {304 fn create_multiple_items_ex_multiple_owners(b: u32, ) -> Weight {274 (1_980_000 as Weight)305 (11_335_000 as Weight)275 // Standard Error: 2_000306 // Standard Error: 2_000276 .saturating_add((6_305_000 as Weight).saturating_mul(b as Weight))307 .saturating_add((6_784_000 as Weight).saturating_mul(b as Weight))277 .saturating_add(RocksDbWeight::get().reads(1 as Weight))308 .saturating_add(RocksDbWeight::get().reads(1 as Weight))278 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))309 .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(b as Weight)))279 .saturating_add(RocksDbWeight::get().writes(3 as Weight))310 .saturating_add(RocksDbWeight::get().writes(3 as Weight))284 // Storage: Refungible AccountBalance (r:1 w:1)315 // Storage: Refungible AccountBalance (r:1 w:1)285 // Storage: Refungible Owned (r:0 w:1)316 // Storage: Refungible Owned (r:0 w:1)286 fn burn_item_partial() -> Weight {317 fn burn_item_partial() -> Weight {287 (21_010_000 as Weight)318 (21_239_000 as Weight)288 .saturating_add(RocksDbWeight::get().reads(3 as Weight))319 .saturating_add(RocksDbWeight::get().reads(3 as Weight))289 .saturating_add(RocksDbWeight::get().writes(4 as Weight))320 .saturating_add(RocksDbWeight::get().writes(4 as Weight))290 }321 }294 // Storage: Refungible TokensBurnt (r:1 w:1)325 // Storage: Refungible TokensBurnt (r:1 w:1)295 // Storage: Refungible TokenData (r:0 w:1)326 // Storage: Refungible TokenData (r:0 w:1)296 // Storage: Refungible Owned (r:0 w:1)327 // Storage: Refungible Owned (r:0 w:1)328 // Storage: Refungible TokenProperties (r:0 w:1)297 fn burn_item_fully() -> Weight {329 fn burn_item_fully() -> Weight {298 (28_413_000 as Weight)330 (29_426_000 as Weight)299 .saturating_add(RocksDbWeight::get().reads(4 as Weight))331 .saturating_add(RocksDbWeight::get().reads(4 as Weight))300 .saturating_add(RocksDbWeight::get().writes(6 as Weight))332 .saturating_add(RocksDbWeight::get().writes(7 as Weight))301 }333 }302 // Storage: Refungible Balance (r:2 w:2)334 // Storage: Refungible Balance (r:2 w:2)303 fn transfer_normal() -> Weight {335 fn transfer_normal() -> Weight {304 (17_513_000 as Weight)336 (17_743_000 as Weight)305 .saturating_add(RocksDbWeight::get().reads(2 as Weight))337 .saturating_add(RocksDbWeight::get().reads(2 as Weight))306 .saturating_add(RocksDbWeight::get().writes(2 as Weight))338 .saturating_add(RocksDbWeight::get().writes(2 as Weight))307 }339 }308 // Storage: Refungible Balance (r:2 w:2)340 // Storage: Refungible Balance (r:2 w:2)309 // Storage: Refungible AccountBalance (r:1 w:1)341 // Storage: Refungible AccountBalance (r:1 w:1)310 // Storage: Refungible Owned (r:0 w:1)342 // Storage: Refungible Owned (r:0 w:1)311 fn transfer_creating() -> Weight {343 fn transfer_creating() -> Weight {312 (20_469_000 as Weight)344 (20_699_000 as Weight)313 .saturating_add(RocksDbWeight::get().reads(3 as Weight))345 .saturating_add(RocksDbWeight::get().reads(3 as Weight))314 .saturating_add(RocksDbWeight::get().writes(4 as Weight))346 .saturating_add(RocksDbWeight::get().writes(4 as Weight))315 }347 }316 // Storage: Refungible Balance (r:2 w:2)348 // Storage: Refungible Balance (r:2 w:2)317 // Storage: Refungible AccountBalance (r:1 w:1)349 // Storage: Refungible AccountBalance (r:1 w:1)318 // Storage: Refungible Owned (r:0 w:1)350 // Storage: Refungible Owned (r:0 w:1)319 fn transfer_removing() -> Weight {351 fn transfer_removing() -> Weight {320 (22_472_000 as Weight)352 (22_833_000 as Weight)321 .saturating_add(RocksDbWeight::get().reads(3 as Weight))353 .saturating_add(RocksDbWeight::get().reads(3 as Weight))322 .saturating_add(RocksDbWeight::get().writes(4 as Weight))354 .saturating_add(RocksDbWeight::get().writes(4 as Weight))323 }355 }324 // Storage: Refungible Balance (r:2 w:2)356 // Storage: Refungible Balance (r:2 w:2)325 // Storage: Refungible AccountBalance (r:2 w:2)357 // Storage: Refungible AccountBalance (r:2 w:2)326 // Storage: Refungible Owned (r:0 w:2)358 // Storage: Refungible Owned (r:0 w:2)327 fn transfer_creating_removing() -> Weight {359 fn transfer_creating_removing() -> Weight {328 (24_866_000 as Weight)360 (24_936_000 as Weight)329 .saturating_add(RocksDbWeight::get().reads(4 as Weight))361 .saturating_add(RocksDbWeight::get().reads(4 as Weight))330 .saturating_add(RocksDbWeight::get().writes(6 as Weight))362 .saturating_add(RocksDbWeight::get().writes(6 as Weight))331 }363 }332 // Storage: Refungible Balance (r:1 w:0)364 // Storage: Refungible Balance (r:1 w:0)333 // Storage: Refungible Allowance (r:0 w:1)365 // Storage: Refungible Allowance (r:0 w:1)334 fn approve() -> Weight {366 fn approve() -> Weight {335 (13_475_000 as Weight)367 (13_446_000 as Weight)336 .saturating_add(RocksDbWeight::get().reads(1 as Weight))368 .saturating_add(RocksDbWeight::get().reads(1 as Weight))337 .saturating_add(RocksDbWeight::get().writes(1 as Weight))369 .saturating_add(RocksDbWeight::get().writes(1 as Weight))338 }370 }339 // Storage: Refungible Allowance (r:1 w:1)371 // Storage: Refungible Allowance (r:1 w:1)340 // Storage: Refungible Balance (r:2 w:2)372 // Storage: Refungible Balance (r:2 w:2)341 fn transfer_from_normal() -> Weight {373 fn transfer_from_normal() -> Weight {342 (24_707_000 as Weight)374 (24_777_000 as Weight)343 .saturating_add(RocksDbWeight::get().reads(3 as Weight))375 .saturating_add(RocksDbWeight::get().reads(3 as Weight))344 .saturating_add(RocksDbWeight::get().writes(3 as Weight))376 .saturating_add(RocksDbWeight::get().writes(3 as Weight))345 }377 }348 // Storage: Refungible AccountBalance (r:1 w:1)380 // Storage: Refungible AccountBalance (r:1 w:1)349 // Storage: Refungible Owned (r:0 w:1)381 // Storage: Refungible Owned (r:0 w:1)350 fn transfer_from_creating() -> Weight {382 fn transfer_from_creating() -> Weight {351 (27_812_000 as Weight)383 (28_483_000 as Weight)352 .saturating_add(RocksDbWeight::get().reads(4 as Weight))384 .saturating_add(RocksDbWeight::get().reads(4 as Weight))353 .saturating_add(RocksDbWeight::get().writes(5 as Weight))385 .saturating_add(RocksDbWeight::get().writes(5 as Weight))354 }386 }357 // Storage: Refungible AccountBalance (r:1 w:1)389 // Storage: Refungible AccountBalance (r:1 w:1)358 // Storage: Refungible Owned (r:0 w:1)390 // Storage: Refungible Owned (r:0 w:1)359 fn transfer_from_removing() -> Weight {391 fn transfer_from_removing() -> Weight {360 (29_966_000 as Weight)392 (29_896_000 as Weight)361 .saturating_add(RocksDbWeight::get().reads(4 as Weight))393 .saturating_add(RocksDbWeight::get().reads(4 as Weight))362 .saturating_add(RocksDbWeight::get().writes(5 as Weight))394 .saturating_add(RocksDbWeight::get().writes(5 as Weight))363 }395 }366 // Storage: Refungible AccountBalance (r:2 w:2)398 // Storage: Refungible AccountBalance (r:2 w:2)367 // Storage: Refungible Owned (r:0 w:2)399 // Storage: Refungible Owned (r:0 w:2)368 fn transfer_from_creating_removing() -> Weight {400 fn transfer_from_creating_removing() -> Weight {369 (31_660_000 as Weight)401 (32_070_000 as Weight)370 .saturating_add(RocksDbWeight::get().reads(5 as Weight))402 .saturating_add(RocksDbWeight::get().reads(5 as Weight))371 .saturating_add(RocksDbWeight::get().writes(7 as Weight))403 .saturating_add(RocksDbWeight::get().writes(7 as Weight))372 }404 }377 // Storage: Refungible TokensBurnt (r:1 w:1)409 // Storage: Refungible TokensBurnt (r:1 w:1)378 // Storage: Refungible TokenData (r:0 w:1)410 // Storage: Refungible TokenData (r:0 w:1)379 // Storage: Refungible Owned (r:0 w:1)411 // Storage: Refungible Owned (r:0 w:1)412 // Storage: Refungible TokenProperties (r:0 w:1)380 fn burn_from() -> Weight {413 fn burn_from() -> Weight {381 (36_248_000 as Weight)414 (36_789_000 as Weight)382 .saturating_add(RocksDbWeight::get().reads(5 as Weight))415 .saturating_add(RocksDbWeight::get().reads(5 as Weight))383 .saturating_add(RocksDbWeight::get().writes(7 as Weight))416 .saturating_add(RocksDbWeight::get().writes(8 as Weight))417 }418 // Storage: Common CollectionPropertyPermissions (r:1 w:1)419 fn set_token_property_permissions(b: u32, ) -> Weight {420 (0 as Weight)421 // Standard Error: 62_000422 .saturating_add((15_803_000 as Weight).saturating_mul(b as Weight))423 .saturating_add(RocksDbWeight::get().reads(1 as Weight))424 .saturating_add(RocksDbWeight::get().writes(1 as Weight))425 }426 // Storage: Common CollectionPropertyPermissions (r:1 w:0)427 // Storage: Refungible TokenProperties (r:1 w:1)428 fn set_token_properties(b: u32, ) -> Weight {429 (0 as Weight)430 // Standard Error: 1_668_000431 .saturating_add((302_308_000 as Weight).saturating_mul(b as Weight))432 .saturating_add(RocksDbWeight::get().reads(2 as Weight))433 .saturating_add(RocksDbWeight::get().writes(1 as Weight))434 }435 // Storage: Common CollectionPropertyPermissions (r:1 w:0)436 // Storage: Refungible TokenProperties (r:1 w:1)437 fn delete_token_properties(b: u32, ) -> Weight {438 (0 as Weight)439 // Standard Error: 1_619_000440 .saturating_add((294_574_000 as Weight).saturating_mul(b as Weight))441 .saturating_add(RocksDbWeight::get().reads(2 as Weight))442 .saturating_add(RocksDbWeight::get().writes(1 as Weight))384 }443 }385 // Storage: Refungible TotalSupply (r:1 w:1)444 // Storage: Refungible TotalSupply (r:1 w:1)386 // Storage: Refungible Balance (r:1 w:1)445 // Storage: Refungible Balance (r:1 w:1)387 fn repartition_item() -> Weight {446 fn repartition_item() -> Weight {388 (8_226_000 as Weight)447 (8_325_000 as Weight)389 .saturating_add(RocksDbWeight::get().reads(2 as Weight))448 .saturating_add(RocksDbWeight::get().reads(2 as Weight))390 .saturating_add(RocksDbWeight::get().writes(2 as Weight))449 .saturating_add(RocksDbWeight::get().writes(2 as Weight))391 }450 }pallets/scheduler/src/lib.rsdiffbeforeafterboth152152153pub use preimage_provider::PreimageProviderAndMaybeRecipient;153pub use preimage_provider::PreimageProviderAndMaybeRecipient;154154155/// Weight templates for calculating actual fees156pub(crate) trait MarginalWeightInfo: WeightInfo {155pub(crate) trait MarginalWeightInfo: WeightInfo {157 fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {156 fn item(periodic: bool, named: bool, resolved: Option<bool>) -> Weight {158 match (periodic, named, resolved) {157 match (periodic, named, resolved) {259 /// If `Some` then the number of blocks to postpone execution for when the item is delayed.258 /// If `Some` then the number of blocks to postpone execution for when the item is delayed.260 type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;259 type NoPreimagePostponement: Get<Option<Self::BlockNumber>>;261260262 /// Sponsoring function. In this version sposorship is disabled261 /// Sponsoring function.263 // type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;262 // type SponsorshipHandler: SponsorshipHandler<Self::AccountId, <Self as Config>::Call>;264263265 /// The helper type used for custom transaction fee logic.264 /// The helper type used for custom transaction fee logic.268267269 /// A Scheduler-Runtime interface for finer payment handling.268 /// A Scheduler-Runtime interface for finer payment handling.270 pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {269 pub trait DispatchCall<T: frame_system::Config + Config, SelfContainedSignedInfo> {271 /// Lock balance required for transaction payment272 fn reserve_balance(270 fn reserve_balance(273 id: ScheduledId,271 id: ScheduledId,274 sponsor: <T as frame_system::Config>::AccountId,272 sponsor: <T as frame_system::Config>::AccountId,292 TransactionValidityError,290 TransactionValidityError,293 >;291 >;294292295 /// Cancel schedule reservation and unlock balance296 fn cancel_reserve(293 fn cancel_reserve(297 id: ScheduledId,294 id: ScheduledId,298 sponsor: <T as frame_system::Config>::AccountId,295 sponsor: <T as frame_system::Config>::AccountId,436 continue;433 continue;437 }434 }438435439 // Sender is the account who signed transaction440 let sender = ensure_signed(436 let sender = ensure_signed(441 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())437 <<T as Config>::Origin as From<T::PalletsOrigin>>::from(s.origin.clone())442 .into(),438 .into(),500 }496 }501 /// Weight should be 0, because transaction already paid497 /// Weight should be 0, because transaction already paid502 0498 0499 //total_weight503 }500 }504 }501 }505502pallets/structure/src/benchmarking.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use super::*;17use super::*;218pallets/structure/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Structure Pallet18//!19//! The Structure pallet provides functionality for handling tokens nesting an unnesting.20//!21//! - [`Config`]22//! - [`Pallet`]23//!24//! ## Overview25//!26//! The Structure pallet provides functions for:27//!28//! - Searching for token parents, children and owners. Actual implementation of searching for29//! parent/child is done by pallets corresponding to token's collection type.30//! - Nesting and unnesting tokens. Actual implementation of nesting is done by pallets corresponding31//! to token's collection type.32//!33//! ### Terminology34//!35//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting36//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in37//! it's child token i.e. parent-child relationship graph shouldn't have38//!39//! - **Parent:** Token that current token is nested in.40//!41//! - **Owner:** Account that owns the token and all nested tokens.42//!43//! ## Interface44//!45//! ### Available Functions46//!47//! - `find_parent` - Find parent of the token. It could be an account or another token.48//! - `parent_chain` - Find chain of parents of the token.49//! - `find_topmost_owner` - Find account or token in the end of the chain of parents.50//! - `check_nesting` - Check if the token could be nested in the other token51//! - `nest_if_sent_to_token` - Nest the token in the other token52//! - `unnest_if_nested` - Unnest the token from the other token531#![cfg_attr(not(feature = "std"), no_std)]54#![cfg_attr(not(feature = "std"), no_std)]25582}135}8313684impl<T: Config> Pallet<T> {137impl<T: Config> Pallet<T> {138 /// Find account owning the `token` or a token that the `token` is nested in.139 ///140 /// Returns the enum that have three variants:141 /// - [`User`](crate::Parent<T>::User): Contains account.142 /// - [`Token`](crate::Parent<T>::Token): Contains token id and collection id.143 /// - [`TokenNotFound`](crate::Parent<T>::TokenNotFound): Indicates that parent was not found85 pub fn find_parent(144 pub fn find_parent(86 collection: CollectionId,145 collection: CollectionId,87 token: TokenId,146 token: TokenId,103 })162 })104 }163 }105164165 /// Get the chain of parents of a token in the nesting hierarchy166 ///167 /// Returns an iterator of addresses of the owning tokens and the owning account,168 /// starting from the immediate parent token, ending with the account.169 /// Returns error if cycle is detected.106 pub fn parent_chain(170 pub fn parent_chain(107 mut collection: CollectionId,171 mut collection: CollectionId,108 mut token: TokenId,172 mut token: TokenId,133 /// Try to dereference address, until finding top level owner197 /// Try to dereference address, until finding top level owner134 ///198 ///135 /// May return token address if parent token not yet exists199 /// May return token address if parent token not yet exists200 ///201 /// - `budget`: Limit for searching parents in depth.136 pub fn find_topmost_owner(202 pub fn find_topmost_owner(137 collection: CollectionId,203 collection: CollectionId,138 token: TokenId,204 token: TokenId,149 })215 })150 }216 }151217218 /// Find the topmost parent and check that assigning `for_nest` token as a child for219 /// `token` wouldn't create a cycle.220 ///221 /// - `budget`: Limit for searching parents in depth.152 pub fn get_checked_topmost_owner(222 pub fn get_checked_topmost_owner(153 collection: CollectionId,223 collection: CollectionId,154 token: TokenId,224 token: TokenId,177 Err(<Error<T>>::DepthLimit.into())247 Err(<Error<T>>::DepthLimit.into())178 }248 }179249250 /// Burn token and all of it's nested tokens251 ///252 /// - `self_budget`: Limit for searching children in depth.253 /// - `breadth_budget`: Limit of breadth of searching children.180 pub fn burn_item_recursively(254 pub fn burn_item_recursively(181 from: T::CrossAccountId,255 from: T::CrossAccountId,182 collection: CollectionId,256 collection: CollectionId,190 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)264 dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)191 }265 }192266193 /// Check if token indirectly owned by specified user267 /// Check if `token` indirectly owned by `user`268 ///269 /// Returns `true` if `user` is `token`'s owner. Or If token is provided as `user` then270 /// check that `user` and `token` have same owner.271 /// Checks that assigning `for_nest` token as a child for `token` wouldn't create a cycle.272 ///273 /// - `budget`: Limit for searching parents in depth.194 pub fn check_indirectly_owned(274 pub fn check_indirectly_owned(195 user: T::CrossAccountId,275 user: T::CrossAccountId,196 collection: CollectionId,276 collection: CollectionId,207 .map(|indirect_owner| indirect_owner == target_parent)287 .map(|indirect_owner| indirect_owner == target_parent)208 }288 }209289290 /// Checks that `under` is valid token and that `token_id` could be nested under it291 /// and that `from` is `under`'s owner292 ///293 /// Returns OK if `under` is not a token294 ///295 /// - `nesting_budget`: Limit for searching parents in depth.210 pub fn check_nesting(296 pub fn check_nesting(211 from: T::CrossAccountId,297 from: T::CrossAccountId,212 under: &T::CrossAccountId,298 under: &T::CrossAccountId,219 })305 })220 }306 }221307308 /// Nests `token_id` under `under` token309 ///310 /// Returns OK if `under` is not a token. Checks that nesting is possible.311 ///312 /// - `nesting_budget`: Limit for searching parents in depth.222 pub fn nest_if_sent_to_token(313 pub fn nest_if_sent_to_token(223 from: T::CrossAccountId,314 from: T::CrossAccountId,224 under: &T::CrossAccountId,315 under: &T::CrossAccountId,235 })326 })236 }327 }237328329 /// Nests `token_id` under `owner` token330 ///331 /// Caller should check that nesting wouldn't cause recursion in nesting238 pub fn nest_if_sent_to_token_unchecked(332 pub fn nest_if_sent_to_token_unchecked(239 owner: &T::CrossAccountId,333 owner: &T::CrossAccountId,240 collection_id: CollectionId,334 collection_id: CollectionId,245 });339 });246 }340 }247341342 /// Unnests `token_id` from `owner`.248 pub fn unnest_if_nested(343 pub fn unnest_if_nested(249 owner: &T::CrossAccountId,344 owner: &T::CrossAccountId,250 collection_id: CollectionId,345 collection_id: CollectionId,pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
primitives/data-structs/Cargo.tomldiffbeforeafterboth6license = 'GPLv3'6license = 'GPLv3'7homepage = "https://unique.network"7homepage = "https://unique.network"8repository = 'https://github.com/UniqueNetwork/unique-chain'8repository = 'https://github.com/UniqueNetwork/unique-chain'9version = '0.1.0'9version = '0.1.1'101011[dependencies]11[dependencies]12scale-info = { version = "2.0.1", default-features = false, features = [12scale-info = { version = "2.0.1", default-features = false, features = [primitives/data-structs/Changelog.mddiffbeforeafterbothno changes
primitives/data-structs/src/lib.rsdiffbeforeafterboth537537 pub pieces: u128,538 pub pieces: u128,539540 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]541 #[derivative(Debug(format_with = "bounded::vec_debug"))]542 pub properties: CollectionPropertiesVec,538}543}539544540#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]545#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]568 pub const_data: BoundedVec<u8, CustomDataLimit>,573 pub const_data: BoundedVec<u8, CustomDataLimit>,569 #[derivative(Debug(format_with = "bounded::map_debug"))]574 #[derivative(Debug(format_with = "bounded::map_debug"))]570 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,575 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,576 #[derivative(Debug(format_with = "bounded::vec_debug"))]577 pub properties: CollectionPropertiesVec,571}578}572579573#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]580#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]runtime/opal/src/lib.rsdiffbeforeafterboth707pub type Barrier = (707pub type Barrier = (708 TakeWeightCredit,708 TakeWeightCredit,709 AllowTopLevelPaidExecutionFrom<Everything>,709 AllowTopLevelPaidExecutionFrom<Everything>,710 AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,711 // ^^^ Parent & its unit plurality gets free execution710 // ^^^ Parent & its unit plurality gets free execution712);711);713712runtime/quartz/src/lib.rsdiffbeforeafterboth706pub type Barrier = (706pub type Barrier = (707 TakeWeightCredit,707 TakeWeightCredit,708 AllowTopLevelPaidExecutionFrom<Everything>,708 AllowTopLevelPaidExecutionFrom<Everything>,709 AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,710 // ^^^ Parent & its unit plurality gets free execution709 // ^^^ Parent & its unit plurality gets free execution711);710);712711runtime/unique/src/lib.rsdiffbeforeafterboth705pub type Barrier = (705pub type Barrier = (706 TakeWeightCredit,706 TakeWeightCredit,707 AllowTopLevelPaidExecutionFrom<Everything>,707 AllowTopLevelPaidExecutionFrom<Everything>,708 AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,709 // ^^^ Parent & its unit plurality gets free execution708 // ^^^ Parent & its unit plurality gets free execution710);709);711710tests/src/createMultipleItems.test.tsdiffbeforeafterboth376 // ReFungible376 // ReFungible377 const collectionIdReFungible =377 const collectionIdReFungible =378 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});378 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});379 {379 const argsReFungible = [380 const argsReFungible = [380 {ReFungible: ['1'.repeat(2049), 10]},381 {ReFungible: ['1'.repeat(2049), 10, []]},381 {ReFungible: ['2'.repeat(2049), 10]},382 {ReFungible: ['2'.repeat(2049), 10, []]},382 {ReFungible: ['3'.repeat(2049), 10]},383 {ReFungible: ['3'.repeat(2049), 10, []]},383 ];384 ];384 const createMultipleItemsTxFungible = api.tx.unique385 const createMultipleItemsTxFungible = api.tx.unique385 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);386 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);386 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;387 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;388 }389 {390 const argsReFungible = [391 {ReFungible: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}},392 {ReFungible: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}},393 {ReFungible: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}},394 ];395 const createMultipleItemsTxFungible = api.tx.unique396 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);397 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;398 }387 });399 });388 });400 });389401tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth28 function burnFrom(address from, uint256 amount) external returns (bool);28 function burnFrom(address from, uint256 amount) external returns (bool);29}29}3031// Selector: 7d9262e632interface Collection is Dummy, ERC165 {33 // Set collection property.34 //35 // @param key Property key.36 // @param value Propery value.37 //38 // Selector: setCollectionProperty(string,bytes) 2f073f6639 function setCollectionProperty(string memory key, bytes memory value)40 external;4142 // Delete collection property.43 //44 // @param key Property key.45 //46 // Selector: deleteCollectionProperty(string) 7b7debce47 function deleteCollectionProperty(string memory key) external;4849 // Get collection property.50 //51 // @dev Throws error if key not found.52 //53 // @param key Property key.54 // @return bytes The property corresponding to the key.55 //56 // Selector: collectionProperty(string) cf24fd6d57 function collectionProperty(string memory key)58 external59 view60 returns (bytes memory);6162 // Set the sponsor of the collection.63 //64 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.65 //66 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.67 //68 // Selector: setCollectionSponsor(address) 7623402e69 function setCollectionSponsor(address sponsor) external;7071 // Collection sponsorship confirmation.72 //73 // @dev After setting the sponsor for the collection, it must be confirmed with this function.74 //75 // Selector: confirmCollectionSponsorship() 3c50e97a76 function confirmCollectionSponsorship() external;7778 // Set limits for the collection.79 // @dev Throws error if limit not found.80 // @param limit Name of the limit. Valid names:81 // "accountTokenOwnershipLimit",82 // "sponsoredDataSize",83 // "sponsoredDataRateLimit",84 // "tokenLimit",85 // "sponsorTransferTimeout",86 // "sponsorApproveTimeout"87 // @param value Value of the limit.88 //89 // Selector: setCollectionLimit(string,uint32) 6a3841db90 function setCollectionLimit(string memory limit, uint32 value) external;9192 // Set limits for the collection.93 // @dev Throws error if limit not found.94 // @param limit Name of the limit. Valid names:95 // "ownerCanTransfer",96 // "ownerCanDestroy",97 // "transfersEnabled"98 // @param value Value of the limit.99 //100 // Selector: setCollectionLimit(string,bool) 993b7fba101 function setCollectionLimit(string memory limit, bool value) external;102103 // Get contract address.104 //105 // Selector: contractAddress() f6b4dfb4106 function contractAddress() external view returns (address);107108 // Add collection admin by substrate address.109 // @param new_admin Substrate administrator address.110 //111 // Selector: addCollectionAdminSubstrate(uint256) 5730062b112 function addCollectionAdminSubstrate(uint256 newAdmin) external;113114 // Remove collection admin by substrate address.115 // @param admin Substrate administrator address.116 //117 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9118 function removeCollectionAdminSubstrate(uint256 admin) external;119120 // Add collection admin.121 // @param new_admin Address of the added administrator.122 //123 // Selector: addCollectionAdmin(address) 92e462c7124 function addCollectionAdmin(address newAdmin) external;125126 // Remove collection admin.127 //128 // @param new_admin Address of the removed administrator.129 //130 // Selector: removeCollectionAdmin(address) fafd7b42131 function removeCollectionAdmin(address admin) external;132133 // Toggle accessibility of collection nesting.134 //135 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'136 //137 // Selector: setCollectionNesting(bool) 112d4586138 function setCollectionNesting(bool enable) external;139140 // Toggle accessibility of collection nesting.141 //142 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'143 // @param collections Addresses of collections that will be available for nesting.144 //145 // Selector: setCollectionNesting(bool,address[]) 64872396146 function setCollectionNesting(bool enable, address[] memory collections)147 external;148149 // Set the collection access method.150 // @param mode Access mode151 // 0 for Normal152 // 1 for AllowList153 //154 // Selector: setCollectionAccess(uint8) 41835d4c155 function setCollectionAccess(uint8 mode) external;156157 // Add the user to the allowed list.158 //159 // @param user Address of a trusted user.160 //161 // Selector: addToCollectionAllowList(address) 67844fe6162 function addToCollectionAllowList(address user) external;163164 // Remove the user from the allowed list.165 //166 // @param user Address of a removed user.167 //168 // Selector: removeFromCollectionAllowList(address) 85c51acb169 function removeFromCollectionAllowList(address user) external;170171 // Switch permission for minting.172 //173 // @param mode Enable if "true".174 //175 // Selector: setCollectionMintMode(bool) 00018e84176 function setCollectionMintMode(bool mode) external;177}3017831// Selector: 942e8b22179// Selector: 942e8b2232interface ERC20 is Dummy, ERC165, ERC20Events {180interface ERC20 is Dummy, ERC165, ERC20Events {65 returns (uint256);213 returns (uint256);66}214}6768// Selector: c894dc3569interface Collection is Dummy, ERC165 {70 // Selector: setCollectionProperty(string,bytes) 2f073f6671 function setCollectionProperty(string memory key, bytes memory value)72 external;7374 // Selector: deleteCollectionProperty(string) 7b7debce75 function deleteCollectionProperty(string memory key) external;7677 // Throws error if key not found78 //79 // Selector: collectionProperty(string) cf24fd6d80 function collectionProperty(string memory key)81 external82 view83 returns (bytes memory);8485 // Selector: ethSetSponsor(address) 8f9af35686 function ethSetSponsor(address sponsor) external;8788 // Selector: ethConfirmSponsorship() a8580d1a89 function ethConfirmSponsorship() external;9091 // Selector: setLimit(string,uint32) 68db30ca92 function setLimit(string memory limit, uint32 value) external;9394 // Selector: setLimit(string,bool) ea67e4c295 function setLimit(string memory limit, bool value) external;9697 // Selector: contractAddress() f6b4dfb498 function contractAddress() external view returns (address);99}100215101interface UniqueFungible is216interface UniqueFungible is102 Dummy,217 Dummy,tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth444445// Selector: 4136937745// Selector: 4136937746interface TokenProperties is Dummy, ERC165 {46interface TokenProperties is Dummy, ERC165 {47 // @notice Set permissions for token property.48 // @dev Throws error if `msg.sender` is not admin or owner of the collection.49 // @param key Property key.50 // @param is_mutable Permission to mutate property.51 // @param collection_admin Permission to mutate property by collection admin if property is mutable.52 // @param token_owner Permission to mutate property by token owner if property is mutable.53 //47 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa54 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa48 function setTokenPropertyPermission(55 function setTokenPropertyPermission(49 string memory key,56 string memory key,52 bool tokenOwner59 bool tokenOwner53 ) external;60 ) external;546162 // @notice Set token property value.63 // @dev Throws error if `msg.sender` has no permission to edit the property.64 // @param tokenId ID of the token.65 // @param key Property key.66 // @param value Property value.67 //55 // Selector: setProperty(uint256,string,bytes) 1752d67b68 // Selector: setProperty(uint256,string,bytes) 1752d67b56 function setProperty(69 function setProperty(57 uint256 tokenId,70 uint256 tokenId,58 string memory key,71 string memory key,59 bytes memory value72 bytes memory value60 ) external;73 ) external;617475 // @notice Delete token property value.76 // @dev Throws error if `msg.sender` has no permission to edit the property.77 // @param tokenId ID of the token.78 // @param key Property key.79 //62 // Selector: deleteProperty(uint256,string) 066111d180 // Selector: deleteProperty(uint256,string) 066111d163 function deleteProperty(uint256 tokenId, string memory key) external;81 function deleteProperty(uint256 tokenId, string memory key) external;648283 // @notice Get token property value.65 // Throws error if key not found84 // @dev Throws error if key not found85 // @param tokenId ID of the token.86 // @param key Property key.87 // @return Property value bytes66 //88 //67 // Selector: property(uint256,string) 7228c32789 // Selector: property(uint256,string) 7228c32768 function property(uint256 tokenId, string memory key)90 function property(uint256 tokenId, string memory key)739574// Selector: 42966c6896// Selector: 42966c6875interface ERC721Burnable is Dummy, ERC165 {97interface ERC721Burnable is Dummy, ERC165 {98 // @notice Burns a specific ERC721 token.99 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized100 // operator of the current owner.101 // @param tokenId The NFT to approve102 //76 // Selector: burn(uint256) 42966c68103 // Selector: burn(uint256) 42966c6877 function burn(uint256 tokenId) external;104 function burn(uint256 tokenId) external;78}105}7910680// Selector: 58800161107// Selector: 5880016181interface ERC721 is Dummy, ERC165, ERC721Events {108interface ERC721 is Dummy, ERC165, ERC721Events {109 // @notice Count all NFTs assigned to an owner110 // @dev NFTs assigned to the zero address are considered invalid, and this111 // function throws for queries about the zero address.112 // @param owner An address for whom to query the balance113 // @return The number of NFTs owned by `owner`, possibly zero114 //82 // Selector: balanceOf(address) 70a08231115 // Selector: balanceOf(address) 70a0823183 function balanceOf(address owner) external view returns (uint256);116 function balanceOf(address owner) external view returns (uint256);84117118 // @notice Find the owner of an NFT119 // @dev NFTs assigned to zero address are considered invalid, and queries120 // about them do throw.121 // @param tokenId The identifier for an NFT122 // @return The address of the owner of the NFT123 //85 // Selector: ownerOf(uint256) 6352211e124 // Selector: ownerOf(uint256) 6352211e86 function ownerOf(uint256 tokenId) external view returns (address);125 function ownerOf(uint256 tokenId) external view returns (address);8712688 // Not implemented127 // @dev Not implemented89 //128 //90 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672129 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a1167291 function safeTransferFromWithData(130 function safeTransferFromWithData(95 bytes memory data134 bytes memory data96 ) external;135 ) external;9713698 // Not implemented137 // @dev Not implemented99 //138 //100 // Selector: safeTransferFrom(address,address,uint256) 42842e0e139 // Selector: safeTransferFrom(address,address,uint256) 42842e0e101 function safeTransferFrom(140 function safeTransferFrom(104 uint256 tokenId143 uint256 tokenId105 ) external;144 ) external;106145146 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE147 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE148 // THEY MAY BE PERMANENTLY LOST149 // @dev Throws unless `msg.sender` is the current owner or an authorized150 // operator for this NFT. Throws if `from` is not the current owner. Throws151 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.152 // @param from The current owner of the NFT153 // @param to The new owner154 // @param tokenId The NFT to transfer155 // @param _value Not used for an NFT156 //107 // Selector: transferFrom(address,address,uint256) 23b872dd157 // Selector: transferFrom(address,address,uint256) 23b872dd108 function transferFrom(158 function transferFrom(109 address from,159 address from,110 address to,160 address to,111 uint256 tokenId161 uint256 tokenId112 ) external;162 ) external;113163164 // @notice Set or reaffirm the approved address for an NFT165 // @dev The zero address indicates there is no approved address.166 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized167 // operator of the current owner.168 // @param approved The new approved NFT controller169 // @param tokenId The NFT to approve170 //114 // Selector: approve(address,uint256) 095ea7b3171 // Selector: approve(address,uint256) 095ea7b3115 function approve(address approved, uint256 tokenId) external;172 function approve(address approved, uint256 tokenId) external;116173117 // Not implemented174 // @dev Not implemented118 //175 //119 // Selector: setApprovalForAll(address,bool) a22cb465176 // Selector: setApprovalForAll(address,bool) a22cb465120 function setApprovalForAll(address operator, bool approved) external;177 function setApprovalForAll(address operator, bool approved) external;121178122 // Not implemented179 // @dev Not implemented123 //180 //124 // Selector: getApproved(uint256) 081812fc181 // Selector: getApproved(uint256) 081812fc125 function getApproved(uint256 tokenId) external view returns (address);182 function getApproved(uint256 tokenId) external view returns (address);126183127 // Not implemented184 // @dev Not implemented128 //185 //129 // Selector: isApprovedForAll(address,address) e985e9c5186 // Selector: isApprovedForAll(address,address) e985e9c5130 function isApprovedForAll(address owner, address operator)187 function isApprovedForAll(address owner, address operator)135192136// Selector: 5b5e139f193// Selector: 5b5e139f137interface ERC721Metadata is Dummy, ERC165 {194interface ERC721Metadata is Dummy, ERC165 {195 // @notice A descriptive name for a collection of NFTs in this contract196 //138 // Selector: name() 06fdde03197 // Selector: name() 06fdde03139 function name() external view returns (string memory);198 function name() external view returns (string memory);140199200 // @notice An abbreviated name for NFTs in this contract201 //141 // Selector: symbol() 95d89b41202 // Selector: symbol() 95d89b41142 function symbol() external view returns (string memory);203 function symbol() external view returns (string memory);143204205 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.206 // @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC207 // 3986. The URI may point to a JSON file that conforms to the "ERC721208 // Metadata JSON Schema".144 // Returns token's const_metadata209 // @return token's const_metadata145 //210 //146 // Selector: tokenURI(uint256) c87b56dd211 // Selector: tokenURI(uint256) c87b56dd147 function tokenURI(uint256 tokenId) external view returns (string memory);212 function tokenURI(uint256 tokenId) external view returns (string memory);152 // Selector: mintingFinished() 05d2035b217 // Selector: mintingFinished() 05d2035b153 function mintingFinished() external view returns (bool);218 function mintingFinished() external view returns (bool);154219220 // @notice Function to mint token.155 // `token_id` should be obtained with `next_token_id` method,221 // @dev `tokenId` should be obtained with `nextTokenId` method,156 // unlike standard, you can't specify it manually222 // unlike standard, you can't specify it manually223 // @param to The new owner224 // @param tokenId ID of the minted NFT157 //225 //158 // Selector: mint(address,uint256) 40c10f19226 // Selector: mint(address,uint256) 40c10f19159 function mint(address to, uint256 tokenId) external returns (bool);227 function mint(address to, uint256 tokenId) external returns (bool);160228229 // @notice Function to mint token with the given tokenUri.161 // `token_id` should be obtained with `next_token_id` method,230 // @dev `tokenId` should be obtained with `nextTokenId` method,162 // unlike standard, you can't specify it manually231 // unlike standard, you can't specify it manually232 // @param to The new owner233 // @param tokenId ID of the minted NFT234 // @param tokenUri Token URI that would be stored in the NFT properties163 //235 //164 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f236 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f165 function mintWithTokenURI(237 function mintWithTokenURI(168 string memory tokenUri240 string memory tokenUri169 ) external returns (bool);241 ) external returns (bool);170242171 // Not implemented243 // @dev Not implemented172 //244 //173 // Selector: finishMinting() 7d64bcb4245 // Selector: finishMinting() 7d64bcb4174 function finishMinting() external returns (bool);246 function finishMinting() external returns (bool);175}247}176248177// Selector: 780e9d63249// Selector: 780e9d63178interface ERC721Enumerable is Dummy, ERC165 {250interface ERC721Enumerable is Dummy, ERC165 {251 // @notice Enumerate valid NFTs252 // @param index A counter less than `totalSupply()`253 // @return The token identifier for the `index`th NFT,254 // (sort order not specified)255 //179 // Selector: tokenByIndex(uint256) 4f6ccce7256 // Selector: tokenByIndex(uint256) 4f6ccce7180 function tokenByIndex(uint256 index) external view returns (uint256);257 function tokenByIndex(uint256 index) external view returns (uint256);181258182 // Not implemented259 // @dev Not implemented183 //260 //184 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59261 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59185 function tokenOfOwnerByIndex(address owner, uint256 index)262 function tokenOfOwnerByIndex(address owner, uint256 index)186 external263 external187 view264 view188 returns (uint256);265 returns (uint256);189266267 // @notice Count NFTs tracked by this contract268 // @return A count of valid NFTs tracked by this contract, where each one of269 // them has an assigned and queryable owner not equal to the zero address270 //190 // Selector: totalSupply() 18160ddd271 // Selector: totalSupply() 18160ddd191 function totalSupply() external view returns (uint256);272 function totalSupply() external view returns (uint256);192}273}193274194// Selector: 7d9262e6275// Selector: 7d9262e6195interface Collection is Dummy, ERC165 {276interface Collection is Dummy, ERC165 {277 // Set collection property.278 //279 // @param key Property key.280 // @param value Propery value.281 //196 // Selector: setCollectionProperty(string,bytes) 2f073f66282 // Selector: setCollectionProperty(string,bytes) 2f073f66197 function setCollectionProperty(string memory key, bytes memory value)283 function setCollectionProperty(string memory key, bytes memory value)198 external;284 external;199285286 // Delete collection property.287 //288 // @param key Property key.289 //200 // Selector: deleteCollectionProperty(string) 7b7debce290 // Selector: deleteCollectionProperty(string) 7b7debce201 function deleteCollectionProperty(string memory key) external;291 function deleteCollectionProperty(string memory key) external;202292293 // Get collection property.294 //203 // Throws error if key not found295 // @dev Throws error if key not found.296 //297 // @param key Property key.298 // @return bytes The property corresponding to the key.204 //299 //205 // Selector: collectionProperty(string) cf24fd6d300 // Selector: collectionProperty(string) cf24fd6d206 function collectionProperty(string memory key)301 function collectionProperty(string memory key)207 external302 external208 view303 view209 returns (bytes memory);304 returns (bytes memory);210305306 // Set the sponsor of the collection.307 //308 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.309 //310 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.311 //211 // Selector: setCollectionSponsor(address) 7623402e312 // Selector: setCollectionSponsor(address) 7623402e212 function setCollectionSponsor(address sponsor) external;313 function setCollectionSponsor(address sponsor) external;213314315 // Collection sponsorship confirmation.316 //317 // @dev After setting the sponsor for the collection, it must be confirmed with this function.318 //214 // Selector: confirmCollectionSponsorship() 3c50e97a319 // Selector: confirmCollectionSponsorship() 3c50e97a215 function confirmCollectionSponsorship() external;320 function confirmCollectionSponsorship() external;216321322 // Set limits for the collection.323 // @dev Throws error if limit not found.324 // @param limit Name of the limit. Valid names:325 // "accountTokenOwnershipLimit",326 // "sponsoredDataSize",327 // "sponsoredDataRateLimit",328 // "tokenLimit",329 // "sponsorTransferTimeout",330 // "sponsorApproveTimeout"331 // @param value Value of the limit.332 //217 // Selector: setCollectionLimit(string,uint32) 6a3841db333 // Selector: setCollectionLimit(string,uint32) 6a3841db218 function setCollectionLimit(string memory limit, uint32 value) external;334 function setCollectionLimit(string memory limit, uint32 value) external;219335336 // Set limits for the collection.337 // @dev Throws error if limit not found.338 // @param limit Name of the limit. Valid names:339 // "ownerCanTransfer",340 // "ownerCanDestroy",341 // "transfersEnabled"342 // @param value Value of the limit.343 //220 // Selector: setCollectionLimit(string,bool) 993b7fba344 // Selector: setCollectionLimit(string,bool) 993b7fba221 function setCollectionLimit(string memory limit, bool value) external;345 function setCollectionLimit(string memory limit, bool value) external;222346347 // Get contract address.348 //223 // Selector: contractAddress() f6b4dfb4349 // Selector: contractAddress() f6b4dfb4224 function contractAddress() external view returns (address);350 function contractAddress() external view returns (address);225351352 // Add collection admin by substrate address.353 // @param new_admin Substrate administrator address.354 //226 // Selector: addCollectionAdminSubstrate(uint256) 5730062b355 // Selector: addCollectionAdminSubstrate(uint256) 5730062b227 function addCollectionAdminSubstrate(uint256 newAdmin) external view;356 function addCollectionAdminSubstrate(uint256 newAdmin) external;228357358 // Remove collection admin by substrate address.359 // @param admin Substrate administrator address.360 //229 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9361 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9230 function removeCollectionAdminSubstrate(uint256 newAdmin) external view;362 function removeCollectionAdminSubstrate(uint256 admin) external;231363364 // Add collection admin.365 // @param new_admin Address of the added administrator.366 //232 // Selector: addCollectionAdmin(address) 92e462c7367 // Selector: addCollectionAdmin(address) 92e462c7233 function addCollectionAdmin(address newAdmin) external view;368 function addCollectionAdmin(address newAdmin) external;234369370 // Remove collection admin.371 //372 // @param new_admin Address of the removed administrator.373 //235 // Selector: removeCollectionAdmin(address) fafd7b42374 // Selector: removeCollectionAdmin(address) fafd7b42236 function removeCollectionAdmin(address admin) external view;375 function removeCollectionAdmin(address admin) external;237376377 // Toggle accessibility of collection nesting.378 //379 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'380 //238 // Selector: setCollectionNesting(bool) 112d4586381 // Selector: setCollectionNesting(bool) 112d4586239 function setCollectionNesting(bool enable) external;382 function setCollectionNesting(bool enable) external;240383384 // Toggle accessibility of collection nesting.385 //386 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'387 // @param collections Addresses of collections that will be available for nesting.388 //241 // Selector: setCollectionNesting(bool,address[]) 64872396389 // Selector: setCollectionNesting(bool,address[]) 64872396242 function setCollectionNesting(bool enable, address[] memory collections)390 function setCollectionNesting(bool enable, address[] memory collections)243 external;391 external;244392393 // Set the collection access method.394 // @param mode Access mode395 // 0 for Normal396 // 1 for AllowList397 //245 // Selector: setCollectionAccess(uint8) 41835d4c398 // Selector: setCollectionAccess(uint8) 41835d4c246 function setCollectionAccess(uint8 mode) external;399 function setCollectionAccess(uint8 mode) external;247400401 // Add the user to the allowed list.402 //403 // @param user Address of a trusted user.404 //248 // Selector: addToCollectionAllowList(address) 67844fe6405 // Selector: addToCollectionAllowList(address) 67844fe6249 function addToCollectionAllowList(address user) external view;406 function addToCollectionAllowList(address user) external;250407408 // Remove the user from the allowed list.409 //410 // @param user Address of a removed user.411 //251 // Selector: removeFromCollectionAllowList(address) 85c51acb412 // Selector: removeFromCollectionAllowList(address) 85c51acb252 function removeFromCollectionAllowList(address user) external view;413 function removeFromCollectionAllowList(address user) external;253414415 // Switch permission for minting.416 //417 // @param mode Enable if "true".418 //254 // Selector: setCollectionMintMode(bool) 00018e84419 // Selector: setCollectionMintMode(bool) 00018e84255 function setCollectionMintMode(bool mode) external;420 function setCollectionMintMode(bool mode) external;256}421}257422258// Selector: d74d154f423// Selector: d74d154f259interface ERC721UniqueExtensions is Dummy, ERC165 {424interface ERC721UniqueExtensions is Dummy, ERC165 {425 // @notice Transfer ownership of an NFT426 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`427 // is the zero address. Throws if `tokenId` is not a valid NFT.428 // @param to The new owner429 // @param tokenId The NFT to transfer430 // @param _value Not used for an NFT431 //260 // Selector: transfer(address,uint256) a9059cbb432 // Selector: transfer(address,uint256) a9059cbb261 function transfer(address to, uint256 tokenId) external;433 function transfer(address to, uint256 tokenId) external;262434435 // @notice Burns a specific ERC721 token.436 // @dev Throws unless `msg.sender` is the current owner or an authorized437 // operator for this NFT. Throws if `from` is not the current owner. Throws438 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.439 // @param from The current owner of the NFT440 // @param tokenId The NFT to transfer441 // @param _value Not used for an NFT442 //263 // Selector: burnFrom(address,uint256) 79cc6790443 // Selector: burnFrom(address,uint256) 79cc6790264 function burnFrom(address from, uint256 tokenId) external;444 function burnFrom(address from, uint256 tokenId) external;265445446 // @notice Returns next free NFT ID.447 //266 // Selector: nextTokenId() 75794a3c448 // Selector: nextTokenId() 75794a3c267 function nextTokenId() external view returns (uint256);449 function nextTokenId() external view returns (uint256);268450451 // @notice Function to mint multiple tokens.452 // @dev `tokenIds` should be an array of consecutive numbers and first number453 // should be obtained with `nextTokenId` method454 // @param to The new owner455 // @param tokenIds IDs of the minted NFTs456 //269 // Selector: mintBulk(address,uint256[]) 44a9945e457 // Selector: mintBulk(address,uint256[]) 44a9945e270 function mintBulk(address to, uint256[] memory tokenIds)458 function mintBulk(address to, uint256[] memory tokenIds)271 external459 external272 returns (bool);460 returns (bool);273461462 // @notice Function to mint multiple tokens with the given tokenUris.463 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive464 // numbers and first number should be obtained with `nextTokenId` method465 // @param to The new owner466 // @param tokens array of pairs of token ID and token URI for minted tokens467 //274 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006468 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006275 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)469 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)276 external470 externaltests/src/eth/fungibleAbi.jsondiffbeforeafterboth49 "name": "Transfer",49 "name": "Transfer",50 "type": "event"50 "type": "event"51 },51 },52 {53 "inputs": [54 { "internalType": "address", "name": "newAdmin", "type": "address" }55 ],56 "name": "addCollectionAdmin",57 "outputs": [],58 "stateMutability": "nonpayable",59 "type": "function"60 },61 {62 "inputs": [63 { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }64 ],65 "name": "addCollectionAdminSubstrate",66 "outputs": [],67 "stateMutability": "nonpayable",68 "type": "function"69 },70 {71 "inputs": [72 { "internalType": "address", "name": "user", "type": "address" }73 ],74 "name": "addToCollectionAllowList",75 "outputs": [],76 "stateMutability": "nonpayable",77 "type": "function"78 },52 {79 {53 "inputs": [80 "inputs": [54 { "internalType": "address", "name": "owner", "type": "address" },81 { "internalType": "address", "name": "owner", "type": "address" },95 "stateMutability": "view",122 "stateMutability": "view",96 "type": "function"123 "type": "function"97 },124 },125 {126 "inputs": [],127 "name": "confirmCollectionSponsorship",128 "outputs": [],129 "stateMutability": "nonpayable",130 "type": "function"131 },98 {132 {99 "inputs": [],133 "inputs": [],100 "name": "contractAddress",134 "name": "contractAddress",116 "stateMutability": "nonpayable",150 "stateMutability": "nonpayable",117 "type": "function"151 "type": "function"118 },152 },153 {154 "inputs": [],155 "name": "name",156 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],157 "stateMutability": "view",158 "type": "function"159 },160 {161 "inputs": [162 { "internalType": "address", "name": "admin", "type": "address" }163 ],164 "name": "removeCollectionAdmin",165 "outputs": [],166 "stateMutability": "nonpayable",167 "type": "function"168 },119 {169 {120 "inputs": [],170 "inputs": [171 { "internalType": "uint256", "name": "admin", "type": "uint256" }172 ],121 "name": "ethConfirmSponsorship",173 "name": "removeCollectionAdminSubstrate",122 "outputs": [],174 "outputs": [],123 "stateMutability": "nonpayable",175 "stateMutability": "nonpayable",124 "type": "function"176 "type": "function"125 },177 },126 {178 {127 "inputs": [179 "inputs": [128 { "internalType": "address", "name": "sponsor", "type": "address" }180 { "internalType": "address", "name": "user", "type": "address" }129 ],181 ],130 "name": "ethSetSponsor",182 "name": "removeFromCollectionAllowList",131 "outputs": [],183 "outputs": [],132 "stateMutability": "nonpayable",184 "stateMutability": "nonpayable",133 "type": "function"185 "type": "function"134 },186 },135 {187 {136 "inputs": [],188 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],189 "name": "setCollectionAccess",190 "outputs": [],191 "stateMutability": "nonpayable",192 "type": "function"193 },194 {195 "inputs": [137 "name": "name",196 { "internalType": "string", "name": "limit", "type": "string" },197 { "internalType": "uint32", "name": "value", "type": "uint32" }198 ],199 "name": "setCollectionLimit",138 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],200 "outputs": [],201 "stateMutability": "nonpayable",202 "type": "function"203 },204 {205 "inputs": [206 { "internalType": "string", "name": "limit", "type": "string" },207 { "internalType": "bool", "name": "value", "type": "bool" }208 ],209 "name": "setCollectionLimit",210 "outputs": [],139 "stateMutability": "view",211 "stateMutability": "nonpayable",140 "type": "function"212 "type": "function"141 },213 },214 {215 "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],216 "name": "setCollectionMintMode",217 "outputs": [],218 "stateMutability": "nonpayable",219 "type": "function"220 },221 {222 "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],223 "name": "setCollectionNesting",224 "outputs": [],225 "stateMutability": "nonpayable",226 "type": "function"227 },228 {229 "inputs": [230 { "internalType": "bool", "name": "enable", "type": "bool" },231 {232 "internalType": "address[]",233 "name": "collections",234 "type": "address[]"235 }236 ],237 "name": "setCollectionNesting",238 "outputs": [],239 "stateMutability": "nonpayable",240 "type": "function"241 },142 {242 {143 "inputs": [243 "inputs": [144 { "internalType": "string", "name": "key", "type": "string" },244 { "internalType": "string", "name": "key", "type": "string" },151 },251 },152 {252 {153 "inputs": [253 "inputs": [154 { "internalType": "string", "name": "limit", "type": "string" },254 { "internalType": "address", "name": "sponsor", "type": "address" }155 { "internalType": "uint32", "name": "value", "type": "uint32" }156 ],255 ],157 "name": "setLimit",256 "name": "setCollectionSponsor",158 "outputs": [],257 "outputs": [],159 "stateMutability": "nonpayable",258 "stateMutability": "nonpayable",160 "type": "function"259 "type": "function"161 },260 },162 {163 "inputs": [164 { "internalType": "string", "name": "limit", "type": "string" },165 { "internalType": "bool", "name": "value", "type": "bool" }166 ],167 "name": "setLimit",168 "outputs": [],169 "stateMutability": "nonpayable",170 "type": "function"171 },172 {261 {173 "inputs": [262 "inputs": [174 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }263 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth86 ],86 ],87 "name": "addCollectionAdmin",87 "name": "addCollectionAdmin",88 "outputs": [],88 "outputs": [],89 "stateMutability": "view",89 "stateMutability": "nonpayable",90 "type": "function"90 "type": "function"91 },91 },92 {92 {95 ],95 ],96 "name": "addCollectionAdminSubstrate",96 "name": "addCollectionAdminSubstrate",97 "outputs": [],97 "outputs": [],98 "stateMutability": "view",98 "stateMutability": "nonpayable",99 "type": "function"99 "type": "function"100 },100 },101 {101 {104 ],104 ],105 "name": "addToCollectionAllowList",105 "name": "addToCollectionAllowList",106 "outputs": [],106 "outputs": [],107 "stateMutability": "view",107 "stateMutability": "nonpayable",108 "type": "function"108 "type": "function"109 },109 },110 {110 {304 ],304 ],305 "name": "removeCollectionAdmin",305 "name": "removeCollectionAdmin",306 "outputs": [],306 "outputs": [],307 "stateMutability": "view",307 "stateMutability": "nonpayable",308 "type": "function"308 "type": "function"309 },309 },310 {310 {311 "inputs": [311 "inputs": [312 { "internalType": "uint256", "name": "newAdmin", "type": "uint256" }312 { "internalType": "uint256", "name": "admin", "type": "uint256" }313 ],313 ],314 "name": "removeCollectionAdminSubstrate",314 "name": "removeCollectionAdminSubstrate",315 "outputs": [],315 "outputs": [],316 "stateMutability": "view",316 "stateMutability": "nonpayable",317 "type": "function"317 "type": "function"318 },318 },319 {319 {322 ],322 ],323 "name": "removeFromCollectionAllowList",323 "name": "removeFromCollectionAllowList",324 "outputs": [],324 "outputs": [],325 "stateMutability": "view",325 "stateMutability": "nonpayable",326 "type": "function"326 "type": "function"327 },327 },328 {328 {tests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth276 [key: string]: AugmentedError<ApiType>;276 [key: string]: AugmentedError<ApiType>;277 };277 };278 fungible: {278 fungible: {279 /**279 /**280 * Fungible token does not support nested280 * Fungible token does not support nesting.281 **/281 **/282 FungibleDisallowsNesting: AugmentedError<ApiType>;282 FungibleDisallowsNesting: AugmentedError<ApiType>;283 /**283 /**284 * Tried to set data for fungible item284 * Tried to set data for fungible item.285 **/285 **/286 FungibleItemsDontHaveData: AugmentedError<ApiType>;286 FungibleItemsDontHaveData: AugmentedError<ApiType>;287 /**287 /**288 * Not default id passed as TokenId argument288 * Not default id passed as TokenId argument.289 * The default value of TokenId for Fungible collection is 0.289 **/290 **/290 FungibleItemsHaveNoId: AugmentedError<ApiType>;291 FungibleItemsHaveNoId: AugmentedError<ApiType>;291 /**292 /**292 * Not Fungible item data used to mint in Fungible collection.293 * Not Fungible item data used to mint in Fungible collection.293 **/294 **/294 NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;295 NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;295 /**296 /**296 * Setting item properties is not allowed297 * Setting item properties is not allowed.297 **/298 **/298 SettingPropertiesNotAllowed: AugmentedError<ApiType>;299 SettingPropertiesNotAllowed: AugmentedError<ApiType>;299 /**300 /**300 * Generic error301 * Generic errortests/src/interfaces/augment-api-query.tsdiffbeforeafterboth187 [key: string]: QueryableStorageEntry<ApiType>;187 [key: string]: QueryableStorageEntry<ApiType>;188 };188 };189 fungible: {189 fungible: {190 /**191 * Storage for delegated assets.192 **/190 allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;193 allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;194 /**195 * Amount of tokens owned by an account inside a collection.196 **/191 balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;197 balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;198 /**199 * Total amount of fungible tokens inside a collection.200 **/192 totalSupply: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;201 totalSupply: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;193 /**202 /**194 * Generic query203 * Generic query400 [key: string]: QueryableStorageEntry<ApiType>;409 [key: string]: QueryableStorageEntry<ApiType>;401 };410 };402 refungible: {411 refungible: {412 /**413 * Amount of tokens owned by account414 **/403 accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;415 accountBalance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u32>, [u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;416 /**417 * Allowance set by an owner for a spender for a token418 **/404 allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;419 allowance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg4: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]>;420 /**421 * Amount of token pieces owned by account422 **/405 balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;423 balance: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array, arg3: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => Observable<u128>, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]>;406 /**424 /**407 * Used to enumerate tokens owned by account425 * Used to enumerate tokens owned by account408 **/426 **/409 owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;427 owned: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, arg3: u32 | AnyNumber | Uint8Array) => Observable<bool>, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]>;428 /**429 * Custom data serialized to bytes for token430 **/410 tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;431 tokenData: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<PalletRefungibleItemData>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;432 tokenProperties: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<UpDataStructsProperties>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;411 tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;433 tokensBurnt: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;434 /**435 * Amount of tokens minted for collection436 **/412 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;437 tokensMinted: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<u32>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;438 /**439 * Total amount of pieces for token440 **/413 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;441 totalSupply: AugmentedQuery<ApiType, (arg1: u32 | AnyNumber | Uint8Array, arg2: u32 | AnyNumber | Uint8Array) => Observable<u128>, [u32, u32]> & QueryableStorageEntry<ApiType, [u32, u32]>;414 /**442 /**415 * Generic query443 * Generic querytests/src/interfaces/default/types.tsdiffbeforeafterboth2461export interface UpDataStructsCreateReFungibleData extends Struct {2461export interface UpDataStructsCreateReFungibleData extends Struct {2462 readonly constData: Bytes;2462 readonly constData: Bytes;2463 readonly pieces: u128;2463 readonly pieces: u128;2464 readonly properties: Vec<UpDataStructsProperty>;2464}2465}246524662466/** @name UpDataStructsCreateRefungibleExData */2467/** @name UpDataStructsCreateRefungibleExData */2467export interface UpDataStructsCreateRefungibleExData extends Struct {2468export interface UpDataStructsCreateRefungibleExData extends Struct {2468 readonly constData: Bytes;2469 readonly constData: Bytes;2469 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;2470 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;2471 readonly properties: Vec<UpDataStructsProperty>;2470}2472}247124732472/** @name UpDataStructsNestingPermissions */2474/** @name UpDataStructsNestingPermissions */tests/src/interfaces/lookup.tsdiffbeforeafterboth1502 **/1502 **/1503 UpDataStructsCreateReFungibleData: {1503 UpDataStructsCreateReFungibleData: {1504 constData: 'Bytes',1504 constData: 'Bytes',1505 pieces: 'u128'1505 pieces: 'u128',1506 properties: 'Vec<UpDataStructsProperty>'1506 },1507 },1507 /**1508 /**1508 * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1509 * Lookup193: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>1527 **/1528 **/1528 UpDataStructsCreateRefungibleExData: {1529 UpDataStructsCreateRefungibleExData: {1529 constData: 'Bytes',1530 constData: 'Bytes',1530 users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>'1531 users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',1532 properties: 'Vec<UpDataStructsProperty>'1531 },1533 },1532 /**1534 /**1533 * Lookup204: pallet_unique_scheduler::pallet::Call<T>1535 * Lookup204: pallet_unique_scheduler::pallet::Call<T>tests/src/interfaces/types-lookup.tsdiffbeforeafterboth1629 export interface UpDataStructsCreateReFungibleData extends Struct {1629 export interface UpDataStructsCreateReFungibleData extends Struct {1630 readonly constData: Bytes;1630 readonly constData: Bytes;1631 readonly pieces: u128;1631 readonly pieces: u128;1632 readonly properties: Vec<UpDataStructsProperty>;1632 }1633 }163316341634 /** @name UpDataStructsCreateItemExData (193) */1635 /** @name UpDataStructsCreateItemExData (193) */1654 export interface UpDataStructsCreateRefungibleExData extends Struct {1655 export interface UpDataStructsCreateRefungibleExData extends Struct {1655 readonly constData: Bytes;1656 readonly constData: Bytes;1656 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;1657 readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;1658 readonly properties: Vec<UpDataStructsProperty>;1657 }1659 }165816601659 /** @name PalletUniqueSchedulerCall (204) */1661 /** @name PalletUniqueSchedulerCall (204) */tests/src/nesting/properties.test.tsdiffbeforeafterboth2import usingApi, {executeTransaction} from '../substrate/substrate-api';2import usingApi, {executeTransaction} from '../substrate/substrate-api';3import {3import {4 addCollectionAdminExpectSuccess,4 addCollectionAdminExpectSuccess,5 CollectionMode,5 createCollectionExpectSuccess,6 createCollectionExpectSuccess,6 setCollectionPermissionsExpectSuccess,7 setCollectionPermissionsExpectSuccess,7 createItemExpectSuccess,8 createItemExpectSuccess,23 });24 });24 });25 });252626 it('Makes sure collectionById supplies required fields', async () => {27 async function testMakeSureSuppliesRequired(mode: CollectionMode) {27 await usingApi(async api => {28 await usingApi(async api => {28 const collectionId = await createCollectionExpectSuccess();29 const collectionId = await createCollectionExpectSuccess({mode: mode});293030 const collectionOption = await api.rpc.unique.collectionById(collectionId);31 const collectionOption = await api.rpc.unique.collectionById(collectionId);31 expect(collectionOption.isSome).to.be.true;32 expect(collectionOption.isSome).to.be.true;57 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);58 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);58 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);59 expect(collection.properties.toHuman()).to.be.deep.equal(collectionProperties);59 });60 });61 }6263 it('Makes sure collectionById supplies required fields for NFT', async () => {64 await testMakeSureSuppliesRequired({type: 'NFT'});60 });65 });6667 it('Makes sure collectionById supplies required fields for ReFungible', async () => {68 await testMakeSureSuppliesRequired({type: 'ReFungible'});69 });61});70});627163// ---------- COLLECTION PROPERTIES72// ---------- COLLECTION PROPERTIES79 });88 });80 });89 });81909182 it('Sets properties for a collection', async () => {92 async function testSetsPropertiesForCollection(mode: string) {83 await usingApi(async api => {93 await usingApi(async api => {84 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));94 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));85 const {collectionId} = getCreateCollectionResult(events);95 const {collectionId} = getCreateCollectionResult(events);869687 // As owner97 // As owner106 {key: 'black_hole', value: ''},116 {key: 'black_hole', value: ''},107 ]);117 ]);108 });118 });119 }120 it('Sets properties for a NFT collection', async () => {121 await testSetsPropertiesForCollection('NFT');109 });122 });123 it('Sets properties for a ReFungible collection', async () => {124 await testSetsPropertiesForCollection('ReFungible');125 });110126111 it('Check valid names for collection properties keys', async () => {127 async function testCheckValidNames(mode: string) {112 await usingApi(async api => {128 await usingApi(async api => {113 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));129 const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: mode}));114 const {collectionId} = getCreateCollectionResult(events);130 const {collectionId} = getCreateCollectionResult(events);115131 116 // alpha symbols132 // alpha symbols117 await expect(executeTransaction(133 await expect(executeTransaction(118 api, 134 api, 119 bob, 135 bob, 120 api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 136 api.tx.unique.setCollectionProperties(collectionId, [{key: 'alpha'}]), 121 )).to.not.be.rejected;137 )).to.not.be.rejected;122138 123 // numeric symbols139 // numeric symbols124 await expect(executeTransaction(140 await expect(executeTransaction(125 api, 141 api, 126 bob, 142 bob, 127 api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 143 api.tx.unique.setCollectionProperties(collectionId, [{key: '123'}]), 128 )).to.not.be.rejected;144 )).to.not.be.rejected;129145 130 // underscore symbol146 // underscore symbol131 await expect(executeTransaction(147 await expect(executeTransaction(132 api, 148 api, 133 bob, 149 bob, 134 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 150 api.tx.unique.setCollectionProperties(collectionId, [{key: 'black_hole'}]), 135 )).to.not.be.rejected;151 )).to.not.be.rejected;136152 137 // dash symbol153 // dash symbol138 await expect(executeTransaction(154 await expect(executeTransaction(139 api, 155 api, 140 bob, 156 bob, 141 api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 157 api.tx.unique.setCollectionProperties(collectionId, [{key: 'semi-automatic'}]), 142 )).to.not.be.rejected;158 )).to.not.be.rejected;143159 144 // underscore symbol160 // underscore symbol145 await expect(executeTransaction(161 await expect(executeTransaction(146 api, 162 api, 147 bob, 163 bob, 148 api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 164 api.tx.unique.setCollectionProperties(collectionId, [{key: 'build.rs'}]), 149 )).to.not.be.rejected;165 )).to.not.be.rejected;150166 151 const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];167 const propertyKeys = ['alpha', '123', 'black_hole', 'semi-automatic', 'build.rs'];152 const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();168 const properties = (await api.rpc.unique.collectionProperties(collectionId, propertyKeys)).toHuman();153 expect(properties).to.be.deep.equal([169 expect(properties).to.be.deep.equal([158 {key: 'build.rs', value: ''},174 {key: 'build.rs', value: ''},159 ]);175 ]);160 });176 });177 }178 it('Check valid names for NFT collection properties keys', async () => {179 await testCheckValidNames('NFT');161 });180 });181 it('Check valid names for ReFungible collection properties keys', async () => {182 await testCheckValidNames('ReFungible');183 });162184163 it('Changes properties of a collection', async () => {185 async function testChangesProperties(mode: CollectionMode) {164 await usingApi(async api => {186 await usingApi(async api => {165 const collection = await createCollectionExpectSuccess();187 const collection = await createCollectionExpectSuccess({mode: mode});166188 167 await expect(executeTransaction(189 await expect(executeTransaction(168 api, 190 api, 169 alice, 191 alice, 170 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 192 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole'}]), 171 )).to.not.be.rejected;193 )).to.not.be.rejected;172194 173 // Mutate the properties195 // Mutate the properties174 await expect(executeTransaction(196 await expect(executeTransaction(175 api, 197 api, 176 alice, 198 alice, 177 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 199 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black_hole', value: 'LIGO'}]), 178 )).to.not.be.rejected;200 )).to.not.be.rejected;179201 180 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();202 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();181 expect(properties).to.be.deep.equal([203 expect(properties).to.be.deep.equal([182 {key: 'electron', value: 'bonded'},204 {key: 'electron', value: 'bonded'},183 {key: 'black_hole', value: 'LIGO'},205 {key: 'black_hole', value: 'LIGO'},184 ]);206 ]);185 });207 });208 }209 it('Changes properties of a NFT collection', async () => {210 await testChangesProperties({type: 'NFT'});186 });211 });212 it('Changes properties of a ReFungible collection', async () => {213 await testChangesProperties({type: 'ReFungible'});214 });187215188 it('Deletes properties of a collection', async () => {216 async function testDeleteProperties(mode: CollectionMode) {189 await usingApi(async api => {217 await usingApi(async api => {190 const collection = await createCollectionExpectSuccess();218 const collection = await createCollectionExpectSuccess({mode: mode});191219 192 await expect(executeTransaction(220 await expect(executeTransaction(193 api, 221 api, 194 alice, 222 alice, 195 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 223 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]), 196 )).to.not.be.rejected;224 )).to.not.be.rejected;197225 198 await expect(executeTransaction(226 await expect(executeTransaction(199 api, 227 api, 200 alice, 228 alice, 201 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 229 api.tx.unique.deleteCollectionProperties(collection, ['electron']), 202 )).to.not.be.rejected;230 )).to.not.be.rejected;203231 204 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();232 const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black_hole'])).toHuman();205 expect(properties).to.be.deep.equal([233 expect(properties).to.be.deep.equal([206 {key: 'black_hole', value: 'LIGO'},234 {key: 'black_hole', value: 'LIGO'},207 ]);235 ]);208 });236 }); 237 }238 it('Deletes properties of a NFT collection', async () => {239 await testDeleteProperties({type: 'NFT'});209 });240 });241 it('Deletes properties of a ReFungible collection', async () => {242 await testDeleteProperties({type: 'ReFungible'});243 });210});244});211245212describe('Negative Integration Test: Collection Properties', () => {246describe('Negative Integration Test: Collection Properties', () => {217 });251 });218 });252 });219 253 220 it('Fails to set properties in a collection if not its onwer/administrator', async () => {254 async function testFailsSetPropertiesIfNotOwnerOrAdmin(mode: CollectionMode) {221 await usingApi(async api => {255 await usingApi(async api => {222 const collection = await createCollectionExpectSuccess();256 const collection = await createCollectionExpectSuccess({mode: mode});223257 224 await expect(executeTransaction(258 await expect(executeTransaction(225 api, 259 api, 226 bob, 260 bob, 230 const properties = (await api.query.common.collectionProperties(collection)).toJSON();264 const properties = (await api.query.common.collectionProperties(collection)).toJSON();231 expect(properties.map).to.be.empty;265 expect(properties.map).to.be.empty;232 expect(properties.consumedSpace).to.equal(0);266 expect(properties.consumedSpace).to.equal(0);233 });267 }); 268 }269 it('Fails to set properties in a NFT collection if not its onwer/administrator', async () => {270 await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'NFT'});234 });271 });272 it('Fails to set properties in a ReFungible collection if not its onwer/administrator', async () => {273 await testFailsSetPropertiesIfNotOwnerOrAdmin({type: 'ReFungible'});274 });235 275 236 it('Fails to set properties that exceed the limits', async () => {276 async function testFailsSetPropertiesThatExeedLimits(mode: CollectionMode) {237 await usingApi(async api => {277 await usingApi(async api => {238 const collection = await createCollectionExpectSuccess();278 const collection = await createCollectionExpectSuccess({mode: mode});239 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 279 const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 240280 241 // Mute the general tx parsing error, too many bytes to process281 // Mute the general tx parsing error, too many bytes to process242 {282 {243 console.error = () => {};283 console.error = () => {};247 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 287 api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 248 )).to.be.rejected;288 )).to.be.rejected;249 }289 }250290 251 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();291 let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();252 expect(properties).to.be.empty;292 expect(properties).to.be.empty;253293 254 await expect(executeTransaction(294 await expect(executeTransaction(255 api, 295 api, 256 alice, 296 alice, 259 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 299 {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 260 ]), 300 ]), 261 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);301 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);262302 263 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();303 properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();264 expect(properties).to.be.empty;304 expect(properties).to.be.empty;265 });305 }); 306 }307 it('Fails to set properties that exceed the limits (NFT)', async () => {308 await testFailsSetPropertiesThatExeedLimits({type: 'NFT'});266 });309 });310 it('Fails to set properties that exceed the limits (ReFungible)', async () => {311 await testFailsSetPropertiesThatExeedLimits({type: 'ReFungible'});312 });267 313 268 it('Fails to set more properties than it is allowed', async () => {314 async function testFailsSetMorePropertiesThanAllowed(mode: CollectionMode) {269 await usingApi(async api => {315 await usingApi(async api => {270 const collection = await createCollectionExpectSuccess();316 const collection = await createCollectionExpectSuccess({mode: mode});271317 272 const propertiesToBeSet = [];318 const propertiesToBeSet = [];273 for (let i = 0; i < 65; i++) {319 for (let i = 0; i < 65; i++) {274 propertiesToBeSet.push({320 propertiesToBeSet.push({275 key: 'electron_' + i,321 key: 'electron_' + i,276 value: Math.random() > 0.5 ? 'high' : 'low',322 value: Math.random() > 0.5 ? 'high' : 'low',277 });323 });278 }324 }279325 280 await expect(executeTransaction(326 await expect(executeTransaction(281 api, 327 api, 282 alice, 328 alice, 283 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 329 api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 284 )).to.be.rejectedWith(/common\.PropertyLimitReached/);330 )).to.be.rejectedWith(/common\.PropertyLimitReached/);285331 286 const properties = (await api.query.common.collectionProperties(collection)).toJSON();332 const properties = (await api.query.common.collectionProperties(collection)).toJSON();287 expect(properties.map).to.be.empty;333 expect(properties.map).to.be.empty;288 expect(properties.consumedSpace).to.equal(0);334 expect(properties.consumedSpace).to.equal(0);289 });335 }); 336 }337 it('Fails to set more properties than it is allowed (NFT)', async () => {338 await testFailsSetMorePropertiesThanAllowed({type: 'NFT'});290 });339 });291292 it('Fails to set properties with invalid names', async () => {340 it('Fails to set more properties than it is allowed (ReFungible)', async () => {341 await testFailsSetMorePropertiesThanAllowed({type: 'ReFungible'});342 });343 344 async function testFailsSetPropertiesWithInvalidNames(mode: CollectionMode) {293 await usingApi(async api => {345 await usingApi(async api => {294 const collection = await createCollectionExpectSuccess();346 const collection = await createCollectionExpectSuccess({mode: mode});295347 296 const invalidProperties = [348 const invalidProperties = [297 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],349 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],298 [{key: 'Mr/Sandman', value: 'Bring me a gene'}],350 [{key: 'Mr/Sandman', value: 'Bring me a gene'}],299 [{key: 'déjà vu', value: 'hmm...'}],351 [{key: 'déjà vu', value: 'hmm...'}],300 ];352 ];301353 302 for (let i = 0; i < invalidProperties.length; i++) {354 for (let i = 0; i < invalidProperties.length; i++) {303 await expect(executeTransaction(355 await expect(executeTransaction(304 api, 356 api, 305 alice, 357 alice, 306 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 358 api.tx.unique.setCollectionProperties(collection, invalidProperties[i]), 307 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);359 ), `on rejecting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);308 }360 }309361 310 await expect(executeTransaction(362 await expect(executeTransaction(311 api, 363 api, 312 alice, 364 alice, 313 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 365 api.tx.unique.setCollectionProperties(collection, [{key: '', value: 'nothing must not exist'}]), 314 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);366 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);315367 316 await expect(executeTransaction(368 await expect(executeTransaction(317 api, 369 api, 318 alice, 370 alice, 319 api.tx.unique.setCollectionProperties(collection, [371 api.tx.unique.setCollectionProperties(collection, [320 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},372 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},321 ]), 373 ]), 322 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;374 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;323375 324 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');376 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');325377 326 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();378 const properties = (await api.rpc.unique.collectionProperties(collection, keys)).toHuman();327 expect(properties).to.be.deep.equal([379 expect(properties).to.be.deep.equal([328 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},380 {key: 'CRISPR-Cas9', value: 'rewriting nature!'},329 ]);381 ]);330382 331 for (let i = 0; i < invalidProperties.length; i++) {383 for (let i = 0; i < invalidProperties.length; i++) {332 await expect(executeTransaction(384 await expect(executeTransaction(333 api, 385 api, 336 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);388 ), `on trying to delete the non-existent badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);337 }389 }338 });390 });391 }392 it('Fails to set properties with invalid names (NFT)', async () => {393 await testFailsSetPropertiesWithInvalidNames({type: 'NFT'});339 });394 });395 it('Fails to set properties with invalid names (ReFungible)', async () => {396 await testFailsSetPropertiesWithInvalidNames({type: 'ReFungible'});397 });340});398});341399342// ---------- ACCESS RIGHTS400// ---------- ACCESS RIGHTS357 });415 });358 });416 });359 417 360 it('Sets access rights to properties of a collection', async () => {418 async function testSetsAccessRightsToProperties(mode: CollectionMode) {361 await usingApi(async api => {419 await usingApi(async api => {362 const collection = await createCollectionExpectSuccess();420 const collection = await createCollectionExpectSuccess({mode: mode});363421 364 await expect(executeTransaction(422 await expect(executeTransaction(365 api, 423 api, 366 alice, 424 alice, 367 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 425 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 368 )).to.not.be.rejected;426 )).to.not.be.rejected;369427 370 await addCollectionAdminExpectSuccess(alice, collection, bob.address);428 await addCollectionAdminExpectSuccess(alice, collection, bob.address);371429 372 await expect(executeTransaction(430 await expect(executeTransaction(373 api, 431 api, 374 alice, 432 alice, 375 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 433 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 376 )).to.not.be.rejected;434 )).to.not.be.rejected;377435 378 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();436 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toHuman();379 expect(propertyRights).to.be.deep.equal([437 expect(propertyRights).to.be.deep.equal([380 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},438 {key: 'skullduggery', permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},381 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},439 {key: 'mindgame', permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},382 ]);440 ]);383 });441 }); 442 }443 it('Sets access rights to properties of a collection (NFT)', async () => {444 await testSetsAccessRightsToProperties({type: 'NFT'});384 });445 });446 it('Sets access rights to properties of a collection (ReFungible)', async () => {447 await testSetsAccessRightsToProperties({type: 'ReFungible'});448 });385 449 386 it('Changes access rights to properties of a collection', async () => {450 async function testChangesAccessRightsToProperty(mode: CollectionMode) {387 await usingApi(async api => {451 await usingApi(async api => {388 const collection = await createCollectionExpectSuccess();452 const collection = await createCollectionExpectSuccess({mode: mode});389453 390 await expect(executeTransaction(454 await expect(executeTransaction(391 api, 455 api, 392 alice, 456 alice, 393 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 457 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 394 )).to.not.be.rejected;458 )).to.not.be.rejected;395459 396 await expect(executeTransaction(460 await expect(executeTransaction(397 api, 461 api, 398 alice, 462 alice, 399 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 463 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 400 )).to.not.be.rejected;464 )).to.not.be.rejected;401465 402 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();466 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();403 expect(propertyRights).to.be.deep.equal([467 expect(propertyRights).to.be.deep.equal([404 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},468 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},405 ]);469 ]);406 });470 });471 }472 it('Changes access rights to properties of a NFT collection', async () => {473 await testChangesAccessRightsToProperty({type: 'NFT'});407 });474 });475 it('Changes access rights to properties of a ReFungible collection', async () => {476 await testChangesAccessRightsToProperty({type: 'ReFungible'});477 });408});478});409479410describe('Negative Integration Test: Access Rights to Token Properties', () => {480describe('Negative Integration Test: Access Rights to Token Properties', () => {415 });485 });416 });486 });417487418 it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {488 async function testPreventsFromSettingAccessRightsNotAdminOrOwner(mode: CollectionMode) {419 await usingApi(async api => {489 await usingApi(async api => {420 const collection = await createCollectionExpectSuccess();490 const collection = await createCollectionExpectSuccess({mode: mode});421491 422 await expect(executeTransaction(492 await expect(executeTransaction(423 api, 493 api, 424 bob, 494 bob, 425 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 495 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 426 )).to.be.rejectedWith(/common\.NoPermission/);496 )).to.be.rejectedWith(/common\.NoPermission/);427497 428 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();498 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();429 expect(propertyRights).to.be.empty;499 expect(propertyRights).to.be.empty;430 });500 });501 }502 it('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async () => {503 await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'NFT'});431 });504 });505 it('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', async () => {506 await testPreventsFromSettingAccessRightsNotAdminOrOwner({type: 'ReFungible'});507 });432508433 it('Prevents from adding too many possible properties', async () => {509 async function testPreventFromAddingTooManyPossibleProperties(mode: CollectionMode) {434 await usingApi(async api => {510 await usingApi(async api => {435 const collection = await createCollectionExpectSuccess();511 const collection = await createCollectionExpectSuccess({mode: mode});436512 437 const constitution = [];513 const constitution = [];438 for (let i = 0; i < 65; i++) {514 for (let i = 0; i < 65; i++) {439 constitution.push({515 constitution.push({440 key: 'property_' + i,516 key: 'property_' + i,441 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},517 permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},442 });518 });443 }519 }444520 445 await expect(executeTransaction(521 await expect(executeTransaction(446 api, 522 api, 447 alice, 523 alice, 448 api.tx.unique.setTokenPropertyPermissions(collection, constitution), 524 api.tx.unique.setTokenPropertyPermissions(collection, constitution), 449 )).to.be.rejectedWith(/common\.PropertyLimitReached/);525 )).to.be.rejectedWith(/common\.PropertyLimitReached/);450526 451 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();527 const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();452 expect(propertyRights).to.be.empty;528 expect(propertyRights).to.be.empty;453 });529 }); 530 }531 it('Prevents from adding too many possible properties (NFT)', async () => {532 await testPreventFromAddingTooManyPossibleProperties({type: 'NFT'});454 });533 });534 it('Prevents from adding too many possible properties (ReFungible)', async () => {535 await testPreventFromAddingTooManyPossibleProperties({type: 'ReFungible'});536 });455537456 it('Prevents access rights to be modified if constant', async () => {538 async function testPreventAccessRightsModifiedIfConstant(mode: CollectionMode) {457 await usingApi(async api => {539 await usingApi(async api => {458 const collection = await createCollectionExpectSuccess();540 const collection = await createCollectionExpectSuccess({mode: mode});459541 460 await expect(executeTransaction(542 await expect(executeTransaction(461 api, 543 api, 462 alice, 544 alice, 463 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 545 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 464 )).to.not.be.rejected;546 )).to.not.be.rejected;465547 466 await expect(executeTransaction(548 await expect(executeTransaction(467 api, 549 api, 468 alice, 550 alice, 469 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 551 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 470 )).to.be.rejectedWith(/common\.NoPermission/);552 )).to.be.rejectedWith(/common\.NoPermission/);471553 472 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();554 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toHuman();473 expect(propertyRights).to.deep.equal([555 expect(propertyRights).to.deep.equal([474 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},556 {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},475 ]);557 ]);476 });558 }); 559 }560 it('Prevents access rights to be modified if constant (NFT)', async () => {561 await testPreventAccessRightsModifiedIfConstant({type: 'NFT'});477 });562 });563 it('Prevents access rights to be modified if constant (ReFungible)', async () => {564 await testPreventAccessRightsModifiedIfConstant({type: 'ReFungible'});565 });478566479 it('Prevents adding properties with invalid names', async () => {567 async function testPreventsAddingPropertiesWithInvalidNames(mode: CollectionMode) {480 await usingApi(async api => {568 await usingApi(async api => {481 const collection = await createCollectionExpectSuccess();569 const collection = await createCollectionExpectSuccess({mode: mode});482570 483 const invalidProperties = [571 const invalidProperties = [484 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],572 [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],485 [{key: 'G#4', permission: {tokenOwner: true}}],573 [{key: 'G#4', permission: {tokenOwner: true}}],486 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],574 [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],487 ];575 ];488576 489 for (let i = 0; i < invalidProperties.length; i++) {577 for (let i = 0; i < invalidProperties.length; i++) {490 await expect(executeTransaction(578 await expect(executeTransaction(491 api, 579 api, 492 alice, 580 alice, 493 api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 581 api.tx.unique.setTokenPropertyPermissions(collection, invalidProperties[i]), 494 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);582 ), `on setting the new badly-named property #${i}`).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);495 }583 }496584 497 await expect(executeTransaction(585 await expect(executeTransaction(498 api, 586 api, 499 alice, 587 alice, 500 api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 588 api.tx.unique.setTokenPropertyPermissions(collection, [{key: '', permission: {}}]), 501 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);589 ), 'on rejecting an unnamed property').to.be.rejectedWith(/common\.EmptyPropertyKey/);502590 503 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string591 const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string504 await expect(executeTransaction(592 await expect(executeTransaction(505 api, 593 api, 508 {key: correctKey, permission: {collectionAdmin: true}},596 {key: correctKey, permission: {collectionAdmin: true}},509 ]), 597 ]), 510 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;598 ), 'on setting the correctly-but-still-badly-named property').to.not.be.rejected;511599 512 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');600 const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');513601 514 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();602 const propertyRights = (await api.rpc.unique.propertyPermissions(collection, keys)).toHuman();515 expect(propertyRights).to.be.deep.equal([603 expect(propertyRights).to.be.deep.equal([516 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},604 {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},517 ]);605 ]);518 });606 });607 }608 it('Prevents adding properties with invalid names (NFT)', async () => {609 await testPreventsAddingPropertiesWithInvalidNames({type: 'NFT'});519 });610 });611 it('Prevents adding properties with invalid names (ReFungible)', async () => {612 await testPreventsAddingPropertiesWithInvalidNames({type: 'ReFungible'});613 });520});614});521615522// ---------- TOKEN PROPERTIES616// ---------- TOKEN PROPERTIES523617524describe('Integration Test: Token Properties', () => {618describe('Integration Test: Token Properties', () => {525 let collection: number;526 let token: number;527 let nestedToken: number;528 let permissions: {permission: any, signers: IKeyringPair[]}[];619 let permissions: {permission: any, signers: IKeyringPair[]}[];529620530 before(async () => {621 before(async () => {531 await usingApi(async (api, privateKeyWrapper) => {622 await usingApi(async (api, privateKeyWrapper) => {532 alice = privateKeyWrapper('//Alice');623 alice = privateKeyWrapper('//Alice'); // collection owner533 bob = privateKeyWrapper('//Bob');624 bob = privateKeyWrapper('//Bob'); // collection admin534 charlie = privateKeyWrapper('//Charlie');625 charlie = privateKeyWrapper('//Charlie'); // token owner535626536 permissions = [627 permissions = [537 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},628 {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},543 ];634 ];544 });635 });545 });636 });546547 beforeEach(async () => {548 await usingApi(async () => {549 collection = await createCollectionExpectSuccess();550 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});551552 token = await createItemExpectSuccess(alice, collection, 'NFT');553 nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});554555 await addCollectionAdminExpectSuccess(alice, collection, bob.address);556 await transferExpectSuccess(collection, token, alice, charlie);557 });558 });559 637 560 it('Reads yet empty properties of a token', async () => {638 async function testReadsYetEmptyProperties(mode: CollectionMode) {561 await usingApi(async api => {639 await usingApi(async api => {562 const collection = await createCollectionExpectSuccess();640 const collection = await createCollectionExpectSuccess({mode: mode});563 const token = await createItemExpectSuccess(alice, collection, 'NFT');641 const token = await createItemExpectSuccess(alice, collection, mode.type);564 642 565 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();643 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();566 expect(properties.map).to.be.empty;644 expect(properties.map).to.be.empty;567 expect(properties.consumedSpace).to.be.equal(0);645 expect(properties.consumedSpace).to.be.equal(0);568646 569 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;647 const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;570 expect(tokenData).to.be.empty;648 expect(tokenData).to.be.empty;571 });649 });650 }651 it('Reads yet empty properties of a token (NFT)', async () => {652 await testReadsYetEmptyProperties({type: 'NFT'});572 });653 });654 it('Reads yet empty properties of a token (ReFungible)', async () => {655 await testReadsYetEmptyProperties({type: 'ReFungible'});656 });573657574 it('Assigns properties to a token according to permissions', async () => {658 async function testAssignPropertiesAccordingToPermissions(mode: CollectionMode, pieces: number) {575 await usingApi(async api => {659 await usingApi(async api => {660 const collection = await createCollectionExpectSuccess({mode: mode});661 const token = await createItemExpectSuccess(alice, collection, mode.type);662 await addCollectionAdminExpectSuccess(alice, collection, bob.address);663 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);664576 const propertyKeys: string[] = [];665 const propertyKeys: string[] = [];577 let i = 0;666 let i = 0;578 for (const permission of permissions) {667 for (const permission of permissions) {603 expect(tokensData[i].value).to.be.equal('Serotonin increase');692 expect(tokensData[i].value).to.be.equal('Serotonin increase');604 }693 }605 });694 });695 }696 it('Assigns properties to a token according to permissions (NFT)', async () => {697 await testAssignPropertiesAccordingToPermissions({type: 'NFT'}, 1);606 });698 });699 it('Assigns properties to a token according to permissions (ReFungible)', async () => {700 await testAssignPropertiesAccordingToPermissions({type: 'ReFungible'}, 100);701 });607702608 it('Changes properties of a token according to permissions', async () => {703 async function testChangesPropertiesAccordingPermission(mode: CollectionMode, pieces: number) {609 await usingApi(async api => {704 await usingApi(async api => {705 const collection = await createCollectionExpectSuccess({mode: mode});706 const token = await createItemExpectSuccess(alice, collection, mode.type);707 await addCollectionAdminExpectSuccess(alice, collection, bob.address);708 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);709610 const propertyKeys: string[] = [];710 const propertyKeys: string[] = [];611 let i = 0;711 let i = 0;612 for (const permission of permissions) {712 for (const permission of permissions) {615 for (const signer of permission.signers) {715 for (const signer of permission.signers) {616 const key = i + '_' + signer.address;716 const key = i + '_' + signer.address;617 propertyKeys.push(key);717 propertyKeys.push(key);618718 619 await expect(executeTransaction(719 await expect(executeTransaction(620 api, 720 api, 621 alice, 721 alice, 622 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 722 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 623 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;723 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;624724 625 await expect(executeTransaction(725 await expect(executeTransaction(626 api, 726 api, 627 signer, 727 signer, 628 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 728 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 629 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;729 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;630730 631 await expect(executeTransaction(731 await expect(executeTransaction(632 api, 732 api, 633 signer, 733 signer, 634 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 734 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 635 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;735 ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;636 }736 }637737 638 i++;738 i++;639 }739 }640740 641 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];741 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toHuman() as any[];642 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];742 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toHuman().properties as any[];643 for (let i = 0; i < properties.length; i++) {743 for (let i = 0; i < properties.length; i++) {644 expect(properties[i].value).to.be.equal('Serotonin stable');744 expect(properties[i].value).to.be.equal('Serotonin stable');645 expect(tokensData[i].value).to.be.equal('Serotonin stable');745 expect(tokensData[i].value).to.be.equal('Serotonin stable');646 }746 }647 });747 });748 }749 it('Changes properties of a token according to permissions (NFT)', async () => {750 await testChangesPropertiesAccordingPermission({type: 'NFT'}, 1);648 });751 });752 it('Changes properties of a token according to permissions (ReFungible)', async () => {753 await testChangesPropertiesAccordingPermission({type: 'ReFungible'}, 100);754 });649755650 it('Deletes properties of a token according to permissions', async () => {756 async function testDeletePropertiesAccordingPermission(mode: CollectionMode, pieces: number) {651 await usingApi(async api => {757 await usingApi(async api => {758 const collection = await createCollectionExpectSuccess({mode: mode});759 const token = await createItemExpectSuccess(alice, collection, mode.type);760 await addCollectionAdminExpectSuccess(alice, collection, bob.address);761 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);762652 const propertyKeys: string[] = [];763 const propertyKeys: string[] = [];653 let i = 0;764 let i = 0;654765 655 for (const permission of permissions) {766 for (const permission of permissions) {656 if (!permission.permission.mutable) continue;767 if (!permission.permission.mutable) continue;657 768 658 for (const signer of permission.signers) {769 for (const signer of permission.signers) {659 const key = i + '_' + signer.address;770 const key = i + '_' + signer.address;660 propertyKeys.push(key);771 propertyKeys.push(key);661772 662 await expect(executeTransaction(773 await expect(executeTransaction(663 api, 774 api, 664 alice, 775 alice, 665 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 776 api.tx.unique.setTokenPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 666 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;777 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;667778 668 await expect(executeTransaction(779 await expect(executeTransaction(669 api, 780 api, 670 signer, 781 signer, 671 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 782 api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 672 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;783 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;673784 674 await expect(executeTransaction(785 await expect(executeTransaction(675 api, 786 api, 676 signer, 787 signer, 680 791 681 i++;792 i++;682 }793 }683794 684 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];795 const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];685 expect(properties).to.be.empty;796 expect(properties).to.be.empty;686 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];797 const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];687 expect(tokensData).to.be.empty;798 expect(tokensData).to.be.empty;688 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);799 expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);689 });800 });801 }802 it('Deletes properties of a token according to permissions (NFT)', async () => {803 await testDeletePropertiesAccordingPermission({type: 'NFT'}, 1);690 });804 });805 it('Deletes properties of a token according to permissions (ReFungible)', async () => {806 await testDeletePropertiesAccordingPermission({type: 'ReFungible'}, 100);807 });691808692 it('Assigns properties to a nested token according to permissions', async () => {809 it('Assigns properties to a nested token according to permissions', async () => {693 await usingApi(async api => {810 await usingApi(async api => {811 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});812 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});813 const token = await createItemExpectSuccess(alice, collection, 'NFT');814 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});815 await addCollectionAdminExpectSuccess(alice, collection, bob.address);816 await transferExpectSuccess(collection, token, alice, charlie);817694 const propertyKeys: string[] = [];818 const propertyKeys: string[] = [];695 let i = 0;819 let i = 0;696 for (const permission of permissions) {820 for (const permission of permissions) {725849726 it('Changes properties of a nested token according to permissions', async () => {850 it('Changes properties of a nested token according to permissions', async () => {727 await usingApi(async api => {851 await usingApi(async api => {852 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});853 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});854 const token = await createItemExpectSuccess(alice, collection, 'NFT');855 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});856 await addCollectionAdminExpectSuccess(alice, collection, bob.address);857 await transferExpectSuccess(collection, token, alice, charlie);858728 const propertyKeys: string[] = [];859 const propertyKeys: string[] = [];729 let i = 0;860 let i = 0;730 for (const permission of permissions) {861 for (const permission of permissions) {767898768 it('Deletes properties of a nested token according to permissions', async () => {899 it('Deletes properties of a nested token according to permissions', async () => {769 await usingApi(async api => {900 await usingApi(async api => {901 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});902 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});903 const token = await createItemExpectSuccess(alice, collection, 'NFT');904 const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});905 await addCollectionAdminExpectSuccess(alice, collection, bob.address);906 await transferExpectSuccess(collection, token, alice, charlie);907770 const propertyKeys: string[] = [];908 const propertyKeys: string[] = [];771 let i = 0;909 let i = 0;772910832 });970 });833 });971 });834972835 beforeEach(async () => {973 async function prepare(mode: CollectionMode, pieces: number) {836 collection = await createCollectionExpectSuccess();974 collection = await createCollectionExpectSuccess({mode: mode});837 token = await createItemExpectSuccess(alice, collection, 'NFT');975 token = await createItemExpectSuccess(alice, collection, mode.type);838 await addCollectionAdminExpectSuccess(alice, collection, bob.address);976 await addCollectionAdminExpectSuccess(alice, collection, bob.address);839 await transferExpectSuccess(collection, token, alice, charlie);977 await transferExpectSuccess(collection, token, alice, charlie, pieces, mode.type);840 978 841 await usingApi(async api => {979 await usingApi(async api => {842 let i = 0;980 let i = 0;848 alice, 986 alice, 849 api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 987 api.tx.unique.setTokenPropertyPermissions(collection, [{key: `${i}`, permission: passage.permission}]), 850 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;988 ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;851989 852 await expect(executeTransaction(990 await expect(executeTransaction(853 api, 991 api, 854 signer, 992 signer, 855 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 993 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin increase'}]), 856 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;994 ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;857995 858 i++;996 i++;859 }997 }860998 861 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;999 originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;862 });1000 }); 863 });1001 }8641002865 it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {1003 async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(mode: CollectionMode, pieces: number) {1004 await prepare(mode, pieces);1005 866 await usingApi(async api => {1006 await usingApi(async api => {867 let i = -1;1007 let i = -1;868 for (const forbiddance of constitution) {1008 for (const forbiddance of constitution) {869 i++;1009 i++;870 if (!forbiddance.permission.mutable) continue;1010 if (!forbiddance.permission.mutable) continue;8711011 872 await expect(executeTransaction(1012 await expect(executeTransaction(873 api, 1013 api, 874 forbiddance.sinner, 1014 forbiddance.sinner, 875 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1015 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 876 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1016 ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);8771017 878 await expect(executeTransaction(1018 await expect(executeTransaction(879 api, 1019 api, 880 forbiddance.sinner, 1020 forbiddance.sinner, 881 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 1021 api.tx.unique.deleteTokenProperties(collection, token, [`${i}`]), 882 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);1022 ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);883 }1023 }8841024 885 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1025 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();886 expect(properties.consumedSpace).to.be.equal(originalSpace);1026 expect(properties.consumedSpace).to.be.equal(originalSpace);887 });1027 });1028 }1029 it('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async () => {1030 await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'NFT'}, 1);888 });1031 });1032 it('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', async () => {1033 await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions({type: 'ReFungible'}, 100);1034 });8891035890 it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {1036 async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(mode: CollectionMode, pieces: number) {1037 await prepare(mode, pieces);1038 891 await usingApi(async api => {1039 await usingApi(async api => {892 let i = -1;1040 let i = -1;893 for (const permission of constitution) {1041 for (const permission of constitution) {894 i++;1042 i++;895 if (permission.permission.mutable) continue;1043 if (permission.permission.mutable) continue;8961044 897 await expect(executeTransaction(1045 await expect(executeTransaction(898 api, 1046 api, 899 permission.signers[0], 1047 permission.signers[0], 900 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 1048 api.tx.unique.setTokenProperties(collection, token, [{key: `${i}`, value: 'Serotonin down'}]), 901 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1049 ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);9021050 903 await expect(executeTransaction(1051 await expect(executeTransaction(904 api, 1052 api, 905 permission.signers[0], 1053 permission.signers[0], 906 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 1054 api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 907 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);1055 ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);908 }1056 }9091057 910 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1058 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();911 expect(properties.consumedSpace).to.be.equal(originalSpace);1059 expect(properties.consumedSpace).to.be.equal(originalSpace);912 });1060 }); 1061 }1062 it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async () => {1063 await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'NFT'}, 1);913 });1064 });1065 it('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', async () => {1066 await testForbidsChangingDeletingPropertiesIfPropertyImmutable({type: 'ReFungible'}, 100);1067 });9141068915 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {1069 async function testForbidsAddingPropertiesIfPropertyNotDeclared(mode: CollectionMode, pieces: number) {1070 await prepare(mode, pieces);1071916 await usingApi(async api => {1072 await usingApi(async api => {917 await expect(executeTransaction(1073 await expect(executeTransaction(925 alice, 1081 alice, 926 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 1082 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 927 ), 'on setting a new non-permitted property').to.not.be.rejected;1083 ), 'on setting a new non-permitted property').to.not.be.rejected;9281084 929 await expect(executeTransaction(1085 await expect(executeTransaction(930 api, 1086 api, 931 alice, 1087 alice, 932 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 1088 api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 933 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);1089 ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);9341090 935 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;1091 expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;936 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1092 const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();937 expect(properties.consumedSpace).to.be.equal(originalSpace);1093 expect(properties.consumedSpace).to.be.equal(originalSpace);938 });1094 });1095 }1096 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async () => {1097 await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'NFT'}, 1);939 });1098 });1099 it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', async () => {1100 await testForbidsAddingPropertiesIfPropertyNotDeclared({type: 'ReFungible'}, 100);1101 });9401102941 it('Forbids adding too many properties to a token', async () => {1103 async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {1104 await prepare(mode, pieces);1105942 await usingApi(async api => {1106 await usingApi(async api => {943 await expect(executeTransaction(1107 await expect(executeTransaction(948 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},1112 {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},949 ]), 1113 ]), 950 ), 'on setting a new non-permitted property').to.not.be.rejected;1114 ), 'on setting a new non-permitted property').to.not.be.rejected;9511115 952 // Mute the general tx parsing error1116 // Mute the general tx parsing error953 {1117 {954 console.error = () => {};1118 console.error = () => {};958 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 1122 api.tx.unique.setCollectionProperties(collection, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]), 959 )).to.be.rejected;1123 )).to.be.rejected;960 }1124 }9611125 962 await expect(executeTransaction(1126 await expect(executeTransaction(963 api, 1127 api, 964 alice, 1128 alice, 967 {key: 'young_years', value: 'neverending'.repeat(1490)},1131 {key: 'young_years', value: 'neverending'.repeat(1490)},968 ]), 1132 ]), 969 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);1133 )).to.be.rejectedWith(/common\.NoSpaceForProperty/);9701134 971 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;1135 expect((await api.rpc.unique.tokenProperties(collection, token, ['a_holy_book', 'young_years'])).toJSON()).to.be.empty;972 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();1136 const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();973 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1137 expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);1138 });1139 }1140 it('Forbids adding too many properties to a token (NFT)', async () => {1141 await testForbidsAddingTooManyProperties({type: 'NFT'}, 1);1142 });1143 it('Forbids adding too many properties to a token (ReFungible)', async () => {1144 await testForbidsAddingTooManyProperties({type: 'ReFungible'}, 100);1145 });1146});11471148describe('ReFungible token properties permissions tests', () => {1149 let collection: number;1150 let token: number;11511152 before(async () => {1153 await usingApi(async (api, privateKeyWrapper) => {1154 alice = privateKeyWrapper('//Alice');1155 bob = privateKeyWrapper('//Bob');1156 charlie = privateKeyWrapper('//Charlie');1157 });1158 });11591160 beforeEach(async () => {1161 await usingApi(async api => {1162 collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});1163 token = await createItemExpectSuccess(alice, collection, 'ReFungible');1164 await addCollectionAdminExpectSuccess(alice, collection, bob.address);11651166 await expect(executeTransaction(1167 api, 1168 alice, 1169 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1170 )).to.not.be.rejected;1171 });1172 });11731174 it('Forbids add token property with tokenOwher==true but signer have\'t all pieces', async () => {1175 await usingApi(async api => {1176 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1177 1178 await expect(executeTransaction(1179 api, 1180 alice, 1181 api.tx.unique.setTokenProperties(collection, token, [1182 {key: 'key', value: 'word'}, 1183 ]), 1184 )).to.be.rejectedWith(/common\.NoPermission/);1185 });1186 });11871188 it('Forbids mutate token property with tokenOwher==true but signer have\'t all pieces', async () => {1189 await usingApi(async api => {1190 await expect(executeTransaction(1191 api, 1192 alice, 1193 api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'key', permission: {mutable:true, tokenOwner: true}}]), 1194 )).to.not.be.rejected;1195 1196 await expect(executeTransaction(1197 api, 1198 alice, 1199 api.tx.unique.setTokenProperties(collection, token, [1200 {key: 'key', value: 'word'}, 1201 ]), 1202 )).to.be.not.rejected;12031204 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1205 1206 await expect(executeTransaction(1207 api, 1208 alice, 1209 api.tx.unique.setTokenProperties(collection, token, [1210 {key: 'key', value: 'bad word'}, 1211 ]), 1212 )).to.be.rejectedWith(/common\.NoPermission/);1213 });1214 });12151216 it('Forbids delete token property with tokenOwher==true but signer have\'t all pieces', async () => {1217 await usingApi(async api => {1218 await expect(executeTransaction(1219 api, 1220 alice, 1221 api.tx.unique.setTokenProperties(collection, token, [1222 {key: 'key', value: 'word'}, 1223 ]), 1224 )).to.be.not.rejected;12251226 await transferExpectSuccess(collection, token, alice, charlie, 33, 'ReFungible');1227 1228 await expect(executeTransaction(1229 api, 1230 alice, 1231 api.tx.unique.deleteTokenProperties(collection, token, [1232 'key',1233 ]), 1234 )).to.be.rejectedWith(/common\.NoPermission/);974 });1235 });975 });1236 });976});1237});tests/src/refungible.test.tsdiffbeforeafterboth14// 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/>.161617import {default as usingApi} from './substrate/substrate-api';17import {default as usingApi, executeTransaction} from './substrate/substrate-api';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {19import {20 createCollectionExpectSuccess,20 createCollectionExpectSuccess,30 transfer,30 transfer,31 burnItem,31 burnItem,32 repartitionRFT,32 repartitionRFT,33 createCollectionWithPropsExpectSuccess,34 getDetailedCollectionInfo,33} from './util/helpers';35} from './util/helpers';343635import chai from 'chai';37import chai from 'chai';188 });190 });189});191});192193describe('Test Refungible properties:', () => {194 before(async () => {195 await usingApi(async (api, privateKeyWrapper) => {196 alice = privateKeyWrapper('//Alice');197 bob = privateKeyWrapper('//Bob');198 });199 });200 201 it('Сreate new collection with properties', async () => {202 await usingApi(async api => {203 const properties = [{key: 'key1', value: 'val1'}];204 const propertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}];205 const collectionId = await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'ReFungible'},206 properties: properties,207 propPerm: propertyPermissions, 208 });209 const collection = (await getDetailedCollectionInfo(api, collectionId))!;210 expect(collection.properties.toHuman()).to.be.deep.equal(properties);211 expect(collection.tokenPropertyPermissions.toHuman()).to.be.deep.equal(propertyPermissions);212 });213 });214});190215tests/src/util/helpers.tsdiffbeforeafterboth284 type: 'ReFungible';284 type: 'ReFungible';285}285}286286287type CollectionMode = Nft | Fungible | ReFungible;287export type CollectionMode = Nft | Fungible | ReFungible;288288289export type Property = {289export type Property = {290 key: any,290 key: any,1414 tx = api.tx.unique.createItem(collectionId, to, createData as any);1414 tx = api.tx.unique.createItem(collectionId, to, createData as any);1415 }1415 }141614161417 const events = await submitTransactionAsync(sender, tx);1417 const events = await executeTransaction(api, sender, tx);1418 const result = getCreateItemResult(events);1418 const result = getCreateItemResult(events);141914191420 const itemCountAfter = await getLastTokenId(api, collectionId);1420 const itemCountAfter = await getLastTokenId(api, collectionId);tests/src/xcmTransfer.test.tsdiffbeforeafterboth31const UNIQUE_CHAIN = 1000;31const UNIQUE_CHAIN = 1000;32const KARURA_CHAIN = 2000;32const KARURA_CHAIN = 2000;33const KARURA_PORT = '9946';33const KARURA_PORT = '9946';34const TRANSFER_AMOUNT = 2000000000000000000000000n;343535describe('Integration test: Exchanging QTZ with Karura', () => {36describe('Integration test: Exchanging QTZ with Karura', () => {36 let alice: IKeyringPair;37 let alice: IKeyringPair;113 },114 },114 },115 },115 fun: {116 fun: {116 Fungible: 5000000000,117 Fungible: TRANSFER_AMOUNT,117 },118 },118 },119 },119 ],120 ],148149149 await usingApi(async (api) => {150 await usingApi(async (api) => {150 const destination = {151 const destination = {151 V0: {152 V1: {153 parents: 1,152 X3: [154 interior: {153 'Parent',155 X2: [154 {156 {Parachain: UNIQUE_CHAIN},155 Parachain: UNIQUE_CHAIN,156 },157 {157 {AccountId32: {158 AccountId32: {159 network: 'Any',158 network: 'Any',160 id: alice.addressRaw,159 id: alice.addressRaw,161 },160 }},162 },163 ],161 ],162 },164 },163 },165 };164 };166165167 const id = {166 const id = {168 ForeignAsset: 0,167 ForeignAsset: 0,169 };168 };170169171 const amount = 5000000000;170 const amount = TRANSFER_AMOUNT;172 const destWeight = 50000000;171 const destWeight = 50000000;173172174 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);173 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);