git.delta.rocks / unique-network / refs/commits / 4d4a023748fc

difftreelog

feat add `EthCrossAccount` type

Trubnikov Sergey2022-09-28parent: #5e5eea4.patch.diff
in: master

14 files changed

modified.maintain/scripts/compile_stub.shdiffbeforeafterboth
--- a/.maintain/scripts/compile_stub.sh
+++ b/.maintain/scripts/compile_stub.sh
@@ -6,6 +6,7 @@
 tmp=$(mktemp -d)
 cd $tmp
 cp $dir/$INPUT input.sol
+echo "Tmp file: $tmp/input.sol"
 solcjs --optimize --bin input.sol -o $PWD
 
 mv input_sol_$(basename $OUTPUT .raw).bin out.bin
modifiedCargo.lockdiffbeforeafterboth
before · Cargo.lock
1011 packageslockfile v3
after · Cargo.lock
1046 packageslockfile v3
modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -18,6 +18,8 @@
 # We have tuple-heavy code in solidity.rs
 impl-trait-for-tuples = "0.2.2"
 
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.27-fee-limit" }
+
 [dev-dependencies]
 # We want to assert some large binary blobs equality in tests
 hex = "0.4.3"
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi.rs
+++ b/crates/evm-coder/src/abi.rs
@@ -402,6 +402,7 @@
 impl sealed::CanBePlacedInVec for U256 {}
 impl sealed::CanBePlacedInVec for string {}
 impl sealed::CanBePlacedInVec for H160 {}
+impl sealed::CanBePlacedInVec for EthCrossAccount {}
 
 impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>
 where
@@ -419,6 +420,70 @@
 	}
 }
 
+impl TypeHelper for EthCrossAccount {
+	fn is_dynamic() -> bool {
+		address::is_dynamic() || uint256::is_dynamic()
+	}
+}
+
+impl AbiRead<EthCrossAccount> for AbiReader<'_> {
+	fn abi_read(&mut self) -> Result<EthCrossAccount> {
+		let size = if !EthCrossAccount::is_dynamic() {
+			Some(<Self as AbiRead<EthCrossAccount>>::size())
+		} else {
+			None
+		};
+		let mut subresult = self.subresult(size)?;
+		let eth = <Self as AbiRead<address>>::abi_read(&mut subresult)?;
+		let sub = <Self as AbiRead<uint256>>::abi_read(&mut subresult)?;
+
+		Ok(EthCrossAccount { eth: eth, sub: sub })
+	}
+
+	fn size() -> usize {
+		<Self as AbiRead<address>>::size() + <Self as AbiRead<uint256>>::size()
+	}
+}
+
+impl AbiWrite for &EthCrossAccount {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		self.eth.abi_write(writer);
+		self.sub.abi_write(writer);
+	}
+}
+
+impl TypeHelper for EthCrossAccount {
+	fn is_dynamic() -> bool {
+		address::is_dynamic() || uint256::is_dynamic()
+	}
+}
+
+impl AbiRead<EthCrossAccount> for AbiReader<'_> {
+	fn abi_read(&mut self) -> Result<EthCrossAccount> {
+		let size = if !EthCrossAccount::is_dynamic() {
+			Some(<Self as AbiRead<EthCrossAccount>>::size())
+		} else {
+			None
+		};
+		let mut subresult = self.subresult(size)?;
+		let eth = <Self as AbiRead<address>>::abi_read(&mut subresult)?;
+		let sub = <Self as AbiRead<uint256>>::abi_read(&mut subresult)?;
+
+		Ok(EthCrossAccount { eth: eth, sub: sub })
+	}
+
+	fn size() -> usize {
+		<Self as AbiRead<address>>::size() + <Self as AbiRead<uint256>>::size()
+	}
+}
+
+impl AbiWrite for &EthCrossAccount {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		self.eth.abi_write(writer);
+		self.sub.abi_write(writer);
+	}
+}
+
 macro_rules! impl_tuples {
 	($($ident:ident)+) => {
 		impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -114,6 +114,7 @@
 
 	#[cfg(not(feature = "std"))]
 	use alloc::{vec::Vec};
+	use pallet_evm::account::CrossAccountId;
 	use primitive_types::{U256, H160, H256};
 
 	pub type address = H160;
@@ -183,6 +184,72 @@
 			self.len() == 0
 		}
 	}
