git.delta.rocks / unique-network / refs/commits / 26f0d33cfa5a

difftreelog

chore fix code review requests

Grigoriy Simonov2022-12-23parent: #0b44e9f.patch.diff
in: master

2 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 { .. } => None,8384		// Not sponsored85		SetTokenPropertyPermission { .. }86		| SetProperties { .. }87		| DeleteProperty { .. }88		| DeleteProperties { .. } => None,8990		SetProperty {91			token_id,92			key,93			value,94			..95		} => {96			let token_id: TokenId = token_id.try_into().ok()?;97			withdraw_set_token_property::<T>(&collection, &who, &token_id, key.len() + value.len())98		}99	}100}101102pub fn token_call_sponsor<T>(103	call: UniqueRefungibleTokenCall<T>,104	token: RefungibleTokenHandle<T>,105	who: &T::CrossAccountId,106) -> Option<()>107where108	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,109{110	use UniqueRefungibleTokenCall::*;111112	match call {113		// Readonly114		ERC165Call(_, _) => None,115116		ERC20(call) => erc20::call_sponsor(call, token, who),117		ERC20UniqueExtensions(call) => erc20::unique_extensions_call_sponsor(call, token, who),118		ERC1633(call) => erc1633::call_sponsor(call, token, who),119	}120}121122mod erc721 {123	use super::*;124125	pub fn call_sponsor<T>(126		call: ERC721Call<T>,127		collection: CollectionHandle<T>,128		who: &T::CrossAccountId,129	) -> Option<()>130	where131		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,132	{133		use ERC721Call::*;134135		match call {136			// Readonly137			ERC165Call(_, _)138			| BalanceOf { .. }139			| OwnerOf { .. }140			| GetApproved { .. }141			| IsApprovedForAll { .. }142			| CollectionHelperAddress => None,143144			// Not sponsored145			SafeTransferFromWithData { .. }146			| SafeTransferFrom { .. }147			| SetApprovalForAll { .. } => None,148149			TransferFrom { token_id, from, .. } => {150				let token_id: TokenId = token_id.try_into().ok()?;151				let from = T::CrossAccountId::from_eth(from);152				withdraw_transfer::<T>(&collection, &from, &token_id)153			}154			Approve { _token_id, .. } => {155				let token_id: TokenId = _token_id.try_into().ok()?;156				withdraw_approve::<T>(&collection, who.as_sub(), &token_id)157			}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			| MintBulk { .. }241			| MintBulkWithTokenUri { .. } => None,242243			Transfer { token_id, .. } => {244				let token_id: TokenId = token_id.try_into().ok()?;245				withdraw_transfer::<T>(&collection, &who, &token_id)246			}247		}248	}249250	pub fn unique_mintable_call_sponsor<T>(251		call: ERC721UniqueMintableCall<T>,252		collection: CollectionHandle<T>,253		who: &T::CrossAccountId,254	) -> Option<()>255	where256		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,257	{258		use ERC721UniqueMintableCall::*;259260		match call {261			// Readonly262			ERC165Call(_, _) | MintingFinished => None,263264			// Not sponsored265			FinishMinting => None,266267			Mint { .. }268			| MintCheckId { .. }269			| MintWithTokenUri { .. }270			| MintWithTokenUriCheckId { .. } => withdraw_create_item::<T>(271				&collection,272				&who,273				&CreateItemData::NFT(CreateNftData::default()),274			),275		}276	}277}278279mod erc20 {280	use super::*;281282	pub fn call_sponsor<T>(283		call: ERC20Call<T>,284		token: RefungibleTokenHandle<T>,285		who: &T::CrossAccountId,286	) -> Option<()>287	where288		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,289	{290		use ERC20Call::*;291292		match call {293			// Readonly294			ERC165Call(_, _)295			| Name296			| Symbol297			| TotalSupply298			| Decimals299			| BalanceOf { .. }300			| Allowance { .. } => None,301302			Transfer { .. } => {303				let RefungibleTokenHandle(handle, token_id) = token;304				let token_id = token_id.try_into().ok()?;305				withdraw_transfer::<T>(&handle, &who, &token_id)306			}307			TransferFrom { from, .. } => {308				let RefungibleTokenHandle(handle, token_id) = token;309				let token_id = token_id.try_into().ok()?;310				let from = T::CrossAccountId::from_eth(from);311				withdraw_transfer::<T>(&handle, &from, &token_id)312			}313			Approve { .. } => {314				let RefungibleTokenHandle(handle, token_id) = token;315				let token_id = token_id.try_into().ok()?;316				withdraw_approve::<T>(&handle, who.as_sub(), &token_id)317			}318		}319	}320321	pub fn unique_extensions_call_sponsor<T>(322		call: ERC20UniqueExtensionsCall<T>,323		_token: RefungibleTokenHandle<T>,324		_who: &T::CrossAccountId,325	) -> Option<()>326	where327		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,328	{329		use ERC20UniqueExtensionsCall::*;330331		match call {332			// Readonly333			ERC165Call(_, _) => None,334335			// Not sponsored336			BurnFrom { .. } | Repartition { .. } => None,337		}338	}339}340341mod erc1633 {342	use super::*;343344	pub fn call_sponsor<T>(345		call: ERC1633Call<T>,346		_token: RefungibleTokenHandle<T>,347		_who: &T::CrossAccountId,348	) -> Option<()>349	where350		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,351	{352		use ERC1633Call::*;353354		match call {355			// Readonly356			ERC165Call(_, _) | ParentToken | ParentTokenId => None,357		}358	}359}
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 { .. } => None,8384		// Not sponsored85		SetTokenPropertyPermission { .. }86		| SetProperties { .. }87		| DeleteProperty { .. }88		| DeleteProperties { .. } => None,8990		SetProperty {91			token_id,92			key,93			value,94			..95		} => {96			let token_id = TokenId::try_from(token_id).ok()?;97			withdraw_set_token_property::<T>(&collection, &who, &token_id, key.len() + value.len())98		}99	}100}101102pub fn token_call_sponsor<T>(103	call: UniqueRefungibleTokenCall<T>,104	token: RefungibleTokenHandle<T>,105	who: &T::CrossAccountId,106) -> Option<()>107where108	T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,109{110	use UniqueRefungibleTokenCall::*;111112	match call {113		// Readonly114		ERC165Call(_, _) => None,115116		ERC20(call) => erc20::call_sponsor(call, token, who),117		ERC20UniqueExtensions(call) => erc20::unique_extensions_call_sponsor(call, token, who),118		ERC1633(call) => erc1633::call_sponsor(call, token, who),119	}120}121122mod erc721 {123	use super::*;124125	pub fn call_sponsor<T>(126		call: ERC721Call<T>,127		collection: CollectionHandle<T>,128		_who: &T::CrossAccountId,129	) -> Option<()>130	where131		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,132	{133		use ERC721Call::*;134135		match call {136			// Readonly137			ERC165Call(_, _)138			| BalanceOf { .. }139			| OwnerOf { .. }140			| GetApproved { .. }141			| IsApprovedForAll { .. }142			| CollectionHelperAddress => None,143144			// Not sponsored145			SafeTransferFromWithData { .. }146			| SafeTransferFrom { .. }147			| SetApprovalForAll { .. } => None,148149			TransferFrom { token_id, from, .. } => {150				let token_id = TokenId::try_from(token_id).ok()?;151				let from = T::CrossAccountId::from_eth(from);152				withdraw_transfer::<T>(&collection, &from, &token_id)153			}154155			// Not supported156			Approve { .. } => None,157		}158	}159160	pub fn enumerable_call_sponsor<T>(161		call: ERC721EnumerableCall<T>,162		_collection: CollectionHandle<T>,163		_who: &T::CrossAccountId,164	) -> Option<()>165	where166		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,167	{168		use ERC721EnumerableCall::*;169170		match call {171			// Readonly172			ERC165Call(_, _) | TokenByIndex { .. } | TokenOfOwnerByIndex { .. } | TotalSupply => {173				None174			}175		}176	}177178	pub fn burnable_call_sponsor<T>(179		call: ERC721BurnableCall<T>,180		_collection: CollectionHandle<T>,181		_who: &T::CrossAccountId,182	) -> Option<()>183	where184		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,185	{186		use ERC721BurnableCall::*;187188		match call {189			// Readonly190			ERC165Call(_, _) => None,191192			// Not sponsored193			Burn { .. } => None,194		}195	}196197	pub fn metadata_call_sponsor<T>(198		call: ERC721MetadataCall<T>,199		_collection: CollectionHandle<T>,200		_who: &T::CrossAccountId,201	) -> Option<()>202	where203		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,204	{205		use ERC721MetadataCall::*;206207		match call {208			// Readonly209			ERC165Call(_, _) | NameProxy | SymbolProxy | TokenUri { .. } => None,210		}211	}212213	pub fn unique_extensions_call_sponsor<T>(214		call: ERC721UniqueExtensionsCall<T>,215		collection: CollectionHandle<T>,216		who: &T::CrossAccountId,217	) -> Option<()>218	where219		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,220	{221		use ERC721UniqueExtensionsCall::*;222223		match call {224			// Readonly225			ERC165Call(_, _)226			| Name227			| Symbol228			| Description229			| CrossOwnerOf { .. }230			| Properties { .. }231			| NextTokenId232			| TokenContractAddress { .. } => None,233234			// Not sponsored235			TransferCross { .. }236			| TransferFromCross { .. }237			| BurnFrom { .. }238			| BurnFromCross { .. }239			| MintBulk { .. }240			| MintBulkWithTokenUri { .. } => None,241242			Transfer { token_id, .. } => {243				let token_id = TokenId::try_from(token_id).ok()?;244				withdraw_transfer::<T>(&collection, &who, &token_id)245			}246		}247	}248249	pub fn unique_mintable_call_sponsor<T>(250		call: ERC721UniqueMintableCall<T>,251		collection: CollectionHandle<T>,252		who: &T::CrossAccountId,253	) -> Option<()>254	where255		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,256	{257		use ERC721UniqueMintableCall::*;258259		match call {260			// Readonly261			ERC165Call(_, _) | MintingFinished => None,262263			// Not sponsored264			FinishMinting => None,265266			Mint { .. }267			| MintCheckId { .. }268			| MintWithTokenUri { .. }269			| MintWithTokenUriCheckId { .. } => withdraw_create_item::<T>(270				&collection,271				&who,272				&CreateItemData::NFT(CreateNftData::default()),273			),274		}275	}276}277278mod erc20 {279	use super::*;280281	pub fn call_sponsor<T>(282		call: ERC20Call<T>,283		token: RefungibleTokenHandle<T>,284		who: &T::CrossAccountId,285	) -> Option<()>286	where287		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,288	{289		use ERC20Call::*;290291		match call {292			// Readonly293			ERC165Call(_, _)294			| Name295			| Symbol296			| TotalSupply297			| Decimals298			| BalanceOf { .. }299			| Allowance { .. } => None,300301			Transfer { .. } => {302				let RefungibleTokenHandle(handle, token_id) = token;303				let token_id = token_id.try_into().ok()?;304				withdraw_transfer::<T>(&handle, &who, &token_id)305			}306			TransferFrom { from, .. } => {307				let RefungibleTokenHandle(handle, token_id) = token;308				let token_id = token_id.try_into().ok()?;309				let from = T::CrossAccountId::from_eth(from);310				withdraw_transfer::<T>(&handle, &from, &token_id)311			}312			Approve { .. } => {313				let RefungibleTokenHandle(handle, token_id) = token;314				let token_id = token_id.try_into().ok()?;315				withdraw_approve::<T>(&handle, who.as_sub(), &token_id)316			}317		}318	}319320	pub fn unique_extensions_call_sponsor<T>(321		call: ERC20UniqueExtensionsCall<T>,322		_token: RefungibleTokenHandle<T>,323		_who: &T::CrossAccountId,324	) -> Option<()>325	where326		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,327	{328		use ERC20UniqueExtensionsCall::*;329330		match call {331			// Readonly332			ERC165Call(_, _) => None,333334			// Not sponsored335			BurnFrom { .. } | Repartition { .. } => None,336		}337	}338}339340mod erc1633 {341	use super::*;342343	pub fn call_sponsor<T>(344		call: ERC1633Call<T>,345		_token: RefungibleTokenHandle<T>,346		_who: &T::CrossAccountId,347	) -> Option<()>348	where349		T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig,350	{351		use ERC1633Call::*;352353		match call {354			// Readonly355			ERC165Call(_, _) | ParentToken | ParentTokenId => None,356		}357	}358}
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -144,15 +144,15 @@
       expect(nextTokenId).to.be.equal('1');
 
       // Set collection permissions:
