git.delta.rocks / unique-network / refs/commits / 1062e172486e

difftreelog

Merge pull request #343 from UniqueNetwork/feature/CORE-302

bugrazoid2022-05-27parents: #459d9af #e5c2d12.patch.diff
in: master
Feature/core 302

49 files changed

added.maintain/scripts/generate_abi.shdiffbeforeafterboth
--- /dev/null
+++ b/.maintain/scripts/generate_abi.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -eu
+
+dir=$PWD
+
+tmp=$(mktemp -d)
+cd $tmp
+cp $dir/$INPUT input.sol
+solcjs --abi -p input.sol
+
+NAME=input_sol_$(basename $INPUT .sol)
+mv $NAME.abi $NAME.json
+prettier $NAME.json > $dir/$OUTPUT
deleted.maintain/scripts/generate_api.shdiffbeforeafterboth
--- a/.maintain/scripts/generate_api.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-set -eu
-
-tmp=$(mktemp)
-cargo test --package $PACKAGE -- $NAME --exact --nocapture --ignored | tee $tmp
-raw=$(mktemp --suffix .sol)
-sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw
-formatted=$(mktemp)
-prettier --use-tabs $raw > $formatted
-
-mv $formatted $OUTPUT
added.maintain/scripts/generate_sol.shdiffbeforeafterboth
--- /dev/null
+++ b/.maintain/scripts/generate_sol.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -eu
+
+tmp=$(mktemp)
+cargo test --package $PACKAGE -- $NAME --exact --nocapture --ignored | tee $tmp
+raw=$(mktemp --suffix .sol)
+sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw
+formatted=$(mktemp)
+prettier --use-tabs $raw > $formatted
+
+mv $formatted $OUTPUT
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4290,6 +4290,9 @@
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+dependencies = [
+ "spin",
+]
 
 [[package]]
 name = "lazycell"
@@ -5467,9 +5470,9 @@
 
 [[package]]
 name = "once_cell"
-version = "1.11.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca"
+checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
 
 [[package]]
 name = "opal-runtime"
@@ -5917,6 +5920,7 @@
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "lazy_static",
  "pallet-evm",
  "pallet-evm-coder-substrate",
  "parity-scale-codec 3.1.2",
@@ -6083,6 +6087,7 @@
  "frame-support",
  "frame-system",
  "log",
+ "pallet-common",
  "pallet-evm",
  "pallet-evm-coder-substrate",
  "parity-scale-codec 3.1.2",
@@ -6090,6 +6095,7 @@
  "sp-core",
  "sp-runtime",
  "sp-std",
+ "up-data-structs",
  "up-sponsorship",
 ]
 
@@ -6814,13 +6820,18 @@
 name = "pallet-unique"
 version = "0.1.0"
 dependencies = [
+ "ethereum",
+ "evm-coder",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
  "pallet-common",
  "pallet-evm",
+ "pallet-evm-coder-substrate",
+ "pallet-nonfungible",
  "parity-scale-codec 3.1.2",
  "scale-info",
+ "serde",
  "sp-core",
  "sp-io",
  "sp-runtime",
@@ -12005,9 +12016,9 @@
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
+checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
 
 [[package]]
 name = "tempfile"
modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -1,33 +1,61 @@
 .PHONY: _help
 _help:
 	@echo "regenerate_solidity - generate stubs/interfaces for contracts defined in native (via evm-coder)"
-	@echo "evm_stubs - recompile contract stubs"
+	@echo "evm_stubs - recompile contract stubs and ABI"
 	@echo "bench - run frame-benchmarking"
 	@echo "  bench-evm-migration"
 	@echo "  bench-unique"
 
+FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs
+FUNGIBLE_EVM_ABI=./tests/src/eth/fungibleAbi.json
+
+NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs
+NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json
+
+CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/
+CONTRACT_HELPERS_ABI=./tests/src/eth/util/contractHelpersAbi.json
+
+COLLECTION_HELPER_STUBS=./pallets/unique/src/eth/stubs/
+COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelperAbi.json
+
+TESTS_API=./tests/src/eth/api/
+
 .PHONY: regenerate_solidity
-regenerate_solidity:
-	PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=./tests/src/eth/api/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=./tests/src/eth/api/ContractHelpers.sol ./.maintain/scripts/generate_api.sh
+regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol CollectionHelper.sol
+
+UniqueFungible.sol:
+	PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
+	PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=$(FUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
+
+UniqueNFT.sol:
+	PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
+	PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
+
+ContractHelpers.sol:
+	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
+	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=$(CONTRACT_HELPERS_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
+
+CollectionHelper.sol:
+	PACKAGE=pallet-unique NAME=eth::collection_helper_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
+	PACKAGE=pallet-unique NAME=eth::collection_helper_impl OUTPUT=$(COLLECTION_HELPER_STUBS)/$@ ./.maintain/scripts/generate_sol.sh
+
+UniqueFungible: UniqueFungible.sol
+	INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw ./.maintain/scripts/compile_stub.sh
+	INPUT=$(FUNGIBLE_EVM_STUBS)/$< OUTPUT=$(FUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh
 
-	PACKAGE=pallet-fungible NAME=erc::gen_impl OUTPUT=./pallets/fungible/src/stubs/UniqueFungible.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=./pallets/nonfungible/src/stubs/UniqueNFT.sol ./.maintain/scripts/generate_api.sh
-	PACKAGE=pallet-evm-contract-helpers NAME=eth::contract_helpers_impl OUTPUT=./pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol ./.maintain/scripts/generate_api.sh
+UniqueNFT: UniqueNFT.sol
+	INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw ./.maintain/scripts/compile_stub.sh
+	INPUT=$(NONFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(NONFUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh
 
-FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs
-NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs
-CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/
+ContractHelpers: ContractHelpers.sol
+	INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw ./.maintain/scripts/compile_stub.sh
+	INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_ABI) ./.maintain/scripts/generate_abi.sh
 
-$(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.sol
-	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
-$(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw: $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.sol
-	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
-$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw: $(CONTRACT_HELPERS_STUBS)/ContractHelpers.sol
-	INPUT=$< OUTPUT=$@ ./.maintain/scripts/compile_stub.sh
+CollectionHelper: CollectionHelper.sol
+	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelper.raw ./.maintain/scripts/compile_stub.sh
+	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh
 
-evm_stubs: $(FUNGIBLE_EVM_STUBS)/UniqueFungible.raw $(NONFUNGIBLE_EVM_STUBS)/UniqueNFT.raw $(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw
+evm_stubs: UniqueFungible UniqueNFT ContractHelpers CollectionHelper
 
 .PHONY: _bench
 _bench:
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -327,7 +327,7 @@
 	}
 }
 
-#[impl_for_tuples(1, 5)]
+#[impl_for_tuples(1, 12)]
 impl SolidityArguments for Tuple {
 	for_tuples!( where #( Tuple: SolidityArguments ),* );
 
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -16,16 +16,18 @@
 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" }
+frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
 fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
 pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
+
 serde = { version = "1.0.130", default-features = false }
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
-frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.21" }
+lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
 
 [features]
 default = ["std"]
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -14,12 +14,17 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-use evm_coder::{solidity_interface, types::*, execution::Result};
+use evm_coder::{
+	solidity_interface,
+	types::*,
+	execution::{Result, Error},
+};
 pub use pallet_evm::{PrecompileOutput, PrecompileResult, account::CrossAccountId};
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_core::{H160, U256};
 use sp_std::vec::Vec;
-use up_data_structs::Property;
+use up_data_structs::{Property, SponsoringRateLimit};
+use alloc::format;
 
 use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
 
@@ -31,7 +36,7 @@
 	fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult>;
 }
 
-#[solidity_interface(name = "CollectionProperties")]
+#[solidity_interface(name = "Collection")]
 impl<T: Config> CollectionHandle<T> {
 	fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -64,4 +69,93 @@
 
 		Ok(prop.to_vec())
 	}
+
+	fn eth_set_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {
+		check_is_owner(caller, self)?;
+
+		let sponsor = T::CrossAccountId::from_eth(sponsor);
+		self.set_sponsor(sponsor.as_sub().clone());
+		save(self);
+		Ok(())
+	}
+
+	fn eth_confirm_sponsorship(&mut self, caller: caller) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		if !self.confirm_sponsorship(caller.as_sub()) {
+			return Err(Error::Revert("Caller is not set as sponsor".into()));
+		}
+		save(self);
+		Ok(())
+	}
+
+	fn set_limit(&mut self, caller: caller, limit: string, value: string) -> Result<void> {
+		check_is_owner(caller, self)?;
+		let mut limits = self.limits.clone();
+
+		match limit.as_str() {
+			"accountTokenOwnershipLimit" => {
+				limits.account_token_ownership_limit = parse_int(value)?;
+			}
+			"sponsoredDataSize" => {
+				limits.sponsored_data_size = parse_int(value)?;
+			}
+			"sponsoredDataRateLimit" => {
+				limits.sponsored_data_rate_limit =
+					Some(SponsoringRateLimit::Blocks(parse_int(value)?.unwrap()));
+			}
+			"tokenLimit" => {
+				limits.token_limit = parse_int(value)?;
+			}
+			"sponsorTransferTimeout" => {
+				limits.sponsor_transfer_timeout = parse_int(value)?;
+			}
+			"sponsorApproveTimeout" => {
+				limits.sponsor_approve_timeout = parse_int(value)?;
+			}
+			"ownerCanTransfer" => {
+				limits.owner_can_transfer = parse_bool(value)?;
+			}
+			"ownerCanDestroy" => {
+				limits.owner_can_destroy = parse_bool(value)?;
+			}
+			"transfersEnabled" => {
+				limits.transfers_enabled = parse_bool(value)?;
+			}
+			_ => return Err(Error::Revert(format!("Unknown limit \"{}\"", limit))),
+		}
+		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)
+			.map_err(dispatch_to_evm::<T>)?;
+		save(self);
+		Ok(())
+	}
+
+	fn contract_address(&self, _caller: caller) -> Result<address> {
+		Ok(crate::eth::collection_id_to_address(self.id))
+	}
+}
+
+fn check_is_owner<T: Config>(caller: caller, collection: &CollectionHandle<T>) -> Result<()> {
+	let caller = T::CrossAccountId::from_eth(caller);
+	collection
+		.check_is_owner(&caller)
+		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
+	Ok(())
+}
+
+fn save<T: Config>(collection: &CollectionHandle<T>) {
+	<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());
+}
+
+fn parse_int(value: string) -> Result<Option<u32>> {
+	value
+		.parse::<u32>()
+		.map_err(|e| Error::Revert(format!("Int value \"{}\" parse error: {}", value, e)))
+		.map(|value| Some(value))
+}
+
+fn parse_bool(value: string) -> Result<Option<bool>> {
+	value
+		.parse::<bool>()
+		.map_err(|e| Error::Revert(format!("Bool value \"{}\" parse error: {}", value, e)))
+		.map(|value| Some(value))
 }
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -17,6 +17,14 @@
 use up_data_structs::CollectionId;
 use sp_core::H160;
 
+lazy_static::lazy_static! {
+	pub static ref KEY_TOKEN_URI: up_data_structs::PropertyKey = {
+		let key: evm_coder::types::string = "tokenURI".into(); //TODO: make static
+		let key: up_data_structs::PropertyKey = key.into_bytes().try_into().expect("Can't create \"tokenURI\" key");
+		key
+	};
+}
+
 // 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1
 // TODO: Unhardcode prefix
 const ETH_COLLECTION_PREFIX: [u8; 16] = [
@@ -37,3 +45,7 @@
 	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));
 	H160(out)
 }
+
+pub fn is_collection(address: &H160) -> bool {
+	address[0..16] == ETH_COLLECTION_PREFIX
+}
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -114,6 +114,15 @@
 			recorder: SubstrateRecorder::new(gas_limit),
 		})
 	}
+
+	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {
+		<CollectionById<T>>::get(id).map(|collection| Self {
+			id,
+			collection,
+			recorder,
+		})
+	}
+
 	pub fn new(id: CollectionId) -> Option<Self> {
 		Self::new_with_gas_limit(id, u64::MAX)
 	}
@@ -140,6 +149,19 @@
 		<CollectionById<T>>::insert(self.id, self.collection);
 		Ok(())
 	}
+
+	pub fn set_sponsor(&mut self, sponsor: T::AccountId) {
+		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);
+	}
+
+	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {
+		if self.collection.sponsorship.pending_sponsor() != Some(sender) {
+			return false;
+		};
+
+		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
+		true
+	}
 }
 impl<T: Config> Deref for CollectionHandle<T> {
 	type Target = Collection<T::AccountId>;
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -8,18 +8,26 @@
 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' }
+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' }
+up-data-structs = { default-features = false, path = '../../primitives/data-structs', features = ['serde1'] }
+
 [dependencies.codec]
 default-features = false
 features = ['derive']
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -24,7 +24,7 @@
 use pallet_evm::account::CrossAccountId;
 use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use pallet_common::{CollectionHandle, erc::CollectionPropertiesCall};
+use pallet_common::{CollectionHandle, erc::CollectionCall};
 
 use crate::{
 	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
@@ -150,7 +150,7 @@
 	is(
 		ERC20,
 		ERC20UniqueExtensions,
-		via("CollectionHandle<T>", common_mut, CollectionProperties)
+		via("CollectionHandle<T>", common_mut, Collection)
 	)
 )]
 impl<T: Config> FungibleHandle<T> {}
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -33,7 +33,7 @@
 use pallet_evm_coder_substrate::WithRecorder;
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
-use sp_std::collections::btree_map::BTreeMap;
+use sp_std::{collections::btree_map::BTreeMap};
 
 pub use pallet::*;
 
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -127,8 +127,8 @@
 	}
 }
 
-// Selector: 9b5e29c5
-contract CollectionProperties is Dummy, ERC165 {
+// Selector: f5652829
+contract Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
 		public
@@ -159,6 +159,34 @@
 		dummy;
 		return hex"";
 	}
+
+	// Selector: ethSetSponsor(address) 8f9af356
+	function ethSetSponsor(address sponsor) public {
+		require(false, stub_error);
+		sponsor;
+		dummy = 0;
+	}
+
+	// Selector: ethConfirmSponsorship() a8580d1a
+	function ethConfirmSponsorship() public {
+		require(false, stub_error);
+		dummy = 0;
+	}
+
+	// Selector: setLimit(string,string) bf4d2014
+	function setLimit(string memory limit, string memory value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
 }
 
 contract UniqueFungible is
@@ -166,5 +194,5 @@
 	ERC165,
 	ERC20,
 	ERC20UniqueExtensions,
-	CollectionProperties
+	Collection
 {}
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -22,7 +22,7 @@
 	PropertyKeyPermission, PropertyValue,
 };
 use pallet_common::{
-	CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,
+	CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _
 };
 use sp_runtime::DispatchError;
 use sp_std::vec::Vec;
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -21,13 +21,16 @@
 };
 use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::BoundedVec;
-use up_data_structs::{TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property};
+use up_data_structs::{
+	TokenId, SchemaVersion, PropertyPermission, PropertyKeyPermission, Property, CollectionId,
+	PropertyKey, CollectionPropertiesVec,
+};
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_core::{H160, U256};
 use sp_std::vec::Vec;
 use pallet_common::{
-	erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall},
-	CollectionHandle,
+	erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
+	CollectionHandle, CollectionPropertyPermissions,
 };
 use pallet_evm::account::CrossAccountId;
 use pallet_evm_coder_substrate::call;
@@ -158,12 +161,21 @@
 	/// Returns token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
 	fn token_uri(&self, token_id: uint256) -> Result<string> {
+		let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+		if !has_token_permission::<T>(self.id, &key) {
+			return Err("No tokenURI permission".into());
+		}
+
 		self.consume_store_reads(1)?;
-		let _token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
-		Ok(string::from_utf8_lossy(
-			todo!()
-		)
-		.into())
+		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+
+		let properties = <TokenProperties<T>>::try_get((self.id, token_id))
+			.map_err(|_| Error::Revert("Token properties not found".into()))?;
+		if let Some(property) = properties.get(&key) {
+			return Ok(string::from_utf8_lossy(property).into());
+		}
+
+		Err("Property tokenURI not found".into())
 	}
 }
 
@@ -350,6 +362,12 @@
 		token_id: uint256,
 		token_uri: string,
 	) -> Result<bool> {
+		let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+		let permission = get_token_permission::<T>(self.id, &key)?;
+		if !permission.collection_admin {
+			return Err("Operation is not allowed".into());
+		}
+
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;
@@ -365,13 +383,22 @@
 			return Err("item id should be next".into());
 		}
 
-		todo!("token uri");
+		let mut properties = CollectionPropertiesVec::default();
+		properties
+			.try_push(Property {
+				key,
+				value: token_uri
+					.into_bytes()
+					.try_into()
+					.map_err(|_| "token uri is too long")?,
+			})
+			.map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?;
 
 		<Pallet<T>>::create_item(
 			self,
 			&caller,
 			CreateItemData::<T> {
-				properties: BoundedVec::default(),
+				properties,
 				owner: to,
 			},
 			&budget,
@@ -386,6 +413,30 @@
 	}
 }
 
+fn get_token_permission<T: Config>(
+	collection_id: CollectionId,
+	key: &PropertyKey,
+) -> Result<PropertyPermission> {
+	let token_property_permissions = CollectionPropertyPermissions::<T>::try_get(collection_id)
+		.map_err(|_| Error::Revert("No permissions for collection".into()))?;
+	let a = token_property_permissions
+		.get(key)
+		.map(|p| p.clone())
+		.ok_or_else(|| Error::Revert("No permission".into()))?;
+	Ok(a)
+}
+
+fn has_token_permission<T: Config>(
+	collection_id: CollectionId,
+	key: &PropertyKey,
+) -> bool {
+	if let Ok(token_property_permissions) = CollectionPropertyPermissions::<T>::try_get(collection_id) {
+		return token_property_permissions.contains_key(key);
+	}
+
+	false
+}
+
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
 	#[weight(<SelfWeightOf<T>>::transfer())]
@@ -491,7 +542,6 @@
 			}
 			expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
 
-			todo!("token uri");
 			data.push(CreateItemData::<T> {
 				properties: BoundedVec::default(),
 				owner: to.clone(),
@@ -513,7 +563,7 @@
 		ERC721UniqueExtensions,
 		ERC721Mintable,
 		ERC721Burnable,
-		via("CollectionHandle<T>", common_mut, CollectionProperties),
+		via("CollectionHandle<T>", common_mut, Collection),
 		TokenProperties,
 	)
 )]
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -33,9 +33,8 @@
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
-use sp_std::{vec::Vec, vec, collections::btree_set::BTreeSet};
+use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap, collections::btree_set::BTreeSet};
 use core::ops::Deref;
-use sp_std::collections::btree_map::BTreeMap;
 use codec::{Encode, Decode, MaxEncodedLen};
 use scale_info::TypeInfo;
 
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -330,40 +330,6 @@
 	}
 }
 
-// Selector: 9b5e29c5
-contract CollectionProperties is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		public
-	{
-		require(false, stub_error);
-		key;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) public {
-		require(false, stub_error);
-		key;
-		dummy = 0;
-	}
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		public
-		view
-		returns (bytes memory)
-	{
-		require(false, stub_error);
-		key;
-		dummy;
-		return hex"";
-	}
-}
-
 // Selector: d74d154f
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
@@ -414,6 +380,68 @@
 	}
 }
 
+// Selector: f5652829
+contract Collection is Dummy, ERC165 {
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		public
+	{
+		require(false, stub_error);
+		key;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) public {
+		require(false, stub_error);
+		key;
+		dummy = 0;
+	}
+
+	// Throws error if key not found
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		public
+		view
+		returns (bytes memory)
+	{
+		require(false, stub_error);
+		key;
+		dummy;
+		return hex"";
+	}
+
+	// Selector: ethSetSponsor(address) 8f9af356
+	function ethSetSponsor(address sponsor) public {
+		require(false, stub_error);
+		sponsor;
+		dummy = 0;
+	}
+
+	// Selector: ethConfirmSponsorship() a8580d1a
+	function ethConfirmSponsorship() public {
+		require(false, stub_error);
+		dummy = 0;
+	}
+
+	// Selector: setLimit(string,string) bf4d2014
+	function setLimit(string memory limit, string memory value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+}
+
 contract UniqueNFT is
 	Dummy,
 	ERC165,
@@ -423,6 +451,6 @@
 	ERC721UniqueExtensions,
 	ERC721Mintable,
 	ERC721Burnable,
-	CollectionProperties,
+	Collection,
 	TokenProperties
 {}
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -19,6 +19,7 @@
 runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']
 std = [
     'codec/std',
+    'serde/std',
     'frame-support/std',
     'frame-system/std',
     'pallet-evm/std',
@@ -27,10 +28,25 @@
     'sp-std/std',
     'sp-runtime/std',
     'frame-benchmarking/std',
+    'evm-coder/std',
+    'pallet-evm-coder-substrate/std',
+    'pallet-nonfungible/std',
 ]
 limit-testing = ["up-data-structs/limit-testing"]
 
 ################################################################################
+# Standart Dependencies
+
+[dependencies.serde]
+default-features = false
+features = ['derive']
+version = '1.0.130'
+
+[dependencies.ethereum]
+version = "0.12.0"
+default-features = false
+
+################################################################################
 # Substrate Dependencies
 
 [dependencies.codec]
@@ -74,7 +90,6 @@
 default-features = false
 git = "https://github.com/paritytech/substrate"
 branch = "polkadot-v0.9.21"
-
 
 ################################################################################
 # Local Dependencies
@@ -85,3 +100,6 @@
 ] }
 pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.21-logs" }
 pallet-common = { default-features = false, path = "../common" }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
