git.delta.rocks / unique-network / refs/commits / 8138c78fd9cb

difftreelog

Merge branch 'feature/app-staking' of https://github.com/UniqueNetwork/unique-chain into feature/app-staking

PraetorP2022-09-06parents: #fc5b26a #837c29c.patch.diff
in: master

11 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5735,6 +5735,7 @@
 name = "pallet-evm-contract-helpers"
 version = "0.2.0"
 dependencies = [
+ "ethereum",
  "evm-coder",
  "fp-evm-mapping",
  "frame-support",
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -9,6 +9,7 @@
     "derive",
 ] }
 log = { default-features = false, version = "0.4.14" }
+ethereum = { version = "0.12.0", default-features = false }
 
 # Substrate
 frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -17,7 +17,9 @@
 //! Implementation of magic contract
 
 use core::marker::PhantomData;
-use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{
+	abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
+};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};
 use pallet_evm::{
 	ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,
@@ -33,6 +35,35 @@
 use up_sponsorship::SponsorshipHandler;
 use sp_std::vec::Vec;
 
+/// Pallet events.
+#[derive(ToLog)]
+pub enum ContractHelpersEvents {
+	/// Contract sponsor was set.
+	ContractSponsorSet {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+		/// New sponsor address.
+		sponsor: address,
+	},
+
+	/// New sponsor was confirm.
+	ContractSponsorshipConfirmed {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+		/// New sponsor address.
+		sponsor: address,
+	},
+
+	/// Collection sponsor was removed.
+	ContractSponsorRemoved {
+		/// Contract address of the affected collection.
+		#[indexed]
+		contract_address: address,
+	},
+}
+
 /// See [`ContractHelpersCall`]
 pub struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
 impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
@@ -46,7 +77,7 @@
 }
 
 /// @title Magic contract, which allows users to reconfigure other contracts
-#[solidity_interface(name = ContractHelpers)]
+#[solidity_interface(name = ContractHelpers, events(ContractHelpersEvents))]
 impl<T: Config> ContractHelpers<T>
 where
 	T::AccountId: AsRef<[u8; 32]>,
@@ -91,8 +122,12 @@
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
-		Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)
-			.map_err(dispatch_to_evm::<T>)?;
+		Pallet::<T>::force_set_sponsor(
+			&T::CrossAccountId::from_eth(caller),
+			contract_address,
+			&T::CrossAccountId::from_eth(contract_address),
+		)
+		.map_err(dispatch_to_evm::<T>)?;
 
 		Ok(())
 	}
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -16,7 +16,7 @@
 
 #![doc = include_str!("../README.md")]
 #![cfg_attr(not(feature = "std"), no_std)]
-#![deny(missing_docs)]
+#![warn(missing_docs)]
 
 use codec::{Decode, Encode, MaxEncodedLen};
 pub use pallet::*;
@@ -27,18 +27,24 @@
 #[frame_support::pallet]
 pub mod pallet {
 	pub use super::*;
+	use crate::eth::ContractHelpersEvents;
 	use frame_support::pallet_prelude::*;
 	use pallet_evm_coder_substrate::DispatchResult;
 	use sp_core::H160;
-	use pallet_evm::account::CrossAccountId;
+	use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
 	use up_data_structs::SponsorshipState;
+	use evm_coder::ToLog;
 
 	#[pallet::config]
 	pub trait Config:
 		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config
 	{
+		/// Overarching event type.
+		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
+
 		/// Address, under which magic contract will be available
 		type ContractAddress: Get<H160>;
+
 		/// In case of enabled sponsoring, but no sponsoring rate limit set,
 		/// this value will be used implicitly
 		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
@@ -150,6 +156,32 @@
 		QueryKind = ValueQuery,
 	>;
 
+	#[pallet::event]
+	#[pallet::generate_deposit(pub fn deposit_event)]
+	pub enum Event<T: Config> {
+		/// Contract sponsor was set.
+		ContractSponsorSet(
+			/// Contract address of the affected collection.
+			H160,
+			/// New sponsor address.
+			T::AccountId,
+		),
+
+		/// New sponsor was confirm.
+		ContractSponsorshipConfirmed(
+			/// Contract address of the affected collection.
+			H160,
+			/// New sponsor address.
+			T::AccountId,
+		),
+
+		/// Collection sponsor was removed.
+		ContractSponsorRemoved(
+			/// Contract address of the affected collection.
+			H160,
+		),
+	}
+
 	impl<T: Config> Pallet<T> {
 		/// Get contract owner.
 		pub fn contract_owner(contract: H160) -> H160 {
@@ -169,43 +201,108 @@
 				contract,
 				SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),
 			);
+
+			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(
+				contract,
+				sponsor.as_sub().clone(),
+			));
+			<PalletEvm<T>>::deposit_log(
+				ContractHelpersEvents::ContractSponsorSet {
+					contract_address: contract,
+					sponsor: *sponsor.as_eth(),
+				}
+				.to_log(contract),
+			);
 			Ok(())
 		}
 
