difftreelog
Merge pull request #469 from UniqueNetwork/feature/refactor_contract_sponsoring
in: master
Feature/refactor contract sponsoring
19 files changed
Cargo.lockdiffbeforeafterboth2345[[package]]2345[[package]]2346name = "fc-consensus"2346name = "fc-consensus"2347version = "2.0.0-dev"2347version = "2.0.0-dev"2348source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2348source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2349dependencies = [2349dependencies = [2350 "async-trait",2350 "async-trait",2351 "fc-db",2351 "fc-db",2364[[package]]2364[[package]]2365name = "fc-db"2365name = "fc-db"2366version = "2.0.0-dev"2366version = "2.0.0-dev"2367source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2367source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2368dependencies = [2368dependencies = [2369 "fp-storage",2369 "fp-storage",2370 "kvdb-rocksdb",2370 "kvdb-rocksdb",2380[[package]]2380[[package]]2381name = "fc-mapping-sync"2381name = "fc-mapping-sync"2382version = "2.0.0-dev"2382version = "2.0.0-dev"2383source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2383source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2384dependencies = [2384dependencies = [2385 "fc-db",2385 "fc-db",2386 "fp-consensus",2386 "fp-consensus",2397[[package]]2397[[package]]2398name = "fc-rpc"2398name = "fc-rpc"2399version = "2.0.0-dev"2399version = "2.0.0-dev"2400source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2400source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2401dependencies = [2401dependencies = [2402 "ethereum",2402 "ethereum",2403 "ethereum-types",2403 "ethereum-types",2437[[package]]2437[[package]]2438name = "fc-rpc-core"2438name = "fc-rpc-core"2439version = "1.1.0-dev"2439version = "1.1.0-dev"2440source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2440source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2441dependencies = [2441dependencies = [2442 "ethereum",2442 "ethereum",2443 "ethereum-types",2443 "ethereum-types",2578[[package]]2578[[package]]2579name = "fp-consensus"2579name = "fp-consensus"2580version = "2.0.0-dev"2580version = "2.0.0-dev"2581source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2581source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2582dependencies = [2582dependencies = [2583 "ethereum",2583 "ethereum",2584 "parity-scale-codec 3.1.5",2584 "parity-scale-codec 3.1.5",2590[[package]]2590[[package]]2591name = "fp-evm"2591name = "fp-evm"2592version = "3.0.0-dev"2592version = "3.0.0-dev"2593source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2593source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2594dependencies = [2594dependencies = [2595 "evm",2595 "evm",2596 "frame-support",2596 "frame-support",2604[[package]]2604[[package]]2605name = "fp-evm-mapping"2605name = "fp-evm-mapping"2606version = "0.1.0"2606version = "0.1.0"2607source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2607source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2608dependencies = [2608dependencies = [2609 "frame-support",2609 "frame-support",2610 "sp-core",2610 "sp-core",2613[[package]]2613[[package]]2614name = "fp-rpc"2614name = "fp-rpc"2615version = "3.0.0-dev"2615version = "3.0.0-dev"2616source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2616source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2617dependencies = [2617dependencies = [2618 "ethereum",2618 "ethereum",2619 "ethereum-types",2619 "ethereum-types",2630[[package]]2630[[package]]2631name = "fp-self-contained"2631name = "fp-self-contained"2632version = "1.0.0-dev"2632version = "1.0.0-dev"2633source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2633source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2634dependencies = [2634dependencies = [2635 "ethereum",2635 "ethereum",2636 "frame-support",2636 "frame-support",2646[[package]]2646[[package]]2647name = "fp-storage"2647name = "fp-storage"2648version = "2.0.0"2648version = "2.0.0"2649source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2649source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2650dependencies = [2650dependencies = [2651 "parity-scale-codec 3.1.5",2651 "parity-scale-codec 3.1.5",2652]2652]5445[[package]]5445[[package]]5446name = "pallet-base-fee"5446name = "pallet-base-fee"5447version = "1.0.0"5447version = "1.0.0"5448source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5448source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5449dependencies = [5449dependencies = [5450 "fp-evm",5450 "fp-evm",5451 "frame-support",5451 "frame-support",555255525553[[package]]5553[[package]]5554name = "pallet-common"5554name = "pallet-common"5555version = "0.1.6"5555version = "0.1.7"5556dependencies = [5556dependencies = [5557 "ethereum",5557 "ethereum",5558 "evm-coder",5558 "evm-coder",5660[[package]]5660[[package]]5661name = "pallet-ethereum"5661name = "pallet-ethereum"5662version = "4.0.0-dev"5662version = "4.0.0-dev"5663source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5663source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5664dependencies = [5664dependencies = [5665 "ethereum",5665 "ethereum",5666 "ethereum-types",5666 "ethereum-types",5689[[package]]5689[[package]]5690name = "pallet-evm"5690name = "pallet-evm"5691version = "6.0.0-dev"5691version = "6.0.0-dev"5692source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5692source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5693dependencies = [5693dependencies = [5694 "evm",5694 "evm",5695 "fp-evm",5695 "fp-evm",573357335734[[package]]5734[[package]]5735name = "pallet-evm-contract-helpers"5735name = "pallet-evm-contract-helpers"5736version = "0.1.2"5736version = "0.2.0"5737dependencies = [5737dependencies = [5738 "evm-coder",5738 "evm-coder",5739 "fp-evm-mapping",5739 "fp-evm-mapping",12130source = "registry+https://github.com/rust-lang/crates.io-index"12130source = "registry+https://github.com/rust-lang/crates.io-index"12131checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"12131checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"12132dependencies = [12132dependencies = [12133 "cfg-if 1.0.0",12133 "cfg-if 0.1.10",12134 "digest 0.10.3",12134 "digest 0.10.3",12135 "rand 0.8.5",12135 "rand 0.8.5",12136 "static_assertions",12136 "static_assertions",crates/evm-coder/CHANGELOG.mddiffbeforeafterboth1# Change Log23All notable changes to this project will be documented in this file.1<!-- bureaucrate goes here -->4## [v0.1.2] 2022-08-1956### Added78 - Implementation `AbiWrite` for tuples.910 ### Fixes1112 - Tuple generation for solidity.132## [v0.1.1] 2022-08-1614## [v0.1.1] 2022-08-16315crates/evm-coder/src/abi.rsdiffbeforeafterboth342 ))342 ))343 }343 }344 }344 }345 #[allow(non_snake_case)]346 impl<$($ident),+> AbiWrite for &($($ident,)+)347 where348 $($ident: AbiWrite,)+349 {350 fn abi_write(&self, writer: &mut AbiWriter) {351 let ($($ident,)+) = self;352 $($ident.abi_write(writer);)+353 }354 }345 };355 };346}356}347357crates/evm-coder/src/solidity.rsdiffbeforeafterboth180 fn is_simple() -> bool {180 fn is_simple() -> bool {181 false181 false182 }182 }183 #[allow(unused_assignments)]183 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {184 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {184 write!(writer, "{}(", tc.collect_tuple::<Self>())?;185 write!(writer, "{}(", tc.collect_tuple::<Self>())?;186 let mut first = true;185 $(187 $(188 if !first {189 write!(writer, ",")?;190 } else {191 first = false;192 }186 <$ident>::solidity_default(writer, tc)?;193 <$ident>::solidity_default(writer, tc)?;187 )*194 )*188 write!(writer, ")")195 write!(writer, ")")pallets/common/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [0.1.7] - 2022-08-1967### Added89 - Add convert funtion from `CrossAccountId` to eth `uint256`.1011 5## [0.1.6] - 2022-08-1612## [0.1.6] - 2022-08-166137### Added14### Addedpallets/common/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-common"2name = "pallet-common"3version = "0.1.6"3version = "0.1.7"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/common/src/eth.rsdiffbeforeafterboth161617//! The module contains a number of functions for converting and checking ethereum identifiers.17//! The module contains a number of functions for converting and checking ethereum identifiers.181819use evm_coder::{types::*};19use evm_coder::types::uint256;20pub use pallet_evm::account::CrossAccountId;20pub use pallet_evm::account::{Config, CrossAccountId};21use sp_core::H160;21use sp_core::H160;22use up_data_structs::CollectionId;22use up_data_structs::CollectionId;2324use crate::Config;252326// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 124// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 127// TODO: Unhardcode prefix25// TODO: Unhardcode prefix52 address[0..16] == ETH_COLLECTION_PREFIX50 address[0..16] == ETH_COLLECTION_PREFIX53}51}5253/// Convert `CrossAccountId` to `uint256`.54pub fn convert_cross_account_to_uint256<T: Config>(from: &T::CrossAccountId) -> uint25655where56 T::AccountId: AsRef<[u8; 32]>,57{58 let slice = from.as_sub().as_ref();59 uint256::from_big_endian(slice)60}546155/// Converts Substrate address to CrossAccountId62/// Converts Substrate address to CrossAccountId56pub fn convert_substrate_address_to_cross_account_id<T: Config>(63pub fn convert_substrate_address_to_cross_account_id<T: Config>(pallets/evm-contract-helpers/CHANGELOG.mddiffbeforeafterboth1# Change Log23All notable changes to this project will be documented in this file.41<!-- bureaucrate goes here -->5## [v0.2.0] - 2022-08-1967### Added89 - Set arbitrary evm address as contract sponsor.10 - Ability to remove current sponsor.1112### Removed13 - Remove methods14 + sponsoring_enabled15 + toggle_sponsoring1617 ### Changed1819 - Change `toggle_sponsoring` to `self_sponsored_enable`.20212## [v0.1.2] 2022-08-1622## [v0.1.2] 2022-08-16323pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-evm-contract-helpers"2name = "pallet-evm-contract-helpers"3version = "0.1.2"3version = "0.2.0"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth161617use core::marker::PhantomData;17use core::marker::PhantomData;18use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};18use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};19use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};19use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};20use pallet_evm::{20use pallet_evm::{21 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,21 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,22 account::CrossAccountId,22 account::CrossAccountId,23};23};24use sp_core::H160;24use sp_core::H160;25use up_data_structs::SponsorshipState;25use crate::{26use crate::{26 AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,27 AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,28 Sponsoring,27};29};28use frame_support::traits::Get;30use frame_support::traits::Get;29use up_sponsorship::SponsorshipHandler;31use up_sponsorship::SponsorshipHandler;424443#[solidity_interface(name = "ContractHelpers")]45#[solidity_interface(name = "ContractHelpers")]44impl<T: Config> ContractHelpers<T> {46impl<T: Config> ContractHelpers<T>47where48 T::AccountId: AsRef<[u8; 32]>,49{50 /// Get contract ovner51 ///52 /// @param Contract_address contract for which the owner is being determined.53 /// @return Contract owner.45 fn contract_owner(&self, contract_address: address) -> Result<address> {54 fn contract_owner(&self, contract_address: address) -> Result<address> {46 Ok(<Owner<T>>::get(contract_address))55 Ok(<Owner<T>>::get(contract_address))47 }56 }485758 /// Set sponsor.59 ///60 /// @param contract_address Contract for which a sponsor is being established.61 /// @param sponsor User address who set as pending sponsor.62 fn set_sponsor(63 &mut self,64 caller: caller,65 contract_address: address,66 sponsor: address,67 ) -> Result<void> {68 self.recorder().consume_sload()?;69 self.recorder().consume_sstore()?;7071 Pallet::<T>::set_sponsor(72 &T::CrossAccountId::from_eth(caller),73 contract_address,74 &T::CrossAccountId::from_eth(sponsor),75 )76 .map_err(dispatch_to_evm::<T>)?;7778 Ok(())79 }8081 /// Set contract as self sponsored.82 ///83 /// @param contract_address Contract for which a self sponsoring is being enabled.49 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {84 fn self_sponsored_enable(&mut self, caller: caller, contract_address: address) -> Result<void> {85 self.recorder().consume_sload()?;86 self.recorder().consume_sstore()?;8750 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)88 Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)89 .map_err(dispatch_to_evm::<T>)?;9091 Ok(())51 }92 }529353 /// Deprecated94 /// Remove sponsor.95 ///96 /// @param contract_address Contract for which a sponsorship is being removed.54 fn toggle_sponsoring(97 fn remove_sponsor(&mut self, caller: caller, contract_address: address) -> Result<void> {55 &mut self,98 self.recorder().consume_sload()?;56 caller: caller,99 self.recorder().consume_sstore()?;100101 Pallet::<T>::remove_sponsor(&T::CrossAccountId::from_eth(caller), contract_address)102 .map_err(dispatch_to_evm::<T>)?;103104 Ok(())105 }106107 /// Confirm sponsorship.108 ///109 /// @dev Caller must be same that set via [`set_sponsor`].110 ///111 /// @param contract_address Сontract for which need to confirm sponsorship.57 contract_address: address,112 fn confirm_sponsorship(&mut self, caller: caller, contract_address: address) -> Result<void> {58 enabled: bool,113 self.recorder().consume_sload()?;114 self.recorder().consume_sstore()?;115116 Pallet::<T>::confirm_sponsorship(&T::CrossAccountId::from_eth(caller), contract_address)117 .map_err(dispatch_to_evm::<T>)?;118119 Ok(())120 }121122 /// Get current sponsor.123 ///124 /// @param contract_address The contract for which a sponsor is requested.125 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.59 ) -> Result<void> {126 fn get_sponsor(&self, contract_address: address) -> Result<(address, uint256)> {127 let sponsor =60 <Pallet<T>>::ensure_owner(contract_address, caller)?;128 Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?;129 let result: (address, uint256) = if sponsor.is_canonical_substrate() {61 <Pallet<T>>::toggle_sponsoring(contract_address, enabled);130 let sponsor = pallet_common::eth::convert_cross_account_to_uint256::<T>(&sponsor);131 (Default::default(), sponsor)132 } else {133 let sponsor = *sponsor.as_eth();134 (sponsor, Default::default())135 };62 Ok(())136 Ok(result)63 }137 }138139 /// Check tat contract has confirmed sponsor.140 ///141 /// @param contract_address The contract for which the presence of a confirmed sponsor is checked.142 /// @return **true** if contract has confirmed sponsor.143 fn has_sponsor(&self, contract_address: address) -> Result<bool> {144 Ok(Pallet::<T>::get_sponsor(contract_address).is_some())145 }146147 /// Check tat contract has pending sponsor.148 ///149 /// @param contract_address The contract for which the presence of a pending sponsor is checked.150 /// @return **true** if contract has pending sponsor.151 fn has_pending_sponsor(&self, contract_address: address) -> Result<bool> {152 Ok(match Sponsoring::<T>::get(contract_address) {153 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,154 SponsorshipState::Unconfirmed(_) => true,155 })156 }157158 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {159 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)160 }6416165 fn set_sponsoring_mode(162 fn set_sponsoring_mode(66 &mut self,163 &mut self,67 caller: caller,164 caller: caller,68 contract_address: address,165 contract_address: address,69 mode: uint8,166 mode: uint8,70 ) -> Result<void> {167 ) -> Result<void> {168 self.recorder().consume_sload()?;169 self.recorder().consume_sstore()?;17071 <Pallet<T>>::ensure_owner(contract_address, caller)?;171 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;72 let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;172 let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;73 <Pallet<T>>::set_sponsoring_mode(contract_address, mode);173 <Pallet<T>>::set_sponsoring_mode(contract_address, mode);17484 contract_address: address,185 contract_address: address,85 rate_limit: uint32,186 rate_limit: uint32,86 ) -> Result<void> {187 ) -> Result<void> {188 self.recorder().consume_sload()?;189 self.recorder().consume_sstore()?;19087 <Pallet<T>>::ensure_owner(contract_address, caller)?;191 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;88 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());192 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());19389 Ok(())194 Ok(())110 contract_address: address,215 contract_address: address,111 enabled: bool,216 enabled: bool,112 ) -> Result<void> {217 ) -> Result<void> {218 self.recorder().consume_sload()?;219 self.recorder().consume_sstore()?;220113 <Pallet<T>>::ensure_owner(contract_address, caller)?;221 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;114 <Pallet<T>>::toggle_allowlist(contract_address, enabled);222 <Pallet<T>>::toggle_allowlist(contract_address, enabled);223115 Ok(())224 Ok(())122 user: address,231 user: address,123 allowed: bool,232 allowed: bool,124 ) -> Result<void> {233 ) -> Result<void> {234 self.recorder().consume_sload()?;235 self.recorder().consume_sstore()?;236125 <Pallet<T>>::ensure_owner(contract_address, caller)?;237 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;126 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);238 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);239127 Ok(())240 Ok(())128 }241 }129}242}130243131pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);244pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);132impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T> {245impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T>246where247 T::AccountId: AsRef<[u8; 32]>,248{133 fn is_reserved(contract: &sp_core::H160) -> bool {249 fn is_reserved(contract: &sp_core::H160) -> bool {134 contract == &T::ContractAddress::get()250 contract == &T::ContractAddress::get()179 for HelpersContractSponsoring<T>295 for HelpersContractSponsoring<T>180{296{181 fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {297 fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {298 let (contract_address, _) = call;182 let mode = <Pallet<T>>::sponsoring_mode(call.0);299 let mode = <Pallet<T>>::sponsoring_mode(*contract_address);183 if mode == SponsoringModeT::Disabled {300 if mode == SponsoringModeT::Disabled {184 return None;301 return None;185 }302 }303304 let sponsor = match <Pallet<T>>::get_sponsor(*contract_address) {305 Some(sponsor) => sponsor,306 None => return None,307 };186308187 if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who.as_eth()) {309 if mode == SponsoringModeT::Allowlisted310 && !<Pallet<T>>::allowed(*contract_address, *who.as_eth())311 {188 return None;312 return None;189 }313 }190 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;314 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;191315192 if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who.as_eth()) {316 if let Some(last_tx_block) = <SponsorBasket<T>>::get(contract_address, who.as_eth()) {193 let limit = <SponsoringRateLimit<T>>::get(&call.0);317 let limit = <SponsoringRateLimit<T>>::get(contract_address);194318195 let timeout = last_tx_block + limit;319 let timeout = last_tx_block + limit;196 if block_number < timeout {320 if block_number < timeout {197 return None;321 return None;198 }322 }199 }323 }200324201 <SponsorBasket<T>>::insert(&call.0, who.as_eth(), block_number);325 <SponsorBasket<T>>::insert(contract_address, who.as_eth(), block_number);202326203 let sponsor = T::CrossAccountId::from_eth(call.0);204 Some(sponsor)327 Some(sponsor)205 }328 }206}329}pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth25#[frame_support::pallet]25#[frame_support::pallet]26pub mod pallet {26pub mod pallet {27 pub use super::*;27 pub use super::*;28 use evm_coder::execution::Result;28 use frame_support::pallet_prelude::*;29 use frame_support::pallet_prelude::*;29 use pallet_evm_coder_substrate::DispatchResult;30 use sp_core::H160;30 use sp_core::H160;31 use pallet_evm::account::CrossAccountId;32 use up_data_structs::SponsorshipState;313332 #[pallet::config]34 #[pallet::config]33 pub trait Config:35 pub trait Config:394140 #[pallet::error]42 #[pallet::error]41 pub enum Error<T> {43 pub enum Error<T> {42 /// This method is only executable by owner44 /// This method is only executable by owner.43 NoPermission,45 NoPermission,4647 /// No pending sponsor for contract.48 NoPendingSponsor,44 }49 }455046 #[pallet::pallet]51 #[pallet::pallet]47 #[pallet::generate_store(pub(super) trait Store)]52 #[pallet::generate_store(pub(super) trait Store)]48 pub struct Pallet<T>(_);53 pub struct Pallet<T>(_);495455 /// Store owner for contract.56 ///57 /// * **Key** - contract address.58 /// * **Value** - owner for contract.50 #[pallet::storage]59 #[pallet::storage]51 pub(super) type Owner<T: Config> =60 pub(super) type Owner<T: Config> =52 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;61 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;56 pub(super) type SelfSponsoring<T: Config> =65 pub(super) type SelfSponsoring<T: Config> =57 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;66 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;586768 /// Store for contract sponsorship state.69 ///70 /// * **Key** - contract address.71 /// * **Value** - sponsorship state.72 #[pallet::storage]73 pub(super) type Sponsoring<T: Config> = StorageMap<74 Hasher = Twox64Concat,75 Key = H160,76 Value = SponsorshipState<T::CrossAccountId>,77 QueryKind = ValueQuery,78 >;7980 /// Store for sponsoring mode.81 ///82 /// ### Usage83 /// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).84 ///85 /// * **Key** - contract address.86 /// * **Value** - [`sponsoring mode`](SponsoringModeT).59 #[pallet::storage]87 #[pallet::storage]60 pub(super) type SponsoringMode<T: Config> =88 pub(super) type SponsoringMode<T: Config> =61 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;89 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;629091 /// Storage for sponsoring rate limit in blocks.92 ///93 /// * **Key** - contract address.94 /// * **Value** - amount of sponsored blocks.63 #[pallet::storage]95 #[pallet::storage]64 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<96 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<65 Hasher = Twox128,97 Hasher = Twox128,69 OnEmpty = T::DefaultSponsoringRateLimit,101 OnEmpty = T::DefaultSponsoringRateLimit,70 >;102 >;71103104 /// Storage for last sponsored block.105 ///106 /// * **Key1** - contract address.107 /// * **Key2** - sponsored user address.108 /// * **Value** - last sponsored block number.72 #[pallet::storage]109 #[pallet::storage]73 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<110 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<74 Hasher1 = Twox128,111 Hasher1 = Twox128,79 QueryKind = OptionQuery,116 QueryKind = OptionQuery,80 >;117 >;81118119 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.120 ///121 /// ### Usage122 /// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.123 ///124 /// * **Key** - contract address.125 /// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.82 #[pallet::storage]126 #[pallet::storage]83 pub(super) type AllowlistEnabled<T: Config> =127 pub(super) type AllowlistEnabled<T: Config> =84 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;128 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;85129130 /// Storage for users that allowed for sponsorship.131 ///132 /// ### Usage133 /// Prefer to delete record from storage if user no more allowed for sponsorship.134 ///135 /// * **Key1** - contract address.136 /// * **Key2** - user that allowed for sponsorship.137 /// * **Value** - allowance for sponsorship.86 #[pallet::storage]138 #[pallet::storage]87 pub(super) type Allowlist<T: Config> = StorageDoubleMap<139 pub(super) type Allowlist<T: Config> = StorageDoubleMap<88 Hasher1 = Twox128,140 Hasher1 = Twox128,94 >;146 >;9514796 impl<T: Config> Pallet<T> {148 impl<T: Config> Pallet<T> {149 /// Get contract owner.150 pub fn contract_owner(contract: H160) -> H160 {151 <Owner<T>>::get(contract)152 }153154 /// Set `sponsor` for `contract`.155 ///156 /// `sender` must be owner of contract.157 pub fn set_sponsor(158 sender: &T::CrossAccountId,159 contract: H160,160 sponsor: &T::CrossAccountId,161 ) -> DispatchResult {162 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;163 Sponsoring::<T>::insert(164 contract,165 SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),166 );167 Ok(())168 }169170 /// Set `contract` as self sponsored.171 ///172 /// `sender` must be owner of contract.173 pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {174 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;175 Sponsoring::<T>::insert(176 contract,177 SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(178 contract,179 )),180 );181 Ok(())182 }183184 /// Remove sponsor for `contract`.185 ///186 /// `sender` must be owner of contract.187 pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {188 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;189 Sponsoring::<T>::remove(contract);190 Ok(())191 }192193 /// Confirm sponsorship.194 ///195 /// `sender` must be same that set via [`set_sponsor`].196 pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {197 match Sponsoring::<T>::get(contract) {198 SponsorshipState::Unconfirmed(sponsor) => {199 ensure!(sponsor == *sender, Error::<T>::NoPermission);200 Sponsoring::<T>::insert(201 contract,202 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),203 );204 Ok(())205 }206 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {207 Err(Error::<T>::NoPendingSponsor.into())208 }209 }210 }211212 /// Get sponsor.213 pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {214 match Sponsoring::<T>::get(contract) {215 SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,216 SponsorshipState::Confirmed(sponsor) => Some(sponsor),217 }218 }21997 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {220 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {98 <SponsoringMode<T>>::get(contract)221 <SponsoringMode<T>>::get(contract)110 <SelfSponsoring<T>>::remove(contract)234 <SelfSponsoring<T>>::remove(contract)111 }235 }112113 pub fn toggle_sponsoring(contract: H160, enabled: bool) {114 Self::set_sponsoring_mode(115 contract,116 if enabled {117 SponsoringModeT::Allowlisted118 } else {119 SponsoringModeT::Disabled120 },121 )122 }123236124 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {237 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {125 <SponsoringRateLimit<T>>::insert(contract, rate_limit);238 <SponsoringRateLimit<T>>::insert(contract, rate_limit);137 <Allowlist<T>>::insert(contract, user, allowed);250 <Allowlist<T>>::insert(contract, user, allowed);138 }251 }139252140 pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {253 pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {141 ensure!(<Owner<T>>::get(&contract) == user, "no permission");254 ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);142 Ok(())255 Ok(())143 }256 }144 }257 }pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 address field_0;9 uint256 field_1;10}5116// Common stubs holder12// Common stubs holder7contract Dummy {13contract Dummy {21 }27 }22}28}232924// Selector: 7b4866f930// Selector: 6073d91725contract ContractHelpers is Dummy, ERC165 {31contract ContractHelpers is Dummy, ERC165 {32 // Get contract ovner33 //34 // @param Contract_address contract for which the owner is being determined.35 // @return Contract owner.36 //26 // Selector: contractOwner(address) 5152b14c37 // Selector: contractOwner(address) 5152b14c27 function contractOwner(address contractAddress)38 function contractOwner(address contractAddress)28 public39 public35 return 0x0000000000000000000000000000000000000000;46 return 0x0000000000000000000000000000000000000000;36 }47 }4849 // Set sponsor.50 //51 // @param contract_address Contract for which a sponsor is being established.52 // @param sponsor User address who set as pending sponsor.53 //54 // Selector: setSponsor(address,address) f01fba9355 function setSponsor(address contractAddress, address sponsor) public {56 require(false, stub_error);57 contractAddress;58 sponsor;59 dummy = 0;60 }6162 // Set contract as self sponsored.63 //64 // @param contract_address Contract for which a self sponsoring is being enabled.65 //66 // Selector: selfSponsoredEnable(address) 89f7d9ae67 function selfSponsoredEnable(address contractAddress) public {68 require(false, stub_error);69 contractAddress;70 dummy = 0;71 }7273 // Remove sponsor.74 //75 // @param contract_address Contract for which a sponsorship is being removed.76 //77 // Selector: removeSponsor(address) ef78425078 function removeSponsor(address contractAddress) public {79 require(false, stub_error);80 contractAddress;81 dummy = 0;82 }8384 // Confirm sponsorship.85 //86 // @dev Caller must be same that set via [`set_sponsor`].87 //88 // @param contract_address Сontract for which need to confirm sponsorship.89 //90 // Selector: confirmSponsorship(address) abc0000191 function confirmSponsorship(address contractAddress) public {92 require(false, stub_error);93 contractAddress;94 dummy = 0;95 }9697 // Get current sponsor.98 //99 // @param contract_address The contract for which a sponsor is requested.100 // @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.101 //102 // Selector: getSponsor(address) 743fc745103 function getSponsor(address contractAddress)104 public105 view106 returns (Tuple0 memory)107 {108 require(false, stub_error);109 contractAddress;110 dummy;111 return Tuple0(0x0000000000000000000000000000000000000000, 0);112 }113114 // Check tat contract has confirmed sponsor.115 //116 // @param contract_address The contract for which the presence of a confirmed sponsor is checked.117 // @return **true** if contract has confirmed sponsor.118 //119 // Selector: hasSponsor(address) 97418603120 function hasSponsor(address contractAddress) public view returns (bool) {121 require(false, stub_error);122 contractAddress;123 dummy;124 return false;125 }126127 // Check tat contract has pending sponsor.128 //129 // @param contract_address The contract for which the presence of a pending sponsor is checked.130 // @return **true** if contract has pending sponsor.131 //132 // Selector: hasPendingSponsor(address) 39b9b242133 function hasPendingSponsor(address contractAddress)134 public135 view136 returns (bool)137 {138 require(false, stub_error);139 contractAddress;140 dummy;141 return false;142 }3714338 // Selector: sponsoringEnabled(address) 6027dc61144 // Selector: sponsoringEnabled(address) 6027dc6139 function sponsoringEnabled(address contractAddress)145 function sponsoringEnabled(address contractAddress)47 return false;153 return false;48 }154 }4950 // Deprecated51 //52 // Selector: toggleSponsoring(address,bool) fcac6d8653 function toggleSponsoring(address contractAddress, bool enabled) public {54 require(false, stub_error);55 contractAddress;56 enabled;57 dummy = 0;58 }5915560 // Selector: setSponsoringMode(address,uint8) fde8a560156 // Selector: setSponsoringMode(address,uint8) fde8a56061 function setSponsoringMode(address contractAddress, uint8 mode) public {157 function setSponsoringMode(address contractAddress, uint8 mode) public {runtime/tests/src/lib.rsdiffbeforeafterboth167}167}168168169#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]169#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]170pub struct TestCrossAccountId(u64, sp_core::H160);170pub struct TestCrossAccountId(u64, sp_core::H160, bool);171impl CrossAccountId<u64> for TestCrossAccountId {171impl CrossAccountId<u64> for TestCrossAccountId {172 fn as_sub(&self) -> &u64 {172 fn as_sub(&self) -> &u64 {173 &self.0173 &self.0178 fn from_sub(sub: u64) -> Self {178 fn from_sub(sub: u64) -> Self {179 let mut eth = [0; 20];179 let mut eth = [0; 20];180 eth[12..20].copy_from_slice(&sub.to_be_bytes());180 eth[12..20].copy_from_slice(&sub.to_be_bytes());181 Self(sub, sp_core::H160(eth))181 Self(sub, sp_core::H160(eth), true)182 }182 }183 fn from_eth(eth: sp_core::H160) -> Self {183 fn from_eth(eth: sp_core::H160) -> Self {184 let mut sub_raw = [0; 8];184 let mut sub_raw = [0; 8];185 sub_raw.copy_from_slice(ð.0[0..8]);185 sub_raw.copy_from_slice(ð.0[0..8]);186 let sub = u64::from_be_bytes(sub_raw);186 let sub = u64::from_be_bytes(sub_raw);187 Self(sub, eth)187 Self(sub, eth, false)188 }188 }189 fn conv_eq(&self, other: &Self) -> bool {189 fn conv_eq(&self, other: &Self) -> bool {190 self.as_sub() == other.as_sub()190 self.as_sub() == other.as_sub()191 }191 }192 fn is_canonical_substrate(&self) -> bool {193 self.2194 }192}195}193196194impl Default for TestCrossAccountId {197impl Default for TestCrossAccountId {tests/src/eth/api/ContractHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 address field_0;9 uint256 field_1;10}5116// Common stubs holder12// Common stubs holder7interface Dummy {13interface Dummy {12 function supportsInterface(bytes4 interfaceID) external view returns (bool);18 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}19}142015// Selector: 7b4866f921// Selector: 6073d91716interface ContractHelpers is Dummy, ERC165 {22interface ContractHelpers is Dummy, ERC165 {23 // Get contract ovner24 //25 // @param Contract_address contract for which the owner is being determined.26 // @return Contract owner.27 //17 // Selector: contractOwner(address) 5152b14c28 // Selector: contractOwner(address) 5152b14c18 function contractOwner(address contractAddress)29 function contractOwner(address contractAddress)19 external30 external20 view31 view21 returns (address);32 returns (address);3334 // Set sponsor.35 //36 // @param contract_address Contract for which a sponsor is being established.37 // @param sponsor User address who set as pending sponsor.38 //39 // Selector: setSponsor(address,address) f01fba9340 function setSponsor(address contractAddress, address sponsor) external;4142 // Set contract as self sponsored.43 //44 // @param contract_address Contract for which a self sponsoring is being enabled.45 //46 // Selector: selfSponsoredEnable(address) 89f7d9ae47 function selfSponsoredEnable(address contractAddress) external;4849 // Remove sponsor.50 //51 // @param contract_address Contract for which a sponsorship is being removed.52 //53 // Selector: removeSponsor(address) ef78425054 function removeSponsor(address contractAddress) external;5556 // Confirm sponsorship.57 //58 // @dev Caller must be same that set via [`set_sponsor`].59 //60 // @param contract_address Сontract for which need to confirm sponsorship.61 //62 // Selector: confirmSponsorship(address) abc0000163 function confirmSponsorship(address contractAddress) external;6465 // Get current sponsor.66 //67 // @param contract_address The contract for which a sponsor is requested.68 // @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.69 //70 // Selector: getSponsor(address) 743fc74571 function getSponsor(address contractAddress)72 external73 view74 returns (Tuple0 memory);7576 // Check tat contract has confirmed sponsor.77 //78 // @param contract_address The contract for which the presence of a confirmed sponsor is checked.79 // @return **true** if contract has confirmed sponsor.80 //81 // Selector: hasSponsor(address) 9741860382 function hasSponsor(address contractAddress) external view returns (bool);8384 // Check tat contract has pending sponsor.85 //86 // @param contract_address The contract for which the presence of a pending sponsor is checked.87 // @return **true** if contract has pending sponsor.88 //89 // Selector: hasPendingSponsor(address) 39b9b24290 function hasPendingSponsor(address contractAddress)91 external92 view93 returns (bool);229423 // Selector: sponsoringEnabled(address) 6027dc6195 // Selector: sponsoringEnabled(address) 6027dc6124 function sponsoringEnabled(address contractAddress)96 function sponsoringEnabled(address contractAddress)25 external97 external26 view98 view27 returns (bool);99 returns (bool);2829 // Deprecated30 //31 // Selector: toggleSponsoring(address,bool) fcac6d8632 function toggleSponsoring(address contractAddress, bool enabled) external;3310034 // Selector: setSponsoringMode(address,uint8) fde8a560101 // Selector: setSponsoringMode(address,uint8) fde8a56035 function setSponsoringMode(address contractAddress, uint8 mode) external;102 function setSponsoringMode(address contractAddress, uint8 mode) external;tests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth1import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, setCollectionSponsorExpectSuccess} from '../util/helpers';1import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents} from './util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers';3import nonFungibleAbi from './nonFungibleAbi.json';3import nonFungibleAbi from './nonFungibleAbi.json';4import {expect} from 'chai';4import {expect} from 'chai';5import {evmToAddress} from '@polkadot/util-crypto';566describe('evm collection sponsoring', () => {7describe('evm collection sponsoring', () => {7 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {8 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {37 ]);38 ]);38 });39 });4041 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {42 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const collectionHelpers = evmCollectionHelpers(web3, owner);44 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();45 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);46 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);47 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);48 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});49 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;50 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;51 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;52 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));53 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');5455 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});56 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;57 expect(collectionSub.sponsorship.isConfirmed).to.be.true;58 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));5960 const user = createEthAccount(web3);61 const nextTokenId = await collectionEvm.methods.nextTokenId().call();62 expect(nextTokenId).to.be.equal('1');6364 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();65 expect(oldPermissions.mintMode).to.be.false;66 expect(oldPermissions.access).to.be.equal('Normal');6768 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});69 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});70 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});7172 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();73 expect(newPermissions.mintMode).to.be.true;74 expect(newPermissions.access).to.be.equal('AllowList');7576 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);77 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);7879 {80 const nextTokenId = await collectionEvm.methods.nextTokenId().call();81 expect(nextTokenId).to.be.equal('1');82 const result = await collectionEvm.methods.mintWithTokenURI(83 user,84 nextTokenId,85 'Test URI',86 ).send({from: user});87 const events = normalizeEvents(result.events);8889 expect(events).to.be.deep.equal([90 {91 address: collectionIdAddress,92 event: 'Transfer',93 args: {94 from: '0x0000000000000000000000000000000000000000',95 to: user,96 tokenId: nextTokenId,97 },98 },99 ]);100101 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);102 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);103104 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');105 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);106 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;107 }108 });109110 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {111 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);112 const collectionHelpers = evmCollectionHelpers(web3, owner);113 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();114 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);115 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);116 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);117 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();118 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;119 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;120 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;121 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));122 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');123 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);124 await sponsorCollection.methods.confirmCollectionSponsorship().send();125 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;126 expect(collectionSub.sponsorship.isConfirmed).to.be.true;127 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));128129 const user = createEthAccount(web3);130 await collectionEvm.methods.addCollectionAdmin(user).send();131 132 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);133 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);134 135 136 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);137 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();138 expect(nextTokenId).to.be.equal('1');139 result = await userCollectionEvm.methods.mintWithTokenURI(140 user,141 nextTokenId,142 'Test URI',143 ).send();144145 const events = normalizeEvents(result.events);146 const address = collectionIdToAddress(collectionId);147148 expect(events).to.be.deep.equal([149 {150 address,151 event: 'Transfer',152 args: {153 from: '0x0000000000000000000000000000000000000000',154 to: user,155 tokenId: nextTokenId,156 },157 },158 ]);159 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');160 161 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);162 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);163 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);164 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;165 });39});166});40167tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth23 itWeb3,23 itWeb3,24 SponsoringMode,24 SponsoringMode,25 createEthAccount,25 createEthAccount,26 collectionIdToAddress,27 GAS_ARGS,28 normalizeEvents,29 subToEth,30 executeEthTxOnSub,31 evmCollectionHelpers,32 getCollectionAddressFromResult,33 evmCollection,34 ethBalanceViaSub,26 ethBalanceViaSub,35} from './util/helpers';27} from './util/helpers';36import {37 addCollectionAdminExpectSuccess,38 createCollectionExpectSuccess,39 getDetailedCollectionInfo,40 transferBalanceTo,41} from '../util/helpers';42import nonFungibleAbi from './nonFungibleAbi.json';43import getBalance from '../substrate/get-balance';44import {evmToAddress} from '@polkadot/util-crypto';452846describe('Sponsoring EVM contracts', () => {29describe('Sponsoring EVM contracts', () => {30 itWeb3('Self sponsored can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {31 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);32 const flipper = await deployFlipper(web3, owner);33 const helpers = contractHelpers(web3, owner);34 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;35 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;36 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;37 });3839 itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {40 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);41 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);42 const flipper = await deployFlipper(web3, owner);43 const helpers = contractHelpers(web3, owner);44 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;45 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');46 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;47 });4847 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {49 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {48 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);50 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);49 const flipper = await deployFlipper(web3, owner);51 const flipper = await deployFlipper(web3, owner);50 const helpers = contractHelpers(web3, owner);52 const helpers = contractHelpers(web3, owner);51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;53 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});54 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;53 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;55 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;54 });56 });555759 const flipper = await deployFlipper(web3, owner);61 const flipper = await deployFlipper(web3, owner);60 const helpers = contractHelpers(web3, owner);62 const helpers = contractHelpers(web3, owner);61 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;63 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;62 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;64 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');63 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;65 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;64 });66 });67 68 itWeb3('Sponsor can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {69 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);70 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);71 const flipper = await deployFlipper(web3, owner);72 const helpers = contractHelpers(web3, owner);73 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;74 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;75 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;76 });77 78 itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {79 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);80 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);81 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);82 const flipper = await deployFlipper(web3, owner);83 const helpers = contractHelpers(web3, owner);84 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;85 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');86 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;87 });658889 itWeb3('Sponsorship can be confirmed by the address that pending as sponsor', async ({api, web3, privateKeyWrapper}) => {90 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);91 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const flipper = await deployFlipper(web3, owner);93 const helpers = contractHelpers(web3, owner);94 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;95 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;96 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;97 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;98 });99100 itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {101 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);102 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const flipper = await deployFlipper(web3, owner);105 const helpers = contractHelpers(web3, owner);106 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;107 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;108 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');109 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;110 });111112 itWeb3('Sponsorship can not be confirmed by the address that not set as sponsor', async ({api, web3, privateKeyWrapper}) => {113 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);114 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);115 const flipper = await deployFlipper(web3, owner);116 const helpers = contractHelpers(web3, owner);117 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;118 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');119 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;120 });121122 itWeb3('Get self sponsored sponsor', async ({api, web3, privateKeyWrapper}) => {123 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);124 const flipper = await deployFlipper(web3, owner);125 const helpers = contractHelpers(web3, owner);126 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();127 128 const result = await helpers.methods.getSponsor(flipper.options.address).call();129130 expect(result[0]).to.be.eq(flipper.options.address);131 expect(result[1]).to.be.eq('0');132 });133134 itWeb3('Get confirmed sponsor', async ({api, web3, privateKeyWrapper}) => {135 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);136 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);137 const flipper = await deployFlipper(web3, owner);138 const helpers = contractHelpers(web3, owner);139 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();140 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});141 142 const result = await helpers.methods.getSponsor(flipper.options.address).call();143144 expect(result[0]).to.be.eq(sponsor);145 expect(result[1]).to.be.eq('0');146 });147148 itWeb3('Sponsor can be removed by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {149 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);150 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);151 const flipper = await deployFlipper(web3, owner);152 const helpers = contractHelpers(web3, owner);153154 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;155 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();156 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});157 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;158 159 await helpers.methods.removeSponsor(flipper.options.address).send();160 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;161 });162163 itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {164 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);165 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);166 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);167 const flipper = await deployFlipper(web3, owner);168 const helpers = contractHelpers(web3, owner);169170 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;171 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();172 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});173 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;174 175 await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');176 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;177 });17866 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {179 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {180 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);181 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);182 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);183184 const flipper = await deployFlipper(web3, owner);185186 const helpers = contractHelpers(web3, owner);187188 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();189 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});190191 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});192 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});193194 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);195 const callerBalanceBefore = await ethBalanceViaSub(api, caller);196197 await flipper.methods.flip().send({from: caller});198 expect(await flipper.methods.getValue().call()).to.be.true;199200 // Balance should be taken from sponsor instead of caller201 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);202 const callerBalanceAfter = await ethBalanceViaSub(api, caller);203 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;204 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);205 });206207 itWeb3('In generous mode, non-allowlisted user transaction will be self sponsored', async ({api, web3, privateKeyWrapper}) => {67 const alice = privateKeyWrapper('//Alice');208 const alice = privateKeyWrapper('//Alice');6820969 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);7321474 const helpers = contractHelpers(web3, owner);215 const helpers = contractHelpers(web3, owner);7521676 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;217 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();21877 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});219 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});78 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});220 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});79 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;8022181 await transferBalanceToEth(api, alice, flipper.options.address);222 await transferBalanceToEth(api, alice, flipper.options.address);8222383 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);224 const contractBalanceBefore = await ethBalanceViaSub(api, flipper.options.address);84 expect(originalFlipperBalance).to.be.not.equal('0');225 const callerBalanceBefore = await ethBalanceViaSub(api, caller);8522686 await flipper.methods.flip().send({from: caller});227 await flipper.methods.flip().send({from: caller});87 expect(await flipper.methods.getValue().call()).to.be.true;228 expect(await flipper.methods.getValue().call()).to.be.true;8822989 // Balance should be taken from flipper instead of caller230 // Balance should be taken from sponsor instead of caller90 const balanceAfter = await web3.eth.getBalance(flipper.options.address);231 const contractBalanceAfter = await ethBalanceViaSub(api, flipper.options.address);232 const callerBalanceAfter = await ethBalanceViaSub(api, caller);233 expect(contractBalanceAfter < contractBalanceBefore).to.be.true;91 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);234 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);92 });235 });9323694 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}) => {237 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');9697 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);238 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);239 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);98 const caller = createEthAccount(web3);240 const caller = createEthAccount(web3);99241100 const flipper = await deployFlipper(web3, owner);242 const flipper = await deployFlipper(web3, owner);103 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});245 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});104 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});246 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});105247106 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;107 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});248 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});108 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});249 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});109 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;110250111 await transferBalanceToEth(api, alice, flipper.options.address);251 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();252 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});112253113 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);254 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);114 expect(originalFlipperBalance).to.be.not.equal('0');255 expect(sponsorBalanceBefore).to.be.not.equal('0');115256116 await flipper.methods.flip().send({from: caller});257 await flipper.methods.flip().send({from: caller});117 expect(await flipper.methods.getValue().call()).to.be.true;258 expect(await flipper.methods.getValue().call()).to.be.true;118259119 // Balance should be taken from flipper instead of caller260 // Balance should be taken from flipper instead of caller120 const balanceAfter = await web3.eth.getBalance(flipper.options.address);261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);121 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;122 });263 });123264124 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}) => {265 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}) => {131272132 const helpers = contractHelpers(web3, owner);273 const helpers = contractHelpers(web3, owner);133274134 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;135 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});275 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});136 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});276 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});137 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;138277139 await transferBalanceToEth(api, alice, flipper.options.address);278 await transferBalanceToEth(api, alice, flipper.options.address);140279150 });289 });151290152 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}) => {291 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');154155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);292 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);293 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);294 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);157 const originalCallerBalance = await web3.eth.getBalance(caller);158295159 const flipper = await deployFlipper(web3, owner);296 const flipper = await deployFlipper(web3, owner);160297161 const helpers = contractHelpers(web3, owner);298 const helpers = contractHelpers(web3, owner);162 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});299 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});163 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});300 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});164301165 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;166 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});302 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});167 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});303 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});168 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;169304170 await transferBalanceToEth(api, alice, flipper.options.address);305 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();306 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});171307172 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);308 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);173 expect(originalFlipperBalance).to.be.not.equal('0');309 const callerBalanceBefore = await ethBalanceViaSub(api, caller);174310175 await flipper.methods.flip().send({from: caller});311 await flipper.methods.flip().send({from: caller});176 expect(await flipper.methods.getValue().call()).to.be.true;312 expect(await flipper.methods.getValue().call()).to.be.true;177313178 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);314 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);315 const callerBalanceAfter = await ethBalanceViaSub(api, caller);316 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;317 expect(callerBalanceAfter).to.be.equals(callerBalanceBefore);179 });318 });180319181 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}) => {320 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');183184 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);321 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);322 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);185 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);323 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);186 const originalCallerBalance = await web3.eth.getBalance(caller);324 const originalCallerBalance = await web3.eth.getBalance(caller);187325191 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});329 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});192 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});330 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});193331194 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;195 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});332 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});196 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});333 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});197 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;198334199 await transferBalanceToEth(api, alice, flipper.options.address);335 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();336 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});200337201 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);338 const originalFlipperBalance = await web3.eth.getBalance(sponsor);202 expect(originalFlipperBalance).to.be.not.equal('0');339 expect(originalFlipperBalance).to.be.not.equal('0');203340204 await flipper.methods.flip().send({from: caller});341 await flipper.methods.flip().send({from: caller});205 expect(await flipper.methods.getValue().call()).to.be.true;342 expect(await flipper.methods.getValue().call()).to.be.true;206 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);343 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);207344208 const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);345 const newFlipperBalance = await web3.eth.getBalance(sponsor);209 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);346 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);210347211 await flipper.methods.flip().send({from: caller});348 await flipper.methods.flip().send({from: caller});212 expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);349 expect(await web3.eth.getBalance(sponsor)).to.be.equal(newFlipperBalance);213 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);350 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);214 });351 });215352219 const flipper = await deployFlipper(web3, owner);356 const flipper = await deployFlipper(web3, owner);220 const helpers = contractHelpers(web3, owner);357 const helpers = contractHelpers(web3, owner);221 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');358 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');222 });223224 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {225 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);226 const collectionHelpers = evmCollectionHelpers(web3, owner);227 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();228 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);229 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);230 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});232 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;233 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;234 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;235 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));236 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');237238 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});239 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;240 expect(collectionSub.sponsorship.isConfirmed).to.be.true;241 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));242243 const user = createEthAccount(web3);244 const nextTokenId = await collectionEvm.methods.nextTokenId().call();245 expect(nextTokenId).to.be.equal('1');246247 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();248 expect(oldPermissions.mintMode).to.be.false;249 expect(oldPermissions.access).to.be.equal('Normal');250251 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});252 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});253 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});254255 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();256 expect(newPermissions.mintMode).to.be.true;257 expect(newPermissions.access).to.be.equal('AllowList');258259 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);260 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);261262 {263 const nextTokenId = await collectionEvm.methods.nextTokenId().call();264 expect(nextTokenId).to.be.equal('1');265 const result = await collectionEvm.methods.mintWithTokenURI(266 user,267 nextTokenId,268 'Test URI',269 ).send({from: user});270 const events = normalizeEvents(result.events);271272 expect(events).to.be.deep.equal([273 {274 address: collectionIdAddress,275 event: 'Transfer',276 args: {277 from: '0x0000000000000000000000000000000000000000',278 to: user,279 tokenId: nextTokenId,280 },281 },282 ]);283284 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);285 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);286287 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');288 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);289 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;290 }291 });292293 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {294 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);295 const collectionHelpers = evmCollectionHelpers(web3, owner);296 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();297 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);298 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);299 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);300 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();301 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;302 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;303 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;304 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));305 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');306 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);307 await sponsorCollection.methods.confirmCollectionSponsorship().send();308 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;309 expect(collectionSub.sponsorship.isConfirmed).to.be.true;310 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));311312 const user = createEthAccount(web3);313 await collectionEvm.methods.addCollectionAdmin(user).send();314 315 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);316 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);317 318 319 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);320 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();321 expect(nextTokenId).to.be.equal('1');322 result = await userCollectionEvm.methods.mintWithTokenURI(323 user,324 nextTokenId,325 'Test URI',326 ).send();327328 const events = normalizeEvents(result.events);329 const address = collectionIdToAddress(collectionId);330331 expect(events).to.be.deep.equal([332 {333 address,334 event: 'Transfer',335 args: {336 from: '0x0000000000000000000000000000000000000000',337 to: user,338 tokenId: nextTokenId,339 },340 },341 ]);342 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');343 344 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);345 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);346 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);347 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;348 });359 });349});360});350361tests/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 sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);42 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 from: matcherOwner,45 from: matcherOwner,49 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});50 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});50 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});51 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});52 51 await transferBalanceToEth(api, alice, matcher.options.address);53 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});54 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});525553 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});56 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});54 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});57 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});100103101 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {104 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {102 const alice = privateKeyWrapper('//Alice');105 const alice = privateKeyWrapper('//Alice');106 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);107 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);108 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);105 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {109 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {112 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});116 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});113 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});117 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});118 114 await transferBalanceToEth(api, alice, matcher.options.address);119 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});120 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});115121116 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});122 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});117 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});123 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});tests/src/eth/sponsoring.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {expect} from 'chai';17import {expect} from 'chai';18import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode, transferBalanceToEth} from './util/helpers';18import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode} from './util/helpers';191920describe('EVM sponsoring', () => {20describe('EVM sponsoring', () => {21 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 owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);2324 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);23 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);25 const caller = createEthAccount(web3);24 const caller = createEthAccount(web3);26 const originalCallerBalance = await web3.eth.getBalance(caller);25 const originalCallerBalance = await web3.eth.getBalance(caller);27 expect(originalCallerBalance).to.be.equal('0');26 expect(originalCallerBalance).to.be.equal('0');32 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});31 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});33 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});32 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});33 34 await helpers.methods.setSponsor(flipper.options.address, sponsor).send({from: owner});35 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});343635 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;37 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;36 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});38 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});37 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});39 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});38 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;40 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;3940 await transferBalanceToEth(api, alice, flipper.options.address);414142 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);42 const originalSponsorBalance = await web3.eth.getBalance(sponsor);43 expect(originalFlipperBalance).to.be.not.equal('0');43 expect(originalSponsorBalance).to.be.not.equal('0');444445 await flipper.methods.flip().send({from: caller});45 await flipper.methods.flip().send({from: caller});46 expect(await flipper.methods.getValue().call()).to.be.true;46 expect(await flipper.methods.getValue().call()).to.be.true;474748 // Balance should be taken from flipper instead of caller48 // Balance should be taken from flipper instead of caller49 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);49 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);50 expect(await web3.eth.getBalance(flipper.options.address)).to.be.not.equals(originalFlipperBalance);50 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);51 });51 });5252 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {53 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {53 const alice = privateKeyWrapper('//Alice');54 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);5455 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);55 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);56 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);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');68 await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});68 await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});69 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;69 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;707071 await transferBalanceToEth(api, alice, collector.options.address);71 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});7273 const originalCollectorBalance = await web3.eth.getBalance(collector.options.address);72 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});7374 const originalSponsorBalance = await web3.eth.getBalance(sponsor);74 expect(originalCollectorBalance).to.be.not.equal('0');75 expect(originalSponsorBalance).to.be.not.equal('0');757676 await collector.methods.giveMoney().send({from: caller, value: '10000'});77 await collector.methods.giveMoney().send({from: caller, value: '10000'});777878 // Balance will be taken from both caller (value) and from collector (fee)79 // Balance will be taken from both caller (value) and from collector (fee)79 expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString());80 expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString());80 expect(await web3.eth.getBalance(collector.options.address)).to.be.not.equals(originalCollectorBalance);81 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);81 expect(await collector.methods.getCollected().call()).to.be.equal('10000');82 expect(await collector.methods.getCollected().call()).to.be.equal('10000');82 });83 });83});84});tests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth26 "stateMutability": "view",26 "stateMutability": "view",27 "type": "function"27 "type": "function"28 },28 },29 {30 "inputs": [31 {32 "internalType": "address",33 "name": "contractAddress",34 "type": "address"35 }36 ],37 "name": "confirmSponsorship",38 "outputs": [],39 "stateMutability": "nonpayable",40 "type": "function"41 },29 {42 {30 "inputs": [43 "inputs": [31 {44 {39 "stateMutability": "view",52 "stateMutability": "view",40 "type": "function"53 "type": "function"41 },54 },55 {56 "inputs": [57 {58 "internalType": "address",59 "name": "contractAddress",60 "type": "address"61 }62 ],63 "name": "getSponsor",64 "outputs": [65 {66 "components": [67 { "internalType": "address", "name": "field_0", "type": "address" },68 { "internalType": "uint256", "name": "field_1", "type": "uint256" }69 ],70 "internalType": "struct Tuple0",71 "name": "",72 "type": "tuple"73 }74 ],75 "stateMutability": "view",76 "type": "function"77 },42 {78 {43 "inputs": [79 "inputs": [44 {80 {52 "stateMutability": "view",88 "stateMutability": "view",53 "type": "function"89 "type": "function"54 },90 },91 {92 "inputs": [93 {94 "internalType": "address",95 "name": "contractAddress",96 "type": "address"97 }98 ],99 "name": "hasPendingSponsor",100 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],101 "stateMutability": "view",102 "type": "function"103 },104 {105 "inputs": [106 {107 "internalType": "address",108 "name": "contractAddress",109 "type": "address"110 }111 ],112 "name": "hasSponsor",113 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],114 "stateMutability": "view",115 "type": "function"116 },117 {118 "inputs": [119 {120 "internalType": "address",121 "name": "contractAddress",122 "type": "address"123 }124 ],125 "name": "removeSponsor",126 "outputs": [],127 "stateMutability": "nonpayable",128 "type": "function"129 },130 {131 "inputs": [132 {133 "internalType": "address",134 "name": "contractAddress",135 "type": "address"136 }137 ],138 "name": "selfSponsoredEnable",139 "outputs": [],140 "stateMutability": "nonpayable",141 "type": "function"142 },143 {144 "inputs": [145 {146 "internalType": "address",147 "name": "contractAddress",148 "type": "address"149 },150 { "internalType": "address", "name": "sponsor", "type": "address" }151 ],152 "name": "setSponsor",153 "outputs": [],154 "stateMutability": "nonpayable",155 "type": "function"156 },55 {157 {56 "inputs": [158 "inputs": [57 {159 {143 "outputs": [],245 "outputs": [],144 "stateMutability": "nonpayable",246 "stateMutability": "nonpayable",145 "type": "function"247 "type": "function"146 },248 }147 {148 "inputs": [149 {150 "internalType": "address",151 "name": "contractAddress",152 "type": "address"153 },154 { "internalType": "bool", "name": "enabled", "type": "bool" }155 ],156 "name": "toggleSponsoring",157 "outputs": [],158 "stateMutability": "nonpayable",159 "type": "function"160 }161]249]162250