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

difftreelog

feat evm collection creation event

Yaroslav Bolyukin2022-05-30parent: #7523de2.patch.diff
in: master

39 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5912,6 +5912,7 @@
 name = "pallet-common"
 version = "0.1.0"
 dependencies = [
+ "ethereum",
  "evm-coder",
  "fp-evm-mapping",
  "frame-benchmarking",
modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -16,12 +16,12 @@
 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
+COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelpersAbi.json
 
 TESTS_API=./tests/src/eth/api/
 
 .PHONY: regenerate_solidity
-regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol CollectionHelper.sol
+regenerate_solidity: UniqueFungible.sol UniqueNFT.sol ContractHelpers.sol CollectionHelpers.sol
 
 UniqueFungible.sol:
 	PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh
@@ -35,7 +35,7 @@
 	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:
+CollectionHelpers.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
 
@@ -51,11 +51,11 @@
 	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
 
-CollectionHelper: CollectionHelper.sol
-	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelper.raw ./.maintain/scripts/compile_stub.sh
+CollectionHelpers: CollectionHelpers.sol
+	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelpers.raw ./.maintain/scripts/compile_stub.sh
 	INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh
 
-evm_stubs: UniqueFungible UniqueNFT ContractHelpers CollectionHelper
+evm_stubs: UniqueFungible UniqueNFT ContractHelpers CollectionHelpers
 
 .PHONY: _bench
 _bench:
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -21,6 +21,7 @@
 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' }
+ethereum = { version = "0.12.0", default-features = false }
 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 }
modifiedpallets/common/src/dispatch.rsdiffbeforeafterboth
--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -56,7 +56,10 @@
 }
 
 pub trait CollectionDispatch<T: Config> {
-	fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult;
+	fn create(
+		sender: T::CrossAccountId,
+		data: CreateCollectionData<T::AccountId>,
+	) -> DispatchResult;
 	fn destroy(sender: T::CrossAccountId, handle: CollectionHandle<T>) -> DispatchResult;
 
 	fn dispatch(handle: CollectionHandle<T>) -> Self;
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 use evm_coder::{
-	solidity_interface, solidity,
+	solidity_interface, solidity, ToLog,
 	types::*,
 	execution::{Result, Error},
 };
@@ -28,6 +28,16 @@
 
 use crate::{Pallet, CollectionHandle, Config, CollectionProperties};
 
+#[derive(ToLog)]
+pub enum CollectionHelpersEvents {
+	CollectionCreated {
+		#[indexed]
+		owner: address,
+		#[indexed]
+		collection_id: address,
+	},
+}
+
 /// Does not always represent a full collection, for RFT it is either
 /// collection (Implementing ERC721), or specific collection token (Implementing ERC20)
 pub trait CommonEvmHandler {
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -21,12 +21,12 @@
 use core::ops::{Deref, DerefMut};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
 use sp_std::vec::Vec;
-use pallet_evm::account::CrossAccountId;
+use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
+use evm_coder::ToLog;
 use frame_support::{
 	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},
 	ensure,
 	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},
-	BoundedVec,
 	weights::Pays,
 	transactional,
 };
@@ -54,7 +54,6 @@
 	CreateItemExData,
 	SponsoringRateLimit,
 	budget::Budget,
-	COLLECTION_FIELD_LIMIT,
 	PhantomType,
 	Property,
 	Properties,
@@ -218,7 +217,11 @@
 
 	#[pallet::config]
 	pub trait Config:
-		frame_system::Config + pallet_evm_coder_substrate::Config + TypeInfo + account::Config
+		frame_system::Config
+		+ pallet_evm_coder_substrate::Config
+		+ pallet_evm::Config
+		+ TypeInfo
+		+ account::Config
 	{
 		type WeightInfo: WeightInfo;
 		type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
@@ -232,6 +235,7 @@
 		type CollectionDispatch: CollectionDispatch<Self>;
 
 		type TreasuryAccountId: Get<Self::AccountId>;
+		type ContractAddress: Get<H160>;
 
 		type EvmTokenAddressMapping: TokenAddressMapping<H160>;
 		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;
@@ -722,7 +726,7 @@
 
 impl<T: Config> Pallet<T> {
 	pub fn init_collection(
-		owner: T::AccountId,
+		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		{
@@ -748,7 +752,7 @@
 		// =========
 
 		let collection = Collection {
-			owner: owner.clone(),
+			owner: owner.as_sub().clone(),
 			name: data.name,
 			mode: data.mode.clone(),
 			description: data.description,
@@ -794,7 +798,7 @@
 				),
 			);
 			<T as Config>::Currency::settle(
-				&owner,
+				&owner.as_sub(),
 				imbalance,
 				WithdrawReasons::TRANSFER,
 				ExistenceRequirement::KeepAlive,
@@ -803,7 +807,18 @@
 		}
 
 		<CreatedCollectionCount<T>>::put(created_count);
-		<Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));
+		<Pallet<T>>::deposit_event(Event::CollectionCreated(
+			id,
+			data.mode.id(),
+			owner.as_sub().clone(),
+		));
+		<PalletEvm<T>>::deposit_log(
+			erc::CollectionHelpersEvents::CollectionCreated {
+				owner: *owner.as_eth(),
+				collection_id: eth::collection_id_to_address(id),
+			}
+			.to_log(T::ContractAddress::get()),
+		);
 		<CollectionById<T>>::insert(id, collection);
 		Ok(id)
 	}
modifiedpallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -66,9 +66,7 @@
 	}
 
 	#[pallet::config]
-	pub trait Config: frame_system::Config {
-		type GasWeightMapping: pallet_evm::GasWeightMapping;
-	}
+	pub trait Config: frame_system::Config + pallet_evm::Config {}
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(_);
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -134,7 +134,7 @@
 
 impl<T: Config> Pallet<T> {
 	pub fn init_collection(
-		owner: T::AccountId,
+		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data)
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,7 +127,7 @@
 	}
 }
 
-// Selector: f5652829
+// Selector: c894dc35
 contract Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -173,8 +173,16 @@
 		dummy = 0;
 	}
 
