git.delta.rocks / unique-network / refs/commits / 3f089fc34b06

difftreelog

refactor EthCrossAccount impl, signature some evm methods, tests and stubs

PraetorP2022-12-14parent: #1f3c059.patch.diff
in: master

16 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -36,7 +36,7 @@
 use crate::{
 	Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,
 	eth::{
-		EthCrossAccount, convert_cross_account_to_uint256, CollectionPermissions as EvmPermissions,
+		EthCrossAccount, CollectionPermissions as EvmPermissions,
 		CollectionLimits as EvmCollectionLimits,
 	},
 	weights::WeightInfo,
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
before · pallets/common/src/eth.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! The module contains a number of functions for converting and checking ethereum identifiers.1819use evm_coder::{20	AbiCoder,21	types::{uint256, address},22};23pub use pallet_evm::{Config, account::CrossAccountId};24use sp_core::H160;25use up_data_structs::CollectionId;2627// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 128// TODO: Unhardcode prefix29const ETH_COLLECTION_PREFIX: [u8; 16] = [30	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,31];3233/// Maps the ethereum address of the collection in substrate.34pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {35	if eth[0..16] != ETH_COLLECTION_PREFIX {36		return None;37	}38	let mut id_bytes = [0; 4];39	id_bytes.copy_from_slice(&eth[16..20]);40	Some(CollectionId(u32::from_be_bytes(id_bytes)))41}4243/// Maps the substrate collection id in ethereum.44pub fn collection_id_to_address(id: CollectionId) -> H160 {45	let mut out = [0; 20];46	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);47	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));48	H160(out)49}5051/// Check if the ethereum address is a collection.52pub fn is_collection(address: &H160) -> bool {53	address[0..16] == ETH_COLLECTION_PREFIX54}5556/// Convert `CrossAccountId` to `uint256`.57pub fn convert_cross_account_to_uint256<T: Config>(from: &T::CrossAccountId) -> uint25658where59	T::AccountId: AsRef<[u8; 32]>,60{61	let slice = from.as_sub().as_ref();62	uint256::from_big_endian(slice)63}6465/// Convert `uint256` to `CrossAccountId`.66pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId67where68	T::AccountId: From<[u8; 32]>,69{70	let mut new_admin_arr = [0_u8; 32];71	from.to_big_endian(&mut new_admin_arr);72	let account_id = T::AccountId::from(new_admin_arr);73	T::CrossAccountId::from_sub(account_id)74}7576/// Convert `CrossAccountId` to `(address, uint256)`.77pub fn convert_cross_account_to_tuple<T: Config>(78	cross_account_id: &T::CrossAccountId,79) -> (address, uint256)80where81	T::AccountId: AsRef<[u8; 32]>,82{83	if cross_account_id.is_canonical_substrate() {84		let sub = convert_cross_account_to_uint256::<T>(cross_account_id);85		(Default::default(), sub)86	} else {87		let eth = *cross_account_id.as_eth();88		(eth, Default::default())89	}90}9192/// Convert tuple `(address, uint256)` to `CrossAccountId`.93///94/// If `address` in the tuple has *default* value, then the canonical form is substrate,95/// if `uint256` has *default* value, then the ethereum form is canonical,96/// if both values are *default* or *non default*, then this is considered an invalid address and `Error` is returned.97pub fn convert_tuple_to_cross_account<T: Config>(98	eth_cross_account_id: (address, uint256),99) -> evm_coder::execution::Result<T::CrossAccountId>100where101	T::AccountId: From<[u8; 32]>,102{103	if eth_cross_account_id == Default::default() {104		Err("All fields of cross account is zeroed".into())105	} else if eth_cross_account_id.0 == Default::default() {106		Ok(convert_uint256_to_cross_account::<T>(107			eth_cross_account_id.1,108		))109	} else if eth_cross_account_id.1 == Default::default() {110		Ok(T::CrossAccountId::from_eth(eth_cross_account_id.0))111	} else {112		Err("All fields of cross account is non zeroed".into())113	}114}115116/// Cross account struct117#[derive(Debug, Default, AbiCoder)]118pub struct EthCrossAccount {119	pub(crate) eth: address,120	pub(crate) sub: uint256,121}122123impl EthCrossAccount {124	/// Converts `CrossAccountId` to `EthCrossAccountId`125	pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self126	where127		T: pallet_evm::Config,128		T::AccountId: AsRef<[u8; 32]>,129	{130		if cross_account_id.is_canonical_substrate() {131			Self {132				eth: Default::default(),133				sub: convert_cross_account_to_uint256::<T>(cross_account_id),134			}135		} else {136			Self {137				eth: *cross_account_id.as_eth(),138				sub: Default::default(),139			}140		}141	}142	/// Creates `EthCrossAccount` from substrate account143	pub fn from_sub<T>(account_id: &T::AccountId) -> Self144	where145		T: pallet_evm::Config,146		T::AccountId: AsRef<[u8; 32]>,147	{148		Self {149			eth: Default::default(),150			sub: uint256::from_big_endian(account_id.as_ref()),151		}152	}153	/// Converts `EthCrossAccount` to `CrossAccountId`154	pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>155	where156		T: pallet_evm::Config,157		T::AccountId: From<[u8; 32]>,158	{159		if self.eth == Default::default() && self.sub == Default::default() {160			Err("All fields of cross account is zeroed".into())161		} else if self.eth == Default::default() {162			Ok(convert_uint256_to_cross_account::<T>(self.sub))163		} else if self.sub == Default::default() {164			Ok(T::CrossAccountId::from_eth(self.eth))165		} else {166			Err("All fields of cross account is non zeroed".into())167		}168	}169}170171/// [`CollectionLimits`](up_data_structs::CollectionLimits) representation for EVM.172#[derive(Debug, Default, Clone, Copy, AbiCoder)]173#[repr(u8)]174pub enum CollectionLimits {175	/// How many tokens can a user have on one account.176	#[default]177	AccountTokenOwnership,178	/// How many bytes of data are available for sponsorship.179	SponsoredDataSize,180	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]181	SponsoredDataRateLimit,182	/// How many tokens can be mined into this collection.183	TokenLimit,184	/// Timeouts for transfer sponsoring.185	SponsorTransferTimeout,186	/// Timeout for sponsoring an approval in passed blocks.187	SponsorApproveTimeout,188	/// Whether the collection owner of the collection can send tokens (which belong to other users).189	OwnerCanTransfer,190	/// Can the collection owner burn other people's tokens.191	OwnerCanDestroy,192	/// Is it possible to send tokens from this collection between users.193	TransferEnabled,194}195#[derive(Default, Debug, Clone, Copy, AbiCoder)]196#[repr(u8)]197pub enum CollectionPermissions {198	#[default]199	CollectionAdmin,200	TokenOwner,201}202203/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.204#[derive(AbiCoder, Copy, Clone, Default, Debug)]205#[repr(u8)]206pub enum EthTokenPermissions {207	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]208	#[default]209	Mutable,210211	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]212	TokenOwner,213214	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]215	CollectionAdmin,216}
after · pallets/common/src/eth.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! The module contains a number of functions for converting and checking ethereum identifiers.1819use evm_coder::{20	AbiCoder,21	types::{uint256, address},22};23pub use pallet_evm::{Config, account::CrossAccountId};24use sp_core::H160;25use up_data_structs::CollectionId;2627// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 128// TODO: Unhardcode prefix29const ETH_COLLECTION_PREFIX: [u8; 16] = [30	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,31];3233/// Maps the ethereum address of the collection in substrate.34pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {35	if eth[0..16] != ETH_COLLECTION_PREFIX {36		return None;37	}38	let mut id_bytes = [0; 4];39	id_bytes.copy_from_slice(&eth[16..20]);40	Some(CollectionId(u32::from_be_bytes(id_bytes)))41}4243/// Maps the substrate collection id in ethereum.44pub fn collection_id_to_address(id: CollectionId) -> H160 {45	let mut out = [0; 20];46	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);47	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));48	H160(out)49}5051/// Check if the ethereum address is a collection.52pub fn is_collection(address: &H160) -> bool {53	address[0..16] == ETH_COLLECTION_PREFIX54}5556/// Convert `uint256` to `CrossAccountId`.57pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId58where59	T::AccountId: From<[u8; 32]>,60{61	let mut new_admin_arr = [0_u8; 32];62	from.to_big_endian(&mut new_admin_arr);63	let account_id = T::AccountId::from(new_admin_arr);64	T::CrossAccountId::from_sub(account_id)65}6667/// Convert tuple `(address, uint256)` to `CrossAccountId`.68///69/// If `address` in the tuple has *default* value, then the canonical form is substrate,70/// if `uint256` has *default* value, then the ethereum form is canonical,71/// if both values are *default* or *non default*, then this is considered an invalid address and `Error` is returned.72pub fn convert_tuple_to_cross_account<T: Config>(73	eth_cross_account_id: (address, uint256),74) -> evm_coder::execution::Result<T::CrossAccountId>75where76	T::AccountId: From<[u8; 32]>,77{78	if eth_cross_account_id == Default::default() {79		Err("All fields of cross account is zeroed".into())80	} else if eth_cross_account_id.0 == Default::default() {81		Ok(convert_uint256_to_cross_account::<T>(82			eth_cross_account_id.1,83		))84	} else if eth_cross_account_id.1 == Default::default() {85		Ok(T::CrossAccountId::from_eth(eth_cross_account_id.0))86	} else {87		Err("All fields of cross account is non zeroed".into())88	}89}9091/// Cross account struct92#[derive(Debug, Default, AbiCoder)]93pub struct EthCrossAccount {94	pub(crate) eth: address,95	pub(crate) sub: uint256,96}9798impl EthCrossAccount {99	/// Converts `CrossAccountId` to `EthCrossAccountId`100	pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self101	where102		T: pallet_evm::Config,103		T::AccountId: AsRef<[u8; 32]>,104	{105		if cross_account_id.is_canonical_substrate() {106			Self::from_sub::<T>(cross_account_id.as_sub())107		} else {108			Self {109				eth: *cross_account_id.as_eth(),110				sub: Default::default(),111			}112		}113	}114	/// Creates `EthCrossAccount` from substrate account115	pub fn from_sub<T>(account_id: &T::AccountId) -> Self116	where117		T: pallet_evm::Config,118		T::AccountId: AsRef<[u8; 32]>,119	{120		Self {121			eth: Default::default(),122			sub: uint256::from_big_endian(account_id.as_ref()),123		}124	}125	/// Converts `EthCrossAccount` to `CrossAccountId`126	pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>127	where128		T: pallet_evm::Config,129		T::AccountId: From<[u8; 32]>,130	{131		if self.eth == Default::default() && self.sub == Default::default() {132			Err("All fields of cross account is zeroed".into())133		} else if self.eth == Default::default() {134			Ok(convert_uint256_to_cross_account::<T>(self.sub))135		} else if self.sub == Default::default() {136			Ok(T::CrossAccountId::from_eth(self.eth))137		} else {138			Err("All fields of cross account is non zeroed".into())139		}140	}141}142143/// [`CollectionLimits`](up_data_structs::CollectionLimits) representation for EVM.144#[derive(Debug, Default, Clone, Copy, AbiCoder)]145#[repr(u8)]146pub enum CollectionLimits {147	/// How many tokens can a user have on one account.148	#[default]149	AccountTokenOwnership,150	/// How many bytes of data are available for sponsorship.151	SponsoredDataSize,152	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]153	SponsoredDataRateLimit,154	/// How many tokens can be mined into this collection.155	TokenLimit,156	/// Timeouts for transfer sponsoring.157	SponsorTransferTimeout,158	/// Timeout for sponsoring an approval in passed blocks.159	SponsorApproveTimeout,160	/// Whether the collection owner of the collection can send tokens (which belong to other users).161	OwnerCanTransfer,162	/// Can the collection owner burn other people's tokens.163	OwnerCanDestroy,164	/// Is it possible to send tokens from this collection between users.165	TransferEnabled,166}167#[derive(Default, Debug, Clone, Copy, AbiCoder)]168#[repr(u8)]169pub enum CollectionPermissions {170	#[default]171	CollectionAdmin,172	TokenOwner,173}174175/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.176#[derive(AbiCoder, Copy, Clone, Default, Debug)]177#[repr(u8)]178pub enum EthTokenPermissions {179	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]180	#[default]181	Mutable,182183	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]184	TokenOwner,185186	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]187	CollectionAdmin,188}
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -50,6 +50,7 @@
     "pallet-evm-coder-substrate/std",
     "pallet-evm/std",
     "up-sponsorship/std",
+    "pallet-common/std",
 ]
 try-runtime = ["frame-support/try-runtime"]
