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

difftreelog

chore fix warnings

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

3 files changed

modifiedpallets/common/src/eth.rsdiffbeforeafterboth
before · pallets/common/src/eth.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! The module contains a number of functions for converting and checking ethereum identifiers.1819use alloc::format;20use sp_std::{vec, vec::Vec};21use evm_coder::{22	AbiCoder,23	types::{uint256, address},24};25pub use pallet_evm::{Config, account::CrossAccountId};26use sp_core::H160;27use up_data_structs::CollectionId;2829// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 130// TODO: Unhardcode prefix31const ETH_COLLECTION_PREFIX: [u8; 16] = [32	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,33];3435/// Maps the ethereum address of the collection in substrate.36pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {37	if eth[0..16] != ETH_COLLECTION_PREFIX {38		return None;39	}40	let mut id_bytes = [0; 4];41	id_bytes.copy_from_slice(&eth[16..20]);42	Some(CollectionId(u32::from_be_bytes(id_bytes)))43}4445/// Maps the substrate collection id in ethereum.46pub fn collection_id_to_address(id: CollectionId) -> H160 {47	let mut out = [0; 20];48	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);49	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));50	H160(out)51}5253/// Check if the ethereum address is a collection.54pub fn is_collection(address: &H160) -> bool {55	address[0..16] == ETH_COLLECTION_PREFIX56}5758/// Convert `uint256` to `CrossAccountId`.59pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId60where61	T::AccountId: From<[u8; 32]>,62{63	let mut new_admin_arr = [0_u8; 32];64	from.to_big_endian(&mut new_admin_arr);65	let account_id = T::AccountId::from(new_admin_arr);66	T::CrossAccountId::from_sub(account_id)67}6869/// Ethereum representation of Optional value with uint256.70#[derive(Debug, Default, AbiCoder)]71pub struct OptionUint {72	status: bool,73	value: uint256,74}7576impl From<u32> for OptionUint {77	fn from(value: u32) -> Self {78		Self {79			status: true,80			value: uint256::from(value),81		}82	}83}8485impl From<Option<u32>> for OptionUint {86	fn from(value: Option<u32>) -> Self {87		match value {88			Some(value) => Self {89				status: true,90				value: value.into(),91			},92			None => Self {93				status: false,94				value: Default::default(),95			},96		}97	}98}99100impl From<bool> for OptionUint {101	fn from(value: bool) -> Self {102		Self {103			status: true,104			value: if value {105				uint256::from(1)106			} else {107				Default::default()108			},109		}110	}111}112113impl From<Option<bool>> for OptionUint {114	fn from(value: Option<bool>) -> Self {115		match value {116			Some(value) => Self::from(value),117			None => Self {118				status: false,119				value: Default::default(),120			},121		}122	}123}124125/// Ethereum representation of Optional value with CrossAddress.126#[derive(Debug, Default, AbiCoder)]127pub struct OptionCrossAddress {128	pub status: bool,129	pub value: CrossAddress,130}131132/// Cross account struct133#[derive(Debug, Default, AbiCoder)]134pub struct CrossAddress {135	pub(crate) eth: address,136	pub(crate) sub: uint256,137}138139impl CrossAddress {140	/// Converts `CrossAccountId` to [`CrossAddress`]141	pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self142	where143		T: pallet_evm::Config,144		T::AccountId: AsRef<[u8; 32]>,145	{146		if cross_account_id.is_canonical_substrate() {147			Self::from_sub::<T>(cross_account_id.as_sub())148		} else {149			Self {150				eth: *cross_account_id.as_eth(),151				sub: Default::default(),152			}153		}154	}155	/// Creates [`CrossAddress`] from substrate account156	pub fn from_sub<T>(account_id: &T::AccountId) -> Self157	where158		T: pallet_evm::Config,159		T::AccountId: AsRef<[u8; 32]>,160	{161		Self {162			eth: Default::default(),163			sub: uint256::from_big_endian(account_id.as_ref()),164		}165	}166	/// Converts [`CrossAddress`] to `CrossAccountId`167	pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>168	where169		T: pallet_evm::Config,170		T::AccountId: From<[u8; 32]>,171	{172		if self.eth == Default::default() && self.sub == Default::default() {173			Err("All fields of cross account is zeroed".into())174		} else if self.eth == Default::default() {175			Ok(convert_uint256_to_cross_account::<T>(self.sub))176		} else if self.sub == Default::default() {177			Ok(T::CrossAccountId::from_eth(self.eth))178		} else {179			Err("All fields of cross account is non zeroed".into())180		}181	}182}183184/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).185#[derive(Debug, Default, AbiCoder)]186pub struct Property {187	key: evm_coder::types::string,188	value: evm_coder::types::bytes,189}190191impl TryFrom<up_data_structs::Property> for Property {192	type Error = evm_coder::execution::Error;193194	fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {195		let key = evm_coder::types::string::from_utf8(from.key.into())196			.map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;197		let value = evm_coder::types::bytes(from.value.to_vec());198		Ok(Property { key, value })199	}200}201202impl TryInto<up_data_structs::Property> for Property {203	type Error = evm_coder::execution::Error;204205	fn try_into(self) -> Result<up_data_structs::Property, Self::Error> {206		let key = <Vec<u8>>::from(self.key)207			.try_into()208			.map_err(|_| "key too large")?;209210		let value = self.value.0.try_into().map_err(|_| "value too large")?;211212		Ok(up_data_structs::Property { key, value })213	}214}215216/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.217#[derive(Debug, Default, Clone, Copy, AbiCoder)]218#[repr(u8)]219pub enum CollectionLimitField {220	/// How many tokens can a user have on one account.221	#[default]222	AccountTokenOwnership,223224	/// How many bytes of data are available for sponsorship.225	SponsoredDataSize,226227	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]228	SponsoredDataRateLimit,229230	/// How many tokens can be mined into this collection.231	TokenLimit,232233	/// Timeouts for transfer sponsoring.234	SponsorTransferTimeout,235236	/// Timeout for sponsoring an approval in passed blocks.237	SponsorApproveTimeout,238239	/// Whether the collection owner of the collection can send tokens (which belong to other users).240	OwnerCanTransfer,241242	/// Can the collection owner burn other people's tokens.243	OwnerCanDestroy,244245	/// Is it possible to send tokens from this collection between users.246	TransferEnabled,247}248249/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.250#[derive(Debug, Default, AbiCoder)]251pub struct CollectionLimit {252	field: CollectionLimitField,253	value: OptionUint,254}255256impl CollectionLimit {257	/// Create [`CollectionLimit`] from field and value.258	pub fn new<T>(field: CollectionLimitField, value: T) -> Self259	where260		OptionUint: From<T>,261	{262		Self {263			field,264			value: value.into(),265		}266	}267	/// Whether the field contains a value.268	pub fn has_value(&self) -> bool {269		self.value.status270	}271}272273impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {274	type Error = evm_coder::execution::Error;275276	fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {277		let value = self.value.value.try_into().map_err(|error| {278			Self::Error::Revert(format!(279				"can't convert value to u32 \"{}\" because: \"{error}\"",280				self.value.value281			))282		})?;283284		let convert_value_to_bool = || match value {285			0 => Ok(false),286			1 => Ok(true),287			_ => {288				return Err(Self::Error::Revert(format!(289					"can't convert value to boolean \"{value}\""290				)))291			}292		};293294		let mut limits = up_data_structs::CollectionLimits::default();295		match self.field {296			CollectionLimitField::AccountTokenOwnership => {297				limits.account_token_ownership_limit = Some(value);298			}299			CollectionLimitField::SponsoredDataSize => {300				limits.sponsored_data_size = Some(value);301			}302			CollectionLimitField::SponsoredDataRateLimit => {303				limits.sponsored_data_rate_limit =304					Some(up_data_structs::SponsoringRateLimit::Blocks(value));305			}306			CollectionLimitField::TokenLimit => {307				limits.token_limit = Some(value);308			}309			CollectionLimitField::SponsorTransferTimeout => {310				limits.sponsor_transfer_timeout = Some(value);311			}312			CollectionLimitField::SponsorApproveTimeout => {313				limits.sponsor_approve_timeout = Some(value);314			}315			CollectionLimitField::OwnerCanTransfer => {316				limits.owner_can_transfer = Some(convert_value_to_bool()?);317			}318			CollectionLimitField::OwnerCanDestroy => {319				limits.owner_can_destroy = Some(convert_value_to_bool()?);320			}321			CollectionLimitField::TransferEnabled => {322				limits.transfers_enabled = Some(convert_value_to_bool()?);323			}324		};325		Ok(limits)326	}327}328329/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.330#[derive(Default, Debug, Clone, Copy, AbiCoder)]331#[repr(u8)]332pub enum CollectionPermissionField {333	/// Owner of token can nest tokens under it.334	#[default]335	TokenOwner,336337	/// Admin of token collection can nest tokens under token.338	CollectionAdmin,339}340341/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.342#[derive(AbiCoder, Copy, Clone, Default, Debug)]343#[repr(u8)]344pub enum TokenPermissionField {345	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]346	#[default]347	Mutable,348349	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]350	TokenOwner,351352	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]353	CollectionAdmin,354}355356/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.357#[derive(Debug, Default, AbiCoder)]358pub struct PropertyPermission {359	/// TokenPermission field.360	code: TokenPermissionField,361	/// TokenPermission value.362	value: bool,363}364365impl PropertyPermission {366	/// Make vector of [`PropertyPermission`] from [`up_data_structs::PropertyPermission`].367	pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec<Self> {368		vec![369			PropertyPermission {370				code: TokenPermissionField::Mutable,371				value: pp.mutable,372			},373			PropertyPermission {374				code: TokenPermissionField::TokenOwner,375				value: pp.token_owner,376			},377			PropertyPermission {378				code: TokenPermissionField::CollectionAdmin,379				value: pp.collection_admin,380			},381		]382	}383384	/// Make [`up_data_structs::PropertyPermission`] from vector of [`PropertyPermission`].385	pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {386		let mut token_permission = up_data_structs::PropertyPermission::default();387388		for PropertyPermission { code, value } in permission {389			match code {390				TokenPermissionField::Mutable => token_permission.mutable = value,391				TokenPermissionField::TokenOwner => token_permission.token_owner = value,392				TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,393			}394		}395		token_permission396	}397}398399/// Ethereum representation of Token Property Permissions.400#[derive(Debug, Default, AbiCoder)]401pub struct TokenPropertyPermission {402	/// Token property key.403	key: evm_coder::types::string,404	/// Token property permissions.405	permissions: Vec<PropertyPermission>,406}407408impl409	From<(410		up_data_structs::PropertyKey,411		up_data_structs::PropertyPermission,412	)> for TokenPropertyPermission413{414	fn from(415		value: (416			up_data_structs::PropertyKey,417			up_data_structs::PropertyPermission,418		),419	) -> Self {420		let (key, permission) = value;421		let key = evm_coder::types::string::from_utf8(key.into_inner())422			.expect("Stored key must be valid");423		let permissions = PropertyPermission::into_vec(permission);424		Self { key, permissions }425	}426}427428impl TokenPropertyPermission {429	/// Convert vector of [`TokenPropertyPermission`] into vector of [`up_data_structs::PropertyKeyPermission`].430	pub fn into_property_key_permissions(431		permissions: Vec<TokenPropertyPermission>,432	) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {433		let mut perms = Vec::new();434435		for TokenPropertyPermission { key, permissions } in permissions {436			let token_permission = PropertyPermission::from_vec(permissions);437438			perms.push(up_data_structs::PropertyKeyPermission {439				key: key.into_bytes().try_into().map_err(|_| "too long key")?,440				permission: token_permission,441			});442		}443		Ok(perms)444	}445}446447/// Nested collections.448#[derive(Debug, Default, AbiCoder)]449pub struct CollectionNesting {450	token_owner: bool,451	ids: Vec<uint256>,452}453454impl CollectionNesting {455	/// Create [`CollectionNesting`].456	pub fn new(token_owner: bool, ids: Vec<uint256>) -> Self {457		Self { token_owner, ids }458	}459}460461/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.462#[derive(Debug, Default, AbiCoder)]463pub struct CollectionNestingPermission {464	field: CollectionPermissionField,465	value: bool,466}467468impl CollectionNestingPermission {469	/// Create [`CollectionNestingPermission`].470	pub fn new(field: CollectionPermissionField, value: bool) -> Self {471		Self { field, value }472	}473}
after · pallets/common/src/eth.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! The module contains a number of functions for converting and checking ethereum identifiers.1819use alloc::format;20use sp_std::{vec, vec::Vec};21use evm_coder::{22	AbiCoder,23	types::{uint256, address},24};25pub use pallet_evm::{Config, account::CrossAccountId};26use sp_core::H160;27use up_data_structs::CollectionId;2829// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 130// TODO: Unhardcode prefix31const ETH_COLLECTION_PREFIX: [u8; 16] = [32	0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,33];3435/// Maps the ethereum address of the collection in substrate.36pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {37	if eth[0..16] != ETH_COLLECTION_PREFIX {38		return None;39	}40	let mut id_bytes = [0; 4];41	id_bytes.copy_from_slice(&eth[16..20]);42	Some(CollectionId(u32::from_be_bytes(id_bytes)))43}4445/// Maps the substrate collection id in ethereum.46pub fn collection_id_to_address(id: CollectionId) -> H160 {47	let mut out = [0; 20];48	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);49	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));50	H160(out)51}5253/// Check if the ethereum address is a collection.54pub fn is_collection(address: &H160) -> bool {55	address[0..16] == ETH_COLLECTION_PREFIX56}5758/// Convert `uint256` to `CrossAccountId`.59pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId60where61	T::AccountId: From<[u8; 32]>,62{63	let mut new_admin_arr = [0_u8; 32];64	from.to_big_endian(&mut new_admin_arr);65	let account_id = T::AccountId::from(new_admin_arr);66	T::CrossAccountId::from_sub(account_id)67}6869/// Ethereum representation of Optional value with uint256.70#[derive(Debug, Default, AbiCoder)]71pub struct OptionUint {72	status: bool,73	value: uint256,74}7576impl From<u32> for OptionUint {77	fn from(value: u32) -> Self {78		Self {79			status: true,80			value: uint256::from(value),81		}82	}83}8485impl From<Option<u32>> for OptionUint {86	fn from(value: Option<u32>) -> Self {87		match value {88			Some(value) => Self {89				status: true,90				value: value.into(),91			},92			None => Self {93				status: false,94				value: Default::default(),95			},96		}97	}98}99100impl From<bool> for OptionUint {101	fn from(value: bool) -> Self {102		Self {103			status: true,104			value: if value {105				uint256::from(1)106			} else {107				Default::default()108			},109		}110	}111}112113impl From<Option<bool>> for OptionUint {114	fn from(value: Option<bool>) -> Self {115		match value {116			Some(value) => Self::from(value),117			None => Self {118				status: false,119				value: Default::default(),120			},121		}122	}123}124125/// Ethereum representation of Optional value with CrossAddress.126#[derive(Debug, Default, AbiCoder)]127pub struct OptionCrossAddress {128	/// TODO: field description129	pub status: bool,130	/// TODO: field description131	pub value: CrossAddress,132}133134/// Cross account struct135#[derive(Debug, Default, AbiCoder)]136pub struct CrossAddress {137	pub(crate) eth: address,138	pub(crate) sub: uint256,139}140141impl CrossAddress {142	/// Converts `CrossAccountId` to [`CrossAddress`]143	pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self144	where145		T: pallet_evm::Config,146		T::AccountId: AsRef<[u8; 32]>,147	{148		if cross_account_id.is_canonical_substrate() {149			Self::from_sub::<T>(cross_account_id.as_sub())150		} else {151			Self {152				eth: *cross_account_id.as_eth(),153				sub: Default::default(),154			}155		}156	}157	/// Creates [`CrossAddress`] from substrate account158	pub fn from_sub<T>(account_id: &T::AccountId) -> Self159	where160		T: pallet_evm::Config,161		T::AccountId: AsRef<[u8; 32]>,162	{163		Self {164			eth: Default::default(),165			sub: uint256::from_big_endian(account_id.as_ref()),166		}167	}168	/// Converts [`CrossAddress`] to `CrossAccountId`169	pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>170	where171		T: pallet_evm::Config,172		T::AccountId: From<[u8; 32]>,173	{174		if self.eth == Default::default() && self.sub == Default::default() {175			Err("All fields of cross account is zeroed".into())176		} else if self.eth == Default::default() {177			Ok(convert_uint256_to_cross_account::<T>(self.sub))178		} else if self.sub == Default::default() {179			Ok(T::CrossAccountId::from_eth(self.eth))180		} else {181			Err("All fields of cross account is non zeroed".into())182		}183	}184}185186/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).187#[derive(Debug, Default, AbiCoder)]188pub struct Property {189	key: evm_coder::types::string,190	value: evm_coder::types::bytes,191}192193impl TryFrom<up_data_structs::Property> for Property {194	type Error = evm_coder::execution::Error;195196	fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {197		let key = evm_coder::types::string::from_utf8(from.key.into())198			.map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;199		let value = evm_coder::types::bytes(from.value.to_vec());200		Ok(Property { key, value })201	}202}203204impl TryInto<up_data_structs::Property> for Property {205	type Error = evm_coder::execution::Error;206207	fn try_into(self) -> Result<up_data_structs::Property, Self::Error> {208		let key = <Vec<u8>>::from(self.key)209			.try_into()210			.map_err(|_| "key too large")?;211212		let value = self.value.0.try_into().map_err(|_| "value too large")?;213214		Ok(up_data_structs::Property { key, value })215	}216}217218/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.219#[derive(Debug, Default, Clone, Copy, AbiCoder)]220#[repr(u8)]221pub enum CollectionLimitField {222	/// How many tokens can a user have on one account.223	#[default]224	AccountTokenOwnership,225226	/// How many bytes of data are available for sponsorship.227	SponsoredDataSize,228229	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]230	SponsoredDataRateLimit,231232	/// How many tokens can be mined into this collection.233	TokenLimit,234235	/// Timeouts for transfer sponsoring.236	SponsorTransferTimeout,237238	/// Timeout for sponsoring an approval in passed blocks.239	SponsorApproveTimeout,240241	/// Whether the collection owner of the collection can send tokens (which belong to other users).242	OwnerCanTransfer,243244	/// Can the collection owner burn other people's tokens.245	OwnerCanDestroy,246247	/// Is it possible to send tokens from this collection between users.248	TransferEnabled,249}250251/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.252#[derive(Debug, Default, AbiCoder)]253pub struct CollectionLimit {254	field: CollectionLimitField,255	value: OptionUint,256}257258impl CollectionLimit {259	/// Create [`CollectionLimit`] from field and value.260	pub fn new<T>(field: CollectionLimitField, value: T) -> Self261	where262		OptionUint: From<T>,263	{264		Self {265			field,266			value: value.into(),267		}268	}269	/// Whether the field contains a value.270	pub fn has_value(&self) -> bool {271		self.value.status272	}273}274275impl TryInto<up_data_structs::CollectionLimits> for CollectionLimit {276	type Error = evm_coder::execution::Error;277278	fn try_into(self) -> Result<up_data_structs::CollectionLimits, Self::Error> {279		let value = self.value.value.try_into().map_err(|error| {280			Self::Error::Revert(format!(281				"can't convert value to u32 \"{}\" because: \"{error}\"",282				self.value.value283			))284		})?;285286		let convert_value_to_bool = || match value {287			0 => Ok(false),288			1 => Ok(true),289			_ => {290				return Err(Self::Error::Revert(format!(291					"can't convert value to boolean \"{value}\""292				)))293			}294		};295296		let mut limits = up_data_structs::CollectionLimits::default();297		match self.field {298			CollectionLimitField::AccountTokenOwnership => {299				limits.account_token_ownership_limit = Some(value);300			}301			CollectionLimitField::SponsoredDataSize => {302				limits.sponsored_data_size = Some(value);303			}304			CollectionLimitField::SponsoredDataRateLimit => {305				limits.sponsored_data_rate_limit =306					Some(up_data_structs::SponsoringRateLimit::Blocks(value));307			}308			CollectionLimitField::TokenLimit => {309				limits.token_limit = Some(value);310			}311			CollectionLimitField::SponsorTransferTimeout => {312				limits.sponsor_transfer_timeout = Some(value);313			}314			CollectionLimitField::SponsorApproveTimeout => {315				limits.sponsor_approve_timeout = Some(value);316			}317			CollectionLimitField::OwnerCanTransfer => {318				limits.owner_can_transfer = Some(convert_value_to_bool()?);319			}320			CollectionLimitField::OwnerCanDestroy => {321				limits.owner_can_destroy = Some(convert_value_to_bool()?);322			}323			CollectionLimitField::TransferEnabled => {324				limits.transfers_enabled = Some(convert_value_to_bool()?);325			}326		};327		Ok(limits)328	}329}330331/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.332#[derive(Default, Debug, Clone, Copy, AbiCoder)]333#[repr(u8)]334pub enum CollectionPermissionField {335	/// Owner of token can nest tokens under it.336	#[default]337	TokenOwner,338339	/// Admin of token collection can nest tokens under token.340	CollectionAdmin,341}342343/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.344#[derive(AbiCoder, Copy, Clone, Default, Debug)]345#[repr(u8)]346pub enum TokenPermissionField {347	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]348	#[default]349	Mutable,350351	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]352	TokenOwner,353354	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]355	CollectionAdmin,356}357358/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.359#[derive(Debug, Default, AbiCoder)]360pub struct PropertyPermission {361	/// TokenPermission field.362	code: TokenPermissionField,363	/// TokenPermission value.364	value: bool,365}366367impl PropertyPermission {368	/// Make vector of [`PropertyPermission`] from [`up_data_structs::PropertyPermission`].369	pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec<Self> {370		vec![371			PropertyPermission {372				code: TokenPermissionField::Mutable,373				value: pp.mutable,374			},375			PropertyPermission {376				code: TokenPermissionField::TokenOwner,377				value: pp.token_owner,378			},379			PropertyPermission {380				code: TokenPermissionField::CollectionAdmin,381				value: pp.collection_admin,382			},383		]384	}385386	/// Make [`up_data_structs::PropertyPermission`] from vector of [`PropertyPermission`].387	pub fn from_vec(permission: Vec<Self>) -> up_data_structs::PropertyPermission {388		let mut token_permission = up_data_structs::PropertyPermission::default();389390		for PropertyPermission { code, value } in permission {391			match code {392				TokenPermissionField::Mutable => token_permission.mutable = value,393				TokenPermissionField::TokenOwner => token_permission.token_owner = value,394				TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value,395			}396		}397		token_permission398	}399}400401/// Ethereum representation of Token Property Permissions.402#[derive(Debug, Default, AbiCoder)]403pub struct TokenPropertyPermission {404	/// Token property key.405	key: evm_coder::types::string,406	/// Token property permissions.407	permissions: Vec<PropertyPermission>,408}409410impl411	From<(412		up_data_structs::PropertyKey,413		up_data_structs::PropertyPermission,414	)> for TokenPropertyPermission415{416	fn from(417		value: (418			up_data_structs::PropertyKey,419			up_data_structs::PropertyPermission,420		),421	) -> Self {422		let (key, permission) = value;423		let key = evm_coder::types::string::from_utf8(key.into_inner())424			.expect("Stored key must be valid");425		let permissions = PropertyPermission::into_vec(permission);426		Self { key, permissions }427	}428}429430impl TokenPropertyPermission {431	/// Convert vector of [`TokenPropertyPermission`] into vector of [`up_data_structs::PropertyKeyPermission`].432	pub fn into_property_key_permissions(433		permissions: Vec<TokenPropertyPermission>,434	) -> evm_coder::execution::Result<Vec<up_data_structs::PropertyKeyPermission>> {435		let mut perms = Vec::new();436437		for TokenPropertyPermission { key, permissions } in permissions {438			let token_permission = PropertyPermission::from_vec(permissions);439440			perms.push(up_data_structs::PropertyKeyPermission {441				key: key.into_bytes().try_into().map_err(|_| "too long key")?,442				permission: token_permission,443			});444		}445		Ok(perms)446	}447}448449/// Nested collections.450#[derive(Debug, Default, AbiCoder)]451pub struct CollectionNesting {452	token_owner: bool,453	ids: Vec<uint256>,454}455456impl CollectionNesting {457	/// Create [`CollectionNesting`].458	pub fn new(token_owner: bool, ids: Vec<uint256>) -> Self {459		Self { token_owner, ids }460	}461}462463/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.464#[derive(Debug, Default, AbiCoder)]465pub struct CollectionNestingPermission {466	field: CollectionPermissionField,467	value: bool,468}469470impl CollectionNestingPermission {471	/// Create [`CollectionNestingPermission`].472	pub fn new(field: CollectionPermissionField, value: bool) -> Self {473		Self { field, value }474	}475}
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -23,7 +23,7 @@
 	execution::Result,
 	generate_stubgen, solidity_interface,
 	types::*,