+pallet-nonfungible = { default-features = false, path = '../../pallets/nonfungible' }
addedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/unique/src/eth/mod.rs
@@ -0,0 +1,171 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+use core::marker::PhantomData;
+use evm_coder::{execution::*, generate_stubgen, solidity_interface, types::*, ToLog};
+use ethereum as _;
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, Pallet as PalletEvm};
+use up_data_structs::{
+	CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
+	MAX_COLLECTION_NAME_LENGTH,
+};
+use frame_support::traits::Get;
+use sp_core::H160;
+use pallet_common::CollectionById;
+
+use sp_std::vec::Vec;
+use alloc::format;
+
+pub trait Config:
+	frame_system::Config
+	+ pallet_evm_coder_substrate::Config
+	+ pallet_evm::account::Config
+	+ pallet_nonfungible::Config
+{
+	type ContractAddress: Get<H160>;
+}
+
+struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);
+impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {
+	fn recorder(&self) -> &SubstrateRecorder<T> {
+		&self.0
+	}
+
+	fn into_recorder(self) -> SubstrateRecorder<T> {
+		self.0
+	}
+}
+
+#[solidity_interface(name = "CollectionHelper")]
+impl<T: Config> EvmCollectionHelper<T> {
+	fn create_721_collection(
+		&self,
+		caller: caller,
+		name: string,
+		description: string,
+		token_prefix: string,
+	) -> Result<address> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let name = name
+			.encode_utf16()
+			.collect::<Vec<u16>>()
+			.try_into()
+			.map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;
+		let description = description
+			.encode_utf16()
+			.collect::<Vec<u16>>()
+			.try_into()
+			.map_err(|_| {
+				error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)
+			})?;
+		let token_prefix = token_prefix
+			.into_bytes()
+			.try_into()
+			.map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;
+
+		let key = pallet_common::eth::KEY_TOKEN_URI.clone();
+		let permission = up_data_structs::PropertyPermission {
+			mutable: true,
+			collection_admin: true,
+			token_owner: false,
+		};
+		let mut token_property_permissions =
+			up_data_structs::CollectionPropertiesPermissionsVec::default();
+		token_property_permissions
+			.try_push(up_data_structs::PropertyKeyPermission { key, permission })
+			.map_err(|e| Error::Revert(format!("{:?}", e)))?;
+
+		let data = CreateCollectionData {
+			name,
+			description,
+			token_prefix,
+			token_property_permissions,
+			..Default::default()
+		};
+
+		let collection_id =
+			<pallet_nonfungible::Pallet<T>>::init_collection(caller.as_sub().clone(), data)
+				.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(
+			EthCollectionEvent::CollectionCreated {
+				owner: *caller.as_eth(),
+				collection_id: address,
+			}
+			.to_log(address),
+		);
+		Ok(address)
+	}
+
+	fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {
+		if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {
+			let collection_id = id;
+			return Ok(<CollectionById<T>>::contains_key(collection_id));
+		}
+
+		Ok(false)
+	}
+}
+
+#[derive(ToLog)]
+pub enum EthCollectionEvent {
+	CollectionCreated {
+		#[indexed]
+		owner: address,
+		#[indexed]
+		collection_id: address,
+	},
+}
+
+pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);
+impl<T: Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {
+	fn is_reserved(contract: &sp_core::H160) -> bool {
+		contract == &T::ContractAddress::get()
+	}
+
+	fn is_used(contract: &sp_core::H160) -> bool {
+		contract == &T::ContractAddress::get()
+	}
+
+	fn call(
+		source: &sp_core::H160,
+		target: &sp_core::H160,
+		gas_left: u64,
+		input: &[u8],
+		value: sp_core::U256,
+	) -> Option<PrecompileResult> {
+		if target != &T::ContractAddress::get() {
+			return None;
+		}
+
+		let helpers = EvmCollectionHelper::<T>(SubstrateRecorder::<T>::new(gas_left));
+		pallet_evm_coder_substrate::call(*source, helpers, value, input)
+	}
+
+	fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
+		(contract == &T::ContractAddress::get())
+			.then(|| include_bytes!("./stubs/CollectionHelper.raw").to_vec())
+	}
+}
+
+generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);
+generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);
+
+fn error_feild_too_long(feild: &str, bound: u32) -> Error {
+	Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))
+}
addedpallets/unique/src/eth/stubs/CollectionHelper.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/unique/src/eth/stubs/CollectionHelper.soldiffbeforeafterboth
--- /dev/null
+++ b/pallets/unique/src/eth/stubs/CollectionHelper.sol
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Common stubs holder
+contract Dummy {
+	uint8 dummy;
+	string stub_error = "this contract is implemented in native";
+}
+
+contract ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID)
+		external
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		interfaceID;
+		return true;
+	}
+}
+
+// Selector: 56c215c5
+contract CollectionHelper is Dummy, ERC165 {
+	// Selector: create721Collection(string,string,string) 951c0151
+	function create721Collection(
+		string memory name,
+		string memory description,
+		string memory tokenPrefix
+	) public view returns (address) {
+		require(false, stub_error);
+		name;
+		description;
+		tokenPrefix;
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+
+	// Selector: isCollectionExist(address) c3de1494
+	function isCollectionExist(address collectionAddress)
+		public
+		view
+		returns (bool)
+	{
+		require(false, stub_error);
+		collectionAddress;
+		dummy;
+		return false;
+	}
+}
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -22,6 +22,8 @@
 	clippy::unused_unit
 )]
 
+extern crate alloc;
+
 use frame_support::{
 	decl_module, decl_storage, decl_error, decl_event,
 	dispatch::DispatchResult,
@@ -46,6 +48,7 @@
 	CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,
 	dispatch::CollectionDispatch,
 };
+pub mod eth;
 
 #[cfg(feature = "runtime-benchmarks")]
 mod benchmarking;
@@ -520,7 +523,7 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner(&sender)?;
 
-			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());
+			target_collection.set_sponsor(new_sponsor.clone());
 
 			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(
 				collection_id,
@@ -544,11 +547,9 @@
 
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			ensure!(
-				target_collection.sponsorship.pending_sponsor() == Some(&sender),
+				target_collection.confirm_sponsorship(&sender),
 				Error::<T>::ConfirmUnsetSponsorFail
 			);
-
-			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
 
 			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(
 				collection_id,
modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -40,6 +40,6 @@
   "sp-std/std",
   "pallet-evm/std",
 ]
-serde1 = ["serde"]
+serde1 = ["serde/alloc"]
 limit-testing = []
 runtime-benchmarks = []
\ No newline at end of file
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -506,6 +506,7 @@
 }
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub enum MetaUpdatePermission {
 	ItemOwner,
 	Admin,
@@ -760,6 +761,10 @@
 		self.0.get(key)
 	}
 
+	pub fn contains_key(&self, key: &PropertyKey) -> bool {
+		self.0.contains_key(key)
+	}
+
 	fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {
 		if key.is_empty() {
 			return Err(PropertiesError::EmptyPropertyKey);
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -50,6 +50,7 @@
 pub use pallet_balances::Call as BalancesCall;
 pub use pallet_evm::{
 	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
+	OnMethodCall, Account as EVMAccount, FeeCalculator, GasWeightMapping,
 };
 pub use frame_support::{
 	construct_runtime, match_types,
@@ -79,7 +80,6 @@
 };
 use smallvec::smallvec;
 use codec::{Encode, Decode};
-use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping};
 use fp_rpc::TransactionStatus;
 use sp_runtime::{
 	traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},
@@ -306,6 +306,7 @@
 		pallet_evm_migration::OnMethodCall<Self>,
 		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
 		CollectionDispatchT<Self>,
+		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,
 	);
 	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
 	type ChainId = ChainId;
@@ -974,6 +975,11 @@
 	pub const HelpersContractAddress: H160 = H160([
 		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
 	]);
+
+	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
+	pub const EvmCollectionHelperAddress: H160 = H160([
+		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
+	]);
 }
 
 impl pallet_evm_contract_helpers::Config for Runtime {
@@ -981,6 +987,10 @@
 	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
 }
 
