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

difftreelog

chore fix code review requests

Grigoriy Simonov2022-12-23parent: #39a2c66.patch.diff
in: master

3 files changed

modifiedruntime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth
before · runtime/common/ethereum/sponsoring/refungible.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//! Implements EVM sponsoring logic via TransactionValidityHack1819use core::convert::TryInto;20use pallet_common::CollectionHandle;21use pallet_evm::account::CrossAccountId;22use pallet_fungible::Config as FungibleConfig;23use pallet_refungible::Config as RefungibleConfig;24use pallet_nonfungible::Config as NonfungibleConfig;25use pallet_unique::Config as UniqueConfig;26use up_data_structs::{CreateItemData, CreateNftData, TokenId};2728use super::common;29use crate::runtime_common::sponsoring::*;3031use pallet_refungible::{32	erc::{33		ERC721BurnableCall, ERC721Call, ERC721EnumerableCall, ERC721MetadataCall,34		ERC721UniqueExtensionsCall, ERC721UniqueMintableCall, TokenPropertiesCall,35		UniqueRefungibleCall,36	},37	erc_token::{38		ERC1633Call, ERC20Call, ERC20UniqueExtensionsCall, RefungibleTokenHandle,39		UniqueRefungibleTokenCall,40	},41};4243pub fn call_sponsor<T>(44	call: UniqueRefungibleCall<T>,45	collection: CollectionHandle<T>,46	who: &T::CrossAccountId,47) -> Option<()>48where49	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,50{51	use UniqueRefungibleCall::*;5253	match call {54		// Readonly55		ERC165Call(_, _) => None,5657		ERC721Enumerable(call) => erc721::enumerable_call_sponsor(call, collection, who),58		ERC721Burnable(call) => erc721::burnable_call_sponsor(call, collection, who),59		ERC721Metadata(call) => erc721::metadata_call_sponsor(call, collection, who),60		Collection(call) => common::collection_call_sponsor(call, collection, who),61		ERC721(call) => erc721::call_sponsor(call, collection, who),62		ERC721UniqueExtensions(call) => {63			erc721::unique_extensions_call_sponsor(call, collection, who)64		}65		ERC721UniqueMintable(call) => erc721::unique_mintable_call_sponsor(call, collection, who),66		TokenProperties(call) => token_properties_call_sponsor(call, collection, who),67	}68}6970pub fn token_properties_call_sponsor<T>(71	call: TokenPropertiesCall<T>,72	collection: CollectionHandle<T>,73	who: &T::CrossAccountId,74) -> Option<()>75where76	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,77{78	use TokenPropertiesCall::*;7980	match call {81		// Readonly82		ERC165Call(_, _) | Property { .. } | TokenPropertyPermissions => None,8384		// Not sponsored85		SetTokenPropertyPermission { .. }86		| SetTokenPropertyPermissions { .. }87		| SetProperties { .. }88		| DeleteProperty { .. }89		| DeleteProperties { .. } => None,9091		SetProperty {92			token_id,93			key,94			value,95			..96		} => {97			let token_id = TokenId::try_from(token_id).ok()?;98			withdraw_set_token_property::<T>(&collection, &who, &token_id, key.len() + value.len())99		}100	}101}102103pub fn token_call_sponsor<T>(104	call: UniqueRefungibleTokenCall<T>,105	token: RefungibleTokenHandle<T>,106	who: &T::CrossAccountId,107) -> Option<()>108where109	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,110{111	use UniqueRefungibleTokenCall::*;112113	match call {114		// Readonly115		ERC165Call(_, _) => None,116117		ERC20(call) => erc20::call_sponsor(call, token, who),118		ERC20UniqueExtensions(call) => erc20::unique_extensions_call_sponsor(call, token, who),119		ERC1633(call) => erc1633::call_sponsor(call, token, who),120	}121}122123mod erc721 {124	use super::*;125126	pub fn call_sponsor<T>(127		call: ERC721Call<T>,128		collection: CollectionHandle<T>,129		_who: &T::CrossAccountId,130	) -> Option<()>131	where132		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,133	{134		use ERC721Call::*;135136		match call {137			// Readonly138			ERC165Call(_, _)139			| BalanceOf { .. }140			| OwnerOf { .. }141			| GetApproved { .. }142			| IsApprovedForAll { .. }143			| CollectionHelperAddress => None,144145			// Not sponsored146			SafeTransferFromWithData { .. }147			| SafeTransferFrom { .. }148			| SetApprovalForAll { .. } => None,149150			TransferFrom { token_id, from, .. } => {151				let token_id = TokenId::try_from(token_id).ok()?;152				let from = T::CrossAccountId::from_eth(from);153				withdraw_transfer::<T>(&collection, &from, &token_id)154			}155156			// Not supported157			Approve { .. } => None,158		}159	}160161	pub fn enumerable_call_sponsor<T>(162		call: ERC721EnumerableCall<T>,163		_collection: CollectionHandle<T>,164		_who: &T::CrossAccountId,165	) -> Option<()>166	where167		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,168	{169		use ERC721EnumerableCall::*;170171		match call {172			// Readonly173			ERC165Call(_, _) | TokenByIndex { .. } | TokenOfOwnerByIndex { .. } | TotalSupply => {174				None175			}176		}177	}178179	pub fn burnable_call_sponsor<T>(180		call: ERC721BurnableCall<T>,181		_collection: CollectionHandle<T>,182		_who: &T::CrossAccountId,183	) -> Option<()>184	where185		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,186	{187		use ERC721BurnableCall::*;188189		match call {190			// Readonly191			ERC165Call(_, _) => None,192193			// Not sponsored194			Burn { .. } => None,195		}196	}197198	pub fn metadata_call_sponsor<T>(199		call: ERC721MetadataCall<T>,200		_collection: CollectionHandle<T>,201		_who: &T::CrossAccountId,202	) -> Option<()>203	where204		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,205	{206		use ERC721MetadataCall::*;207208		match call {209			// Readonly210			ERC165Call(_, _) | NameProxy | SymbolProxy | TokenUri { .. } => None,211		}212	}213214	pub fn unique_extensions_call_sponsor<T>(215		call: ERC721UniqueExtensionsCall<T>,216		collection: CollectionHandle<T>,217		who: &T::CrossAccountId,218	) -> Option<()>219	where220		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,221	{222		use ERC721UniqueExtensionsCall::*;223224		match call {225			// Readonly226			ERC165Call(_, _)227			| Name228			| Symbol229			| Description230			| CrossOwnerOf { .. }231			| Properties { .. }232			| NextTokenId233			| TokenContractAddress { .. } => None,234235			// Not sponsored236			TransferCross { .. }237			| TransferFromCross { .. }238			| BurnFrom { .. }239			| BurnFromCross { .. }240			| MintCross { .. }241			| MintBulk { .. }242			| MintBulkWithTokenUri { .. } => None,243244			Transfer { token_id, .. } => {245				let token_id = TokenId::try_from(token_id).ok()?;246				withdraw_transfer::<T>(&collection, &who, &token_id)247			}248		}249	}250251	pub fn unique_mintable_call_sponsor<T>(252		call: ERC721UniqueMintableCall<T>,253		collection: CollectionHandle<T>,254		who: &T::CrossAccountId,255	) -> Option<()>256	where257		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,258	{259		use ERC721UniqueMintableCall::*;260261		match call {262			// Readonly263			ERC165Call(_, _) | MintingFinished => None,264265			// Not sponsored266			FinishMinting => None,267268			Mint { .. }269			| MintCheckId { .. }270			| MintWithTokenUri { .. }271			| MintWithTokenUriCheckId { .. } => withdraw_create_item::<T>(272				&collection,273				&who,274				&CreateItemData::NFT(CreateNftData::default()),275			),276		}277	}278}279280mod erc20 {281	use super::*;282283	pub fn call_sponsor<T>(284		call: ERC20Call<T>,285		token: RefungibleTokenHandle<T>,286		who: &T::CrossAccountId,287	) -> Option<()>288	where289		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,290	{291		use ERC20Call::*;292293		match call {294			// Readonly295			ERC165Call(_, _)296			| Name297			| Symbol298			| TotalSupply299			| Decimals300			| BalanceOf { .. }301			| Allowance { .. } => None,302303			Transfer { .. } => {304				let RefungibleTokenHandle(handle, token_id) = token;305				let token_id = token_id.try_into().ok()?;306				withdraw_transfer::<T>(&handle, &who, &token_id)307			}308			TransferFrom { from, .. } => {309				let RefungibleTokenHandle(handle, token_id) = token;310				let token_id = token_id.try_into().ok()?;311				let from = T::CrossAccountId::from_eth(from);312				withdraw_transfer::<T>(&handle, &from, &token_id)313			}314			Approve { .. } => {315				let RefungibleTokenHandle(handle, token_id) = token;316				let token_id = token_id.try_into().ok()?;317				withdraw_approve::<T>(&handle, who.as_sub(), &token_id)318			}319		}320	}321322	pub fn unique_extensions_call_sponsor<T>(323		call: ERC20UniqueExtensionsCall<T>,324		_token: RefungibleTokenHandle<T>,325		_who: &T::CrossAccountId,326	) -> Option<()>327	where328		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,329	{330		use ERC20UniqueExtensionsCall::*;331332		match call {333			// Readonly334			ERC165Call(_, _) => None,335336			// Not sponsored337			BurnFrom { .. }338			| BurnFromCross { .. }339			| ApproveCross { .. }340			| TransferCross { .. }341			| TransferFromCross { .. }342			| Repartition { .. } => None,343		}344	}345}346347mod erc1633 {348	use super::*;349350	pub fn call_sponsor<T>(351		call: ERC1633Call<T>,352		_token: RefungibleTokenHandle<T>,353		_who: &T::CrossAccountId,354	) -> Option<()>355	where356		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,357	{358		use ERC1633Call::*;359360		match call {361			// Readonly362			ERC165Call(_, _) | ParentToken | ParentTokenId => None,363		}364	}365}
after · runtime/common/ethereum/sponsoring/refungible.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//! Implements EVM sponsoring logic via TransactionValidityHack1819use core::convert::TryInto;20use pallet_common::CollectionHandle;21use pallet_evm::account::CrossAccountId;22use pallet_fungible::Config as FungibleConfig;23use pallet_refungible::Config as RefungibleConfig;24use pallet_nonfungible::Config as NonfungibleConfig;25use pallet_unique::Config as UniqueConfig;26use up_data_structs::{CreateItemData, CreateNftData, TokenId};2728use super::common;29use crate::runtime_common::sponsoring::*;3031use pallet_refungible::{32	erc::{33		ERC721BurnableCall, ERC721Call, ERC721EnumerableCall, ERC721MetadataCall,34		ERC721UniqueExtensionsCall, ERC721UniqueMintableCall, TokenPropertiesCall,35		UniqueRefungibleCall,36	},37	erc_token::{38		ERC1633Call, ERC20Call, ERC20UniqueExtensionsCall, RefungibleTokenHandle,39		UniqueRefungibleTokenCall,40	},41};4243pub fn call_sponsor<T>(44	call: UniqueRefungibleCall<T>,45	collection: CollectionHandle<T>,46	who: &T::CrossAccountId,47) -> Option<()>48where49	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,50{51	use UniqueRefungibleCall::*;5253	match call {54		// Readonly55		ERC165Call(_, _) => None,5657		ERC721Enumerable(call) => erc721::enumerable_call_sponsor(call, collection, who),58		ERC721Burnable(call) => erc721::burnable_call_sponsor(call, collection, who),59		ERC721Metadata(call) => erc721::metadata_call_sponsor(call, collection, who),60		Collection(call) => common::collection_call_sponsor(call, collection, who),61		ERC721(call) => erc721::call_sponsor(call, collection, who),62		ERC721UniqueExtensions(call) => {63			erc721::unique_extensions_call_sponsor(call, collection, who)64		}65		ERC721UniqueMintable(call) => erc721::unique_mintable_call_sponsor(call, collection, who),66		TokenProperties(call) => token_properties_call_sponsor(call, collection, who),67	}68}6970pub fn token_properties_call_sponsor<T>(71	call: TokenPropertiesCall<T>,72	collection: CollectionHandle<T>,73	who: &T::CrossAccountId,74) -> Option<()>75where76	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,77{78	use TokenPropertiesCall::*;7980	match call {81		// Readonly82		ERC165Call(_, _) | Property { .. } | TokenPropertyPermissions => None,8384		// Not sponsored85		SetTokenPropertyPermission { .. }86		| SetTokenPropertyPermissions { .. }87		| SetProperties { .. }88		| DeleteProperty { .. }89		| DeleteProperties { .. } => None,9091		SetProperty {92			token_id,93			key,94			value,95			..96		} => {97			let token_id = TokenId::try_from(token_id).ok()?;98			withdraw_set_token_property::<T>(&collection, &who, &token_id, key.len() + value.len())99		}100	}101}102103pub fn token_call_sponsor<T>(104	call: UniqueRefungibleTokenCall<T>,105	token: RefungibleTokenHandle<T>,106	who: &T::CrossAccountId,107) -> Option<()>108where109	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,110{111	use UniqueRefungibleTokenCall::*;112113	match call {114		// Readonly115		ERC165Call(_, _) => None,116117		ERC20(call) => erc20::call_sponsor(call, token, who),118		ERC20UniqueExtensions(call) => erc20::unique_extensions_call_sponsor(call, token, who),119		ERC1633(call) => erc1633::call_sponsor(call, token, who),120	}121}122123mod erc721 {124	use super::*;125126	pub fn call_sponsor<T>(127		call: ERC721Call<T>,128		collection: CollectionHandle<T>,129		_who: &T::CrossAccountId,130	) -> Option<()>131	where132		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,133	{134		use ERC721Call::*;135136		match call {137			// Readonly138			ERC165Call(_, _)139			| BalanceOf { .. }140			| OwnerOf { .. }141			| GetApproved { .. }142			| IsApprovedForAll { .. }143			| CollectionHelperAddress => None,144145			// Not sponsored146			SafeTransferFromWithData { .. }147			| SafeTransferFrom { .. }148			| SetApprovalForAll { .. } => None,149150			TransferFrom { token_id, from, .. } => {151				let token_id = TokenId::try_from(token_id).ok()?;152				let from = T::CrossAccountId::from_eth(from);153				withdraw_transfer::<T>(&collection, &from, &token_id)154			}155156			// Not supported157			Approve { .. } => None,158		}159	}160161	pub fn enumerable_call_sponsor<T>(162		call: ERC721EnumerableCall<T>,163		_collection: CollectionHandle<T>,164		_who: &T::CrossAccountId,165	) -> Option<()>166	where167		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,168	{169		use ERC721EnumerableCall::*;170171		match call {172			// Readonly173			ERC165Call(_, _) | TokenByIndex { .. } | TokenOfOwnerByIndex { .. } | TotalSupply => {174				None175			}176		}177	}178179	pub fn burnable_call_sponsor<T>(180		call: ERC721BurnableCall<T>,181		_collection: CollectionHandle<T>,182		_who: &T::CrossAccountId,183	) -> Option<()>184	where185		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,186	{187		use ERC721BurnableCall::*;188189		match call {190			// Readonly191			ERC165Call(_, _) => None,192193			// Not sponsored194			Burn { .. } => None,195		}196	}197198	pub fn metadata_call_sponsor<T>(199		call: ERC721MetadataCall<T>,200		_collection: CollectionHandle<T>,201		_who: &T::CrossAccountId,202	) -> Option<()>203	where204		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,205	{206		use ERC721MetadataCall::*;207208		match call {209			// Readonly210			ERC165Call(_, _) | NameProxy | SymbolProxy | TokenUri { .. } => None,211		}212	}213214	pub fn unique_extensions_call_sponsor<T>(215		call: ERC721UniqueExtensionsCall<T>,216		collection: CollectionHandle<T>,217		who: &T::CrossAccountId,218	) -> Option<()>219	where220		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,221	{222		use ERC721UniqueExtensionsCall::*;223224		match call {225			// Readonly226			ERC165Call(_, _)227			| Name228			| Symbol229			| Description230			| CrossOwnerOf { .. }231			| Properties { .. }232			| NextTokenId233			| TokenContractAddress { .. } => None,234235			// Not sponsored236			| BurnFrom { .. }237			| BurnFromCross { .. } => None,238			239			MintCross { .. }240			| MintBulk { .. }241			| MintBulkWithTokenUri { .. } => {242				withdraw_create_item::<T>(243					&collection,244					&who,245					&CreateItemData::NFT(CreateNftData::default()),246				)247			}248249			TransferCross { token_id, .. }250			| TransferFromCross { token_id, .. }251			| Transfer { token_id, .. } => {252				let token_id = TokenId::try_from(token_id).ok()?;253				withdraw_transfer::<T>(&collection, &who, &token_id)254			}255		}256	}257258	pub fn unique_mintable_call_sponsor<T>(259		call: ERC721UniqueMintableCall<T>,260		collection: CollectionHandle<T>,261		who: &T::CrossAccountId,262	) -> Option<()>263	where264		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,265	{266		use ERC721UniqueMintableCall::*;267268		match call {269			// Readonly270			ERC165Call(_, _) | MintingFinished => None,271272			// Not sponsored273			FinishMinting => None,274275			Mint { .. }276			| MintCheckId { .. }277			| MintWithTokenUri { .. }278			| MintWithTokenUriCheckId { .. } => withdraw_create_item::<T>(279				&collection,280				&who,281				&CreateItemData::NFT(CreateNftData::default()),282			),283		}284	}285}286287mod erc20 {288	use super::*;289290	pub fn call_sponsor<T>(291		call: ERC20Call<T>,292		token: RefungibleTokenHandle<T>,293		who: &T::CrossAccountId,294	) -> Option<()>295	where296		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,297	{298		use ERC20Call::*;299300		match call {301			// Readonly302			ERC165Call(_, _)303			| Name304			| Symbol305			| TotalSupply306			| Decimals307			| BalanceOf { .. }308			| Allowance { .. } => None,309310			Transfer { .. } => {311				let RefungibleTokenHandle(handle, token_id) = token;312				let token_id = token_id.try_into().ok()?;313				withdraw_transfer::<T>(&handle, &who, &token_id)314			}315			TransferFrom { from, .. } => {316				let RefungibleTokenHandle(handle, token_id) = token;317				let token_id = token_id.try_into().ok()?;318				let from = T::CrossAccountId::from_eth(from);319				withdraw_transfer::<T>(&handle, &from, &token_id)320			}321			Approve { .. } => {322				let RefungibleTokenHandle(handle, token_id) = token;323				let token_id = token_id.try_into().ok()?;324				withdraw_approve::<T>(&handle, who.as_sub(), &token_id)325			}326		}327	}328329	pub fn unique_extensions_call_sponsor<T>(330		call: ERC20UniqueExtensionsCall<T>,331		token: RefungibleTokenHandle<T>,332		who: &T::CrossAccountId,333	) -> Option<()>334	where335		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,336	{337		use ERC20UniqueExtensionsCall::*;338339		match call {340			// Readonly341			ERC165Call(_, _) => None,342343			// Not sponsored344			BurnFrom { .. }345			| BurnFromCross { .. }346			| Repartition { .. } => None,347			348			TransferCross { .. }349			| TransferFromCross { .. } => {350				let RefungibleTokenHandle(handle, token_id) = token;351				let token_id = token_id.try_into().ok()?;352				withdraw_transfer::<T>(&handle, &who, &token_id)353			}354355			ApproveCross { .. } => {356				let RefungibleTokenHandle(handle, token_id) = token;357				let token_id = token_id.try_into().ok()?;358				withdraw_approve::<T>(&handle, who.as_sub(), &token_id)359			}360		}361	}362}363364mod erc1633 {365	use super::*;366367	pub fn call_sponsor<T>(368		call: ERC1633Call<T>,369		_token: RefungibleTokenHandle<T>,370		_who: &T::CrossAccountId,371	) -> Option<()>372	where373		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,374	{375		use ERC1633Call::*;376377		match call {378			// Readonly379			ERC165Call(_, _) | ParentToken | ParentTokenId => None,380		}381	}382}
modifiedtests/src/eth/abi/reFungibleDeprecated.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungibleDeprecated.json
+++ b/tests/src/eth/abi/reFungibleDeprecated.json
@@ -98,5 +98,33 @@
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
+    ],
+    "name": "mintBulk",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      {
+        "components": [
+          { "internalType": "uint256", "name": "field_0", "type": "uint256" },
+          { "internalType": "string", "name": "field_1", "type": "string" }
+        ],
+        "internalType": "struct Tuple0[]",
+        "name": "tokens",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulkWithTokenURI",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
   }
 ]
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -16,6 +16,7 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index';
+import { CrossAccountId } from '../util/playgrounds/unique';
 import {itEth, expect} from './util';
 
 describe('evm nft collection sponsoring', () => {
@@ -158,6 +159,7 @@
 
       const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
       const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+      const userBalanceBefore =  await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
       // User can mint token without balance:
       {
@@ -181,7 +183,7 @@
 
         expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
         expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
-        expect(userBalanceAfter).to.be.eq(0n);
+        expect(userBalanceAfter).to.be.eq(userBalanceBefore);
         expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
       }
     }));