+
+	#[derive(Debug)]
+	pub struct EthCrossAccount {
+		pub(crate) eth: address,
+		pub(crate) sub: uint256,
+	}
+
+	impl EthCrossAccount {
+		pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self
+		where
+			T: pallet_evm::account::Config,
+			T::AccountId: AsRef<[u8; 32]>,
+		{
+			if cross_account_id.is_canonical_substrate() {
+				Self {
+					eth: Default::default(),
+					sub: convert_cross_account_to_uint256::<T>(cross_account_id),
+				}
+			} else {
+				Self {
+					eth: *cross_account_id.as_eth(),
+					sub: Default::default(),
+				}
+			}
+		}
+
+		pub fn into_sub_cross_account<T>(&self) -> crate::execution::Result<T::CrossAccountId>
+		where
+			T: pallet_evm::account::Config,
+			T::AccountId: From<[u8; 32]>,
+		{
+			if self.eth == Default::default() && self.sub == Default::default() {
+				Err("All fields of cross account is zeroed".into())
+			} else if self.eth == Default::default() {
+				Ok(convert_uint256_to_cross_account::<T>(self.sub))
+			} else if self.sub == Default::default() {
+				Ok(T::CrossAccountId::from_eth(self.eth))
+			} else {
+				Err("All fields of cross account is non zeroed".into())
+			}
+		}
+	}
+
+	/// Convert `CrossAccountId` to `uint256`.
+	pub fn convert_cross_account_to_uint256<T: pallet_evm::account::Config>(
+		from: &T::CrossAccountId,
+	) -> uint256
+	where
+		T::AccountId: AsRef<[u8; 32]>,
+	{
+		let slice = from.as_sub().as_ref();
+		uint256::from_big_endian(slice)
+	}
+
+	/// Convert `uint256` to `CrossAccountId`.
+	pub fn convert_uint256_to_cross_account<T: pallet_evm::account::Config>(
+		from: uint256,
+	) -> T::CrossAccountId
+	where
+		T::AccountId: From<[u8; 32]>,
+	{
+		let mut new_admin_arr = [0_u8; 32];
+		from.to_big_endian(&mut new_admin_arr);
+		let account_id = T::AccountId::from(new_admin_arr);
+		T::CrossAccountId::from_sub(account_id)
+	}
 }
 
 /// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -72,6 +72,10 @@
 		self.anonymous.borrow_mut().insert(names, id);
 		format!("Tuple{}", id)
 	}
+	pub fn collect_struct<T: StructCollect>(&self) -> String {
+		self.collect(<T as StructCollect>::declaration());
+		<T as StructCollect>::name()
+	}
 	pub fn finish(self) -> Vec<string> {
 		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();
 		data.sort_by_key(|(_, id)| Reverse(*id));
@@ -79,6 +83,13 @@
 	}
 }
 
+pub trait StructCollect: 'static {
+	/// Structure name.
+	fn name() -> String;
+	/// Structure declaration.
+	fn declaration() -> String;
+}
+
 pub trait SolidityTypeName: 'static {
 	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
 	/// "simple" types are stored inline, no `memory` modifier should be used in solidity
@@ -145,6 +156,7 @@
 impl sealed::CanBePlacedInVec for uint256 {}
 impl sealed::CanBePlacedInVec for string {}
 impl sealed::CanBePlacedInVec for address {}
+impl sealed::CanBePlacedInVec for EthCrossAccount {}
 
 impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {
 	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
@@ -161,6 +173,60 @@
 	}
 }
 