-      const oldPermissions = (await collectionSub.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
+      const oldPermissions = (await collectionSub.getData())!.raw.permissions;
       expect(oldPermissions.mintMode).to.be.false;
       expect(oldPermissions.access).to.be.equal('Normal');
 
       await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
       await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
       await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
-      const newPermissions = (await collectionSub.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
+  
+      const newPermissions = (await collectionSub.getData())!.raw.permissions;
       expect(newPermissions.mintMode).to.be.true;
       expect(newPermissions.access).to.be.equal('AllowList');
 
@@ -380,174 +380,106 @@
   //   expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
   // });
 
-  // Soft-deprecated
-  itEth('[eth] Remove sponsor', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+  [
+    'setCollectionSponsorCross',
+    'setCollectionSponsor', // Soft-deprecated
+  ].map(testCase => 
+    itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+  
+      let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
+      const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+      const sponsor = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+      const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+  
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+      result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner});
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
+  
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+      expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
+  
+      await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
+  
+      const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
+      expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');
+    }));
 
-    let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
-    const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, true);
-
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
-    await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-
-    const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
-    expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');
-  });
-
-  itEth('[cross] Remove sponsor', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-
-    let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)});
-    const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner);
-
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-    result = await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;
-
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-    expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
-
-    await collectionEvm.methods.removeCollectionSponsor().send({from: owner});
-
-    const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner});
-    expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');
-  });
-
-  // Soft-deprecated
-  itEth('[eth] Sponsoring collection from evm address via access list', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-
-    const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
-
-    const collection = helper.rft.getCollectionObject(collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);
-
-    await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
-    let collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
-
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-    collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-
-    const user = helper.eth.createAccount();
-    const nextTokenId = await collectionEvm.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-
-    const oldPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
-    expect(oldPermissions.mintMode).to.be.false;
-    expect(oldPermissions.access).to.be.equal('Normal');
-
-    await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
-    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
-    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
-    const newPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
-    expect(newPermissions.mintMode).to.be.true;
-    expect(newPermissions.access).to.be.equal('AllowList');
-
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
-    {
-      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
-      const events = helper.eth.normalizeEvents(result.events);
-
-      expect(events).to.deep.include({
-        address: collectionAddress,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: user,
-          tokenId: '1',
-        },
-      });
-
-      const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner));
-      const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
-
-      expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-      expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
-      expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
-    }
-  });
-
-  itEth('[cross] Sponsoring collection from evm address via access list', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-
-    const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
-
-    const collection = helper.rft.getCollectionObject(collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
-
-    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
-    let collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
+  [
+    'setCollectionSponsorCross',
+    'setCollectionSponsor', // Soft-deprecated
+  ].map(testCase => 
+    itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+  
+      const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', '');
+  
+      const collectionSub = helper.rft.getCollectionObject(collectionId);
+      const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+  
+      // Set collection sponsor:
+      await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner});
+      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 expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
+      
+      // Sponsor can confirm sponsorship:
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
+      sponsorship = (await collectionSub.getData())!.raw.sponsorship;
+      expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
+  
+      // Create user with no balance:
+      const user = helper.eth.createAccount();
+      const userCross = helper.ethCrossAccount.fromAddress(user);
+      const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+      expect(nextTokenId).to.be.equal('1');
+  
+      // Set collection permissions:
+      const oldPermissions = (await collectionSub.getData())!.raw.permissions;
+      expect(oldPermissions.mintMode).to.be.false;
+      expect(oldPermissions.access).to.be.equal('Normal');
 
-    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
-    collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-
-    const user = helper.eth.createAccount();
-    const userCross = helper.ethCrossAccount.fromAddress(user);
-    const nextTokenId = await collectionEvm.methods.nextTokenId().call();
-    expect(nextTokenId).to.be.equal('1');
-
-    const oldPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
-    expect(oldPermissions.mintMode).to.be.false;
-    expect(oldPermissions.access).to.be.equal('Normal');
-
-    await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
-    await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
-    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
-
-    const newPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
-    expect(newPermissions.mintMode).to.be.true;
-    expect(newPermissions.access).to.be.equal('AllowList');
-
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
-    {
-      const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
-      const events = helper.eth.normalizeEvents(result.events);
-
-      expect(events).to.deep.include({
-        address: collectionAddress,
-        event: 'Transfer',
-        args: {
-          from: '0x0000000000000000000000000000000000000000',
-          to: user,
-          tokenId: '1',
-        },
-      });
+      await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
+      await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
+      await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
+  
+      const newPermissions = (await collectionSub.getData())!.raw.permissions;
+      expect(newPermissions.mintMode).to.be.true;
+      expect(newPermissions.access).to.be.equal('AllowList');
+  
+      const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
 
-      const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner));
-      const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));
+      // User can mint token without balance:
+      {
+        const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+        const events = helper.eth.normalizeEvents(result.events);
 
-      expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-      expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);
-      expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
-    }
-  });
+        expect(events).to.deep.include({
+          address: collectionAddress,
+          event: 'Transfer',
+          args: {
+            from: '0x0000000000000000000000000000000000000000',
+            to: user,
+            tokenId: '1',
+          },
+        });
+  
+        const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+        const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth));
+        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(0n);
+        expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;
+      }
+    }));
 
   // TODO: Temprorary off. Need refactor
   // itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {
@@ -605,37 +537,84 @@
   //   }
   // });
 
-  // Soft-deprecated
-  itEth('[eth] Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
+  [
+    'setCollectionSponsorCross',
+    'setCollectionSponsor', // Soft-deprecated
+  ].map(testCase => 
+    itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      const sponsor = await helper.eth.createAccountWithBalance(donor);
+      const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+  
+      const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
+
+      const collectionSub = helper.rft.getCollectionObject(collectionId);
+      const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor');
+      // Set collection sponsor:
+      await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
+      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('caller is not set as sponsor');
+  
+      await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
+      collectionData = (await collectionSub.getData())!;
+      expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+  
+      const user = helper.eth.createAccount();
+      const userCross = helper.ethCrossAccount.fromAddress(user);
+      await collectionEvm.methods.addCollectionAdminCross(userCross).send();
+  
+      const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
+      const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
+    
+      const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+      const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
+  
+      const events = helper.eth.normalizeEvents(mintingResult.events);
+      const address = helper.ethAddress.fromCollectionId(collectionId);
+  
+      expect(events).to.deep.include({
+        address,
+        event: 'Transfer',
+        args: {
+          from: '0x0000000000000000000000000000000000000000',
+          to: user,
+          tokenId: '1',
+        },
+      });
+      expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
+  
+      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;
+    }));
+
+  itEth('Check that transaction via EVM spend money from substrate sponsor address', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
+    const sponsor = alice;
+    const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
 
     const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const collection = helper.rft.getCollectionObject(collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true);
 
-    await collectionEvm.methods.setCollectionSponsor(sponsor).send();
-    let collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
+    const collectionSub = helper.rft.getCollectionObject(collectionId);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
+    // Set collection sponsor:
+    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
 
-    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
-    await sponsorCollection.methods.confirmCollectionSponsorship().send();
-    collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
+    await collectionSub.confirmSponsorship(sponsor);
 
     const user = helper.eth.createAccount();
-    await collectionEvm.methods.addCollectionAdmin(user).send();
+    const userCross = helper.ethCrossAccount.fromAddress(user);
+    await collectionEvm.methods.addCollectionAdminCross(userCross).send();
 
     const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
-    const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', user, true);
+    const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address);
+  
+    const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user});
+    const tokenId = mintingResult.events.Transfer.returnValues.tokenId;
 