+impl pallet_unique::eth::Config for Runtime {
+	type ContractAddress = EvmCollectionHelperAddress;
+}
+
 construct_runtime!(
 	pub enum Runtime where
 		Block = Block,
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
before · runtime/quartz/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//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.1819#![cfg_attr(not(feature = "std"), no_std)]20// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.21#![recursion_limit = "1024"]22#![allow(clippy::from_over_into, clippy::identity_op)]23#![allow(clippy::fn_to_numeric_cast_with_truncation)]24// Make the WASM binary available.25#[cfg(feature = "std")]26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));2728use sp_api::impl_runtime_apis;29use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};30use sp_runtime::DispatchError;31// #[cfg(any(feature = "std", test))]32// pub use sp_runtime::BuildStorage;3334use sp_runtime::{35	Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,36	traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero},37	transaction_validity::{TransactionSource, TransactionValidity},38	ApplyExtrinsicResult, RuntimeAppPublic,39};4041use sp_std::prelude::*;4243#[cfg(feature = "std")]44use sp_version::NativeVersion;45use sp_version::RuntimeVersion;46pub use pallet_transaction_payment::{47	Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,48};49// A few exports that help ease life for downstream crates.50pub use pallet_balances::Call as BalancesCall;51pub use pallet_evm::{52	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,53};54pub use frame_support::{55	construct_runtime, match_types,56	dispatch::DispatchResult,57	PalletId, parameter_types, StorageValue, ConsensusEngineId,58	traits::{59		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,60		Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,61		OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance,62	},63	weights::{64		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},65		DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,66		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,67	},68};69use unique_runtime_common::dispatch::{CollectionDispatchT, CollectionDispatch};70use up_data_structs::*;71// use pallet_contracts::weights::WeightInfo;72// #[cfg(any(feature = "std", test))]73use frame_system::{74	self as frame_system, EnsureRoot, EnsureSigned,75	limits::{BlockWeights, BlockLength},76};77use sp_arithmetic::{78	traits::{BaseArithmetic, Unsigned},79};80use smallvec::smallvec;81use codec::{Encode, Decode};82use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping};83use fp_rpc::TransactionStatus;84use sp_runtime::{85	traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},86	transaction_validity::TransactionValidityError,87	SaturatedConversion,88};8990// pub use pallet_timestamp::Call as TimestampCall;91pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;9293// Polkadot imports94use pallet_xcm::XcmPassthrough;95use polkadot_parachain::primitives::Sibling;96use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};97use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};98use xcm_builder::{99	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,100	EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,101	RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,102	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,103	ParentIsPreset,104};105use xcm_executor::{Config, XcmExecutor, Assets};106use sp_std::{marker::PhantomData};107108use xcm::latest::{109	//	Xcm,110	AssetId::{Concrete},111	Fungibility::Fungible as XcmFungible,112	MultiAsset,113	Error as XcmError,114};115use xcm_executor::traits::{MatchesFungible, WeightTrader};116//use xcm_executor::traits::MatchesFungible;117use sp_runtime::traits::CheckedConversion;118119use unique_runtime_common::{impl_common_runtime_apis, types::*, constants::*};120121pub const RUNTIME_NAME: &str = "quartz";122pub const TOKEN_SYMBOL: &str = "QTZ";123124type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;125126impl RuntimeInstance for Runtime {127	type CrossAccountId = self::CrossAccountId;128129	type TransactionConverter = self::TransactionConverter;130131	fn get_transaction_converter() -> TransactionConverter {132		TransactionConverter133	}134}135136/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know137/// the specifics of the runtime. They can then be made to be agnostic over specific formats138/// of data like extrinsics, allowing for them to continue syncing the network through upgrades139/// to even the core data structures.140pub mod opaque {141	use sp_std::prelude::*;142	use sp_runtime::impl_opaque_keys;143	use super::Aura;144145	pub use unique_runtime_common::types::*;146147	impl_opaque_keys! {148		pub struct SessionKeys {149			pub aura: Aura,150		}151	}152}153154/// This runtime version.155pub const VERSION: RuntimeVersion = RuntimeVersion {156	spec_name: create_runtime_str!(RUNTIME_NAME),157	impl_name: create_runtime_str!(RUNTIME_NAME),158	authoring_version: 1,159	spec_version: 920000,160	impl_version: 0,161	apis: RUNTIME_API_VERSIONS,162	transaction_version: 1,163	state_version: 0,164};165166#[derive(codec::Encode, codec::Decode)]167pub enum XCMPMessage<XAccountId, XBalance> {168	/// Transfer tokens to the given account from the Parachain account.169	TransferToken(XAccountId, XBalance),170}171172/// The version information used to identify this runtime when compiled natively.173#[cfg(feature = "std")]174pub fn native_version() -> NativeVersion {175	NativeVersion {176		runtime_version: VERSION,177		can_author_with: Default::default(),178	}179}180181type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;182183pub struct DealWithFees;184impl OnUnbalanced<NegativeImbalance> for DealWithFees {185	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {186		if let Some(fees) = fees_then_tips.next() {187			// for fees, 100% to treasury188			let mut split = fees.ration(100, 0);189			if let Some(tips) = fees_then_tips.next() {190				// for tips, if any, 100% to treasury191				tips.ration_merge_into(100, 0, &mut split);192			}193			Treasury::on_unbalanced(split.0);194			// Author::on_unbalanced(split.1);195		}196	}197}198199parameter_types! {200	pub const BlockHashCount: BlockNumber = 2400;201	pub RuntimeBlockLength: BlockLength =202		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);203	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);204	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;205	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()206		.base_block(BlockExecutionWeight::get())207		.for_class(DispatchClass::all(), |weights| {208			weights.base_extrinsic = ExtrinsicBaseWeight::get();209		})210		.for_class(DispatchClass::Normal, |weights| {211			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);212		})213		.for_class(DispatchClass::Operational, |weights| {214			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);215			// Operational transactions have some extra reserved space, so that they216			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.217			weights.reserved = Some(218				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT219			);220		})221		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)222		.build_or_panic();223	pub const Version: RuntimeVersion = VERSION;224	pub const SS58Prefix: u8 = 255;225}226227parameter_types! {228	pub const ChainId: u64 = 8881;229}230231pub struct FixedFee;232impl FeeCalculator for FixedFee {233	fn min_gas_price() -> U256 {234		MIN_GAS_PRICE.into()235	}236}237238// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case239// (contract, which only writes a lot of data),240// approximating on top of our real store write weight241parameter_types! {242	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;243	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;244	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();245}246247/// Limiting EVM execution to 50% of block for substrate users and management tasks248/// EVM transaction consumes more weight than substrate's, so we can't rely on them being249/// scheduled fairly250const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);251parameter_types! {252	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());253}254255pub enum FixedGasWeightMapping {}256impl GasWeightMapping for FixedGasWeightMapping {257	fn gas_to_weight(gas: u64) -> Weight {258		gas.saturating_mul(WeightPerGas::get())259	}260	fn weight_to_gas(weight: Weight) -> u64 {261		weight / WeightPerGas::get()262	}263}264265impl pallet_evm::Config for Runtime {266	type BlockGasLimit = BlockGasLimit;267	type FeeCalculator = FixedFee;268	type GasWeightMapping = FixedGasWeightMapping;269	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;270	type CallOrigin = EnsureAddressTruncated<Self>;271	type WithdrawOrigin = EnsureAddressTruncated<Self>;272	type AddressMapping = HashedAddressMapping<Self::Hashing>;273	type PrecompilesType = ();274	type PrecompilesValue = ();275	type Currency = Balances;276	type Event = Event;277	type OnMethodCall = (278		pallet_evm_migration::OnMethodCall<Self>,279		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,280		CollectionDispatchT<Self>,281	);282	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;283	type ChainId = ChainId;284	type Runner = pallet_evm::runner::stack::Runner<Self>;285	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;286	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;287	type FindAuthor = EthereumFindAuthor<Aura>;288}289290impl pallet_evm_migration::Config for Runtime {291	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;292}293294pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);295impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {296	fn find_author<'a, I>(digests: I) -> Option<H160>297	where298		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,299	{300		if let Some(author_index) = F::find_author(digests) {301			let authority_id = Aura::authorities()[author_index as usize].clone();302			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));303		}304		None305	}306}307308impl pallet_ethereum::Config for Runtime {309	type Event = Event;310	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;311}312313impl pallet_randomness_collective_flip::Config for Runtime {}314315impl frame_system::Config for Runtime {316	/// The data to be stored in an account.317	type AccountData = pallet_balances::AccountData<Balance>;318	/// The identifier used to distinguish between accounts.319	type AccountId = AccountId;320	/// The basic call filter to use in dispatchable.321	type BaseCallFilter = Everything;322	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).323	type BlockHashCount = BlockHashCount;324	/// The maximum length of a block (in bytes).325	type BlockLength = RuntimeBlockLength;326	/// The index type for blocks.327	type BlockNumber = BlockNumber;328	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.329	type BlockWeights = RuntimeBlockWeights;330	/// The aggregated dispatch type that is available for extrinsics.331	type Call = Call;332	/// The weight of database operations that the runtime can invoke.333	type DbWeight = RocksDbWeight;334	/// The ubiquitous event type.335	type Event = Event;336	/// The type for hashing blocks and tries.337	type Hash = Hash;338	/// The hashing algorithm used.339	type Hashing = BlakeTwo256;340	/// The header type.341	type Header = generic::Header<BlockNumber, BlakeTwo256>;342	/// The index type for storing how many extrinsics an account has signed.343	type Index = Index;344	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.345	type Lookup = AccountIdLookup<AccountId, ()>;346	/// What to do if an account is fully reaped from the system.347	type OnKilledAccount = ();348	/// What to do if a new account is created.349	type OnNewAccount = ();350	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;351	/// The ubiquitous origin type.352	type Origin = Origin;353	/// This type is being generated by `construct_runtime!`.354	type PalletInfo = PalletInfo;355	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.356	type SS58Prefix = SS58Prefix;357	/// Weight information for the extrinsics of this pallet.358	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;359	/// Version of the runtime.360	type Version = Version;361	type MaxConsumers = ConstU32<16>;362}363364parameter_types! {365	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;366}367368impl pallet_timestamp::Config for Runtime {369	/// A timestamp: milliseconds since the unix epoch.370	type Moment = u64;371	type OnTimestampSet = ();372	type MinimumPeriod = MinimumPeriod;373	type WeightInfo = ();374}375376parameter_types! {377	// pub const ExistentialDeposit: u128 = 500;378	pub const ExistentialDeposit: u128 = 0;379	pub const MaxLocks: u32 = 50;380}381382impl pallet_balances::Config for Runtime {383	type MaxLocks = MaxLocks;384	type MaxReserves = ();385	type ReserveIdentifier = [u8; 8];386	/// The type for recording an account's balance.387	type Balance = Balance;388	/// The ubiquitous event type.389	type Event = Event;390	type DustRemoval = Treasury;391	type ExistentialDeposit = ExistentialDeposit;392	type AccountStore = System;393	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;394}395396pub const fn deposit(items: u32, bytes: u32) -> Balance {397	items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE398}399400/*401parameter_types! {402	pub TombstoneDeposit: Balance = deposit(403		1,404		sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,405	);406	pub DepositPerContract: Balance = TombstoneDeposit::get();407	pub const DepositPerStorageByte: Balance = deposit(0, 1);408	pub const DepositPerStorageItem: Balance = deposit(1, 0);409	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);410	pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;411	pub const SignedClaimHandicap: u32 = 2;412	pub const MaxDepth: u32 = 32;413	pub const MaxValueSize: u32 = 16 * 1024;414	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb415	// The lazy deletion runs inside on_initialize.416	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *417		RuntimeBlockWeights::get().max_block;418	// The weight needed for decoding the queue should be less or equal than a fifth419	// of the overall weight dedicated to the lazy deletion.420	pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (421			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -422			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)423		)) / 5) as u32;424	pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();425}426427impl pallet_contracts::Config for Runtime {428	type Time = Timestamp;429	type Randomness = RandomnessCollectiveFlip;430	type Currency = Balances;431	type Event = Event;432	type RentPayment = ();433	type SignedClaimHandicap = SignedClaimHandicap;434	type TombstoneDeposit = TombstoneDeposit;435	type DepositPerContract = DepositPerContract;436	type DepositPerStorageByte = DepositPerStorageByte;437	type DepositPerStorageItem = DepositPerStorageItem;438	type RentFraction = RentFraction;439	type SurchargeReward = SurchargeReward;440	type WeightPrice = pallet_transaction_payment::Pallet<Self>;441	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;442	type ChainExtension = NFTExtension;443	type DeletionQueueDepth = DeletionQueueDepth;444	type DeletionWeightLimit = DeletionWeightLimit;445	type Schedule = Schedule;446	type CallStack = [pallet_contracts::Frame<Self>; 31];447}448*/449450parameter_types! {451	/// This value increases the priority of `Operational` transactions by adding452	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.453	pub const OperationalFeeMultiplier: u8 = 5;454}455456/// Linear implementor of `WeightToFeePolynomial`457pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);458459impl<T> WeightToFeePolynomial for LinearFee<T>460where461	T: BaseArithmetic + From<u32> + Copy + Unsigned,462{463	type Balance = T;464465	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {466		smallvec!(WeightToFeeCoefficient {467			// Targeting 0.1 Unique per NFT transfer468			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),469			coeff_frac: Perbill::zero(),470			negative: false,471			degree: 1,472		})473	}474}475476impl pallet_transaction_payment::Config for Runtime {477	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;478	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;479	type OperationalFeeMultiplier = OperationalFeeMultiplier;480	type WeightToFee = LinearFee<Balance>;481	type FeeMultiplierUpdate = ();482}483484parameter_types! {485	pub const ProposalBond: Permill = Permill::from_percent(5);486	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;487	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;488	pub const SpendPeriod: BlockNumber = 5 * MINUTES;489	pub const Burn: Permill = Permill::from_percent(0);490	pub const TipCountdown: BlockNumber = 1 * DAYS;491	pub const TipFindersFee: Percent = Percent::from_percent(20);492	pub const TipReportDepositBase: Balance = 1 * UNIQUE;493	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;494	pub const BountyDepositBase: Balance = 1 * UNIQUE;495	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;496	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");497	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;498	pub const MaximumReasonLength: u32 = 16384;499	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);500	pub const BountyValueMinimum: Balance = 5 * UNIQUE;501	pub const MaxApprovals: u32 = 100;502}503504impl pallet_treasury::Config for Runtime {505	type PalletId = TreasuryModuleId;506	type Currency = Balances;507	type ApproveOrigin = EnsureRoot<AccountId>;508	type RejectOrigin = EnsureRoot<AccountId>;509	type Event = Event;510	type OnSlash = ();511	type ProposalBond = ProposalBond;512	type ProposalBondMinimum = ProposalBondMinimum;513	type ProposalBondMaximum = ProposalBondMaximum;514	type SpendPeriod = SpendPeriod;515	type Burn = Burn;516	type BurnDestination = ();517	type SpendFunds = ();518	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;519	type MaxApprovals = MaxApprovals;520}521522impl pallet_sudo::Config for Runtime {523	type Event = Event;524	type Call = Call;525}526527pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);528529impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider530	for RelayChainBlockNumberProvider<T>531{532	type BlockNumber = BlockNumber;533534	fn current_block_number() -> Self::BlockNumber {535		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()536			.map(|d| d.relay_parent_number)537			.unwrap_or_default()538	}539}540541parameter_types! {542	pub const MinVestedTransfer: Balance = 10 * UNIQUE;543	pub const MaxVestingSchedules: u32 = 28;544}545546impl orml_vesting::Config for Runtime {547	type Event = Event;548	type Currency = pallet_balances::Pallet<Runtime>;549	type MinVestedTransfer = MinVestedTransfer;550	type VestedTransferOrigin = EnsureSigned<AccountId>;551	type WeightInfo = ();552	type MaxVestingSchedules = MaxVestingSchedules;553	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;554}555556parameter_types! {557	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;558	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;559}560561impl cumulus_pallet_parachain_system::Config for Runtime {562	type Event = Event;563	type SelfParaId = parachain_info::Pallet<Self>;564	type OnSystemEvent = ();565	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<566	// 	MaxDownwardMessageWeight,567	// 	XcmExecutor<XcmConfig>,568	// 	Call,569	// >;570	type OutboundXcmpMessageSource = XcmpQueue;571	type DmpMessageHandler = DmpQueue;572	type ReservedDmpWeight = ReservedDmpWeight;573	type ReservedXcmpWeight = ReservedXcmpWeight;574	type XcmpMessageHandler = XcmpQueue;575}576577impl parachain_info::Config for Runtime {}578579impl cumulus_pallet_aura_ext::Config for Runtime {}580581parameter_types! {582	pub const RelayLocation: MultiLocation = MultiLocation::parent();583	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;584	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();585	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();586}587588/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used589/// when determining ownership of accounts for asset transacting and when attempting to use XCM590/// `Transact` in order to determine the dispatch Origin.591pub type LocationToAccountId = (592	// The parent (Relay-chain) origin converts to the default `AccountId`.593	ParentIsPreset<AccountId>,594	// Sibling parachain origins convert to AccountId via the `ParaId::into`.595	SiblingParachainConvertsVia<Sibling, AccountId>,596	// Straight up local `AccountId32` origins just alias directly to `AccountId`.597	AccountId32Aliases<RelayNetwork, AccountId>,598);599600pub struct OnlySelfCurrency;601impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {602	fn matches_fungible(a: &MultiAsset) -> Option<B> {603		match (&a.id, &a.fun) {604			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),605			_ => None,606		}607	}608}609610/// Means for transacting assets on this chain.611pub type LocalAssetTransactor = CurrencyAdapter<612	// Use this currency:613	Balances,614	// Use this currency when it is a fungible asset matching the given location or name:615	OnlySelfCurrency,616	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:617	LocationToAccountId,618	// Our chain's account ID type (we can't get away without mentioning it explicitly):619	AccountId,620	// We don't track any teleports.621	(),622>;623624/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,625/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can626/// biases the kind of local `Origin` it will become.627pub type XcmOriginToTransactDispatchOrigin = (628	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location629	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for630	// foreign chains who want to have a local sovereign account on this chain which they control.631	SovereignSignedViaLocation<LocationToAccountId, Origin>,632	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when633	// recognised.634	RelayChainAsNative<RelayOrigin, Origin>,635	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when636	// recognised.637	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,638	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a639	// transaction from the Root origin.640	ParentAsSuperuser<Origin>,641	// Native signed account converter; this just converts an `AccountId32` origin into a normal642	// `Origin::Signed` origin of the same 32-byte value.643	SignedAccountId32AsNative<RelayNetwork, Origin>,644	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.645	XcmPassthrough<Origin>,646);647648parameter_types! {649	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.650	pub UnitWeightCost: Weight = 1_000_000;651	// 1200 UNIQUEs buy 1 second of weight.652	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);653	pub const MaxInstructions: u32 = 100;654	pub const MaxAuthorities: u32 = 100_000;655}656657match_types! {658	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {659		MultiLocation { parents: 1, interior: Here } |660		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }661	};662}663664pub type Barrier = (665	TakeWeightCredit,666	AllowTopLevelPaidExecutionFrom<Everything>,667	AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,668	// ^^^ Parent & its unit plurality gets free execution669);670671pub struct UsingOnlySelfCurrencyComponents<672	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,673	AssetId: Get<MultiLocation>,674	AccountId,675	Currency: CurrencyT<AccountId>,676	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,677>(678	Weight,679	Currency::Balance,680	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,681);682impl<683		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,684		AssetId: Get<MultiLocation>,685		AccountId,686		Currency: CurrencyT<AccountId>,687		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,688	> WeightTrader689	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>690{691	fn new() -> Self {692		Self(0, Zero::zero(), PhantomData)693	}694695	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {696		let amount = WeightToFee::calc(&weight);697		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;698699		// location to this parachain through relay chain700		let option1: xcm::v1::AssetId = Concrete(MultiLocation {701			parents: 1,702			interior: X1(Parachain(ParachainInfo::parachain_id().into())),703		});704		// direct location705		let option2: xcm::v1::AssetId = Concrete(MultiLocation {706			parents: 0,707			interior: Here,708		});709710		let required = if payment.fungible.contains_key(&option1) {711			(option1, u128_amount).into()712		} else if payment.fungible.contains_key(&option2) {713			(option2, u128_amount).into()714		} else {715			(Concrete(MultiLocation::default()), u128_amount).into()716		};717718		let unused = payment719			.checked_sub(required)720			.map_err(|_| XcmError::TooExpensive)?;721		self.0 = self.0.saturating_add(weight);722		self.1 = self.1.saturating_add(amount);723		Ok(unused)724	}725726	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {727		let weight = weight.min(self.0);728		let amount = WeightToFee::calc(&weight);729		self.0 -= weight;730		self.1 = self.1.saturating_sub(amount);731		let amount: u128 = amount.saturated_into();732		if amount > 0 {733			Some((AssetId::get(), amount).into())734		} else {735			None736		}737	}738}739impl<740		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,741		AssetId: Get<MultiLocation>,742		AccountId,743		Currency: CurrencyT<AccountId>,744		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,745	> Drop746	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>747{748	fn drop(&mut self) {749		OnUnbalanced::on_unbalanced(Currency::issue(self.1));750	}751}752753pub struct XcmConfig;754impl Config for XcmConfig {755	type Call = Call;756	type XcmSender = XcmRouter;757	// How to withdraw and deposit an asset.758	type AssetTransactor = LocalAssetTransactor;759	type OriginConverter = XcmOriginToTransactDispatchOrigin;760	type IsReserve = NativeAsset;761	type IsTeleporter = (); // Teleportation is disabled762	type LocationInverter = LocationInverter<Ancestry>;763	type Barrier = Barrier;764	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;765	type Trader = UsingOnlySelfCurrencyComponents<766		IdentityFee<Balance>,767		RelayLocation,768		AccountId,769		Balances,770		(),771	>;772	type ResponseHandler = (); // Don't handle responses for now.773	type SubscriptionService = PolkadotXcm;774775	type AssetTrap = PolkadotXcm;776	type AssetClaims = PolkadotXcm;777}778779// parameter_types! {780// 	pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;781// }782783/// No local origins on this chain are allowed to dispatch XCM sends/executions.784pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);785786/// The means for routing XCM messages which are not for local execution into the right message787/// queues.788pub type XcmRouter = (789	// Two routers - use UMP to communicate with the relay chain:790	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,791	// ..and XCMP to communicate with the sibling chains.792	XcmpQueue,793);794795impl pallet_evm_coder_substrate::Config for Runtime {796	type GasWeightMapping = FixedGasWeightMapping;797}798799impl pallet_xcm::Config for Runtime {800	type Event = Event;801	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;802	type XcmRouter = XcmRouter;803	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;804	type XcmExecuteFilter = Everything;805	type XcmExecutor = XcmExecutor<XcmConfig>;806	type XcmTeleportFilter = Everything;807	type XcmReserveTransferFilter = Everything;808	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;809	type LocationInverter = LocationInverter<Ancestry>;810	type Origin = Origin;811	type Call = Call;812	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;813	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;814}815816impl cumulus_pallet_xcm::Config for Runtime {817	type Event = Event;818	type XcmExecutor = XcmExecutor<XcmConfig>;819}820821impl cumulus_pallet_xcmp_queue::Config for Runtime {822	type WeightInfo = ();823	type Event = Event;824	type XcmExecutor = XcmExecutor<XcmConfig>;825	type ChannelInfo = ParachainSystem;826	type VersionWrapper = ();827	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;828	type ControllerOrigin = EnsureRoot<AccountId>;829	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;830}831832impl cumulus_pallet_dmp_queue::Config for Runtime {833	type Event = Event;834	type XcmExecutor = XcmExecutor<XcmConfig>;835	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;836}837838impl pallet_aura::Config for Runtime {839	type AuthorityId = AuraId;840	type DisabledValidators = ();841	type MaxAuthorities = MaxAuthorities;842}843844parameter_types! {845	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account();846	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;847}848849impl pallet_common::Config for Runtime {850	type Event = Event;851852	type Currency = Balances;853	type CollectionCreationPrice = CollectionCreationPrice;854	type TreasuryAccountId = TreasuryAccountId;855	type CollectionDispatch = CollectionDispatchT<Self>;856857	type EvmTokenAddressMapping = EvmTokenAddressMapping;858	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;859}860861impl pallet_structure::Config for Runtime {862	type Event = Event;863	type Call = Call;864	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;865}866867impl pallet_evm::account::Config for Runtime {868	type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;869	type EvmAddressMapping = HashedAddressMapping<Self::Hashing>;870	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;871}872873impl pallet_fungible::Config for Runtime {874	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;875}876impl pallet_refungible::Config for Runtime {877	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;878}879impl pallet_nonfungible::Config for Runtime {880	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;881}882883impl pallet_proxy_rmrk_core::Config for Runtime {884	type Event = Event;885}886887impl pallet_proxy_rmrk_equip::Config for Runtime {888	type Event = Event;889}890891impl pallet_unique::Config for Runtime {892	type Event = Event;893	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;894}895896parameter_types! {897	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied898}899900/// Used for the pallet inflation901impl pallet_inflation::Config for Runtime {902	type Currency = Balances;903	type TreasuryAccountId = TreasuryAccountId;904	type InflationBlockInterval = InflationBlockInterval;905	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;906}907908// parameter_types! {909// 	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *910// 		RuntimeBlockWeights::get().max_block;911// 	pub const MaxScheduledPerBlock: u32 = 50;912// }913914type EvmSponsorshipHandler = (915	pallet_unique::UniqueEthSponsorshipHandler<Runtime>,916	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,917);918type SponsorshipHandler = (919	pallet_unique::UniqueSponsorshipHandler<Runtime>,920	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,921	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,922);923924// impl pallet_unq_scheduler::Config for Runtime {925// 	type Event = Event;926// 	type Origin = Origin;927// 	type PalletsOrigin = OriginCaller;928// 	type Call = Call;929// 	type MaximumWeight = MaximumSchedulerWeight;930// 	type ScheduleOrigin = EnsureSigned<AccountId>;931// 	type MaxScheduledPerBlock = MaxScheduledPerBlock;932// 	type SponsorshipHandler = SponsorshipHandler;933// 	type WeightInfo = ();934// }935936impl pallet_evm_transaction_payment::Config for Runtime {937	type EvmSponsorshipHandler = EvmSponsorshipHandler;938	type Currency = Balances;939}940941impl pallet_charge_transaction::Config for Runtime {942	type SponsorshipHandler = SponsorshipHandler;943}944945// impl pallet_contract_helpers::Config for Runtime {946//	 type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;947// }948949parameter_types! {950	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049951	pub const HelpersContractAddress: H160 = H160([952		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,953	]);954}955956impl pallet_evm_contract_helpers::Config for Runtime {957	type ContractAddress = HelpersContractAddress;958	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;959}960961construct_runtime!(962	pub enum Runtime where963		Block = Block,964		NodeBlock = opaque::Block,965		UncheckedExtrinsic = UncheckedExtrinsic966	{967		ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,968		ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,969970		Aura: pallet_aura::{Pallet, Config<T>} = 22,971		AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,972973		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,974		RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,975		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,976		TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,977		Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,978		Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,979		System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,980		Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,981		// Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,982		// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,983984		// XCM helpers.985		XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,986		PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,987		CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,988		DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,989990		// Unique Pallets991		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,992		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,993		// Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,994		// free = 63995		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,996		// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,997		Common: pallet_common::{Pallet, Storage, Event<T>} = 66,998		Fungible: pallet_fungible::{Pallet, Storage} = 67,999		Refungible: pallet_refungible::{Pallet, Storage} = 68,1000		Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,1001		Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,1002		RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,1003		RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,10041005		// Frontier1006		EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,1007		Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,10081009		EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,1010		EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,1011		EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,1012		EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,1013	}1014);10151016pub struct TransactionConverter;10171018impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {1019	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {1020		UncheckedExtrinsic::new_unsigned(1021			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),1022		)1023	}1024}10251026impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {1027	fn convert_transaction(1028		&self,1029		transaction: pallet_ethereum::Transaction,1030	) -> opaque::UncheckedExtrinsic {1031		let extrinsic = UncheckedExtrinsic::new_unsigned(1032			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),1033		);1034		let encoded = extrinsic.encode();1035		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])1036			.expect("Encoded extrinsic is always valid")1037	}1038}10391040/// The address format for describing accounts.1041pub type Address = sp_runtime::MultiAddress<AccountId, ()>;1042/// Block header type as expected by this runtime.1043pub type Header = generic::Header<BlockNumber, BlakeTwo256>;1044/// Block type as expected by this runtime.1045pub type Block = generic::Block<Header, UncheckedExtrinsic>;1046/// A Block signed with a Justification1047pub type SignedBlock = generic::SignedBlock<Block>;1048/// BlockId type as expected by this runtime.1049pub type BlockId = generic::BlockId<Block>;1050/// The SignedExtension to the basic transaction logic.1051pub type SignedExtra = (1052	frame_system::CheckSpecVersion<Runtime>,1053	// system::CheckTxVersion<Runtime>,1054	frame_system::CheckGenesis<Runtime>,1055	frame_system::CheckEra<Runtime>,1056	frame_system::CheckNonce<Runtime>,1057	frame_system::CheckWeight<Runtime>,1058	pallet_charge_transaction::ChargeTransactionPayment<Runtime>,1059	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,1060	pallet_ethereum::FakeTransactionFinalizer<Runtime>,1061);1062/// Unchecked extrinsic type as expected by this runtime.1063pub type UncheckedExtrinsic =1064	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;1065/// Extrinsic type that has already been checked.1066pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;1067/// Executive: handles dispatch to the various modules.1068pub type Executive = frame_executive::Executive<1069	Runtime,1070	Block,1071	frame_system::ChainContext<Runtime>,1072	Runtime,1073	AllPalletsReversedWithSystemFirst,1074>;10751076impl_opaque_keys! {1077	pub struct SessionKeys {1078		pub aura: Aura,1079	}1080}10811082impl fp_self_contained::SelfContainedCall for Call {1083	type SignedInfo = H160;10841085	fn is_self_contained(&self) -> bool {1086		match self {1087			Call::Ethereum(call) => call.is_self_contained(),1088			_ => false,1089		}1090	}10911092	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {1093		match self {1094			Call::Ethereum(call) => call.check_self_contained(),1095			_ => None,1096		}1097	}10981099	fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option<TransactionValidity> {1100		match self {1101			Call::Ethereum(call) => call.validate_self_contained(info),1102			_ => None,1103		}1104	}11051106	fn pre_dispatch_self_contained(1107		&self,1108		info: &Self::SignedInfo,1109	) -> Option<Result<(), TransactionValidityError>> {1110		match self {1111			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),1112			_ => None,1113		}1114	}11151116	fn apply_self_contained(1117		self,1118		info: Self::SignedInfo,1119	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {1120		match self {1121			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(1122				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),1123			)),1124			_ => None,1125		}1126	}1127}11281129macro_rules! dispatch_unique_runtime {1130	($collection:ident.$method:ident($($name:ident),*)) => {{1131		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);1132		let dispatch = collection.as_dyn();11331134		Ok::<_, DispatchError>(dispatch.$method($($name),*))1135	}};1136}11371138impl_common_runtime_apis!();11391140struct CheckInherents;11411142impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {1143	fn check_inherents(1144		block: &Block,1145		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,1146	) -> sp_inherents::CheckInherentsResult {1147		let relay_chain_slot = relay_state_proof1148			.read_slot()1149			.expect("Could not read the relay chain slot from the proof");11501151		let inherent_data =1152			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(1153				relay_chain_slot,1154				sp_std::time::Duration::from_secs(6),1155			)1156			.create_inherent_data()1157			.expect("Could not create the timestamp inherent data");11581159		inherent_data.check_extrinsics(block)1160	}1161}11621163cumulus_pallet_parachain_system::register_validate_block!(1164	Runtime = Runtime,1165	BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,1166	CheckInherents = CheckInherents,1167);
after · runtime/quartz/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//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.1819#![cfg_attr(not(feature = "std"), no_std)]20// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.21#![recursion_limit = "1024"]22#![allow(clippy::from_over_into, clippy::identity_op)]23#![allow(clippy::fn_to_numeric_cast_with_truncation)]24// Make the WASM binary available.25#[cfg(feature = "std")]26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));2728use sp_api::impl_runtime_apis;29use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160};30use sp_runtime::DispatchError;31// #[cfg(any(feature = "std", test))]32// pub use sp_runtime::BuildStorage;3334use sp_runtime::{35	Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,36	traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, AccountIdConversion, Zero},37	transaction_validity::{TransactionSource, TransactionValidity},38	ApplyExtrinsicResult, RuntimeAppPublic,39};4041use sp_std::prelude::*;4243#[cfg(feature = "std")]44use sp_version::NativeVersion;45use sp_version::RuntimeVersion;46pub use pallet_transaction_payment::{47	Multiplier, TargetedFeeAdjustment, FeeDetails, RuntimeDispatchInfo,48};49// A few exports that help ease life for downstream crates.50pub use pallet_balances::Call as BalancesCall;51pub use pallet_evm::{52	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,53};54pub use frame_support::{55	construct_runtime, match_types,56	dispatch::DispatchResult,57	PalletId, parameter_types, StorageValue, ConsensusEngineId,58	traits::{59		tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,60		Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,61		OnUnbalanced, Randomness, FindAuthor, ConstU32, Imbalance,62	},63	weights::{64		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},65		DispatchClass, DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,66		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients, ConstantMultiplier,67	},68};69use up_data_structs::*;70// use pallet_contracts::weights::WeightInfo;71// #[cfg(any(feature = "std", test))]72use frame_system::{73	self as frame_system, EnsureRoot, EnsureSigned,74	limits::{BlockWeights, BlockLength},75};76use sp_arithmetic::{77	traits::{BaseArithmetic, Unsigned},78};79use smallvec::smallvec;80use codec::{Encode, Decode};81use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping};82use fp_rpc::TransactionStatus;83use sp_runtime::{84	traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},85	transaction_validity::TransactionValidityError,86	SaturatedConversion,87};8889// pub use pallet_timestamp::Call as TimestampCall;90pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;9192// Polkadot imports93use pallet_xcm::XcmPassthrough;94use polkadot_parachain::primitives::Sibling;95use up_data_structs::mapping::{CrossTokenAddressMapping, EvmTokenAddressMapping};96use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};97use xcm_builder::{98	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,99	EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,100	RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,101	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,102	ParentIsPreset,103};104use xcm_executor::{Config, XcmExecutor, Assets};105use sp_std::{marker::PhantomData};106107use xcm::latest::{108	//	Xcm,109	AssetId::{Concrete},110	Fungibility::Fungible as XcmFungible,111	MultiAsset,112	Error as XcmError,113};114use xcm_executor::traits::{MatchesFungible, WeightTrader};115//use xcm_executor::traits::MatchesFungible;116use sp_runtime::traits::CheckedConversion;117118use unique_runtime_common::{119	impl_common_runtime_apis,120	types::*,121	constants::*,122	dispatch::{CollectionDispatchT, CollectionDispatch},123	sponsoring::UniqueSponsorshipHandler,124	eth_sponsoring::UniqueEthSponsorshipHandler,125	weights::CommonWeights,126};127128pub const RUNTIME_NAME: &str = "quartz";129pub const TOKEN_SYMBOL: &str = "QTZ";130131type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;132133impl RuntimeInstance for Runtime {134	type CrossAccountId = self::CrossAccountId;135136	type TransactionConverter = self::TransactionConverter;137138	fn get_transaction_converter() -> TransactionConverter {139		TransactionConverter140	}141}142143/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know144/// the specifics of the runtime. They can then be made to be agnostic over specific formats145/// of data like extrinsics, allowing for them to continue syncing the network through upgrades146/// to even the core data structures.147pub mod opaque {148	use sp_std::prelude::*;149	use sp_runtime::impl_opaque_keys;150	use super::Aura;151152	pub use unique_runtime_common::types::*;153154	impl_opaque_keys! {155		pub struct SessionKeys {156			pub aura: Aura,157		}158	}159}160161/// This runtime version.162pub const VERSION: RuntimeVersion = RuntimeVersion {163	spec_name: create_runtime_str!(RUNTIME_NAME),164	impl_name: create_runtime_str!(RUNTIME_NAME),165	authoring_version: 1,166	spec_version: 920000,167	impl_version: 0,168	apis: RUNTIME_API_VERSIONS,169	transaction_version: 1,170	state_version: 0,171};172173#[derive(codec::Encode, codec::Decode)]174pub enum XCMPMessage<XAccountId, XBalance> {175	/// Transfer tokens to the given account from the Parachain account.176	TransferToken(XAccountId, XBalance),177}178179/// The version information used to identify this runtime when compiled natively.180#[cfg(feature = "std")]181pub fn native_version() -> NativeVersion {182	NativeVersion {183		runtime_version: VERSION,184		can_author_with: Default::default(),185	}186}187188type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;189190pub struct DealWithFees;191impl OnUnbalanced<NegativeImbalance> for DealWithFees {192	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {193		if let Some(fees) = fees_then_tips.next() {194			// for fees, 100% to treasury195			let mut split = fees.ration(100, 0);196			if let Some(tips) = fees_then_tips.next() {197				// for tips, if any, 100% to treasury198				tips.ration_merge_into(100, 0, &mut split);199			}200			Treasury::on_unbalanced(split.0);201			// Author::on_unbalanced(split.1);202		}203	}204}205206parameter_types! {207	pub const BlockHashCount: BlockNumber = 2400;208	pub RuntimeBlockLength: BlockLength =209		BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);210	pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);211	pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;212	pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()213		.base_block(BlockExecutionWeight::get())214		.for_class(DispatchClass::all(), |weights| {215			weights.base_extrinsic = ExtrinsicBaseWeight::get();216		})217		.for_class(DispatchClass::Normal, |weights| {218			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);219		})220		.for_class(DispatchClass::Operational, |weights| {221			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);222			// Operational transactions have some extra reserved space, so that they223			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.224			weights.reserved = Some(225				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT226			);227		})228		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)229		.build_or_panic();230	pub const Version: RuntimeVersion = VERSION;231	pub const SS58Prefix: u8 = 255;232}233234parameter_types! {235	pub const ChainId: u64 = 8881;236}237238pub struct FixedFee;239impl FeeCalculator for FixedFee {240	fn min_gas_price() -> U256 {241		MIN_GAS_PRICE.into()242	}243}244245// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case246// (contract, which only writes a lot of data),247// approximating on top of our real store write weight248parameter_types! {249	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / <Runtime as frame_system::Config>::DbWeight::get().write;250	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;251	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();252}253254/// Limiting EVM execution to 50% of block for substrate users and management tasks255/// EVM transaction consumes more weight than substrate's, so we can't rely on them being256/// scheduled fairly257const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);258parameter_types! {259	pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get());260}261262pub enum FixedGasWeightMapping {}263impl GasWeightMapping for FixedGasWeightMapping {264	fn gas_to_weight(gas: u64) -> Weight {265		gas.saturating_mul(WeightPerGas::get())266	}267	fn weight_to_gas(weight: Weight) -> u64 {268		weight / WeightPerGas::get()269	}270}271272impl pallet_evm::Config for Runtime {273	type BlockGasLimit = BlockGasLimit;274	type FeeCalculator = FixedFee;275	type GasWeightMapping = FixedGasWeightMapping;276	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;277	type CallOrigin = EnsureAddressTruncated<Self>;278	type WithdrawOrigin = EnsureAddressTruncated<Self>;279	type AddressMapping = HashedAddressMapping<Self::Hashing>;280	type PrecompilesType = ();281	type PrecompilesValue = ();282	type Currency = Balances;283	type Event = Event;284	type OnMethodCall = (285		pallet_evm_migration::OnMethodCall<Self>,286		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,287		CollectionDispatchT<Self>,288		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,289	);290	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;291	type ChainId = ChainId;292	type Runner = pallet_evm::runner::stack::Runner<Self>;293	type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;294	type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;295	type FindAuthor = EthereumFindAuthor<Aura>;296}297298impl pallet_evm_migration::Config for Runtime {299	type WeightInfo = pallet_evm_migration::weights::SubstrateWeight<Self>;300}301302pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);303impl<F: FindAuthor<u32>> FindAuthor<H160> for EthereumFindAuthor<F> {304	fn find_author<'a, I>(digests: I) -> Option<H160>305	where306		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,307	{308		if let Some(author_index) = F::find_author(digests) {309			let authority_id = Aura::authorities()[author_index as usize].clone();310			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));311		}312		None313	}314}315316impl pallet_ethereum::Config for Runtime {317	type Event = Event;318	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;319}320321impl pallet_randomness_collective_flip::Config for Runtime {}322323impl frame_system::Config for Runtime {324	/// The data to be stored in an account.325	type AccountData = pallet_balances::AccountData<Balance>;326	/// The identifier used to distinguish between accounts.327	type AccountId = AccountId;328	/// The basic call filter to use in dispatchable.329	type BaseCallFilter = Everything;330	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).331	type BlockHashCount = BlockHashCount;332	/// The maximum length of a block (in bytes).333	type BlockLength = RuntimeBlockLength;334	/// The index type for blocks.335	type BlockNumber = BlockNumber;336	/// The weight of the overhead invoked on the block import process, independent of the extrinsics included in that block.337	type BlockWeights = RuntimeBlockWeights;338	/// The aggregated dispatch type that is available for extrinsics.339	type Call = Call;340	/// The weight of database operations that the runtime can invoke.341	type DbWeight = RocksDbWeight;342	/// The ubiquitous event type.343	type Event = Event;344	/// The type for hashing blocks and tries.345	type Hash = Hash;346	/// The hashing algorithm used.347	type Hashing = BlakeTwo256;348	/// The header type.349	type Header = generic::Header<BlockNumber, BlakeTwo256>;350	/// The index type for storing how many extrinsics an account has signed.351	type Index = Index;352	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.353	type Lookup = AccountIdLookup<AccountId, ()>;354	/// What to do if an account is fully reaped from the system.355	type OnKilledAccount = ();356	/// What to do if a new account is created.357	type OnNewAccount = ();358	type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;359	/// The ubiquitous origin type.360	type Origin = Origin;361	/// This type is being generated by `construct_runtime!`.362	type PalletInfo = PalletInfo;363	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.364	type SS58Prefix = SS58Prefix;365	/// Weight information for the extrinsics of this pallet.366	type SystemWeightInfo = frame_system::weights::SubstrateWeight<Self>;367	/// Version of the runtime.368	type Version = Version;369	type MaxConsumers = ConstU32<16>;370}371372parameter_types! {373	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;374}375376impl pallet_timestamp::Config for Runtime {377	/// A timestamp: milliseconds since the unix epoch.378	type Moment = u64;379	type OnTimestampSet = ();380	type MinimumPeriod = MinimumPeriod;381	type WeightInfo = ();382}383384parameter_types! {385	// pub const ExistentialDeposit: u128 = 500;386	pub const ExistentialDeposit: u128 = 0;387	pub const MaxLocks: u32 = 50;388}389390impl pallet_balances::Config for Runtime {391	type MaxLocks = MaxLocks;392	type MaxReserves = ();393	type ReserveIdentifier = [u8; 8];394	/// The type for recording an account's balance.395	type Balance = Balance;396	/// The ubiquitous event type.397	type Event = Event;398	type DustRemoval = Treasury;399	type ExistentialDeposit = ExistentialDeposit;400	type AccountStore = System;401	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;402}403404pub const fn deposit(items: u32, bytes: u32) -> Balance {405	items as Balance * 15 * CENTIUNIQUE + (bytes as Balance) * 6 * CENTIUNIQUE406}407408/*409parameter_types! {410	pub TombstoneDeposit: Balance = deposit(411		1,412		sp_std::mem::size_of::<pallet_contracts::Pallet<Runtime>> as u32,413	);414	pub DepositPerContract: Balance = TombstoneDeposit::get();415	pub const DepositPerStorageByte: Balance = deposit(0, 1);416	pub const DepositPerStorageItem: Balance = deposit(1, 0);417	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS);418	pub const SurchargeReward: Balance = 150 * MILLIUNIQUE;419	pub const SignedClaimHandicap: u32 = 2;420	pub const MaxDepth: u32 = 32;421	pub const MaxValueSize: u32 = 16 * 1024;422	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb423	// The lazy deletion runs inside on_initialize.424	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *425		RuntimeBlockWeights::get().max_block;426	// The weight needed for decoding the queue should be less or equal than a fifth427	// of the overall weight dedicated to the lazy deletion.428	pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / (429			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(1) -430			<Runtime as pallet_contracts::Config>::WeightInfo::on_initialize_per_queue_item(0)431		)) / 5) as u32;432	pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();433}434435impl pallet_contracts::Config for Runtime {436	type Time = Timestamp;437	type Randomness = RandomnessCollectiveFlip;438	type Currency = Balances;439	type Event = Event;440	type RentPayment = ();441	type SignedClaimHandicap = SignedClaimHandicap;442	type TombstoneDeposit = TombstoneDeposit;443	type DepositPerContract = DepositPerContract;444	type DepositPerStorageByte = DepositPerStorageByte;445	type DepositPerStorageItem = DepositPerStorageItem;446	type RentFraction = RentFraction;447	type SurchargeReward = SurchargeReward;448	type WeightPrice = pallet_transaction_payment::Pallet<Self>;449	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;450	type ChainExtension = NFTExtension;451	type DeletionQueueDepth = DeletionQueueDepth;452	type DeletionWeightLimit = DeletionWeightLimit;453	type Schedule = Schedule;454	type CallStack = [pallet_contracts::Frame<Self>; 31];455}456*/457458parameter_types! {459	/// This value increases the priority of `Operational` transactions by adding460	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.461	pub const OperationalFeeMultiplier: u8 = 5;462}463464/// Linear implementor of `WeightToFeePolynomial`465pub struct LinearFee<T>(sp_std::marker::PhantomData<T>);466467impl<T> WeightToFeePolynomial for LinearFee<T>468where469	T: BaseArithmetic + From<u32> + Copy + Unsigned,470{471	type Balance = T;472473	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {474		smallvec!(WeightToFeeCoefficient {475			// Targeting 0.1 Unique per NFT transfer476			coeff_integer: WEIGHT_TO_FEE_COEFF.into(),477			coeff_frac: Perbill::zero(),478			negative: false,479			degree: 1,480		})481	}482}483484impl pallet_transaction_payment::Config for Runtime {485	type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter<Balances, DealWithFees>;486	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;487	type OperationalFeeMultiplier = OperationalFeeMultiplier;488	type WeightToFee = LinearFee<Balance>;489	type FeeMultiplierUpdate = ();490}491492parameter_types! {493	pub const ProposalBond: Permill = Permill::from_percent(5);494	pub const ProposalBondMinimum: Balance = 1 * UNIQUE;495	pub const ProposalBondMaximum: Balance = 1000 * UNIQUE;496	pub const SpendPeriod: BlockNumber = 5 * MINUTES;497	pub const Burn: Permill = Permill::from_percent(0);498	pub const TipCountdown: BlockNumber = 1 * DAYS;499	pub const TipFindersFee: Percent = Percent::from_percent(20);500	pub const TipReportDepositBase: Balance = 1 * UNIQUE;501	pub const DataDepositPerByte: Balance = 1 * CENTIUNIQUE;502	pub const BountyDepositBase: Balance = 1 * UNIQUE;503	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;504	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");505	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;506	pub const MaximumReasonLength: u32 = 16384;507	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);508	pub const BountyValueMinimum: Balance = 5 * UNIQUE;509	pub const MaxApprovals: u32 = 100;510}511512impl pallet_treasury::Config for Runtime {513	type PalletId = TreasuryModuleId;514	type Currency = Balances;515	type ApproveOrigin = EnsureRoot<AccountId>;516	type RejectOrigin = EnsureRoot<AccountId>;517	type Event = Event;518	type OnSlash = ();519	type ProposalBond = ProposalBond;520	type ProposalBondMinimum = ProposalBondMinimum;521	type ProposalBondMaximum = ProposalBondMaximum;522	type SpendPeriod = SpendPeriod;523	type Burn = Burn;524	type BurnDestination = ();525	type SpendFunds = ();526	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;527	type MaxApprovals = MaxApprovals;528}529530impl pallet_sudo::Config for Runtime {531	type Event = Event;532	type Call = Call;533}534535pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);536537impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider538	for RelayChainBlockNumberProvider<T>539{540	type BlockNumber = BlockNumber;541542	fn current_block_number() -> Self::BlockNumber {543		cumulus_pallet_parachain_system::Pallet::<T>::validation_data()544			.map(|d| d.relay_parent_number)545			.unwrap_or_default()546	}547}548549parameter_types! {550	pub const MinVestedTransfer: Balance = 10 * UNIQUE;551	pub const MaxVestingSchedules: u32 = 28;552}553554impl orml_vesting::Config for Runtime {555	type Event = Event;556	type Currency = pallet_balances::Pallet<Runtime>;557	type MinVestedTransfer = MinVestedTransfer;558	type VestedTransferOrigin = EnsureSigned<AccountId>;559	type WeightInfo = ();560	type MaxVestingSchedules = MaxVestingSchedules;561	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;562}563564parameter_types! {565	pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;566	pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;567}568569impl cumulus_pallet_parachain_system::Config for Runtime {570	type Event = Event;571	type SelfParaId = parachain_info::Pallet<Self>;572	type OnSystemEvent = ();573	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<574	// 	MaxDownwardMessageWeight,575	// 	XcmExecutor<XcmConfig>,576	// 	Call,577	// >;578	type OutboundXcmpMessageSource = XcmpQueue;579	type DmpMessageHandler = DmpQueue;580	type ReservedDmpWeight = ReservedDmpWeight;581	type ReservedXcmpWeight = ReservedXcmpWeight;582	type XcmpMessageHandler = XcmpQueue;583}584585impl parachain_info::Config for Runtime {}586587impl cumulus_pallet_aura_ext::Config for Runtime {}588589parameter_types! {590	pub const RelayLocation: MultiLocation = MultiLocation::parent();591	pub const RelayNetwork: NetworkId = NetworkId::Polkadot;592	pub RelayOrigin: Origin = cumulus_pallet_xcm::Origin::Relay.into();593	pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();594}595596/// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used597/// when determining ownership of accounts for asset transacting and when attempting to use XCM598/// `Transact` in order to determine the dispatch Origin.599pub type LocationToAccountId = (600	// The parent (Relay-chain) origin converts to the default `AccountId`.601	ParentIsPreset<AccountId>,602	// Sibling parachain origins convert to AccountId via the `ParaId::into`.603	SiblingParachainConvertsVia<Sibling, AccountId>,604	// Straight up local `AccountId32` origins just alias directly to `AccountId`.605	AccountId32Aliases<RelayNetwork, AccountId>,606);607608pub struct OnlySelfCurrency;609impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {610	fn matches_fungible(a: &MultiAsset) -> Option<B> {611		match (&a.id, &a.fun) {612			(Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),613			_ => None,614		}615	}616}617618/// Means for transacting assets on this chain.619pub type LocalAssetTransactor = CurrencyAdapter<620	// Use this currency:621	Balances,622	// Use this currency when it is a fungible asset matching the given location or name:623	OnlySelfCurrency,624	// Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:625	LocationToAccountId,626	// Our chain's account ID type (we can't get away without mentioning it explicitly):627	AccountId,628	// We don't track any teleports.629	(),630>;631632/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,633/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can634/// biases the kind of local `Origin` it will become.635pub type XcmOriginToTransactDispatchOrigin = (636	// Sovereign account converter; this attempts to derive an `AccountId` from the origin location637	// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for638	// foreign chains who want to have a local sovereign account on this chain which they control.639	SovereignSignedViaLocation<LocationToAccountId, Origin>,640	// Native converter for Relay-chain (Parent) location; will converts to a `Relay` origin when641	// recognised.642	RelayChainAsNative<RelayOrigin, Origin>,643	// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when644	// recognised.645	SiblingParachainAsNative<cumulus_pallet_xcm::Origin, Origin>,646	// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a647	// transaction from the Root origin.648	ParentAsSuperuser<Origin>,649	// Native signed account converter; this just converts an `AccountId32` origin into a normal650	// `Origin::Signed` origin of the same 32-byte value.651	SignedAccountId32AsNative<RelayNetwork, Origin>,652	// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.653	XcmPassthrough<Origin>,654);655656parameter_types! {657	// One XCM operation is 1_000_000 weight - almost certainly a conservative estimate.658	pub UnitWeightCost: Weight = 1_000_000;659	// 1200 UNIQUEs buy 1 second of weight.660	pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), 1_200 * UNIQUE);661	pub const MaxInstructions: u32 = 100;662	pub const MaxAuthorities: u32 = 100_000;663}664665match_types! {666	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {667		MultiLocation { parents: 1, interior: Here } |668		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }669	};670}671672pub type Barrier = (673	TakeWeightCredit,674	AllowTopLevelPaidExecutionFrom<Everything>,675	AllowUnpaidExecutionFrom<ParentOrParentsUnitPlurality>,676	// ^^^ Parent & its unit plurality gets free execution677);678679pub struct UsingOnlySelfCurrencyComponents<680	WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,681	AssetId: Get<MultiLocation>,682	AccountId,683	Currency: CurrencyT<AccountId>,684	OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,685>(686	Weight,687	Currency::Balance,688	PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,689);690impl<691		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,692		AssetId: Get<MultiLocation>,693		AccountId,694		Currency: CurrencyT<AccountId>,695		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,696	> WeightTrader697	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>698{699	fn new() -> Self {700		Self(0, Zero::zero(), PhantomData)701	}702703	fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {704		let amount = WeightToFee::calc(&weight);705		let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;706707		// location to this parachain through relay chain708		let option1: xcm::v1::AssetId = Concrete(MultiLocation {709			parents: 1,710			interior: X1(Parachain(ParachainInfo::parachain_id().into())),711		});712		// direct location713		let option2: xcm::v1::AssetId = Concrete(MultiLocation {714			parents: 0,715			interior: Here,716		});717718		let required = if payment.fungible.contains_key(&option1) {719			(option1, u128_amount).into()720		} else if payment.fungible.contains_key(&option2) {721			(option2, u128_amount).into()722		} else {723			(Concrete(MultiLocation::default()), u128_amount).into()724		};725726		let unused = payment727			.checked_sub(required)728			.map_err(|_| XcmError::TooExpensive)?;729		self.0 = self.0.saturating_add(weight);730		self.1 = self.1.saturating_add(amount);731		Ok(unused)732	}733734	fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {735		let weight = weight.min(self.0);736		let amount = WeightToFee::calc(&weight);737		self.0 -= weight;738		self.1 = self.1.saturating_sub(amount);739		let amount: u128 = amount.saturated_into();740		if amount > 0 {741			Some((AssetId::get(), amount).into())742		} else {743			None744		}745	}746}747impl<748		WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,749		AssetId: Get<MultiLocation>,750		AccountId,751		Currency: CurrencyT<AccountId>,752		OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,753	> Drop754	for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>755{756	fn drop(&mut self) {757		OnUnbalanced::on_unbalanced(Currency::issue(self.1));758	}759}760761pub struct XcmConfig;762impl Config for XcmConfig {763	type Call = Call;764	type XcmSender = XcmRouter;765	// How to withdraw and deposit an asset.766	type AssetTransactor = LocalAssetTransactor;767	type OriginConverter = XcmOriginToTransactDispatchOrigin;768	type IsReserve = NativeAsset;769	type IsTeleporter = (); // Teleportation is disabled770	type LocationInverter = LocationInverter<Ancestry>;771	type Barrier = Barrier;772	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;773	type Trader = UsingOnlySelfCurrencyComponents<774		IdentityFee<Balance>,775		RelayLocation,776		AccountId,777		Balances,778		(),779	>;780	type ResponseHandler = (); // Don't handle responses for now.781	type SubscriptionService = PolkadotXcm;782783	type AssetTrap = PolkadotXcm;784	type AssetClaims = PolkadotXcm;785}786787// parameter_types! {788// 	pub const MaxDownwardMessageWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 10;789// }790791/// No local origins on this chain are allowed to dispatch XCM sends/executions.792pub type LocalOriginToLocation = (SignedToAccountId32<Origin, AccountId, RelayNetwork>,);793794/// The means for routing XCM messages which are not for local execution into the right message795/// queues.796pub type XcmRouter = (797	// Two routers - use UMP to communicate with the relay chain:798	cumulus_primitives_utility::ParentAsUmp<ParachainSystem, ()>,799	// ..and XCMP to communicate with the sibling chains.800	XcmpQueue,801);802803impl pallet_evm_coder_substrate::Config for Runtime {804	type GasWeightMapping = FixedGasWeightMapping;805}806807impl pallet_xcm::Config for Runtime {808	type Event = Event;809	type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;810	type XcmRouter = XcmRouter;811	type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;812	type XcmExecuteFilter = Everything;813	type XcmExecutor = XcmExecutor<XcmConfig>;814	type XcmTeleportFilter = Everything;815	type XcmReserveTransferFilter = Everything;816	type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;817	type LocationInverter = LocationInverter<Ancestry>;818	type Origin = Origin;819	type Call = Call;820	const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;821	type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;822}823824impl cumulus_pallet_xcm::Config for Runtime {825	type Event = Event;826	type XcmExecutor = XcmExecutor<XcmConfig>;827}828829impl cumulus_pallet_xcmp_queue::Config for Runtime {830	type WeightInfo = ();831	type Event = Event;832	type XcmExecutor = XcmExecutor<XcmConfig>;833	type ChannelInfo = ParachainSystem;834	type VersionWrapper = ();835	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;836	type ControllerOrigin = EnsureRoot<AccountId>;837	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;838}839840impl cumulus_pallet_dmp_queue::Config for Runtime {841	type Event = Event;842	type XcmExecutor = XcmExecutor<XcmConfig>;843	type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;844}845846impl pallet_aura::Config for Runtime {847	type AuthorityId = AuraId;848	type DisabledValidators = ();849	type MaxAuthorities = MaxAuthorities;850}851852parameter_types! {853	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account();854	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;855}856857impl pallet_common::Config for Runtime {858	type Event = Event;859860	type Currency = Balances;861	type CollectionCreationPrice = CollectionCreationPrice;862	type TreasuryAccountId = TreasuryAccountId;863	type CollectionDispatch = CollectionDispatchT<Self>;864865	type EvmTokenAddressMapping = EvmTokenAddressMapping;866	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;867}868869impl pallet_structure::Config for Runtime {870	type Event = Event;871	type Call = Call;872	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;873}874875impl pallet_evm::account::Config for Runtime {876	type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Self>;877	type EvmAddressMapping = HashedAddressMapping<Self::Hashing>;878	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;879}880881impl pallet_fungible::Config for Runtime {882	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;883}884impl pallet_refungible::Config for Runtime {885	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;886}887impl pallet_nonfungible::Config for Runtime {888	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;889}890891impl pallet_proxy_rmrk_core::Config for Runtime {892	type Event = Event;893}894895impl pallet_proxy_rmrk_equip::Config for Runtime {896	type Event = Event;897}898899impl pallet_unique::Config for Runtime {900	type Event = Event;901	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;902	type CommonWeightInfo = CommonWeights<Self>;903}904905parameter_types! {906	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied907}908909/// Used for the pallet inflation910impl pallet_inflation::Config for Runtime {911	type Currency = Balances;912	type TreasuryAccountId = TreasuryAccountId;913	type InflationBlockInterval = InflationBlockInterval;914	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;915}916917// parameter_types! {918// 	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(50) *919// 		RuntimeBlockWeights::get().max_block;920// 	pub const MaxScheduledPerBlock: u32 = 50;921// }922923type EvmSponsorshipHandler = (924	UniqueEthSponsorshipHandler<Runtime>,925	pallet_evm_contract_helpers::HelpersContractSponsoring<Runtime>,926);927type SponsorshipHandler = (928	UniqueSponsorshipHandler<Runtime>,929	//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,930	pallet_evm_transaction_payment::BridgeSponsorshipHandler<Runtime>,931);932933// impl pallet_unq_scheduler::Config for Runtime {934// 	type Event = Event;935// 	type Origin = Origin;936// 	type PalletsOrigin = OriginCaller;937// 	type Call = Call;938// 	type MaximumWeight = MaximumSchedulerWeight;939// 	type ScheduleOrigin = EnsureSigned<AccountId>;940// 	type MaxScheduledPerBlock = MaxScheduledPerBlock;941// 	type SponsorshipHandler = SponsorshipHandler;942// 	type WeightInfo = ();943// }944945impl pallet_evm_transaction_payment::Config for Runtime {946	type EvmSponsorshipHandler = EvmSponsorshipHandler;947	type Currency = Balances;948}949950impl pallet_charge_transaction::Config for Runtime {951	type SponsorshipHandler = SponsorshipHandler;952}953954// impl pallet_contract_helpers::Config for Runtime {955//	 type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;956// }957958parameter_types! {959	// 0x842899ECF380553E8a4de75bF534cdf6fBF64049960	pub const HelpersContractAddress: H160 = H160([961		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,962	]);963		964	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f965	pub const EvmCollectionHelperAddress: H160 = H160([966		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,967	]);968}969970impl pallet_evm_contract_helpers::Config for Runtime {971	type ContractAddress = HelpersContractAddress;972	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;973}974975impl pallet_unique::eth::Config for Runtime {976	type ContractAddress = EvmCollectionHelperAddress;977}978979construct_runtime!(980	pub enum Runtime where981		Block = Block,982		NodeBlock = opaque::Block,983		UncheckedExtrinsic = UncheckedExtrinsic984	{985		ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Config, Storage, Inherent, Event<T>, ValidateUnsigned} = 20,986		ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21,987988		Aura: pallet_aura::{Pallet, Config<T>} = 22,989		AuraExt: cumulus_pallet_aura_ext::{Pallet, Config} = 23,990991		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>} = 30,992		RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage} = 31,993		Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent} = 32,994		TransactionPayment: pallet_transaction_payment::{Pallet, Storage} = 33,995		Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,996		Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,997		System: frame_system::{Pallet, Call, Storage, Config, Event<T>} = 36,998		Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,999		// Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,1000		// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,10011002		// XCM helpers.1003		XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event<T>} = 50,1004		PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin} = 51,1005		CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event<T>, Origin} = 52,1006		DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 53,10071008		// Unique Pallets1009		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,1010		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,1011		// Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,1012		// free = 631013		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,1014		// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage} = 65,1015		Common: pallet_common::{Pallet, Storage, Event<T>} = 66,1016		Fungible: pallet_fungible::{Pallet, Storage} = 67,1017		Refungible: pallet_refungible::{Pallet, Storage} = 68,1018		Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69,1019		Structure: pallet_structure::{Pallet, Call, Storage, Event<T>} = 70,1020		RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event<T>} = 71,1021		RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event<T>} = 72,10221023		// Frontier1024		EVM: pallet_evm::{Pallet, Config, Call, Storage, Event<T>} = 100,1025		Ethereum: pallet_ethereum::{Pallet, Config, Call, Storage, Event, Origin} = 101,10261027		EvmCoderSubstrate: pallet_evm_coder_substrate::{Pallet, Storage} = 150,1028		EvmContractHelpers: pallet_evm_contract_helpers::{Pallet, Storage} = 151,1029		EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,1030		EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,1031	}1032);10331034pub struct TransactionConverter;10351036impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {1037	fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {1038		UncheckedExtrinsic::new_unsigned(1039			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),1040		)1041	}1042}10431044impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {1045	fn convert_transaction(1046		&self,1047		transaction: pallet_ethereum::Transaction,1048	) -> opaque::UncheckedExtrinsic {1049		let extrinsic = UncheckedExtrinsic::new_unsigned(1050			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),1051		);1052		let encoded = extrinsic.encode();1053		opaque::UncheckedExtrinsic::decode(&mut &encoded[..])1054			.expect("Encoded extrinsic is always valid")1055	}1056}10571058/// The address format for describing accounts.1059pub type Address = sp_runtime::MultiAddress<AccountId, ()>;1060/// Block header type as expected by this runtime.1061pub type Header = generic::Header<BlockNumber, BlakeTwo256>;1062/// Block type as expected by this runtime.1063pub type Block = generic::Block<Header, UncheckedExtrinsic>;1064/// A Block signed with a Justification1065pub type SignedBlock = generic::SignedBlock<Block>;1066/// BlockId type as expected by this runtime.1067pub type BlockId = generic::BlockId<Block>;1068/// The SignedExtension to the basic transaction logic.1069pub type SignedExtra = (1070	frame_system::CheckSpecVersion<Runtime>,1071	// system::CheckTxVersion<Runtime>,1072	frame_system::CheckGenesis<Runtime>,1073	frame_system::CheckEra<Runtime>,1074	frame_system::CheckNonce<Runtime>,1075	frame_system::CheckWeight<Runtime>,1076	pallet_charge_transaction::ChargeTransactionPayment<Runtime>,1077	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,1078	pallet_ethereum::FakeTransactionFinalizer<Runtime>,1079);1080/// Unchecked extrinsic type as expected by this runtime.1081pub type UncheckedExtrinsic =1082	fp_self_contained::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;1083/// Extrinsic type that has already been checked.1084pub type CheckedExtrinsic = fp_self_contained::CheckedExtrinsic<AccountId, Call, SignedExtra, H160>;1085/// Executive: handles dispatch to the various modules.1086pub type Executive = frame_executive::Executive<1087	Runtime,1088	Block,1089	frame_system::ChainContext<Runtime>,1090	Runtime,1091	AllPalletsReversedWithSystemFirst,1092>;10931094impl_opaque_keys! {1095	pub struct SessionKeys {1096		pub aura: Aura,1097	}1098}10991100impl fp_self_contained::SelfContainedCall for Call {1101	type SignedInfo = H160;11021103	fn is_self_contained(&self) -> bool {1104		match self {1105			Call::Ethereum(call) => call.is_self_contained(),1106			_ => false,1107		}1108	}11091110	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {1111		match self {1112			Call::Ethereum(call) => call.check_self_contained(),1113			_ => None,1114		}1115	}11161117	fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option<TransactionValidity> {1118		match self {1119			Call::Ethereum(call) => call.validate_self_contained(info),1120			_ => None,1121		}1122	}11231124	fn pre_dispatch_self_contained(1125		&self,1126		info: &Self::SignedInfo,1127	) -> Option<Result<(), TransactionValidityError>> {1128		match self {1129			Call::Ethereum(call) => call.pre_dispatch_self_contained(info),1130			_ => None,1131		}1132	}11331134	fn apply_self_contained(1135		self,1136		info: Self::SignedInfo,1137	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {1138		match self {1139			call @ Call::Ethereum(pallet_ethereum::Call::transact { .. }) => Some(call.dispatch(1140				Origin::from(pallet_ethereum::RawOrigin::EthereumTransaction(info)),1141			)),1142			_ => None,1143		}1144	}1145}11461147macro_rules! dispatch_unique_runtime {1148	($collection:ident.$method:ident($($name:ident),*)) => {{1149		let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);1150		let dispatch = collection.as_dyn();11511152		Ok::<_, DispatchError>(dispatch.$method($($name),*))1153	}};1154}11551156impl_common_runtime_apis!();11571158struct CheckInherents;11591160impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {1161	fn check_inherents(1162		block: &Block,1163		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,1164	) -> sp_inherents::CheckInherentsResult {1165		let relay_chain_slot = relay_state_proof1166			.read_slot()1167			.expect("Could not read the relay chain slot from the proof");11681169		let inherent_data =1170			cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(1171				relay_chain_slot,1172				sp_std::time::Duration::from_secs(6),1173			)1174			.create_inherent_data()1175			.expect("Could not create the timestamp inherent data");11761177		inherent_data.check_extrinsics(block)1178	}1179}11801181cumulus_pallet_parachain_system::register_validate_block!(1182	Runtime = Runtime,1183	BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,1184	CheckInherents = CheckInherents,1185);
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -49,7 +49,8 @@
 // A few exports that help ease life for downstream crates.
 pub use pallet_balances::Call as BalancesCall;
 pub use pallet_evm::{
-	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _,
+	EnsureAddressTruncated, HashedAddressMapping, Runner, account::CrossAccountId as _, OnMethodCall,
+	Account as EVMAccount, FeeCalculator, GasWeightMapping,
 };
 pub use frame_support::{
 	construct_runtime, match_types,
@@ -84,7 +85,6 @@
 };
 use smallvec::smallvec;
 use codec::{Encode, Decode};
-use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping};
 use fp_rpc::TransactionStatus;
 use sp_runtime::{
 	traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},