-	// Selector: setLimit(string,string) bf4d2014
-	function setLimit(string memory limit, string memory value) public {
+	// Selector: setLimit(string,uint32) 68db30ca
+	function setLimit(string memory limit, uint32 value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: setLimit(string,bool) ea67e4c2
+	function setLimit(string memory limit, bool value) public {
 		require(false, stub_error);
 		limit;
 		value;
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -295,7 +295,7 @@
 // unchecked calls skips any permission checks
 impl<T: Config> Pallet<T> {
 	pub fn init_collection(
-		owner: T::AccountId,
+		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data)
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,57 +330,7 @@
 	}
 }
 
-// Selector: d74d154f
-contract ERC721UniqueExtensions is Dummy, ERC165 {
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 tokenId) public {
-		require(false, stub_error);
-		to;
-		tokenId;
-		dummy = 0;
-	}
-
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 tokenId) public {
-		require(false, stub_error);
-		from;
-		tokenId;
-		dummy = 0;
-	}
-
-	// Selector: nextTokenId() 75794a3c
-	function nextTokenId() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	// Selector: mintBulk(address,uint256[]) 44a9945e
-	function mintBulk(address to, uint256[] memory tokenIds)
-		public
-		returns (bool)
-	{
-		require(false, stub_error);
-		to;
-		tokenIds;
-		dummy = 0;
-		return false;
-	}
-
-	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
-	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
-		public
-		returns (bool)
-	{
-		require(false, stub_error);
-		to;
-		tokens;
-		dummy = 0;
-		return false;
-	}
-}
-
-// Selector: f5652829
+// Selector: c894dc35
 contract Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -426,8 +376,16 @@
 		dummy = 0;
 	}
 
-	// Selector: setLimit(string,string) bf4d2014
-	function setLimit(string memory limit, string memory value) public {
+	// Selector: setLimit(string,uint32) 68db30ca
+	function setLimit(string memory limit, uint32 value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: setLimit(string,bool) ea67e4c2
+	function setLimit(string memory limit, bool value) public {
 		require(false, stub_error);
 		limit;
 		value;
@@ -442,6 +400,56 @@
 	}
 }
 
+// Selector: d74d154f
+contract ERC721UniqueExtensions is Dummy, ERC165 {
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 tokenId) public {
+		require(false, stub_error);
+		to;
+		tokenId;
+		dummy = 0;
+	}
+
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) public {
+		require(false, stub_error);
+		from;
+		tokenId;
+		dummy = 0;
+	}
+
+	// Selector: nextTokenId() 75794a3c
+	function nextTokenId() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+
+	// Selector: mintBulk(address,uint256[]) 44a9945e
+	function mintBulk(address to, uint256[] memory tokenIds)
+		public
+		returns (bool)
+	{
+		require(false, stub_error);
+		to;
+		tokenIds;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+		public
+		returns (bool)
+	{
+		require(false, stub_error);
+		to;
+		tokens;
+		dummy = 0;
+		return false;
+	}
+}
+
 contract UniqueNFT is
 	Dummy,
 	ERC165,
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -139,7 +139,8 @@
 				..Default::default()
 			};
 
-			let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
+			let collection_id_res =
+				<PalletNft<T>>::init_collection(T::CrossAccountId::from_sub(sender.clone()), data);
 
 			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
 				return Err(<Error<T>>::NoAvailableCollectionId.into());
modifiedpallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -94,7 +94,7 @@
 				..Default::default()
 			};
 
-			let collection_id_res = <PalletNft<T>>::init_collection(sender.clone(), data);
+			let collection_id_res = <PalletNft<T>>::init_collection(cross_sender.clone(), data);
 
 			if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
 				return Err(<Error<T>>::NoAvailableBaseId.into());
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -197,7 +197,7 @@
 // unchecked calls skips any permission checks
 impl<T: Config> Pallet<T> {
 	pub fn init_collection(
-		owner: T::AccountId,
+		owner: T::CrossAccountId,
 		data: CreateCollectionData<T::AccountId>,
 	) -> Result<CollectionId, DispatchError> {
 		<PalletCommon<T>>::init_collection(owner, data)
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -24,14 +24,17 @@
 	MAX_COLLECTION_NAME_LENGTH,
 };
 use frame_support::traits::Get;
-use pallet_common::{CollectionById, erc::token_uri_key};
+use pallet_common::{
+	CollectionById,
+	erc::{token_uri_key, CollectionHelpersEvents},
+};
 use crate::{SelfWeightOf, Config, weights::WeightInfo};
 
 use sp_std::vec::Vec;
 use alloc::format;
 
-struct EvmCollectionHelper<T: Config>(SubstrateRecorder<T>);
-impl<T: Config> WithRecorder<T> for EvmCollectionHelper<T> {
+struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);
+impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {
 	fn recorder(&self) -> &SubstrateRecorder<T> {
 		&self.0
 	}
@@ -41,8 +44,8 @@
 	}
 }
 
-#[solidity_interface(name = "CollectionHelper")]
-impl<T: Config + pallet_nonfungible::Config> EvmCollectionHelper<T> {
+#[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]
+impl<T: Config + pallet_nonfungible::Config> EvmCollectionHelpers<T> {
 	#[weight(<SelfWeightOf<T>>::create_collection())]
 	fn create_nonfungible_collection(
 		&self,
@@ -89,9 +92,8 @@
 			..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 collection_id = <pallet_nonfungible::Pallet<T>>::init_collection(caller.clone(), data)
+			.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;
 
 		let address = pallet_common::eth::collection_id_to_address(collection_id);
 		Ok(address)
@@ -107,8 +109,8 @@
 	}
 }
 
-pub struct CollectionHelperOnMethodCall<T: Config>(PhantomData<*const T>);
-impl<T: Config + pallet_nonfungible::Config> OnMethodCall<T> for CollectionHelperOnMethodCall<T> {
+pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);
+impl<T: Config + pallet_nonfungible::Config> OnMethodCall<T> for CollectionHelpersOnMethodCall<T> {
 	fn is_reserved(contract: &sp_core::H160) -> bool {
 		contract == &T::ContractAddress::get()
 	}
@@ -128,18 +130,18 @@
 			return None;
 		}
 
-		let helpers = EvmCollectionHelper::<T>(SubstrateRecorder::<T>::new(gas_left));
+		let helpers = EvmCollectionHelpers::<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())
+			.then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())
 	}
 }
 
-generate_stubgen!(collection_helper_impl, CollectionHelperCall<()>, true);
-generate_stubgen!(collection_helper_iface, CollectionHelperCall<()>, false);
+generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);
+generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);
 
 fn error_feild_too_long(feild: &str, bound: u32) -> Error {
 	Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))
deletedpallets/unique/src/eth/stubs/CollectionHelper.rawdiffbeforeafterboth

binary blob — no preview