-	ToLog, AbiCoder,
+	ToLog,
 };
 use pallet_common::eth;
 use pallet_evm::{
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -151,7 +151,7 @@
       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');
@@ -332,16 +332,16 @@
       nominal = helper.balance.getOneTokenNominal();
     });
   });
-  
+
   [
     'mintCross',
     'mintWithTokenURI',
-  ].map(testCase => 
+  ].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);
@@ -351,11 +351,11 @@
       expect(await helper.balance.getEthereum(minter)).to.equal(0n);
 
       const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
-      const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
+      const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true);
 
       await collection.addToAllowList(alice, {Ethereum: minter});
       await collection.addAdmin(alice, {Ethereum: owner});
-      const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
+      const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner);
       await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/')
         .send();
 
@@ -387,26 +387,26 @@
   [
     'setCollectionSponsorCross',
     'setCollectionSponsor', // Soft-deprecated
-  ].map(testCase => 
+  ].map(testCase =>
     itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
-      const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);
-  
+      const collectionHelpers = await 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');
-  
+      const collectionEvm = await 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 sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner});
       expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000');
     }));
@@ -414,35 +414,35 @@
   [
     'setCollectionSponsorCross',
     'setCollectionSponsor', // Soft-deprecated
-  ].map(testCase => 
+  ].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');
-  
+      const collectionEvm = await 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('ConfirmSponsorshipFail');
-      
+
       // 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;
