git.delta.rocks / unique-network / refs/commits / 886d2a88cd00

difftreelog

Merge pull request #281 from UniqueNetwork/feature/contract-sponsoring-modes

kozyrevdev2022-02-17parents: #57eee2a #97d7053.patch.diff
in: master
Generous contract sponsoring mode

12 files changed

modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi.rs
+++ b/crates/evm-coder/src/abi.rs
@@ -95,6 +95,10 @@
 		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
 	}
 
+	pub fn uint8(&mut self) -> Result<u8> {
+		Ok(self.read_padleft::<1>()?[0])
+	}
+
 	pub fn uint32(&mut self) -> Result<u32> {
 		Ok(u32::from_be_bytes(self.read_padleft()?))
 	}
@@ -243,6 +247,7 @@
 	};
 }
 
+impl_abi_readable!(u8, uint8);
 impl_abi_readable!(u32, uint32);
 impl_abi_readable!(u64, uint64);
 impl_abi_readable!(u128, uint128);
deletedpallets/evm-contract-helpers/exp.rsdiffbeforeafterboth

no changes

modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -4,7 +4,7 @@
 use pallet_evm::{ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure};
 use sp_core::H160;
 use crate::{
-	AllowlistEnabled, Config, Owner, Pallet, SelfSponsoring, SponsorBasket, SponsoringRateLimit,
+	AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,
 };
 use frame_support::traits::Get;
 use up_sponsorship::SponsorshipHandler;
@@ -28,9 +28,10 @@
 	}
 
 	fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
-		Ok(<SelfSponsoring<T>>::get(contract_address))
+		Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)
 	}
 
+	/// Deprecated
 	fn toggle_sponsoring(
 		&mut self,
 		caller: caller,
@@ -42,6 +43,22 @@
 		Ok(())
 	}
 
+	fn set_sponsoring_mode(
+		&mut self,
+		caller: caller,
+		contract_address: address,
+		mode: uint8,
+	) -> Result<void> {
+		<Pallet<T>>::ensure_owner(contract_address, caller)?;
+		let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;
+		<Pallet<T>>::set_sponsoring_mode(contract_address, mode);
+		Ok(())
+	}
+
+	fn sponsoring_mode(&self, contract_address: address) -> Result<uint8> {
+		Ok(<Pallet<T>>::sponsoring_mode(contract_address).to_eth())
+	}
+
 	fn set_sponsoring_rate_limit(
 		&mut self,
 		caller: caller,
@@ -146,10 +163,11 @@
 pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);
 impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for HelpersContractSponsoring<T> {
 	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {
-		if !<SelfSponsoring<T>>::get(&call.0) {
+		let mode = <Pallet<T>>::sponsoring_mode(call.0);
+		if mode == SponsoringModeT::Disabled {
 			return None;
 		}
-		if !<Pallet<T>>::allowed(call.0, *who) {
+		if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who) {
 			return None;
 		}
 		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -1,11 +1,14 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
+use codec::{Decode, Encode, MaxEncodedLen};
 pub use pallet::*;
 pub use eth::*;
+use scale_info::TypeInfo;
 pub mod eth;
 
 #[frame_support::pallet]
 pub mod pallet {
+	pub use super::*;
 	use evm_coder::execution::Result;
 	use frame_support::pallet_prelude::*;
 	use sp_core::H160;
@@ -31,10 +34,15 @@
 		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;
 
 	#[pallet::storage]
+	#[deprecated]
 	pub(super) type SelfSponsoring<T: Config> =
 		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;
 
 	#[pallet::storage]
+	pub(super) type SponsoringMode<T: Config> =
+		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;
+
+	#[pallet::storage]
 	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<
 		Hasher = Twox128,
 		Key = H160,
@@ -68,8 +76,31 @@
 	>;
 
 	impl<T: Config> Pallet<T> {
+		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {
+			<SponsoringMode<T>>::get(contract)
+				.or_else(|| {
+					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)
+				})
+				.unwrap_or_default()
+		}
+		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {
+			if mode == SponsoringModeT::Disabled {
+				<SponsoringMode<T>>::remove(contract);
+			} else {
+				<SponsoringMode<T>>::insert(contract, mode);
+			}
+			<SelfSponsoring<T>>::remove(contract)
+		}
+
 		pub fn toggle_sponsoring(contract: H160, enabled: bool) {
-			<SelfSponsoring<T>>::insert(contract, enabled);
+			Self::set_sponsoring_mode(
+				contract,
+				if enabled {
+					SponsoringModeT::Allowlisted
+				} else {
+					SponsoringModeT::Disabled
+				},
+			)
 		}
 
 		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {
@@ -94,3 +125,34 @@
 		}
 	}
 }
+
+#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]
+pub enum SponsoringModeT {
+	Disabled,
+	Allowlisted,
+	Generous,
+}
+
+impl SponsoringModeT {
+	fn from_eth(v: u8) -> Option<Self> {
+		Some(match v {
+			0 => Self::Disabled,
+			1 => Self::Allowlisted,
+			2 => Self::Generous,
+			_ => return None,
+		})
+	}
+	fn to_eth(self) -> u8 {
+		match self {
+			SponsoringModeT::Disabled => 0,
+			SponsoringModeT::Allowlisted => 1,
+			SponsoringModeT::Generous => 2,
+		}
+	}
+}
+
+impl Default for SponsoringModeT {
+	fn default() -> Self {
+		Self::Disabled
+	}
+}
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -21,7 +21,7 @@
 	}
 }
 