@@ -332,32 +334,67 @@
     });
   });
   
-  itEth('sponsors mint transactions', async ({helper}) => {
-    const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}});
-    await collection.setSponsor(alice, alice.address);
-    await collection.confirmSponsorship(alice);
+  [
+    'mintCross',
+    'mintWithTokenURI',
+    'mintBulk',
+    'mintBulkWithTokenUri',
+  ].map(testCase => 
+    itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => {
+      const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [
+        {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}},
+      ]});
+      
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      await collection.setSponsor(alice, alice.address);
+      await collection.confirmSponsorship(alice);
 
-    const minter = helper.eth.createAccount();
-    expect(await helper.balance.getEthereum(minter)).to.equal(0n);
+      const minter = helper.eth.createAccount();
+      const minterCross = helper.ethCrossAccount.fromAddress(minter);
+      expect(await helper.balance.getEthereum(minter)).to.equal(0n);
 
-    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', minter);
+      const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+      const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
 
-    await collection.addToAllowList(alice, {Ethereum: minter});
+      await collection.addToAllowList(alice, {Ethereum: minter});
+      helper.collection.addAdmin(alice, collection.collectionId, {Ethereum: owner});
+      const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+      await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')
+        .send();
 
-    const result = await contract.methods.mint(minter).send();
+      let mintingResult;
+      let tokenId;
+      const nextTokenId = await contract.methods.nextTokenId().call();
+      switch (testCase) {
+        case 'mintCross':
+          mintingResult = await contract.methods.mintCross(minterCross, []).send();
+          break;
+        case 'mintWithTokenURI':
+          mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send();
+          tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+          expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+          break;
+        case 'mintBulk':
+          mintingResult = await contract.methods.mintBulk(minter, [nextTokenId]).send();
+          break;
+        case 'mintBulkWithTokenUri':
+          mintingResult = await contract.methods.mintBulkWithTokenURI(minter, [[nextTokenId, 'Test URI']]).send();
+          tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+          expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+          break;
+      }
 
