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

difftreelog

fix small fixes

Trubnikov Sergey2022-08-25parent: #9d78c86.patch.diff
in: master

7 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
before · pallets/common/src/erc.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//! This module contains the implementation of pallet methods for evm.1819use evm_coder::{20	solidity_interface, solidity, ToLog,21	types::*,22	execution::{Result, Error},23};24pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};25use pallet_evm_coder_substrate::dispatch_to_evm;26use sp_std::vec::Vec;27use up_data_structs::{28	AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,29	SponsoringRateLimit, SponsorshipState,30};31use alloc::format;3233use crate::{34	Pallet, CollectionHandle, Config, CollectionProperties,35	eth::{convert_cross_account_to_uint256, convert_uint256_to_cross_account},36};3738/// Events for ethereum collection helper.39#[derive(ToLog)]40pub enum CollectionHelpersEvents {41	/// The collection has been created.42	CollectionCreated {43		/// Collection owner.44		#[indexed]45		owner: address,4647		/// Collection ID.48		#[indexed]49		collection_id: address,50	},51}5253/// Does not always represent a full collection, for RFT it is either54/// collection (Implementing ERC721), or specific collection token (Implementing ERC20).55pub trait CommonEvmHandler {56	const CODE: &'static [u8];5758	/// Call precompiled handle.59	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;60}6162/// @title A contract that allows you to work with collections.63#[solidity_interface(name = Collection)]64impl<T: Config> CollectionHandle<T>65where66	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,67{68	/// Set collection property.69	///70	/// @param key Property key.71	/// @param value Propery value.72	fn set_collection_property(73		&mut self,74		caller: caller,75		key: string,76		value: bytes,77	) -> Result<void> {78		let caller = T::CrossAccountId::from_eth(caller);79		let key = <Vec<u8>>::from(key)80			.try_into()81			.map_err(|_| "key too large")?;82		let value = value.try_into().map_err(|_| "value too large")?;8384		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })85			.map_err(dispatch_to_evm::<T>)86	}8788	/// Delete collection property.89	///90	/// @param key Property key.91	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {92		let caller = T::CrossAccountId::from_eth(caller);93		let key = <Vec<u8>>::from(key)94			.try_into()95			.map_err(|_| "key too large")?;9697		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)98	}99100	/// Get collection property.101	///102	/// @dev Throws error if key not found.103	///104	/// @param key Property key.105	/// @return bytes The property corresponding to the key.106	fn collection_property(&self, key: string) -> Result<bytes> {107		let key = <Vec<u8>>::from(key)108			.try_into()109			.map_err(|_| "key too large")?;110111		let props = <CollectionProperties<T>>::get(self.id);112		let prop = props.get(&key).ok_or("key not found")?;113114		Ok(prop.to_vec())115	}116117	/// Set the sponsor of the collection.118	///119	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.120	///121	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.122	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {123		check_is_owner_or_admin(caller, self)?;124125		let sponsor = T::CrossAccountId::from_eth(sponsor);126		self.set_sponsor(sponsor.as_sub().clone())127			.map_err(dispatch_to_evm::<T>)?;128		save(self)129	}130131	/// Set the substrate sponsor of the collection.132	///133	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.134	///135	/// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.136	fn set_collection_sponsor_substrate(137		&mut self,138		caller: caller,139		sponsor: uint256,140	) -> Result<void> {141		check_is_owner_or_admin(caller, self)?;142143		let sponsor = convert_uint256_to_cross_account::<T>(sponsor);144		self.set_sponsor(sponsor.as_sub().clone())145			.map_err(dispatch_to_evm::<T>)?;146		save(self)147	}148149	// /// Whether there is a pending sponsor.150	fn has_collection_pending_sponsor(&self) -> Result<bool> {151		Ok(matches!(152			self.collection.sponsorship,153			SponsorshipState::Unconfirmed(_)154		))155	}156157	/// Collection sponsorship confirmation.158	///159	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.160	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {161		let caller = T::CrossAccountId::from_eth(caller);162		if !self163			.confirm_sponsorship(caller.as_sub())164			.map_err(dispatch_to_evm::<T>)?165		{166			return Err("caller is not set as sponsor".into());167		}168		save(self)169	}170171	/// Remove collection sponsor.172	fn remove_collection_sponsor(&mut self, caller: caller) -> Result<void> {173		check_is_owner_or_admin(caller, self)?;174		self.remove_sponsor().map_err(dispatch_to_evm::<T>)?;175		save(self)176	}177178	/// Get current sponsor.179	///180	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.181	fn get_collection_sponsor(&self) -> Result<(address, uint256)> {182		let sponsor = match self.collection.sponsorship {183			SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => {184				return Ok(Default::default())185			}186			SponsorshipState::Confirmed(ref sponsor) => sponsor,187		};188		let sponsor = T::CrossAccountId::from_sub(sponsor.clone());189		let sponsor_sub = convert_cross_account_to_uint256::<T>(&sponsor);190		Ok((*sponsor.as_eth(), sponsor_sub))191	}192193	/// Set limits for the collection.194	/// @dev Throws error if limit not found.195	/// @param limit Name of the limit. Valid names:196	/// 	"accountTokenOwnershipLimit",197	/// 	"sponsoredDataSize",198	/// 	"sponsoredDataRateLimit",199	/// 	"tokenLimit",200	/// 	"sponsorTransferTimeout",201	/// 	"sponsorApproveTimeout"202	/// @param value Value of the limit.203	#[solidity(rename_selector = "setCollectionLimit")]204	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {205		check_is_owner_or_admin(caller, self)?;206		let mut limits = self.limits.clone();207208		match limit.as_str() {209			"accountTokenOwnershipLimit" => {210				limits.account_token_ownership_limit = Some(value);211			}212			"sponsoredDataSize" => {213				limits.sponsored_data_size = Some(value);214			}215			"sponsoredDataRateLimit" => {216				limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value));217			}218			"tokenLimit" => {219				limits.token_limit = Some(value);220			}221			"sponsorTransferTimeout" => {222				limits.sponsor_transfer_timeout = Some(value);223			}224			"sponsorApproveTimeout" => {225				limits.sponsor_approve_timeout = Some(value);226			}227			_ => {228				return Err(Error::Revert(format!(229					"unknown integer limit \"{}\"",230					limit231				)))232			}233		}234		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)235			.map_err(dispatch_to_evm::<T>)?;236		save(self)237	}238239	/// Set limits for the collection.240	/// @dev Throws error if limit not found.241	/// @param limit Name of the limit. Valid names:242	/// 	"ownerCanTransfer",243	/// 	"ownerCanDestroy",244	/// 	"transfersEnabled"245	/// @param value Value of the limit.246	#[solidity(rename_selector = "setCollectionLimit")]247	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {248		check_is_owner_or_admin(caller, self)?;249		let mut limits = self.limits.clone();250251		match limit.as_str() {252			"ownerCanTransfer" => {253				limits.owner_can_transfer = Some(value);254			}255			"ownerCanDestroy" => {256				limits.owner_can_destroy = Some(value);257			}258			"transfersEnabled" => {259				limits.transfers_enabled = Some(value);260			}261			_ => {262				return Err(Error::Revert(format!(263					"unknown boolean limit \"{}\"",264					limit265				)))266			}267		}268		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)269			.map_err(dispatch_to_evm::<T>)?;270		save(self)271	}272273	/// Get contract address.274	fn contract_address(&self, _caller: caller) -> Result<address> {275		Ok(crate::eth::collection_id_to_address(self.id))276	}277278	/// Add collection admin by substrate address.279	/// @param newAdmin Substrate administrator address.280	fn add_collection_admin_substrate(281		&mut self,282		caller: caller,283		new_admin: uint256,284	) -> Result<void> {285		let caller = T::CrossAccountId::from_eth(caller);286		let new_admin = convert_uint256_to_cross_account::<T>(new_admin);287		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;288		Ok(())289	}290291	/// Remove collection admin by substrate address.292	/// @param admin Substrate administrator address.293	fn remove_collection_admin_substrate(294		&mut self,295		caller: caller,296		admin: uint256,297	) -> Result<void> {298		let caller = T::CrossAccountId::from_eth(caller);299		let admin = convert_uint256_to_cross_account::<T>(admin);300		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;301		Ok(())302	}303304	/// Add collection admin.305	/// @param newAdmin Address of the added administrator.306	fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {307		let caller = T::CrossAccountId::from_eth(caller);308		let new_admin = T::CrossAccountId::from_eth(new_admin);309		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;310		Ok(())311	}312313	/// Remove collection admin.314	///315	/// @param admin Address of the removed administrator.316	fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {317		let caller = T::CrossAccountId::from_eth(caller);318		let admin = T::CrossAccountId::from_eth(admin);319		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;320		Ok(())321	}322323	/// Toggle accessibility of collection nesting.324	///325	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'326	#[solidity(rename_selector = "setCollectionNesting")]327	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {328		check_is_owner_or_admin(caller, self)?;329330		let mut permissions = self.collection.permissions.clone();331		let mut nesting = permissions.nesting().clone();332		nesting.token_owner = enable;333		nesting.restricted = None;334		permissions.nesting = Some(nesting);335336		self.collection.permissions = <Pallet<T>>::clamp_permissions(337			self.collection.mode.clone(),338			&self.collection.permissions,339			permissions,340		)341		.map_err(dispatch_to_evm::<T>)?;342343		save(self)344	}345346	/// Toggle accessibility of collection nesting.347	///348	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'349	/// @param collections Addresses of collections that will be available for nesting.350	#[solidity(rename_selector = "setCollectionNesting")]351	fn set_nesting(352		&mut self,353		caller: caller,354		enable: bool,355		collections: Vec<address>,356	) -> Result<void> {357		if collections.is_empty() {358			return Err("no addresses provided".into());359		}360		check_is_owner_or_admin(caller, self)?;361362		let mut permissions = self.collection.permissions.clone();363		match enable {364			false => {365				let mut nesting = permissions.nesting().clone();366				nesting.token_owner = false;367				nesting.restricted = None;368				permissions.nesting = Some(nesting);369			}370			true => {371				let mut bv = OwnerRestrictedSet::new();372				for i in collections {373					bv.try_insert(crate::eth::map_eth_to_id(&i).ok_or(Error::Revert(374						"Can't convert address into collection id".into(),375					))?)376					.map_err(|_| "too many collections")?;377				}378				let mut nesting = permissions.nesting().clone();379				nesting.token_owner = true;380				nesting.restricted = Some(bv);381				permissions.nesting = Some(nesting);382			}383		};384385		self.collection.permissions = <Pallet<T>>::clamp_permissions(386			self.collection.mode.clone(),387			&self.collection.permissions,388			permissions,389		)390		.map_err(dispatch_to_evm::<T>)?;391392		save(self)393	}394395	/// Set the collection access method.396	/// @param mode Access mode397	/// 	0 for Normal398	/// 	1 for AllowList399	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {400		check_is_owner_or_admin(caller, self)?;401		let permissions = CollectionPermissions {402			access: Some(match mode {403				0 => AccessMode::Normal,404				1 => AccessMode::AllowList,405				_ => return Err("not supported access mode".into()),406			}),407			..Default::default()408		};409		self.collection.permissions = <Pallet<T>>::clamp_permissions(410			self.collection.mode.clone(),411			&self.collection.permissions,412			permissions,413		)414		.map_err(dispatch_to_evm::<T>)?;415416		save(self)417	}418419	/// Add the user to the allowed list.420	///421	/// @param user Address of a trusted user.422	fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {423		let caller = T::CrossAccountId::from_eth(caller);424		let user = T::CrossAccountId::from_eth(user);425		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;426		Ok(())427	}428429	/// Remove the user from the allowed list.430	///431	/// @param user Address of a removed user.432	fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {433		let caller = T::CrossAccountId::from_eth(caller);434		let user = T::CrossAccountId::from_eth(user);435		<Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;436		Ok(())437	}438439	/// Switch permission for minting.440	///441	/// @param mode Enable if "true".442	fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {443		check_is_owner_or_admin(caller, self)?;444		let permissions = CollectionPermissions {445			mint_mode: Some(mode),446			..Default::default()447		};448		self.collection.permissions = <Pallet<T>>::clamp_permissions(449			self.collection.mode.clone(),450			&self.collection.permissions,451			permissions,452		)453		.map_err(dispatch_to_evm::<T>)?;454455		save(self)456	}457458	/// Check that account is the owner or admin of the collection459	///460	/// @param user account to verify461	/// @return "true" if account is the owner or admin462	#[solidity(rename_selector = "isOwnerOrAdmin")]463	fn is_owner_or_admin_eth(&self, user: address) -> Result<bool> {464		let user = T::CrossAccountId::from_eth(user);465		Ok(self.is_owner_or_admin(&user))466	}467468	/// Check that substrate account is the owner or admin of the collection469	///470	/// @param user account to verify471	/// @return "true" if account is the owner or admin472	fn is_owner_or_admin_substrate(&self, user: uint256) -> Result<bool> {473		let user = convert_uint256_to_cross_account::<T>(user);474		Ok(self.is_owner_or_admin(&user))475	}476477	/// Returns collection type478	///479	/// @return `Fungible` or `NFT` or `ReFungible`480	fn unique_collection_type(&mut self) -> Result<string> {481		let mode = match self.collection.mode {482			CollectionMode::Fungible(_) => "Fungible",483			CollectionMode::NFT => "NFT",484			CollectionMode::ReFungible => "ReFungible",485		};486		Ok(mode.into())487	}488489	/// Changes collection owner to another account490	///491	/// @dev Owner can be changed only by current owner492	/// @param newOwner new owner account493	fn set_owner(&mut self, caller: caller, new_owner: address) -> Result<void> {494		let caller = T::CrossAccountId::from_eth(caller);495		let new_owner = T::CrossAccountId::from_eth(new_owner);496		self.set_owner_internal(caller, new_owner)497			.map_err(dispatch_to_evm::<T>)498	}499500	/// Changes collection owner to another substrate account501	///502	/// @dev Owner can be changed only by current owner503	/// @param newOwner new owner substrate account504	fn set_owner_substrate(&mut self, caller: caller, new_owner: uint256) -> Result<void> {505		let caller = T::CrossAccountId::from_eth(caller);506		let new_owner = convert_uint256_to_cross_account::<T>(new_owner);507		self.set_owner_internal(caller, new_owner)508			.map_err(dispatch_to_evm::<T>)509	}510}511512fn check_is_owner_or_admin<T: Config>(513	caller: caller,514	collection: &CollectionHandle<T>,515) -> Result<T::CrossAccountId> {516	let caller = T::CrossAccountId::from_eth(caller);517	collection518		.check_is_owner_or_admin(&caller)519		.map_err(dispatch_to_evm::<T>)?;520	Ok(caller)521}522523fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {524	// TODO possibly delete for the lack of transaction525	collection.consume_store_writes(1)?;526	collection527		.check_is_internal()528		.map_err(dispatch_to_evm::<T>)?;529	collection.save().map_err(dispatch_to_evm::<T>)?;530	Ok(())531}532533/// Contains static property keys and values.534pub mod static_property {535	use evm_coder::{536		execution::{Result, Error},537	};538	use alloc::format;539540	const EXPECT_CONVERT_ERROR: &str = "length < limit";541542	/// Keys.543	pub mod key {544		use super::*;545546		/// Key "schemaName".547		pub fn schema_name() -> up_data_structs::PropertyKey {548			property_key_from_bytes(b"schemaName").expect(EXPECT_CONVERT_ERROR)549		}550551		/// Key "baseURI".552		pub fn base_uri() -> up_data_structs::PropertyKey {553			property_key_from_bytes(b"baseURI").expect(EXPECT_CONVERT_ERROR)554		}555556		/// Key "url".557		pub fn url() -> up_data_structs::PropertyKey {558			property_key_from_bytes(b"url").expect(EXPECT_CONVERT_ERROR)559		}560561		/// Key "suffix".562		pub fn suffix() -> up_data_structs::PropertyKey {563			property_key_from_bytes(b"suffix").expect(EXPECT_CONVERT_ERROR)564		}565566		/// Key "parentNft".567		pub fn parent_nft() -> up_data_structs::PropertyKey {568			property_key_from_bytes(b"parentNft").expect(EXPECT_CONVERT_ERROR)569		}570	}571572	/// Values.573	pub mod value {574		use super::*;575576		/// Value "ERC721Metadata".577		pub const ERC721_METADATA: &[u8] = b"ERC721Metadata";578579		/// Value for [`ERC721_METADATA`].580		pub fn erc721() -> up_data_structs::PropertyValue {581			property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR)582		}583	}584585	/// Convert `byte` to [`PropertyKey`].586	pub fn property_key_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyKey> {587		bytes.to_vec().try_into().map_err(|_| {588			Error::Revert(format!(589				"Property key is too long. Max length is {}.",590				up_data_structs::PropertyKey::bound()591			))592		})593	}594595	/// Convert `bytes` to [`PropertyValue`].596	pub fn property_value_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyValue> {597		bytes.to_vec().try_into().map_err(|_| {598			Error::Revert(format!(599				"Property key is too long. Max length is {}.",600				up_data_structs::PropertyKey::bound()601			))602		})603	}604}
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -64,7 +64,7 @@
 where
 	T::AccountId: From<[u8; 32]>,
 {
-	let mut new_admin_arr: [u8; 32] = Default::default();
+	let mut new_admin_arr = [0_u8; 32];
 	from.to_big_endian(&mut new_admin_arr);
 	let account_id = T::AccountId::from(new_admin_arr);
 	T::CrossAccountId::from_sub(account_id)
modifiedpallets/fungible/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/fungible/CHANGELOG.md
+++ b/pallets/fungible/CHANGELOG.md
@@ -5,7 +5,7 @@
 ## [v0.1.4] - 2022-08-24
 
 ### Change
- - Add bound `AsRef<[u8]>` to `T::CrossAccountId`.
+ - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
 
 <!-- bureaucrate goes here -->
 ## [v0.1.3] 2022-08-16
modifiedpallets/nonfungible/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/nonfungible/CHANGELOG.md
+++ b/pallets/nonfungible/CHANGELOG.md
@@ -5,7 +5,7 @@
 ## [v0.1.5] - 2022-08-24
 
 ### Change
- - Add bound `AsRef<[u8]>` to `T::CrossAccountId`.
+ - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
 
 <!-- bureaucrate goes here -->
 ## [v0.1.4] 2022-08-16
modifiedpallets/refungible/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/refungible/CHANGELOG.md
+++ b/pallets/refungible/CHANGELOG.md
@@ -5,7 +5,7 @@
 ## [v0.2.4] - 2022-08-24
 
 ### Change
- - Add bound `AsRef<[u8]>` to `T::CrossAccountId`.
+ - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
 
 <!-- bureaucrate goes here -->
 ## [v0.2.3] 2022-08-16
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -1,4 +1,4 @@
-import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';
+import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';
 import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub, subToEth} from './util/helpers';
 import nonFungibleAbi from './nonFungibleAbi.json';
 import {expect} from 'chai';
@@ -57,7 +57,7 @@
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;
     
     const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});
-    expect(sponsorTuple.field_0).to.be.eq(subToEth(sponsor.address));
+    expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);
   });
 
   itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => {
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -99,6 +99,10 @@
   }
 }
 
+export function bigIntToSub(api: ApiPromise, number: bigint) {
+  return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
+}
+
 export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {
   if (typeof input === 'string') {
     if (input.length >= 47) {