deletedpallets/unique/src/eth/stubs/CollectionHelper.soldiffbeforeafterboth
--- a/pallets/unique/src/eth/stubs/CollectionHelper.sol
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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;
-	}
-}
addedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

addedpallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth
--- /dev/null
+++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol
@@ -0,0 +1,59 @@
+// 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;
+	}
+}
+
+// Inline
+contract CollectionHelpersEvents {
+	event CollectionCreated(
+		address indexed owner,
+		address indexed collectionId
+	);
+}
+
+// Selector: 20947cd0
+contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
+	// Selector: createNonfungibleCollection(string,string,string) e34a6844
+	function createNonfungibleCollection(
+		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
after · pallets/unique/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#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20	clippy::too_many_arguments,21	clippy::unnecessary_mut_passed,22	clippy::unused_unit23)]2425extern crate alloc;2627use frame_support::{28	decl_module, decl_storage, decl_error, decl_event,29	dispatch::DispatchResult,30	ensure,31	weights::{Weight},32	transactional,33	pallet_prelude::{DispatchResultWithPostInfo, ConstU32},34	BoundedVec,35};36use scale_info::TypeInfo;37use frame_system::{self as system, ensure_signed};38use sp_runtime::{sp_std::prelude::Vec};39use up_data_structs::{40	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,41	CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId,42	SponsorshipState, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,43	PropertyKeyPermission,44};45use pallet_evm::account::CrossAccountId;46use pallet_common::{47	CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,48	dispatch::CollectionDispatch,49};50pub mod eth;5152#[cfg(feature = "runtime-benchmarks")]53mod benchmarking;54pub mod weights;55use weights::WeightInfo;5657const NESTING_BUDGET: u32 = 5;5859decl_error! {60	/// Error for non-fungible-token module.61	pub enum Error for Module<T: Config> {62		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.63		CollectionDecimalPointLimitExceeded,64		/// This address is not set as sponsor, use setCollectionSponsor first.65		ConfirmUnsetSponsorFail,66		/// Length of items properties must be greater than 0.67		EmptyArgument,68	}69}7071pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {72	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;7374	/// Weight information for extrinsics in this pallet.75	type WeightInfo: WeightInfo;76	type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;77}7879decl_event! {80	pub enum Event<T>81	where82		<T as frame_system::Config>::AccountId,83		<T as pallet_evm::account::Config>::CrossAccountId,84	{85		/// Collection sponsor was removed86		///87		/// # Arguments88		///89		/// * collection_id: Globally unique collection identifier.90		CollectionSponsorRemoved(CollectionId),9192		/// Collection admin was added93		///94		/// # Arguments95		///96		/// * collection_id: Globally unique collection identifier.97		///98		/// * admin:  Admin address.99		CollectionAdminAdded(CollectionId, CrossAccountId),100101		/// Collection owned was change102		///103		/// # Arguments104		///105		/// * collection_id: Globally unique collection identifier.106		///107		/// * owner:  New owner address.108		CollectionOwnedChanged(CollectionId, AccountId),109110		/// Collection sponsor was set111		///112		/// # Arguments113		///114		/// * collection_id: Globally unique collection identifier.115		///116		/// * owner:  New sponsor address.117		CollectionSponsorSet(CollectionId, AccountId),118119		/// New sponsor was confirm120		///121		/// # Arguments122		///123		/// * collection_id: Globally unique collection identifier.124		///125		/// * sponsor:  New sponsor address.126		SponsorshipConfirmed(CollectionId, AccountId),127128		/// Collection admin was removed129		///130		/// # Arguments131		///132		/// * collection_id: Globally unique collection identifier.133		///134		/// * admin:  Admin address.135		CollectionAdminRemoved(CollectionId, CrossAccountId),136137		/// Address was remove from allow list138		///139		/// # Arguments140		///141		/// * collection_id: Globally unique collection identifier.142		///143		/// * user:  Address.144		AllowListAddressRemoved(CollectionId, CrossAccountId),145146		/// Address was add to allow list147		///148		/// # Arguments149		///150		/// * collection_id: Globally unique collection identifier.151		///152		/// * user:  Address.153		AllowListAddressAdded(CollectionId, CrossAccountId),154155		/// Collection limits was set156		///157		/// # Arguments158		///159		/// * collection_id: Globally unique collection identifier.160		CollectionLimitSet(CollectionId),161162		CollectionPermissionSet(CollectionId),163	}164}165166type SelfWeightOf<T> = <T as Config>::WeightInfo;167168// # Used definitions169//170// ## User control levels171//172// chain-controlled - key is uncontrolled by user173//                    i.e autoincrementing index174//                    can use non-cryptographic hash175// real - key is controlled by user176//        but it is hard to generate enough colliding values, i.e owner of signed txs177//        can use non-cryptographic hash178// controlled - key is completly controlled by users179//              i.e maps with mutable keys180//              should use cryptographic hash181//182// ## User control level downgrade reasons183//184// ?1 - chain-controlled -> controlled185//      collections/tokens can be destroyed, resulting in massive holes186// ?2 - chain-controlled -> controlled187//      same as ?1, but can be only added, resulting in easier exploitation188// ?3 - real -> controlled189//      no confirmation required, so addresses can be easily generated190decl_storage! {191	trait Store for Module<T: Config> as Unique {192193		//#region Private members194		/// Used for migrations195		ChainVersion: u64;196		//#endregion197198		//#region Tokens transfer rate limit baskets199		/// (Collection id (controlled?2), who created (real))200		/// TODO: Off chain worker should remove from this map when collection gets removed201		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;202		/// Collection id (controlled?2), token id (controlled?2)203		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;204		/// Collection id (controlled?2), owning user (real)205		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;206		/// Collection id (controlled?2), token id (controlled?2)207		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;208		//#endregion209210		/// Variable metadata sponsoring211		/// Collection id (controlled?2), token id (controlled?2)212		#[deprecated]213		pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;214		pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;215216		/// Approval sponsoring217		pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;218		pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;219		pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;220	}221}222223decl_module! {224	pub struct Module<T: Config> for enum Call225	where226		origin: T::Origin227	{228		type Error = Error<T>;229230		fn deposit_event() = default;231232		fn on_initialize(_now: T::BlockNumber) -> Weight {233			0234		}235236		fn on_runtime_upgrade() -> Weight {237			let limit = None;238239			<VariableMetaDataBasket<T>>::remove_all(limit);240241			0242		}243244		/// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner of the collection is set to the address that signed the transaction and can be changed later.245		///246		/// # Permissions247		///248		/// * Anyone.249		///250		/// # Arguments251		///252		/// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.253		///254		/// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.255		///256		/// * token_prefix: UTF-8 string with token prefix.257		///258		/// * mode: [CollectionMode] collection type and type dependent data.259		// returns collection ID260		#[weight = <SelfWeightOf<T>>::create_collection()]261		#[transactional]262		#[deprecated]263		pub fn create_collection(origin,264								 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,265								 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,266								 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,267								 mode: CollectionMode) -> DispatchResult  {268			let data: CreateCollectionData<T::AccountId> = CreateCollectionData {269				name: collection_name,270				description: collection_description,271				token_prefix,272				mode,273				..Default::default()274			};275			Self::create_collection_ex(origin, data)276		}277278		/// This method creates a collection279		///280		/// Prefer it to deprecated [`created_collection`] method281		#[weight = <SelfWeightOf<T>>::create_collection()]282		#[transactional]283		pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {284			let sender = ensure_signed(origin)?;285286			// =========287288			T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;289290			Ok(())291		}292293		/// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.294		///295		/// # Permissions296		///297		/// * Collection Owner.298		///299		/// # Arguments300		///301		/// * collection_id: collection to destroy.302		#[weight = <SelfWeightOf<T>>::destroy_collection()]303		#[transactional]304		pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {305			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);306			let collection = <CollectionHandle<T>>::try_get(collection_id)?;307308			// =========309310			T::CollectionDispatch::destroy(sender, collection)?;311312			<NftTransferBasket<T>>::remove_prefix(collection_id, None);313			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);314			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);315316			<NftApproveBasket<T>>::remove_prefix(collection_id, None);317			<FungibleApproveBasket<T>>::remove_prefix(collection_id, None);318			<RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);319320			Ok(())321		}322323		/// Add an address to allow list.324		///325		/// # Permissions326		///327		/// * Collection Owner328		/// * Collection Admin329		///330		/// # Arguments331		///332		/// * collection_id.333		///334		/// * address.335		#[weight = <SelfWeightOf<T>>::add_to_allow_list()]336		#[transactional]337		pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{338339			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);340			let collection = <CollectionHandle<T>>::try_get(collection_id)?;341342			<PalletCommon<T>>::toggle_allowlist(343				&collection,344				&sender,345				&address,346				true,347			)?;348349			Self::deposit_event(Event::<T>::AllowListAddressAdded(350				collection_id,351				address352			));353354			Ok(())355		}356357		/// Remove an address from allow list.358		///359		/// # Permissions360		///361		/// * Collection Owner362		/// * Collection Admin363		///364		/// # Arguments365		///366		/// * collection_id.367		///368		/// * address.369		#[weight = <SelfWeightOf<T>>::remove_from_allow_list()]370		#[transactional]371		pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{372373			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);374			let collection = <CollectionHandle<T>>::try_get(collection_id)?;375376			<PalletCommon<T>>::toggle_allowlist(377				&collection,378				&sender,379				&address,380				false,381			)?;382383			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(384				collection_id,385				address386			));387388			Ok(())389		}390391		/// Change the owner of the collection.392		///393		/// # Permissions394		///395		/// * Collection Owner.396		///397		/// # Arguments398		///399		/// * collection_id.400		///401		/// * new_owner.402		#[weight = <SelfWeightOf<T>>::change_collection_owner()]403		#[transactional]404		pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {405406			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);407408			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;409			target_collection.check_is_owner(&sender)?;410411			target_collection.owner = new_owner.clone();412			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(413				collection_id,414				new_owner415			));416417			target_collection.save()418		}419420		/// Adds an admin of the Collection.421		/// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership.422		///423		/// # Permissions424		///425		/// * Collection Owner.426		/// * Collection Admin.427		///428		/// # Arguments429		///430		/// * collection_id: ID of the Collection to add admin for.431		///432		/// * new_admin_id: Address of new admin to add.433		#[weight = <SelfWeightOf<T>>::add_collection_admin()]434		#[transactional]435		pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {436			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);437			let collection = <CollectionHandle<T>>::try_get(collection_id)?;438439			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(440				collection_id,441				new_admin_id.clone()442			));443444			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)445		}446447		/// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.448		///449		/// # Permissions450		///451		/// * Collection Owner.452		/// * Collection Admin.453		///454		/// # Arguments455		///456		/// * collection_id: ID of the Collection to remove admin for.457		///458		/// * account_id: Address of admin to remove.459		#[weight = <SelfWeightOf<T>>::remove_collection_admin()]460		#[transactional]461		pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {462			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);463			let collection = <CollectionHandle<T>>::try_get(collection_id)?;464465			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(466				collection_id,467				account_id.clone()468			));469470			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)471		}472473		/// # Permissions474		///475		/// * Collection Owner476		///477		/// # Arguments478		///479		/// * collection_id.480		///481		/// * new_sponsor.482		#[weight = <SelfWeightOf<T>>::set_collection_sponsor()]483		#[transactional]484		pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {485			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);486487			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;488			target_collection.check_is_owner(&sender)?;489490			target_collection.set_sponsor(new_sponsor.clone());491492			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(493				collection_id,494				new_sponsor495			));496497			target_collection.save()498		}499500		/// # Permissions501		///502		/// * Sponsor.503		///504		/// # Arguments505		///506		/// * collection_id.507		#[weight = <SelfWeightOf<T>>::confirm_sponsorship()]508		#[transactional]509		pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {510			let sender = ensure_signed(origin)?;511512			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;513			ensure!(514				target_collection.confirm_sponsorship(&sender),515				Error::<T>::ConfirmUnsetSponsorFail516			);517518			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(519				collection_id,520				sender521			));522523			target_collection.save()524		}525526		/// Switch back to pay-per-own-transaction model.527		///528		/// # Permissions529		///530		/// * Collection owner.531		///532		/// # Arguments533		///534		/// * collection_id.535		#[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]536		#[transactional]537		pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {538			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);539540			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;541			target_collection.check_is_owner(&sender)?;542543			target_collection.sponsorship = SponsorshipState::Disabled;544545			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(546				collection_id547			));548			target_collection.save()549		}550551		/// This method creates a concrete instance of NFT Collection created with CreateCollection method.552		///553		/// # Permissions554		///555		/// * Collection Owner.556		/// * Collection Admin.557		/// * Anyone if558		///     * Allow List is enabled, and559		///     * Address is added to allow list, and560		///     * MintPermission is enabled (see SetMintPermission method)561		///562		/// # Arguments563		///564		/// * collection_id: ID of the collection.565		///566		/// * owner: Address, initial owner of the NFT.567		///568		/// * data: Token data to store on chain.569		#[weight = T::CommonWeightInfo::create_item()]570		#[transactional]571		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {572			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);573			let budget = budget::Value::new(NESTING_BUDGET);574575			dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))576		}577578		/// This method creates multiple items in a collection created with CreateCollection method.579		///580		/// # Permissions581		///582		/// * Collection Owner.583		/// * Collection Admin.584		/// * Anyone if585		///     * Allow List is enabled, and586		///     * Address is added to allow list, and587		///     * MintPermission is enabled (see SetMintPermission method)588		///589		/// # Arguments590		///591		/// * collection_id: ID of the collection.592		///593		/// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].594		///595		/// * owner: Address, initial owner of the NFT.596		#[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]597		#[transactional]598		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {599			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);600			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);601			let budget = budget::Value::new(NESTING_BUDGET);602603			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))604		}605606		#[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]607		#[transactional]608		pub fn set_collection_properties(609			origin,610			collection_id: CollectionId,611			properties: Vec<Property>612		) -> DispatchResultWithPostInfo {613			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);614615			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);616617			dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))618		}619620		#[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]621		#[transactional]622		pub fn delete_collection_properties(623			origin,624			collection_id: CollectionId,625			property_keys: Vec<PropertyKey>,626		) -> DispatchResultWithPostInfo {627			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);628629			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);630631			dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))632		}633634		#[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]635		#[transactional]636		pub fn set_token_properties(637			origin,638			collection_id: CollectionId,639			token_id: TokenId,640			properties: Vec<Property>641		) -> DispatchResultWithPostInfo {642			ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);643644			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);645646			dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))647		}648649		#[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]650		#[transactional]651		pub fn delete_token_properties(652			origin,653			collection_id: CollectionId,654			token_id: TokenId,655			property_keys: Vec<PropertyKey>656		) -> DispatchResultWithPostInfo {657			ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);658659			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);660661			dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))662		}663664		#[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]665		#[transactional]666		pub fn set_property_permissions(667			origin,668			collection_id: CollectionId,669			property_permissions: Vec<PropertyKeyPermission>,670		) -> DispatchResultWithPostInfo {671			ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);672673			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);674675			dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))676		}677678		#[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]679		#[transactional]680		pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {681			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);682			let budget = budget::Value::new(NESTING_BUDGET);683684			dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))685		}686687		// TODO! transaction weight688689		/// Set transfers_enabled value for particular collection690		///691		/// # Permissions692		///693		/// * Collection Owner.694		///695		/// # Arguments696		///697		/// * collection_id: ID of the collection.698		///699		/// * value: New flag value.700		#[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]701		#[transactional]702		pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {703			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);704			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;705			target_collection.check_is_owner(&sender)?;706707			// =========708709			target_collection.limits.transfers_enabled = Some(value);710			target_collection.save()711		}712713		/// Destroys a concrete instance of NFT.714		///715		/// # Permissions716		///717		/// * Collection Owner.718		/// * Collection Admin.719		/// * Current NFT Owner.720		///721		/// # Arguments722		///723		/// * collection_id: ID of the collection.724		///725		/// * item_id: ID of NFT to burn.726		#[weight = T::CommonWeightInfo::burn_item()]727		#[transactional]728		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {729			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);730731			let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;732			if value == 1 {733				<NftTransferBasket<T>>::remove(collection_id, item_id);734				<NftApproveBasket<T>>::remove(collection_id, item_id);735			}736			// Those maps should be cleared only if token disappears completly, need to move this part of logic to pallets?737			// <FungibleApproveBasket<T>>::remove(collection_id, sender.as_sub());738			// <RefungibleApproveBasket<T>>::remove((collection_id, item_id, sender.as_sub()));739			Ok(post_info)740		}741742		/// Destroys a concrete instance of NFT on behalf of the owner743		/// See also: [`approve`]744		///745		/// # Permissions746		///747		/// * Collection Owner.748		/// * Collection Admin.749		/// * Current NFT Owner.750		///751		/// # Arguments752		///753		/// * collection_id: ID of the collection.754		///755		/// * item_id: ID of NFT to burn.756		///757		/// * from: owner of item758		#[weight = T::CommonWeightInfo::burn_from()]759		#[transactional]760		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {761			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);762			let budget = budget::Value::new(NESTING_BUDGET);763764			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))765		}766767		/// Change ownership of the token.768		///769		/// # Permissions770		///771		/// * Collection Owner772		/// * Collection Admin773		/// * Current NFT owner774		///775		/// # Arguments776		///777		/// * recipient: Address of token recipient.778		///779		/// * collection_id.780		///781		/// * item_id: ID of the item782		///     * Non-Fungible Mode: Required.783		///     * Fungible Mode: Ignored.784		///     * Re-Fungible Mode: Required.785		///786		/// * value: Amount to transfer.787		///     * Non-Fungible Mode: Ignored788		///     * Fungible Mode: Must specify transferred amount789		///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)790		#[weight = T::CommonWeightInfo::transfer()]791		#[transactional]792		pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {793			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);794			let budget = budget::Value::new(NESTING_BUDGET);795796			dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))797		}798799		/// Set, change, or remove approved address to transfer the ownership of the NFT.800		///801		/// # Permissions802		///803		/// * Collection Owner804		/// * Collection Admin805		/// * Current NFT owner806		///807		/// # Arguments808		///809		/// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).810		///811		/// * collection_id.812		///813		/// * item_id: ID of the item.814		#[weight = T::CommonWeightInfo::approve()]815		#[transactional]816		pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {817			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);818819			dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))820		}821822		/// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.823		///824		/// # Permissions825		/// * Collection Owner826		/// * Collection Admin827		/// * Current NFT owner828		/// * Address approved by current NFT owner829		///830		/// # Arguments831		///832		/// * from: Address that owns token.833		///834		/// * recipient: Address of token recipient.835		///836		/// * collection_id.837		///838		/// * item_id: ID of the item.839		///840		/// * value: Amount to transfer.841		#[weight = T::CommonWeightInfo::transfer_from()]842		#[transactional]843		pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {844			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);845			let budget = budget::Value::new(NESTING_BUDGET);846847			dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))848		}849850		#[weight = <SelfWeightOf<T>>::set_collection_limits()]851		#[transactional]852		pub fn set_collection_limits(853			origin,854			collection_id: CollectionId,855			new_limit: CollectionLimits,856		) -> DispatchResult {857			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);858			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;859			target_collection.check_is_owner(&sender)?;860			let old_limit = &target_collection.limits;861862			target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;863864			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(865				collection_id866			));867868			target_collection.save()869		}870871		#[weight = <SelfWeightOf<T>>::set_collection_limits()]872		#[transactional]873		pub fn set_collection_permissions(874			origin,875			collection_id: CollectionId,876			new_limit: CollectionPermissions,877		) -> DispatchResult {878			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);879			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;880			target_collection.check_is_owner(&sender)?;881			let old_limit = &target_collection.permissions;882883			target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;884885			<Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(886				collection_id887			));888889			target_collection.save()890		}891	}892}
modifiedruntime/common/src/dispatch.rsdiffbeforeafterboth
--- a/runtime/common/src/dispatch.rs
+++ b/runtime/common/src/dispatch.rs
@@ -30,7 +30,10 @@
 		+ pallet_nonfungible::Config
 		+ pallet_refungible::Config,
 {
-	fn create(sender: T::AccountId, data: CreateCollectionData<T::AccountId>) -> DispatchResult {
+	fn create(
+		sender: T::CrossAccountId,
+		data: CreateCollectionData<T::AccountId>,
+	) -> DispatchResult {
 		let _id = match data.mode {
 			CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data)?,
 			CollectionMode::Fungible(decimal_points) => {
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -306,7 +306,7 @@
 		pallet_evm_migration::OnMethodCall<Self>,
 		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
 		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,
+		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
 	);
 	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
 	type ChainId = ChainId;
@@ -821,9 +821,7 @@
 	XcmpQueue,
 );
 
-impl pallet_evm_coder_substrate::Config for Runtime {
-	type GasWeightMapping = FixedGasWeightMapping;
-}
+impl pallet_evm_coder_substrate::Config for Runtime {}
 
 impl pallet_xcm::Config for Runtime {
 	type Event = Event;
@@ -885,6 +883,7 @@
 
 	type EvmTokenAddressMapping = EvmTokenAddressMapping;
 	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+	type ContractAddress = EvmCollectionHelpersAddress;
 }
 
 impl pallet_structure::Config for Runtime {
@@ -917,7 +916,6 @@
 	type Event = Event;
 	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
 	type CommonWeightInfo = CommonWeights<Self>;
-	type ContractAddress = EvmCollectionHelperAddress;
 }
 
 parameter_types! {
@@ -980,7 +978,7 @@
 	]);
 
 	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelperAddress: H160 = H160([
+	pub const EvmCollectionHelpersAddress: H160 = H160([
 		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
 	]);
 }
modifiedruntime/quartz/src/lib.rsdiffbeforeafterboth
--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -285,7 +285,7 @@
 		pallet_evm_migration::OnMethodCall<Self>,
 		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
 		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,
+		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
 	);
 	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
 	type ChainId = ChainId;
@@ -800,9 +800,7 @@
 	XcmpQueue,
 );
 
-impl pallet_evm_coder_substrate::Config for Runtime {
-	type GasWeightMapping = FixedGasWeightMapping;
-}
+impl pallet_evm_coder_substrate::Config for Runtime {}
 
 impl pallet_xcm::Config for Runtime {
 	type Event = Event;
@@ -864,6 +862,7 @@
 
 	type EvmTokenAddressMapping = EvmTokenAddressMapping;
 	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+	type ContractAddress = EvmCollectionHelpersAddress;
 }
 
 impl pallet_structure::Config for Runtime {
@@ -900,7 +899,6 @@
 	type Event = Event;
 	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
 	type CommonWeightInfo = CommonWeights<Self>;
-	type ContractAddress = EvmCollectionHelperAddress;
 }
 
 parameter_types! {
@@ -963,7 +961,7 @@
 	]);
 		
 	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelperAddress: H160 = H160([
+	pub const EvmCollectionHelpersAddress: H160 = H160([
 		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
 	]);
 }
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -208,9 +208,7 @@
 	type BlockHashMapping = SubstrateBlockHashMapping<Self>;
 	type TransactionValidityHack = ();
 }