-    const events = helper.eth.normalizeEvents(result.events);
-    expect(events).to.deep.include({
-      address: collectionAddress,
-      event: 'Transfer',
-      args: {
-        from: '0x0000000000000000000000000000000000000000',
-        to: minter,
-        tokenId: '1',
-      },
-    });
-  });
+      const events = helper.eth.normalizeEvents(mintingResult.events);
+      expect(events).to.deep.include({
+        address: collectionAddress,
+        event: 'Transfer',
+        args: {
+          from: '0x0000000000000000000000000000000000000000',
+          to: minter,
+          tokenId: '1',
+        },
+      });
+    }));
 
   [
     'setCollectionSponsorCross',
@@ -405,7 +442,6 @@
       let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
       expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
       // Account cannot confirm sponsorship if it is not set as a sponsor
-      //await collectionEvm.methods.confirmCollectionSponsorship().call();
       await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
       
       // Sponsor can confirm sponsorship:
@@ -434,6 +470,7 @@
   
       const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
       const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+      const userBalanceBefore =  await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
       // User can mint token without balance:
       {
@@ -456,7 +493,7 @@
   
         expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
         expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
-        expect(userBalanceAfter).to.be.eq(0n);
+        expect(userBalanceAfter).to.be.eq(userBalanceBefore);
         expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
       }
     }));