-    const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').send();
-    const tokenId = result.events.Transfer.returnValues.tokenId;
-
-    const events = helper.eth.normalizeEvents(result.events);
+    const events = helper.eth.normalizeEvents(mintingResult.events);
     const address = helper.ethAddress.fromCollectionId(collectionId);
 
     expect(events).to.deep.include({
@@ -647,63 +626,33 @@
         tokenId: '1',
       },
     });
-    expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+    expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI');
 
     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));
+    const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address);
     expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
   });
 
-  itEth('[cross] Check that transaction via EVM spend money from sponsor address', async ({helper}) => {
+  itEth('Can reassign collection sponsor', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
+    const sponsorEth = await helper.eth.createAccountWithBalance(donor);
+    const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth);
+    const [sponsorSub] = await helper.arrange.createAccounts([100n], donor);
+    const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub);
 
     const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const collection = helper.rft.getCollectionObject(collectionId);
-    const sponsor = await helper.eth.createAccountWithBalance(donor);
-    const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor);
+    const collectionSub = helper.rft.getCollectionObject(collectionId);
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
-    await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-    let collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');
-
-    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
-    await sponsorCollection.methods.confirmCollectionSponsorship().send();
-    collectionData = (await collection.getData())!;
-    expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-
-    const user = helper.eth.createAccount();
-    const userCross = helper.ethCrossAccount.fromAddress(user);
-    await collectionEvm.methods.addCollectionAdminCross(userCross).send();
-
-    const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
-    const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));
-
-    const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', user);
-
-    const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').send();
-    const tokenId = result.events.Transfer.returnValues.tokenId;
-
-    const events = helper.eth.normalizeEvents(result.events);
-    const address = helper.ethAddress.fromCollectionId(collectionId);
-
-    expect(events).to.deep.include({
-      address,
-      event: 'Transfer',
-      args: {
-        from: '0x0000000000000000000000000000000000000000',
-        to: user,
-        tokenId: '1',
-      },
-    });
-    expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');
+    // Set and confirm sponsor:
+    await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
+    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
 
-    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;
+    // Can reassign sponsor:
+    await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner});
+    const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship;
+    expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address});
   });
 });
 
@@ -727,17 +676,13 @@
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-
-    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
-    await sponsorCollection.methods.confirmCollectionSponsorship().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 userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', user);
-
-    const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').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);    
@@ -767,17 +712,13 @@
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-
-    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
-    await sponsorCollection.methods.confirmCollectionSponsorship().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 userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', user);
 
-    const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').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);    
@@ -808,17 +749,13 @@
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
-
-    const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
-    await sponsorCollection.methods.confirmCollectionSponsorship().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 userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', user);
-
-    const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').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);