git.delta.rocks / unique-network / refs/commits / dc6d7fbf1b22

difftreelog

CORE-302 Create collection from EVM principle

Trubnikov Sergey2022-04-13parent: #459d9af.patch.diff
in: master

9 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6078,18 +6078,22 @@
 name = "pallet-evm-contract-helpers"
 version = "0.1.0"
 dependencies = [
+ "ethereum",
  "evm-coder",
  "fp-evm-mapping",
  "frame-support",
  "frame-system",
  "log",
+ "pallet-common",
  "pallet-evm",
  "pallet-evm-coder-substrate",
+ "pallet-nonfungible",
  "parity-scale-codec 3.1.2",
  "scale-info",
  "sp-core",
  "sp-runtime",
  "sp-std",
+ "up-data-structs",
  "up-sponsorship",
 ]
 
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -8,18 +8,28 @@
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
-frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
-frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
-sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
-sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
-sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
-evm-coder = { default-features = false, path = '../../crates/evm-coder' }
-pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
+ethereum = { version = "0.12.0", default-features = false }
+log = { default-features = false, version = "0.4.14" }
+
+# Substrate
+frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' }
+frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' }
+sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' }
+sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' }
+sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.21' }
+
+# Unique
 pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
 fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
 up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.21" }
-log = "0.4.14"
 
+# Locals
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+pallet-common = { default-features = false, path = '../../pallets/common' }
+pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
+pallet-nonfungible = { default-features = false, path = '../../pallets/nonfungible' }
+up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
+
 [dependencies.codec]
 default-features = false
 features = ['derive']
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -15,11 +15,12 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 use core::marker::PhantomData;
-use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{abi::AbiWriter, execution::*, generate_stubgen, solidity_interface, types::*, ToLog};
+use ethereum as _;
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
 use pallet_evm::{
 	ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure,
-	account::CrossAccountId,
+	account::CrossAccountId, Pallet as PalletEvm
 };
 use sp_core::H160;
 use crate::{
@@ -40,6 +41,16 @@
 	}
 }
 
+#[derive(ToLog)]
+pub enum ContractHelperEvent {
+	CollectionCreated {
+		#[indexed]
+		owner: address,
+		#[indexed]
+		collection_id: address,
+	},
+}
+
 #[solidity_interface(name = "ContractHelpers")]
 impl<T: Config> ContractHelpers<T> {
 	fn contract_owner(&self, contract_address: address) -> Result<address> {
@@ -126,6 +137,25 @@
 		<Pallet<T>>::toggle_allowed(contract_address, user, allowed);
 		Ok(())
 	}
+
+	fn create_721_collection(&self, caller: caller) -> Result<address> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let collection_id = <pallet_nonfungible::Pallet<T>>::init_collection(
+			caller.as_sub().clone(),
+			Default::default(),
+		)
+		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+		let address = pallet_common::eth::collection_id_to_address(collection_id);
+
+		<PalletEvm<T>>::deposit_log(
+			ContractHelperEvent::CollectionCreated {
+				owner: *caller.as_eth(),
+				collection_id: address,
+			}
+			.to_log(address),
+		);
+		Ok(address)
+	}
 }
 
 pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