@@ -120,7 +120,15 @@
 //use xcm_executor::traits::MatchesFungible;
 use sp_runtime::traits::CheckedConversion;
 
-use unique_runtime_common::{impl_common_runtime_apis, types::*, constants::*};
+use unique_runtime_common::{
+	impl_common_runtime_apis,
+	types::*,
+	constants::*,
+	dispatch::{CollectionDispatchT, CollectionDispatch},
+	sponsoring::UniqueSponsorshipHandler,
+	eth_sponsoring::UniqueEthSponsorshipHandler,
+	weights::CommonWeights,
+};
 
 pub const RUNTIME_NAME: &str = "unique";
 pub const TOKEN_SYMBOL: &str = "UNQ";
@@ -282,6 +290,7 @@
 		pallet_evm_migration::OnMethodCall<Self>,
 		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
 		CollectionDispatchT<Self>,
+		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,
 	);
 	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
 	type ChainId = ChainId;
@@ -956,6 +965,11 @@
 	pub const HelpersContractAddress: H160 = H160([
 		0x84, 0x28, 0x99, 0xec, 0xf3, 0x80, 0x55, 0x3e, 0x8a, 0x4d, 0xe7, 0x5b, 0xf5, 0x34, 0xcd, 0xf6, 0xfb, 0xf6, 0x40, 0x49,
 	]);