@@ -465,7 +502,7 @@
     'setCollectionSponsorCross',
     'setCollectionSponsor', // Soft-deprecated
   ].map(testCase => 
-    itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => {
+    itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
       const sponsor = await helper.eth.createAccountWithBalance(donor);
       const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
@@ -475,15 +512,21 @@
       const collectionSub = helper.rft.getCollectionObject(collectionId);
       const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
       // Set collection sponsor:
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
       await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
       let collectionData = (await collectionSub.getData())!;
       expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
       await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
   
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
       collectionData = (await collectionSub.getData())!;
       expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-  
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+      const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
+      expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorTuple.sub))).to.be.equal(helper.address.ethToSubstrate(sponsor));
+
       const user = helper.eth.createAccount();
       const userCross = helper.ethCrossAccount.fromAddress(user);
       await collectionEvm.methods.addCollectionAdminCross(userCross).send();
@@ -514,7 +557,7 @@
       expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
     }));
 
-  itEth('Check that transaction via EVM spend money from substrate sponsor address', async ({helper}) => {
+  itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const sponsor = alice;
     const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
@@ -527,9 +570,16 @@
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true;
+    let collectionData = (await collectionSub.getData())!;
+    expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address);
+    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     await collectionSub.confirmSponsorship(sponsor);
+    collectionData = (await collectionSub.getData())!;
+    expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address);
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
+    const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
+    expect(BigInt(sponsorTuple.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex')));
 
     const user = helper.eth.createAccount();
     const userCross = helper.ethCrossAccount.fromAddress(user);
@@ -585,6 +635,7 @@
 
     const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
     const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
+    const userBalanceBefore =  await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
     {
       const nextTokenId = await collectionEvm.methods.nextTokenId().call();
@@ -609,9 +660,11 @@
 
       const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
       const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
+      const userBalanceAfter =  await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
       expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
       expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
+      expect(userBalanceAfter).to.be.eq(userBalanceBefore);
       expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
     }
   });