-impl pallet_evm_coder_substrate::Config for Test {
-	type GasWeightMapping = ();
-}
+impl pallet_evm_coder_substrate::Config for Test {}
 
 impl pallet_common::Config for Test {
 	type WeightInfo = ();
@@ -222,6 +220,7 @@
 	type CollectionDispatch = CollectionDispatchT<Self>;
 	type EvmTokenAddressMapping = EvmTokenAddressMapping;
 	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+	type ContractAddress = EvmCollectionHelpersAddress;
 }
 
 impl pallet_evm::account::Config for Test {
@@ -247,7 +246,7 @@
 
 parameter_types! {
 	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelperAddress: H160 = H160([
+	pub const EvmCollectionHelpersAddress: H160 = H160([
 		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
 	]);
 }
@@ -256,7 +255,6 @@
 	type Event = ();
 	type WeightInfo = ();
 	type CommonWeightInfo = CommonWeights<Self>;
-	type ContractAddress = EvmCollectionHelperAddress;
 }
 
 // Build genesis storage according to the mock runtime.
modifiedruntime/unique/src/lib.rsdiffbeforeafterboth
--- a/runtime/unique/src/lib.rs
+++ b/runtime/unique/src/lib.rs
@@ -290,7 +290,7 @@
 		pallet_evm_migration::OnMethodCall<Self>,
 		pallet_evm_contract_helpers::HelpersOnMethodCall<Self>,
 		CollectionDispatchT<Self>,
-		pallet_unique::eth::CollectionHelperOnMethodCall<Self>,
+		pallet_unique::eth::CollectionHelpersOnMethodCall<Self>,
 	);
 	type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;
 	type ChainId = ChainId;
@@ -805,9 +805,7 @@
 	XcmpQueue,
 );
 