+impl SolidityTupleType for EthCrossAccount {
+	fn names(tc: &TypeCollector) -> Vec<string> {
+		let mut collected = Vec::with_capacity(Self::len());
+		{
+			let mut out = string::new();
+			address::solidity_name(&mut out, tc).expect("no fmt error");
+			collected.push(out);
+		}
+		{
+			let mut out = string::new();
+			uint256::solidity_name(&mut out, tc).expect("no fmt error");
+			collected.push(out);
+		}
+		collected
+	}
+
+	fn len() -> usize {
+		2
+	}
+}
+impl SolidityTypeName for EthCrossAccount {
+	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		write!(writer, "{}", tc.collect_struct::<Self>())
+	}
+
+	fn is_simple() -> bool {
+		false
+	}
+
+	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		write!(writer, "{}(", tc.collect_tuple::<Self>())?;
+		address::solidity_default(writer, tc)?;
+		write!(writer, ",")?;
+		uint256::solidity_default(writer, tc)?;
+		write!(writer, ")")
+	}
+}
+
+impl StructCollect for EthCrossAccount {
+	fn name() -> String {
+		"EthCrossAccount".into()
+	}
+
+	fn declaration() -> String {
+		let mut str = String::new();
+		writeln!(str, "/// @dev Cross account struct").unwrap();
+		writeln!(str, "struct {} {{", Self::name()).unwrap();
+		writeln!(str, "\taddress eth;").unwrap();
+		writeln!(str, "\tuint256 sub;").unwrap();
+		writeln!(str, "}}").unwrap();
+		str
+	}
+}
+
 pub trait SolidityTupleType {
 	fn names(tc: &TypeCollector) -> Vec<String>;
 	fn len() -> usize;
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -16,7 +16,7 @@
 
 //! The module contains a number of functions for converting and checking ethereum identifiers.
 
-use evm_coder::types::{uint256, address};
+use evm_coder::types::{uint256, address, EthCrossAccount};
 pub use pallet_evm::account::{Config, CrossAccountId};
 use sp_core::H160;
 use up_data_structs::CollectionId;
modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -1,627 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev 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;
-	}
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb3152af3
-contract Collection is Dummy, ERC165 {
-	/// Set collection property.
-	///
-	/// @param key Property key.
-	/// @param value Propery value.
-	/// @dev EVM selector for this function is: 0x2f073f66,
-	///  or in textual repr: setCollectionProperty(string,bytes)
-	function setCollectionProperty(string memory key, bytes memory value) public {
-		require(false, stub_error);
-		key;
-		value;
-		dummy = 0;
-	}
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Tuple10[] memory properties) public {
-		require(false, stub_error);
-		properties;
-		dummy = 0;
-	}
-
-	/// Delete collection property.
-	///
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x7b7debce,
-	///  or in textual repr: deleteCollectionProperty(string)
-	function deleteCollectionProperty(string memory key) public {
-		require(false, stub_error);
-		key;
-		dummy = 0;
-	}
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) public {
-		require(false, stub_error);
-		keys;
-		dummy = 0;
-	}
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) public view returns (bytes memory) {
-		require(false, stub_error);
-		key;
-		dummy;
-		return hex"";
-	}
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) public view returns (Tuple10[] memory) {
-		require(false, stub_error);
-		keys;
-		dummy;
-		return new Tuple10[](0);
-	}
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x7623402e,
-	///  or in textual repr: setCollectionSponsor(address)
-	function setCollectionSponsor(address sponsor) public {
-		require(false, stub_error);
-		sponsor;
-		dummy = 0;
-	}
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(Tuple6 memory sponsor) public {
-		require(false, stub_error);
-		sponsor;
-		dummy = 0;
-	}
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() public view returns (bool) {
-		require(false, stub_error);
-		dummy;
-		return false;
-	}
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	/// Get current sponsor.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	/// @dev EVM selector for this function is: 0x6ec0a9f1,
-	///  or in textual repr: collectionSponsor()
-	function collectionSponsor() public view returns (Tuple6 memory) {
-		require(false, stub_error);
-		dummy;
-		return Tuple6(0x0000000000000000000000000000000000000000, 0);
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"accountTokenOwnershipLimit",
-	/// 	"sponsoredDataSize",
-	/// 	"sponsoredDataRateLimit",
-	/// 	"tokenLimit",
-	/// 	"sponsorTransferTimeout",
-	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
-	/// 	"ownerCanDestroy",
-	/// 	"transfersEnabled"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() public view returns (address) {
-		require(false, stub_error);
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
-	}
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(Tuple6 memory newAdmin) public {
-		require(false, stub_error);
-		newAdmin;
-		dummy = 0;
-	}
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(Tuple6 memory admin) public {
-		require(false, stub_error);
-		admin;
-		dummy = 0;
-	}
-
-	/// Add collection admin.
-	/// @param newAdmin Address of the added administrator.
-	/// @dev EVM selector for this function is: 0x92e462c7,
-	///  or in textual repr: addCollectionAdmin(address)
-	function addCollectionAdmin(address newAdmin) public {
-		require(false, stub_error);
-		newAdmin;
-		dummy = 0;
-	}
-
-	/// Remove collection admin.
-	///
-	/// @param admin Address of the removed administrator.
-	/// @dev EVM selector for this function is: 0xfafd7b42,
-	///  or in textual repr: removeCollectionAdmin(address)
-	function removeCollectionAdmin(address admin) public {
-		require(false, stub_error);
-		admin;
-		dummy = 0;
-	}
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	/// @dev EVM selector for this function is: 0x112d4586,
-	///  or in textual repr: setCollectionNesting(bool)
-	function setCollectionNesting(bool enable) public {
-		require(false, stub_error);
-		enable;
-		dummy = 0;
-	}
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	/// @param collections Addresses of collections that will be available for nesting.
-	/// @dev EVM selector for this function is: 0x64872396,
-	///  or in textual repr: setCollectionNesting(bool,address[])
-	function setCollectionNesting(bool enable, address[] memory collections) public {
-		require(false, stub_error);
-		enable;
-		collections;
-		dummy = 0;
-	}
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) public view returns (bool) {
-		require(false, stub_error);
-		user;
-		dummy;
-		return false;
-	}
-
-	/// Add the user to the allowed list.
-	///
-	/// @param user Address of a trusted user.
-	/// @dev EVM selector for this function is: 0x67844fe6,
-	///  or in textual repr: addToCollectionAllowList(address)
-	function addToCollectionAllowList(address user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(Tuple6 memory user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	/// Remove the user from the allowed list.
-	///
-	/// @param user Address of a removed user.
-	/// @dev EVM selector for this function is: 0x85c51acb,
-	///  or in textual repr: removeFromCollectionAllowList(address)
-	function removeFromCollectionAllowList(address user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(Tuple6 memory user) public {
-		require(false, stub_error);
-		user;
-		dummy = 0;
-	}
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x9811b0c7,
-	///  or in textual repr: isOwnerOrAdmin(address)
-	function isOwnerOrAdmin(address user) public view returns (bool) {
-		require(false, stub_error);
-		user;
-		dummy;
-		return false;
-	}
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(Tuple6 memory user) public view returns (bool) {
-		require(false, stub_error);
-		user;
-		dummy;
-		return false;
-	}
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() public view returns (Tuple6 memory) {
-		require(false, stub_error);
-		dummy;
-		return Tuple6(0x0000000000000000000000000000000000000000, 0);
-	}
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner account
-	/// @dev EVM selector for this function is: 0x4f53e226,
-	///  or in textual repr: changeCollectionOwner(address)
-	function changeCollectionOwner(address newOwner) public {
-		require(false, stub_error);
-		newOwner;
-		dummy = 0;
-	}
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() public view returns (Tuple6[] memory) {
-		require(false, stub_error);
-		dummy;
-		return new Tuple6[](0);
-	}
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0xe5c9913f,
-	///  or in textual repr: setOwnerCross((address,uint256))
-	function setOwnerCross(Tuple6 memory newOwner) public {
-		require(false, stub_error);
-		newOwner;
-		dummy = 0;
-	}
-}
-
-/// @dev anonymous struct
-struct Tuple10 {
-	string field_0;
-	bytes field_1;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x032e5926
-contract ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(Tuple6 memory spender, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		spender;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0x79cc6790,
-	///  or in textual repr: burnFrom(address,uint256)
-	function burnFrom(address from, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		from;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(Tuple6 memory from, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		from;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// Mint tokens for multiple accounts.
-	/// @param amounts array of pairs of account address and amount
-	/// @dev EVM selector for this function is: 0x1acf2d55,
-	///  or in textual repr: mintBulk((address,uint256)[])
-	function mintBulk(Tuple6[] memory amounts) public returns (bool) {
-		require(false, stub_error);
-		amounts;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		Tuple6 memory from,
-		Tuple6 memory to,
-		uint256 amount
-	) public returns (bool) {
-		require(false, stub_error);
-		from;
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-}
-
-/// @dev anonymous struct
-struct Tuple6 {
-	address field_0;
-	uint256 field_1;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-contract ERC20Mintable is Dummy, ERC165 {
-	/// Mint tokens for `to` account.
-	/// @param to account that will receive minted tokens
-	/// @param amount amount of tokens to mint
-	/// @dev EVM selector for this function is: 0x40c10f19,
-	///  or in textual repr: mint(address,uint256)
-	function mint(address to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-}
-
-/// @dev inlined interface
-contract ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-contract ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() public view returns (string memory) {
-		require(false, stub_error);
-		dummy;
-		return "";
-	}
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() public view returns (uint8) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		dummy;
-		return 0;
-	}
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) public returns (bool) {
-		require(false, stub_error);
-		from;
-		to;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		spender;
-		amount;
-		dummy = 0;
-		return false;
-	}
-
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) public view returns (uint256) {
-		require(false, stub_error);
-		owner;
-		spender;
-		dummy;
-		return 0;
-	}
-}
-
-contract UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -715,13 +715,13 @@
 	fn transfer_from_cross(
 		&mut self,
 		caller: caller,
-		from: (address, uint256),
-		to: (address, uint256),
+		from: EthCrossAccount,
+		to: EthCrossAccount,
 		token_id: uint256,
 	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		let from = convert_tuple_to_cross_account::<T>(from)?;
-		let to = convert_tuple_to_cross_account::<T>(to)?;
+		let from = from.into_sub_cross_account::<T>()?;
+		let to = to.into_sub_cross_account::<T>()?;
 		let token_id = token_id.try_into()?;
 		let budget = self
 			.recorder
modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -238,10 +238,17 @@
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
 	/// @dev EVM selector for this function is: 0x6ec0a9f1,
 	///  or in textual repr: collectionSponsor()
+<<<<<<< HEAD
 	function collectionSponsor() public view returns (Tuple6 memory) {
 		require(false, stub_error);
 		dummy;
 		return Tuple6(0x0000000000000000000000000000000000000000, 0);
+=======
+	function collectionSponsor() public view returns (Tuple19 memory) {
+		require(false, stub_error);
+		dummy;
+		return Tuple19(0x0000000000000000000000000000000000000000, 0);
+>>>>>>> feat: add `EthCrossAccount` type
 	}
 
 	/// Set limits for the collection.
@@ -475,10 +482,17 @@
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
+<<<<<<< HEAD
 	function collectionOwner() public view returns (Tuple6 memory) {
 		require(false, stub_error);
 		dummy;
 		return Tuple6(0x0000000000000000000000000000000000000000, 0);
+=======
+	function collectionOwner() public view returns (Tuple19 memory) {
+		require(false, stub_error);
+		dummy;
+		return Tuple19(0x0000000000000000000000000000000000000000, 0);
+>>>>>>> feat: add `EthCrossAccount` type
 	}
 
 	/// Changes collection owner to another account
@@ -520,8 +534,8 @@
 
 /// @dev anonymous struct
 struct Tuple19 {
-	string field_0;
-	bytes field_1;
+	address field_0;
+	uint256 field_1;
 }
 
 /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
@@ -813,10 +827,17 @@
 	string field_1;
 }
 
+<<<<<<< HEAD
 /// @dev anonymous struct
 struct Tuple6 {
 	address field_0;
 	uint256 field_1;
+=======
+/// @dev Cross account struct
+struct EthCrossAccount {
+	address eth;
+	uint256 sub;
+>>>>>>> feat: add `EthCrossAccount` type
 }
 
 /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -730,18 +730,18 @@
 		token_id: uint256,
 	) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		let from = convert_tuple_to_cross_account::<T>(from)?;
-		let to = convert_tuple_to_cross_account::<T>(to)?;
-		let token_id = token_id.try_into()?;
-		let budget = self
-			.recorder
-			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+		// let from = convert_tuple_to_cross_account::<T>(from)?;
+		// let to = convert_tuple_to_cross_account::<T>(to)?;
+		// let token_id = token_id.try_into()?;
+		// let budget = self
+		// 	.recorder
+		// 	.weight_calls_budget(<StructureWeight<T>>::find_parent());
 
-		let balance = balance(self, token_id, &from)?;
-		ensure_single_owner(self, token_id, balance)?;
+		// let balance = balance(self, token_id, &from)?;
+		// ensure_single_owner(self, token_id, balance)?;
 
-		Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, balance, &budget)
-			.map_err(dispatch_to_evm::<T>)?;
+		// Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, balance, &budget)
+		// 	.map_err(dispatch_to_evm::<T>)?;
 		Ok(())
 	}
 
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -1,393 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb3152af3
-interface Collection is Dummy, ERC165 {
-	/// Set collection property.
-	///
-	/// @param key Property key.
-	/// @param value Propery value.
-	/// @dev EVM selector for this function is: 0x2f073f66,
-	///  or in textual repr: setCollectionProperty(string,bytes)
-	function setCollectionProperty(string memory key, bytes memory value) external;
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Tuple10[] memory properties) external;
-
-	/// Delete collection property.
-	///
-	/// @param key Property key.
-	/// @dev EVM selector for this function is: 0x7b7debce,
-	///  or in textual repr: deleteCollectionProperty(string)
-	function deleteCollectionProperty(string memory key) external;
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) external;
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) external view returns (bytes memory);
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) external view returns (Tuple10[] memory);
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x7623402e,
-	///  or in textual repr: setCollectionSponsor(address)
-	function setCollectionSponsor(address sponsor) external;
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(Tuple6 memory sponsor) external;
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() external view returns (bool);
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() external;
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() external;
-
-	/// Get current sponsor.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	/// @dev EVM selector for this function is: 0x6ec0a9f1,
-	///  or in textual repr: collectionSponsor()
-	function collectionSponsor() external view returns (Tuple6 memory);
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"accountTokenOwnershipLimit",
-	/// 	"sponsoredDataSize",
-	/// 	"sponsoredDataRateLimit",
-	/// 	"tokenLimit",
-	/// 	"sponsorTransferTimeout",
-	/// 	"sponsorApproveTimeout"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x6a3841db,
-	///  or in textual repr: setCollectionLimit(string,uint32)
-	function setCollectionLimit(string memory limit, uint32 value) external;
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Name of the limit. Valid names:
-	/// 	"ownerCanTransfer",
-	/// 	"ownerCanDestroy",
-	/// 	"transfersEnabled"
-	/// @param value Value of the limit.
-	/// @dev EVM selector for this function is: 0x993b7fba,
-	///  or in textual repr: setCollectionLimit(string,bool)
-	function setCollectionLimit(string memory limit, bool value) external;
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() external view returns (address);
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(Tuple6 memory newAdmin) external;
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(Tuple6 memory admin) external;
-
-	/// Add collection admin.
-	/// @param newAdmin Address of the added administrator.
-	/// @dev EVM selector for this function is: 0x92e462c7,
-	///  or in textual repr: addCollectionAdmin(address)
-	function addCollectionAdmin(address newAdmin) external;
-
-	/// Remove collection admin.
-	///
-	/// @param admin Address of the removed administrator.
-	/// @dev EVM selector for this function is: 0xfafd7b42,
-	///  or in textual repr: removeCollectionAdmin(address)
-	function removeCollectionAdmin(address admin) external;
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	/// @dev EVM selector for this function is: 0x112d4586,
-	///  or in textual repr: setCollectionNesting(bool)
-	function setCollectionNesting(bool enable) external;
-
-	/// Toggle accessibility of collection nesting.
-	///
-	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	/// @param collections Addresses of collections that will be available for nesting.
-	/// @dev EVM selector for this function is: 0x64872396,
-	///  or in textual repr: setCollectionNesting(bool,address[])
-	function setCollectionNesting(bool enable, address[] memory collections) external;
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) external;
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) external view returns (bool);
-
-	/// Add the user to the allowed list.
-	///
-	/// @param user Address of a trusted user.
-	/// @dev EVM selector for this function is: 0x67844fe6,
-	///  or in textual repr: addToCollectionAllowList(address)
-	function addToCollectionAllowList(address user) external;
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(Tuple6 memory user) external;
-
-	/// Remove the user from the allowed list.
-	///
-	/// @param user Address of a removed user.
-	/// @dev EVM selector for this function is: 0x85c51acb,
-	///  or in textual repr: removeFromCollectionAllowList(address)
-	function removeFromCollectionAllowList(address user) external;
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(Tuple6 memory user) external;
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) external;
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x9811b0c7,
-	///  or in textual repr: isOwnerOrAdmin(address)
-	function isOwnerOrAdmin(address user) external view returns (bool);
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(Tuple6 memory user) external view returns (bool);
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() external view returns (string memory);
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (Tuple6 memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner account
-	/// @dev EVM selector for this function is: 0x4f53e226,
-	///  or in textual repr: changeCollectionOwner(address)
-	function changeCollectionOwner(address newOwner) external;
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() external view returns (Tuple6[] memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0xe5c9913f,
-	///  or in textual repr: setOwnerCross((address,uint256))
-	function setOwnerCross(Tuple6 memory newOwner) external;
-}
-
-/// @dev anonymous struct
-struct Tuple10 {
-	string field_0;
-	bytes field_1;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x032e5926
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(Tuple6 memory spender, uint256 amount) external returns (bool);
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0x79cc6790,
-	///  or in textual repr: burnFrom(address,uint256)
-	function burnFrom(address from, uint256 amount) external returns (bool);
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(Tuple6 memory from, uint256 amount) external returns (bool);
-
-	/// Mint tokens for multiple accounts.
-	/// @param amounts array of pairs of account address and amount
-	/// @dev EVM selector for this function is: 0x1acf2d55,
-	///  or in textual repr: mintBulk((address,uint256)[])
-	function mintBulk(Tuple6[] memory amounts) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		Tuple6 memory from,
-		Tuple6 memory to,
-		uint256 amount
-	) external returns (bool);
-}
-
-/// @dev anonymous struct
-struct Tuple6 {
-	address field_0;
-	uint256 field_1;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-interface ERC20Mintable is Dummy, ERC165 {
-	/// Mint tokens for `to` account.
-	/// @param to account that will receive minted tokens
-	/// @param amount amount of tokens to mint
-	/// @dev EVM selector for this function is: 0x40c10f19,
-	///  or in textual repr: mint(address,uint256)
-	function mint(address to, uint256 amount) external returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() external view returns (uint8);
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -159,7 +159,7 @@
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
 	/// @dev EVM selector for this function is: 0x6ec0a9f1,
 	///  or in textual repr: collectionSponsor()
-	function collectionSponsor() external view returns (Tuple6 memory);
+	function collectionSponsor() external view returns (Tuple8 memory);
 
 	/// Set limits for the collection.
 	/// @dev Throws error if limit not found.
@@ -310,7 +310,7 @@
 	/// If address is canonical then substrate mirror is zero and vice versa.
 	/// @dev EVM selector for this function is: 0xdf727d3b,
 	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (Tuple6 memory);
+	function collectionOwner() external view returns (Tuple8 memory);
 
 	/// Changes collection owner to another account
 	///
@@ -339,8 +339,8 @@
 
 /// @dev anonymous struct
 struct Tuple19 {
-	string field_0;
-	bytes field_1;
+	address field_0;
+	uint256 field_1;
 }
 
 /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
@@ -524,7 +524,6 @@
 	// /// @dev EVM selector for this function is: 0x36543006,
 	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
 	// function mintBulkWithTokenURI(address to, Tuple8[] memory tokens) external returns (bool);
-
 }
 
 /// @dev anonymous struct
@@ -534,7 +533,7 @@
 }
 
 /// @dev anonymous struct