@@ -451,11 +451,11 @@
       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 userBalanceBefore =  await helper.balance.getSubstrate(helper.address.ethToSubstrate(user));
@@ -474,11 +474,11 @@
             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(userBalanceBefore);
@@ -489,16 +489,16 @@
   [
     'setCollectionSponsorCross',
     'setCollectionSponsor', // Soft-deprecated
-  ].map(testCase => 
+  ].map(testCase =>
     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);
-  
+
       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');
+      const collectionEvm = await 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();
@@ -507,7 +507,7 @@
       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));
@@ -520,16 +520,16 @@
       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',
@@ -540,7 +540,7 @@
         },
       });
       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));
@@ -555,7 +555,7 @@
     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, false);
+    const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
     // Set collection sponsor:
     expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false;
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
@@ -577,7 +577,7 @@
 
     const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner));
     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;
 
@@ -608,7 +608,7 @@
     const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor);
 
     const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', '');
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
+    const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false);
 
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner});
 
@@ -619,7 +619,7 @@
     expect(nextTokenId).to.be.equal('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});
 
@@ -636,8 +636,8 @@
       ).send({from: user});
 
       const events = helper.eth.normalizeEvents(mintingResult.events);
-      
 
+
       expect(events).to.deep.include({
         address: collectionAddress,
         event: 'Transfer',
@@ -668,7 +668,7 @@
 
     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);
+    const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
     // Set and confirm sponsor:
     await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner});
@@ -685,7 +685,7 @@
     'transferCross',
     'transferFrom',
     'transferFromCross',
-  ].map(testCase => 
+  ].map(testCase =>
     itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
 
@@ -693,7 +693,7 @@
       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 collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
       await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
@@ -704,7 +704,7 @@
 
       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));
@@ -748,7 +748,7 @@
     'transferCross',
     'transferFrom',
     'transferFromCross',
-  ].map(testCase => 
+  ].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);
 
@@ -756,7 +756,7 @@
       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 collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
       await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
@@ -768,9 +768,9 @@
       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);   
+      const tokenContract = await 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));
@@ -801,7 +801,7 @@
   [
     'approve',
     'approveCross',
-  ].map(testCase => 
+  ].map(testCase =>
     itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => {
       const owner = await helper.eth.createAccountWithBalance(donor);
 
@@ -809,7 +809,7 @@
       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 collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner);
 
       await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send();
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
@@ -821,9 +821,9 @@
       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);  
+      const tokenContract = await 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));