-stubgen = ["evm-coder/stubgen"]
+stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"]
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -175,18 +175,11 @@
 	///
 	/// @param contractAddress The contract for which a sponsor is requested.
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	fn sponsor(&self, contract_address: address) -> Result<(address, uint256)> {
-		let sponsor =
-			Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?;
-		Ok(pallet_common::eth::convert_cross_account_to_tuple::<T>(
-			&sponsor,
+	fn sponsor(&self, contract_address: address) -> Result<EthCrossAccount> {
+		Ok(EthCrossAccount::from_sub_cross_account::<T>(
+			&Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?,
 		))
 	}
-	// fn sponsor(&self, contract_address: address) -> Result<EthCrossAccount> {
-	// 	Ok(EthCrossAccount::from_sub_cross_account::<T>(
-	// 		&Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?,
-	// 	))
-	// }
 
 	/// Check tat contract has confirmed sponsor.
 	///
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -96,11 +96,11 @@
 	/// @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: 0x766c4f37,
 	///  or in textual repr: sponsor(address)
-	function sponsor(address contractAddress) public view returns (Tuple0 memory) {
+	function sponsor(address contractAddress) public view returns (EthCrossAccount memory) {
 		require(false, stub_error);
 		contractAddress;
 		dummy;
-		return Tuple0(0x0000000000000000000000000000000000000000, 0);
+		return EthCrossAccount(0x0000000000000000000000000000000000000000, 0);
 	}
 
 	/// Check tat contract has confirmed sponsor.
@@ -265,8 +265,8 @@
 	}
 }
 
-/// @dev anonymous struct
-struct Tuple0 {
-	address field_0;
-	uint256 field_1;
+/// @dev Cross account struct
+struct EthCrossAccount {
+	address eth;
+	uint256 sub;
 }
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -605,7 +605,7 @@
 		Ok(false)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	#[weight(<SelfWeightOf<T>>::create_item())]
@@ -618,7 +618,7 @@
 		Ok(token_id)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @dev `tokenId` should be obtained with `nextTokenId` method,
 	///  unlike standard, you can't specify it manually
 	/// @param to The new owner
@@ -1070,7 +1070,7 @@
 		Ok(true)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -738,7 +738,7 @@
 		return false;
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	/// @dev EVM selector for this function is: 0x6a627842,
@@ -750,7 +750,7 @@
 		return 0;
 	}
 
-	// /// @notice Function to mint token.
+	// /// @notice Function to a mint token.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
 	// /// @param to The new owner
@@ -995,7 +995,7 @@
 	// 	return false;
 	// }
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -637,7 +637,7 @@
 		Ok(false)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	#[weight(<SelfWeightOf<T>>::create_item())]
@@ -650,7 +650,7 @@
 		Ok(token_id)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @dev `tokenId` should be obtained with `nextTokenId` method,
 	///  unlike standard, you can't specify it manually
 	/// @param to The new owner
@@ -1120,7 +1120,7 @@
 		Ok(true)
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -733,7 +733,7 @@
 		return false;
 	}
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	/// @dev EVM selector for this function is: 0x6a627842,
@@ -745,7 +745,7 @@
 		return 0;
 	}
 