-// Selector: 31acb1fe
+// Selector: 7b4866f9
 contract ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
@@ -47,6 +47,8 @@
 		return false;
 	}
 
+	// Deprecated
+	//
 	// Selector: toggleSponsoring(address,bool) fcac6d86
 	function toggleSponsoring(address contractAddress, bool enabled) public {
 		require(false, stub_error);
@@ -55,6 +57,26 @@
 		dummy = 0;
 	}
 
+	// Selector: setSponsoringMode(address,uint8) fde8a560
+	function setSponsoringMode(address contractAddress, uint8 mode) public {
+		require(false, stub_error);
+		contractAddress;
+		mode;
+		dummy = 0;
+	}
+
+	// Selector: sponsoringMode(address) b70c7267
+	function sponsoringMode(address contractAddress)
+		public
+		view
+		returns (uint8)
+	{
+		require(false, stub_error);
+		contractAddress;
+		dummy;
+		return 0;
+	}
+
 	// Selector: setSponsoringRateLimit(address,uint32) 77b6c908
 	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
 		public
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -12,7 +12,7 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
-// Selector: 31acb1fe
+// Selector: 7b4866f9
 interface ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
@@ -26,9 +26,20 @@
 		view
 		returns (bool);
 
+	// Deprecated
+	//
 	// Selector: toggleSponsoring(address,bool) fcac6d86
 	function toggleSponsoring(address contractAddress, bool enabled) external;
 
+	// Selector: setSponsoringMode(address,uint8) fde8a560
+	function setSponsoringMode(address contractAddress, uint8 mode) external;
+
+	// Selector: sponsoringMode(address) b70c7267
+	function sponsoringMode(address contractAddress)
+		external
+		view
+		returns (uint8);
+
 	// Selector: setSponsoringRateLimit(address,uint32) 77b6c908
 	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)
 		external;
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -10,7 +10,10 @@
   createEthAccountWithBalance,
   transferBalanceToEth,
   deployFlipper,
-  itWeb3} from './util/helpers';
+  itWeb3,
+  SponsoringMode,
+  createEthAccount,
+} from './util/helpers';
 
 describe('Sponsoring EVM contracts', () => {
   itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {
@@ -18,7 +21,7 @@
     const flipper = await deployFlipper(web3, owner);
     const helpers = contractHelpers(web3, owner);
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
   });
 
@@ -28,11 +31,11 @@
     const flipper = await deployFlipper(web3, owner);
     const helpers = contractHelpers(web3, owner);
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await expect(helpers.methods.toggleSponsoring(notOwner, true).send({from: notOwner})).to.rejected;
+    await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
   });
 
-  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}) => {
+  itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3}) => {
     const alice = privateKey('//Alice');
 
     const owner = await createEthAccountWithBalance(api, web3);
@@ -41,11 +44,39 @@
     const flipper = await deployFlipper(web3, owner);
 
     const helpers = contractHelpers(web3, owner);
+
+    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
+    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
+    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
+
+    await transferBalanceToEth(api, alice, flipper.options.address);
+
+    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);
+    expect(originalFlipperBalance).to.be.not.equal('0');
+
+    await flipper.methods.flip().send({from: caller});
+    expect(await flipper.methods.getValue().call()).to.be.true;
+
+    // Balance should be taken from flipper instead of caller
+    const balanceAfter = await web3.eth.getBalance(flipper.options.address);
+    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);
+  });
+
+  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}) => {
+    const alice = privateKey('//Alice');
+
+    const owner = await createEthAccountWithBalance(api, web3);
+    const caller = createEthAccount(web3);
+
+    const flipper = await deployFlipper(web3, owner);
+
+    const helpers = contractHelpers(web3, owner);
     await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});
     await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
 
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
 
@@ -66,14 +97,14 @@
     const alice = privateKey('//Alice');
 
     const owner = await createEthAccountWithBalance(api, web3);