-		/// Set `contract` as self sponsored.
+		/// Set sponsor as already confirmed.
 		///
 		/// `sender` must be owner of contract.
-		pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
-			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;
+		pub fn force_set_sponsor(
+			sender: &T::CrossAccountId,
+			contract_address: H160,
+			sponsor: &T::CrossAccountId,
+		) -> DispatchResult {
+			Pallet::<T>::ensure_owner(contract_address, *sender.as_eth())?;
 			Sponsoring::<T>::insert(
-				contract,
+				contract_address,
 				SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(
-					contract,
+					contract_address,
 				)),
 			);
+
+			let eth_sponsor = *sponsor.as_eth();
+			let sub_sponsor = sponsor.as_sub().clone();
+
+			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorSet(
+				contract_address,
+				sub_sponsor.clone(),
+			));
+			<PalletEvm<T>>::deposit_log(
+				ContractHelpersEvents::ContractSponsorSet {
+					contract_address,
+					sponsor: eth_sponsor,
+				}
+				.to_log(contract_address),
+			);
+
+			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(
+				contract_address,
+				sub_sponsor,
+			));
+			<PalletEvm<T>>::deposit_log(
+				ContractHelpersEvents::ContractSponsorshipConfirmed {
+					contract_address,
+					sponsor: eth_sponsor,
+				}
+				.to_log(contract_address),
+			);
+
 			Ok(())
 		}
 
 		/// Remove sponsor for `contract`.
 		///
 		/// `sender` must be owner of contract.
-		pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
-			Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;
-			Sponsoring::<T>::remove(contract);
+		pub fn remove_sponsor(sender: &T::CrossAccountId, contract_address: H160) -> DispatchResult {
+			Pallet::<T>::ensure_owner(contract_address, *sender.as_eth())?;
+			Sponsoring::<T>::remove(contract_address);
+
+			<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorRemoved(contract_address));
+			<PalletEvm<T>>::deposit_log(
+				ContractHelpersEvents::ContractSponsorRemoved { contract_address }.to_log(contract_address),
+			);
+
 			Ok(())
 		}
 
 		/// Confirm sponsorship.
 		///
 		/// `sender` must be same that set via [`set_sponsor`].