-	// /// @notice Function to mint token.
+	// /// @notice Function to a mint token.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
 	// /// @param to The new owner
@@ -979,7 +979,7 @@
 	// 	return false;
 	// }
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedtests/src/eth/abi/contractHelpers.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/contractHelpers.json
+++ b/tests/src/eth/abi/contractHelpers.json
@@ -223,10 +223,10 @@
     "outputs": [
       {
         "components": [
-          { "internalType": "address", "name": "field_0", "type": "address" },
-          { "internalType": "uint256", "name": "field_1", "type": "uint256" }
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
         ],
-        "internalType": "struct Tuple0",
+        "internalType": "struct EthCrossAccount",
         "name": "",
         "type": "tuple"
       }
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -69,7 +69,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: 0x766c4f37,
 	///  or in textual repr: sponsor(address)
-	function sponsor(address contractAddress) external view returns (Tuple0 memory);
+	function sponsor(address contractAddress) external view returns (EthCrossAccount memory);
 
 	/// Check tat contract has confirmed sponsor.
 	///
@@ -171,8 +171,8 @@
 	function toggleAllowlist(address contractAddress, bool enabled) external;
 }
 
-/// @dev anonymous struct
-struct Tuple0 {
-	address field_0;
-	uint256 field_1;
+/// @dev Cross account struct
+struct EthCrossAccount {
+	address eth;
+	uint256 sub;
 }
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -515,14 +515,14 @@
 	///  or in textual repr: mintingFinished()
 	function mintingFinished() external view returns (bool);
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	/// @dev EVM selector for this function is: 0x6a627842,
 	///  or in textual repr: mint(address)
 	function mint(address to) external returns (uint256);
 
-	// /// @notice Function to mint token.
+	// /// @notice Function to a mint token.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
 	// /// @param to The new owner
@@ -674,7 +674,7 @@
 	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
 	// function mintBulkWithTokenURI(address to, Tuple13[] memory tokens) external returns (bool);
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -513,14 +513,14 @@
 	///  or in textual repr: mintingFinished()
 	function mintingFinished() external view returns (bool);
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	/// @dev EVM selector for this function is: 0x6a627842,
 	///  or in textual repr: mint(address)
 	function mint(address to) external returns (uint256);
 
-	// /// @notice Function to mint token.
+	// /// @notice Function to a mint token.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
 	// /// @param to The new owner
@@ -666,7 +666,7 @@
 	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
 	// function mintBulkWithTokenURI(address to, Tuple12[] memory tokens) external returns (bool);
 
-	/// @notice Function to mint token.
+	/// @notice Function to a mint token.
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -17,7 +17,6 @@
 import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util';
 import {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
-import exp from 'constants';
 import {ITokenPropertyPermission} from '../util/playgrounds/types';
 
 
@@ -180,9 +179,16 @@
     const caller = await helper.eth.createAccountWithBalance(donor);
     const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);
     const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });
-    const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,
-      collectionAdmin: true,
-      mutable: true}}; });
+    const permissions: ITokenPropertyPermission[] = properties
+      .map(p => {
+        return {
+          key: p.key, permission: {
+            tokenOwner: true,
+            collectionAdmin: true,
+            mutable: true,
+          },
+        };
+      });
     
     
     const collection = await helper.nft.mintCollection(minter, {
@@ -198,7 +204,7 @@
     let tokenId = result.events.Transfer.returnValues.tokenId;
     expect(tokenId).to.be.equal(expectedTokenId);
 
-    const event = result.events.Transfer;
+    let event = result.events.Transfer;
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
@@ -206,10 +212,16 @@
     
     expectedTokenId = await contract.methods.nextTokenId().call();
     result = await contract.methods.mintCross(receiverCross, properties).send();
+    event = result.events.Transfer;
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
+    expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+    
     tokenId = result.events.Transfer.returnValues.tokenId;
-
+    
     expect(tokenId).to.be.equal(expectedTokenId);
-    
+
     expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
       .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));
   });
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -17,7 +17,7 @@
 import {Pallets, requirePalletsOrSkip} from '../util';
 import {expect, itEth, usingEthPlaygrounds} from './util';
 import {IKeyringPair} from '@polkadot/types/types';
-import { ITokenPropertyPermission } from '../util/playgrounds/types';
+import {ITokenPropertyPermission} from '../util/playgrounds/types';
 
 describe('Refungible: Information getting', () => {
   let donor: IKeyringPair;
@@ -159,7 +159,7 @@
     let tokenId = result.events.Transfer.returnValues.tokenId;
     expect(tokenId).to.be.equal(expectedTokenId);
 
-    const event = result.events.Transfer;
+    let event = result.events.Transfer;
     expect(event.address).to.be.equal(collectionAddress);
     expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
     expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
@@ -167,6 +167,12 @@
     
     expectedTokenId = await contract.methods.nextTokenId().call();
     result = await contract.methods.mintCross(receiverCross, properties).send();
+    event = result.events.Transfer;
+    expect(event.address).to.be.equal(collectionAddress);
+    expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+    expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
+    expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+    
     tokenId = result.events.Transfer.returnValues.tokenId;
 
     expect(tokenId).to.be.equal(expectedTokenId);