-impl pallet_evm_coder_substrate::Config for Runtime {
-	type GasWeightMapping = FixedGasWeightMapping;
-}
+impl pallet_evm_coder_substrate::Config for Runtime {}
 
 impl pallet_xcm::Config for Runtime {
 	type Event = Event;
@@ -869,6 +867,7 @@
 
 	type EvmTokenAddressMapping = EvmTokenAddressMapping;
 	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
+	type ContractAddress = EvmCollectionHelpersAddress;
 }
 
 impl pallet_structure::Config for Runtime {
@@ -905,7 +904,6 @@
 	type Event = Event;
 	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
 	type CommonWeightInfo = CommonWeights<Self>;
-	type ContractAddress = EvmCollectionHelperAddress;
 }
 
 parameter_types! {
@@ -968,7 +966,7 @@
 	]);
 		
 	// 0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f
-	pub const EvmCollectionHelperAddress: H160 = H160([
+	pub const EvmCollectionHelpersAddress: H160 = H160([
 		0x6c, 0x4e, 0x9f, 0xe1, 0xae, 0x37, 0xa4, 0x1e, 0x93, 0xce, 0xe4, 0x29, 0xe8, 0xe1, 0x88, 0x1a, 0xbd, 0xcb, 0xb5, 0x4f,
 	]);
 }
deletedtests/src/eth/api/CollectionHelper.soldiffbeforeafterboth
--- a/tests/src/eth/api/CollectionHelper.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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);
-}
addedtests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -0,0 +1,37 @@
+// 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);
+}
+
+// Inline
+interface CollectionHelpersEvents {
+	event CollectionCreated(
+		address indexed owner,
+		address indexed collectionId
+	);
+}
+
+// Selector: 20947cd0
+interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
+	// Selector: createNonfungibleCollection(string,string,string) e34a6844
+	function createNonfungibleCollection(
+		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,7 +65,7 @@
 		returns (uint256);
 }
 