+		
+	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
+	pub const EvmCollectionHelperAddress: H160 = H160([
+		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
+	]);
 }
 
 impl pallet_evm_contract_helpers::Config for Runtime {
@@ -963,6 +977,10 @@
 	type DefaultSponsoringRateLimit = DefaultSponsoringRateLimit;
 }
 
+impl pallet_unique::eth::Config for Runtime {
+	type ContractAddress = EvmCollectionHelperAddress;
+}
+
 construct_runtime!(
 	pub enum Runtime where
 		Block = Block,
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -73,6 +73,7 @@
     "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
     "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
     "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
+    "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",
     "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
     "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",
     "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",
@@ -88,7 +89,7 @@
     "bignumber.js": "^9.0.2",
     "chai-as-promised": "^7.1.1",
     "find-process": "^1.4.7",
-    "solc": "^0.8.13",
+    "solc": "0.8.13",
     "web3": "^1.7.3"
   },
   "standard": {
addedtests/src/eth/api/CollectionHelper.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/api/CollectionHelper.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+// Selector: 56c215c5
+interface CollectionHelper is Dummy, ERC165 {
+	// Selector: create721Collection(string,string,string) 951c0151
+	function create721Collection(
+		string memory name,
+		string memory description,
+		string memory tokenPrefix
+	) external view returns (address);
+
+	// Selector: isCollectionExist(address) c3de1494
+	function isCollectionExist(address collectionAddress)
+		external
+		view
+		returns (bool);
+}
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -65,8 +65,8 @@
 		returns (uint256);
 }
 
-// Selector: 9b5e29c5
-interface CollectionProperties is Dummy, ERC165 {
+// Selector: f5652829
+interface Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
 		external;
@@ -81,6 +81,18 @@
 		external
 		view
 		returns (bytes memory);
+
+	// Selector: ethSetSponsor(address) 8f9af356
+	function ethSetSponsor(address sponsor) external;
+
+	// Selector: ethConfirmSponsorship() a8580d1a
+	function ethConfirmSponsorship() external;
+
+	// Selector: setLimit(string,string) bf4d2014
+	function setLimit(string memory limit, string memory value) external;
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() external view returns (address);
 }
 
 interface UniqueFungible is
@@ -88,5 +100,5 @@
 	ERC165,
 	ERC20,
 	ERC20UniqueExtensions,
-	CollectionProperties
+	Collection
 {}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -191,24 +191,6 @@
 	function totalSupply() external view returns (uint256);
 }
 
-// Selector: 9b5e29c5
-interface CollectionProperties is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		external;
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) external;
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		external
-		view
-		returns (bytes memory);
-}
-
 // Selector: d74d154f
 interface ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
@@ -231,6 +213,36 @@
 		returns (bool);
 }
 
+// Selector: f5652829
+interface Collection is Dummy, ERC165 {
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		external;
+
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) external;
+
+	// Throws error if key not found
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		external
+		view
+		returns (bytes memory);
+
+	// Selector: ethSetSponsor(address) 8f9af356
+	function ethSetSponsor(address sponsor) external;
+
+	// Selector: ethConfirmSponsorship() a8580d1a
+	function ethConfirmSponsorship() external;
+
+	// Selector: setLimit(string,string) bf4d2014
+	function setLimit(string memory limit, string memory value) external;
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() external view returns (address);
+}
+
 interface UniqueNFT is
 	Dummy,
 	ERC165,
@@ -240,6 +252,6 @@
 	ERC721UniqueExtensions,
 	ERC721Mintable,
 	ERC721Burnable,
-	CollectionProperties,
+	Collection,
 	TokenProperties
 {}
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -14,7 +14,17 @@
 // 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 {
+  collectionIdToAddress, 
+  createEthAccount, 
+  createEthAccountWithBalance, 
+  deployFlipper, 
+  ethBalanceViaSub, 
+  GAS_ARGS, 
+  itWeb3, 
+  recordEthFee, 
+  usingWeb3,
+} from './util/helpers';
 import {expect} from 'chai';
 import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