-struct Tuple6 {
+struct Tuple8 {
 	address field_0;
 	uint256 field_1;
 }
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -250,7 +250,11 @@
           { "internalType": "address", "name": "field_0", "type": "address" },
           { "internalType": "uint256", "name": "field_1", "type": "uint256" }
         ],
+<<<<<<< HEAD
         "internalType": "struct Tuple6",
+=======
+        "internalType": "struct Tuple19",
+>>>>>>> feat: add `EthCrossAccount` type
         "name": "",
         "type": "tuple"
       }
@@ -293,7 +297,11 @@
           { "internalType": "address", "name": "field_0", "type": "address" },
           { "internalType": "uint256", "name": "field_1", "type": "uint256" }
         ],
+<<<<<<< HEAD
         "internalType": "struct Tuple6",
+=======
+        "internalType": "struct Tuple19",
+>>>>>>> feat: add `EthCrossAccount` type
         "name": "",
         "type": "tuple"
       }
@@ -794,7 +802,11 @@
           { "internalType": "address", "name": "field_0", "type": "address" },
           { "internalType": "uint256", "name": "field_1", "type": "uint256" }
         ],
+<<<<<<< HEAD
         "internalType": "struct Tuple6",
+=======
+        "internalType": "struct EthCrossAccount",
+>>>>>>> feat: add `EthCrossAccount` type
         "name": "from",
         "type": "tuple"
       },
@@ -803,7 +815,11 @@
           { "internalType": "address", "name": "field_0", "type": "address" },
           { "internalType": "uint256", "name": "field_1", "type": "uint256" }
         ],
+<<<<<<< HEAD
         "internalType": "struct Tuple6",
+=======
+        "internalType": "struct EthCrossAccount",
+>>>>>>> feat: add `EthCrossAccount` type
         "name": "to",
         "type": "tuple"
       },