@@ -636,6 +689,58 @@
     const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
     expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
   });
+
+  [
+    'transfer',
+    'transferCross',
+    'transferFrom',
+    'transferFromCross',
+  ].map(testCase => 
+    itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+
+      const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+      const sponsor = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+      const receiver = await helper.eth.createAccountWithBalance(donor);
+      const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+
+      await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+
+      const user = await helper.eth.createAccountWithBalance(donor);
+      const userCross = helper.ethCrossAccount.fromAddress(user);
+      await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+
+      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+      const tokenId = result.events.Transfer.returnValues.tokenId;
+      
+      const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+
+      switch (testCase) {
+        case 'transfer':
+          await collectionEvm.methods.transfer(receiver, tokenId).send({from: user});
+          break;
+        case 'transferCross':
+          await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+          break;
+        case 'transferFrom':
+          await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user});
+          break;
+        case 'transferFromCross':
+          await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user});
+          break;
+      }
+
+      const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+      const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+      const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+      expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+    }));
 });
 
 describe('evm RFT token sponsoring', () => {
@@ -648,117 +753,106 @@
     });
   });
 
-  itEth('[cross] Check that transfer via EVM spend money from sponsor address', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
+  [
+    'transfer',
+    'transferCross',
+    'transferFrom',
+    'transferFromCross',
+  ].map(testCase => 
+    itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
 
-    const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+      const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+      const sponsor = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+      const receiver = await helper.eth.createAccountWithBalance(donor);
+      const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
-    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+      await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
 
-    const user = await helper.eth.createAccountWithBalance(donor);
-    const userCross = helper.ethCrossAccount.fromAddress(user);
-    await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+      const user = await helper.eth.createAccountWithBalance(donor);
+      const userCross = helper.ethCrossAccount.fromAddress(user);
+      await collectionEvm.methods.addCollectionAdminCross(userCross).send();
 
-    const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
-    const tokenId = result.events.Transfer.returnValues.tokenId;
+      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+      const tokenId = result.events.Transfer.returnValues.tokenId;
 
-    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);    
-    await tokenContract.methods.repartition(2).send();
-    
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+      const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);   
+      await tokenContract.methods.repartition(2).send();
+      
+      const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
-    await tokenContract.methods.transfer(receiver, 1).send();
+      switch (testCase) {
+        case 'transfer':
+          await tokenContract.methods.transfer(receiver, 1).send();
+          break;
+        case 'transferCross':
+          await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
+          break;
+        case 'transferFrom':
+          await tokenContract.methods.transferFrom(user, receiver, 1).send();
+          break;
+        case 'transferFromCross':
+          await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send();
+          break;
+      }
 