-// Selector: f5652829
+// Selector: c894dc35
 interface Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -88,8 +88,11 @@
 	// Selector: ethConfirmSponsorship() a8580d1a
 	function ethConfirmSponsorship() external;
 
-	// Selector: setLimit(string,string) bf4d2014
-	function setLimit(string memory limit, string memory value) external;
+	// Selector: setLimit(string,uint32) 68db30ca
+	function setLimit(string memory limit, uint32 value) external;
+
+	// Selector: setLimit(string,bool) ea67e4c2
+	function setLimit(string memory limit, bool value) external;
 
 	// Selector: contractAddress() f6b4dfb4
 	function contractAddress() external view returns (address);
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -191,29 +191,7 @@
 	function totalSupply() external view returns (uint256);
 }
 
-// Selector: d74d154f
-interface ERC721UniqueExtensions is Dummy, ERC165 {
-	// Selector: transfer(address,uint256) a9059cbb
-	function transfer(address to, uint256 tokenId) external;
-
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 tokenId) external;
-
-	// Selector: nextTokenId() 75794a3c
-	function nextTokenId() external view returns (uint256);
-
-	// Selector: mintBulk(address,uint256[]) 44a9945e
-	function mintBulk(address to, uint256[] memory tokenIds)
-		external
-		returns (bool);
-
-	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
-	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
-		external
-		returns (bool);
-}
-
-// Selector: f5652829
+// Selector: c894dc35
 interface Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -236,13 +214,38 @@
 	// Selector: ethConfirmSponsorship() a8580d1a
 	function ethConfirmSponsorship() external;
 