before · pallets/evm-contract-helpers/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use codec::{Decode, Encode, MaxEncodedLen};20pub use pallet::*;21pub use eth::*;22use scale_info::TypeInfo;23pub mod eth;2425#[frame_support::pallet]26pub mod pallet {27	pub use super::*;28	use evm_coder::execution::Result;29	use frame_support::pallet_prelude::*;30	use sp_core::H160;3132	#[pallet::config]33	pub trait Config:34		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config35	{36		type ContractAddress: Get<H160>;37		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;38	}3940	#[pallet::error]41	pub enum Error<T> {42		/// This method is only executable by owner43		NoPermission,44	}4546	#[pallet::pallet]47	#[pallet::generate_store(pub(super) trait Store)]48	pub struct Pallet<T>(_);4950	#[pallet::storage]51	pub(super) type Owner<T: Config> =52		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;5354	#[pallet::storage]55	#[deprecated]56	pub(super) type SelfSponsoring<T: Config> =57		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;5859	#[pallet::storage]60	pub(super) type SponsoringMode<T: Config> =61		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;6263	#[pallet::storage]64	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<65		Hasher = Twox128,66		Key = H160,67		Value = T::BlockNumber,68		QueryKind = ValueQuery,69		OnEmpty = T::DefaultSponsoringRateLimit,70	>;7172	#[pallet::storage]73	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<74		Hasher1 = Twox128,75		Key1 = H160,76		Hasher2 = Twox128,77		Key2 = H160,78		Value = T::BlockNumber,79		QueryKind = OptionQuery,80	>;8182	#[pallet::storage]83	pub(super) type AllowlistEnabled<T: Config> =84		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8586	#[pallet::storage]87	pub(super) type Allowlist<T: Config> = StorageDoubleMap<88		Hasher1 = Twox128,89		Key1 = H160,90		Hasher2 = Twox128,91		Key2 = H160,92		Value = bool,93		QueryKind = ValueQuery,94	>;9596	impl<T: Config> Pallet<T> {97		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {98			<SponsoringMode<T>>::get(contract)99				.or_else(|| {100					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)101				})102				.unwrap_or_default()103		}104		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {105			if mode == SponsoringModeT::Disabled {106				<SponsoringMode<T>>::remove(contract);107			} else {108				<SponsoringMode<T>>::insert(contract, mode);109			}110			<SelfSponsoring<T>>::remove(contract)111		}112113		pub fn toggle_sponsoring(contract: H160, enabled: bool) {114			Self::set_sponsoring_mode(115				contract,116				if enabled {117					SponsoringModeT::Allowlisted118				} else {119					SponsoringModeT::Disabled120				},121			)122		}123124		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {125			<SponsoringRateLimit<T>>::insert(contract, rate_limit);126		}127128		pub fn allowed(contract: H160, user: H160) -> bool {129			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user130		}131132		pub fn toggle_allowlist(contract: H160, enabled: bool) {133			<AllowlistEnabled<T>>::insert(contract, enabled)134		}135136		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {137			<Allowlist<T>>::insert(contract, user, allowed);138		}139140		pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {141			ensure!(<Owner<T>>::get(&contract) == user, "no permission");142			Ok(())143		}144	}145}146147#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]148pub enum SponsoringModeT {149	Disabled,150	Allowlisted,151	Generous,152}153154impl SponsoringModeT {155	fn from_eth(v: u8) -> Option<Self> {156		Some(match v {157			0 => Self::Disabled,158			1 => Self::Allowlisted,159			2 => Self::Generous,160			_ => return None,161		})162	}163	fn to_eth(self) -> u8 {164		match self {165			SponsoringModeT::Disabled => 0,166			SponsoringModeT::Allowlisted => 1,167			SponsoringModeT::Generous => 2,168		}169	}170}171172impl Default for SponsoringModeT {173	fn default() -> Self {174		Self::Disabled175	}176}
after · pallets/evm-contract-helpers/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819use codec::{Decode, Encode, MaxEncodedLen};20pub use pallet::*;21pub use eth::*;22use scale_info::TypeInfo;23pub mod eth;2425#[frame_support::pallet]26pub mod pallet {27	pub use super::*;28	use evm_coder::execution::Result;29	use frame_support::pallet_prelude::*;30	use sp_core::H160;3132	#[pallet::config]33	pub trait Config:34		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config + pallet_nonfungible::Config35	{36		type ContractAddress: Get<H160>;37		type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;38	}3940	#[pallet::error]41	pub enum Error<T> {42		/// This method is only executable by owner43		NoPermission,44	}4546	#[pallet::pallet]47	#[pallet::generate_store(pub(super) trait Store)]48	pub struct Pallet<T>(_);4950	#[pallet::storage]51	pub(super) type Owner<T: Config> =52		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;5354	#[pallet::storage]55	#[deprecated]56	pub(super) type SelfSponsoring<T: Config> =57		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;5859	#[pallet::storage]60	pub(super) type SponsoringMode<T: Config> =61		StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;6263	#[pallet::storage]64	pub(super) type SponsoringRateLimit<T: Config> = StorageMap<65		Hasher = Twox128,66		Key = H160,67		Value = T::BlockNumber,68		QueryKind = ValueQuery,69		OnEmpty = T::DefaultSponsoringRateLimit,70	>;7172	#[pallet::storage]73	pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<74		Hasher1 = Twox128,75		Key1 = H160,76		Hasher2 = Twox128,77		Key2 = H160,78		Value = T::BlockNumber,79		QueryKind = OptionQuery,80	>;8182	#[pallet::storage]83	pub(super) type AllowlistEnabled<T: Config> =84		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;8586	#[pallet::storage]87	pub(super) type Allowlist<T: Config> = StorageDoubleMap<88		Hasher1 = Twox128,89		Key1 = H160,90		Hasher2 = Twox128,91		Key2 = H160,92		Value = bool,93		QueryKind = ValueQuery,94	>;9596	impl<T: Config> Pallet<T> {97		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {98			<SponsoringMode<T>>::get(contract)99				.or_else(|| {100					<SelfSponsoring<T>>::get(contract).then(|| SponsoringModeT::Allowlisted)101				})102				.unwrap_or_default()103		}104		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {105			if mode == SponsoringModeT::Disabled {106				<SponsoringMode<T>>::remove(contract);107			} else {108				<SponsoringMode<T>>::insert(contract, mode);109			}110			<SelfSponsoring<T>>::remove(contract)111		}112113		pub fn toggle_sponsoring(contract: H160, enabled: bool) {114			Self::set_sponsoring_mode(115				contract,116				if enabled {117					SponsoringModeT::Allowlisted118				} else {119					SponsoringModeT::Disabled120				},121			)122		}123124		pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {125			<SponsoringRateLimit<T>>::insert(contract, rate_limit);126		}127128		pub fn allowed(contract: H160, user: H160) -> bool {129			<Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user130		}131132		pub fn toggle_allowlist(contract: H160, enabled: bool) {133			<AllowlistEnabled<T>>::insert(contract, enabled)134		}135136		pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {137			<Allowlist<T>>::insert(contract, user, allowed);138		}139140		pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {141			ensure!(<Owner<T>>::get(&contract) == user, "no permission");142			Ok(())143		}144	}145}146147#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]148pub enum SponsoringModeT {149	Disabled,150	Allowlisted,151	Generous,152}153154impl SponsoringModeT {155	fn from_eth(v: u8) -> Option<Self> {156		Some(match v {157			0 => Self::Disabled,158			1 => Self::Allowlisted,159			2 => Self::Generous,160			_ => return None,161		})162	}163	fn to_eth(self) -> u8 {164		match self {165			SponsoringModeT::Disabled => 0,166			SponsoringModeT::Allowlisted => 1,167			SponsoringModeT::Generous => 2,168		}169	}170}171172impl Default for SponsoringModeT {173	fn default() -> Self {174		Self::Disabled175	}176}
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: 7b4866f9
+// Selector: e123b7a8
 contract ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