-		pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {
-			match Sponsoring::<T>::get(contract) {
+		pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract_address: H160) -> DispatchResult {
+			match Sponsoring::<T>::get(contract_address) {
 				SponsorshipState::Unconfirmed(sponsor) => {
 					ensure!(sponsor == *sender, Error::<T>::NoPermission);
+					let eth_sponsor = *sponsor.as_eth();
+					let sub_sponsor = sponsor.as_sub().clone();
 					Sponsoring::<T>::insert(
-						contract,
+						contract_address,
 						SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),
 					);
+
+					<Pallet<T>>::deposit_event(Event::<T>::ContractSponsorshipConfirmed(
+						contract_address,
+						sub_sponsor,
+					));
+					<PalletEvm<T>>::deposit_log(
+						ContractHelpersEvents::ContractSponsorshipConfirmed {
+							contract_address,
+							sponsor: eth_sponsor,
+						}
+						.to_log(contract_address),
+					);
+
 					Ok(())
 				}
 				SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {
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,9 +21,19 @@
 	}
 }
 
+/// @dev inlined interface
+contract ContractHelpersEvents {
+	event ContractSponsorSet(address indexed contractAddress, address sponsor);
+	event ContractSponsorshipConfirmed(
+		address indexed contractAddress,
+		address sponsor
+	);
+	event ContractSponsorRemoved(address indexed contractAddress);
+}
+
 /// @title Magic contract, which allows users to reconfigure other contracts
 /// @dev the ERC-165 identifier for this interface is 0xd77fab70
-contract ContractHelpers is Dummy, ERC165 {
+contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
 	/// Get user, which deployed specified contract
 	/// @dev May return zero address in case if contract is deployed
 	///  using uniquenetwork evm-migration pallet, or using other terms not
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
--- a/runtime/common/config/ethereum.rs
+++ b/runtime/common/config/ethereum.rs
@@ -112,6 +112,7 @@
 }
 
 impl pallet_evm_contract_helpers::Config for Runtime {
+	type Event = Event;
 	type ContractAddress = HelpersContractAddress;
 	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
 }
modifiedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
--- a/runtime/common/construct_runtime/mod.rs
+++ b/runtime/common/construct_runtime/mod.rs
@@ -85,7 +85,7 @@
                 Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,
 
                 EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,
-                EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,
+                EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage, Event<T>} = 151,
                 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,
                 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,
             }
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -12,9 +12,19 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
+/// @dev inlined interface
+interface ContractHelpersEvents {
+	event ContractSponsorSet(address indexed contractAddress, address sponsor);
+	event ContractSponsorshipConfirmed(
+		address indexed contractAddress,
+		address sponsor
+	);
+	event ContractSponsorRemoved(address indexed contractAddress);
+}
+
 /// @title Magic contract, which allows users to reconfigure other contracts
 /// @dev the ERC-165 identifier for this interface is 0xd77fab70
-interface ContractHelpers is Dummy, ERC165 {
+interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
 	/// Get user, which deployed specified contract
 	/// @dev May return zero address in case if contract is deployed
 	///  using uniquenetwork evm-migration pallet, or using other terms not
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -24,6 +24,7 @@
   SponsoringMode,
   createEthAccount,
   ethBalanceViaSub,
+  normalizeEvents,
 } from './util/helpers';
 
 describe('Sponsoring EVM contracts', () => {
@@ -36,6 +37,33 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
   });
 
+  itWeb3.only('Set self sponsored events', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    
+    const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorSet',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: flipper.options.address,
+        },
+      },
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorshipConfirmed',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: flipper.options.address,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -75,6 +103,26 @@
     expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;
   });
   
+  itWeb3('Set sponsor event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    
+    const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorSet',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: sponsor,
+        },
+      },
+    ]);
+  });
+  
   itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -97,6 +145,26 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;
   });
 
+  itWeb3('Confirm sponsorship event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+    await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;
+    const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorshipConfirmed',
+        args: {
+          contractAddress: flipper.options.address,
+          sponsor: sponsor,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
@@ -160,6 +228,28 @@
     expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;
   });
 