-	// Selector: setLimit(string,string) bf4d2014
-	function setLimit(string memory limit, string memory value) external;
+	// Selector: setLimit(string,uint32) 68db30ca
+	function setLimit(string memory limit, uint32 value) external;
+
+	// Selector: setLimit(string,bool) ea67e4c2
+	function setLimit(string memory limit, bool value) external;
 
 	// Selector: contractAddress() f6b4dfb4
 	function contractAddress() external view returns (address);
 }
 
+// Selector: d74d154f
+interface ERC721UniqueExtensions is Dummy, ERC165 {
+	// Selector: transfer(address,uint256) a9059cbb
+	function transfer(address to, uint256 tokenId) external;
+
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 tokenId) external;
+
+	// Selector: nextTokenId() 75794a3c
+	function nextTokenId() external view returns (uint256);
+
+	// Selector: mintBulk(address,uint256[]) 44a9945e
+	function mintBulk(address to, uint256[] memory tokenIds)
+		external
+		returns (bool);
+
+	// Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+	function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+		external
+		returns (bool);
+}
+
 interface UniqueNFT is
 	Dummy,
 	ERC165,
deletedtests/src/eth/collectionHelperAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/collectionHelperAbi.json
+++ /dev/null
@@ -1,35 +0,0 @@
-[
-  {
-    "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"
-  }
-]
addedtests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/collectionHelpersAbi.json
@@ -0,0 +1,54 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      }
+    ],
+    "name": "CollectionCreated",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "name", "type": "string" },
+      { "internalType": "string", "name": "description", "type": "string" },
+      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+    ],
+    "name": "createNonfungibleCollection",
+    "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,7 +29,7 @@
   normalizeEvents,
   subToEth,
   executeEthTxOnSub,
-  evmCollectionHelper,
+  evmCollectionHelpers,
   getCollectionAddressFromResult,
   evmCollection,
 } from './util/helpers';
@@ -224,8 +224,8 @@
   //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 collectionHelpers = evmCollectionHelpers(web3, owner);