@@ -144,4 +144,11 @@
 		allowed;
 		dummy = 0;
 	}
+
+	// Selector: create721Collection() 9a6bd151
+	function create721Collection() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
 }
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: 7b4866f9
+// Selector: e123b7a8
 interface ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
@@ -71,4 +71,7 @@
 		address user,
 		bool allowed
 	) external;
+
+	// Selector: create721Collection() 9a6bd151
+	function create721Collection() external view returns (address);
 }
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -14,9 +14,21 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee, usingWeb3} from './util/helpers';
+import {
+  collectionIdFromAddress, 
+  collectionIdToAddress, 
+  contractHelpers, 
+  createEthAccount, 
+  createEthAccountWithBalance, 
+  deployFlipper, 
+  ethBalanceViaSub, 
+  GAS_ARGS, 
+  itWeb3, 
+  recordEthFee, 
+  usingWeb3,
+} from './util/helpers';
 import {expect} from 'chai';
-import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';
+import {createCollectionExpectSuccess, createItemExpectSuccess, getCreatedCollectionCount, UNIQUE} from '../util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import privateKey from '../substrate/privateKey';
 import {Contract} from 'web3-eth-contract';
@@ -112,3 +124,18 @@
     expect(await contract(web3).methods.supportsInterface('0x01ffc9a7').call()).to.be.true;
   });
 });
