difftreelog
Merge branch 'develop' into feature/CORE-386_1
in: master
54 files changed
Makefilediffbeforeafterboth93bench-structure:93bench-structure:94 make _bench PALLET=structure94 make _bench PALLET=structure9596.PHONY: bench-rmrk-core97bench-rmrk-core:98 make _bench PALLET=proxy-rmrk-core959996.PHONY: bench100.PHONY: bench97bench: bench-evm-migration bench-unique bench-structure bench-fungible bench-refungible bench-nonfungible101bench: bench-evm-migration bench-unique bench-structure bench-fungible bench-refungible bench-nonfungible bench-rmrk-core98102pallets/common/src/benchmarking.rsdiffbeforeafterboth109 create_collection_raw(109 create_collection_raw(110 owner,110 owner,111 CollectionMode::NFT,111 CollectionMode::NFT,112 |owner, data| <Pallet<T>>::init_collection(owner, data),112 |owner, data| <Pallet<T>>::init_collection(owner, data, true),113 |h| h,113 |h| h,114 )114 )115}115}pallets/common/src/dispatch.rsdiffbeforeafterboth11use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};11use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};121213// TODO: move to benchmarking13// TODO: move to benchmarking14/// Price of [`dispatch_call`] call with noop `call` argument14/// Price of [`dispatch_tx`] call with noop `call` argument15pub fn dispatch_weight<T: Config>() -> Weight {15pub fn dispatch_weight<T: Config>() -> Weight {16 // Read collection16 // Read collection17 <T as frame_system::Config>::DbWeight::get().reads(1)17 <T as frame_system::Config>::DbWeight::get().reads(1)21}21}222223/// Helper function to implement substrate calls for common collection methods23/// Helper function to implement substrate calls for common collection methods24pub fn dispatch_call<24pub fn dispatch_tx<25 T: Config,25 T: Config,26 C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,26 C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,27>(27>(pallets/common/src/lib.rsdiffbeforeafterboth427 /// Target collection doesn't supports this operation427 /// Target collection doesn't supports this operation428 UnsupportedOperation,428 UnsupportedOperation,429429430 /// Not sufficient founds to perform action430 /// Not sufficient funds to perform action431 NotSufficientFounds,431 NotSufficientFounds,432432433 /// Collection has nesting disabled433 /// Collection has nesting disabledpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth51 create_collection_raw(51 create_collection_raw(52 owner,52 owner,53 CollectionMode::NFT,53 CollectionMode::NFT,54 <Pallet<T>>::init_collection,54 |owner, data| <Pallet<T>>::init_collection(owner, data, true),55 NonfungibleHandle::cast,55 NonfungibleHandle::cast,56 )56 )57}57}99 sender: cross_from_sub(owner); burner: cross_sub;99 sender: cross_from_sub(owner); burner: cross_sub;100 };100 };101 let item = create_max_item(&collection, &sender, burner.clone())?;101 let item = create_max_item(&collection, &sender, burner.clone())?;102 }: {<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)}102 }: {<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)?}103103104 burn_recursively_breadth_plus_self_plus_self_per_each_raw {104 burn_recursively_breadth_plus_self_plus_self_per_each_raw {105 let b in 0..200;105 let b in 0..200;111 for i in 0..b {111 for i in 0..b {112 create_max_item(&collection, &sender, T::CrossTokenAddressMapping::token_to_address(collection.id, item))?;112 create_max_item(&collection, &sender, T::CrossTokenAddressMapping::token_to_address(collection.id, item))?;113 }113 }114 }: {<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)}114 }: {<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)?}115115116 transfer {116 transfer {117 bench_init!{117 bench_init!{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)?}186 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props, false)?}187187188 delete_token_properties {188 delete_token_properties {189 let b in 0..MAX_PROPERTIES_PER_ITEM;189 let b in 0..MAX_PROPERTIES_PER_ITEM;205 value: property_value(),205 value: property_value(),206 }).collect::<Vec<_>>();206 }).collect::<Vec<_>>();207 let item = create_max_item(&collection, &owner, owner.clone())?;207 let item = create_max_item(&collection, &owner, owner.clone())?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props)?;208 <Pallet<T>>::set_token_properties(&collection, &owner, item, props, false)?;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)?}210 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete)?}211}211}pallets/proxy-rmrk-core/src/benchmarking.rsdiffbeforeafterbothno changes
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth313132pub use pallet::*;32pub use pallet::*;333334#[cfg(feature = "runtime-benchmarks")]35pub mod benchmarking;34pub mod misc;36pub mod misc;35pub mod property;37pub mod property;3638pub mod weights;3940pub type SelfWeightOf<T> = <T as Config>::WeightInfo;4142use weights::WeightInfo;37use misc::*;43use misc::*;38pub use property::*;44pub use property::*;394551 frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config57 frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config52 {58 {53 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;59 type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;60 type WeightInfo: WeightInfo;54 }61 }556256 #[pallet::storage]63 #[pallet::storage]169176170 #[pallet::call]177 #[pallet::call]171 impl<T: Config> Pallet<T> {178 impl<T: Config> Pallet<T> {179 /// Create a collection180 #[transactional]172 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]181 #[pallet::weight(<SelfWeightOf<T>>::create_collection())]173 #[transactional]174 pub fn create_collection(182 pub fn create_collection(175 origin: OriginFor<T>,183 origin: OriginFor<T>,176 metadata: RmrkString,184 metadata: RmrkString,222 Ok(())230 Ok(())223 }231 }224232233 /// destroy collection225 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]234 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]226 #[transactional]235 #[transactional]227 pub fn destroy_collection(236 pub fn destroy_collection(248 Ok(())257 Ok(())249 }258 }250259260 /// Change the issuer of a collection261 ///262 /// Parameters:263 /// - `origin`: sender of the transaction264 /// - `collection_id`: collection id of the nft to change issuer of265 /// - `new_issuer`: Collection's new issuer251 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]266 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]252 #[transactional]267 #[transactional]253 pub fn change_collection_issuer(268 pub fn change_collection_issuer(278 Ok(())293 Ok(())279 }294 }280295296 /// lock collection281 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]297 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]282 #[transactional]298 #[transactional]283 pub fn lock_collection(299 pub fn lock_collection(309 Ok(())325 Ok(())310 }326 }311327328 /// Mints an NFT in the specified collection329 /// Sets metadata and the royalty attribute330 ///331 /// Parameters:332 /// - `collection_id`: The class of the asset to be minted.333 /// - `nft_id`: The nft value of the asset to be minted.334 /// - `recipient`: Receiver of the royalty335 /// - `royalty`: Permillage reward from each trade for the Recipient336 /// - `metadata`: Arbitrary data about an nft, e.g. IPFS hash337 /// - `transferable`: Ability to transfer this NFT312 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]338 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]313 #[transactional]339 #[transactional]314 pub fn mint_nft(340 pub fn mint_nft(378 Ok(())404 Ok(())379 }405 }380406407 /// burn nft381 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]408 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]382 #[transactional]409 #[transactional]383 pub fn burn_nft(410 pub fn burn_nft(409 Ok(())436 Ok(())410 }437 }411438439 /// Transfers a NFT from an Account or NFT A to another Account or NFT B440 ///441 /// Parameters:442 /// - `origin`: sender of the transaction443 /// - `rmrk_collection_id`: collection id of the nft to be transferred444 /// - `rmrk_nft_id`: nft id of the nft to be transferred445 /// - `new_owner`: new owner of the nft which can be either an account or a NFT412 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]446 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]413 #[transactional]447 #[transactional]414 pub fn send(448 pub fn send(462496463 let target_nft_budget = budget::Value::new(NESTING_BUDGET);497 let target_nft_budget = budget::Value::new(NESTING_BUDGET);464498465 let target_nft_owner = <PalletStructure<T>>::get_checked_indirect_owner(499 let target_nft_owner = <PalletStructure<T>>::get_checked_topmost_owner(466 target_collection_id,500 target_collection_id,467 target_nft_id.into(),501 target_nft_id.into(),468 Some((collection_id, nft_id)),502 Some((collection_id, nft_id)),513 Ok(())547 Ok(())514 }548 }515549550 /// Accepts an NFT sent from another account to self or owned NFT551 ///552 /// Parameters:553 /// - `origin`: sender of the transaction554 /// - `rmrk_collection_id`: collection id of the nft to be accepted555 /// - `rmrk_nft_id`: nft id of the nft to be accepted556 /// - `new_owner`: either origin's account ID or origin-owned NFT, whichever the NFT was557 /// sent to516 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]558 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]517 #[transactional]559 #[transactional]518 pub fn accept_nft(560 pub fn accept_nft(582 Ok(())624 Ok(())583 }625 }584626627 /// Rejects an NFT sent from another account to self or owned NFT628 ///629 /// Parameters:630 /// - `origin`: sender of the transaction631 /// - `rmrk_collection_id`: collection id of the nft to be accepted632 /// - `rmrk_nft_id`: nft id of the nft to be accepted585 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]633 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]586 #[transactional]634 #[transactional]587 pub fn reject_nft(635 pub fn reject_nft(618 Ok(())666 Ok(())619 }667 }620668669 /// accept the addition of a new resource to an existing NFT621 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]670 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]622 #[transactional]671 #[transactional]623 pub fn accept_resource(672 pub fn accept_resource(674 Ok(())723 Ok(())675 }724 }676725726 /// accept the removal of a resource of an existing NFT677 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]727 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]678 #[transactional]728 #[transactional]679 pub fn accept_resource_removal(729 pub fn accept_resource_removal(731 Ok(())781 Ok(())732 }782 }733783784 /// set a custom value on an NFT734 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]785 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]735 #[transactional]786 #[transactional]736 pub fn set_property(787 pub fn set_property(790 Ok(())841 Ok(())791 }842 }792843844 /// set a different order of resource priority793 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]845 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]794 #[transactional]846 #[transactional]795 pub fn set_priority(847 pub fn set_priority(828 Ok(())880 Ok(())829 }881 }830882883 /// Create basic resource831 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]884 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]832 #[transactional]885 #[transactional]833 pub fn add_basic_resource(886 pub fn add_basic_resource(865 Ok(())918 Ok(())866 }919 }867920921 /// Create composable resource868 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]922 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]869 #[transactional]923 #[transactional]870 pub fn add_composable_resource(924 pub fn add_composable_resource(905 Ok(())959 Ok(())906 }960 }907961962 /// Create slot resource908 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]963 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]909 #[transactional]964 #[transactional]910 pub fn add_slot_resource(965 pub fn add_slot_resource(944 Ok(())999 Ok(())945 }1000 }94610011002 /// remove resource947 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]1003 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]948 #[transactional]1004 #[transactional]949 pub fn remove_resource(1005 pub fn remove_resource(pallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use super::*;17use super::*;2use codec::{Encode, Decode, Error};18use codec::{Encode, Decode, Error};pallets/proxy-rmrk-core/src/property.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use super::*;17use super::*;2use core::convert::AsRef;18use core::convert::AsRef;pallets/proxy-rmrk-core/src/weights.rsdiffbeforeafterbothno changes
pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth747475 #[pallet::call]75 #[pallet::call]76 impl<T: Config> Pallet<T> {76 impl<T: Config> Pallet<T> {77 /// Creates a new Base.78 /// Modeled after [base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md)79 ///80 /// Parameters:81 /// - origin: Caller, will be assigned as the issuer of the Base82 /// - base_type: media type, e.g. "svg"83 /// - symbol: arbitrary client-chosen symbol84 /// - parts: array of Fixed and Slot parts composing the base, confined in length by85 /// RmrkPartsLimit77 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]86 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]78 #[transactional]87 #[transactional]79 pub fn create_base(88 pub fn create_base(137 Ok(())146 Ok(())138 }147 }139148149 /// Adds a Theme to a Base.150 /// Modeled after [themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md)151 /// Themes are stored in the Themes storage152 /// A Theme named "default" is required prior to adding other Themes.153 ///154 /// Parameters:155 /// - origin: The caller of the function, must be issuer of the base156 /// - base_id: The Base containing the Theme to be updated157 /// - theme: The Theme to add to the Base. A Theme has a name and properties, which are an158 /// array of [key, value, inherit].159 /// - key: arbitrary BoundedString, defined by client160 /// - value: arbitrary BoundedString, defined by client161 /// - inherit: optional bool140 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]162 #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]141 #[transactional]163 #[transactional]142 pub fn theme_add(164 pub fn theme_add(pallets/structure/src/lib.rsdiffbeforeafterboth149 })149 })150 }150 }151151152 pub fn get_checked_indirect_owner(152 pub fn get_checked_topmost_owner(153 collection: CollectionId,153 collection: CollectionId,154 token: TokenId,154 token: TokenId,155 for_nest: Option<(CollectionId, TokenId)>,155 for_nest: Option<(CollectionId, TokenId)>,203 None => user,203 None => user,204 };204 };205205206 Self::get_checked_indirect_owner(collection, token, for_nest, budget)206 Self::get_checked_topmost_owner(collection, token, for_nest, budget)207 .map(|indirect_owner| indirect_owner == target_parent)207 .map(|indirect_owner| indirect_owner == target_parent)208 }208 }209209pallets/unique/src/lib.rsdiffbeforeafterboth44};44};45use pallet_evm::account::CrossAccountId;45use pallet_evm::account::CrossAccountId;46use pallet_common::{46use pallet_common::{47 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,47 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_tx,48 dispatch::CollectionDispatch,48 dispatch::CollectionDispatch,49};49};50pub mod eth;50pub mod eth;581 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);581 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);582 let budget = budget::Value::new(NESTING_BUDGET);582 let budget = budget::Value::new(NESTING_BUDGET);583583584 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))584 dispatch_tx::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))585 }585 }586586587 /// This method creates multiple items in a collection created with CreateCollection method.587 /// This method creates multiple items in a collection created with CreateCollection method.609 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);609 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);610 let budget = budget::Value::new(NESTING_BUDGET);610 let budget = budget::Value::new(NESTING_BUDGET);611611612 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))612 dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))613 }613 }614614615 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]615 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]623623624 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);624 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);625625626 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))626 dispatch_tx::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))627 }627 }628628629 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]629 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]637637638 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);638 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);639639640 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))640 dispatch_tx::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))641 }641 }642642643 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]643 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]652652653 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);653 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);654654655 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))655 dispatch_tx::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))656 }656 }657657658 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]658 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]667667668 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);668 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);669669670 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))670 dispatch_tx::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))671 }671 }672672673 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]673 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]681681682 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);682 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);683683684 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))684 dispatch_tx::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))685 }685 }686686687 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]687 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]690 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);690 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);691 let budget = budget::Value::new(NESTING_BUDGET);691 let budget = budget::Value::new(NESTING_BUDGET);692692693 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))693 dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))694 }694 }695695696 // TODO! transaction weight696 // TODO! transaction weight738 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {738 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {739 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);739 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);740740741 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;741 let post_info = dispatch_tx::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;742 if value == 1 {742 if value == 1 {743 <NftTransferBasket<T>>::remove(collection_id, item_id);743 <NftTransferBasket<T>>::remove(collection_id, item_id);744 <NftApproveBasket<T>>::remove(collection_id, item_id);744 <NftApproveBasket<T>>::remove(collection_id, item_id);771 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);771 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);772 let budget = budget::Value::new(NESTING_BUDGET);772 let budget = budget::Value::new(NESTING_BUDGET);773773774 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))774 dispatch_tx::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))775 }775 }776776777 /// Change ownership of the token.777 /// Change ownership of the token.803 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);803 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);804 let budget = budget::Value::new(NESTING_BUDGET);804 let budget = budget::Value::new(NESTING_BUDGET);805805806 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))806 dispatch_tx::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))807 }807 }808808809 /// Set, change, or remove approved address to transfer the ownership of the NFT.809 /// Set, change, or remove approved address to transfer the ownership of the NFT.826 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {826 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {827 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);827 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);828828829 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))829 dispatch_tx::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))830 }830 }831831832 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.832 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.854 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);854 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);855 let budget = budget::Value::new(NESTING_BUDGET);855 let budget = budget::Value::new(NESTING_BUDGET);856856857 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))857 dispatch_tx::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))858 }858 }859859860 #[weight = <SelfWeightOf<T>>::set_collection_limits()]860 #[weight = <SelfWeightOf<T>>::set_collection_limits()]primitives/rmrk-rpc/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161#![cfg_attr(not(feature = "std"), no_std)]17#![cfg_attr(not(feature = "std"), no_std)]218primitives/rmrk-traits/src/base.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode, MaxEncodedLen};5use codec::{Decode, Encode, MaxEncodedLen};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/collection.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode, MaxEncodedLen};5use codec::{Decode, Encode, MaxEncodedLen};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/lib.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41#![cfg_attr(not(feature = "std"), no_std)]5#![cfg_attr(not(feature = "std"), no_std)]26primitives/rmrk-traits/src/nft.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode, MaxEncodedLen};5use codec::{Decode, Encode, MaxEncodedLen};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/part.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode, MaxEncodedLen};5use codec::{Decode, Encode, MaxEncodedLen};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/property.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode};5use codec::{Decode, Encode};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/resource.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode, MaxEncodedLen};5use codec::{Decode, Encode, MaxEncodedLen};2use scale_info::TypeInfo;6use scale_info::TypeInfo;primitives/rmrk-traits/src/serialize.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use core::convert::AsRef;5use core::convert::AsRef;2use serde::ser::{self, Serialize};6use serde::ser::{self, Serialize};primitives/rmrk-traits/src/theme.rsdiffbeforeafterboth1// Copyright (C) 2021-2022 RMRK2// This file is part of rmrk-substrate.3// License: Apache 2.0 modified by RMRK, see https://github.com/rmrk-team/rmrk-substrate/blob/main/LICENSE41use codec::{Decode, Encode};5use codec::{Decode, Encode};2use scale_info::TypeInfo;6use scale_info::TypeInfo;runtime/common/src/constants.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use sp_runtime::Perbill;17use sp_runtime::Perbill;2use frame_support::{18use frame_support::{runtime/common/src/dispatch.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use frame_support::{dispatch::DispatchResult, ensure};17use frame_support::{dispatch::DispatchResult, ensure};2use pallet_evm::{PrecompileHandle, PrecompileResult};18use pallet_evm::{PrecompileHandle, PrecompileResult};runtime/common/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161#![cfg_attr(not(feature = "std"), no_std)]17#![cfg_attr(not(feature = "std"), no_std)]218runtime/common/src/runtime_apis.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161#[macro_export]17#[macro_export]2macro_rules! impl_common_runtime_apis {18macro_rules! impl_common_runtime_apis {331 .iter()347 .iter()332 .filter_map(|(res_id)| Some(RmrkResourceInfo {348 .filter_map(|(res_id)| Some(RmrkResourceInfo {333 id: res_id.0,349 id: res_id.0,334 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).unwrap(),350 pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?,335 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).unwrap(),351 pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?,336 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).unwrap() {352 resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? {337 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {353 ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource {338 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),354 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,339 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),355 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,340 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),356 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,341 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),357 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,342 }),358 }),343 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {359 ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource {344 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).unwrap(),360 parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?,345 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).unwrap(),361 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,346 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),362 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,347 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),363 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,348 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),364 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,349 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),365 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,350 }),366 }),351 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {367 ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource {352 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).unwrap(),368 base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?,353 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).unwrap(),369 src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?,354 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).unwrap(),370 metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?,355 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).unwrap(),371 slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?,356 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).unwrap(),372 license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?,357 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).unwrap(),373 thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?,358 }),374 }),359 },375 },360 }))376 }))447 let theme_names = collection.collection_tokens()463 let theme_names = collection.collection_tokens()448 .iter()464 .iter()449 .filter_map(|token_id| {465 .filter_map(|token_id| {450 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();466 let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?;451467452 match nft_type {468 match nft_type {453 Theme => Some(469 Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(),454 RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).unwrap()455 ),456 _ => None470 _ => None457 }471 }458 })472 })829 list_benchmark!(list, extra, pallet_fungible, Fungible);843 list_benchmark!(list, extra, pallet_fungible, Fungible);830 list_benchmark!(list, extra, pallet_refungible, Refungible);844 list_benchmark!(list, extra, pallet_refungible, Refungible);831 list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);845 list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);846 list_benchmark!(list, extra, pallet_proxy_rmrk_core, RmrkCore);832 // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);847 // list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);833848834 let storage_info = AllPalletsReversedWithSystemFirst::storage_info();849 let storage_info = AllPalletsReversedWithSystemFirst::storage_info();872 add_benchmark!(params, batches, pallet_fungible, Fungible);887 add_benchmark!(params, batches, pallet_fungible, Fungible);873 add_benchmark!(params, batches, pallet_refungible, Refungible);888 add_benchmark!(params, batches, pallet_refungible, Refungible);874 add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);889 add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);890 add_benchmark!(params, batches, pallet_proxy_rmrk_core, RmrkCore);875 // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);891 // add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);876892877 if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }893 if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }runtime/common/src/types.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161use sp_runtime::{17use sp_runtime::{2 traits::{Verify, IdentifyAccount, BlakeTwo256},18 traits::{Verify, IdentifyAccount, BlakeTwo256},runtime/opal/src/lib.rsdiffbeforeafterboth919}919}920920921impl pallet_proxy_rmrk_core::Config for Runtime {921impl pallet_proxy_rmrk_core::Config for Runtime {922 type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;922 type Event = Event;923 type Event = Event;923}924}924925runtime/quartz/src/lib.rsdiffbeforeafterboth918}918}919919920impl pallet_proxy_rmrk_core::Config for Runtime {920impl pallet_proxy_rmrk_core::Config for Runtime {921 type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;921 type Event = Event;922 type Event = Event;922}923}923924runtime/unique/src/lib.rsdiffbeforeafterboth917}917}918918919impl pallet_proxy_rmrk_core::Config for Runtime {919impl pallet_proxy_rmrk_core::Config for Runtime {920 type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight<Self>;920 type Event = Event;921 type Event = Event;921}922}922923tests/src/addCollectionAdmin.test.tsdiffbeforeafterboth41 });41 });42 });42 });4344 it('Add admin using added collection admin.', async () => {45 await usingApi(async (api, privateKeyWrapper) => {46 const collectionId = await createCollectionExpectSuccess();47 const alice = privateKeyWrapper('//Alice');48 const bob = privateKeyWrapper('//Bob');49 const charlie = privateKeyWrapper('//CHARLIE');5051 const collection = await queryCollectionExpectSuccess(api, collectionId);52 expect(collection.owner.toString()).to.be.equal(alice.address);5354 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));55 await submitTransactionAsync(alice, changeAdminTx);5657 const adminListAfterAddAdmin = await getAdminList(api, collectionId);58 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));5960 const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));61 await submitTransactionAsync(bob, changeAdminTxCharlie);62 const adminListAfterAddNewAdmin = await getAdminList(api, collectionId);63 expect(adminListAfterAddNewAdmin).to.be.deep.contains(normalizeAccountId(bob.address));64 expect(adminListAfterAddNewAdmin).to.be.deep.contains(normalizeAccountId(charlie.address));65 });66 });67});43});684469describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {45describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {46 it("Not owner can't add collection admin.", async () => {47 await usingApi(async (api, privateKeyWrapper) => {48 const collectionId = await createCollectionExpectSuccess();49 const alice = privateKeyWrapper('//Alice');50 const bob = privateKeyWrapper('//Bob');51 const charlie = privateKeyWrapper('//CHARLIE');5253 const collection = await queryCollectionExpectSuccess(api, collectionId);54 expect(collection.owner.toString()).to.be.equal(alice.address);5556 const adminListAfterAddAdmin = await getAdminList(api, collectionId);57 expect(adminListAfterAddAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address));5859 const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));60 await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected;61 62 const adminListAfterAddNewAdmin = await getAdminList(api, collectionId);63 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address));64 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address));65 });66 });6770 it("Not owner can't add collection admin.", async () => {68 it("Admin can't add collection admin.", async () => {71 await usingApi(async (api, privateKeyWrapper) => {69 await usingApi(async (api, privateKeyWrapper) => {72 const collectionId = await createCollectionExpectSuccess();70 const collectionId = await createCollectionExpectSuccess();73 const alice = privateKeyWrapper('//Alice');71 const alice = privateKeyWrapper('//Alice');74 const nonOwner = privateKeyWrapper('//Bob_stash');72 const bob = privateKeyWrapper('//Bob');73 const charlie = privateKeyWrapper('//CHARLIE');7475 const collection = await queryCollectionExpectSuccess(api, collectionId);76 expect(collection.owner.toString()).to.be.equal(alice.address);757776 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(alice.address));78 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));79 await submitTransactionAsync(alice, changeAdminTx);8081 const adminListAfterAddAdmin = await getAdminList(api, collectionId);82 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));8384 const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));77 await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected;85 await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected;7886 79 const adminListAfterAddAdmin = await getAdminList(api, collectionId);87 const adminListAfterAddNewAdmin = await getAdminList(api, collectionId);80 expect(adminListAfterAddAdmin).not.to.be.deep.contains(normalizeAccountId(alice.address));88 expect(adminListAfterAddNewAdmin).to.be.deep.contains(normalizeAccountId(bob.address));8182 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)83 await createCollectionExpectSuccess();89 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address));84 });90 });85 });91 });92tests/src/eth/allowlist.test.tsdiffbeforeafterboth18import {contractHelpers, createEthAccountWithBalance, deployFlipper, itWeb3} from './util/helpers';18import {contractHelpers, createEthAccountWithBalance, deployFlipper, itWeb3} from './util/helpers';191920describe('EVM allowlist', () => {20describe('EVM allowlist', () => {21 itWeb3('Contract allowlist can be toggled', async ({api, web3}) => {21 itWeb3('Contract allowlist can be toggled', async ({api, web3, privateKeyWrapper}) => {22 const owner = await createEthAccountWithBalance(api, web3);22 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);23 const flipper = await deployFlipper(web3, owner);23 const flipper = await deployFlipper(web3, owner);242425 const helpers = contractHelpers(web3, owner);25 const helpers = contractHelpers(web3, owner);36 expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;36 expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;37 });37 });383839 itWeb3('Non-allowlisted user can\'t call contract with allowlist enabled', async ({api, web3}) => {39 itWeb3('Non-allowlisted user can\'t call contract with allowlist enabled', async ({api, web3, privateKeyWrapper}) => {40 const owner = await createEthAccountWithBalance(api, web3);40 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);41 const flipper = await deployFlipper(web3, owner);41 const flipper = await deployFlipper(web3, owner);42 const caller = await createEthAccountWithBalance(api, web3);42 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);434344 const helpers = contractHelpers(web3, owner);44 const helpers = contractHelpers(web3, owner);4545tests/src/eth/base.test.tsdiffbeforeafterboth32import Web3 from 'web3';32import Web3 from 'web3';333334describe('Contract calls', () => {34describe('Contract calls', () => {35 itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api}) => {35 itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api, privateKeyWrapper}) => {36 const deployer = await createEthAccountWithBalance(api, web3);36 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);37 const flipper = await deployFlipper(web3, deployer);37 const flipper = await deployFlipper(web3, deployer);383839 const cost = await recordEthFee(api, deployer, () => flipper.methods.flip().send({from: deployer}));39 const cost = await recordEthFee(api, deployer, () => flipper.methods.flip().send({from: deployer}));40 expect(cost < BigInt(0.2 * Number(UNIQUE))).to.be.true;40 expect(cost < BigInt(0.2 * Number(UNIQUE))).to.be.true;41 });41 });424243 itWeb3('Balance transfer fee is less than 0.2 UNQ', async ({web3, api}) => {43 itWeb3('Balance transfer fee is less than 0.2 UNQ', async ({web3, api, privateKeyWrapper}) => {44 const userA = await createEthAccountWithBalance(api, web3);44 const userA = await createEthAccountWithBalance(api, web3, privateKeyWrapper);45 const userB = createEthAccount(web3);45 const userB = createEthAccount(web3);464647 const cost = await recordEthFee(api, userA, () => web3.eth.sendTransaction({from: userA, to: userB, value: '1000000', ...GAS_ARGS}));47 const cost = await recordEthFee(api, userA, () => web3.eth.sendTransaction({from: userA, to: userB, value: '1000000', ...GAS_ARGS}));50 });50 });515152 itWeb3('NFT transfer is close to 0.15 UNQ', async ({web3, api, privateKeyWrapper}) => {52 itWeb3('NFT transfer is close to 0.15 UNQ', async ({web3, api, privateKeyWrapper}) => {53 const caller = await createEthAccountWithBalance(api, web3);53 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);54 const receiver = createEthAccount(web3);54 const receiver = createEthAccount(web3);555556 const alice = privateKeyWrapper('//Alice');56 const alice = privateKeyWrapper('//Alice');tests/src/eth/collectionProperties.test.tsdiffbeforeafterboth7describe('EVM collection properties', () => {7describe('EVM collection properties', () => {8 itWeb3('Can be set', async({web3, api, privateKeyWrapper}) => {8 itWeb3('Can be set', async({web3, api, privateKeyWrapper}) => {9 const alice = privateKeyWrapper('//Alice');9 const alice = privateKeyWrapper('//Alice');10 const caller = await createEthAccountWithBalance(api, web3);10 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);11 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});11 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});121213 await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});13 await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});22 });22 });23 itWeb3('Can be deleted', async({web3, api, privateKeyWrapper}) => {23 itWeb3('Can be deleted', async({web3, api, privateKeyWrapper}) => {24 const alice = privateKeyWrapper('//Alice');24 const alice = privateKeyWrapper('//Alice');25 const caller = await createEthAccountWithBalance(api, web3);25 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);26 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});26 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});272728 await executeTransaction(api, alice, api.tx.unique.setCollectionProperties(collection, [{key: 'testKey', value: 'testValue'}]));28 await executeTransaction(api, alice, api.tx.unique.setCollectionProperties(collection, [{key: 'testKey', value: 'testValue'}]));tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth44import {evmToAddress} from '@polkadot/util-crypto';44import {evmToAddress} from '@polkadot/util-crypto';454546describe('Sponsoring EVM contracts', () => {46describe('Sponsoring EVM contracts', () => {47 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {47 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {48 const owner = await createEthAccountWithBalance(api, web3);48 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);49 const flipper = await deployFlipper(web3, owner);49 const flipper = await deployFlipper(web3, owner);50 const helpers = contractHelpers(web3, owner);50 const helpers = contractHelpers(web3, owner);51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;52 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});52 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});53 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;53 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;54 });54 });555556 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {56 itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {57 const owner = await createEthAccountWithBalance(api, web3);57 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);58 const notOwner = await createEthAccountWithBalance(api, web3);58 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);59 const flipper = await deployFlipper(web3, owner);59 const flipper = await deployFlipper(web3, owner);60 const helpers = contractHelpers(web3, owner);60 const helpers = contractHelpers(web3, owner);61 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;61 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;66 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {66 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {67 const alice = privateKeyWrapper('//Alice');67 const alice = privateKeyWrapper('//Alice');686869 const owner = await createEthAccountWithBalance(api, web3);69 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);70 const caller = await createEthAccountWithBalance(api, web3);70 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);717172 const flipper = await deployFlipper(web3, owner);72 const flipper = await deployFlipper(web3, owner);737394 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => {94 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => {95 const alice = privateKeyWrapper('//Alice');95 const alice = privateKeyWrapper('//Alice');969697 const owner = await createEthAccountWithBalance(api, web3);97 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);98 const caller = createEthAccount(web3);98 const caller = createEthAccount(web3);9999100 const flipper = await deployFlipper(web3, owner);100 const flipper = await deployFlipper(web3, owner);124 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => {124 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => {125 const alice = privateKeyWrapper('//Alice');125 const alice = privateKeyWrapper('//Alice');126126127 const owner = await createEthAccountWithBalance(api, web3);127 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);128 const caller = createEthAccount(web3);128 const caller = createEthAccount(web3);129129130 const flipper = await deployFlipper(web3, owner);130 const flipper = await deployFlipper(web3, owner);152 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {152 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {153 const alice = privateKeyWrapper('//Alice');153 const alice = privateKeyWrapper('//Alice');154154155 const owner = await createEthAccountWithBalance(api, web3);155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156 const caller = await createEthAccountWithBalance(api, web3);156 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);157 const originalCallerBalance = await web3.eth.getBalance(caller);157 const originalCallerBalance = await web3.eth.getBalance(caller);158158159 const flipper = await deployFlipper(web3, owner);159 const flipper = await deployFlipper(web3, owner);181 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {181 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {182 const alice = privateKeyWrapper('//Alice');182 const alice = privateKeyWrapper('//Alice');183183184 const owner = await createEthAccountWithBalance(api, web3);184 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);185 const caller = await createEthAccountWithBalance(api, web3);185 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);186 const originalCallerBalance = await web3.eth.getBalance(caller);186 const originalCallerBalance = await web3.eth.getBalance(caller);187187188 const flipper = await deployFlipper(web3, owner);188 const flipper = await deployFlipper(web3, owner);214 });214 });215215216 // TODO: Find a way to calculate default rate limit216 // TODO: Find a way to calculate default rate limit217 itWeb3('Default rate limit equals 7200', async ({api, web3}) => {217 itWeb3('Default rate limit equals 7200', async ({api, web3, privateKeyWrapper}) => {218 const owner = await createEthAccountWithBalance(api, web3);218 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);219 const flipper = await deployFlipper(web3, owner);219 const flipper = await deployFlipper(web3, owner);220 const helpers = contractHelpers(web3, owner);220 const helpers = contractHelpers(web3, owner);221 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');221 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');222 });222 });223223224 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3}) => {224 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {225 const owner = await createEthAccountWithBalance(api, web3);225 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);226 const collectionHelpers = evmCollectionHelpers(web3, owner);226 const collectionHelpers = evmCollectionHelpers(web3, owner);227 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();227 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();228 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);228 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);229 const sponsor = await createEthAccountWithBalance(api, web3);229 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);230 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);230 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});231 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});232 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;232 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;233 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;233 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;234 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;234 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));235 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));235 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236237237 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});238 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});238 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;239 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;239 expect(collectionSub.sponsorship.isConfirmed).to.be.true;240 expect(collectionSub.sponsorship.isConfirmed).to.be.true;240 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));241 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));241242242 const user = createEthAccount(web3);243 const user = createEthAccount(web3);243 const nextTokenId = await collectionEvm.methods.nextTokenId().call();244 const nextTokenId = await collectionEvm.methods.nextTokenId().call();289 }290 }290 });291 });291292292 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3}) => {293 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {293 const owner = await createEthAccountWithBalance(api, web3);294 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);294 const collectionHelpers = evmCollectionHelpers(web3, owner);295 const collectionHelpers = evmCollectionHelpers(web3, owner);295 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();296 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();296 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);297 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);297 const sponsor = await createEthAccountWithBalance(api, web3);298 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);298 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);299 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);299 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();300 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();300 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;301 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;302 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;301 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;303 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;302 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));304 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));303 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');305 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');304 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);306 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);305 await sponsorCollection.methods.confirmCollectionSponsorship().send();307 await sponsorCollection.methods.confirmCollectionSponsorship().send();306 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;308 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;307 expect(collectionSub.sponsorship.isConfirmed).to.be.true;309 expect(collectionSub.sponsorship.isConfirmed).to.be.true;308 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));310 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));309311310 const user = createEthAccount(web3);312 const user = createEthAccount(web3);311 await collectionEvm.methods.addCollectionAdmin(user).send();313 await collectionEvm.methods.addCollectionAdmin(user).send();tests/src/eth/createCollection.test.tsdiffbeforeafterboth28} from './util/helpers';28} from './util/helpers';292930describe('Create collection from EVM', () => {30describe('Create collection from EVM', () => {31 itWeb3('Create collection', async ({api, web3}) => {31 // itWeb3('Create collection', async ({api, web3, privateKeyWrapper}) => {32 const owner = await createEthAccountWithBalance(api, web3);32 // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);33 const collectionHelper = evmCollectionHelpers(web3, owner);33 // const collectionHelper = evmCollectionHelpers(web3, owner);34 const collectionName = 'CollectionEVM';34 // const collectionName = 'CollectionEVM';35 const description = 'Some description';35 // const description = 'Some description';36 const tokenPrefix = 'token prefix';36 // const tokenPrefix = 'token prefix';37 37 38 const collectionCountBefore = await getCreatedCollectionCount(api);38 // const collectionCountBefore = await getCreatedCollectionCount(api);39 const result = await collectionHelper.methods39 // const result = await collectionHelper.methods40 .createNonfungibleCollection(collectionName, description, tokenPrefix)40 // .createNonfungibleCollection(collectionName, description, tokenPrefix)41 .send();41 // .send();42 const collectionCountAfter = await getCreatedCollectionCount(api);42 // const collectionCountAfter = await getCreatedCollectionCount(api);43 43 44 const {collectionId, collection} = await getCollectionAddressFromResult(api, result);44 // const {collectionId, collection} = await getCollectionAddressFromResult(api, result);45 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);45 // expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);46 expect(collectionId).to.be.eq(collectionCountAfter);46 // expect(collectionId).to.be.eq(collectionCountAfter);47 expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName);47 // expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName);48 expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description);48 // expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description);49 expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix);49 // expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix);50 });50 // });515152 itWeb3('Check collection address exist', async ({api, web3}) => {52 // itWeb3('Check collection address exist', async ({api, web3, privateKeyWrapper}) => {53 const owner = await createEthAccountWithBalance(api, web3);53 // const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);54 const collectionHelpers = evmCollectionHelpers(web3, owner);54 // const collectionHelpers = evmCollectionHelpers(web3, owner);55 55 56 const expectedCollectionId = await getCreatedCollectionCount(api) + 1;56 // const expectedCollectionId = await getCreatedCollectionCount(api) + 1;57 const expectedCollectionAddress = collectionIdToAddress(expectedCollectionId);57 // const expectedCollectionAddress = collectionIdToAddress(expectedCollectionId);58 expect(await collectionHelpers.methods58 // expect(await collectionHelpers.methods59 .isCollectionExist(expectedCollectionAddress)59 // .isCollectionExist(expectedCollectionAddress)60 .call()).to.be.false;60 // .call()).to.be.false;616162 await collectionHelpers.methods62 // await collectionHelpers.methods63 .createNonfungibleCollection('A', 'A', 'A')63 // .createNonfungibleCollection('A', 'A', 'A')64 .send();64 // .send();65 65 66 expect(await collectionHelpers.methods66 // expect(await collectionHelpers.methods67 .isCollectionExist(expectedCollectionAddress)67 // .isCollectionExist(expectedCollectionAddress)68 .call()).to.be.true;68 // .call()).to.be.true;69 });69 // });70 70 71 itWeb3('Set sponsorship', async ({api, web3}) => {71 itWeb3('Set sponsorship', async ({api, web3, privateKeyWrapper}) => {72 const owner = await createEthAccountWithBalance(api, web3);72 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);73 const collectionHelpers = evmCollectionHelpers(web3, owner);73 const collectionHelpers = evmCollectionHelpers(web3, owner);74 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();74 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();75 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);75 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);76 const sponsor = await createEthAccountWithBalance(api, web3);76 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);77 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);77 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);78 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();78 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();79 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;79 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;80 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;80 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;81 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;81 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));82 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));82 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');83 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');83 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);84 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);84 await sponsorCollection.methods.confirmCollectionSponsorship().send();85 await sponsorCollection.methods.confirmCollectionSponsorship().send();85 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;86 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;86 expect(collectionSub.sponsorship.isConfirmed).to.be.true;87 expect(collectionSub.sponsorship.isConfirmed).to.be.true;87 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));88 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));88 });89 });899090 itWeb3('Set limits', async ({api, web3}) => {91 itWeb3('Set limits', async ({api, web3, privateKeyWrapper}) => {91 const owner = await createEthAccountWithBalance(api, web3);92 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const collectionHelpers = evmCollectionHelpers(web3, owner);93 const collectionHelpers = evmCollectionHelpers(web3, owner);93 const result = await collectionHelpers.methods.createNonfungibleCollection('Const collection', '5', '5').send();94 const result = await collectionHelpers.methods.createNonfungibleCollection('Const collection', '5', '5').send();94 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);95 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);127 expect(collectionSub.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled);128 expect(collectionSub.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled);128 });129 });129130130 itWeb3('Collection address exist', async ({api, web3}) => {131 itWeb3('Collection address exist', async ({api, web3, privateKeyWrapper}) => {131 const owner = await createEthAccountWithBalance(api, web3);132 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);132 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';133 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';133 const collectionHelpers = evmCollectionHelpers(web3, owner);134 const collectionHelpers = evmCollectionHelpers(web3, owner);134 expect(await collectionHelpers.methods135 expect(await collectionHelpers.methods144});145});145146146describe('(!negative tests!) Create collection from EVM', () => {147describe('(!negative tests!) Create collection from EVM', () => {147 itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3}) => {148 itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3, privateKeyWrapper}) => {148 const owner = await createEthAccountWithBalance(api, web3);149 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);149 const helper = evmCollectionHelpers(web3, owner);150 const helper = evmCollectionHelpers(web3, owner);150 {151 {151 const MAX_NAME_LENGHT = 64;152 const MAX_NAME_LENGHT = 64;190 .call()).to.be.rejectedWith('NotSufficientFounds');191 .call()).to.be.rejectedWith('NotSufficientFounds');191 });192 });192193193 itWeb3('(!negative test!) Check owner', async ({api, web3}) => {194 itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => {194 const owner = await createEthAccountWithBalance(api, web3);195 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);195 const notOwner = await createEthAccount(web3);196 const notOwner = await createEthAccount(web3);196 const collectionHelpers = evmCollectionHelpers(web3, owner);197 const collectionHelpers = evmCollectionHelpers(web3, owner);197 const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send();198 const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send();198 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);199 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);199 const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress);200 const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress);200 const EXPECTED_ERROR = 'NoPermission';201 const EXPECTED_ERROR = 'NoPermission';201 {202 {202 const sponsor = await createEthAccountWithBalance(api, web3);203 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);203 await expect(contractEvmFromNotOwner.methods204 await expect(contractEvmFromNotOwner.methods204 .setCollectionSponsor(sponsor)205 .setCollectionSponsor(sponsor)205 .call()).to.be.rejectedWith(EXPECTED_ERROR);206 .call()).to.be.rejectedWith(EXPECTED_ERROR);216 }217 }217 });218 });218219219 itWeb3('(!negative test!) Set limits', async ({api, web3}) => {220 itWeb3('(!negative test!) Set limits', async ({api, web3, privateKeyWrapper}) => {220 const owner = await createEthAccountWithBalance(api, web3);221 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);221 const collectionHelpers = evmCollectionHelpers(web3, owner);222 const collectionHelpers = evmCollectionHelpers(web3, owner);222 const result = await collectionHelpers.methods.createNonfungibleCollection('Schema collection', 'A', 'A').send();223 const result = await collectionHelpers.methods.createNonfungibleCollection('Schema collection', 'A', 'A').send();223 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);224 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);tests/src/eth/crossTransfer.test.tsdiffbeforeafterboth48 });48 });49 const alice = privateKeyWrapper('//Alice');49 const alice = privateKeyWrapper('//Alice');50 const bob = privateKeyWrapper('//Bob');50 const bob = privateKeyWrapper('//Bob');51 const bobProxy = await createEthAccountWithBalance(api, web3);51 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);52 const aliceProxy = await createEthAccountWithBalance(api, web3);52 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);535354 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, alice.address);54 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, alice.address);55 await transferExpectSuccess(collection, 0, alice, {Ethereum: aliceProxy} , 200, 'Fungible');55 await transferExpectSuccess(collection, 0, alice, {Ethereum: aliceProxy} , 200, 'Fungible');85 const alice = privateKeyWrapper('//Alice');85 const alice = privateKeyWrapper('//Alice');86 const bob = privateKeyWrapper('//Bob');86 const bob = privateKeyWrapper('//Bob');87 const charlie = privateKeyWrapper('//Charlie');87 const charlie = privateKeyWrapper('//Charlie');88 const bobProxy = await createEthAccountWithBalance(api, web3);88 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);89 const aliceProxy = await createEthAccountWithBalance(api, web3);89 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);90 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});90 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});91 await transferExpectSuccess(collection, tokenId, alice, {Ethereum: aliceProxy} , 1, 'NFT');91 await transferExpectSuccess(collection, tokenId, alice, {Ethereum: aliceProxy} , 1, 'NFT');92 const address = collectionIdToAddress(collection);92 const address = collectionIdToAddress(collection);tests/src/eth/fungible.test.tsdiffbeforeafterboth27 });27 });28 const alice = privateKeyWrapper('//Alice');28 const alice = privateKeyWrapper('//Alice');292930 const caller = await createEthAccountWithBalance(api, web3);30 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);313132 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});32 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});333345 });45 });46 const alice = privateKeyWrapper('//Alice');46 const alice = privateKeyWrapper('//Alice');474748 const caller = await createEthAccountWithBalance(api, web3);48 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);494950 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});50 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});515165 });65 });66 const alice = privateKeyWrapper('//Alice');66 const alice = privateKeyWrapper('//Alice');676768 const owner = await createEthAccountWithBalance(api, web3);68 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);696970 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});70 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});7171208 });208 });209 const alice = privateKeyWrapper('//Alice');209 const alice = privateKeyWrapper('//Alice');210210211 const owner = await createEthAccountWithBalance(api, web3);211 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);212 const spender = createEthAccount(web3);212 const spender = createEthAccount(web3);213213214 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});214 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});226 });226 });227 const alice = privateKeyWrapper('//Alice');227 const alice = privateKeyWrapper('//Alice');228228229 const owner = await createEthAccountWithBalance(api, web3);229 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);230 const spender = await createEthAccountWithBalance(api, web3);230 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);231231232 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});232 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});233233246 });246 });247 const alice = privateKeyWrapper('//Alice');247 const alice = privateKeyWrapper('//Alice');248248249 const owner = await createEthAccountWithBalance(api, web3);249 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);250 const receiver = createEthAccount(web3);250 const receiver = createEthAccount(web3);251251252 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});252 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});tests/src/eth/helpersSmoke.test.tsdiffbeforeafterboth18import {createEthAccountWithBalance, deployFlipper, itWeb3, contractHelpers} from './util/helpers';18import {createEthAccountWithBalance, deployFlipper, itWeb3, contractHelpers} from './util/helpers';191920describe('Helpers sanity check', () => {20describe('Helpers sanity check', () => {21 itWeb3('Contract owner is recorded', async ({api, web3}) => {21 itWeb3('Contract owner is recorded', async ({api, web3, privateKeyWrapper}) => {22 const owner = await createEthAccountWithBalance(api, web3);22 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);232324 const flipper = await deployFlipper(web3, owner);24 const flipper = await deployFlipper(web3, owner);252526 expect(await contractHelpers(web3, owner).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner);26 expect(await contractHelpers(web3, owner).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner);27 });27 });282829 itWeb3('Flipper is working', async ({api, web3}) => {29 itWeb3('Flipper is working', async ({api, web3, privateKeyWrapper}) => {30 const owner = await createEthAccountWithBalance(api, web3);30 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);31 const flipper = await deployFlipper(web3, owner);31 const flipper = await deployFlipper(web3, owner);323233 expect(await flipper.methods.getValue().call()).to.be.false;33 expect(await flipper.methods.getValue().call()).to.be.false;tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth39describe('Matcher contract usage', () => {39describe('Matcher contract usage', () => {40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {41 const alice = privateKeyWrapper('//Alice');41 const alice = privateKeyWrapper('//Alice');42 const matcherOwner = await createEthAccountWithBalance(api, web3);42 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {43 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 from: matcherOwner,44 from: matcherOwner,45 ...GAS_ARGS,45 ...GAS_ARGS,100100101 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {101 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {102 const alice = privateKeyWrapper('//Alice');102 const alice = privateKeyWrapper('//Alice');103 const matcherOwner = await createEthAccountWithBalance(api, web3);103 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const escrow = await createEthAccountWithBalance(api, web3);104 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);105 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {105 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {106 from: matcherOwner,106 from: matcherOwner,107 ...GAS_ARGS,107 ...GAS_ARGS,171171172 itWeb3('Sell tokens from substrate user via EVM contract', async ({api, web3, privateKeyWrapper}) => {172 itWeb3('Sell tokens from substrate user via EVM contract', async ({api, web3, privateKeyWrapper}) => {173 const alice = privateKeyWrapper('//Alice');173 const alice = privateKeyWrapper('//Alice');174 const matcherOwner = await createEthAccountWithBalance(api, web3);174 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);175 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {175 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {176 from: matcherOwner,176 from: matcherOwner,177 ...GAS_ARGS,177 ...GAS_ARGS,tests/src/eth/migration.test.tsdiffbeforeafterboth54 ];54 ];555556 const alice = privateKeyWrapper('//Alice');56 const alice = privateKeyWrapper('//Alice');57 const caller = await createEthAccountWithBalance(api, web3);57 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);585859 await submitTransactionAsync(alice, api.tx.sudo.sudo(api.tx.evmMigration.begin(ADDRESS) as any));59 await submitTransactionAsync(alice, api.tx.sudo.sudo(api.tx.evmMigration.begin(ADDRESS) as any));60 await submitTransactionAsync(alice, api.tx.sudo.sudo(api.tx.evmMigration.setData(ADDRESS, DATA as any) as any));60 await submitTransactionAsync(alice, api.tx.sudo.sudo(api.tx.evmMigration.setData(ADDRESS, DATA as any) as any));tests/src/eth/nonFungible.test.tsdiffbeforeafterboth26 mode: {type: 'NFT'},26 mode: {type: 'NFT'},27 });27 });28 const alice = privateKeyWrapper('//Alice');28 const alice = privateKeyWrapper('//Alice');29 const caller = await createEthAccountWithBalance(api, web3);29 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);303031 await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});31 await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});323243 });43 });44 const alice = privateKeyWrapper('//Alice');44 const alice = privateKeyWrapper('//Alice');454546 const caller = await createEthAccountWithBalance(api, web3);46 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);47 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum:caller});47 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum:caller});48 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});48 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});49 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});49 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});61 });61 });62 const alice = privateKeyWrapper('//Alice');62 const alice = privateKeyWrapper('//Alice');636364 const caller = await createEthAccountWithBalance(api, web3);64 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});65 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});666667 const address = collectionIdToAddress(collection);67 const address = collectionIdToAddress(collection);73});73});747475describe('NFT: Plain calls', () => {75describe('NFT: Plain calls', () => {76 itWeb3('Can perform mint()', async ({web3, api}) => {76 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {77 const owner = await createEthAccountWithBalance(api, web3);77 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);78 const helper = evmCollectionHelpers(web3, owner);78 const helper = evmCollectionHelpers(web3, owner);79 let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();79 let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();80 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);80 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);119 });119 });120 const alice = privateKeyWrapper('//Alice');120 const alice = privateKeyWrapper('//Alice');121121122 const caller = await createEthAccountWithBalance(api, web3);122 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);123 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: caller});123 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: caller});124 await submitTransactionAsync(alice, changeAdminTx);124 await submitTransactionAsync(alice, changeAdminTx);125 const receiver = createEthAccount(web3);125 const receiver = createEthAccount(web3);182 });182 });183 const alice = privateKeyWrapper('//Alice');183 const alice = privateKeyWrapper('//Alice');184184185 const owner = await createEthAccountWithBalance(api, web3);185 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);186186187 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});187 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});188188341 });341 });342 const alice = privateKeyWrapper('//Alice');342 const alice = privateKeyWrapper('//Alice');343343344 const owner = await createEthAccountWithBalance(api, web3);344 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);345 const spender = createEthAccount(web3);345 const spender = createEthAccount(web3);346346347 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});347 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});359 });359 });360 const alice = privateKeyWrapper('//Alice');360 const alice = privateKeyWrapper('//Alice');361361362 const owner = await createEthAccountWithBalance(api, web3);362 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);363 const spender = await createEthAccountWithBalance(api, web3);363 const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);364364365 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});365 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});366366379 });379 });380 const alice = privateKeyWrapper('//Alice');380 const alice = privateKeyWrapper('//Alice');381381382 const owner = await createEthAccountWithBalance(api, web3);382 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);383 const receiver = createEthAccount(web3);383 const receiver = createEthAccount(web3);384384385 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});385 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});541});541});542542543describe('Common metadata', () => {543describe('Common metadata', () => {544 itWeb3('Returns collection name', async ({api, web3}) => {544 itWeb3('Returns collection name', async ({api, web3, privateKeyWrapper}) => {545 const collection = await createCollectionExpectSuccess({545 const collection = await createCollectionExpectSuccess({546 name: 'token name',546 name: 'token name',547 mode: {type: 'NFT'},547 mode: {type: 'NFT'},548 });548 });549 const caller = await createEthAccountWithBalance(api, web3);549 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);550550551 const address = collectionIdToAddress(collection);551 const address = collectionIdToAddress(collection);552 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});552 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});555 expect(name).to.equal('token name');555 expect(name).to.equal('token name');556 });556 });557557558 itWeb3('Returns symbol name', async ({api, web3}) => {558 itWeb3('Returns symbol name', async ({api, web3, privateKeyWrapper}) => {559 const collection = await createCollectionExpectSuccess({559 const collection = await createCollectionExpectSuccess({560 tokenPrefix: 'TOK',560 tokenPrefix: 'TOK',561 mode: {type: 'NFT'},561 mode: {type: 'NFT'},562 });562 });563 const caller = await createEthAccountWithBalance(api, web3);563 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);564564565 const address = collectionIdToAddress(collection);565 const address = collectionIdToAddress(collection);566 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});566 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});tests/src/eth/payable.test.tsdiffbeforeafterboth22import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance';22import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance';232324describe('EVM payable contracts', () => {24describe('EVM payable contracts', () => {25 itWeb3('Evm contract can receive wei from eth account', async ({api, web3}) => {25 itWeb3('Evm contract can receive wei from eth account', async ({api, web3, privateKeyWrapper}) => {26 const deployer = await createEthAccountWithBalance(api, web3);26 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);27 const contract = await deployCollector(web3, deployer);27 const contract = await deployCollector(web3, deployer);282829 await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', ...GAS_ARGS});29 await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', ...GAS_ARGS});32 });32 });333334 itWeb3('Evm contract can receive wei from substrate account', async ({api, web3, privateKeyWrapper}) => {34 itWeb3('Evm contract can receive wei from substrate account', async ({api, web3, privateKeyWrapper}) => {35 const deployer = await createEthAccountWithBalance(api, web3);35 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);36 const contract = await deployCollector(web3, deployer);36 const contract = await deployCollector(web3, deployer);37 const alice = privateKeyWrapper('//Alice');37 const alice = privateKeyWrapper('//Alice');3838626263 // We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible63 // We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible64 itWeb3('Wei sent directly to backing storage of evm contract balance is unaccounted', async({api, web3, privateKeyWrapper}) => {64 itWeb3('Wei sent directly to backing storage of evm contract balance is unaccounted', async({api, web3, privateKeyWrapper}) => {65 const deployer = await createEthAccountWithBalance(api, web3);65 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);66 const contract = await deployCollector(web3, deployer);66 const contract = await deployCollector(web3, deployer);67 const alice = privateKeyWrapper('//Alice');67 const alice = privateKeyWrapper('//Alice');686875 const FEE_BALANCE = 1000n * UNIQUE;75 const FEE_BALANCE = 1000n * UNIQUE;76 const CONTRACT_BALANCE = 1n * UNIQUE;76 const CONTRACT_BALANCE = 1n * UNIQUE;777778 const deployer = await createEthAccountWithBalance(api, web3);78 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);79 const contract = await deployCollector(web3, deployer);79 const contract = await deployCollector(web3, deployer);80 const alice = privateKeyWrapper('//Alice');80 const alice = privateKeyWrapper('//Alice');8181tests/src/eth/proxy/fungibleProxy.test.tsdiffbeforeafterboth21import {ApiPromise} from '@polkadot/api';21import {ApiPromise} from '@polkadot/api';22import Web3 from 'web3';22import Web3 from 'web3';23import {readFile} from 'fs/promises';23import {readFile} from 'fs/promises';24import {IKeyringPair} from '@polkadot/types/types';242525async function proxyWrap(api: ApiPromise, web3: Web3, wrapped: any) {26async function proxyWrap(api: ApiPromise, web3: Web3, wrapped: any, privateKeyWrapper: (account: string) => IKeyringPair) {26 // Proxy owner has no special privilegies, we don't need to reuse them27 // Proxy owner has no special privilegies, we don't need to reuse them27 const owner = await createEthAccountWithBalance(api, web3);28 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);28 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {29 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueFungibleProxy.abi`)).toString()), undefined, {29 from: owner,30 from: owner,30 ...GAS_ARGS,31 ...GAS_ARGS,40 mode: {type: 'Fungible', decimalPoints: 0},41 mode: {type: 'Fungible', decimalPoints: 0},41 });42 });42 const alice = privateKeyWrapper('//Alice');43 const alice = privateKeyWrapper('//Alice');43 const caller = await createEthAccountWithBalance(api, web3);44 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);444545 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});46 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});464747 const address = collectionIdToAddress(collection);48 const address = collectionIdToAddress(collection);48 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}));49 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);49 const totalSupply = await contract.methods.totalSupply().call();50 const totalSupply = await contract.methods.totalSupply().call();505151 expect(totalSupply).to.equal('200');52 expect(totalSupply).to.equal('200');57 mode: {type: 'Fungible', decimalPoints: 0},58 mode: {type: 'Fungible', decimalPoints: 0},58 });59 });59 const alice = privateKeyWrapper('//Alice');60 const alice = privateKeyWrapper('//Alice');60 const caller = await createEthAccountWithBalance(api, web3);61 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);616262 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});63 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: caller});636464 const address = collectionIdToAddress(collection);65 const address = collectionIdToAddress(collection);65 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}));66 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);66 const balance = await contract.methods.balanceOf(caller).call();67 const balance = await contract.methods.balanceOf(caller).call();676868 expect(balance).to.equal('200');69 expect(balance).to.equal('200');76 mode: {type: 'Fungible', decimalPoints: 0},77 mode: {type: 'Fungible', decimalPoints: 0},77 });78 });78 const alice = privateKeyWrapper('//Alice');79 const alice = privateKeyWrapper('//Alice');79 const caller = await createEthAccountWithBalance(api, web3);80 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);80 const spender = createEthAccount(web3);81 const spender = createEthAccount(web3);818282 const address = collectionIdToAddress(collection);83 const address = collectionIdToAddress(collection);83 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}));84 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);84 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: contract.options.address});85 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: contract.options.address});858686 {87 {112 mode: {type: 'Fungible', decimalPoints: 0},113 mode: {type: 'Fungible', decimalPoints: 0},113 });114 });114 const alice = privateKeyWrapper('//Alice');115 const alice = privateKeyWrapper('//Alice');115 const caller = await createEthAccountWithBalance(api, web3);116 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);116 const owner = await createEthAccountWithBalance(api, web3);117 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);117118118 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});119 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});119120120 const receiver = createEthAccount(web3);121 const receiver = createEthAccount(web3);121122122 const address = collectionIdToAddress(collection);123 const address = collectionIdToAddress(collection);123 const evmCollection = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});124 const evmCollection = new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS});124 const contract = await proxyWrap(api, web3, evmCollection);125 const contract = await proxyWrap(api, web3, evmCollection, privateKeyWrapper);125126126 await evmCollection.methods.approve(contract.options.address, 100).send({from: owner});127 await evmCollection.methods.approve(contract.options.address, 100).send({from: owner});127128167 mode: {type: 'Fungible', decimalPoints: 0},168 mode: {type: 'Fungible', decimalPoints: 0},168 });169 });169 const alice = privateKeyWrapper('//Alice');170 const alice = privateKeyWrapper('//Alice');170 const caller = await createEthAccountWithBalance(api, web3);171 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);171 const receiver = await createEthAccountWithBalance(api, web3);172 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);172173173 const address = collectionIdToAddress(collection);174 const address = collectionIdToAddress(collection);174 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}));175 const contract = await proxyWrap(api, web3, new web3.eth.Contract(fungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);175 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: contract.options.address});176 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: contract.options.address});176177177 {178 {tests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth22import Web3 from 'web3';22import Web3 from 'web3';23import {readFile} from 'fs/promises';23import {readFile} from 'fs/promises';24import {ApiPromise} from '@polkadot/api';24import {ApiPromise} from '@polkadot/api';25import {IKeyringPair} from '@polkadot/types/types';252626async function proxyWrap(api: ApiPromise, web3: Web3, wrapped: any) {27async function proxyWrap(api: ApiPromise, web3: Web3, wrapped: any, privateKeyWrapper: (account: string) => IKeyringPair) {27 // Proxy owner has no special privilegies, we don't need to reuse them28 // Proxy owner has no special privilegies, we don't need to reuse them28 const owner = await createEthAccountWithBalance(api, web3);29 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);29 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {30 const proxyContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/UniqueNFTProxy.abi`)).toString()), undefined, {30 from: owner,31 from: owner,31 ...GAS_ARGS,32 ...GAS_ARGS,40 mode: {type: 'NFT'},41 mode: {type: 'NFT'},41 });42 });42 const alice = privateKeyWrapper('//Alice');43 const alice = privateKeyWrapper('//Alice');43 const caller = await createEthAccountWithBalance(api, web3);44 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);444545 await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});46 await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});464747 const address = collectionIdToAddress(collection);48 const address = collectionIdToAddress(collection);48 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));49 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);49 const totalSupply = await contract.methods.totalSupply().call();50 const totalSupply = await contract.methods.totalSupply().call();505151 expect(totalSupply).to.equal('1');52 expect(totalSupply).to.equal('1');57 });58 });58 const alice = privateKeyWrapper('//Alice');59 const alice = privateKeyWrapper('//Alice');596060 const caller = await createEthAccountWithBalance(api, web3);61 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);61 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});62 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});62 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});63 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});63 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});64 await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});646565 const address = collectionIdToAddress(collection);66 const address = collectionIdToAddress(collection);66 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));67 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);67 const balance = await contract.methods.balanceOf(caller).call();68 const balance = await contract.methods.balanceOf(caller).call();686969 expect(balance).to.equal('3');70 expect(balance).to.equal('3');75 });76 });76 const alice = privateKeyWrapper('//Alice');77 const alice = privateKeyWrapper('//Alice');777878 const caller = await createEthAccountWithBalance(api, web3);79 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);79 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});80 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});808181 const address = collectionIdToAddress(collection);82 const address = collectionIdToAddress(collection);82 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));83 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);83 const owner = await contract.methods.ownerOf(tokenId).call();84 const owner = await contract.methods.ownerOf(tokenId).call();848585 expect(owner).to.equal(caller);86 expect(owner).to.equal(caller);86 });87 });87});88});888989describe('NFT (Via EVM proxy): Plain calls', () => {90describe('NFT (Via EVM proxy): Plain calls', () => {90 itWeb3('Can perform mint()', async ({web3, api}) => {91 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {91 const owner = await createEthAccountWithBalance(api, web3);92 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const collectionHelper = evmCollectionHelpers(web3, owner);93 const collectionHelper = evmCollectionHelpers(web3, owner);93 const result = await collectionHelper.methods94 const result = await collectionHelper.methods94 .createNonfungibleCollection('A', 'A', 'A')95 .createNonfungibleCollection('A', 'A', 'A')95 .send();96 .send();96 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);97 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);97 const caller = await createEthAccountWithBalance(api, web3);98 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);98 const receiver = createEthAccount(web3);99 const receiver = createEthAccount(web3);99 const collectionEvmOwned = evmCollection(web3, owner, collectionIdAddress);100 const collectionEvmOwned = evmCollection(web3, owner, collectionIdAddress);100 const collectionEvm = evmCollection(web3, caller, collectionIdAddress);101 const collectionEvm = evmCollection(web3, caller, collectionIdAddress);101 const contract = await proxyWrap(api, web3, collectionEvm);102 const contract = await proxyWrap(api, web3, collectionEvm, privateKeyWrapper);102 await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send();103 await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send();103104104 {105 {135 });136 });136 const alice = privateKeyWrapper('//Alice');137 const alice = privateKeyWrapper('//Alice');137138138 const caller = await createEthAccountWithBalance(api, web3);139 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);139 const receiver = createEthAccount(web3);140 const receiver = createEthAccount(web3);140141141 const address = collectionIdToAddress(collection);142 const address = collectionIdToAddress(collection);142 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));143 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);143 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: contract.options.address});144 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: contract.options.address});144 await submitTransactionAsync(alice, changeAdminTx);145 await submitTransactionAsync(alice, changeAdminTx);145146197 mode: {type: 'NFT'},198 mode: {type: 'NFT'},198 });199 });199 const alice = privateKeyWrapper('//Alice');200 const alice = privateKeyWrapper('//Alice');200 const caller = await createEthAccountWithBalance(api, web3);201 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);201202202 const address = collectionIdToAddress(collection);203 const address = collectionIdToAddress(collection);203 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));204 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);204 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});205 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});205206206 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: contract.options.address});207 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: contract.options.address});229 mode: {type: 'NFT'},230 mode: {type: 'NFT'},230 });231 });231 const alice = privateKeyWrapper('//Alice');232 const alice = privateKeyWrapper('//Alice');232 const caller = await createEthAccountWithBalance(api, web3);233 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);233 const spender = createEthAccount(web3);234 const spender = createEthAccount(web3);234235235 const address = collectionIdToAddress(collection);236 const address = collectionIdToAddress(collection);236 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address));237 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address), privateKeyWrapper);237 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});238 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});238239239 {240 {259 mode: {type: 'NFT'},260 mode: {type: 'NFT'},260 });261 });261 const alice = privateKeyWrapper('//Alice');262 const alice = privateKeyWrapper('//Alice');262 const caller = await createEthAccountWithBalance(api, web3);263 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);263 const owner = await createEthAccountWithBalance(api, web3);264 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);264265265 const receiver = createEthAccount(web3);266 const receiver = createEthAccount(web3);266267267 const address = collectionIdToAddress(collection);268 const address = collectionIdToAddress(collection);268 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});269 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});269 const contract = await proxyWrap(api, web3, evmCollection);270 const contract = await proxyWrap(api, web3, evmCollection, privateKeyWrapper);270 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});271 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});271272272 await evmCollection.methods.approve(contract.options.address, tokenId).send({from: owner});273 await evmCollection.methods.approve(contract.options.address, tokenId).send({from: owner});303 mode: {type: 'NFT'},304 mode: {type: 'NFT'},304 });305 });305 const alice = privateKeyWrapper('//Alice');306 const alice = privateKeyWrapper('//Alice');306 const caller = await createEthAccountWithBalance(api, web3);307 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);307 const receiver = createEthAccount(web3);308 const receiver = createEthAccount(web3);308309309 const address = collectionIdToAddress(collection);310 const address = collectionIdToAddress(collection);310 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}));311 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}), privateKeyWrapper);311 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});312 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});312313313 {314 {tests/src/eth/scheduling.test.tsdiffbeforeafterboth17import {expect} from 'chai';17import {expect} from 'chai';18import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';18import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';19import {scheduleExpectSuccess, waitNewBlocks} from '../util/helpers';19import {scheduleExpectSuccess, waitNewBlocks} from '../util/helpers';20import privateKey from '../substrate/privateKey';212022describe('Scheduing EVM smart contracts', () => {21describe('Scheduing EVM smart contracts', () => {23 itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3}) => {22 itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3, privateKeyWrapper}) => {24 const deployer = await createEthAccountWithBalance(api, web3);23 const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);25 const flipper = await deployFlipper(web3, deployer);24 const flipper = await deployFlipper(web3, deployer);26 const initialValue = await flipper.methods.getValue().call();25 const initialValue = await flipper.methods.getValue().call();27 const alice = privateKey('//Alice');26 const alice = privateKeyWrapper('//Alice');28 await transferBalanceToEth(api, alice, subToEth(alice.address));27 await transferBalanceToEth(api, alice, subToEth(alice.address));292830 {29 {tests/src/eth/sponsoring.test.tsdiffbeforeafterboth21 itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => {21 itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => {22 const alice = privateKeyWrapper('//Alice');22 const alice = privateKeyWrapper('//Alice');232324 const owner = await createEthAccountWithBalance(api, web3);24 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);25 const caller = createEthAccount(web3);25 const caller = createEthAccount(web3);26 const originalCallerBalance = await web3.eth.getBalance(caller);26 const originalCallerBalance = await web3.eth.getBalance(caller);27 expect(originalCallerBalance).to.be.equal('0');27 expect(originalCallerBalance).to.be.equal('0');52 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {52 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {53 const alice = privateKeyWrapper('//Alice');53 const alice = privateKeyWrapper('//Alice');545455 const owner = await createEthAccountWithBalance(api, web3);55 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);56 const caller = await createEthAccountWithBalance(api, web3);56 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);57 const originalCallerBalance = await web3.eth.getBalance(caller);57 const originalCallerBalance = await web3.eth.getBalance(caller);58 expect(originalCallerBalance).to.be.not.equal('0');58 expect(originalCallerBalance).to.be.not.equal('0');5959tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth7describe('EVM token properties', () => {7describe('EVM token properties', () => {8 itWeb3('Can be reconfigured', async({web3, api, privateKeyWrapper}) => {8 itWeb3('Can be reconfigured', async({web3, api, privateKeyWrapper}) => {9 const alice = privateKeyWrapper('//Alice');9 const alice = privateKeyWrapper('//Alice');10 const caller = await createEthAccountWithBalance(api, web3);10 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);11 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {11 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {12 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});12 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});13 await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});13 await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller});25 });25 });26 itWeb3('Can be set', async({web3, api, privateKeyWrapper}) => {26 itWeb3('Can be set', async({web3, api, privateKeyWrapper}) => {27 const alice = privateKeyWrapper('//Alice');27 const alice = privateKeyWrapper('//Alice');28 const caller = await createEthAccountWithBalance(api, web3);28 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);29 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});29 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});30 const token = await createItemExpectSuccess(alice, collection, 'NFT');30 const token = await createItemExpectSuccess(alice, collection, 'NFT');313148 });48 });49 itWeb3('Can be deleted', async({web3, api, privateKeyWrapper}) => {49 itWeb3('Can be deleted', async({web3, api, privateKeyWrapper}) => {50 const alice = privateKeyWrapper('//Alice');50 const alice = privateKeyWrapper('//Alice');51 const caller = await createEthAccountWithBalance(api, web3);51 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);52 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});52 const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});53 const token = await createItemExpectSuccess(alice, collection, 'NFT');53 const token = await createItemExpectSuccess(alice, collection, 'NFT');5454tests/src/eth/util/helpers.tsdiffbeforeafterboth112 return account.address;112 return account.address;113}113}114114115export async function createEthAccountWithBalance(api: ApiPromise, web3: Web3) {115export async function createEthAccountWithBalance(api: ApiPromise, web3: Web3, privateKeyWrapper: (account: string) => IKeyringPair) {116 const alice = privateKey('//Alice');116 const alice = privateKeyWrapper('//Alice');117 const account = createEthAccount(web3);117 const account = createEthAccount(web3);118 await transferBalanceToEth(api, alice, account);118 await transferBalanceToEth(api, alice, account);119119tests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth46 });46 });47 });47 });4849 it('Remove collection admin by admin.', async () => {50 await usingApi(async (api, privateKeyWrapper) => {51 const collectionId = await createCollectionExpectSuccess();52 const alice = privateKeyWrapper('//Alice');53 const bob = privateKeyWrapper('//Bob');54 const charlie = privateKeyWrapper('//Charlie');55 const collection = await queryCollectionExpectSuccess(api, collectionId);56 expect(collection.owner.toString()).to.be.eq(alice.address);57 // first - add collection admin Bob58 const addAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));59 await submitTransactionAsync(alice, addAdminTx);6061 const addAdminTx2 = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));62 await submitTransactionAsync(alice, addAdminTx2);6364 const adminListAfterAddAdmin = await getAdminList(api, collectionId);65 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));6667 // then remove bob from admins of collection68 const removeAdminTx = api.tx.unique.removeCollectionAdmin(collectionId, normalizeAccountId(bob.address));69 await submitTransactionAsync(charlie, removeAdminTx);7071 const adminListAfterRemoveAdmin = await getAdminList(api, collectionId);72 expect(adminListAfterRemoveAdmin).not.to.be.deep.contains(normalizeAccountId(bob.address));73 });74 });754876 it('Remove admin from collection that has no admins', async () => {49 it('Remove admin from collection that has no admins', async () => {77 await usingApi(async (api, privateKeyWrapper) => {50 await usingApi(async (api, privateKeyWrapper) => {120 });93 });121 });94 });12295123 it('Regular user Can\'t remove collection admin', async () => {96 it('Regular user can\'t remove collection admin', async () => {124 await usingApi(async (api, privateKeyWrapper) => {97 await usingApi(async (api, privateKeyWrapper) => {125 const collectionId = await createCollectionExpectSuccess();98 const collectionId = await createCollectionExpectSuccess();126 const alice = privateKeyWrapper('//Alice');99 const alice = privateKeyWrapper('//Alice');138 });111 });139 });112 });113114 it('Admin can\'t remove collection admin.', async () => {115 await usingApi(async (api, privateKeyWrapper) => {116 const collectionId = await createCollectionExpectSuccess();117 const alice = privateKeyWrapper('//Alice');118 const bob = privateKeyWrapper('//Bob');119 const charlie = privateKeyWrapper('//Charlie');120121 const adminListAfterAddAdmin = await getAdminList(api, collectionId);122 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));123124 const removeAdminTx = api.tx.unique.removeCollectionAdmin(collectionId, normalizeAccountId(bob.address));125 await expect(submitTransactionAsync(charlie, removeAdminTx)).to.be.rejected;126127 const adminListAfterRemoveAdmin = await getAdminList(api, collectionId);128 expect(adminListAfterRemoveAdmin).to.be.deep.contains(normalizeAccountId(bob.address));129 expect(adminListAfterRemoveAdmin).to.be.deep.contains(normalizeAccountId(charlie.address));130 });131 });140});132});141133tests/src/rmrk/rmrk.test.tsdiffbeforeafterboth494950describe('RMRK External Integration Test', () => {50describe('RMRK External Integration Test', () => {51 before(async () => {51 before(async () => {52 await usingApi(async () => {52 await usingApi(async (api, privateKeyWrapper) => {53 alice = privateKey('//Alice');53 alice = privateKeyWrapper('//Alice');54 });54 });55 });55 });565675 let rmrkNftId: number;75 let rmrkNftId: number;767677 before(async () => {77 before(async () => {78 await usingApi(async api => {78 await usingApi(async (api, privateKeyWrapper) => {79 alice = privateKey('//Alice');79 alice = privateKeyWrapper('//Alice');80 bob = privateKey('//Bob');80 bob = privateKeyWrapper('//Bob');818182 const collectionIds = await createRmrkCollection(api, alice);82 const collectionIds = await createRmrkCollection(api, alice);83 uniqueCollectionId = collectionIds.uniqueId;83 uniqueCollectionId = collectionIds.uniqueId;210 let nftId: number;210 let nftId: number;211211212 before(async () => {212 before(async () => {213 await usingApi(async () => {213 await usingApi(async (api, privateKeyWrapper) => {214 alice = privateKey('//Alice');214 alice = privateKeyWrapper('//Alice');215 bob = privateKey('//Bob');215 bob = privateKeyWrapper('//Bob');216216217 collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});217 collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});218 nftId = await createItemExpectSuccess(alice, collectionId, 'NFT');218 nftId = await createItemExpectSuccess(alice, collectionId, 'NFT');tests/src/rpc.load.tsdiffbeforeafterboth59 const deployer = await findUnusedAddress(api, privateKeyWrapper);59 const deployer = await findUnusedAddress(api, privateKeyWrapper);606061 // Transfer balance to it61 // Transfer balance to it62 const keyring = new Keyring({type: 'sr25519'});63 const alice = keyring.addFromUri('//Alice');62 const alice = privateKeyWrapper('//Alice');64 const amount = BigInt(endowment) + 10n**15n;63 const amount = BigInt(endowment) + 10n**15n;65 const tx = api.tx.balances.transfer(deployer.address, amount);64 const tx = api.tx.balances.transfer(deployer.address, amount);66 await submitTransactionAsync(alice, tx);65 await submitTransactionAsync(alice, tx);tests/src/scheduler.test.tsdiffbeforeafterboth161617import chai, {expect} from 'chai';17import chai, {expect} from 'chai';18import chaiAsPromised from 'chai-as-promised';18import chaiAsPromised from 'chai-as-promised';19import privateKey from './substrate/privateKey';20import {19import {21 default as usingApi, 20 default as usingApi, 22 submitTransactionAsync,21 submitTransactionAsync,52 let scheduledIdSlider: number;51 let scheduledIdSlider: number;535254 before(async() => {53 before(async() => {55 await usingApi(async () => {54 await usingApi(async (api, privateKeyWrapper) => {56 alice = privateKey('//Alice');55 alice = privateKeyWrapper('//Alice');57 bob = privateKey('//Bob');56 bob = privateKeyWrapper('//Bob');58 });57 });595860 scheduledIdBase = '0x' + '0'.repeat(31);59 scheduledIdBase = '0x' + '0'.repeat(31);