addedtests/src/eth/collectionHelperAbi.jsondiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/collectionHelperAbi.json
@@ -0,0 +1,35 @@
+[
+  {
+    "inputs": [
+      { "internalType": "string", "name": "name", "type": "string" },
+      { "internalType": "string", "name": "description", "type": "string" },
+      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+    ],
+    "name": "create721Collection",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "collectionAddress",
+        "type": "address"
+      }
+    ],
+    "name": "isCollectionExist",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  }
+]
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -29,19 +29,19 @@
   normalizeEvents,
   subToEth,
   executeEthTxOnSub,
+  evmCollectionHelper,
+  getCollectionAddressFromResult,
+  evmCollection,
 } from './util/helpers';
 import {
   addCollectionAdminExpectSuccess,
   createCollectionExpectSuccess,
-  getCreateCollectionResult,
+  getDetailedCollectionInfo,
   transferBalanceTo,
 } from '../util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
-import {
-  submitTransactionAsync,
-} from '../substrate/substrate-api';
 import getBalance from '../substrate/get-balance';
-import {alicesPublicKey} from '../accounts';
+import {evmToAddress} from '@polkadot/util-crypto';
 
 describe('Sponsoring EVM contracts', () => {
   itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {
@@ -221,89 +221,87 @@
     expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');
   });
 
-  itWeb3('Sponsoring evm address from substrate collection', async ({api, web3}) => {
-    const owner = privateKey('//Alice');
-    const userEth = createEthAccount(web3);
-    const collectionId = await createCollectionExpectSuccess();
+  //TODO: CORE-302 add eth methods
+  itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    let result = await collectionHelper.methods.create721Collection('Sponsor collection', '1', '1').send();
+    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+    const sponsor = await createEthAccountWithBalance(api, web3);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+    result = await collectionEvm.methods.ethSetSponsor(sponsor).send();
+    let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+    expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
+    expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
+    await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
 
-    {
-      const tx = api.tx.unique.setCollectionSponsor(collectionId, owner.address);
-      const events = await submitTransactionAsync(owner, tx);
-      const result = getCreateCollectionResult(events);
-      expect(result.success).to.be.true;
-    }
-    {
-      const tx = api.tx.unique.confirmSponsorship(collectionId);
-      const events = await submitTransactionAsync(owner, tx);
-      const result = getCreateCollectionResult(events);
-      expect(result.success).to.be.true;
-    }
+    const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
+    await sponsorCollection.methods.ethConfirmSponsorship().send();
+    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+    expect(collectionSub.sponsorship.isConfirmed).to.be.true;
+    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
 
-    const address = collectionIdToAddress(collectionId);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS});
+    const user = createEthAccount(web3);
+    const userContract = evmCollection(web3, user, collectionIdAddress);
+    const nextTokenId = await userContract.methods.nextTokenId().call();
 
-    { // This part should fail, because user not in access list and user have no money
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      await expect(contract.methods.mintWithTokenURI(
-        userEth,
-        nextTokenId,
-        'Test URI',
-      ).call({from: userEth})).to.be.rejectedWith(/PublicMintingNotAllowed/);
-    }
-
-    {
-      const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList');
-      const events = await submitTransactionAsync(owner, tx);
-      const result = getCreateCollectionResult(events);
-      expect(result.success).to.be.true;
-    }
-    {
-      const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth});
-      const events = await submitTransactionAsync(owner, tx);
-      const result = getCreateCollectionResult(events);
-      expect(result.success).to.be.true;
-    }
-    {
-      const tx = api.tx.unique.setMintPermission(collectionId, true);
-      const events = await submitTransactionAsync(owner, tx);
-      const result = getCreateCollectionResult(events);
-      expect(result.success).to.be.true;
-    }
+    expect(nextTokenId).to.be.equal('1');
+    await expect(userContract.methods.mintWithTokenURI(
+      user,
+      nextTokenId,
+      'Test URI',
+    ).call()).to.be.rejectedWith('PublicMintingNotAllowed');
+    
+    // TODO: add this methods to eth
+    // {
+    //   const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList');
+    //   const events = await submitTransactionAsync(owner, tx);
+    //   const result = getCreateCollectionResult(events);
+    //   expect(result.success).to.be.true;
+    // }
+    // {
+    //   const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth});
+    //   const events = await submitTransactionAsync(owner, tx);
+    //   const result = getCreateCollectionResult(events);
+    //   expect(result.success).to.be.true;
+    // }
+    // {
+    //   const tx = api.tx.unique.setMintPermission(collectionId, true);
+    //   const events = await submitTransactionAsync(owner, tx);
+    //   const result = getCreateCollectionResult(events);
+    //   expect(result.success).to.be.true;
+    // }
 
-    const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]);
+    // const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]);
 
     {
-      const nextTokenId = await contract.methods.nextTokenId().call();
+      const nextTokenId = await userContract.methods.nextTokenId().call();
       expect(nextTokenId).to.be.equal('1');
-      const result = await contract.methods.mintWithTokenURI(
-        userEth,
+      const result = await userContract.methods.mintWithTokenURI(
+        user,
         nextTokenId,
         'Test URI',
-      ).send({from: userEth});
+      ).send();
       const events = normalizeEvents(result.events);
 
       expect(events).to.be.deep.equal([
         {
-          address,
+          collectionIdAddress,
           event: 'Transfer',
           args: {
             from: '0x0000000000000000000000000000000000000000',
-            to: userEth,
+            to: user,
             tokenId: nextTokenId,
           },
         },
       ]);
 
-      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+      expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
     }
-
-    const [alicesBalanceAfter] = await getBalance(api, [alicesPublicKey]);
-    expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
   });
-
 