-    const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
-    const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
-    const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-    expect(userBalanceAfter).to.be.eq(userBalanceBefore);
-  });
+      const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+      const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+      const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+      expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+    }));
 
-  itEth('[cross] Check that approve via EVM spend money from sponsor address', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
+  [
+    'approve',
+    'approveCross',
+  ].map(testCase => 
+    itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
 
-    const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+      const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+      const sponsor = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+      const receiver = await helper.eth.createAccountWithBalance(donor);
+      const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
-    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+      await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
 
-    const user = await helper.eth.createAccountWithBalance(donor);
-    const userCross = helper.ethCrossAccount.fromAddress(user);
-    await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+      const user = await helper.eth.createAccountWithBalance(donor);
+      const userCross = helper.ethCrossAccount.fromAddress(user);
+      await collectionEvm.methods.addCollectionAdminCross(userCross).send();
 
-    const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
-    const tokenId = result.events.Transfer.returnValues.tokenId;
+      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+      const tokenId = result.events.Transfer.returnValues.tokenId;
 
-    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);    
-    await tokenContract.methods.repartition(2).send();
-    
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+      const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);  
+      await tokenContract.methods.repartition(2).send();
+      
+      const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
 
-    await tokenContract.methods.approve(receiver, 1).send();
+      switch (testCase) {
+        case 'approve':
+          await tokenContract.methods.approve(receiver, 1).send();
+          break;
+        case 'approveCross':
+          await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send();
+          break;
+      }
 
-    const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
-    const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
-    const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-    expect(userBalanceAfter).to.be.eq(userBalanceBefore);
-  });
-  
-
-  itEth('[cross] Check that transferFrom via EVM spend money from sponsor address', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-
-    const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
+      const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+      const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
+      const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
+      expect(userBalanceAfter).to.be.eq(userBalanceBefore);
+    }));
+});
 
-    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-
-    const user = await helper.eth.createAccountWithBalance(donor);
-    const userCross = helper.ethCrossAccount.fromAddress(user);
-    await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
-    const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
-    const tokenId = result.events.Transfer.returnValues.tokenId;
-
-    const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, user);    
-    await tokenContract.methods.repartition(2).send();
-    await tokenContract.methods.approve(receiver, 1).send();
-    
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-    const receiverBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(receiver));
-
-    const receiverTokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, receiver);   
-    await receiverTokenContract.methods.transferFrom(user, receiver, 1).send();
-
-    const receiverBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(receiver));
-    expect(receiverBalanceAfter).to.be.eq(receiverBalanceBefore);
-    const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
-    const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
-    const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
-    expect(userBalanceAfter).to.be.eq(userBalanceBefore);
-  });
-});