+
+describe('Create collection from EVM', () => {
+  itWeb3('Create collection', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    console.log(owner);
+    const helpers = contractHelpers(web3, owner);
+    const collectionCountBefore = await getCreatedCollectionCount(api);
+    const result = await helpers.methods.create721Collection().send();
+    console.log(result.events[0].raw);
+    const collectionId = collectionIdFromAddress(result.events[0].raw.topics[2]);
+    const collectionCountAfter = await getCreatedCollectionCount(api);
+    expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
+    expect(collectionId).to.be.eq(collectionCountAfter);
+  });
+});
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -1,216 +1,248 @@
 [
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "contract",
-                "type": "address"
-            }
-        ],
-        "name": "allowlistEnabled",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "caller",
-                "type": "address"
-            }
-        ],
-        "name": "allowed",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            }
-        ],
-        "name": "contractOwner",
-        "outputs": [
-            {
-                "internalType": "address",
-                "name": "",
-                "type": "address"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            }
-        ],
-        "name": "sponsoringEnabled",
-        "outputs": [
-            {
-                "internalType": "bool",
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            },
-            {
-                "internalType": "address",
-                "name": "user",
-                "type": "address"
-            },
-            {
-                "internalType": "bool",
-                "name": "isAllowed",
-                "type": "bool"
-            }
-        ],
-        "name": "toggleAllowed",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            },
-            {
-                "internalType": "bool",
-                "name": "enabled",
-                "type": "bool"
-            }
-        ],
-        "name": "toggleAllowlist",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "type": "address"
-            },
-            {
-                "internalType": "bool",
-                "name": "enabled",
-                "type": "bool"
-            }
-        ],
-        "name": "toggleSponsoring",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "target",
-                "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"
-            }
-        ],
-        "name": "setSponsoringRateLimit",
-        "outputs": [],
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "inputs": [
-            {
-                "internalType": "address",
-                "name": "contractAddress",
-                "type": "address"
-            }
-        ],
-        "name": "getSponsoringRateLimit",
-        "outputs": [
-            {
-                "internalType": "uint32",
-                "name": "",
-                "type": "uint32"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    }
-]
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "user",
+				"type": "address"
+			}
+		],
+		"name": "allowed",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			}
+		],
+		"name": "allowlistEnabled",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			}
+		],
+		"name": "contractOwner",
+		"outputs": [
+			{
+				"internalType": "address",
+				"name": "",
+				"type": "address"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [],
+		"name": "create721Collection",
+		"outputs": [
+			{
+				"internalType": "address",
+				"name": "",
+				"type": "address"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			}
+		],
+		"name": "getSponsoringRateLimit",
+		"outputs": [
+			{
+				"internalType": "uint32",
+				"name": "",
+				"type": "uint32"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "uint8",
+				"name": "mode",
+				"type": "uint8"
+			}
+		],
+		"name": "setSponsoringMode",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "uint32",
+				"name": "rateLimit",
+				"type": "uint32"
+			}
+		],
+		"name": "setSponsoringRateLimit",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			}
+		],
+		"name": "sponsoringEnabled",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			}
+		],
+		"name": "sponsoringMode",
+		"outputs": [
+			{
+				"internalType": "uint8",
+				"name": "",
+				"type": "uint8"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "bytes4",
+				"name": "interfaceID",
+				"type": "bytes4"
+			}
+		],
+		"name": "supportsInterface",
+		"outputs": [
+			{
+				"internalType": "bool",
+				"name": "",
+				"type": "bool"
+			}
+		],
+		"stateMutability": "view",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "address",
+				"name": "user",
+				"type": "address"
+			},
+			{
+				"internalType": "bool",
+				"name": "allowed",
+				"type": "bool"
+			}
+		],
+		"name": "toggleAllowed",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "bool",
+				"name": "enabled",
+				"type": "bool"
+			}
+		],
+		"name": "toggleAllowlist",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"type": "function"
+	},
+	{
+		"inputs": [
+			{
+				"internalType": "address",
+				"name": "contractAddress",
+				"type": "address"
+			},
+			{
+				"internalType": "bool",
+				"name": "enabled",
+				"type": "bool"
+			}
+		],
+		"name": "toggleSponsoring",
+		"outputs": [],
+		"stateMutability": "nonpayable",
+		"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
@@ -72,6 +72,9 @@
   ]);
   return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));
 }
+export function collectionIdFromAddress(address: string): number {
+  return Number('0x' + address.substring(address.length - 8));
+}
 
 export function tokenIdToAddress(collection: number, token: number): string {
   const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0,
@@ -84,7 +87,6 @@
   return {
     Ethereum: tokenIdToAddress(collection, token),
   };
-}
 
 export function createEthAccount(web3: Web3) {
   const account = web3.eth.accounts.create();