-  itWeb3('Check that transaction via EVM spend money from substrate address', async ({api, web3}) => {
+  //TODO: CORE-302 add eth methods
+  itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3}) => {
     const owner = privateKey('//Alice');
     const user = privateKey(`//User/${Date.now()}`);
     const userEth = subToEth(user.address);
addedtests/src/eth/createCollection.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/createCollection.test.ts
@@ -0,0 +1,236 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// 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 {evmToAddress} from '@polkadot/util-crypto';
+import {expect} from 'chai';
+import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
+import {
+  evmCollectionHelper,
+  collectionIdToAddress,
+  createEthAccount,
+  createEthAccountWithBalance,
+  evmCollection,
+  itWeb3,
+  getCollectionAddressFromResult,
+} from './util/helpers';
+
+describe('Create collection from EVM', () => {
+  itWeb3('Create collection', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const helper = evmCollectionHelper(web3, owner);
+    const collectionName = 'CollectionEVM';
+    const description = 'Some description';
+    const tokenPrefix = 'token prefix';
+  
+    const collectionCountBefore = await getCreatedCollectionCount(api);
+    const result = await helper.methods
+      .create721Collection(collectionName, description, tokenPrefix)
+      .send();
+    const collectionCountAfter = await getCreatedCollectionCount(api);
+  
+    const {collectionId, collection} = await getCollectionAddressFromResult(api, result);
+    expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);
+    expect(collectionId).to.be.eq(collectionCountAfter);
+    expect(collection.name.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(collectionName);
+    expect(collection.description.map(v => String.fromCharCode(v.toNumber())).join('')).to.be.eq(description);
+    expect(collection.tokenPrefix.toHuman()).to.be.eq(tokenPrefix);
+    expect(collection.schemaVersion.type).to.be.eq('ImageURL');
+  });
+
+  itWeb3('Check collection address exist', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+  
+    const expectedCollectionId = await getCreatedCollectionCount(api) + 1;
+    const expectedCollectionAddress = collectionIdToAddress(expectedCollectionId);
+    expect(await collectionHelper.methods
+      .isCollectionExist(expectedCollectionAddress)
+      .call()).to.be.false;
+
+    await collectionHelper.methods
+      .create721Collection('A', 'A', 'A')
+      .send();
+    
+    expect(await collectionHelper.methods
+      .isCollectionExist(expectedCollectionAddress)
+      .call()).to.be.true;
+  });
+  
+  itWeb3('Set sponsorship', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    let result = await collectionHelper.methods.create721Collection('Sponsor collection', '1', '1').send();
+    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+    const sponsor = await createEthAccountWithBalance(api, web3);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+    result = await collectionEvm.methods.ethSetSponsor(sponsor).send();
+    let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+    expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
+    expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
+    await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
+    const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
+    await sponsorCollection.methods.ethConfirmSponsorship().send();
+    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+    expect(collectionSub.sponsorship.isConfirmed).to.be.true;
+    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
+  });
+
+  itWeb3('Set limits', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    const result = await collectionHelper.methods.create721Collection('Const collection', '5', '5').send();
+    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+    const limits = {
+      accountTokenOwnershipLimit: 1000,
+      sponsoredDataSize: 1024,
+      sponsoredDataRateLimit: 30,
+      tokenLimit: 1000000,
+      sponsorTransferTimeout: 6,
+      sponsorApproveTimeout: 6,
+      ownerCanTransfer: false,
+      ownerCanDestroy: false,
+      transfersEnabled: false,
+    };
+
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+    await collectionEvm.methods.setLimit('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit.toString()).send();
+    await collectionEvm.methods.setLimit('sponsoredDataSize', limits.sponsoredDataSize.toString()).send();
+    await collectionEvm.methods.setLimit('sponsoredDataRateLimit', limits.sponsoredDataRateLimit.toString()).send();
+    await collectionEvm.methods.setLimit('tokenLimit', limits.tokenLimit.toString()).send();
+    await collectionEvm.methods.setLimit('sponsorTransferTimeout', limits.sponsorTransferTimeout.toString()).send();
+    await collectionEvm.methods.setLimit('sponsorApproveTimeout', limits.sponsorApproveTimeout.toString()).send();
+    await collectionEvm.methods.setLimit('ownerCanTransfer', limits.ownerCanTransfer.toString()).send();
+    await collectionEvm.methods.setLimit('ownerCanDestroy', limits.ownerCanDestroy.toString()).send();
+    await collectionEvm.methods.setLimit('transfersEnabled', limits.transfersEnabled.toString()).send();
+    
+    const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
+    expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);
+    expect(collectionSub.limits.sponsoredDataSize.unwrap().toNumber()).to.be.eq(limits.sponsoredDataSize);
+    expect(collectionSub.limits.sponsoredDataRateLimit.unwrap().asBlocks.toNumber()).to.be.eq(limits.sponsoredDataRateLimit);
+    expect(collectionSub.limits.tokenLimit.unwrap().toNumber()).to.be.eq(limits.tokenLimit);
+    expect(collectionSub.limits.sponsorTransferTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorTransferTimeout);
+    expect(collectionSub.limits.sponsorApproveTimeout.unwrap().toNumber()).to.be.eq(limits.sponsorApproveTimeout);
+    expect(collectionSub.limits.ownerCanTransfer.toHuman()).to.be.eq(limits.ownerCanTransfer);
+    expect(collectionSub.limits.ownerCanDestroy.toHuman()).to.be.eq(limits.ownerCanDestroy);
+    expect(collectionSub.limits.transfersEnabled.toHuman()).to.be.eq(limits.transfersEnabled);
+  });
+
+  itWeb3('Collection address exist', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    expect(await collectionHelper.methods
+      .isCollectionExist(collectionAddressForNonexistentCollection).call())
+      .to.be.false;
+    
+    const result = await collectionHelper.methods.create721Collection('Collection address exist', '7', '7').send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    expect(await collectionHelper.methods
+      .isCollectionExist(collectionIdAddress).call())
+      .to.be.true;
+  });
+});
+
+describe('(!negative tests!) Create collection from EVM', () => {
+  itWeb3('(!negative test!) Create collection (bad lengths)', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const helper = evmCollectionHelper(web3, owner);
+    {
+      const MAX_NAME_LENGHT = 64;
+      const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1);
+      const description = 'A';
+      const tokenPrefix = 'A';
+    
+      await expect(helper.methods
+        .create721Collection(collectionName, description, tokenPrefix)
+        .call()).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGHT);
+      
+    }
+    {  
+      const MAX_DESCRIPTION_LENGHT = 256;
+      const collectionName = 'A';
+      const description = 'A'.repeat(MAX_DESCRIPTION_LENGHT + 1);
+      const tokenPrefix = 'A';
+      await expect(helper.methods
+        .create721Collection(collectionName, description, tokenPrefix)
+        .call()).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGHT);
+    }
+    {  
+      const MAX_TOKEN_PREFIX_LENGHT = 16;
+      const collectionName = 'A';
+      const description = 'A';
+      const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGHT + 1);
+      await expect(helper.methods
+        .create721Collection(collectionName, description, tokenPrefix)
+        .call()).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGHT);
+    }
+  });
+  
+  itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
+    const owner = await createEthAccount(web3);
+    const helper = evmCollectionHelper(web3, owner);
+    const collectionName = 'A';
+    const description = 'A';
+    const tokenPrefix = 'A';
+    
+    await expect(helper.methods
+      .create721Collection(collectionName, description, tokenPrefix)
+      .call()).to.be.rejectedWith('NotSufficientFounds');
+  });
+
+  itWeb3('(!negative test!) Check owner', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const notOwner = await createEthAccount(web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    const result = await collectionHelper.methods.create721Collection('A', 'A', 'A').send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress);
+    const EXPECTED_ERROR = 'NoPermission';
+    {
+      const sponsor = await createEthAccountWithBalance(api, web3);
+      await expect(contractEvmFromNotOwner.methods
+        .ethSetSponsor(sponsor)
+        .call()).to.be.rejectedWith(EXPECTED_ERROR);
+      
+      const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);
+      await expect(sponsorCollection.methods
+        .ethConfirmSponsorship()
+        .call()).to.be.rejectedWith('Caller is not set as sponsor');
+    }
+    {
+      await expect(contractEvmFromNotOwner.methods
+        .setLimit('account_token_ownership_limit', '1000')
+        .call()).to.be.rejectedWith(EXPECTED_ERROR);
+    }
+  });
+
+  itWeb3('(!negative test!) Set limits', async ({api, web3}) => {
+    const owner = await createEthAccountWithBalance(api, web3);
+    const collectionHelper = evmCollectionHelper(web3, owner);
+    const result = await collectionHelper.methods.create721Collection('Schema collection', 'A', 'A').send();
+    const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
+    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
+    await expect(collectionEvm.methods
+      .setLimit('badLimit', 'true')
+      .call()).to.be.rejectedWith('Unknown limit "badLimit"');
+    await expect(collectionEvm.methods
+      .setLimit('sponsoredDataSize', 'badValue')
+      .call()).to.be.rejectedWith('Int value "badValue" parse error:');
+    await expect(collectionEvm.methods
+      .setLimit('ownerCanTransfer', 'badValue')
+      .call()).to.be.rejectedWith('Bool value "badValue" parse error:');
+  });
+});
\ No newline at end of file
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/fungibleAbi.json
+++ b/tests/src/eth/fungibleAbi.json
@@ -1,175 +1,206 @@
 [
-    {
-        "constant": false,
-        "inputs": [
-            {
-                "name": "_spender",
-                "type": "address"
-            },
-            {
-                "name": "_value",
-                "type": "uint256"
-            }
-        ],
-        "name": "approve",
-        "outputs": [
-            {
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "constant": true,
-        "inputs": [],
-        "name": "totalSupply",
-        "outputs": [
-            {
-                "name": "",
-                "type": "uint256"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "constant": false,
-        "inputs": [
-            {
-                "name": "_from",
-                "type": "address"
-            },
-            {
-                "name": "_to",
-                "type": "address"
-            },
-            {
-                "name": "_value",
-                "type": "uint256"
-            }
-        ],
-        "name": "transferFrom",
-        "outputs": [
-            {
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "constant": true,
-        "inputs": [
-            {
-                "name": "_owner",
-                "type": "address"
-            }
-        ],
-        "name": "balanceOf",
-        "outputs": [
-            {
-                "name": "balance",
-                "type": "uint256"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "constant": false,
-        "inputs": [
-            {
-                "name": "_to",
-                "type": "address"
-            },
-            {
-                "name": "_value",
-                "type": "uint256"
-            }
-        ],
-        "name": "transfer",
-        "outputs": [
-            {
-                "name": "",
-                "type": "bool"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "nonpayable",
-        "type": "function"
-    },
-    {
-        "constant": true,
-        "inputs": [
-            {
-                "name": "_owner",
-                "type": "address"
-            },
-            {
-                "name": "_spender",
-                "type": "address"
-            }
-        ],
-        "name": "allowance",
-        "outputs": [
-            {
-                "name": "",
-                "type": "uint256"
-            }
-        ],
-        "payable": false,
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "anonymous": false,
-        "inputs": [
-            {
-                "indexed": true,
-                "name": "owner",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "name": "spender",
-                "type": "address"
-            },
-            {
-                "indexed": false,
-                "name": "value",
-                "type": "uint256"
-            }
-        ],
-        "name": "Approval",
-        "type": "event"
-    },
-    {
-        "anonymous": false,
-        "inputs": [
-            {
-                "indexed": true,
-                "name": "from",
-                "type": "address"
-            },
-            {
-                "indexed": true,
-                "name": "to",
-                "type": "address"
-            },
-            {
-                "indexed": false,
-                "name": "value",
-                "type": "uint256"
-            }
-        ],
-        "name": "Transfer",
-        "type": "event"
-    }
-]
\ No newline at end of file
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "spender",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "spender", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "spender", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "collectionProperty",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "contractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "deleteCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "ethConfirmSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "ethSetSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "limit", "type": "string" },
+      { "internalType": "string", "name": "value", "type": "string" }
+    ],
+    "name": "setLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
deletedtests/src/eth/fungibleMetadataAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/fungibleMetadataAbi.json
+++ /dev/null
@@ -1,41 +0,0 @@
-[
-    {
-        "inputs": [],
-        "name": "name",
-        "outputs": [
-            {
-                "internalType": "string",
-                "name": "",
-                "type": "string"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "symbol",
-        "outputs": [
-            {
-                "internalType": "string",
-                "name": "",
-                "type": "string"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    },
-    {
-        "inputs": [],
-        "name": "decimals",
-        "outputs": [
-            {
-                "internalType": "uint8",
-                "name": "",
-                "type": "uint8"
-            }
-        ],
-        "stateMutability": "view",
-        "type": "function"
-    }
-]
\ No newline at end of file
deletedtests/src/eth/metadata.test.tsdiffbeforeafterboth
--- a/tests/src/eth/metadata.test.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// 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 {expect} from 'chai';
-import {createCollectionExpectSuccess} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents} from './util/helpers';
-import fungibleMetadataAbi from './fungibleMetadataAbi.json';
-import privateKey from '../substrate/privateKey';
-import {submitTransactionAsync} from '../substrate/substrate-api';
-import nonFungibleAbi from './nonFungibleAbi.json';
-
-describe('Common metadata', () => {
-  itWeb3('Returns collection name', async ({api, web3}) => {
-    const collection = await createCollectionExpectSuccess({
-      name: 'token name',
-      mode: {type: 'NFT'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS});
-    const name = await contract.methods.name().call();
-
-    expect(name).to.equal('token name');
-  });
-
-  itWeb3('Returns symbol name', async ({api, web3}) => {
-    const collection = await createCollectionExpectSuccess({
-      tokenPrefix: 'TOK',
-      mode: {type: 'NFT'},
-    });
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS});
-    const symbol = await contract.methods.symbol().call();
-
-    expect(symbol).to.equal('TOK');
-  });
-});
-
-describe('Fungible metadata', () => {
-  itWeb3('Returns fungible decimals', async ({api, web3}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'Fungible', decimalPoints: 6},
-    });
-    const caller = await createEthAccountWithBalance(api, web3);
-
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(fungibleMetadataAbi as any, address, {from: caller, ...GAS_ARGS});
-    const decimals = await contract.methods.decimals().call();
-
-    expect(+decimals).to.equal(6);
-  });
-});
-
-describe('Support ERC721Metadata', () => {
-  itWeb3('Check unsupport ERC721Metadata SchemaVersion::Unique', async ({web3, api}) => {
-    const collectionId = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-      schemaVersion: 'Unique',
-      name: 'some_name',
-      tokenPrefix: 'some_prefix',
-    });
-    const collection = await api.rpc.unique.collectionById(collectionId);
-    expect(collection.isSome).to.be.true;
-    expect(collection.unwrap().schemaVersion.toHuman()).to.be.eq('Unique');
-
-    const alice = privateKey('//Alice');
-
-    const caller = await createEthAccountWithBalance(api, web3);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, {Ethereum: caller});
-    await submitTransactionAsync(alice, changeAdminTx);
-
-    const address = collectionIdToAddress(collectionId);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
-
-    expect(await contract.methods.name().call()).to.be.eq('some_name');
-    expect(await contract.methods.symbol().call()).to.be.eq('some_prefix');
-
-    const receiver = createEthAccount(web3);
-    const nextTokenId = await contract.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-    await expect(contract.methods.mintWithTokenURI(
-      receiver,
-      nextTokenId,
-      'Test URI',
-    ).call({from: caller})).to.be.rejectedWith('Unsupported schema version! Support only ImageURL');
-
-    await expect(contract.methods.mintBulkWithTokenURI(
-      receiver,
-      [
-        [nextTokenId, 'Test URI 0'],
-        [+nextTokenId + 1, 'Test URI 1'],
-        [+nextTokenId + 2, 'Test URI 2'],
-      ],
-    ).call({from: caller})).to.be.rejectedWith('Unsupported schema version! Support only ImageURL');
-  });
-
-  itWeb3('Check support ERC721Metadata for SchemaVersion::ImageURL', async ({web3, api}) => {
-    const collectionId = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-      name: 'some_name',
-      tokenPrefix: 'some_prefix',
-    });
-    const collection = await api.rpc.unique.collectionById(collectionId);
-    expect(collection.isSome).to.be.true;
-    expect(collection.unwrap().schemaVersion.toHuman()).to.be.eq('ImageURL');
-
-    const alice = privateKey('//Alice');
-
-    const caller = await createEthAccountWithBalance(api, web3);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, {Ethereum: caller});
-    await submitTransactionAsync(alice, changeAdminTx);
-
-    const address = collectionIdToAddress(collectionId);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
-    
-    expect(await contract.methods.name().call()).to.be.eq('some_name');
-    expect(await contract.methods.symbol().call()).to.be.eq('some_prefix');
-
-    const receiver = createEthAccount(web3);
-    { // mintWithTokenURI
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      const result = await contract.methods.mintWithTokenURI(
-        receiver,
-        nextTokenId,
-        'Test URI',
-      ).send({from: caller});
-      const events = normalizeEvents(result.events);
-  
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: nextTokenId,
-          },
-        },
-      ]);
-  
-      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-    }
-
-    { // mintBulkWithTokenURI
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('2');
-      const result = await contract.methods.mintBulkWithTokenURI(
-        receiver,
-        [
-          [nextTokenId, 'Test URI 0'],
-          [+nextTokenId + 1, 'Test URI 1'],
-          [+nextTokenId + 2, 'Test URI 2'],
-        ],
-      ).send({from: caller});
-      const events = normalizeEvents(result.events);
-
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: nextTokenId,
-          },
-        },
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 1),
-          },
-        },
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: String(+nextTokenId + 2),
-          },
-        },
-      ]);
-
-      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
-      expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
-      expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
-    }
-  });
-});
-
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -16,7 +16,7 @@
 
 import privateKey from '../substrate/privateKey';
 import {approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';
-import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelper, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import {expect} from 'chai';
 import {submitTransactionAsync} from '../substrate/substrate-api';
@@ -75,45 +75,46 @@
 
 describe('NFT: Plain calls', () => {
   itWeb3('Can perform mint()', async ({web3, api}) => {
-    const collection = await createCollectionExpectSuccess({
-      mode: {type: 'NFT'},
-    });
-    const alice = privateKey('//Alice');
-
-    const caller = await createEthAccountWithBalance(api, web3);
-    const changeAdminTx = api.tx.unique.addCollectionAdmin(collection, {Ethereum: caller});
-    await submitTransactionAsync(alice, changeAdminTx);
+    const owner = await createEthAccountWithBalance(api, web3);
+    const helper = evmCollectionHelper(web3, owner);
+    let result = await helper.methods.create721Collection('Mint collection', '6', '6').send();
+    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const receiver = createEthAccount(web3);
+    const contract = evmCollection(web3, owner, collectionIdAddress);
+    const nextTokenId = await contract.methods.nextTokenId().call();
 
-    const address = collectionIdToAddress(collection);
-    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    expect(nextTokenId).to.be.equal('1');
+    result = await contract.methods.mintWithTokenURI(
+      receiver,
+      nextTokenId,
+      'Test URI',
+    ).send();
 
-    {
-      const nextTokenId = await contract.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      const result = await contract.methods.mintWithTokenURI(
-        receiver,
-        nextTokenId,
-        'Test URI',
-      ).send({from: caller});
-      const events = normalizeEvents(result.events);
+    const events = normalizeEvents(result.events);
+    const address = collectionIdToAddress(collectionId);
 
-      expect(events).to.be.deep.equal([
-        {
-          address,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: receiver,
-            tokenId: nextTokenId,
-          },
+    expect(events).to.be.deep.equal([
+      {
+        address,
+        event: 'Transfer',
+        args: {
+          from: '0x0000000000000000000000000000000000000000',
+          to: receiver,
+          tokenId: nextTokenId,
         },
-      ]);
+      },
+    ]);
+
+    expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
 
-      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-    }
+    // TODO: this wont work right now, need release 919000 first
+    // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send();
+    // const tokenUri = await contract.methods.tokenURI(nextTokenId).call();
+    // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);
   });
-  itWeb3('Can perform mintBulk()', async ({web3, api}) => {
+
+  //TODO: CORE-302 add eth methods
+  itWeb3.skip('Can perform mintBulk()', async ({web3, api}) => {
     const collection = await createCollectionExpectSuccess({
       mode: {type: 'NFT'},
     });
@@ -539,3 +540,33 @@
     ]);
   });
 });
+
+describe('Common metadata', () => {
+  itWeb3('Returns collection name', async ({api, web3}) => {
+    const collection = await createCollectionExpectSuccess({
+      name: 'token name',
+      mode: {type: 'NFT'},
+    });
+    const caller = await createEthAccountWithBalance(api, web3);
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const name = await contract.methods.name().call();
+
+    expect(name).to.equal('token name');
+  });
+
+  itWeb3('Returns symbol name', async ({api, web3}) => {
+    const collection = await createCollectionExpectSuccess({
+      tokenPrefix: 'TOK',
+      mode: {type: 'NFT'},
+    });
+    const caller = await createEthAccountWithBalance(api, web3);
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+    const symbol = await contract.methods.symbol().call();
+
+    expect(symbol).to.equal('TOK');
+  });
+});
\ No newline at end of file
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -1,738 +1,431 @@
 [
-	{
-		"anonymous": false,
-		"inputs": [
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "owner",
-				"type": "address"
-			},
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "approved",
-				"type": "address"
-			},
-			{
-				"indexed": true,
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "Approval",
-		"type": "event"
-	},
-	{
-		"anonymous": false,
-		"inputs": [
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "owner",
-				"type": "address"
-			},
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "operator",
-				"type": "address"
-			},
-			{
-				"indexed": false,
-				"internalType": "bool",
-				"name": "approved",
-				"type": "bool"
-			}
-		],
-		"name": "ApprovalForAll",
-		"type": "event"
-	},
-	{
-		"anonymous": false,
-		"inputs": [],
-		"name": "MintingFinished",
-		"type": "event"
-	},
-	{
-		"anonymous": false,
-		"inputs": [
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "from",
-				"type": "address"
-			},
-			{
-				"indexed": true,
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"indexed": true,
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "Transfer",
-		"type": "event"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "approved",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "approve",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "owner",
-				"type": "address"
-			}
-		],
-		"name": "balanceOf",
-		"outputs": [
-			{
-				"internalType": "uint256",
-				"name": "",
-				"type": "uint256"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "burn",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "from",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "burnFrom",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			}
-		],
-		"name": "collectionProperty",
-		"outputs": [
-			{
-				"internalType": "bytes",
-				"name": "",
-				"type": "bytes"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			}
-		],
-		"name": "deleteCollectionProperty",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			},
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			}
-		],
-		"name": "deleteProperty",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "finishMinting",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "getApproved",
-		"outputs": [
-			{
-				"internalType": "address",
-				"name": "",
-				"type": "address"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "owner",
-				"type": "address"
-			},
-			{
-				"internalType": "address",
-				"name": "operator",
-				"type": "address"
-			}
-		],
-		"name": "isApprovedForAll",
-		"outputs": [
-			{
-				"internalType": "address",
-				"name": "",
-				"type": "address"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "mint",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256[]",
-				"name": "tokenIds",
-				"type": "uint256[]"
-			}
-		],
-		"name": "mintBulk",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"components": [
-					{
-						"internalType": "uint256",
-						"name": "field_0",
-						"type": "uint256"
-					},
-					{
-						"internalType": "string",
-						"name": "field_1",
-						"type": "string"
-					}
-				],
-				"internalType": "struct Tuple0[]",
-				"name": "tokens",
-				"type": "tuple[]"
-			}
-		],
-		"name": "mintBulkWithTokenURI",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			},
-			{
-				"internalType": "string",
-				"name": "tokenUri",
-				"type": "string"
-			}
-		],
-		"name": "mintWithTokenURI",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "mintingFinished",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "name",
-		"outputs": [
-			{
-				"internalType": "string",
-				"name": "",
-				"type": "string"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "nextTokenId",
-		"outputs": [
-			{
-				"internalType": "uint256",
-				"name": "",
-				"type": "uint256"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "ownerOf",
-		"outputs": [
-			{
-				"internalType": "address",
-				"name": "",
-				"type": "address"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			},
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			}
-		],
-		"name": "property",
-		"outputs": [
-			{
-				"internalType": "bytes",
-				"name": "",
-				"type": "bytes"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "from",
-				"type": "address"
-			},
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "safeTransferFrom",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "from",
-				"type": "address"
-			},
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			},
-			{
-				"internalType": "bytes",
-				"name": "data",
-				"type": "bytes"
-			}
-		],
-		"name": "safeTransferFromWithData",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "operator",
-				"type": "address"
-			},
-			{
-				"internalType": "bool",
-				"name": "approved",
-				"type": "bool"
-			}
-		],
-		"name": "setApprovalForAll",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			},
-			{
-				"internalType": "bytes",
-				"name": "value",
-				"type": "bytes"
-			}
-		],
-		"name": "setCollectionProperty",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			},
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			},
-			{
-				"internalType": "bytes",
-				"name": "value",
-				"type": "bytes"
-			}
-		],
-		"name": "setProperty",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "string",
-				"name": "key",
-				"type": "string"
-			},
-			{
-				"internalType": "bool",
-				"name": "isMutable",
-				"type": "bool"
-			},
-			{
-				"internalType": "bool",
-				"name": "collectionAdmin",
-				"type": "bool"
-			},
-			{
-				"internalType": "bool",
-				"name": "tokenOwner",
-				"type": "bool"
-			}
-		],
-		"name": "setTokenPropertyPermission",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "bytes4",
-				"name": "interfaceID",
-				"type": "bytes4"
-			}
-		],
-		"name": "supportsInterface",
-		"outputs": [
-			{
-				"internalType": "bool",
-				"name": "",
-				"type": "bool"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "symbol",
-		"outputs": [
-			{
-				"internalType": "string",
-				"name": "",
-				"type": "string"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "index",
-				"type": "uint256"
-			}
-		],
-		"name": "tokenByIndex",
-		"outputs": [
-			{
-				"internalType": "uint256",
-				"name": "",
-				"type": "uint256"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "owner",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "index",
-				"type": "uint256"
-			}
-		],
-		"name": "tokenOfOwnerByIndex",
-		"outputs": [
-			{
-				"internalType": "uint256",
-				"name": "",
-				"type": "uint256"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "tokenURI",
-		"outputs": [
-			{
-				"internalType": "string",
-				"name": "",
-				"type": "string"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [],
-		"name": "totalSupply",
-		"outputs": [
-			{
-				"internalType": "uint256",
-				"name": "",
-				"type": "uint256"
-			}
-		],
-		"stateMutability": "view",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "transfer",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	},
-	{
-		"inputs": [
-			{
-				"internalType": "address",
-				"name": "from",
-				"type": "address"
-			},
-			{
-				"internalType": "address",
-				"name": "to",
-				"type": "address"
-			},
-			{
-				"internalType": "uint256",
-				"name": "tokenId",
-				"type": "uint256"
-			}
-		],
-		"name": "transferFrom",
-		"outputs": [],
-		"stateMutability": "nonpayable",
-		"type": "function"
-	}
-]
\ No newline at end of file
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "approved",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "operator",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "bool",
+        "name": "approved",
+        "type": "bool"
+      }
+    ],
+    "name": "ApprovalForAll",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [],
+    "name": "MintingFinished",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "approved", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burn",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "collectionProperty",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "contractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "deleteCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "deleteProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "ethConfirmSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "ethSetSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "finishMinting",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "getApproved",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "operator", "type": "address" }
+    ],
+    "name": "isApprovedForAll",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "mint",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
+    ],
+    "name": "mintBulk",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      {
+        "components": [
+          { "internalType": "uint256", "name": "field_0", "type": "uint256" },
+          { "internalType": "string", "name": "field_1", "type": "string" }
+        ],
+        "internalType": "struct Tuple0[]",
+        "name": "tokens",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulkWithTokenURI",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "tokenUri", "type": "string" }
+    ],
+    "name": "mintWithTokenURI",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "mintingFinished",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "nextTokenId",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "ownerOf",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "property",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "safeTransferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "bytes", "name": "data", "type": "bytes" }
+    ],
+    "name": "safeTransferFromWithData",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "operator", "type": "address" },
+      { "internalType": "bool", "name": "approved", "type": "bool" }
+    ],
+    "name": "setApprovalForAll",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "limit", "type": "string" },
+      { "internalType": "string", "name": "value", "type": "string" }
+    ],
+    "name": "setLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bool", "name": "isMutable", "type": "bool" },
+      { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },
+      { "internalType": "bool", "name": "tokenOwner", "type": "bool" }
+    ],
+    "name": "setTokenPropertyPermission",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenOfOwnerByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "tokenURI",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -88,7 +88,8 @@
 });
 
 describe('NFT (Via EVM proxy): Plain calls', () => {
-  itWeb3('Can perform mint()', async ({web3, api}) => {
+  //TODO: CORE-302 add eth methods
+  itWeb3.skip('Can perform mint()', async ({web3, api}) => {
     const collection = await createCollectionExpectSuccess({
       mode: {type: 'NFT'},
     });
@@ -127,7 +128,9 @@
       expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
     }
   });
-  itWeb3('Can perform mintBulk()', async ({web3, api}) => {
+  
+  //TODO: CORE-302 add eth methods
+  itWeb3.skip('Can perform mintBulk()', async ({web3, api}) => {
     const collection = await createCollectionExpectSuccess({
       mode: {type: 'NFT'},
     });
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/util/contractHelpersAbi.json
+++ b/tests/src/eth/util/contractHelpersAbi.json
@@ -1,216 +1,161 @@
 [
-    {
-        "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": [
+      {
+        "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"
+  }
 ]
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -23,11 +23,13 @@
 import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api';
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect} from 'chai';
-import {CrossAccountId, getGenericResult, UNIQUE} from '../../util/helpers';
+import {CrossAccountId, getDetailedCollectionInfo, getGenericResult, UNIQUE} from '../../util/helpers';
 import * as solc from 'solc';
 import config from '../../config';
 import privateKey from '../../substrate/privateKey';
 import contractHelpersAbi from './contractHelpersAbi.json';
+import nonFungibleAbi from '../nonFungibleAbi.json';
+import collectionHelperAbi from '../collectionHelperAbi.json';
 import getBalance from '../../substrate/get-balance';
 import waitNewBlocks from '../../substrate/wait-new-blocks';
 
@@ -66,12 +68,30 @@
   ];
 }
 
+export async function getCollectionAddressFromResult(api: ApiPromise, result: any) {
+  const collectionIdAddress = normalizeAddress(result.events[0].raw.topics[2]);
+  const collectionId = collectionIdFromAddress(collectionIdAddress);  
+  const collection = (await getDetailedCollectionInfo(api, collectionId))!;
+  return {collectionIdAddress, collectionId, collection};
+}
+
 export function collectionIdToAddress(collection: number): string {
   const buf = Buffer.from([0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,
     ...encodeIntBE(collection),
   ]);
   return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));
 }
+export function collectionIdFromAddress(address: string): number {
+  if (!address.startsWith('0x'))
+    throw 'address not starts with "0x"';
+  if (address.length > 42)
+    throw 'address length is more than 20 bytes';
+  return Number('0x' + address.substring(address.length - 8));
+}
+  
+export function normalizeAddress(address: string): string {
+  return '0x' + address.substring(address.length - 40);
+}
 
 export function tokenIdToAddress(collection: number, token: number): string {
   const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0,
@@ -271,6 +291,26 @@
   return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});
 }
 
+/** 
+ * evm collection helper
+ * @param web3 
+ * @param caller - eth address
+ * @returns 
+ */
+export function evmCollectionHelper(web3: Web3, caller: string) {
+  return new web3.eth.Contract(collectionHelperAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS});
+}
+
+/** 
+ * evm collection
+ * @param web3 
+ * @param caller - eth address
+ * @returns 
+ */
+export function evmCollection(web3: Web3, caller: string, collection: string) {
+  return new web3.eth.Contract(nonFungibleAbi as any, collection, {from: caller, ...GAS_ARGS});
+}
+
 /**
  * Execute ethereum method call using substrate account
  * @param to target contract
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -1,7 +1,6 @@
 // Auto-generated via `yarn polkadot-types-from-defs`, do not edit
 /* eslint-disable */
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructsBaseInfo, PhantomTypeUpDataStructsCollectionInfo, PhantomTypeUpDataStructsNftChild, PhantomTypeUpDataStructsNftInfo, PhantomTypeUpDataStructsPartType, PhantomTypeUpDataStructsPropertyInfo, PhantomTypeUpDataStructsResourceInfo, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTheme, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './unique';
 import type { Data, StorageKey } from '@polkadot/types';
 import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec';
 import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
@@ -291,27 +290,6 @@
     CoreOccupied: CoreOccupied;
     CrateVersion: CrateVersion;
     CreatedBlock: CreatedBlock;
-    CumulusPalletDmpQueueCall: CumulusPalletDmpQueueCall;
-    CumulusPalletDmpQueueConfigData: CumulusPalletDmpQueueConfigData;
-    CumulusPalletDmpQueueError: CumulusPalletDmpQueueError;
-    CumulusPalletDmpQueueEvent: CumulusPalletDmpQueueEvent;
-    CumulusPalletDmpQueuePageIndexData: CumulusPalletDmpQueuePageIndexData;
-    CumulusPalletParachainSystemCall: CumulusPalletParachainSystemCall;
-    CumulusPalletParachainSystemError: CumulusPalletParachainSystemError;
-    CumulusPalletParachainSystemEvent: CumulusPalletParachainSystemEvent;
-    CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot;
-    CumulusPalletXcmCall: CumulusPalletXcmCall;
-    CumulusPalletXcmError: CumulusPalletXcmError;
-    CumulusPalletXcmEvent: CumulusPalletXcmEvent;
-    CumulusPalletXcmpQueueCall: CumulusPalletXcmpQueueCall;
-    CumulusPalletXcmpQueueError: CumulusPalletXcmpQueueError;
-    CumulusPalletXcmpQueueEvent: CumulusPalletXcmpQueueEvent;
-    CumulusPalletXcmpQueueInboundChannelDetails: CumulusPalletXcmpQueueInboundChannelDetails;
-    CumulusPalletXcmpQueueInboundState: CumulusPalletXcmpQueueInboundState;
-    CumulusPalletXcmpQueueOutboundChannelDetails: CumulusPalletXcmpQueueOutboundChannelDetails;
-    CumulusPalletXcmpQueueOutboundState: CumulusPalletXcmpQueueOutboundState;
-    CumulusPalletXcmpQueueQueueConfigData: CumulusPalletXcmpQueueQueueConfigData;
-    CumulusPrimitivesParachainInherentParachainInherentData: CumulusPrimitivesParachainInherentParachainInherentData;
     Data: Data;
     DeferredOffenceOf: DeferredOffenceOf;
     DefunctVoter: DefunctVoter;
@@ -378,25 +356,11 @@
     EthAddress: EthAddress;
     EthBlock: EthBlock;
     EthBloom: EthBloom;
-    EthbloomBloom: EthbloomBloom;
     EthCallRequest: EthCallRequest;
     EthereumAccountId: EthereumAccountId;
     EthereumAddress: EthereumAddress;
-    EthereumBlock: EthereumBlock;
-    EthereumHeader: EthereumHeader;
-    EthereumLog: EthereumLog;
     EthereumLookupSource: EthereumLookupSource;
-    EthereumReceiptEip658ReceiptData: EthereumReceiptEip658ReceiptData;
-    EthereumReceiptReceiptV3: EthereumReceiptReceiptV3;
     EthereumSignature: EthereumSignature;
-    EthereumTransactionAccessListItem: EthereumTransactionAccessListItem;
-    EthereumTransactionEip1559Transaction: EthereumTransactionEip1559Transaction;
-    EthereumTransactionEip2930Transaction: EthereumTransactionEip2930Transaction;
-    EthereumTransactionLegacyTransaction: EthereumTransactionLegacyTransaction;
-    EthereumTransactionTransactionAction: EthereumTransactionTransactionAction;
-    EthereumTransactionTransactionSignature: EthereumTransactionTransactionSignature;
-    EthereumTransactionTransactionV2: EthereumTransactionTransactionV2;
-    EthereumTypesHashH64: EthereumTypesHashH64;
     EthFilter: EthFilter;
     EthFilterAddress: EthFilterAddress;
     EthFilterChanges: EthFilterChanges;
@@ -433,11 +397,6 @@
     EventMetadataV9: EventMetadataV9;
     EventRecord: EventRecord;
     EvmAccount: EvmAccount;
-    EvmCoreErrorExitError: EvmCoreErrorExitError;
-    EvmCoreErrorExitFatal: EvmCoreErrorExitFatal;
-    EvmCoreErrorExitReason: EvmCoreErrorExitReason;
-    EvmCoreErrorExitRevert: EvmCoreErrorExitRevert;
-    EvmCoreErrorExitSucceed: EvmCoreErrorExitSucceed;
     EvmLog: EvmLog;
     EvmVicinity: EvmVicinity;
     ExecReturnValue: ExecReturnValue;
@@ -476,31 +435,6 @@
     Forcing: Forcing;
     ForkTreePendingChange: ForkTreePendingChange;
     ForkTreePendingChangeNode: ForkTreePendingChangeNode;
-    FpRpcTransactionStatus: FpRpcTransactionStatus;
-    FrameSupportPalletId: FrameSupportPalletId;
-    FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
-    FrameSupportWeightsDispatchClass: FrameSupportWeightsDispatchClass;
-    FrameSupportWeightsDispatchInfo: FrameSupportWeightsDispatchInfo;
-    FrameSupportWeightsPays: FrameSupportWeightsPays;
-    FrameSupportWeightsPerDispatchClassU32: FrameSupportWeightsPerDispatchClassU32;
-    FrameSupportWeightsPerDispatchClassU64: FrameSupportWeightsPerDispatchClassU64;
-    FrameSupportWeightsPerDispatchClassWeightsPerClass: FrameSupportWeightsPerDispatchClassWeightsPerClass;
-    FrameSupportWeightsRuntimeDbWeight: FrameSupportWeightsRuntimeDbWeight;
-    FrameSupportWeightsWeightToFeeCoefficient: FrameSupportWeightsWeightToFeeCoefficient;
-    FrameSystemAccountInfo: FrameSystemAccountInfo;
-    FrameSystemCall: FrameSystemCall;
-    FrameSystemError: FrameSystemError;
-    FrameSystemEvent: FrameSystemEvent;
-    FrameSystemEventRecord: FrameSystemEventRecord;
-    FrameSystemExtensionsCheckGenesis: FrameSystemExtensionsCheckGenesis;
-    FrameSystemExtensionsCheckNonce: FrameSystemExtensionsCheckNonce;
-    FrameSystemExtensionsCheckSpecVersion: FrameSystemExtensionsCheckSpecVersion;
-    FrameSystemExtensionsCheckWeight: FrameSystemExtensionsCheckWeight;
-    FrameSystemLastRuntimeUpgradeInfo: FrameSystemLastRuntimeUpgradeInfo;
-    FrameSystemLimitsBlockLength: FrameSystemLimitsBlockLength;
-    FrameSystemLimitsBlockWeights: FrameSystemLimitsBlockWeights;
-    FrameSystemLimitsWeightsPerClass: FrameSystemLimitsWeightsPerClass;
-    FrameSystemPhase: FrameSystemPhase;
     FullIdentification: FullIdentification;
     FunctionArgumentMetadataLatest: FunctionArgumentMetadataLatest;
     FunctionArgumentMetadataV10: FunctionArgumentMetadataV10;
@@ -716,7 +650,6 @@
     OffchainAccuracyCompact: OffchainAccuracyCompact;
     OffenceDetails: OffenceDetails;
     Offender: Offender;
-    OpalRuntimeRuntime: OpalRuntimeRuntime;
     OpaqueCall: OpaqueCall;
     OpaqueMultiaddr: OpaqueMultiaddr;
     OpaqueNetworkState: OpaqueNetworkState;
@@ -732,10 +665,6 @@
     OriginKindV0: OriginKindV0;
     OriginKindV1: OriginKindV1;
     OriginKindV2: OriginKindV2;
-    OrmlVestingModuleCall: OrmlVestingModuleCall;
-    OrmlVestingModuleError: OrmlVestingModuleError;
-    OrmlVestingModuleEvent: OrmlVestingModuleEvent;
-    OrmlVestingVestingSchedule: OrmlVestingVestingSchedule;
     OutboundHrmpMessage: OutboundHrmpMessage;
     OutboundLaneData: OutboundLaneData;
     OutboundMessageFee: OutboundMessageFee;
@@ -746,76 +675,21 @@
     Owner: Owner;
     PageCounter: PageCounter;
     PageIndexData: PageIndexData;
-    PalletBalancesAccountData: PalletBalancesAccountData;
-    PalletBalancesBalanceLock: PalletBalancesBalanceLock;
-    PalletBalancesCall: PalletBalancesCall;
-    PalletBalancesError: PalletBalancesError;
-    PalletBalancesEvent: PalletBalancesEvent;
-    PalletBalancesReasons: PalletBalancesReasons;
-    PalletBalancesReleases: PalletBalancesReleases;
-    PalletBalancesReserveData: PalletBalancesReserveData;
     PalletCallMetadataLatest: PalletCallMetadataLatest;
     PalletCallMetadataV14: PalletCallMetadataV14;
-    PalletCommonError: PalletCommonError;
-    PalletCommonEvent: PalletCommonEvent;
     PalletConstantMetadataLatest: PalletConstantMetadataLatest;
     PalletConstantMetadataV14: PalletConstantMetadataV14;
     PalletErrorMetadataLatest: PalletErrorMetadataLatest;
     PalletErrorMetadataV14: PalletErrorMetadataV14;
-    PalletEthereumCall: PalletEthereumCall;
-    PalletEthereumError: PalletEthereumError;
-    PalletEthereumEvent: PalletEthereumEvent;
-    PalletEthereumFakeTransactionFinalizer: PalletEthereumFakeTransactionFinalizer;
     PalletEventMetadataLatest: PalletEventMetadataLatest;
     PalletEventMetadataV14: PalletEventMetadataV14;
-    PalletEvmAccountBasicCrossAccountIdRepr: PalletEvmAccountBasicCrossAccountIdRepr;
-    PalletEvmCall: PalletEvmCall;
-    PalletEvmCoderSubstrateError: PalletEvmCoderSubstrateError;
-    PalletEvmContractHelpersError: PalletEvmContractHelpersError;
-    PalletEvmContractHelpersSponsoringModeT: PalletEvmContractHelpersSponsoringModeT;
-    PalletEvmError: PalletEvmError;
-    PalletEvmEvent: PalletEvmEvent;
-    PalletEvmMigrationCall: PalletEvmMigrationCall;
-    PalletEvmMigrationError: PalletEvmMigrationError;
-    PalletFungibleError: PalletFungibleError;
     PalletId: PalletId;
-    PalletInflationCall: PalletInflationCall;
     PalletMetadataLatest: PalletMetadataLatest;
     PalletMetadataV14: PalletMetadataV14;
-    PalletNonfungibleError: PalletNonfungibleError;
-    PalletNonfungibleItemData: PalletNonfungibleItemData;
-    PalletRefungibleError: PalletRefungibleError;
-    PalletRefungibleItemData: PalletRefungibleItemData;
-    PalletRmrkCoreCall: PalletRmrkCoreCall;
-    PalletRmrkCoreError: PalletRmrkCoreError;
-    PalletRmrkCoreEvent: PalletRmrkCoreEvent;
-    PalletRmrkEquipCall: PalletRmrkEquipCall;
-    PalletRmrkEquipError: PalletRmrkEquipError;
-    PalletRmrkEquipEvent: PalletRmrkEquipEvent;
     PalletsOrigin: PalletsOrigin;
     PalletStorageMetadataLatest: PalletStorageMetadataLatest;
     PalletStorageMetadataV14: PalletStorageMetadataV14;
-    PalletStructureCall: PalletStructureCall;
-    PalletStructureError: PalletStructureError;
-    PalletStructureEvent: PalletStructureEvent;
-    PalletSudoCall: PalletSudoCall;
-    PalletSudoError: PalletSudoError;
-    PalletSudoEvent: PalletSudoEvent;
-    PalletTemplateTransactionPaymentCall: PalletTemplateTransactionPaymentCall;
-    PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment;
-    PalletTimestampCall: PalletTimestampCall;
-    PalletTransactionPaymentReleases: PalletTransactionPaymentReleases;
-    PalletTreasuryCall: PalletTreasuryCall;
-    PalletTreasuryError: PalletTreasuryError;
-    PalletTreasuryEvent: PalletTreasuryEvent;
-    PalletTreasuryProposal: PalletTreasuryProposal;
-    PalletUniqueCall: PalletUniqueCall;
-    PalletUniqueError: PalletUniqueError;
-    PalletUniqueRawEvent: PalletUniqueRawEvent;
     PalletVersion: PalletVersion;
-    PalletXcmCall: PalletXcmCall;
-    PalletXcmError: PalletXcmError;
-    PalletXcmEvent: PalletXcmEvent;
     ParachainDispatchOrigin: ParachainDispatchOrigin;
     ParachainInherentData: ParachainInherentData;
     ParachainProposal: ParachainProposal;
@@ -855,27 +729,9 @@
     PerU16: PerU16;
     Phantom: Phantom;
     PhantomData: PhantomData;
-    PhantomTypeUpDataStructsBaseInfo: PhantomTypeUpDataStructsBaseInfo;
-    PhantomTypeUpDataStructsCollectionInfo: PhantomTypeUpDataStructsCollectionInfo;
-    PhantomTypeUpDataStructsNftChild: PhantomTypeUpDataStructsNftChild;
-    PhantomTypeUpDataStructsNftInfo: PhantomTypeUpDataStructsNftInfo;
-    PhantomTypeUpDataStructsPartType: PhantomTypeUpDataStructsPartType;
-    PhantomTypeUpDataStructsPropertyInfo: PhantomTypeUpDataStructsPropertyInfo;
-    PhantomTypeUpDataStructsResourceInfo: PhantomTypeUpDataStructsResourceInfo;
-    PhantomTypeUpDataStructsRpcCollection: PhantomTypeUpDataStructsRpcCollection;
-    PhantomTypeUpDataStructsTheme: PhantomTypeUpDataStructsTheme;
-    PhantomTypeUpDataStructsTokenData: PhantomTypeUpDataStructsTokenData;
     Phase: Phase;
     PhragmenScore: PhragmenScore;
     Points: Points;
-    PolkadotCorePrimitivesInboundDownwardMessage: PolkadotCorePrimitivesInboundDownwardMessage;
-    PolkadotCorePrimitivesInboundHrmpMessage: PolkadotCorePrimitivesInboundHrmpMessage;
-    PolkadotCorePrimitivesOutboundHrmpMessage: PolkadotCorePrimitivesOutboundHrmpMessage;
-    PolkadotParachainPrimitivesXcmpMessageFormat: PolkadotParachainPrimitivesXcmpMessageFormat;
-    PolkadotPrimitivesV2AbridgedHostConfiguration: PolkadotPrimitivesV2AbridgedHostConfiguration;
-    PolkadotPrimitivesV2AbridgedHrmpChannel: PolkadotPrimitivesV2AbridgedHrmpChannel;
-    PolkadotPrimitivesV2PersistedValidationData: PolkadotPrimitivesV2PersistedValidationData;
-    PolkadotPrimitivesV2UpgradeRestriction: PolkadotPrimitivesV2UpgradeRestriction;
     PortableType: PortableType;
     PortableTypeV14: PortableTypeV14;
     Precommits: Precommits;
@@ -1071,20 +927,7 @@
     SolutionSupports: SolutionSupports;
     SpanIndex: SpanIndex;
     SpanRecord: SpanRecord;
-    SpCoreEcdsaSignature: SpCoreEcdsaSignature;
-    SpCoreEd25519Signature: SpCoreEd25519Signature;
-    SpCoreSr25519Signature: SpCoreSr25519Signature;
     SpecVersion: SpecVersion;
-    SpRuntimeArithmeticError: SpRuntimeArithmeticError;
-    SpRuntimeDigest: SpRuntimeDigest;
-    SpRuntimeDigestDigestItem: SpRuntimeDigestDigestItem;
-    SpRuntimeDispatchError: SpRuntimeDispatchError;
-    SpRuntimeModuleError: SpRuntimeModuleError;
-    SpRuntimeMultiSignature: SpRuntimeMultiSignature;
-    SpRuntimeTokenError: SpRuntimeTokenError;
-    SpRuntimeTransactionalError: SpRuntimeTransactionalError;
-    SpTrieStorageProof: SpTrieStorageProof;
-    SpVersionRuntimeVersion: SpVersionRuntimeVersion;
     Sr25519Signature: Sr25519Signature;
     StakingLedger: StakingLedger;
     StakingLedgerTo223: StakingLedgerTo223;
@@ -1181,50 +1024,6 @@
     UnlockChunk: UnlockChunk;
     UnrewardedRelayer: UnrewardedRelayer;
     UnrewardedRelayersState: UnrewardedRelayersState;
-    UpDataStructsAccessMode: UpDataStructsAccessMode;
-    UpDataStructsCollection: UpDataStructsCollection;
-    UpDataStructsCollectionField: UpDataStructsCollectionField;
-    UpDataStructsCollectionLimits: UpDataStructsCollectionLimits;
-    UpDataStructsCollectionMode: UpDataStructsCollectionMode;
-    UpDataStructsCollectionStats: UpDataStructsCollectionStats;
-    UpDataStructsCreateCollectionData: UpDataStructsCreateCollectionData;
-    UpDataStructsCreateFungibleData: UpDataStructsCreateFungibleData;
-    UpDataStructsCreateItemData: UpDataStructsCreateItemData;
-    UpDataStructsCreateItemExData: UpDataStructsCreateItemExData;
-    UpDataStructsCreateNftData: UpDataStructsCreateNftData;
-    UpDataStructsCreateNftExData: UpDataStructsCreateNftExData;
-    UpDataStructsCreateReFungibleData: UpDataStructsCreateReFungibleData;
-    UpDataStructsCreateRefungibleExData: UpDataStructsCreateRefungibleExData;
-    UpDataStructsNestingRule: UpDataStructsNestingRule;
-    UpDataStructsProperties: UpDataStructsProperties;
-    UpDataStructsPropertiesMapBoundedVec: UpDataStructsPropertiesMapBoundedVec;
-    UpDataStructsPropertiesMapPropertyPermission: UpDataStructsPropertiesMapPropertyPermission;
-    UpDataStructsProperty: UpDataStructsProperty;
-    UpDataStructsPropertyKeyPermission: UpDataStructsPropertyKeyPermission;
-    UpDataStructsPropertyPermission: UpDataStructsPropertyPermission;
-    UpDataStructsRmrkAccountIdOrCollectionNftTuple: UpDataStructsRmrkAccountIdOrCollectionNftTuple;
-    UpDataStructsRmrkBaseInfo: UpDataStructsRmrkBaseInfo;
-    UpDataStructsRmrkBasicResource: UpDataStructsRmrkBasicResource;
-    UpDataStructsRmrkCollectionInfo: UpDataStructsRmrkCollectionInfo;
-    UpDataStructsRmrkComposableResource: UpDataStructsRmrkComposableResource;
-    UpDataStructsRmrkEquippableList: UpDataStructsRmrkEquippableList;
-    UpDataStructsRmrkFixedPart: UpDataStructsRmrkFixedPart;
-    UpDataStructsRmrkNftChild: UpDataStructsRmrkNftChild;
-    UpDataStructsRmrkNftInfo: UpDataStructsRmrkNftInfo;
-    UpDataStructsRmrkPartType: UpDataStructsRmrkPartType;
-    UpDataStructsRmrkPropertyInfo: UpDataStructsRmrkPropertyInfo;
-    UpDataStructsRmrkResourceInfo: UpDataStructsRmrkResourceInfo;
-    UpDataStructsRmrkResourceTypes: UpDataStructsRmrkResourceTypes;
-    UpDataStructsRmrkRoyaltyInfo: UpDataStructsRmrkRoyaltyInfo;
-    UpDataStructsRmrkSlotPart: UpDataStructsRmrkSlotPart;
-    UpDataStructsRmrkSlotResource: UpDataStructsRmrkSlotResource;
-    UpDataStructsRmrkTheme: UpDataStructsRmrkTheme;
-    UpDataStructsRmrkThemeProperty: UpDataStructsRmrkThemeProperty;
-    UpDataStructsRpcCollection: UpDataStructsRpcCollection;
-    UpDataStructsSchemaVersion: UpDataStructsSchemaVersion;
-    UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
-    UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
-    UpDataStructsTokenData: UpDataStructsTokenData;
     UpgradeGoAhead: UpgradeGoAhead;
     UpgradeRestriction: UpgradeRestriction;
     UpwardMessage: UpwardMessage;
@@ -1296,7 +1095,6 @@
     WithdrawReasons: WithdrawReasons;
     Xcm: Xcm;
     XcmAssetId: XcmAssetId;
-    XcmDoubleEncoded: XcmDoubleEncoded;
     XcmError: XcmError;
     XcmErrorV0: XcmErrorV0;
     XcmErrorV1: XcmErrorV1;
@@ -1309,41 +1107,8 @@
     XcmOriginKind: XcmOriginKind;
     XcmpMessageFormat: XcmpMessageFormat;
     XcmV0: XcmV0;
-    XcmV0Junction: XcmV0Junction;
-    XcmV0JunctionBodyId: XcmV0JunctionBodyId;
-    XcmV0JunctionBodyPart: XcmV0JunctionBodyPart;
-    XcmV0JunctionNetworkId: XcmV0JunctionNetworkId;
-    XcmV0MultiAsset: XcmV0MultiAsset;
-    XcmV0MultiLocation: XcmV0MultiLocation;
-    XcmV0Order: XcmV0Order;
-    XcmV0OriginKind: XcmV0OriginKind;
-    XcmV0Response: XcmV0Response;
-    XcmV0Xcm: XcmV0Xcm;
     XcmV1: XcmV1;
-    XcmV1Junction: XcmV1Junction;
-    XcmV1MultiAsset: XcmV1MultiAsset;
-    XcmV1MultiassetAssetId: XcmV1MultiassetAssetId;
-    XcmV1MultiassetAssetInstance: XcmV1MultiassetAssetInstance;
-    XcmV1MultiassetFungibility: XcmV1MultiassetFungibility;
-    XcmV1MultiassetMultiAssetFilter: XcmV1MultiassetMultiAssetFilter;
-    XcmV1MultiassetMultiAssets: XcmV1MultiassetMultiAssets;
-    XcmV1MultiassetWildFungibility: XcmV1MultiassetWildFungibility;
-    XcmV1MultiassetWildMultiAsset: XcmV1MultiassetWildMultiAsset;
-    XcmV1MultiLocation: XcmV1MultiLocation;
-    XcmV1MultilocationJunctions: XcmV1MultilocationJunctions;
-    XcmV1Order: XcmV1Order;
-    XcmV1Response: XcmV1Response;
-    XcmV1Xcm: XcmV1Xcm;
     XcmV2: XcmV2;
-    XcmV2Instruction: XcmV2Instruction;
-    XcmV2Response: XcmV2Response;
-    XcmV2TraitsError: XcmV2TraitsError;
-    XcmV2TraitsOutcome: XcmV2TraitsOutcome;
-    XcmV2WeightLimit: XcmV2WeightLimit;
-    XcmV2Xcm: XcmV2Xcm;
     XcmVersion: XcmVersion;
-    XcmVersionedMultiAssets: XcmVersionedMultiAssets;
-    XcmVersionedMultiLocation: XcmVersionedMultiLocation;
-    XcmVersionedXcm: XcmVersionedXcm;
   } // InterfaceTypes
 } // declare module
modifiedtests/src/interfaces/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types.ts
+++ b/tests/src/interfaces/types.ts
@@ -1,5 +1,3 @@
 // Auto-generated via `yarn polkadot-types-from-defs`, do not edit
 /* eslint-disable */
 
-export * from './unique/types';
-export * from './rmrk/types';
modifiedtests/yarn.lockdiffbeforeafterboth
--- a/tests/yarn.lock
+++ b/tests/yarn.lock
@@ -8615,7 +8615,7 @@
   resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
   integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
 
-solc@^0.8.13:
+solc@0.8.13:
   version "0.8.13"
   resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.13.tgz#bafc7fcc11a627e2281e489076b80497123bb704"
   integrity sha512-C0yTN+rjEOGO6uVOXI8+EKa75SFMuZpQ2tryex4QxWIg0HRWZvCHKfVPuLZ5wx06Sb6GBp6uQA5yqQyXZnXOJw==