+    let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const sponsor = await createEthAccountWithBalance(api, web3);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
modifiedtests/src/eth/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createCollection.test.ts
+++ b/tests/src/eth/createCollection.test.ts
@@ -18,7 +18,7 @@
 import {expect} from 'chai';
 import {getCreatedCollectionCount, getDetailedCollectionInfo} from '../util/helpers';
 import {
-  evmCollectionHelper,
+  evmCollectionHelpers,
   collectionIdToAddress,
   createEthAccount,
   createEthAccountWithBalance,
@@ -30,14 +30,14 @@
 describe('Create collection from EVM', () => {
   itWeb3('Create collection', async ({api, web3}) => {
     const owner = await createEthAccountWithBalance(api, web3);
-    const helper = evmCollectionHelper(web3, owner);
+    const helper = evmCollectionHelpers(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)
+      .createNonfungibleCollection(collectionName, description, tokenPrefix)
       .send();
     const collectionCountAfter = await getCreatedCollectionCount(api);
   
@@ -51,27 +51,27 @@
 
   itWeb3('Check collection address exist', async ({api, web3}) => {
     const owner = await createEthAccountWithBalance(api, web3);
-    const collectionHelper = evmCollectionHelper(web3, owner);
+    const collectionHelpers = evmCollectionHelpers(web3, owner);
   
     const expectedCollectionId = await getCreatedCollectionCount(api) + 1;
     const expectedCollectionAddress = collectionIdToAddress(expectedCollectionId);
-    expect(await collectionHelper.methods
+    expect(await collectionHelpers.methods
       .isCollectionExist(expectedCollectionAddress)
       .call()).to.be.false;
 
-    await collectionHelper.methods
-      .create721Collection('A', 'A', 'A')
+    await collectionHelpers.methods
+      .createNonfungibleCollection('A', 'A', 'A')
       .send();
     
-    expect(await collectionHelper.methods
+    expect(await collectionHelpers.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 collectionHelpers = evmCollectionHelpers(web3, owner);
+    let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const sponsor = await createEthAccountWithBalance(api, web3);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
@@ -89,8 +89,8 @@
 
   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 collectionHelpers = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelpers.methods.createNonfungibleCollection('Const collection', '5', '5').send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const limits = {
       accountTokenOwnershipLimit: 1000,
@@ -105,15 +105,15 @@
     };
 
     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();
+    await collectionEvm.methods['setLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();
+    await collectionEvm.methods['setLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();
+    await collectionEvm.methods['setLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();
+    await collectionEvm.methods['setLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();
+    await collectionEvm.methods['setLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();
+    await collectionEvm.methods['setLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();
+    await collectionEvm.methods['setLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();
+    await collectionEvm.methods['setLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();
+    await collectionEvm.methods['setLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();
     
     const collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
     expect(collectionSub.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.be.eq(limits.accountTokenOwnershipLimit);
@@ -130,14 +130,14 @@
   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
+    const collectionHelpers = evmCollectionHelpers(web3, owner);
+    expect(await collectionHelpers.methods
       .isCollectionExist(collectionAddressForNonexistentCollection).call())
       .to.be.false;
     
-    const result = await collectionHelper.methods.create721Collection('Collection address exist', '7', '7').send();
+    const result = await collectionHelpers.methods.createNonfungibleCollection('Collection address exist', '7', '7').send();
     const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
-    expect(await collectionHelper.methods
+    expect(await collectionHelpers.methods
       .isCollectionExist(collectionIdAddress).call())
       .to.be.true;
   });
@@ -146,7 +146,7 @@
 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 helper = evmCollectionHelpers(web3, owner);
     {
       const MAX_NAME_LENGHT = 64;
       const collectionName = 'A'.repeat(MAX_NAME_LENGHT + 1);
@@ -154,7 +154,7 @@
       const tokenPrefix = 'A';
     
       await expect(helper.methods
-        .create721Collection(collectionName, description, tokenPrefix)
+        .createNonfungibleCollection(collectionName, description, tokenPrefix)
         .call()).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGHT);
       
     }
@@ -164,7 +164,7 @@
       const description = 'A'.repeat(MAX_DESCRIPTION_LENGHT + 1);
       const tokenPrefix = 'A';
       await expect(helper.methods
-        .create721Collection(collectionName, description, tokenPrefix)
+        .createNonfungibleCollection(collectionName, description, tokenPrefix)
         .call()).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGHT);
     }
     {  
@@ -173,28 +173,28 @@
       const description = 'A';
       const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGHT + 1);
       await expect(helper.methods
-        .create721Collection(collectionName, description, tokenPrefix)
+        .createNonfungibleCollection(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 helper = evmCollectionHelpers(web3, owner);
     const collectionName = 'A';
     const description = 'A';
     const tokenPrefix = 'A';
     
     await expect(helper.methods
-      .create721Collection(collectionName, description, tokenPrefix)
+      .createNonfungibleCollection(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 collectionHelpers = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send();
     const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
     const contractEvmFromNotOwner = evmCollection(web3, notOwner, collectionIdAddress);
     const EXPECTED_ERROR = 'NoPermission';
@@ -218,18 +218,12 @@
 
   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 collectionHelpers = evmCollectionHelpers(web3, owner);
+    const result = await collectionHelpers.methods.createNonfungibleCollection('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:');
+      .call()).to.be.rejectedWith('Unknown boolean limit "badLimit"');
   });
 });
\ No newline at end of file
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/fungibleAbi.json
+++ b/tests/src/eth/fungibleAbi.json
@@ -152,7 +152,17 @@
   {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "string", "name": "value", "type": "string" }
+      { "internalType": "uint32", "name": "value", "type": "uint32" }
+    ],
+    "name": "setLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "limit", "type": "string" },
+      { "internalType": "bool", "name": "value", "type": "bool" }
     ],
     "name": "setLimit",
     "outputs": [],
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, evmCollection, evmCollectionHelper, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, 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';
@@ -76,8 +76,8 @@
 describe('NFT: Plain calls', () => {
   itWeb3('Can perform mint()', async ({web3, api}) => {
     const owner = await createEthAccountWithBalance(api, web3);
-    const helper = evmCollectionHelper(web3, owner);
-    let result = await helper.methods.create721Collection('Mint collection', '6', '6').send();
+    const helper = evmCollectionHelpers(web3, owner);
+    let result = await helper.methods.createNonfungibleCollection('Mint collection', '6', '6').send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const receiver = createEthAccount(web3);
     const contract = evmCollection(web3, owner, collectionIdAddress);
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -326,7 +326,17 @@
   {
     "inputs": [
       { "internalType": "string", "name": "limit", "type": "string" },
-      { "internalType": "string", "name": "value", "type": "string" }
+      { "internalType": "uint32", "name": "value", "type": "uint32" }
+    ],
+    "name": "setLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "limit", "type": "string" },
+      { "internalType": "bool", "name": "value", "type": "bool" }
     ],
     "name": "setLimit",
     "outputs": [],
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -29,7 +29,7 @@
 import privateKey from '../../substrate/privateKey';
 import contractHelpersAbi from './contractHelpersAbi.json';
 import nonFungibleAbi from '../nonFungibleAbi.json';
-import collectionHelperAbi from '../collectionHelperAbi.json';
+import collectionHelpersAbi from '../collectionHelpersAbi.json';
 import getBalance from '../../substrate/get-balance';
 import waitNewBlocks from '../../substrate/wait-new-blocks';
 
@@ -69,7 +69,7 @@
 }
 
 export async function getCollectionAddressFromResult(api: ApiPromise, result: any) {
-  const collectionIdAddress = normalizeAddress(result.events[0].raw.topics[2]);
+  const collectionIdAddress = normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
   const collectionId = collectionIdFromAddress(collectionIdAddress);  
   const collection = (await getDetailedCollectionInfo(api, collectionId))!;
   return {collectionIdAddress, collectionId, collection};
@@ -297,8 +297,8 @@
  * @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});
+export function evmCollectionHelpers(web3: Web3, caller: string) {
+  return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS});
 }
 
 /**