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

difftreelog

Merge branch 'develop' into doc/scheduler

Yaroslav Bolyukin2022-07-21parents: #4c545c7 #ae91eae.patch.diff
in: master

51 files changed

modifiedCargo.lockdiffbeforeafterboth
57315731
5732[[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",
63206320
6321[[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",
1273312733
12734[[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",
addedpallets/common/CHANGELOG.MDdiffbeforeafterboth

no changes

modifiedpallets/common/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
1//! Module with interfaces for dispatching collections.
2
1use 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 pallets
21}23}
2224
23/// 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 result
65}70}
6671
72/// 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;
82
83 /// 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;
7388
89 /// 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;
93
94 /// Get the collection handle for the corresponding implementation.
75 fn into_inner(self) -> CollectionHandle<T>;95 fn into_inner(self) -> CollectionHandle<T>;
7696
97 /// Get the implementation of [`CommonCollectionOperations`].
77 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;98 fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;
78}99}
79100
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! This module contains the implementation of pallet methods for evm.
1618
17use evm_coder::{19use evm_coder::{
18 solidity_interface, solidity, ToLog,20 solidity_interface, solidity, ToLog,
2931
30use crate::{Pallet, CollectionHandle, Config, CollectionProperties};32use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
3133
34/// 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,
42
43 /// Collection ID.
37 #[indexed]44 #[indexed]
38 collection_id: address,45 collection_id: address,
39 },46 },
40}47}
4148
42/// Does not always represent a full collection, for RFT it is either49/// Does not always represent a full collection, for RFT it is either
43/// 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];
4653
54 /// 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}
4957
58/// @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>
52where61where
53 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 }
7083
84 /// 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 }
7995
96 /// 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 }
91112
113 /// 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)?;
94120
98 save(self)124 save(self)
99 }125 }
100126
127 /// 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 !self
109 save(self)138 save(self)
110 }139 }
111140
141 /// 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 }
147186
187 /// 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 }
174220
221 /// 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 }
178225
226 /// 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 }
188241
242 /// 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 }
203257
258 /// 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 }
210266
267 /// 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 }
217276
277 /// 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 }
237299
300 /// 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 }
282348
349 /// Set the collection access method.
350 /// @param mode Access mode
351 /// 0 for Normal
352 /// 1 for AllowList
283 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 }
302372
373 /// 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 }
309382
383 /// 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 }
316392
393 /// 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}
353432
433/// 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()
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! The module contains a number of functions for converting and checking ethereum identifiers.
1618
17use 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];
2527
28/// 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}
37
38/// 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(&ETH_COLLECTION_PREFIX);41 out[0..16].copy_from_slice(&ETH_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}
4045
46/// 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_PREFIX
43}49}
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17//! # Common pallet
18//!
19//! The Common pallet provides functionality for handling collections.
20//!
21//! ## Overview
22//!
23//! The Common pallet provides an interface for common collection operations for different collection types
24//! (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//! ### Terminology
38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will
39//! 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 various
44//! metadata can be placed.
45//!
46//! **Permissions on token properties** - For each property in the token can be set permission
47//! to change, see [`PropertyPermission`].
48//!
49//! **Collection administrator** - For a collection, you can set administrators who have the right
50//! to most actions on the collection.
51
52#![warn(missing_docs)]
17#![cfg_attr(not(feature = "std"), no_std)]53#![cfg_attr(not(feature = "std"), no_std)]
18
19extern crate alloc;54extern crate alloc;
2055
21use core::ops::{Deref, DerefMut};56use core::ops::{Deref, DerefMut};
90pub mod eth;125pub mod eth;
91pub mod weights;126pub mod weights;
92127
128/// Weight info.
93pub type SelfWeightOf<T> = <T as Config>::WeightInfo;129pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
94130
131/// 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 id
97 pub id: CollectionId,140 pub id: CollectionId,
98 collection: Collection<T::AccountId>,141 collection: Collection<T::AccountId>,
142 /// Substrate recorder for counting consumed gas
99 pub recorder: SubstrateRecorder<T>,143 pub recorder: SubstrateRecorder<T>,
100}144}
145
101impl<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.recorder
106 self.recorder151 self.recorder
107 }152 }
108}153}
154
109impl<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 }
117164
165 /// 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 }
125173
174 /// 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 }
129179
180 /// 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 }
133184
185 /// 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.recorder
136 .consume_gas(T::GasWeightMapping::weight_to_gas(188 .consume_gas(T::GasWeightMapping::weight_to_gas(
140 ))192 ))
141 }193 }
142194
195 /// 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.recorder
145 .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 }
204
205 /// 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 }
155210
211 /// 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 }
160220
221 /// Confirm sponsorship
222 ///
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 }
169233
170 /// 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 }
179243
180 /// 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}
204268
205impl<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 }
275
276 /// 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 }
280
281 /// 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 }
286
287 /// 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 }
291
292 /// 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 }
296
297 /// 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 + TypeInfo
250 + account::Config325 + account::Config
251 {326 {
327 /// Weight information for functions of this pallet.
252 type WeightInfo: WeightInfo;328 type WeightInfo: WeightInfo;
329
330 /// 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>>;
254332
333 /// Handler of accounts and payment.
255 type Currency: Currency<Self::AccountId>;334 type Currency: Currency<Self::AccountId>;
256335
336 /// 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 >;
341
342 /// Dispatcher of operations on collections.
261 type CollectionDispatch: CollectionDispatch<Self>;343 type CollectionDispatch: CollectionDispatch<Self>;
262344
345 /// Account which holds the chain's treasury.
263 type TreasuryAccountId: Get<Self::AccountId>;346 type TreasuryAccountId: Get<Self::AccountId>;
347
348 /// Address under which the CollectionHelper contract would be available.
264 type ContractAddress: Get<H160>;349 type ContractAddress: Get<H160>;
265350
351 /// Mapper for token addresses to Ethereum addresses.
266 type EvmTokenAddressMapping: TokenAddressMapping<H160>;352 type EvmTokenAddressMapping: TokenAddressMapping<H160>;
353
354 /// Mapper for token addresses to [`CrossAccountId`].
267 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;355 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;
268 }356 }
269357
276364
277 #[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_LIMIT
281 }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 created
288 ///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 ),
297385
298 /// New collection was destroyed386 /// New collection was destroyed
299 ///387 CollectionDestroyed(
300 /// # Arguments388 /// Globally unique identifier of collection.
301 ///
302 /// * collection_id: Globally unique identifier of collection.
303 CollectionDestroyed(CollectionId),389 CollectionId,
390 ),
304391
305 /// 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 item
314 ///399 T::CrossAccountId,
315 /// * amount: Always 1 for NFT400 /// Always 1 for NFT
316 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),401 u128,
402 ),
317403
318 /// 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 ),
330415
331 /// Item was transferred416 /// Item was transferred
332 ///
333 /// * collection_id: Id of collection to which item is belong
334 ///
335 /// * item_id: Id of an item
336 ///
337 /// * sender: Original owner of item
338 ///
339 /// * recipient: New owner of item
340 ///
341 /// * amount: Always 1 for NFT
342 Transfer(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 ),
349429
350 /// * collection_id430 /// Amount pieces of token owned by `sender` was approved for `spender`.
351 ///
352 /// * item_id
353 ///
354 /// * sender
355 ///
356 /// * spender
357 ///
358 /// * amount
359 Approved(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 ),
366443
367 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 ),
368451
369 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 ),
370459
371 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 ),
372469
373 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 ),
374479
375 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 }
377488
378 #[pallet::error]489 #[pallet::error]
460 CollectionIsInternal,571 CollectionIsInternal,
461 }572 }
462573
574 /// 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>;
577
578 /// 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>;
468582
469 /// 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 >;
477591
478 /// 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 >;
488602
603 /// 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 >;
497612
613 /// 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 >;
527643
528 /// 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}
620736
621impl<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>>::AddressIsZero
627 );745 );
628 Ok(())746 Ok(())
629 }747 }
748
749 /// 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 }
755
756 /// 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 }
762
763 /// 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 }
767
768 /// 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 }
652778
779 /// 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 }
685812
813 /// 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}
759887
760impl<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 }
860993
994 /// 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 }
8881025
1026 /// 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 }
9061048
1049 /// 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 }
9191066
1067 /// 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 }
9321084
1085 /// 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 }
9451102
1103 /// 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 }
9651127
1128 /// 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 }
9781145
979 // 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 }
9901162
1163 /// 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 }
10201197
1198 /// 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 }
10331215
1216 /// 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 }
10401223
1224 /// 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 }
10511235
1236 /// 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 }
10781263
1264 /// 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 }
11071293
1294 /// 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 }
11261313
1314 /// 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 }
11611349
1350 /// 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 }
12061395
1396 /// 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}
12201410
1411/// 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}
12271418
1228/// 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;
1423
1424 /// Weight of items creation.
1231 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1425 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;
1426
1427 /// Weight of items creation.
1232 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1428 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;
1429
1430 /// The weight of the burning item.
1233 fn burn_item() -> Weight;1431 fn burn_item() -> Weight;
1432
1433 /// 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;
1437
1438 /// 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;
1442
1443 /// 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;
1447
1448 /// 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;
1452
1453 /// Token property permissions set weight.
1454 ///
1455 /// * `amount`- The number of property permissions to set.
1238 fn set_token_property_permissions(amount: u32) -> Weight;1456 fn set_token_property_permissions(amount: u32) -> Weight;
1457
1458 /// Transfer price of the token or its parts.
1239 fn transfer() -> Weight;1459 fn transfer() -> Weight;
1460
1461 /// The price of setting the permission of the operation from another user.
1240 fn approve() -> Weight;1462 fn approve() -> Weight;
1463
1464 /// Transfer price from another user.
1241 fn transfer_from() -> Weight;1465 fn transfer_from() -> Weight;
1466
1467 /// The price of burning a token from another user.
1242 fn burn_from() -> Weight;1468 fn burn_from() -> Weight;
12431469
1244 /// Differs from burn_item in case of Fungible and Refungible, as it should burn1470 /// Differs from burn_item in case of Fungible and Refungible, as it should burn
1245 /// whole users's balance1471 /// whole users's balance.
1246 ///1472 ///
1247 /// This method shouldn't be used directly, as it doesn't count breadth price, use `burn_recursively` instead1473 /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
1248 fn burn_recursively_self_raw() -> Weight;1474 fn burn_recursively_self_raw() -> Weight;
1475
1249 /// Cost of iterating over `amount` children while burning, without counting child burning itself1476 /// Cost of iterating over `amount` children while burning, without counting child burning itself.
1250 ///1477 ///
1251 /// This method shouldn't be used directly, as it doesn't count depth price, use `burn_recursively` instead1478 /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead
1252 fn burn_recursively_breadth_raw(amount: u32) -> Weight;1479 fn burn_recursively_breadth_raw(amount: u32) -> Weight;
12531480
1481 /// The price of recursive burning a token.
1482 ///
1483 /// `max_selfs` - 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}
12601491
1492/// 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}
12641497
1498/// Common collection operations.
1499///
1500/// It wraps methods in Fungible, Nonfungible and Refungible pallets
1501/// 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;
1516
1517 /// 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;
1530
1531 /// 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;
1543
1544 /// 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;
1555
1556 /// 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;
1569
1570 /// 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;
1579
1580 /// 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;
1589
1590 /// Set token properties.
1591 ///
1592 /// The appropriate [`PropertyPermission`] for the token property
1593 /// 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;
1606
1607 /// Remove token properties.
1608 ///
1609 /// The appropriate [`PropertyPermission`] for the token property
1610 /// 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;
1623
1624 /// 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;
1635
1636 /// 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;
1651
1652 /// 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;
1665
1666 /// 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;
1685
1686 /// 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;
13601703
1704 /// 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;
13681717
1718 /// 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));
13701723
1724 /// 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));
13721729
1730 /// 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>;
1734
1735 /// Get all the tokens in the collection.
1374 fn collection_tokens(&self) -> Vec<TokenId>;1736 fn collection_tokens(&self) -> Vec<TokenId>;
1737
1738 /// 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;
1742
1743 /// Get the id of the last minted token.
1376 fn last_token_id(&self) -> TokenId;1744 fn last_token_id(&self) -> TokenId;
13771745
1746 /// 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>;
1750
1751 /// 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>;
1756
1380 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>;
1763
1381 /// Amount of unique collection tokens1764 /// Amount of unique collection tokens
1382 fn total_supply(&self) -> u32;1765 fn total_supply(&self) -> u32;
1766
1383 /// 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;
1771
1385 /// 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;
1774
1387 /// Amount of token pieces1775 /// Amount of token pieces
1388 fn total_pieces(&self, token: TokenId) -> Option<u128>;1776 fn total_pieces(&self, token: TokenId) -> Option<u128>;
1777
1778 /// 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;
1789
1790 /// 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}
13971793
1794/// Extension for RFT collection.
1398pub trait RefungibleExtensions<T>1795pub trait RefungibleExtensions<T>
1399where1796where
1400 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}
14091813
1410// 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),
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
105 }105 }
106}106}
107107
108/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
109/// 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,
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! ERC-20 standart support implementation.
1618
17use core::char::{REPLACEMENT_CHARACTER, decode_utf16};19use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
18use core::convert::TryInto;20use core::convert::TryInto;
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! # Fungible Pallet
18//!
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 tokens
31//!
32//! Fungible tokens or assets are divisible and non-unique. For instance,
33//! fiat currencies like the dollar are fungible: A $1 bill
34//! 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’s
37//! 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 equal
40//! 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 token
42//! that can be replaced by another identical coin or token, and they are
43//! both mutually interchangeable. A popular implementation of fungible tokens is
44//! the ERC-20 token standard.
45//!
46//! ### ERC-20
47//!
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 another
54//! * get the current token balance of an account
55//! * get the total supply of the token available on the network
56//! * approve whether an amount of token from an account can be spent by a third-party account
57//!
58//! ## Overview
59//!
60//! The module provides functionality for asset management of fungible asset, supports ERC-20 standart, includes:
61//!
62//! * Asset Issuance
63//! * Asset Transferal
64//! * Asset Destruction
65//! * Delegated Asset Transfers
66//!
67//! **NOTE:** The created fungible asset always has `token_id` = 0.
68//! So `tokenA` and `tokenB` will have different `collection_id`.
69//!
70//! ### Implementations
71//!
72//! The Fungible pallet provides implementations for the following traits.
73//!
74//! - [`WithRecorder`](pallet_evm_coder_substrate::WithRecorder): Trait for EVM support
75//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing with collections
76//! - [`CommonWeightInfo`](pallet_common::CommonWeightInfo): Functions for retrieval of transaction weight
77//! - [`CommonEvmHandler`](pallet_common::erc::CommonEvmHandler): Function for handling EVM runtime calls
1678
17#![cfg_attr(not(feature = "std"), no_std)]79#![cfg_attr(not(feature = "std"), no_std)]
1880
57 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 }
69132
78 #[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>(_);
80143
144 /// 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>;
84148
149 /// 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 >;
94159
160 /// 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}
172
173/// 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`].
106175
107pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);176pub struct FungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);
177
178/// 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 }
184
185 /// 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.0
114 }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.0
117 }192 }
132 }207 }
133}208}
134209
210/// Pallet implementation for fungible assets
135impl<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 }
219
220 /// 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 }
161240
241 ///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) != 0
164 }244 }
165245
246 /// Burns the specified amount of the token. If the token balance
247 /// 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 }
209292
293 /// Transfers the specified amount of tokens. Will check that
294 /// 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 token
210 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 }
279369
370 /// 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 }
380472
473 /// Set allowance for the spender to `transfer` or `burn` owner's tokens.
474 ///
475 /// - `collection`: Collection that contains the token
476 /// - `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 }
404502
503 /// 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 }
548
549 /// 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.
443553
444 pub fn transfer_from(554 pub fn transfer_from(
445 collection: &FungibleHandle<T>,555 collection: &FungibleHandle<T>,
460 Ok(())570 Ok(())
461 }571 }
462572
573 /// 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` should
576 /// 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 }
480595
481 /// 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 configured
599 /// to allow public minting.
600 ///
601 /// - `data`: Contains user who will become the owners of the tokens and amount
602 /// 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,
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
43 }43 }
44}44}
45
46// Selector: 7d9262e6
47contract 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) 2f073f66
54 function setCollectionProperty(string memory key, bytes memory value)
55 public
56 {
57 require(false, stub_error);
58 key;
59 value;
60 dummy = 0;
61 }
62
63 // Delete collection property.
64 //
65 // @param key Property key.
66 //
67 // Selector: deleteCollectionProperty(string) 7b7debce
68 function deleteCollectionProperty(string memory key) public {
69 require(false, stub_error);
70 key;
71 dummy = 0;
72 }
73
74 // 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) cf24fd6d
82 function collectionProperty(string memory key)
83 public
84 view
85 returns (bytes memory)
86 {
87 require(false, stub_error);
88 key;
89 dummy;
90 return hex"";
91 }
92
93 // 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) 7623402e
100 function setCollectionSponsor(address sponsor) public {
101 require(false, stub_error);
102 sponsor;
103 dummy = 0;
104 }
105
106 // Collection sponsorship confirmation.
107 //
108 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
109 //
110 // Selector: confirmCollectionSponsorship() 3c50e97a
111 function confirmCollectionSponsorship() public {
112 require(false, stub_error);
113 dummy = 0;
114 }
115
116 // 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) 6a3841db
128 function setCollectionLimit(string memory limit, uint32 value) public {
129 require(false, stub_error);
130 limit;
131 value;
132 dummy = 0;
133 }
134
135 // 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) 993b7fba
144 function setCollectionLimit(string memory limit, bool value) public {
145 require(false, stub_error);
146 limit;
147 value;
148 dummy = 0;
149 }
150
151 // Get contract address.
152 //
153 // Selector: contractAddress() f6b4dfb4
154 function contractAddress() public view returns (address) {
155 require(false, stub_error);
156 dummy;
157 return 0x0000000000000000000000000000000000000000;
158 }
159
160 // Add collection admin by substrate address.
161 // @param new_admin Substrate administrator address.
162 //
163 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
164 function addCollectionAdminSubstrate(uint256 newAdmin) public {
165 require(false, stub_error);
166 newAdmin;
167 dummy = 0;
168 }
169
170 // Remove collection admin by substrate address.
171 // @param admin Substrate administrator address.
172 //
173 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
174 function removeCollectionAdminSubstrate(uint256 admin) public {
175 require(false, stub_error);
176 admin;
177 dummy = 0;
178 }
179
180 // Add collection admin.
181 // @param new_admin Address of the added administrator.
182 //
183 // Selector: addCollectionAdmin(address) 92e462c7
184 function addCollectionAdmin(address newAdmin) public {
185 require(false, stub_error);
186 newAdmin;
187 dummy = 0;
188 }
189
190 // Remove collection admin.
191 //
192 // @param new_admin Address of the removed administrator.
193 //
194 // Selector: removeCollectionAdmin(address) fafd7b42
195 function removeCollectionAdmin(address admin) public {
196 require(false, stub_error);
197 admin;
198 dummy = 0;
199 }
200
201 // Toggle accessibility of collection nesting.
202 //
203 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
204 //
205 // Selector: setCollectionNesting(bool) 112d4586
206 function setCollectionNesting(bool enable) public {
207 require(false, stub_error);
208 enable;
209 dummy = 0;
210 }
211
212 // 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[]) 64872396
218 function setCollectionNesting(bool enable, address[] memory collections)
219 public
220 {
221 require(false, stub_error);
222 enable;
223 collections;
224 dummy = 0;
225 }
226
227 // Set the collection access method.
228 // @param mode Access mode
229 // 0 for Normal
230 // 1 for AllowList
231 //
232 // Selector: setCollectionAccess(uint8) 41835d4c
233 function setCollectionAccess(uint8 mode) public {
234 require(false, stub_error);
235 mode;
236 dummy = 0;
237 }
238
239 // Add the user to the allowed list.
240 //
241 // @param user Address of a trusted user.
242 //
243 // Selector: addToCollectionAllowList(address) 67844fe6
244 function addToCollectionAllowList(address user) public {
245 require(false, stub_error);
246 user;
247 dummy = 0;
248 }
249
250 // Remove the user from the allowed list.
251 //
252 // @param user Address of a removed user.
253 //
254 // Selector: removeFromCollectionAllowList(address) 85c51acb
255 function removeFromCollectionAllowList(address user) public {
256 require(false, stub_error);
257 user;
258 dummy = 0;
259 }
260
261 // Switch permission for minting.
262 //
263 // @param mode Enable if "true".
264 //
265 // Selector: setCollectionMintMode(bool) 00018e84
266 function setCollectionMintMode(bool mode) public {
267 require(false, stub_error);
268 mode;
269 dummy = 0;
270 }
271}
45272
46// Selector: 942e8b22273// Selector: 942e8b22
47contract ERC20 is Dummy, ERC165, ERC20Events {274contract ERC20 is Dummy, ERC165, ERC20Events {
127 }354 }
128}355}
129
130// Selector: c894dc35
131contract Collection is Dummy, ERC165 {
132 // Selector: setCollectionProperty(string,bytes) 2f073f66
133 function setCollectionProperty(string memory key, bytes memory value)
134 public
135 {
136 require(false, stub_error);
137 key;
138 value;
139 dummy = 0;
140 }
141
142 // Selector: deleteCollectionProperty(string) 7b7debce
143 function deleteCollectionProperty(string memory key) public {
144 require(false, stub_error);
145 key;
146 dummy = 0;
147 }
148
149 // Throws error if key not found
150 //
151 // Selector: collectionProperty(string) cf24fd6d
152 function collectionProperty(string memory key)
153 public
154 view
155 returns (bytes memory)
156 {
157 require(false, stub_error);
158 key;
159 dummy;
160 return hex"";
161 }
162
163 // Selector: ethSetSponsor(address) 8f9af356
164 function ethSetSponsor(address sponsor) public {
165 require(false, stub_error);
166 sponsor;
167 dummy = 0;
168 }
169
170 // Selector: ethConfirmSponsorship() a8580d1a
171 function ethConfirmSponsorship() public {
172 require(false, stub_error);
173 dummy = 0;
174 }
175
176 // Selector: setLimit(string,uint32) 68db30ca
177 function setLimit(string memory limit, uint32 value) public {
178 require(false, stub_error);
179 limit;
180 value;
181 dummy = 0;
182 }
183
184 // Selector: setLimit(string,bool) ea67e4c2
185 function setLimit(string memory limit, bool value) public {
186 require(false, stub_error);
187 limit;
188 value;
189 dummy = 0;
190 }
191
192 // Selector: contractAddress() f6b4dfb4
193 function contractAddress() public view returns (address) {
194 require(false, stub_error);
195 dummy;
196 return 0x0000000000000000000000000000000000000000;
197 }
198}
199356
200contract UniqueFungible is357contract UniqueFungible is
201 Dummy,358 Dummy,
modifiedpallets/inflation/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! # Inflation
18//!
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//! ## Interface
24//!
25//! ### Dispatchable Functions
26//!
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 Treasury
29//! account if it does not exist and perform the first inflation deposit.
1630
17// #![recursion_limit = "1024"]31// #![recursion_limit = "1024"]
18#![cfg_attr(not(feature = "std"), no_std)]32#![cfg_attr(not(feature = "std"), no_std)]
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
183 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)?}
187187
188 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}
212212
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
133 }133 }
134}134}
135135
136/// Implementation of `CommonCollectionOperations` for `NonfungibleHandle`. It wraps Nonfungible Pallete
137/// 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,
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! # Nonfungible Pallet EVM API
18//!
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.
1621
17extern crate alloc;22extern crate alloc;
18use core::{23use core::{
40 SelfWeightOf, weights::WeightInfo, TokenProperties,45 SelfWeightOf, weights::WeightInfo, TokenProperties,
41};46};
4247
48/// @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 }
7082
83 /// @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 }
98115
116 /// @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 }
113134
135 /// @notice Get token property value.
114 /// Throws error if key not found136 /// @dev Throws error if key not found
137 /// @param tokenId ID of the token.
138 /// @param key Property key.
139 /// @return Property value bytes
115 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)
127152
128#[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 destroyed
157 /// (`to` == 0). Exception: during contract creation, any number of NFTs
158 /// may be created and assigned without emitting Transfer. At the time of
159 /// 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 or
169 /// reaffirmed. The zero address indicates there is no approved address.
170 /// When a Transfer event emits, this also indicates that the approved
171 /// 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}
161197
198/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
199/// @dev See https://eips.ethereum.org/EIPS/eip-721
162#[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 contract
164 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 }
169208
209 /// @notice An abbreviated name for NFTs in this contract
170 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 }
173213
214 /// @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 RFC
216 /// 3986. The URI may point to a JSON file that conforms to the "ERC721
217 /// Metadata JSON Schema".
174 /// Returns token's const_metadata218 /// @return token's const_metadata
175 #[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}
194238
239/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
240/// @dev See https://eips.ethereum.org/EIPS/eip-721
195#[solidity_interface(name = "ERC721Enumerable")]241#[solidity_interface(name = "ERC721Enumerable")]
196impl<T: Config> NonfungibleHandle<T> {242impl<T: Config> NonfungibleHandle<T> {
243 /// @notice Enumerate valid NFTs
244 /// @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 }
200250
201 /// Not implemented251 /// @dev Not implemented
202 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 implemetable
204 Err("not implemented".into())254 Err("not implemented".into())
205 }255 }
206256
257 /// @notice Count NFTs tracked by this contract
258 /// @return A count of valid NFTs tracked by this contract, where each one of
259 /// them has an assigned and queryable owner not equal to the zero address
207 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}
212265
266/// @title ERC-721 Non-Fungible Token Standard
267/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
213#[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 owner
271 /// @dev NFTs assigned to the zero address are considered invalid, and this
272 /// function throws for queries about the zero address.
273 /// @param owner An address for whom to query the balance
274 /// @return The number of NFTs owned by `owner`, possibly zero
215 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 NFT
282 /// @dev NFTs assigned to zero address are considered invalid, and queries
283 /// about them do throw.
284 /// @param tokenId The identifier for an NFT
285 /// @return The address of the owner of the NFT
221 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 .owner
227 .as_eth())292 .as_eth())
228 }293 }
229 /// Not implemented294 /// @dev Not implemented
230 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 implemetable
239 Err("not implemented".into())304 Err("not implemented".into())
240 }305 }
241 /// Not implemented306 /// @dev Not implemented
242 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 }
252317
318 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
319 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
320 /// THEY MAY BE PERMANENTLY LOST
321 /// @dev Throws unless `msg.sender` is the current owner or an authorized
322 /// operator for this NFT. Throws if `from` is not the current owner. Throws
323 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
324 /// @param from The current owner of the NFT
325 /// @param to The new owner
326 /// @param tokenId The NFT to transfer
327 /// @param _value Not used for an NFT
253 #[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 }
274349
350 /// @notice Set or reaffirm the approved address for an NFT
351 /// @dev The zero address indicates there is no approved address.
352 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
353 /// operator of the current owner.
354 /// @param approved The new approved NFT controller
355 /// @param tokenId The NFT to approve
275 #[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 }
291372
292 /// Not implemented373 /// @dev Not implemented
293 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 }
302383
303 /// Not implemented384 /// @dev Not implemented
304 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 implemetable
306 Err("not implemented".into())387 Err("not implemented".into())
307 }388 }
308389
309 /// Not implemented390 /// @dev Not implemented
310 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 implemetable
312 Err("not implemented".into())393 Err("not implemented".into())
313 }394 }
314}395}
315396
397/// @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 authorized
402 /// operator of the current owner.
403 /// @param tokenId The NFT to approve
318 #[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}
327413
414/// @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 }
333420
421 /// @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 manually
424 /// @param to The new owner
425 /// @param tokenId ID of the minted NFT
336 #[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 }
366456
457 /// @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 manually
460 /// @param to The new owner
461 /// @param tokenId ID of the minted NFT
462 /// @param tokenUri Token URI that would be stored in the NFT properties
369 #[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 }
422516
423 /// Not implemented517 /// @dev Not implemented
424 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 false
450}544}
451545
546/// @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 NFT
550 /// @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 owner
553 /// @param tokenId The NFT to transfer
554 /// @param _value Not used for an NFT
454 #[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 }
472573
574 /// @notice Burns a specific ERC721 token.
575 /// @dev Throws unless `msg.sender` is the current owner or an authorized
576 /// operator for this NFT. Throws if `from` is not the current owner. Throws
577 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
578 /// @param from The current owner of the NFT
579 /// @param tokenId The NFT to transfer
580 /// @param _value Not used for an NFT
473 #[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 }
492600
601 /// @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 }
500609
610 /// @notice Function to mint multiple tokens.
611 /// @dev `tokenIds` should be an array of consecutive numbers and first number
612 /// should be obtained with `nextTokenId` method
613 /// @param to The new owner
614 /// @param tokenIds IDs of the minted NFTs
501 #[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 }
531645
646 /// @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 consecutive
648 /// numbers and first number should be obtained with `nextTokenId` method
649 /// @param to The new owner
650 /// @param tokens array of pairs of token ID and token URI for minted tokens
532 #[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(
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! # Nonfungible Pallet
18//!
19//! The Nonfungible pallet provides functionality for handling nonfungible collections and tokens.
20//!
21//! - [`Config`]
22//! - [`NonfungibleHandle`]
23//! - [`Pallet`]
24//! - [`CommonWeights`]
25//!
26//! ## Overview
27//!
28//! The Nonfungible pallet provides functions for:
29//!
30//! - NFT collection creation and removal
31//! - Minting and burning of NFT tokens
32//! - Retrieving account balances
33//! - Transfering NFT tokens
34//! - Setting and checking allowance for NFT tokens
35//! - Setting properties and permissions for NFT collections and tokens
36//! - Nesting and unnesting tokens
37//!
38//! ### Terminology
39//!
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 account
46//!
47//! - **Allowance:** NFT tokens owned by one account that another account is allowed to make operations on
48//!
49//! - **Burning:** The process of “deleting” a token from a collection and from
50//! an account balance of the owner.
51//!
52//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting
53//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in
54//! 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 are
57//! attached to a collection. Set of permissions could be defined for each property.
58//!
59//! ### Implementations
60//!
61//! The Nonfungible pallet provides implementations for the following traits. If these traits provide
62//! 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 weight
65//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing
66//! with collections
67//!
68//! ## Interface
69//!
70//! ### Dispatchable Functions
71//!
72//! - `init_collection` - Create NFT collection. NFT collection can be configured to allow or deny access for
73//! 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//! ## Assumptions
88//!
89//! * To perform operations on tokens sender should be in collection's allow list if collection access mode is `AllowList`.
1690
17#![cfg_attr(not(feature = "std"), no_std)]91#![cfg_attr(not(feature = "std"), no_std)]
1892
102 #[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>(_);
104178
179 /// 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>;
183
184 /// 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>;
111188
189 /// 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 >;
118196
197 /// 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 >;
127206
207 /// 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 >;
140221
141 /// 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 >;
152233
153 /// 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 >;
165246
247 /// 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 >;
175257
258 /// 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}
274357
275impl<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 }
363
364 /// 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 }
282370
371 /// 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 }
296387
388 /// 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 }
310402
403 /// 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 }
320415
416 /// 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 }
329425
426 /// 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 }
337436
437 /// Get ID of the last minted token
338 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}
342442
343// unchecked calls skips any permission checks443// unchecked calls skips any permission checks
344impl<T: Config> Pallet<T> {444impl<T: Config> Pallet<T> {
445 /// Create NFT collection
446 ///
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 }
457
458 /// Destroy NFT collection
459 ///
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 }
375485
486 /// Burn NFT token
487 ///
488 /// `burn` removes `token` from the `collection`, from it's owner and from the parent token
489 /// 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 burned
494 /// - `collection`: Collection that contains the token
376 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 }
444563
564 /// Same as [`burn`] but burns all the tokens that are nested in the token first
565 ///
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.burn
445 #[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 }
483608
609 /// Batch operation to add, edit or remove properties for the token
610 ///
611 /// All affected properties should have mutable permission and sender should have
612 /// 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 }
576709
710 /// Batch operation to add or edit properties for the token
711 ///
712 /// Same as [`modify_token_properties`] but doesn't allow to remove properties
713 ///
714 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
577 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 }
594732
733 /// Add or edit single property for the token
734 ///
735 /// Calls [`set_token_properties`] internally
736 ///
737 /// [`set_token_properties`]: struct.Pallet.html#method.set_token_properties
595 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 }
613756
757 /// Batch operation to remove properties from the token
758 ///
759 /// Same as [`modify_token_properties`] but doesn't allow to add or edit properties
760 ///
761 /// [`modify_token_properties`]: struct.Pallet.html#method.modify_token_properties
614 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 }
632780
781 /// Remove single property from the token
782 ///
783 /// Calls [`delete_token_properties`] internally
784 ///
785 /// [`delete_token_properties`]: struct.Pallet.html#method.delete_token_properties
633 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 }
648801
802 /// Add or edit properties for the collection
649 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 }
656810
811 /// Remove properties from the collection
657 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 }
664819
820 /// 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 }
672830
831 /// 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 }
680841
842 /// 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 depth
681 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 }
771941
942 /// Batch operation to mint multiple NFT tokens.
943 ///
944 /// The sender should be the owner/admin of the collection or collection should be configured
945 /// to allow public minting.
946 /// Throws if amount of tokens reached it's limit for the collection or if caller reached
947 /// token ownership limit.
948 ///
949 /// - `data`: Contains list of token properties and users who will become the owners of the
950 /// corresponging tokens.
951 /// - `nesting_budget`: Limit for token nesting depth
772 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 }
9551135
1136 /// 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 }
9871170
1171 /// 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 }
10291213
1214 /// 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.transfer
1030 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 }
10451235
1236 /// 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 should
1239 /// set allowance for the spender to burn token.
1240 ///
1241 /// [`burn`]: struct.Pallet.html#method.burn
1046 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 }
10591255
1256 /// 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 }
11281326
1327 /// 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_items
1130 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,
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
5353
54// Selector: 4136937754// Selector: 41369377
55contract 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) 222d97fa
57 function setTokenPropertyPermission(64 function setTokenPropertyPermission(
58 string memory key,65 string memory key,
68 dummy = 0;75 dummy = 0;
69 }76 }
7077
78 // @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) 1752d67b
72 function setProperty(85 function setProperty(
73 uint256 tokenId,86 uint256 tokenId,
81 dummy = 0;94 dummy = 0;
82 }95 }
8396
97 // @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) 066111d1
85 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 }
91109
110 // @notice Get token property value.
92 // Throws error if key not found111 // @dev Throws error if key not found
112 // @param tokenId ID of the token.
113 // @param key Property key.
114 // @return Property value bytes
93 //115 //
94 // Selector: property(uint256,string) 7228c327116 // Selector: property(uint256,string) 7228c327
95 function property(uint256 tokenId, string memory key)117 function property(uint256 tokenId, string memory key)
107129
108// Selector: 42966c68130// Selector: 42966c68
109contract 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 authorized
134 // operator of the current owner.
135 // @param tokenId The NFT to approve
136 //
110 // Selector: burn(uint256) 42966c68137 // Selector: burn(uint256) 42966c68
111 function burn(uint256 tokenId) public {138 function burn(uint256 tokenId) public {
112 require(false, stub_error);139 require(false, stub_error);
117144
118// Selector: 58800161145// Selector: 58800161
119contract ERC721 is Dummy, ERC165, ERC721Events {146contract ERC721 is Dummy, ERC165, ERC721Events {
147 // @notice Count all NFTs assigned to an owner
148 // @dev NFTs assigned to the zero address are considered invalid, and this
149 // function throws for queries about the zero address.
150 // @param owner An address for whom to query the balance
151 // @return The number of NFTs owned by `owner`, possibly zero
152 //
120 // Selector: balanceOf(address) 70a08231153 // Selector: balanceOf(address) 70a08231
121 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 }
127160
161 // @notice Find the owner of an NFT
162 // @dev NFTs assigned to zero address are considered invalid, and queries
163 // about them do throw.
164 // @param tokenId The identifier for an NFT
165 // @return The address of the owner of the NFT
166 //
128 // Selector: ownerOf(uint256) 6352211e167 // Selector: ownerOf(uint256) 6352211e
129 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 }
135174
136 // Not implemented175 // @dev Not implemented
137 //176 //
138 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672177 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
139 function safeTransferFromWithData(178 function safeTransferFromWithData(
150 dummy = 0;189 dummy = 0;
151 }190 }
152191
153 // Not implemented192 // @dev Not implemented
154 //193 //
155 // Selector: safeTransferFrom(address,address,uint256) 42842e0e194 // Selector: safeTransferFrom(address,address,uint256) 42842e0e
156 function safeTransferFrom(195 function safeTransferFrom(
165 dummy = 0;204 dummy = 0;
166 }205 }
167206
207 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
208 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
209 // THEY MAY BE PERMANENTLY LOST
210 // @dev Throws unless `msg.sender` is the current owner or an authorized
211 // operator for this NFT. Throws if `from` is not the current owner. Throws
212 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
213 // @param from The current owner of the NFT
214 // @param to The new owner
215 // @param tokenId The NFT to transfer
216 // @param _value Not used for an NFT
217 //
168 // Selector: transferFrom(address,address,uint256) 23b872dd218 // Selector: transferFrom(address,address,uint256) 23b872dd
169 function transferFrom(219 function transferFrom(
170 address from,220 address from,
178 dummy = 0;228 dummy = 0;
179 }229 }
180230
231 // @notice Set or reaffirm the approved address for an NFT
232 // @dev The zero address indicates there is no approved address.
233 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
234 // operator of the current owner.
235 // @param approved The new approved NFT controller
236 // @param tokenId The NFT to approve
237 //
181 // Selector: approve(address,uint256) 095ea7b3238 // Selector: approve(address,uint256) 095ea7b3
182 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 }
188245
189 // Not implemented246 // @dev Not implemented
190 //247 //
191 // Selector: setApprovalForAll(address,bool) a22cb465248 // Selector: setApprovalForAll(address,bool) a22cb465
192 function setApprovalForAll(address operator, bool approved) public {249 function setApprovalForAll(address operator, bool approved) public {
196 dummy = 0;253 dummy = 0;
197 }254 }
198255
199 // Not implemented256 // @dev Not implemented
200 //257 //
201 // Selector: getApproved(uint256) 081812fc258 // Selector: getApproved(uint256) 081812fc
202 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 }
208265
209 // Not implemented266 // @dev Not implemented
210 //267 //
211 // Selector: isApprovedForAll(address,address) e985e9c5268 // Selector: isApprovedForAll(address,address) e985e9c5
212 function isApprovedForAll(address owner, address operator)269 function isApprovedForAll(address owner, address operator)
224281
225// Selector: 5b5e139f282// Selector: 5b5e139f
226contract ERC721Metadata is Dummy, ERC165 {283contract ERC721Metadata is Dummy, ERC165 {
284 // @notice A descriptive name for a collection of NFTs in this contract
285 //
227 // Selector: name() 06fdde03286 // Selector: name() 06fdde03
228 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 }
233292
293 // @notice An abbreviated name for NFTs in this contract
294 //
234 // Selector: symbol() 95d89b41295 // Selector: symbol() 95d89b41
235 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 }
240301
302 // @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 RFC
304 // 3986. The URI may point to a JSON file that conforms to the "ERC721
305 // Metadata JSON Schema".
241 // Returns token's const_metadata306 // @return token's const_metadata
242 //307 //
243 // Selector: tokenURI(uint256) c87b56dd308 // Selector: tokenURI(uint256) c87b56dd
244 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 }
260325
326 // @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 manually
329 // @param to The new owner
330 // @param tokenId ID of the minted NFT
263 //331 //
264 // Selector: mint(address,uint256) 40c10f19332 // Selector: mint(address,uint256) 40c10f19
265 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 }
272340
341 // @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 manually
344 // @param to The new owner
345 // @param tokenId ID of the minted NFT
346 // @param tokenUri Token URI that would be stored in the NFT properties
275 //347 //
276 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f348 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
277 function mintWithTokenURI(349 function mintWithTokenURI(
287 return false;359 return false;
288 }360 }
289361
290 // Not implemented362 // @dev Not implemented
291 //363 //
292 // Selector: finishMinting() 7d64bcb4364 // Selector: finishMinting() 7d64bcb4
293 function finishMinting() public returns (bool) {365 function finishMinting() public returns (bool) {
299371
300// Selector: 780e9d63372// Selector: 780e9d63
301contract ERC721Enumerable is Dummy, ERC165 {373contract ERC721Enumerable is Dummy, ERC165 {
374 // @notice Enumerate valid NFTs
375 // @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) 4f6ccce7
303 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 }
309386
310 // Not implemented387 // @dev Not implemented
311 //388 //
312 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59389 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
313 function tokenOfOwnerByIndex(address owner, uint256 index)390 function tokenOfOwnerByIndex(address owner, uint256 index)
322 return 0;399 return 0;
323 }400 }
324401
402 // @notice Count NFTs tracked by this contract
403 // @return A count of valid NFTs tracked by this contract, where each one of
404 // them has an assigned and queryable owner not equal to the zero address
405 //
325 // Selector: totalSupply() 18160ddd406 // Selector: totalSupply() 18160ddd
326 function totalSupply() public view returns (uint256) {407 function totalSupply() public view returns (uint256) {
327 require(false, stub_error);408 require(false, stub_error);
332413
333// Selector: 7d9262e6414// Selector: 7d9262e6
334contract 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) 2f073f66
336 function setCollectionProperty(string memory key, bytes memory value)422 function setCollectionProperty(string memory key, bytes memory value)
337 public423 public
342 dummy = 0;428 dummy = 0;
343 }429 }
344430
431 // Delete collection property.
432 //
433 // @param key Property key.
434 //
345 // Selector: deleteCollectionProperty(string) 7b7debce435 // Selector: deleteCollectionProperty(string) 7b7debce
346 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 }
351441
442 // 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) cf24fd6d
355 function collectionProperty(string memory key)450 function collectionProperty(string memory key)
363 return hex"";458 return hex"";
364 }459 }
365460
461 // 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) 7623402e
367 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 }
372473
474 // 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() 3c50e97a
374 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 }
378483
484 // 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) 6a3841db
380 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 }
386502
503 // 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) 993b7fba
388 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 }
394518
519 // Get contract address.
520 //
395 // Selector: contractAddress() f6b4dfb4521 // Selector: contractAddress() f6b4dfb4
396 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 }
401527
528 // Add collection admin by substrate address.
529 // @param new_admin Substrate administrator address.
530 //
402 // Selector: addCollectionAdminSubstrate(uint256) 5730062b531 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
403 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 }
408537
538 // Remove collection admin by substrate address.
539 // @param admin Substrate administrator address.
540 //
409 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9541 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
410 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 }
415547
548 // Add collection admin.
549 // @param new_admin Address of the added administrator.
550 //
416 // Selector: addCollectionAdmin(address) 92e462c7551 // Selector: addCollectionAdmin(address) 92e462c7
417 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 }
422557
558 // Remove collection admin.
559 //
560 // @param new_admin Address of the removed administrator.
561 //
423 // Selector: removeCollectionAdmin(address) fafd7b42562 // Selector: removeCollectionAdmin(address) fafd7b42
424 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 }
429568
569 // 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) 112d4586
431 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 }
436579
580 // 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[]) 64872396
438 function setCollectionNesting(bool enable, address[] memory collections)586 function setCollectionNesting(bool enable, address[] memory collections)
439 public587 public
444 dummy = 0;592 dummy = 0;
445 }593 }
446594
595 // Set the collection access method.
596 // @param mode Access mode
597 // 0 for Normal
598 // 1 for AllowList
599 //
447 // Selector: setCollectionAccess(uint8) 41835d4c600 // Selector: setCollectionAccess(uint8) 41835d4c
448 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 }
453606
607 // 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) 67844fe6
455 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 }
460617
618 // 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) 85c51acb
462 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 }
467628
629 // Switch permission for minting.
630 //
631 // @param mode Enable if "true".
632 //
468 // Selector: setCollectionMintMode(bool) 00018e84633 // Selector: setCollectionMintMode(bool) 00018e84
469 function setCollectionMintMode(bool mode) public {634 function setCollectionMintMode(bool mode) public {
470 require(false, stub_error);635 require(false, stub_error);
475640
476// Selector: d74d154f641// Selector: d74d154f
477contract ERC721UniqueExtensions is Dummy, ERC165 {642contract ERC721UniqueExtensions is Dummy, ERC165 {
643 // @notice Transfer ownership of an NFT
644 // @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 owner
647 // @param tokenId The NFT to transfer
648 // @param _value Not used for an NFT
649 //
478 // Selector: transfer(address,uint256) a9059cbb650 // Selector: transfer(address,uint256) a9059cbb
479 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 }
485657
658 // @notice Burns a specific ERC721 token.
659 // @dev Throws unless `msg.sender` is the current owner or an authorized
660 // operator for this NFT. Throws if `from` is not the current owner. Throws
661 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
662 // @param from The current owner of the NFT
663 // @param tokenId The NFT to transfer
664 // @param _value Not used for an NFT
665 //
486 // Selector: burnFrom(address,uint256) 79cc6790666 // Selector: burnFrom(address,uint256) 79cc6790
487 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 }
493673
674 // @notice Returns next free NFT ID.
675 //
494 // Selector: nextTokenId() 75794a3c676 // Selector: nextTokenId() 75794a3c
495 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 }
500682
683 // @notice Function to mint multiple tokens.
684 // @dev `tokenIds` should be an array of consecutive numbers and first number
685 // should be obtained with `nextTokenId` method
686 // @param to The new owner
687 // @param tokenIds IDs of the minted NFTs
688 //
501 // Selector: mintBulk(address,uint256[]) 44a9945e689 // Selector: mintBulk(address,uint256[]) 44a9945e
502 function mintBulk(address to, uint256[] memory tokenIds)690 function mintBulk(address to, uint256[] memory tokenIds)
503 public691 public
510 return false;698 return false;
511 }699 }
512700
701 // @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 consecutive
703 // numbers and first number should be obtained with `nextTokenId` method
704 // @param to The new owner
705 // @param tokens array of pairs of token ID and token URI for minted tokens
706 //
513 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006707 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
514 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)708 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
515 public709 public
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
3//! Autogenerated weights for pallet_nonfungible3//! Autogenerated weights for pallet_nonfungible
4//!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-dev
6//! 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: 1024
88
9// 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_000
70 .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_000
82 .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_000
123 .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_000
170 .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_000
180 .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_000
190 .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_000
214 .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_000
226 .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_000
267 .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_000
314 .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_000
324 .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_000
334 .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}
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
1[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"
66
addedpallets/refungible/Changelog.mddiffbeforeafterboth

no changes

modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
18use crate::{Pallet, Config, RefungibleHandle};18use crate::{Pallet, Config, RefungibleHandle};
1919
20use 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)?}
210
211 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)?}
226
227 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)?}
248
249 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)?}
206272
207 repartition_item {273 repartition_item {
208 bench_init!{274 bench_init!{
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
20use 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}
46
47fn 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 0
52 }
53}
4354
44pub 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 }
4960
50 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 }
5373
54 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 }
6995
70 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 0
73 }98 }
7499
75 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 0
78 }102 }
79103
80 fn set_token_properties(_amount: u32) -> Weight {104 fn set_token_properties(amount: u32) -> Weight {
81 // Error105 <SelfWeightOf<T>>::set_token_properties(amount)
82 0
83 }106 }
84107
85 fn delete_token_properties(_amount: u32) -> Weight {108 fn delete_token_properties(amount: u32) -> Weight {
86 // Error109 <SelfWeightOf<T>>::delete_token_properties(amount)
87 0
88 }110 }
89111
90 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 0
93 }114 }
94115
95 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}
147169
170/// Implementation of `CommonCollectionOperations` for `RefungibleHandle`. It wraps Refungible Pallete
171/// 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,
295319
296 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);
326
301 fail!(<Error<T>>::SettingPropertiesNotAllowed)327 with_weight(
328 <Pallet<T>>::set_collection_properties(self, &sender, properties),
329 weight,
330 )
302 }331 }
303332
304 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);
339
309 fail!(<Error<T>>::SettingPropertiesNotAllowed)340 with_weight(
341 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),
342 weight,
343 )
310 }344 }
311345
312 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);
354
319 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 }
321367
322 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);
375
327 fail!(<Error<T>>::SettingPropertiesNotAllowed)376 with_weight(
377 <Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),
378 weight,
379 )
328 }380 }
329381
330 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);
390
337 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 }
339402
371 TokenId(<TokensMinted<T>>::get(self.id))434 TokenId(<TokensMinted<T>>::get(self.id))
372 }435 }
373436
374 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 }
377440
378 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {441 fn token_property(&self, _token_id: TokenId, _key: &PropertyKey) -> Option<PropertyValue> {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17//! # Refungible Pallet
18//!
19//! The Refungible pallet provides functionality for handling refungible collections and tokens.
20//!
21//! - [`Config`]
22//! - [`RefungibleHandle`]
23//! - [`Pallet`]
24//! - [`CommonWeights`]
25//!
26//! ## Overview
27//!
28//! The Refungible pallet provides functions for:
29//!
30//! - RFT collection creation and removal
31//! - Minting and burning of RFT tokens
32//! - Partition and repartition of RFT tokens
33//! - Retrieving number of pieces of RFT token
34//! - Retrieving account balances
35//! - Transfering RFT token pieces
36//! - Burning RFT token pieces
37//! - Setting and checking allowance for RFT tokens
38//!
39//! ### Terminology
40//!
41//! - **RFT token:** Non fungible token that was partitioned to pieces. If an account owns all
42//! 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 account
50//!
51//! - **Allowance:** Maximum number of RFT token pieces that one account is allowed to
52//! transfer from the balance of another account
53//!
54//! - **Burning:** The process of “deleting” a token from a collection or removing token pieces from
55//! an account balance.
56//!
57//! ### Implementations
58//!
59//! The Refungible pallet provides implementations for the following traits. If these traits provide
60//! 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 weight
63//! - [`CommonCollectionOperations`](pallet_common::CommonCollectionOperations): Functions for dealing
64//! with collections
65//! - [`RefungibleExtensions`](pallet_common::RefungibleExtensions): Functions specific for refungible
66//! collection
67//!
68//! ## Interface
69//!
70//! ### Dispatchable Functions
71//!
72//! - `init_collection` - Create RFT collection. RFT collection can be configured to allow or deny access for
73//! 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//! ## Assumptions
83//!
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.
87
17#![cfg_attr(not(feature = "std"), no_std)]88#![cfg_attr(not(feature = "std"), no_std)]
1889
19use 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>(_);
88164
165 /// Amount of tokens minted for collection
89 #[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>;
169
170 /// Amount of burnt tokens for collection
92 #[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>;
95174
175 /// Custom data serialized to bytes for token
96 #[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 >;
102182
103 #[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 >;
191
192 /// Total amount of pieces for token
193 #[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 >;
121211
212 /// Amount of tokens owned by account
122 #[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 >;
132223
224 /// Amount of token pieces owned by account
133 #[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 >;
144236
237 /// Allowance set by an owner for a spender for a token
145 #[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}
189282
190impl<T: Config> Pallet<T> {283impl<T: Config> Pallet<T> {
284 /// Get number of RFT tokens in collection
191 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 }
288
289 /// Check that RFT token exists
290 ///
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 }
295
296 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)?;
306
307 Ok(())
308 }
309
310 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)?;
320
321 Ok(())
322 }
197}323}
198324
199// unchecked calls skips any permission checks325// unchecked calls skips any permission checks
200impl<T: Config> Pallet<T> {326impl<T: Config> Pallet<T> {
327 /// Create RFT collection
328 ///
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 }
338
339 /// Destroy RFT collection
340 ///
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 }
237373
238 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)?;
242381
243 <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 event
249 Ok(())389 Ok(())
250 }390 }
251391
392 /// Burn RFT token pieces
393 ///
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 being
397 /// one of the owners of the token. If there is no account that owns any pieces of
398 /// 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 burned
402 /// - `collection`: Collection that contains the token
252 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 }
321472
473 #[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 }
490
491 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(
492 sender.clone(),
493 collection.id,
494 token_id,
495 None,
496 nesting_budget,
497 )?;
498
499 Ok(is_bundle_owner)
500 };
501
502 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);
507
508 let is_property_exists = TokenProperties::<T>::get((collection.id, token_id))
509 .get(&key)
510 .is_some();
511
512 match permission {
513 PropertyPermission { mutable: false, .. } if is_property_exists => {
514 return Err(<CommonError<T>>::NoPermission.into());
515 }
516
517 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_create
526 || (collection_admin && is_collection_admin())
527 || (token_owner && is_token_owner()?))
528 {
529 fail!(<CommonError<T>>::NoPermission);
530 }
531 }
532 }
533
534 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)?;
540
541 <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)?;
552
553 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
554 collection.id,
555 token_id,
556 key,
557 ));
558 }
559 }
560 }
561
562 Ok(())
563 }
564
565 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 }
582
583 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;
591
592 Self::set_token_properties(
593 collection,
594 sender,
595 token_id,
596 [property].into_iter(),
597 is_token_create,
598 nesting_budget,
599 )
600 }
601
602 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;
610
611 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 }
620
621 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 }
636
637 /// 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 transfered
645 /// - `collection`: Collection that contains the token
322 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 }
425749
750 /// 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,
507836
508 // =========837 // =========
509838
839 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]);
843
844 <TokenData<T>>::insert(
845 (collection.id, token_id),
846 ItemData {
847 const_data: data.const_data.clone(),
848 },
849 );
850
851 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 }
863
864 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 })?;
877
510 <TokensMinted<T>>::insert(collection.id, tokens_minted);878 <TokensMinted<T>>::insert(collection.id, tokens_minted);
879
511 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 }
883
514 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]);
517886
518 <TokenData<T>>::insert(
519 (collection.id, token_id),
520 ItemData {
521 const_data: token.const_data,
522 },
523 );
524
525 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 );
536891
537 // TODO: ERC20 transfer event892 // TODO: ERC20 transfer event
538 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(893 <PalletCommon<T>>::deposit_event(CommonEvent::ItemCreated(
568 ))923 ))
569 }924 }
570925
926 /// 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 }
638996
997 /// 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.transfer
639 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 }
6591023
1024 /// 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 should
1027 /// set allowance for the spender to burn pieces
1028 ///
1029 /// [`burn`]: struct.Pallet.html#method.burn
660 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 }
6791049
680 /// 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 configured
1053 /// to allow public minting.
1054 ///
1055 /// - `data`: Contains list of users who will become the owners of the token pieces and amount
1056 /// 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 }
6891065
1066 /// 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 some
1070 /// 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 pieces
702 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>>::RepartitionWhileNotOwningAllPieces
707 );1090 );
7081091
711 Ok(())1094 Ok(())
712 }1095 }
7131096
1097 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 owner
1108 }
1109
714 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 }
1113
1114 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 }
1121
1122 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 }
1129
1130 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}
7181138
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
3//! Autogenerated weights for pallet_refungible3//! Autogenerated weights for pallet_refungible
4//!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-dev
6//! 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: 1024
88
9// 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}
5457
62 // 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_000
78 .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_000
92 .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_000
107 .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_000
225 .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_000
234 .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_000
243 .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_000
247 .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_000
261 .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_000
276 .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_000
422 .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_000
431 .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_000
440 .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 }
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
152152
153pub use preimage_provider::PreimageProviderAndMaybeRecipient;153pub use preimage_provider::PreimageProviderAndMaybeRecipient;
154154
155/// Weight templates for calculating actual fees
156pub(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>>;
261260
262 /// 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>;
264263
265 /// The helper type used for custom transaction fee logic.264 /// The helper type used for custom transaction fee logic.
268267
269 /// 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 payment
272 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 >;
294292
295 /// Cancel schedule reservation and unlock balance
296 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 }
438435
439 // Sender is the account who signed transaction
440 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 paid
502 0498 0
499 //total_weight
503 }500 }
504 }501 }
505502
modifiedpallets/structure/src/benchmarking.rsdiffbeforeafterboth
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
2// This file is part of Unique Network.
3
4// Unique Network is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Unique Network is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
1use super::*;17use super::*;
218
modifiedpallets/structure/src/lib.rsdiffbeforeafterboth
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
2// This file is part of Unique Network.
3
4// Unique Network is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Unique Network is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
16
17//! # Structure Pallet
18//!
19//! The Structure pallet provides functionality for handling tokens nesting an unnesting.
20//!
21//! - [`Config`]
22//! - [`Pallet`]
23//!
24//! ## Overview
25//!
26//! The Structure pallet provides functions for:
27//!
28//! - Searching for token parents, children and owners. Actual implementation of searching for
29//! 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 corresponding
31//! to token's collection type.
32//!
33//! ### Terminology
34//!
35//! - **Nesting:** Setting up parent-child relationship between tokens. Nested tokens are inhereting
36//! owner from their parent. There could be multiple levels of nesting. Token couldn't be nested in
37//! it's child token i.e. parent-child relationship graph shouldn't have
38//!
39//! - **Parent:** Token that current token is nested in.
40//!
41//! - **Owner:** Account that owns the token and all nested tokens.
42//!
43//! ## Interface
44//!
45//! ### Available Functions
46//!
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 token
51//! - `nest_if_sent_to_token` - Nest the token in the other token
52//! - `unnest_if_nested` - Unnest the token from the other token
53
1#![cfg_attr(not(feature = "std"), no_std)]54#![cfg_attr(not(feature = "std"), no_std)]
255
82}135}
83136
84impl<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 found
85 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 }
105164
165 /// Get the chain of parents of a token in the nesting hierarchy
166 ///
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 owner
134 ///198 ///
135 /// May return token address if parent token not yet exists199 /// May return token address if parent token not yet exists
200 ///
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 }
151217
218 /// Find the topmost parent and check that assigning `for_nest` token as a child for
219 /// `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 }
179249
250 /// Burn token and all of it's nested tokens
251 ///
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 }
192266
193 /// 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` then
270 /// 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 }
209289
290 /// Checks that `under` is valid token and that `token_id` could be nested under it
291 /// and that `from` is `under`'s owner
292 ///
293 /// Returns OK if `under` is not a token
294 ///
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 }
221307
308 /// Nests `token_id` under `under` token
309 ///
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 }
237328
329 /// Nests `token_id` under `owner` token
330 ///
331 /// Caller should check that nesting wouldn't cause recursion in nesting
238 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 }
247341
342 /// 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,
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
6license = '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'
1010
11[dependencies]11[dependencies]
12scale-info = { version = "2.0.1", default-features = false, features = [12scale-info = { version = "2.0.1", default-features = false, features = [
addedprimitives/data-structs/Changelog.mddiffbeforeafterboth

no changes

modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
537
537 pub pieces: u128,538 pub pieces: u128,
539
540 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
541 #[derivative(Debug(format_with = "bounded::vec_debug"))]
542 pub properties: CollectionPropertiesVec,
538}543}
539544
540#[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}
572579
573#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]580#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
707pub 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 execution
712);711);
713712
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
706pub 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 execution
711);710);
712711
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
705pub 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 execution
710);709);
711710
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
376 // ReFungible376 // ReFungible
377 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.unique
385 .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.unique
396 .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible);
397 await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected;
398 }
387 });399 });
388 });400 });
389401
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
28 function burnFrom(address from, uint256 amount) external returns (bool);28 function burnFrom(address from, uint256 amount) external returns (bool);
29}29}
30
31// Selector: 7d9262e6
32interface 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) 2f073f66
39 function setCollectionProperty(string memory key, bytes memory value)
40 external;
41
42 // Delete collection property.
43 //
44 // @param key Property key.
45 //
46 // Selector: deleteCollectionProperty(string) 7b7debce
47 function deleteCollectionProperty(string memory key) external;
48
49 // 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) cf24fd6d
57 function collectionProperty(string memory key)
58 external
59 view
60 returns (bytes memory);
61
62 // 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) 7623402e
69 function setCollectionSponsor(address sponsor) external;
70
71 // Collection sponsorship confirmation.
72 //
73 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
74 //
75 // Selector: confirmCollectionSponsorship() 3c50e97a
76 function confirmCollectionSponsorship() external;
77
78 // 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) 6a3841db
90 function setCollectionLimit(string memory limit, uint32 value) external;
91
92 // 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) 993b7fba
101 function setCollectionLimit(string memory limit, bool value) external;
102
103 // Get contract address.
104 //
105 // Selector: contractAddress() f6b4dfb4
106 function contractAddress() external view returns (address);
107
108 // Add collection admin by substrate address.
109 // @param new_admin Substrate administrator address.
110 //
111 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
112 function addCollectionAdminSubstrate(uint256 newAdmin) external;
113
114 // Remove collection admin by substrate address.
115 // @param admin Substrate administrator address.
116 //
117 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
118 function removeCollectionAdminSubstrate(uint256 admin) external;
119
120 // Add collection admin.
121 // @param new_admin Address of the added administrator.
122 //
123 // Selector: addCollectionAdmin(address) 92e462c7
124 function addCollectionAdmin(address newAdmin) external;
125
126 // Remove collection admin.
127 //
128 // @param new_admin Address of the removed administrator.
129 //
130 // Selector: removeCollectionAdmin(address) fafd7b42
131 function removeCollectionAdmin(address admin) external;
132
133 // Toggle accessibility of collection nesting.
134 //
135 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
136 //
137 // Selector: setCollectionNesting(bool) 112d4586
138 function setCollectionNesting(bool enable) external;
139
140 // 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[]) 64872396
146 function setCollectionNesting(bool enable, address[] memory collections)
147 external;
148
149 // Set the collection access method.
150 // @param mode Access mode
151 // 0 for Normal
152 // 1 for AllowList
153 //
154 // Selector: setCollectionAccess(uint8) 41835d4c
155 function setCollectionAccess(uint8 mode) external;
156
157 // Add the user to the allowed list.
158 //
159 // @param user Address of a trusted user.
160 //
161 // Selector: addToCollectionAllowList(address) 67844fe6
162 function addToCollectionAllowList(address user) external;
163
164 // Remove the user from the allowed list.
165 //
166 // @param user Address of a removed user.
167 //
168 // Selector: removeFromCollectionAllowList(address) 85c51acb
169 function removeFromCollectionAllowList(address user) external;
170
171 // Switch permission for minting.
172 //
173 // @param mode Enable if "true".
174 //
175 // Selector: setCollectionMintMode(bool) 00018e84
176 function setCollectionMintMode(bool mode) external;
177}
30178
31// Selector: 942e8b22179// Selector: 942e8b22
32interface ERC20 is Dummy, ERC165, ERC20Events {180interface ERC20 is Dummy, ERC165, ERC20Events {
65 returns (uint256);213 returns (uint256);
66}214}
67
68// Selector: c894dc35
69interface Collection is Dummy, ERC165 {
70 // Selector: setCollectionProperty(string,bytes) 2f073f66
71 function setCollectionProperty(string memory key, bytes memory value)
72 external;
73
74 // Selector: deleteCollectionProperty(string) 7b7debce
75 function deleteCollectionProperty(string memory key) external;
76
77 // Throws error if key not found
78 //
79 // Selector: collectionProperty(string) cf24fd6d
80 function collectionProperty(string memory key)
81 external
82 view
83 returns (bytes memory);
84
85 // Selector: ethSetSponsor(address) 8f9af356
86 function ethSetSponsor(address sponsor) external;
87
88 // Selector: ethConfirmSponsorship() a8580d1a
89 function ethConfirmSponsorship() external;
90
91 // Selector: setLimit(string,uint32) 68db30ca
92 function setLimit(string memory limit, uint32 value) external;
93
94 // Selector: setLimit(string,bool) ea67e4c2
95 function setLimit(string memory limit, bool value) external;
96
97 // Selector: contractAddress() f6b4dfb4
98 function contractAddress() external view returns (address);
99}
100215
101interface UniqueFungible is216interface UniqueFungible is
102 Dummy,217 Dummy,
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
4444
45// Selector: 4136937745// Selector: 41369377
46interface 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) 222d97fa
48 function setTokenPropertyPermission(55 function setTokenPropertyPermission(
49 string memory key,56 string memory key,
52 bool tokenOwner59 bool tokenOwner
53 ) external;60 ) external;
5461
62 // @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) 1752d67b
56 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 value
60 ) external;73 ) external;
6174
75 // @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) 066111d1
63 function deleteProperty(uint256 tokenId, string memory key) external;81 function deleteProperty(uint256 tokenId, string memory key) external;
6482
83 // @notice Get token property value.
65 // Throws error if key not found84 // @dev Throws error if key not found
85 // @param tokenId ID of the token.
86 // @param key Property key.
87 // @return Property value bytes
66 //88 //
67 // Selector: property(uint256,string) 7228c32789 // Selector: property(uint256,string) 7228c327
68 function property(uint256 tokenId, string memory key)90 function property(uint256 tokenId, string memory key)
7395
74// Selector: 42966c6896// Selector: 42966c68
75interface 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 authorized
100 // operator of the current owner.
101 // @param tokenId The NFT to approve
102 //
76 // Selector: burn(uint256) 42966c68103 // Selector: burn(uint256) 42966c68
77 function burn(uint256 tokenId) external;104 function burn(uint256 tokenId) external;
78}105}
79106
80// Selector: 58800161107// Selector: 58800161
81interface ERC721 is Dummy, ERC165, ERC721Events {108interface ERC721 is Dummy, ERC165, ERC721Events {
109 // @notice Count all NFTs assigned to an owner
110 // @dev NFTs assigned to the zero address are considered invalid, and this
111 // function throws for queries about the zero address.
112 // @param owner An address for whom to query the balance
113 // @return The number of NFTs owned by `owner`, possibly zero
114 //
82 // Selector: balanceOf(address) 70a08231115 // Selector: balanceOf(address) 70a08231
83 function balanceOf(address owner) external view returns (uint256);116 function balanceOf(address owner) external view returns (uint256);
84117
118 // @notice Find the owner of an NFT
119 // @dev NFTs assigned to zero address are considered invalid, and queries
120 // about them do throw.
121 // @param tokenId The identifier for an NFT
122 // @return The address of the owner of the NFT
123 //
85 // Selector: ownerOf(uint256) 6352211e124 // Selector: ownerOf(uint256) 6352211e
86 function ownerOf(uint256 tokenId) external view returns (address);125 function ownerOf(uint256 tokenId) external view returns (address);
87126
88 // Not implemented127 // @dev Not implemented
89 //128 //
90 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672129 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
91 function safeTransferFromWithData(130 function safeTransferFromWithData(
95 bytes memory data134 bytes memory data
96 ) external;135 ) external;
97136
98 // Not implemented137 // @dev Not implemented
99 //138 //
100 // Selector: safeTransferFrom(address,address,uint256) 42842e0e139 // Selector: safeTransferFrom(address,address,uint256) 42842e0e
101 function safeTransferFrom(140 function safeTransferFrom(
104 uint256 tokenId143 uint256 tokenId
105 ) external;144 ) external;
106145
146 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
147 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
148 // THEY MAY BE PERMANENTLY LOST
149 // @dev Throws unless `msg.sender` is the current owner or an authorized
150 // operator for this NFT. Throws if `from` is not the current owner. Throws
151 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
152 // @param from The current owner of the NFT
153 // @param to The new owner
154 // @param tokenId The NFT to transfer
155 // @param _value Not used for an NFT
156 //
107 // Selector: transferFrom(address,address,uint256) 23b872dd157 // Selector: transferFrom(address,address,uint256) 23b872dd
108 function transferFrom(158 function transferFrom(
109 address from,159 address from,
110 address to,160 address to,
111 uint256 tokenId161 uint256 tokenId
112 ) external;162 ) external;
113163
164 // @notice Set or reaffirm the approved address for an NFT
165 // @dev The zero address indicates there is no approved address.
166 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
167 // operator of the current owner.
168 // @param approved The new approved NFT controller
169 // @param tokenId The NFT to approve
170 //
114 // Selector: approve(address,uint256) 095ea7b3171 // Selector: approve(address,uint256) 095ea7b3
115 function approve(address approved, uint256 tokenId) external;172 function approve(address approved, uint256 tokenId) external;
116173
117 // Not implemented174 // @dev Not implemented
118 //175 //
119 // Selector: setApprovalForAll(address,bool) a22cb465176 // Selector: setApprovalForAll(address,bool) a22cb465
120 function setApprovalForAll(address operator, bool approved) external;177 function setApprovalForAll(address operator, bool approved) external;
121178
122 // Not implemented179 // @dev Not implemented
123 //180 //
124 // Selector: getApproved(uint256) 081812fc181 // Selector: getApproved(uint256) 081812fc
125 function getApproved(uint256 tokenId) external view returns (address);182 function getApproved(uint256 tokenId) external view returns (address);
126183
127 // Not implemented184 // @dev Not implemented
128 //185 //
129 // Selector: isApprovedForAll(address,address) e985e9c5186 // Selector: isApprovedForAll(address,address) e985e9c5
130 function isApprovedForAll(address owner, address operator)187 function isApprovedForAll(address owner, address operator)
135192
136// Selector: 5b5e139f193// Selector: 5b5e139f
137interface ERC721Metadata is Dummy, ERC165 {194interface ERC721Metadata is Dummy, ERC165 {
195 // @notice A descriptive name for a collection of NFTs in this contract
196 //
138 // Selector: name() 06fdde03197 // Selector: name() 06fdde03
139 function name() external view returns (string memory);198 function name() external view returns (string memory);
140199
200 // @notice An abbreviated name for NFTs in this contract
201 //
141 // Selector: symbol() 95d89b41202 // Selector: symbol() 95d89b41
142 function symbol() external view returns (string memory);203 function symbol() external view returns (string memory);
143204
205 // @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 RFC
207 // 3986. The URI may point to a JSON file that conforms to the "ERC721
208 // Metadata JSON Schema".
144 // Returns token's const_metadata209 // @return token's const_metadata
145 //210 //
146 // Selector: tokenURI(uint256) c87b56dd211 // Selector: tokenURI(uint256) c87b56dd
147 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() 05d2035b
153 function mintingFinished() external view returns (bool);218 function mintingFinished() external view returns (bool);
154219
220 // @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 manually
223 // @param to The new owner
224 // @param tokenId ID of the minted NFT
157 //225 //
158 // Selector: mint(address,uint256) 40c10f19226 // Selector: mint(address,uint256) 40c10f19
159 function mint(address to, uint256 tokenId) external returns (bool);227 function mint(address to, uint256 tokenId) external returns (bool);
160228
229 // @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 manually
232 // @param to The new owner
233 // @param tokenId ID of the minted NFT
234 // @param tokenUri Token URI that would be stored in the NFT properties
163 //235 //
164 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f236 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
165 function mintWithTokenURI(237 function mintWithTokenURI(
168 string memory tokenUri240 string memory tokenUri
169 ) external returns (bool);241 ) external returns (bool);
170242
171 // Not implemented243 // @dev Not implemented
172 //244 //
173 // Selector: finishMinting() 7d64bcb4245 // Selector: finishMinting() 7d64bcb4
174 function finishMinting() external returns (bool);246 function finishMinting() external returns (bool);
175}247}
176248
177// Selector: 780e9d63249// Selector: 780e9d63
178interface ERC721Enumerable is Dummy, ERC165 {250interface ERC721Enumerable is Dummy, ERC165 {
251 // @notice Enumerate valid NFTs
252 // @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) 4f6ccce7
180 function tokenByIndex(uint256 index) external view returns (uint256);257 function tokenByIndex(uint256 index) external view returns (uint256);
181258
182 // Not implemented259 // @dev Not implemented
183 //260 //
184 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59261 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
185 function tokenOfOwnerByIndex(address owner, uint256 index)262 function tokenOfOwnerByIndex(address owner, uint256 index)
186 external263 external
187 view264 view
188 returns (uint256);265 returns (uint256);
189266
267 // @notice Count NFTs tracked by this contract
268 // @return A count of valid NFTs tracked by this contract, where each one of
269 // them has an assigned and queryable owner not equal to the zero address
270 //
190 // Selector: totalSupply() 18160ddd271 // Selector: totalSupply() 18160ddd
191 function totalSupply() external view returns (uint256);272 function totalSupply() external view returns (uint256);
192}273}
193274
194// Selector: 7d9262e6275// Selector: 7d9262e6
195interface 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) 2f073f66
197 function setCollectionProperty(string memory key, bytes memory value)283 function setCollectionProperty(string memory key, bytes memory value)
198 external;284 external;
199285
286 // Delete collection property.
287 //
288 // @param key Property key.
289 //
200 // Selector: deleteCollectionProperty(string) 7b7debce290 // Selector: deleteCollectionProperty(string) 7b7debce
201 function deleteCollectionProperty(string memory key) external;291 function deleteCollectionProperty(string memory key) external;
202292
293 // 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) cf24fd6d
206 function collectionProperty(string memory key)301 function collectionProperty(string memory key)
207 external302 external
208 view303 view
209 returns (bytes memory);304 returns (bytes memory);
210305
306 // 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) 7623402e
212 function setCollectionSponsor(address sponsor) external;313 function setCollectionSponsor(address sponsor) external;
213314
315 // 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() 3c50e97a
215 function confirmCollectionSponsorship() external;320 function confirmCollectionSponsorship() external;
216321
322 // 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) 6a3841db
218 function setCollectionLimit(string memory limit, uint32 value) external;334 function setCollectionLimit(string memory limit, uint32 value) external;
219335
336 // 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) 993b7fba
221 function setCollectionLimit(string memory limit, bool value) external;345 function setCollectionLimit(string memory limit, bool value) external;
222346
347 // Get contract address.
348 //
223 // Selector: contractAddress() f6b4dfb4349 // Selector: contractAddress() f6b4dfb4
224 function contractAddress() external view returns (address);350 function contractAddress() external view returns (address);
225351
352 // Add collection admin by substrate address.
353 // @param new_admin Substrate administrator address.
354 //
226 // Selector: addCollectionAdminSubstrate(uint256) 5730062b355 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
227 function addCollectionAdminSubstrate(uint256 newAdmin) external view;356 function addCollectionAdminSubstrate(uint256 newAdmin) external;
228357
358 // Remove collection admin by substrate address.
359 // @param admin Substrate administrator address.
360 //
229 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9361 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
230 function removeCollectionAdminSubstrate(uint256 newAdmin) external view;362 function removeCollectionAdminSubstrate(uint256 admin) external;
231363
364 // Add collection admin.
365 // @param new_admin Address of the added administrator.
366 //
232 // Selector: addCollectionAdmin(address) 92e462c7367 // Selector: addCollectionAdmin(address) 92e462c7
233 function addCollectionAdmin(address newAdmin) external view;368 function addCollectionAdmin(address newAdmin) external;
234369
370 // Remove collection admin.
371 //
372 // @param new_admin Address of the removed administrator.
373 //
235 // Selector: removeCollectionAdmin(address) fafd7b42374 // Selector: removeCollectionAdmin(address) fafd7b42
236 function removeCollectionAdmin(address admin) external view;375 function removeCollectionAdmin(address admin) external;
237376
377 // 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) 112d4586
239 function setCollectionNesting(bool enable) external;382 function setCollectionNesting(bool enable) external;
240383
384 // 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[]) 64872396
242 function setCollectionNesting(bool enable, address[] memory collections)390 function setCollectionNesting(bool enable, address[] memory collections)
243 external;391 external;
244392
393 // Set the collection access method.
394 // @param mode Access mode
395 // 0 for Normal
396 // 1 for AllowList
397 //
245 // Selector: setCollectionAccess(uint8) 41835d4c398 // Selector: setCollectionAccess(uint8) 41835d4c
246 function setCollectionAccess(uint8 mode) external;399 function setCollectionAccess(uint8 mode) external;
247400
401 // 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) 67844fe6
249 function addToCollectionAllowList(address user) external view;406 function addToCollectionAllowList(address user) external;
250407
408 // 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) 85c51acb
252 function removeFromCollectionAllowList(address user) external view;413 function removeFromCollectionAllowList(address user) external;
253414
415 // Switch permission for minting.
416 //
417 // @param mode Enable if "true".
418 //
254 // Selector: setCollectionMintMode(bool) 00018e84419 // Selector: setCollectionMintMode(bool) 00018e84
255 function setCollectionMintMode(bool mode) external;420 function setCollectionMintMode(bool mode) external;
256}421}
257422
258// Selector: d74d154f423// Selector: d74d154f
259interface ERC721UniqueExtensions is Dummy, ERC165 {424interface ERC721UniqueExtensions is Dummy, ERC165 {
425 // @notice Transfer ownership of an NFT
426 // @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 owner
429 // @param tokenId The NFT to transfer
430 // @param _value Not used for an NFT
431 //
260 // Selector: transfer(address,uint256) a9059cbb432 // Selector: transfer(address,uint256) a9059cbb
261 function transfer(address to, uint256 tokenId) external;433 function transfer(address to, uint256 tokenId) external;
262434
435 // @notice Burns a specific ERC721 token.
436 // @dev Throws unless `msg.sender` is the current owner or an authorized
437 // operator for this NFT. Throws if `from` is not the current owner. Throws
438 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
439 // @param from The current owner of the NFT
440 // @param tokenId The NFT to transfer
441 // @param _value Not used for an NFT
442 //
263 // Selector: burnFrom(address,uint256) 79cc6790443 // Selector: burnFrom(address,uint256) 79cc6790
264 function burnFrom(address from, uint256 tokenId) external;444 function burnFrom(address from, uint256 tokenId) external;
265445
446 // @notice Returns next free NFT ID.
447 //
266 // Selector: nextTokenId() 75794a3c448 // Selector: nextTokenId() 75794a3c
267 function nextTokenId() external view returns (uint256);449 function nextTokenId() external view returns (uint256);
268450
451 // @notice Function to mint multiple tokens.
452 // @dev `tokenIds` should be an array of consecutive numbers and first number
453 // should be obtained with `nextTokenId` method
454 // @param to The new owner
455 // @param tokenIds IDs of the minted NFTs
456 //
269 // Selector: mintBulk(address,uint256[]) 44a9945e457 // Selector: mintBulk(address,uint256[]) 44a9945e
270 function mintBulk(address to, uint256[] memory tokenIds)458 function mintBulk(address to, uint256[] memory tokenIds)
271 external459 external
272 returns (bool);460 returns (bool);
273461
462 // @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 consecutive
464 // numbers and first number should be obtained with `nextTokenId` method
465 // @param to The new owner
466 // @param tokens array of pairs of token ID and token URI for minted tokens
467 //
274 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006468 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
275 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)469 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
276 external470 external
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
49 "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" }
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
86 ],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 {
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
276 [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 error
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
187 [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 query
400 [key: string]: QueryableStorageEntry<ApiType>;409 [key: string]: QueryableStorageEntry<ApiType>;
401 };410 };
402 refungible: {411 refungible: {
412 /**
413 * Amount of tokens owned by account
414 **/
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 token
418 **/
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 account
422 **/
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 account
408 **/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 token
430 **/
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 collection
436 **/
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 token
440 **/
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 query
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
2461export 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}
24652466
2466/** @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}
24712473
2472/** @name UpDataStructsNestingPermissions */2474/** @name UpDataStructsNestingPermissions */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
1502 **/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>
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
1629 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 }
16331634
1634 /** @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 }
16581660
1659 /** @name PalletUniqueSchedulerCall (204) */1661 /** @name PalletUniqueSchedulerCall (204) */
modifiedtests/src/nesting/properties.test.tsdiffbeforeafterboth
2import 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 });
2526
26 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});
2930
30 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 }
62
63 it('Makes sure collectionById supplies required fields for NFT', async () => {
64 await testMakeSureSuppliesRequired({type: 'NFT'});
60 });65 });
66
67 it('Makes sure collectionById supplies required fields for ReFungible', async () => {
68 await testMakeSureSuppliesRequired({type: 'ReFungible'});
69 });
61});70});
6271
63// ---------- COLLECTION PROPERTIES72// ---------- COLLECTION PROPERTIES
79 });88 });
80 });89 });
8190
91
82 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);
8696
87 // As owner97 // As owner
106 {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 });
110126
111 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 symbols
117 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 symbols
124 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 symbol
131 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 symbol
138 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 symbol
145 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 });
162184
163 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 properties
174 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 });
187215
188 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});
211245
212describe('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 process
242 {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 });
291
292 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});
341399
342// ---------- ACCESS RIGHTS400// ---------- ACCESS RIGHTS
357 });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});
409479
410describe('Negative Integration Test: Access Rights to Token Properties', () => {480describe('Negative Integration Test: Access Rights to Token Properties', () => {
415 });485 });
416 });486 });
417487
418 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 });
432508
433 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 });
455537
456 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 });
478566
479 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-string
504 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});
521615
522// ---------- TOKEN PROPERTIES616// ---------- TOKEN PROPERTIES
523617
524describe('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[]}[];
529620
530 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 owner
533 bob = privateKeyWrapper('//Bob');624 bob = privateKeyWrapper('//Bob'); // collection admin
534 charlie = privateKeyWrapper('//Charlie');625 charlie = privateKeyWrapper('//Charlie'); // token owner
535626
536 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 });
546
547 beforeEach(async () => {
548 await usingApi(async () => {
549 collection = await createCollectionExpectSuccess();
550 await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {tokenOwner: true}});
551
552 token = await createItemExpectSuccess(alice, collection, 'NFT');
553 nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, token)});
554
555 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 });
573657
574 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);
664
576 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 });
607702
608 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);
709
610 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 });
649755
650 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);
762
652 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 });
691808
692 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);
817
694 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) {
725849
726 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);
858
728 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) {
767898
768 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);
907
770 const propertyKeys: string[] = [];908 const propertyKeys: string[] = [];
771 let i = 0;909 let i = 0;
772910
832 });970 });
833 });971 });
834972
835 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 }
8641002
865 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 });
8891035
890 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 });
9141068
915 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);
1071
916 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 });
9401102
941 it('Forbids adding too many properties to a token', async () => {1103 async function testForbidsAddingTooManyProperties(mode: CollectionMode, pieces: number) {
1104 await prepare(mode, pieces);
1105
942 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 error
953 {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});
1147
1148describe('ReFungible token properties permissions tests', () => {
1149 let collection: number;
1150 let token: number;
1151
1152 before(async () => {
1153 await usingApi(async (api, privateKeyWrapper) => {
1154 alice = privateKeyWrapper('//Alice');
1155 bob = privateKeyWrapper('//Bob');
1156 charlie = privateKeyWrapper('//Charlie');
1157 });
1158 });
1159
1160 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);
1165
1166 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 });
1173
1174 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 });
1187
1188 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;
1203
1204 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 });
1215
1216 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;
1225
1226 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});
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {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';
3436
35import chai from 'chai';37import chai from 'chai';
188 });190 });
189});191});
192
193describe('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});
190215
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
284 type: 'ReFungible';284 type: 'ReFungible';
285}285}
286286
287type CollectionMode = Nft | Fungible | ReFungible;287export type CollectionMode = Nft | Fungible | ReFungible;
288288
289export 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 }
14161416
1417 const events = await submitTransactionAsync(sender, tx);1417 const events = await executeTransaction(api, sender, tx);
1418 const result = getCreateItemResult(events);1418 const result = getCreateItemResult(events);
14191419
1420 const itemCountAfter = await getLastTokenId(api, collectionId);1420 const itemCountAfter = await getLastTokenId(api, collectionId);
modifiedtests/src/xcmTransfer.test.tsdiffbeforeafterboth
31const 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;
3435
35describe('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 ],
148149
149 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 };
166165
167 const id = {166 const id = {
168 ForeignAsset: 0,167 ForeignAsset: 0,
169 };168 };
170169
171 const amount = 5000000000;170 const amount = TRANSFER_AMOUNT;
172 const destWeight = 50000000;171 const destWeight = 50000000;
173172
174 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);173 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);