-    const caller = await createEthAccountWithBalance(api, web3);
+    const caller = createEthAccount(web3);
 
     const flipper = await deployFlipper(web3, owner);
 
     const helpers = contractHelpers(web3, owner);
 
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
 
@@ -104,7 +135,7 @@
     await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
 
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
 
@@ -133,7 +164,7 @@
     await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
 
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
 
@@ -157,33 +188,4 @@
     const helpers = contractHelpers(web3, owner);
     expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');
   });
-
-  itWeb3('If allowlist mode is off and sponsorship is on, sponsorship does not work', async ({api, web3}) => {
-    const alice = privateKey('//Alice');
-
-    const owner = await createEthAccountWithBalance(api, web3);
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const flipper = await deployFlipper(web3, owner);
-
-    const helpers = contractHelpers(web3, owner);
-
-    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
-    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
-    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
-
-    await transferBalanceToEth(api, alice, flipper.options.address);
-
-    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);
-    expect(originalFlipperBalance).to.be.not.equal('0');
-
-    await flipper.methods.flip().send({from: caller});
-    expect(await flipper.methods.getValue().call()).to.be.true;
-
-    // Balance should be taken from flipper instead of caller
-    const balanceAfter = await web3.eth.getBalance(flipper.options.address);
-    expect(+balanceAfter).to.be.equals(+originalFlipperBalance);
-  });
-
 });
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
--- a/tests/src/eth/marketplace/marketplace.test.ts
+++ b/tests/src/eth/marketplace/marketplace.test.ts
@@ -2,7 +2,7 @@
 import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance';
 import privateKey from '../../substrate/privateKey';
 import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionLimitsExpectSuccess, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';
-import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';
+import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, SponsoringMode, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';
 import {evmToAddress} from '@polkadot/util-crypto';
 import nonFungibleAbi from '../nonFungibleAbi.json';
 import fungibleAbi from '../fungibleAbi.json';
@@ -20,7 +20,7 @@
     });
     const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});
     const helpers = contractHelpers(web3, matcherOwner);
-    await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});
+    await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
     await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
     await transferBalanceToEth(api, alice, matcher.options.address);
 
@@ -147,7 +147,7 @@
     const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});
     await matcher.methods.setEscrow(escrow).send({from: matcherOwner});
     const helpers = contractHelpers(web3, matcherOwner);
-    await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});
+    await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});
     await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
     await transferBalanceToEth(api, alice, matcher.options.address);
 
modifiedtests/src/eth/sponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/sponsoring.test.ts
+++ b/tests/src/eth/sponsoring.test.ts
@@ -1,6 +1,6 @@
 import {expect} from 'chai';
 import privateKey from '../substrate/privateKey';
-import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, transferBalanceToEth} from './util/helpers';
+import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode, transferBalanceToEth} from './util/helpers';
 
 describe('EVM sponsoring', () => {
   itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3}) => {
@@ -18,7 +18,7 @@
     await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});
 
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(flipper.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;
 
@@ -49,7 +49,7 @@
     await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner});
 
     expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.false;
-    await helpers.methods.toggleSponsoring(collector.options.address, true).send({from: owner});
+    await helpers.methods.setSponsoringMode(collector.options.address, SponsoringMode.Allowlisted).send({from: owner});
     await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});
     expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;
 
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -147,6 +147,43 @@
                 "type": "address"
             },
             {
+                "internalType": "uint8",
+                "name": "mode",
+                "type": "uint8"
+            }
+        ],
+        "name": "setSponsoringMode",
+        "outputs": [],
+        "stateMutability": "nonpayable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
+                "internalType": "address",
+                "name": "target",
+                "type": "address"
+            }
+        ],
+        "name": "sponsoringMode",
+        "outputs": [
+            {
+                "internalType": "uint8",
+                "name": "",
+                "type": "uint8"
+            }
+        ],
+        "stateMutability": "nonpayable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
+                "internalType": "address",
+                "name": "target",
+                "type": "address"
+            },
+            {
                 "internalType": "uint32",
                 "name": "limit",
                 "type": "uint32"
@@ -176,4 +213,4 @@
         "stateMutability": "view",
         "type": "function"
     }
-]
\ No newline at end of file
+]
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -21,6 +21,12 @@
 
 export const GAS_ARGS = {gas: 2500000};
 
+export enum SponsoringMode {
+  Disabled = 0,
+  Allowlisted = 1,
+  Generous = 2,
+}
+
 let web3Connected = false;
 export async function usingWeb3<T>(cb: (web3: Web3) => Promise<T> | T): Promise<T> {
   if (web3Connected) throw new Error('do not nest usingWeb3 calls');