git.delta.rocks / unique-network / refs/commits / 999c24f384bf

difftreelog

Merge pull request #469 from UniqueNetwork/feature/refactor_contract_sponsoring

Yaroslav Bolyukin2022-08-25parents: #cdbbf09 #e80fd26.patch.diff
in: master
Feature/refactor contract sponsoring

19 files changed

modifiedCargo.lockdiffbeforeafterboth
2345[[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",
55525552
5553[[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",
57335733
5734[[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",
modifiedcrates/evm-coder/CHANGELOG.mddiffbeforeafterboth
1# Change Log
2
3All notable changes to this project will be documented in this file.
1<!-- bureaucrate goes here -->4## [v0.1.2] 2022-08-19
5
6### Added
7
8 - Implementation `AbiWrite` for tuples.
9
10 ### Fixes
11
12 - Tuple generation for solidity.
13
2## [v0.1.1] 2022-08-1614## [v0.1.1] 2022-08-16
315
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
342 ))342 ))
343 }343 }
344 }344 }
345 #[allow(non_snake_case)]
346 impl<$($ident),+> AbiWrite for &($($ident,)+)
347 where
348 $($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}
347357
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
180 fn is_simple() -> bool {180 fn is_simple() -> bool {
181 false181 false
182 }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, ")")
modifiedpallets/common/CHANGELOG.mddiffbeforeafterboth
22
3All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.
44
5## [0.1.7] - 2022-08-19
6
7### Added
8
9 - Add convert funtion from `CrossAccountId` to eth `uint256`.
10
11
5## [0.1.6] - 2022-08-1612## [0.1.6] - 2022-08-16
613
7### Added14### Added
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
1616
17//! 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.
1818
19use 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;
23
24use crate::Config;
2523
26// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 124// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1
27// TODO: Unhardcode prefix25// TODO: Unhardcode prefix
52 address[0..16] == ETH_COLLECTION_PREFIX50 address[0..16] == ETH_COLLECTION_PREFIX
53}51}
52
53/// Convert `CrossAccountId` to `uint256`.
54pub fn convert_cross_account_to_uint256<T: Config>(from: &T::CrossAccountId) -> uint256
55where
56 T::AccountId: AsRef<[u8; 32]>,
57{
58 let slice = from.as_sub().as_ref();
59 uint256::from_big_endian(slice)
60}
5461
55/// Converts Substrate address to CrossAccountId62/// Converts Substrate address to CrossAccountId
56pub fn convert_substrate_address_to_cross_account_id<T: Config>(63pub fn convert_substrate_address_to_cross_account_id<T: Config>(
modifiedpallets/evm-contract-helpers/CHANGELOG.mddiffbeforeafterboth
1# Change Log
2
3All notable changes to this project will be documented in this file.
4
1<!-- bureaucrate goes here -->5## [v0.2.0] - 2022-08-19
6
7### Added
8
9 - Set arbitrary evm address as contract sponsor.
10 - Ability to remove current sponsor.
11
12### Removed
13 - Remove methods
14 + sponsoring_enabled
15 + toggle_sponsoring
16
17 ### Changed
18
19 - Change `toggle_sponsoring` to `self_sponsored_enable`.
20
21
2## [v0.1.2] 2022-08-1622## [v0.1.2] 2022-08-16
323
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
1616
17use 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;
4244
43#[solidity_interface(name = "ContractHelpers")]45#[solidity_interface(name = "ContractHelpers")]
44impl<T: Config> ContractHelpers<T> {46impl<T: Config> ContractHelpers<T>
47where
48 T::AccountId: AsRef<[u8; 32]>,
49{
50 /// Get contract ovner
51 ///
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 }
4857
58 /// 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()?;
70
71 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>)?;
77
78 Ok(())
79 }
80
81 /// 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()?;
87
50 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>)?;
90
91 Ok(())
51 }92 }
5293
53 /// 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()?;
100
101 Pallet::<T>::remove_sponsor(&T::CrossAccountId::from_eth(caller), contract_address)
102 .map_err(dispatch_to_evm::<T>)?;
103
104 Ok(())
105 }
106
107 /// 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()?;
115
116 Pallet::<T>::confirm_sponsorship(&T::CrossAccountId::from_eth(caller), contract_address)
117 .map_err(dispatch_to_evm::<T>)?;
118
119 Ok(())
120 }
121
122 /// 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 }
138
139 /// 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 }
146
147 /// 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 }
157
158 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
159 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)
160 }
64161
65 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()?;
170
71 <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);
174
84 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()?;
190
87 <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());
193
89 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()?;
220
113 <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);
223
115 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()?;
236
125 <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);
239
127 Ok(())240 Ok(())
128 }241 }
129}242}
130243
131pub 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>
246where
247 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 }
303
304 let sponsor = match <Pallet<T>>::get_sponsor(*contract_address) {
305 Some(sponsor) => sponsor,
306 None => return None,
307 };
186308
187 if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who.as_eth()) {309 if mode == SponsoringModeT::Allowlisted
310 && !<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;
191315
192 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);
194318
195 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 }
200324
201 <SponsorBasket<T>>::insert(&call.0, who.as_eth(), block_number);325 <SponsorBasket<T>>::insert(contract_address, who.as_eth(), block_number);
202326
203 let sponsor = T::CrossAccountId::from_eth(call.0);
204 Some(sponsor)327 Some(sponsor)
205 }328 }
206}329}
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
25#[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;
3133
32 #[pallet::config]34 #[pallet::config]
33 pub trait Config:35 pub trait Config:
3941
40 #[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,
46
47 /// No pending sponsor for contract.
48 NoPendingSponsor,
44 }49 }
4550
46 #[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>(_);
4954
55 /// 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>;
5867
68 /// 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 >;
79
80 /// Store for sponsoring mode.
81 ///
82 /// ### Usage
83 /// 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>;
6290
91 /// 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 >;
71103
104 /// 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 >;
81118
119 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.
120 ///
121 /// ### Usage
122 /// 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>;
85129
130 /// Storage for users that allowed for sponsorship.
131 ///
132 /// ### Usage
133 /// 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 >;
95147
96 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 }
153
154 /// 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 }
169
170 /// 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 }
183
184 /// 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 }
192
193 /// 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 }
211
212 /// 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 }
219
97 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 }
112
113 pub fn toggle_sponsoring(contract: H160, enabled: bool) {
114 Self::set_sponsoring_mode(
115 contract,
116 if enabled {
117 SponsoringModeT::Allowlisted
118 } else {
119 SponsoringModeT::Disabled
120 },
121 )
122 }
123236
124 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 }
139252
140 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 }
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 address field_0;
9 uint256 field_1;
10}
511
6// Common stubs holder12// Common stubs holder
7contract Dummy {13contract Dummy {
21 }27 }
22}28}
2329
24// Selector: 7b4866f930// Selector: 6073d917
25contract ContractHelpers is Dummy, ERC165 {31contract ContractHelpers is Dummy, ERC165 {
32 // Get contract ovner
33 //
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) 5152b14c
27 function contractOwner(address contractAddress)38 function contractOwner(address contractAddress)
28 public39 public
35 return 0x0000000000000000000000000000000000000000;46 return 0x0000000000000000000000000000000000000000;
36 }47 }
48
49 // 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) f01fba93
55 function setSponsor(address contractAddress, address sponsor) public {
56 require(false, stub_error);
57 contractAddress;
58 sponsor;
59 dummy = 0;
60 }
61
62 // Set contract as self sponsored.
63 //
64 // @param contract_address Contract for which a self sponsoring is being enabled.
65 //
66 // Selector: selfSponsoredEnable(address) 89f7d9ae
67 function selfSponsoredEnable(address contractAddress) public {
68 require(false, stub_error);
69 contractAddress;
70 dummy = 0;
71 }
72
73 // Remove sponsor.
74 //
75 // @param contract_address Contract for which a sponsorship is being removed.
76 //
77 // Selector: removeSponsor(address) ef784250
78 function removeSponsor(address contractAddress) public {
79 require(false, stub_error);
80 contractAddress;
81 dummy = 0;
82 }
83
84 // 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) abc00001
91 function confirmSponsorship(address contractAddress) public {
92 require(false, stub_error);
93 contractAddress;
94 dummy = 0;
95 }
96
97 // 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) 743fc745
103 function getSponsor(address contractAddress)
104 public
105 view
106 returns (Tuple0 memory)
107 {
108 require(false, stub_error);
109 contractAddress;
110 dummy;
111 return Tuple0(0x0000000000000000000000000000000000000000, 0);
112 }
113
114 // 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) 97418603
120 function hasSponsor(address contractAddress) public view returns (bool) {
121 require(false, stub_error);
122 contractAddress;
123 dummy;
124 return false;
125 }
126
127 // 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) 39b9b242
133 function hasPendingSponsor(address contractAddress)
134 public
135 view
136 returns (bool)
137 {
138 require(false, stub_error);
139 contractAddress;
140 dummy;
141 return false;
142 }
37143
38 // Selector: sponsoringEnabled(address) 6027dc61144 // Selector: sponsoringEnabled(address) 6027dc61
39 function sponsoringEnabled(address contractAddress)145 function sponsoringEnabled(address contractAddress)
47 return false;153 return false;
48 }154 }
49
50 // Deprecated
51 //
52 // Selector: toggleSponsoring(address,bool) fcac6d86
53 function toggleSponsoring(address contractAddress, bool enabled) public {
54 require(false, stub_error);
55 contractAddress;
56 enabled;
57 dummy = 0;
58 }
59155
60 // Selector: setSponsoringMode(address,uint8) fde8a560156 // Selector: setSponsoringMode(address,uint8) fde8a560
61 function setSponsoringMode(address contractAddress, uint8 mode) public {157 function setSponsoringMode(address contractAddress, uint8 mode) public {
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
167}167}
168168
169#[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.0
178 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(&eth.0[0..8]);185 sub_raw.copy_from_slice(&eth.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.2
194 }
192}195}
193196
194impl Default for TestCrossAccountId {197impl Default for TestCrossAccountId {
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 address field_0;
9 uint256 field_1;
10}
511
6// Common stubs holder12// Common stubs holder
7interface Dummy {13interface Dummy {
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);18 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}19}
1420
15// Selector: 7b4866f921// Selector: 6073d917
16interface ContractHelpers is Dummy, ERC165 {22interface ContractHelpers is Dummy, ERC165 {
23 // Get contract ovner
24 //
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) 5152b14c
18 function contractOwner(address contractAddress)29 function contractOwner(address contractAddress)
19 external30 external
20 view31 view
21 returns (address);32 returns (address);
33
34 // 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) f01fba93
40 function setSponsor(address contractAddress, address sponsor) external;
41
42 // Set contract as self sponsored.
43 //
44 // @param contract_address Contract for which a self sponsoring is being enabled.
45 //
46 // Selector: selfSponsoredEnable(address) 89f7d9ae
47 function selfSponsoredEnable(address contractAddress) external;
48
49 // Remove sponsor.
50 //
51 // @param contract_address Contract for which a sponsorship is being removed.
52 //
53 // Selector: removeSponsor(address) ef784250
54 function removeSponsor(address contractAddress) external;
55
56 // 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) abc00001
63 function confirmSponsorship(address contractAddress) external;
64
65 // 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) 743fc745
71 function getSponsor(address contractAddress)
72 external
73 view
74 returns (Tuple0 memory);
75
76 // 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) 97418603
82 function hasSponsor(address contractAddress) external view returns (bool);
83
84 // 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) 39b9b242
90 function hasPendingSponsor(address contractAddress)
91 external
92 view
93 returns (bool);
2294
23 // Selector: sponsoringEnabled(address) 6027dc6195 // Selector: sponsoringEnabled(address) 6027dc61
24 function sponsoringEnabled(address contractAddress)96 function sponsoringEnabled(address contractAddress)
25 external97 external
26 view98 view
27 returns (bool);99 returns (bool);
28
29 // Deprecated
30 //
31 // Selector: toggleSponsoring(address,bool) fcac6d86
32 function toggleSponsoring(address contractAddress, bool enabled) external;
33100
34 // Selector: setSponsoringMode(address,uint8) fde8a560101 // Selector: setSponsoringMode(address,uint8) fde8a560
35 function setSponsoringMode(address contractAddress, uint8 mode) external;102 function setSponsoringMode(address contractAddress, uint8 mode) external;
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
1import {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';
56
6describe('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 });
40
41 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');
54
55 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)));
59
60 const user = createEthAccount(web3);
61 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
62 expect(nextTokenId).to.be.equal('1');
63
64 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
65 expect(oldPermissions.mintMode).to.be.false;
66 expect(oldPermissions.access).to.be.equal('Normal');
67
68 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});
71
72 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
73 expect(newPermissions.mintMode).to.be.true;
74 expect(newPermissions.access).to.be.equal('AllowList');
75
76 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
77 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
78
79 {
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);
88
89 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 ]);
100
101 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
102 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
103
104 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 });
109
110 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)));
128
129 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();
144
145 const events = normalizeEvents(result.events);
146 const address = collectionIdToAddress(collectionId);
147
148 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});
40167
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
23 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';
4528
46describe('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 });
38
39 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 });
48
47 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 });
5557
59 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 });
6588
89 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 });
99
100 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 });
111
112 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 });
121
122 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();
129
130 expect(result[0]).to.be.eq(flipper.options.address);
131 expect(result[1]).to.be.eq('0');
132 });
133
134 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();
143
144 expect(result[0]).to.be.eq(sponsor);
145 expect(result[1]).to.be.eq('0');
146 });
147
148 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);
153
154 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 });
162
163 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);
169
170 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 });
178
66 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);
183
184 const flipper = await deployFlipper(web3, owner);
185
186 const helpers = contractHelpers(web3, owner);
187
188 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
189 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
190
191 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
192 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
193
194 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
195 const callerBalanceBefore = await ethBalanceViaSub(api, caller);
196
197 await flipper.methods.flip().send({from: caller});
198 expect(await flipper.methods.getValue().call()).to.be.true;
199
200 // Balance should be taken from sponsor instead of caller
201 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 });
206
207 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');
68209
69 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
73214
74 const helpers = contractHelpers(web3, owner);215 const helpers = contractHelpers(web3, owner);
75216
76 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;217 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
218
77 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;
80221
81 await transferBalanceToEth(api, alice, flipper.options.address);222 await transferBalanceToEth(api, alice, flipper.options.address);
82223
83 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);
85226
86 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;
88229
89 // Balance should be taken from flipper instead of caller230 // Balance should be taken from sponsor instead of caller
90 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 });
93236
94 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => {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');
96
97 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);
99241
100 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});
105247
106 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;
110250
111 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});
112253
113 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');
115256
116 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;
118259
119 // Balance should be taken from flipper instead of caller260 // Balance should be taken from flipper instead of caller
120 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 });
123264
124 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => {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}) => {
131272
132 const helpers = contractHelpers(web3, owner);273 const helpers = contractHelpers(web3, owner);
133274
134 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;
138277
139 await transferBalanceToEth(api, alice, flipper.options.address);278 await transferBalanceToEth(api, alice, flipper.options.address);
140279
150 });289 });
151290
152 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {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');
154
155 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);
158295
159 const flipper = await deployFlipper(web3, owner);296 const flipper = await deployFlipper(web3, owner);
160297
161 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});
164301
165 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;
169304
170 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});
171307
172 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);
174310
175 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;
177313
178 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 });
180319
181 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {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');
183
184 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);
187325
191 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});
193331
194 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;
198334
199 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});
200337
201 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');
203340
204 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);
207344
208 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);
210347
211 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 });
215352
219 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 });
223
224 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');
237
238 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)));
242
243 const user = createEthAccount(web3);
244 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
245 expect(nextTokenId).to.be.equal('1');
246
247 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
248 expect(oldPermissions.mintMode).to.be.false;
249 expect(oldPermissions.access).to.be.equal('Normal');
250
251 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});
254
255 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
256 expect(newPermissions.mintMode).to.be.true;
257 expect(newPermissions.access).to.be.equal('AllowList');
258
259 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
260 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
261
262 {
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);
271
272 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 ]);
283
284 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
285 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
286
287 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 });
292
293 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)));
311
312 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();
327
328 const events = normalizeEvents(result.events);
329 const address = collectionIdToAddress(collectionId);
330
331 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});
350361
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
39describe('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});
5255
53 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});
100103
101 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});
115121
116 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});
modifiedtests/src/eth/sponsoring.test.tsdiffbeforeafterboth
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {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';
1919
20describe('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);
23
24 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});
3436
35 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;
39
40 await transferBalanceToEth(api, alice, flipper.options.address);
4141
42 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');
4444
45 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;
4747
48 // Balance should be taken from flipper instead of caller48 // Balance should be taken from flipper instead of caller
49 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 });
52
52 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);
54
55 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;
7070
71 await transferBalanceToEth(api, alice, collector.options.address);71 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});
72
73 const originalCollectorBalance = await web3.eth.getBalance(collector.options.address);72 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});
73
74 const originalSponsorBalance = await web3.eth.getBalance(sponsor);
74 expect(originalCollectorBalance).to.be.not.equal('0');75 expect(originalSponsorBalance).to.be.not.equal('0');
7576
76 await collector.methods.giveMoney().send({from: caller, value: '10000'});77 await collector.methods.giveMoney().send({from: caller, value: '10000'});
7778
78 // 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});
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
26 "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