+  itWeb3('Remove sponsor event', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const flipper = await deployFlipper(web3, owner);
+    const helpers = contractHelpers(web3, owner);
+
+    await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
+    await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
+    
+    const result = await helpers.methods.removeSponsor(flipper.options.address).send();
+    const events = normalizeEvents(result.events);
+    expect(events).to.be.deep.equal([
+      {
+        address: flipper.options.address,
+        event: 'ContractSponsorRemoved',
+        args: {
+          contractAddress: flipper.options.address,
+        },
+      },
+    ]);
+  });
+
   itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {
     const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
before · tests/src/eth/util/contractHelpersAbi.json
1[2  {3    "inputs": [4      {5        "internalType": "address",6        "name": "contractAddress",7        "type": "address"8      },9      { "internalType": "address", "name": "user", "type": "address" }10    ],11    "name": "allowed",12    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],13    "stateMutability": "view",14    "type": "function"15  },16  {17    "inputs": [18      {19        "internalType": "address",20        "name": "contractAddress",21        "type": "address"22      }23    ],24    "name": "allowlistEnabled",25    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],26    "stateMutability": "view",27    "type": "function"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  },42  {43    "inputs": [44      {45        "internalType": "address",46        "name": "contractAddress",47        "type": "address"48      }49    ],50    "name": "contractOwner",51    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],52    "stateMutability": "view",53    "type": "function"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  },78  {79    "inputs": [80      {81        "internalType": "address",82        "name": "contractAddress",83        "type": "address"84      }85    ],86    "name": "getSponsoringRateLimit",87    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],88    "stateMutability": "view",89    "type": "function"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  },157  {158    "inputs": [159      {160        "internalType": "address",161        "name": "contractAddress",162        "type": "address"163      },164      { "internalType": "uint8", "name": "mode", "type": "uint8" }165    ],166    "name": "setSponsoringMode",167    "outputs": [],168    "stateMutability": "nonpayable",169    "type": "function"170  },171  {172    "inputs": [173      {174        "internalType": "address",175        "name": "contractAddress",176        "type": "address"177      },178      { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }179    ],180    "name": "setSponsoringRateLimit",181    "outputs": [],182    "stateMutability": "nonpayable",183    "type": "function"184  },185  {186    "inputs": [187      {188        "internalType": "address",189        "name": "contractAddress",190        "type": "address"191      }192    ],193    "name": "sponsoringEnabled",194    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],195    "stateMutability": "view",196    "type": "function"197  },198  {199    "inputs": [200      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }201    ],202    "name": "supportsInterface",203    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],204    "stateMutability": "view",205    "type": "function"206  },207  {208    "inputs": [209      {210        "internalType": "address",211        "name": "contractAddress",212        "type": "address"213      },214      { "internalType": "address", "name": "user", "type": "address" },215      { "internalType": "bool", "name": "isAllowed", "type": "bool" }216    ],217    "name": "toggleAllowed",218    "outputs": [],219    "stateMutability": "nonpayable",220    "type": "function"221  },222  {223    "inputs": [224      {225        "internalType": "address",226        "name": "contractAddress",227        "type": "address"228      },229      { "internalType": "bool", "name": "enabled", "type": "bool" }230    ],231    "name": "toggleAllowlist",232    "outputs": [],233    "stateMutability": "nonpayable",234    "type": "function"235  }236]
after · tests/src/eth/util/contractHelpersAbi.json
1[2  {3    "anonymous": false,4    "inputs": [5      {6        "indexed": true,7        "internalType": "address",8        "name": "contractAddress",9        "type": "address"10      }11    ],12    "name": "ContractSponsorRemoved",13    "type": "event"14  },15  {16    "anonymous": false,17    "inputs": [18      {19        "indexed": true,20        "internalType": "address",21        "name": "contractAddress",22        "type": "address"23      },24      {25        "indexed": false,26        "internalType": "address",27        "name": "sponsor",28        "type": "address"29      }30    ],31    "name": "ContractSponsorSet",32    "type": "event"33  },34  {35    "anonymous": false,36    "inputs": [37      {38        "indexed": true,39        "internalType": "address",40        "name": "contractAddress",41        "type": "address"42      },43      {44        "indexed": false,45        "internalType": "address",46        "name": "sponsor",47        "type": "address"48      }49    ],50    "name": "ContractSponsorshipConfirmed",51    "type": "event"52  },53  {54    "inputs": [55      {56        "internalType": "address",57        "name": "contractAddress",58        "type": "address"59      },60      { "internalType": "address", "name": "user", "type": "address" }61    ],62    "name": "allowed",63    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],64    "stateMutability": "view",65    "type": "function"66  },67  {68    "inputs": [69      {70        "internalType": "address",71        "name": "contractAddress",72        "type": "address"73      }74    ],75    "name": "allowlistEnabled",76    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],77    "stateMutability": "view",78    "type": "function"79  },80  {81    "inputs": [82      {83        "internalType": "address",84        "name": "contractAddress",85        "type": "address"86      }87    ],88    "name": "confirmSponsorship",89    "outputs": [],90    "stateMutability": "nonpayable",91    "type": "function"92  },93  {94    "inputs": [95      {96        "internalType": "address",97        "name": "contractAddress",98        "type": "address"99      }100    ],101    "name": "contractOwner",102    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],103    "stateMutability": "view",104    "type": "function"105  },106  {107    "inputs": [108      {109        "internalType": "address",110        "name": "contractAddress",111        "type": "address"112      }113    ],114    "name": "getSponsor",115    "outputs": [116      {117        "components": [118          { "internalType": "address", "name": "field_0", "type": "address" },119          { "internalType": "uint256", "name": "field_1", "type": "uint256" }120        ],121        "internalType": "struct Tuple0",122        "name": "",123        "type": "tuple"124      }125    ],126    "stateMutability": "view",127    "type": "function"128  },129  {130    "inputs": [131      {132        "internalType": "address",133        "name": "contractAddress",134        "type": "address"135      }136    ],137    "name": "getSponsoringRateLimit",138    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],139    "stateMutability": "view",140    "type": "function"141  },142  {143    "inputs": [144      {145        "internalType": "address",146        "name": "contractAddress",147        "type": "address"148      }149    ],150    "name": "hasPendingSponsor",151    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],152    "stateMutability": "view",153    "type": "function"154  },155  {156    "inputs": [157      {158        "internalType": "address",159        "name": "contractAddress",160        "type": "address"161      }162    ],163    "name": "hasSponsor",164    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],165    "stateMutability": "view",166    "type": "function"167  },168  {169    "inputs": [170      {171        "internalType": "address",172        "name": "contractAddress",173        "type": "address"174      }175    ],176    "name": "removeSponsor",177    "outputs": [],178    "stateMutability": "nonpayable",179    "type": "function"180  },181  {182    "inputs": [183      {184        "internalType": "address",185        "name": "contractAddress",186        "type": "address"187      }188    ],189    "name": "selfSponsoredEnable",190    "outputs": [],191    "stateMutability": "nonpayable",192    "type": "function"193  },194  {195    "inputs": [196      {197        "internalType": "address",198        "name": "contractAddress",199        "type": "address"200      },201      { "internalType": "address", "name": "sponsor", "type": "address" }202    ],203    "name": "setSponsor",204    "outputs": [],205    "stateMutability": "nonpayable",206    "type": "function"207  },208  {209    "inputs": [210      {211        "internalType": "address",212        "name": "contractAddress",213        "type": "address"214      },215      { "internalType": "uint8", "name": "mode", "type": "uint8" }216    ],217    "name": "setSponsoringMode",218    "outputs": [],219    "stateMutability": "nonpayable",220    "type": "function"221  },222  {223    "inputs": [224      {225        "internalType": "address",226        "name": "contractAddress",227        "type": "address"228      },229      { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }230    ],231    "name": "setSponsoringRateLimit",232    "outputs": [],233    "stateMutability": "nonpayable",234    "type": "function"235  },236  {237    "inputs": [238      {239        "internalType": "address",240        "name": "contractAddress",241        "type": "address"242      }243    ],244    "name": "sponsoringEnabled",245    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],246    "stateMutability": "view",247    "type": "function"248  },249  {250    "inputs": [251      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }252    ],253    "name": "supportsInterface",254    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],255    "stateMutability": "view",256    "type": "function"257  },258  {259    "inputs": [260      {261        "internalType": "address",262        "name": "contractAddress",263        "type": "address"264      },265      { "internalType": "address", "name": "user", "type": "address" },266      { "internalType": "bool", "name": "isAllowed", "type": "bool" }267    ],268    "name": "toggleAllowed",269    "outputs": [],270    "stateMutability": "nonpayable",271    "type": "function"272  },273  {274    "inputs": [275      {276        "internalType": "address",277        "name": "contractAddress",278        "type": "address"279      },280      { "internalType": "bool", "name": "enabled", "type": "bool" }281    ],282    "name": "toggleAllowlist",283    "outputs": [],284    "stateMutability": "nonpayable",285    "type": "function"286  }287]