git.delta.rocks / unique-network / refs/commits / 742862849b4b

difftreelog

fix EVM mint with properties, minor improvements

Daniel Shiposha2023-10-13parent: #aae21d3.patch.diff
in: master

9 files changed

modifiedpallets/common/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/common/src/benchmarking.rs
+++ b/pallets/common/src/benchmarking.rs
@@ -29,9 +29,8 @@
 use sp_std::{vec, vec::Vec};
 use up_data_structs::{
 	AccessMode, CollectionId, CollectionMode, CollectionPermissions, CreateCollectionData,
-	NestingPermissions, PropertiesPermissionMap, Property, PropertyKey, PropertyValue,
-	MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_PROPERTIES_PER_ITEM,
-	MAX_TOKEN_PREFIX_LENGTH,
+	NestingPermissions, Property, PropertyKey, PropertyValue, MAX_COLLECTION_DESCRIPTION_LENGTH,
+	MAX_COLLECTION_NAME_LENGTH, MAX_PROPERTIES_PER_ITEM, MAX_TOKEN_PREFIX_LENGTH,
 };
 
 use crate::{BenchmarkPropertyWriter, CollectionHandle, Config, Pallet};
@@ -190,31 +189,6 @@
 		#[block]
 		{
 			<Pallet<T>>::set_collection_properties(&collection, &owner, props.into_iter())?;
-		}
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn delete_collection_properties(
-		b: Linear<0, MAX_PROPERTIES_PER_ITEM>,
-	) -> Result<(), BenchmarkError> {
-		bench_init! {
-			owner: sub; collection: collection(owner);
-			owner: cross_from_sub;
-		};
-		let props = (0..b)
-			.map(|p| Property {
-				key: property_key(p as usize),
-				value: property_value(),
-			})
-			.collect::<Vec<_>>();
-		<Pallet<T>>::set_collection_properties(&collection, &owner, props.into_iter())?;
-		let to_delete = (0..b).map(|p| property_key(p as usize)).collect::<Vec<_>>();
-
-		#[block]
-		{
-			<Pallet<T>>::delete_collection_properties(&collection, &owner, to_delete.into_iter())?;
 		}
 
 		Ok(())
@@ -253,7 +227,7 @@
 	}
 
 	#[benchmark]
-	fn init_token_properties_common() -> Result<(), BenchmarkError> {
+	fn property_writer_load_collection_info() -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
 			sender: sub;
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.1819pub use pallet_evm::{20	account::CrossAccountId, PrecompileHandle, PrecompileOutput, PrecompileResult,21};22use pallet_evm_coder_substrate::{23	abi::AbiType,24	dispatch_to_evm,25	execution::{Error, PreDispatch, Result},26	frontier_contract, solidity_interface,27	types::*,28	ToLog,29};30use sp_std::{vec, vec::Vec};31use up_data_structs::{32	CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property, SponsoringRateLimit,33	SponsorshipState,34};3536use crate::{37	eth, weights::WeightInfo, CollectionHandle, CollectionProperties, Config, Pallet, SelfWeightOf,38};3940frontier_contract! {41	macro_rules! CollectionHandle_result {...}42	impl<T: Config> Contract for CollectionHandle<T> {...}43}4445/// Events for ethereum collection helper.46#[derive(ToLog)]47pub enum CollectionHelpersEvents {48	/// The collection has been created.49	CollectionCreated {50		/// Collection owner.51		#[indexed]52		owner: Address,5354		/// Collection ID.55		#[indexed]56		collection_id: Address,57	},58	/// The collection has been destroyed.59	CollectionDestroyed {60		/// Collection ID.61		#[indexed]62		collection_id: Address,63	},64	/// The collection has been changed.65	CollectionChanged {66		/// Collection ID.67		#[indexed]68		collection_id: Address,69	},70}7172/// Does not always represent a full collection, for RFT it is either73/// collection (Implementing ERC721), or specific collection token (Implementing ERC20).74pub trait CommonEvmHandler {75	/// Raw compiled binary code of the contract stub76	const CODE: &'static [u8];7778	/// Call precompiled handle.79	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;80}8182/// @title A contract that allows you to work with collections.83#[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))]84impl<T: Config> CollectionHandle<T>85where86	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,87{88	/// Set collection property.89	///90	/// @param key Property key.91	/// @param value Propery value.92	#[solidity(hide)]93	#[weight(<SelfWeightOf<T>>::set_collection_properties(1))]94	fn set_collection_property(&mut self, caller: Caller, key: String, value: Bytes) -> Result<()> {95		let caller = T::CrossAccountId::from_eth(caller);96		let key = <Vec<u8>>::from(key)97			.try_into()98			.map_err(|_| "key too large")?;99		let value = value.0.try_into().map_err(|_| "value too large")?;100101		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })102			.map_err(dispatch_to_evm::<T>)103	}104105	/// Set collection properties.106	///107	/// @param properties Vector of properties key/value pair.108	#[weight(<SelfWeightOf<T>>::set_collection_properties(properties.len() as u32))]109	fn set_collection_properties(110		&mut self,111		caller: Caller,112		properties: Vec<eth::Property>,113	) -> Result<()> {114		let caller = T::CrossAccountId::from_eth(caller);115116		let properties = properties117			.into_iter()118			.map(eth::Property::try_into)119			.collect::<Result<Vec<_>>>()?;120121		<Pallet<T>>::set_collection_properties(self, &caller, properties.into_iter())122			.map_err(dispatch_to_evm::<T>)123	}124125	/// Delete collection property.126	///127	/// @param key Property key.128	#[solidity(hide)]129	#[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]130	fn delete_collection_property(&mut self, caller: Caller, key: String) -> Result<()> {131		let caller = T::CrossAccountId::from_eth(caller);132		let key = <Vec<u8>>::from(key)133			.try_into()134			.map_err(|_| "key too large")?;135136		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)137	}138139	/// Delete collection properties.140	///141	/// @param keys Properties keys.142	#[weight(<SelfWeightOf<T>>::delete_collection_properties(keys.len() as u32))]143	fn delete_collection_properties(&mut self, caller: Caller, keys: Vec<String>) -> Result<()> {144		let caller = T::CrossAccountId::from_eth(caller);145		let keys = keys146			.into_iter()147			.map(|key| {148				<Vec<u8>>::from(key)149					.try_into()150					.map_err(|_| Error::Revert("key too large".into()))151			})152			.collect::<Result<Vec<_>>>()?;153154		<Pallet<T>>::delete_collection_properties(self, &caller, keys.into_iter())155			.map_err(dispatch_to_evm::<T>)156	}157158	/// Get collection property.159	///160	/// @dev Throws error if key not found.161	///162	/// @param key Property key.163	/// @return bytes The property corresponding to the key.164	fn collection_property(&self, key: String) -> Result<Bytes> {165		let key = <Vec<u8>>::from(key)166			.try_into()167			.map_err(|_| "key too large")?;168169		let props = CollectionProperties::<T>::get(self.id);170		let prop = props.get(&key).ok_or("key not found")?;171172		Ok(Bytes(prop.to_vec()))173	}174175	/// Get collection properties.176	///177	/// @param keys Properties keys. Empty keys for all propertyes.178	/// @return Vector of properties key/value pairs.179	fn collection_properties(&self, keys: Vec<String>) -> Result<Vec<eth::Property>> {180		let keys = keys181			.into_iter()182			.map(|key| {183				<Vec<u8>>::from(key)184					.try_into()185					.map_err(|_| Error::Revert("key too large".into()))186			})187			.collect::<Result<Vec<_>>>()?;188189		let properties = Pallet::<T>::filter_collection_properties(190			self.id,191			if keys.is_empty() { None } else { Some(keys) },192		)193		.map_err(dispatch_to_evm::<T>)?;194195		let properties = properties196			.into_iter()197			.map(Property::try_into)198			.collect::<Result<Vec<_>>>()?;199		Ok(properties)200	}201202	/// Set the sponsor of the collection.203	///204	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.205	///206	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.207	#[solidity(hide)]208	fn set_collection_sponsor(&mut self, caller: Caller, sponsor: Address) -> Result<()> {209		self.consume_store_reads_and_writes(1, 1)?;210211		let caller = T::CrossAccountId::from_eth(caller);212213		let sponsor = T::CrossAccountId::from_eth(sponsor);214		self.set_sponsor(&caller, sponsor.as_sub().clone())215			.map_err(dispatch_to_evm::<T>)216	}217218	/// Set the sponsor of the collection.219	///220	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.221	///222	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.223	fn set_collection_sponsor_cross(224		&mut self,225		caller: Caller,226		sponsor: eth::CrossAddress,227	) -> Result<()> {228		self.consume_store_reads_and_writes(1, 1)?;229230		let caller = T::CrossAccountId::from_eth(caller);231232		let sponsor = sponsor.into_sub_cross_account::<T>()?;233		self.set_sponsor(&caller, sponsor.as_sub().clone())234			.map_err(dispatch_to_evm::<T>)235	}236237	/// Whether there is a pending sponsor.238	fn has_collection_pending_sponsor(&self) -> Result<bool> {239		Ok(matches!(240			self.collection.sponsorship,241			SponsorshipState::Unconfirmed(_)242		))243	}244245	/// Collection sponsorship confirmation.246	///247	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.248	fn confirm_collection_sponsorship(&mut self, caller: Caller) -> Result<()> {249		self.consume_store_writes(1)?;250251		let caller = T::CrossAccountId::from_eth(caller);252		self.confirm_sponsorship(caller.as_sub())253			.map_err(dispatch_to_evm::<T>)254	}255256	/// Remove collection sponsor.257	fn remove_collection_sponsor(&mut self, caller: Caller) -> Result<()> {258		self.consume_store_reads_and_writes(1, 1)?;259		let caller = T::CrossAccountId::from_eth(caller);260		self.remove_sponsor(&caller).map_err(dispatch_to_evm::<T>)261	}262263	/// Get current sponsor.264	///265	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.266	fn collection_sponsor(&self) -> Result<eth::CrossAddress> {267		let sponsor = match self.collection.sponsorship.sponsor() {268			Some(sponsor) => sponsor,269			None => return Ok(Default::default()),270		};271272		Ok(eth::CrossAddress::from_sub::<T>(sponsor))273	}274275	/// Get current collection limits.276	///277	/// @return Array of collection limits278	fn collection_limits(&self) -> Result<Vec<eth::CollectionLimit>> {279		let limits = &self.collection.limits;280281		Ok(vec![282			eth::CollectionLimit::new(283				eth::CollectionLimitField::AccountTokenOwnership,284				limits.account_token_ownership_limit,285			),286			eth::CollectionLimit::new(287				eth::CollectionLimitField::SponsoredDataSize,288				limits.sponsored_data_size,289			),290			limits291				.sponsored_data_rate_limit292				.and_then(|limit| {293					if let SponsoringRateLimit::Blocks(blocks) = limit {294						Some(eth::CollectionLimit::new(295							eth::CollectionLimitField::SponsoredDataRateLimit,296							Some(blocks),297						))298					} else {299						None300					}301				})302				.unwrap_or_else(|| {303					eth::CollectionLimit::new(304						eth::CollectionLimitField::SponsoredDataRateLimit,305						Default::default(),306					)307				}),308			eth::CollectionLimit::new(eth::CollectionLimitField::TokenLimit, limits.token_limit),309			eth::CollectionLimit::new(310				eth::CollectionLimitField::SponsorTransferTimeout,311				limits.sponsor_transfer_timeout,312			),313			eth::CollectionLimit::new(314				eth::CollectionLimitField::SponsorApproveTimeout,315				limits.sponsor_approve_timeout,316			),317			eth::CollectionLimit::new(318				eth::CollectionLimitField::OwnerCanTransfer,319				limits.owner_can_transfer.map(u32::from),320			),321			eth::CollectionLimit::new(322				eth::CollectionLimitField::OwnerCanDestroy,323				limits.owner_can_destroy.map(u32::from),324			),325			eth::CollectionLimit::new(326				eth::CollectionLimitField::TransferEnabled,327				limits.transfers_enabled.map(u32::from),328			),329		])330	}331332	/// Set limits for the collection.333	/// @dev Throws error if limit not found.334	/// @param limit Some limit.335	#[solidity(rename_selector = "setCollectionLimit")]336	fn set_collection_limit(&mut self, caller: Caller, limit: eth::CollectionLimit) -> Result<()> {337		self.consume_store_reads_and_writes(1, 1)?;338339		if !limit.has_value() {340			return Err(Error::Revert("user can't disable limits".into()));341		}342343		let caller = T::CrossAccountId::from_eth(caller);344		<Pallet<T>>::update_limits(&caller, self, limit.try_into()?).map_err(dispatch_to_evm::<T>)345	}346347	/// Get contract address.348	fn contract_address(&self) -> Result<Address> {349		Ok(crate::eth::collection_id_to_address(self.id))350	}351352	/// Add collection admin.353	/// @param newAdmin Cross account administrator address.354	fn add_collection_admin_cross(355		&mut self,356		caller: Caller,357		new_admin: eth::CrossAddress,358	) -> Result<()> {359		self.consume_store_reads_and_writes(2, 2)?;360361		let caller = T::CrossAccountId::from_eth(caller);362		let new_admin = new_admin.into_sub_cross_account::<T>()?;363		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;364		Ok(())365	}366367	/// Remove collection admin.368	/// @param admin Cross account administrator address.369	fn remove_collection_admin_cross(370		&mut self,371		caller: Caller,372		admin: eth::CrossAddress,373	) -> Result<()> {374		self.consume_store_reads_and_writes(2, 2)?;375376		let caller = T::CrossAccountId::from_eth(caller);377		let admin = admin.into_sub_cross_account::<T>()?;378		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;379		Ok(())380	}381382	/// Add collection admin.383	/// @param newAdmin Address of the added administrator.384	#[solidity(hide)]385	fn add_collection_admin(&mut self, caller: Caller, new_admin: Address) -> Result<()> {386		self.consume_store_reads_and_writes(2, 2)?;387388		let caller = T::CrossAccountId::from_eth(caller);389		let new_admin = T::CrossAccountId::from_eth(new_admin);390		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;391		Ok(())392	}393394	/// Remove collection admin.395	///396	/// @param admin Address of the removed administrator.397	#[solidity(hide)]398	fn remove_collection_admin(&mut self, caller: Caller, admin: Address) -> Result<()> {399		self.consume_store_reads_and_writes(2, 2)?;400401		let caller = T::CrossAccountId::from_eth(caller);402		let admin = T::CrossAccountId::from_eth(admin);403		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;404		Ok(())405	}406407	#[solidity(rename_selector = "setCollectionNesting")]408	fn set_nesting(409		&mut self,410		caller: Caller,411		collection_nesting_and_permissions: eth::CollectionNestingAndPermission,412	) -> Result<()> {413		self.consume_store_reads_and_writes(1, 1)?;414415		let caller = T::CrossAccountId::from_eth(caller);416417		let mut permissions = self.collection.permissions.clone();418		let mut nesting = permissions.nesting().clone();419420		let bv = if !collection_nesting_and_permissions.restricted.is_empty() {421			let mut bv = OwnerRestrictedSet::new();422			for address in collection_nesting_and_permissions.restricted.iter() {423				bv.try_insert(crate::eth::map_eth_to_id(address).ok_or_else(|| {424					Error::Revert("Can't convert address into collection id".into())425				})?)426				.map_err(|_| "too many collections")?;427			}428			Some(bv)429		} else {430			None431		};432433		nesting.token_owner = collection_nesting_and_permissions.token_owner;434		nesting.collection_admin = collection_nesting_and_permissions.collection_admin;435		nesting.restricted = bv;436		permissions.nesting = Some(nesting);437438		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)439	}440441	/// Toggle accessibility of collection nesting.442	///443	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'444	#[solidity(hide, rename_selector = "setCollectionNesting")]445	fn set_nesting_bool(&mut self, caller: Caller, enable: bool) -> Result<()> {446		self.consume_store_reads_and_writes(1, 1)?;447448		let caller = T::CrossAccountId::from_eth(caller);449450		let mut permissions = self.collection.permissions.clone();451		let mut nesting = permissions.nesting().clone();452		nesting.token_owner = enable;453		nesting.restricted = None;454		permissions.nesting = Some(nesting);455456		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)457	}458459	/// Toggle accessibility of collection nesting.460	///461	/// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'462	/// @param collections Addresses of collections that will be available for nesting.463	#[solidity(hide, rename_selector = "setCollectionNesting")]464	fn set_nesting_collection_ids(465		&mut self,466		caller: Caller,467		enable: bool,468		collections: Vec<Address>,469	) -> Result<()> {470		self.consume_store_reads_and_writes(1, 1)?;471472		if collections.is_empty() {473			return Err("no addresses provided".into());474		}475		let caller = T::CrossAccountId::from_eth(caller);476477		let mut permissions = self.collection.permissions.clone();478		match enable {479			false => {480				let mut nesting = permissions.nesting().clone();481				nesting.token_owner = false;482				nesting.restricted = None;483				permissions.nesting = Some(nesting);484			}485			true => {486				let mut bv = OwnerRestrictedSet::new();487				for i in collections {488					bv.try_insert(crate::eth::map_eth_to_id(&i).ok_or_else(|| {489						Error::Revert("Can't convert address into collection id".into())490					})?)491					.map_err(|_| "too many collections")?;492				}493				let mut nesting = permissions.nesting().clone();494				nesting.token_owner = true;495				nesting.restricted = Some(bv);496				permissions.nesting = Some(nesting);497			}498		};499500		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)501	}502503	#[solidity(rename_selector = "collectionNesting")]504	fn collection_nesting(&self) -> Result<eth::CollectionNestingAndPermission> {505		let nesting = self.collection.permissions.nesting();506507		Ok(eth::CollectionNestingAndPermission::new(508			nesting.token_owner,509			nesting.collection_admin,510			nesting511				.restricted512				.clone()513				.map(|b| {514					b.0.into_inner()515						.iter()516						.map(|id| crate::eth::collection_id_to_address(id.0.into()))517						.collect()518				})519				.unwrap_or_default(),520		))521	}522523	/// Returns nesting for a collection524	#[solidity(hide, rename_selector = "collectionNestingRestrictedCollectionIds")]525	fn collection_nesting_restricted_ids(&self) -> Result<eth::CollectionNesting> {526		let nesting = self.collection.permissions.nesting();527528		Ok(eth::CollectionNesting::new(529			nesting.token_owner,530			nesting531				.restricted532				.clone()533				.map(|b| b.0.into_inner().iter().map(|id| id.0.into()).collect())534				.unwrap_or_default(),535		))536	}537538	/// Returns permissions for a collection539	#[solidity(hide)]540	fn collection_nesting_permissions(&self) -> Result<Vec<eth::CollectionNestingPermission>> {541		let nesting = self.collection.permissions.nesting();542		Ok(vec![543			eth::CollectionNestingPermission::new(544				eth::CollectionPermissionField::CollectionAdmin,545				nesting.collection_admin,546			),547			eth::CollectionNestingPermission::new(548				eth::CollectionPermissionField::TokenOwner,549				nesting.token_owner,550			),551		])552	}553	/// Set the collection access method.554	/// @param mode Access mode555	fn set_collection_access(&mut self, caller: Caller, mode: eth::AccessMode) -> Result<()> {556		self.consume_store_reads_and_writes(1, 1)?;557558		let caller = T::CrossAccountId::from_eth(caller);559		let permissions = CollectionPermissions {560			access: Some(mode.into()),561			..Default::default()562		};563		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)564	}565566	/// Checks that user allowed to operate with collection.567	///568	/// @param user User address to check.569	fn allowlisted_cross(&self, user: eth::CrossAddress) -> Result<bool> {570		let user = user.into_sub_cross_account::<T>()?;571		Ok(Pallet::<T>::allowed(self.id, user))572	}573574	/// Add the user to the allowed list.575	///576	/// @param user Address of a trusted user.577	#[solidity(hide)]578	fn add_to_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {579		self.consume_store_writes(1)?;580581		let caller = T::CrossAccountId::from_eth(caller);582		let user = T::CrossAccountId::from_eth(user);583		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;584		Ok(())585	}586587	/// Add user to allowed list.588	///589	/// @param user User cross account address.590	fn add_to_collection_allow_list_cross(591		&mut self,592		caller: Caller,593		user: eth::CrossAddress,594	) -> Result<()> {595		self.consume_store_writes(1)?;596597		let caller = T::CrossAccountId::from_eth(caller);598		let user = user.into_sub_cross_account::<T>()?;599		Pallet::<T>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;600		Ok(())601	}602603	/// Remove the user from the allowed list.604	///605	/// @param user Address of a removed user.606	#[solidity(hide)]607	fn remove_from_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {608		self.consume_store_writes(1)?;609610		let caller = T::CrossAccountId::from_eth(caller);611		let user = T::CrossAccountId::from_eth(user);612		<Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;613		Ok(())614	}615616	/// Remove user from allowed list.617	///618	/// @param user User cross account address.619	fn remove_from_collection_allow_list_cross(620		&mut self,621		caller: Caller,622		user: eth::CrossAddress,623	) -> Result<()> {624		self.consume_store_writes(1)?;625626		let caller = T::CrossAccountId::from_eth(caller);627		let user = user.into_sub_cross_account::<T>()?;628		Pallet::<T>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;629		Ok(())630	}631632	/// Switch permission for minting.633	///634	/// @param mode Enable if "true".635	fn set_collection_mint_mode(&mut self, caller: Caller, mode: bool) -> Result<()> {636		self.consume_store_reads_and_writes(1, 1)?;637638		let caller = T::CrossAccountId::from_eth(caller);639		let permissions = CollectionPermissions {640			mint_mode: Some(mode),641			..Default::default()642		};643		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)644	}645646	/// Check that account is the owner or admin of the collection647	///648	/// @param user account to verify649	/// @return "true" if account is the owner or admin650	#[solidity(hide, rename_selector = "isOwnerOrAdmin")]651	fn is_owner_or_admin_eth(&self, user: Address) -> Result<bool> {652		let user = T::CrossAccountId::from_eth(user);653		Ok(self.is_owner_or_admin(&user))654	}655656	/// Check that account is the owner or admin of the collection657	///658	/// @param user User cross account to verify659	/// @return "true" if account is the owner or admin660	fn is_owner_or_admin_cross(&self, user: eth::CrossAddress) -> Result<bool> {661		let user = user.into_sub_cross_account::<T>()?;662		Ok(self.is_owner_or_admin(&user))663	}664665	/// Returns collection type666	///667	/// @return `Fungible` or `NFT` or `ReFungible`668	fn unique_collection_type(&self) -> Result<String> {669		let mode = match self.collection.mode {670			CollectionMode::Fungible(_) => "Fungible",671			CollectionMode::NFT => "NFT",672			CollectionMode::ReFungible => "ReFungible",673		};674		Ok(mode.into())675	}676677	/// Get collection owner.678	///679	/// @return Tuble with sponsor address and his substrate mirror.680	/// If address is canonical then substrate mirror is zero and vice versa.681	fn collection_owner(&self) -> Result<eth::CrossAddress> {682		Ok(eth::CrossAddress::from_sub_cross_account::<T>(683			&T::CrossAccountId::from_sub(self.owner.clone()),684		))685	}686687	/// Changes collection owner to another account688	///689	/// @dev Owner can be changed only by current owner690	/// @param newOwner new owner account691	#[solidity(hide, rename_selector = "changeCollectionOwner")]692	fn set_owner(&mut self, caller: Caller, new_owner: Address) -> Result<()> {693		self.consume_store_writes(1)?;694695		let caller = T::CrossAccountId::from_eth(caller);696		let new_owner = T::CrossAccountId::from_eth(new_owner);697		self.change_owner(caller, new_owner)698			.map_err(dispatch_to_evm::<T>)699	}700701	/// Get collection administrators702	///703	/// @return Vector of tuples with admins address and his substrate mirror.704	/// If address is canonical then substrate mirror is zero and vice versa.705	fn collection_admins(&self) -> Result<Vec<eth::CrossAddress>> {706		let result = crate::IsAdmin::<T>::iter_prefix((self.id,))707			.map(|(admin, _)| eth::CrossAddress::from_sub_cross_account::<T>(&admin))708			.collect();709		Ok(result)710	}711712	/// Changes collection owner to another account713	///714	/// @dev Owner can be changed only by current owner715	/// @param newOwner new owner cross account716	fn change_collection_owner_cross(717		&mut self,718		caller: Caller,719		new_owner: eth::CrossAddress,720	) -> Result<()> {721		self.consume_store_writes(1)?;722723		let caller = T::CrossAccountId::from_eth(caller);724		let new_owner = new_owner.into_sub_cross_account::<T>()?;725		self.change_owner(caller, new_owner)726			.map_err(dispatch_to_evm::<T>)727	}728}729730/// Contains static property keys and values.731pub mod static_property {732	use alloc::format;733734	use pallet_evm_coder_substrate::execution::{Error, Result};735736	const EXPECT_CONVERT_ERROR: &str = "length < limit";737738	/// Keys.739	pub mod key {740		use super::*;741742		/// Key "baseURI".743		pub fn base_uri() -> up_data_structs::PropertyKey {744			property_key_from_bytes(b"baseURI").expect(EXPECT_CONVERT_ERROR)745		}746747		/// Key "url".748		pub fn url() -> up_data_structs::PropertyKey {749			property_key_from_bytes(b"URI").expect(EXPECT_CONVERT_ERROR)750		}751752		/// Key "suffix".753		pub fn suffix() -> up_data_structs::PropertyKey {754			property_key_from_bytes(b"URISuffix").expect(EXPECT_CONVERT_ERROR)755		}756757		/// Key "parentNft".758		pub fn parent_nft() -> up_data_structs::PropertyKey {759			property_key_from_bytes(b"parentNft").expect(EXPECT_CONVERT_ERROR)760		}761	}762763	/// Convert `byte` to [`PropertyKey`].764	pub fn property_key_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyKey> {765		bytes.to_vec().try_into().map_err(|_| {766			Error::Revert(format!(767				"Property key is too long. Max length is {}.",768				up_data_structs::PropertyKey::bound()769			))770		})771	}772773	/// Convert `bytes` to [`PropertyValue`].774	pub fn property_value_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyValue> {775		bytes.to_vec().try_into().map_err(|_| {776			Error::Revert(format!(777				"Property key is too long. Max length is {}.",778				up_data_structs::PropertyKey::bound()779			))780		})781	}782}
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -2626,8 +2626,8 @@
 impl<T: Config> BenchmarkPropertyWriter<T> {
 	/// Creates a [`PropertyWriter`] for benchmarking tokens properties writing.
 	pub fn new<'a, Handle>(
-		collection: &Handle,
-		collection_lazy_info: PropertyWriterLazyCollectionInfo,
+		collection: &'a Handle,
+		collection_lazy_info: PropertyWriterLazyCollectionInfo<'a>,
 	) -> PropertyWriter<'a, Self, T, Handle>
 	where
 		Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -18,7 +18,6 @@
 use pallet_common::{
 	bench_init,
 	benchmarking::{create_collection_raw, property_key, property_value},
-	CommonCollectionOperations,
 };
 use sp_std::prelude::*;
 use up_data_structs::{
@@ -131,53 +130,12 @@
 		#[block]
 		{
 			<Pallet<T>>::burn(&collection, &burner, item)?;
-		}
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn burn_recursively_self_raw() -> Result<(), BenchmarkError> {
-		bench_init! {
-			owner: sub; collection: collection(owner);
-			sender: cross_from_sub(owner); burner: cross_sub;
-		};
-		let item = create_max_item(&collection, &sender, burner.clone())?;
-
-		#[block]
-		{
-			<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)?;
 		}
 
 		Ok(())
 	}
 
 	#[benchmark]
-	fn burn_recursively_breadth_plus_self_plus_self_per_each_raw(
-		b: Linear<0, 200>,
-	) -> Result<(), BenchmarkError> {
-		bench_init! {
-			owner: sub; collection: collection(owner);
-			sender: cross_from_sub(owner); burner: cross_sub;
-		};
-		let item = create_max_item(&collection, &sender, burner.clone())?;
-		for _ in 0..b {
-			create_max_item(
-				&collection,
-				&sender,
-				T::CrossTokenAddressMapping::token_to_address(collection.id, item),
-			)?;
-		}
-
-		#[block]
-		{
-			<Pallet<T>>::burn_recursively(&collection, &burner, item, &Unlimited, &Unlimited)?;
-		}
-
-		Ok(())
-	}
-
-	#[benchmark]
 	fn transfer_raw() -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
@@ -262,116 +220,34 @@
 		{
 			<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?;
 		}
-	}
 
-	// set_token_properties {
-	// 	let b in 0..MAX_PROPERTIES_PER_ITEM;
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
-	// 	let perms = (0..b).map(|k| PropertyKeyPermission {
-	// 		key: property_key(k as usize),
-	// 		permission: PropertyPermission {
-	// 			mutable: false,
-	// 			collection_admin: true,
-	// 			token_owner: true,
-	// 		},
-	// 	}).collect::<Vec<_>>();
-	// 	<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-	// 	let props = (0..b).map(|k| Property {
-	// 		key: property_key(k as usize),
-	// 		value: property_value(),
-	// 	}).collect::<Vec<_>>();
-	// 	let item = create_max_item(&collection, &owner, owner.clone())?;
-	// }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?}
-
-	// load_token_properties {
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
-
-	// 	let item = create_max_item(&collection, &owner, owner.clone())?;
-	// }: {
-	// 	pallet_common::BenchmarkPropertyWriter::<T>::load_token_properties(
-	// 		&collection,
-	// 		item,
-	// 	)
-	// }
-
-	// write_token_properties {
-	// 	let b in 0..MAX_PROPERTIES_PER_ITEM;
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
+		Ok(())
+	}
 
-	// 	let perms = (0..b).map(|k| PropertyKeyPermission {
-	// 		key: property_key(k as usize),
-	// 		permission: PropertyPermission {
-	// 			mutable: false,
-	// 			collection_admin: true,
-	// 			token_owner: true,
-	// 		},
-	// 	}).collect::<Vec<_>>();
-	// 	<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-	// 	let props = (0..b).map(|k| Property {
-	// 		key: property_key(k as usize),
-	// 		value: property_value(),
-	// 	}).collect::<Vec<_>>();
-	// 	let item = create_max_item(&collection, &owner, owner.clone())?;
-
-	// 	let lazy_collection_info = pallet_common::BenchmarkPropertyWriter::<T>::load_collection_info(
-	// 		&collection,
-	// 		&owner,
-	// 	);
-	// }: {
-	// 	let mut property_writer = pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info);
-
-	// 	property_writer.write_token_properties(
-	// 		item,
-	// 		props.into_iter(),
-	// 		crate::erc::ERC721TokenEvent::TokenChanged {
-	// 			token_id: item.into(),
-	// 		}
-	// 		.to_log(T::ContractAddress::get()),
-	// 	)?
-	// }
-
 	#[benchmark]
-	fn set_token_property_permissions(
-		b: Linear<0, MAX_PROPERTIES_PER_ITEM>,
-	) -> Result<(), BenchmarkError> {
+	fn load_token_properties() -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
 			owner: cross_from_sub;
 		};
-		let perms = (0..b)
-			.map(|k| PropertyKeyPermission {
-				key: property_key(k as usize),
-				permission: PropertyPermission {
-					mutable: false,
-					collection_admin: false,
-					token_owner: false,
-				},
-			})
-			.collect::<Vec<_>>();
 
+		let item = create_max_item(&collection, &owner, owner.clone())?;
+
 		#[block]
 		{
-			<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
+			pallet_common::BenchmarkPropertyWriter::<T>::load_token_properties(&collection, item);
 		}
 
 		Ok(())
 	}
 
 	#[benchmark]
-	fn set_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
+	fn write_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
 			owner: cross_from_sub;
 		};
+
 		let perms = (0..b)
 			.map(|k| PropertyKeyPermission {
 				key: property_key(k as usize),
@@ -391,71 +267,29 @@
 			.collect::<Vec<_>>();
 		let item = create_max_item(&collection, &owner, owner.clone())?;
 
+		let lazy_collection_info =
+			pallet_common::BenchmarkPropertyWriter::<T>::load_collection_info(&collection, &owner);
+
 		#[block]
 		{
-			<Pallet<T>>::set_token_properties(
-				&collection,
-				&owner,
+			let mut property_writer =
+				pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info);
+
+			property_writer.write_token_properties(
 				item,
 				props.into_iter(),
-				&Unlimited,
+				crate::erc::ERC721TokenEvent::TokenChanged {
+					token_id: item.into(),
+				}
+				.to_log(T::ContractAddress::get()),
 			)?;
 		}
 
 		Ok(())
 	}
 
-	// TODO:
 	#[benchmark]
-	fn init_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
-		// bench_init! {
-		// 	owner: sub; collection: collection(owner);
-		// 	owner: cross_from_sub;
-		// };
-
-		// let perms = (0..b)
-		// 	.map(|k| PropertyKeyPermission {
-		// 		key: property_key(k as usize),
-		// 		permission: PropertyPermission {
-		// 			mutable: false,
-		// 			collection_admin: true,
-		// 			token_owner: true,
-		// 		},
-		// 	})
-		// 	.collect::<Vec<_>>();
-		// <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-		#[block]
-		{}
-		// let props = (0..b)
-		// 	.map(|k| Property {
-		// 		key: property_key(k as usize),
-		// 		value: property_value(),
-		// 	})
-		// 	.collect::<Vec<_>>();
-		// let item = create_max_item(&collection, &owner, owner.clone())?;
-
-		// let (is_collection_admin, property_permissions) =
-		// 	load_is_admin_and_property_permissions(&collection, &owner);
-		// #[block]
-		// {
-		// 	let mut property_writer =
-		// 		pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info);
-
-		// 	property_writer.write_token_properties(
-		// 		item,
-		// 		props.into_iter(),
-		// 		crate::erc::ERC721TokenEvent::TokenChanged {
-		// 			token_id: item.into(),
-		// 		}
-		// 		.to_log(T::ContractAddress::get()),
-		// 	)?;
-		// }
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn delete_token_properties(
+	fn set_token_property_permissions(
 		b: Linear<0, MAX_PROPERTIES_PER_ITEM>,
 	) -> Result<(), BenchmarkError> {
 		bench_init! {
@@ -466,54 +300,16 @@
 			.map(|k| PropertyKeyPermission {
 				key: property_key(k as usize),
 				permission: PropertyPermission {
-					mutable: true,
-					collection_admin: true,
-					token_owner: true,
+					mutable: false,
+					collection_admin: false,
+					token_owner: false,
 				},
-			})
-			.collect::<Vec<_>>();
-		<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-		let props = (0..b)
-			.map(|k| Property {
-				key: property_key(k as usize),
-				value: property_value(),
 			})
 			.collect::<Vec<_>>();
-		let item = create_max_item(&collection, &owner, owner.clone())?;
-		<Pallet<T>>::set_token_properties(
-			&collection,
-			&owner,
-			item,
-			props.into_iter(),
-			&Unlimited,
-		)?;
-		let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
 
 		#[block]
 		{
-			<Pallet<T>>::delete_token_properties(
-				&collection,
-				&owner,
-				item,
-				to_delete.into_iter(),
-				&Unlimited,
-			)?;
-		}
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn token_owner() -> Result<(), BenchmarkError> {
-		bench_init! {
-			owner: sub; collection: collection(owner);
-			owner: cross_from_sub;
-		};
-		let item = create_max_item(&collection, &owner, owner.clone())?;
-
-		#[block]
-		{
-			collection.token_owner(item).unwrap();
+			<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
 		}
 
 		Ok(())
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -39,24 +39,21 @@
 impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
 	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
 		match data {
-			CreateItemExData::NFT(t) => <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)
-				.saturating_add(write_token_properties_total_weight::<T, _>(
-					t.iter().map(|t| t.properties.len() as u32),
-					<SelfWeightOf<T>>::write_token_properties,
-				)),
+			CreateItemExData::NFT(t) => mint_with_props_weight::<T>(
+				<SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32),
+				t.iter().map(|t| t.properties.len() as u32),
+			),
 			_ => Weight::zero(),
 		}
 	}
 
 	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
-		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
-			write_token_properties_total_weight::<T, _>(
-				data.iter().map(|t| match t {
-					up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32,
-					_ => 0,
-				}),
-				<SelfWeightOf<T>>::write_token_properties,
-			),
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items(data.len() as u32),
+			data.iter().map(|t| match t {
+				up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32,
+				_ => 0,
+			}),
 		)
 	}
 
@@ -113,6 +110,16 @@
 	}
 }
 
+pub(crate) fn mint_with_props_weight<T: Config>(
+	create_no_data_weight: Weight,
+	tokens: impl Iterator<Item = u32> + Clone,
+) -> Weight {
+	create_no_data_weight.saturating_add(write_token_properties_total_weight::<T, _>(
+		tokens,
+		<SelfWeightOf<T>>::write_token_properties,
+	))
+}
+
 fn map_create_data<T: Config>(
 	data: up_data_structs::CreateItemData,
 	to: &T::CrossAccountId,
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -49,8 +49,10 @@
 };
 
 use crate::{
-	common::CommonWeights, weights::WeightInfo, AccountBalance, Config, CreateItemData,
-	NonfungibleHandle, Pallet, SelfWeightOf, TokenData, TokenProperties, TokensMinted,
+	common::{mint_with_props_weight, CommonWeights},
+	weights::WeightInfo,
+	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, SelfWeightOf, TokenData,
+	TokenProperties, TokensMinted,
 };
 
 /// Nft events.
@@ -620,7 +622,7 @@
 	/// @param tokenUri Token URI that would be stored in the NFT properties
 	/// @return uint256 The id of the newly minted token
 	#[solidity(rename_selector = "mintWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [1].into_iter()))]
 	fn mint_with_token_uri(
 		&mut self,
 		caller: Caller,
@@ -642,7 +644,7 @@
 	/// @param tokenId ID of the minted NFT
 	/// @param tokenUri Token URI that would be stored in the NFT properties
 	#[solidity(hide, rename_selector = "mintWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [1].into_iter()))]
 	fn mint_with_token_uri_check_id(
 		&mut self,
 		caller: Caller,
@@ -974,7 +976,12 @@
 
 	/// @notice Function to mint a token.
 	/// @param data Array of pairs of token owner and token's properties for minted token
-	#[weight(<SelfWeightOf<T>>::create_multiple_items(data.len() as u32) + <SelfWeightOf<T>>::set_token_properties(data.len() as u32))]
+	#[weight(
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items_ex(data.len() as u32),
+			data.iter().map(|d| d.properties.len() as u32),
+		)
+	)]
 	fn mint_bulk_cross(&mut self, caller: Caller, data: Vec<MintTokenData>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 
@@ -1008,7 +1015,12 @@
 	/// @param to The new owner
 	/// @param tokens array of pairs of token ID and token URI for minted tokens
 	#[solidity(hide, rename_selector = "mintBulkWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]
+	#[weight(
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32),
+			tokens.iter().map(|_| 1),
+		)
+	)]
 	fn mint_bulk_with_token_uri(
 		&mut self,
 		caller: Caller,
@@ -1056,7 +1068,7 @@
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [properties.len() as u32].into_iter()))]
 	fn mint_cross(
 		&mut self,
 		caller: Caller,
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -421,114 +421,30 @@
 		Ok(())
 	}
 
-	// set_token_properties {
-	// 	let b in 0..MAX_PROPERTIES_PER_ITEM;
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
-	// 	let perms = (0..b).map(|k| PropertyKeyPermission {
-	// 		key: property_key(k as usize),
-	// 		permission: PropertyPermission {
-	// 			mutable: false,
-	// 			collection_admin: true,
-	// 			token_owner: true,
-	// 		},
-	// 	}).collect::<Vec<_>>();
-	// 	<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-	// 	let props = (0..b).map(|k| Property {
-	// 		key: property_key(k as usize),
-	// 		value: property_value(),
-	// 	}).collect::<Vec<_>>();
-	// 	let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
-	// }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?}
-
-	// load_token_properties {
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
-
-	// 	let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
-	// }: {
-	// 	pallet_common::BenchmarkPropertyWriter::<T>::load_token_properties(
-	// 		&collection,
-	// 		item,
-	// 	)
-	// }
-
-	// write_token_properties {
-	// 	let b in 0..MAX_PROPERTIES_PER_ITEM;
-	// 	bench_init!{
-	// 		owner: sub; collection: collection(owner);
-	// 		owner: cross_from_sub;
-	// 	};
-
-	// 	let perms = (0..b).map(|k| PropertyKeyPermission {
-	// 		key: property_key(k as usize),
-	// 		permission: PropertyPermission {
-	// 			mutable: false,
-	// 			collection_admin: true,
-	// 			token_owner: true,
-	// 		},
-	// 	}).collect::<Vec<_>>();
-	// 	<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-	// 	let props = (0..b).map(|k| Property {
-	// 		key: property_key(k as usize),
-	// 		value: property_value(),
-	// 	}).collect::<Vec<_>>();
-	// 	let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
-
-	// 	let lazy_collection_info = pallet_common::BenchmarkPropertyWriter::<T>::load_collection_info(
-	// 		&collection,
-	// 		&owner,
-	// 	);
-	// }: {
-	// 	let mut property_writer = pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info);
-
-	// 	property_writer.write_token_properties(
-	// 		item,
-	// 		props.into_iter(),
-	// 		crate::erc::ERC721TokenEvent::TokenChanged {
-	// 			token_id: item.into(),
-	// 		}
-	// 		.to_log(T::ContractAddress::get()),
-	// 	)?
-	// }
-
 	#[benchmark]
-	fn set_token_property_permissions(
-		b: Linear<0, MAX_PROPERTIES_PER_ITEM>,
-	) -> Result<(), BenchmarkError> {
+	fn load_token_properties() -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
 			owner: cross_from_sub;
 		};
-		let perms = (0..b)
-			.map(|k| PropertyKeyPermission {
-				key: property_key(k as usize),
-				permission: PropertyPermission {
-					mutable: false,
-					collection_admin: false,
-					token_owner: false,
-				},
-			})
-			.collect::<Vec<_>>();
 
+		let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
+
 		#[block]
 		{
-			<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
+			pallet_common::BenchmarkPropertyWriter::<T>::load_token_properties(&collection, item);
 		}
 
 		Ok(())
 	}
 
 	#[benchmark]
-	fn set_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
+	fn write_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
 		bench_init! {
 			owner: sub; collection: collection(owner);
 			owner: cross_from_sub;
 		};
+
 		let perms = (0..b)
 			.map(|k| PropertyKeyPermission {
 				key: property_key(k as usize),
@@ -548,73 +464,29 @@
 			.collect::<Vec<_>>();
 		let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
 
+		let lazy_collection_info =
+			pallet_common::BenchmarkPropertyWriter::<T>::load_collection_info(&collection, &owner);
+
 		#[block]
 		{
-			<Pallet<T>>::set_token_properties(
-				&collection,
-				&owner,
+			let mut property_writer =
+				pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info);
+
+			property_writer.write_token_properties(
 				item,
 				props.into_iter(),
-				&Unlimited,
+				crate::erc::ERC721TokenEvent::TokenChanged {
+					token_id: item.into(),
+				}
+				.to_log(T::ContractAddress::get()),
 			)?;
 		}
 
 		Ok(())
 	}
 
-	// TODO:
 	#[benchmark]
-	fn init_token_properties(b: Linear<0, MAX_PROPERTIES_PER_ITEM>) -> Result<(), BenchmarkError> {
-		// bench_init! {
-		// 	owner: sub; collection: collection(owner);
-		// 	owner: cross_from_sub;
-		// };
-
-		// let perms = (0..b)
-		// 	.map(|k| PropertyKeyPermission {
-		// 		key: property_key(k as usize),
-		// 		permission: PropertyPermission {
-		// 			mutable: false,
-		// 			collection_admin: true,
-		// 			token_owner: true,
-		// 		},
-		// 	})
-		// 	.collect::<Vec<_>>();
-		// <Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-
-		#[block]
-		{}
-		// let props = (0..b).map(|k| Property {
-		// 	key: property_key(k as usize),
-		// 	value: property_value(),
-		// }).collect::<Vec<_>>();
-		// let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
-
-		// let (is_collection_admin, property_permissions) = load_is_admin_and_property_permissions(&collection, &owner)
-		// let mut property_writer = pallet_common::collection_info_loaded_property_writer(
-		// 	&collection,
-		// 	is_collection_admin,
-		// 	property_permissions,
-		// );
-
-		// #[block]
-		// {
-		// 	property_writer.write_token_properties(
-		// 		true,
-		// 		item,
-		// 		props.into_iter(),
-		// 		crate::erc::ERC721TokenEvent::TokenChanged {
-		// 			token_id: item.into(),
-		// 		}
-		// 		.to_log(T::ContractAddress::get()),
-		// 	)?;
-		// }
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn delete_token_properties(
+	fn set_token_property_permissions(
 		b: Linear<0, MAX_PROPERTIES_PER_ITEM>,
 	) -> Result<(), BenchmarkError> {
 		bench_init! {
@@ -625,38 +497,16 @@
 			.map(|k| PropertyKeyPermission {
 				key: property_key(k as usize),
 				permission: PropertyPermission {
-					mutable: true,
-					collection_admin: true,
-					token_owner: true,
+					mutable: false,
+					collection_admin: false,
+					token_owner: false,
 				},
-			})
-			.collect::<Vec<_>>();
-		<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
-		let props = (0..b)
-			.map(|k| Property {
-				key: property_key(k as usize),
-				value: property_value(),
 			})
 			.collect::<Vec<_>>();
-		let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
-		<Pallet<T>>::set_token_properties(
-			&collection,
-			&owner,
-			item,
-			props.into_iter(),
-			&Unlimited,
-		)?;
-		let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
 
 		#[block]
 		{
-			<Pallet<T>>::delete_token_properties(
-				&collection,
-				&owner,
-				item,
-				to_delete.into_iter(),
-				&Unlimited,
-			)?;
+			<Pallet<T>>::set_token_property_permissions(&collection, &owner, perms)?;
 		}
 
 		Ok(())
@@ -673,22 +523,6 @@
 		#[block]
 		{
 			<Pallet<T>>::repartition(&collection, &owner, item, 200)?;
-		}
-
-		Ok(())
-	}
-
-	#[benchmark]
-	fn token_owner() -> Result<(), BenchmarkError> {
-		bench_init! {
-			owner: sub; collection: collection(owner);
-			sender: cross_from_sub(owner); owner: cross_sub;
-		};
-		let item = create_max_item(&collection, &sender, [(owner, 100)])?;
-
-		#[block]
-		{
-			<Pallet<T>>::token_owner(collection.id, item).unwrap();
 		}
 
 		Ok(())
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -47,35 +47,27 @@
 pub struct CommonWeights<T: Config>(PhantomData<T>);
 impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
 	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
-		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
-			write_token_properties_total_weight::<T, _>(
-				data.iter().map(|data| match data {
-					up_data_structs::CreateItemData::ReFungible(rft_data) => {
-						rft_data.properties.len() as u32
-					}
-					_ => 0,
-				}),
-				<SelfWeightOf<T>>::write_token_properties,
-			),
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items(data.len() as u32),
+			data.iter().map(|data| match data {
+				up_data_structs::CreateItemData::ReFungible(rft_data) => {
+					rft_data.properties.len() as u32
+				}
+				_ => 0,
+			}),
 		)
 	}
 
 	fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {
 		match call {
-			CreateItemExData::RefungibleMultipleOwners(i) => {
-				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)
-					.saturating_add(write_token_properties_total_weight::<T, _>(
-						[i.properties.len() as u32].into_iter(),
-						<SelfWeightOf<T>>::write_token_properties,
-					))
-			}
-			CreateItemExData::RefungibleMultipleItems(i) => {
-				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)
-					.saturating_add(write_token_properties_total_weight::<T, _>(
-						i.iter().map(|d| d.properties.len() as u32),
-						<SelfWeightOf<T>>::write_token_properties,
-					))
-			}
+			CreateItemExData::RefungibleMultipleOwners(i) => mint_with_props_weight::<T>(
+				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32),
+				[i.properties.len() as u32].into_iter(),
+			),
+			CreateItemExData::RefungibleMultipleItems(i) => mint_with_props_weight::<T>(
+				<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32),
+				i.iter().map(|d| d.properties.len() as u32),
+			),
 			_ => Weight::zero(),
 		}
 	}
@@ -138,6 +130,16 @@
 	}
 }
 
+pub(crate) fn mint_with_props_weight<T: Config>(
+	create_no_data_weight: Weight,
+	tokens: impl Iterator<Item = u32> + Clone,
+) -> Weight {
+	create_no_data_weight.saturating_add(write_token_properties_total_weight::<T, _>(
+		tokens,
+		<SelfWeightOf<T>>::write_token_properties,
+	))
+}
+
 fn map_create_data<T: Config>(
 	data: up_data_structs::CreateItemData,
 	to: &T::CrossAccountId,
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -50,8 +50,10 @@
 };
 
 use crate::{
-	common::CommonWeights, weights::WeightInfo, AccountBalance, Balance, Config, CreateItemData,
-	Pallet, RefungibleHandle, SelfWeightOf, TokenProperties, TokensMinted, TotalSupply,
+	common::{mint_with_props_weight, CommonWeights},
+	weights::WeightInfo,
+	AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, SelfWeightOf,
+	TokenProperties, TokensMinted, TotalSupply,
 };
 
 frontier_contract! {
@@ -661,7 +663,7 @@
 	/// @param tokenUri Token URI that would be stored in the NFT properties
 	/// @return uint256 The id of the newly minted token
 	#[solidity(rename_selector = "mintWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [1].into_iter()))]
 	fn mint_with_token_uri(
 		&mut self,
 		caller: Caller,
@@ -683,7 +685,7 @@
 	/// @param tokenId ID of the minted RFT
 	/// @param tokenUri Token URI that would be stored in the RFT properties
 	#[solidity(hide, rename_selector = "mintWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(1))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [1].into_iter()))]
 	fn mint_with_token_uri_check_id(
 		&mut self,
 		caller: Caller,
@@ -1052,22 +1054,26 @@
 	}
 
 	/// @notice Function to mint a token.
-	/// @param tokenProperties Properties of minted token
-	#[weight(if token_properties.len() == 1 {
-		<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(token_properties.iter().next().unwrap().owners.len() as u32)
+	/// @param tokensData Data of minted token(s)
+	#[weight(if tokens_data.len() == 1 {
+		let token_data = tokens_data.first().unwrap();
+
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(token_data.owners.len() as u32),
+			[token_data.properties.len() as u32].into_iter(),
+		)
 	} else {
-		<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(token_properties.len() as u32)
-	} + <SelfWeightOf<T>>::set_token_properties(token_properties.len() as u32))]
-	fn mint_bulk_cross(
-		&mut self,
-		caller: Caller,
-		token_properties: Vec<MintTokenData>,
-	) -> Result<bool> {
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(tokens_data.len() as u32),
+			tokens_data.iter().map(|d| d.properties.len() as u32),
+		)
+	})]
+	fn mint_bulk_cross(&mut self, caller: Caller, tokens_data: Vec<MintTokenData>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
-		let has_multiple_tokens = token_properties.len() > 1;
+		let has_multiple_tokens = tokens_data.len() > 1;
 
-		let mut create_rft_data = Vec::with_capacity(token_properties.len());
-		for MintTokenData { owners, properties } in token_properties {
+		let mut create_rft_data = Vec::with_capacity(tokens_data.len());
+		for MintTokenData { owners, properties } in tokens_data {
 			let has_multiple_owners = owners.len() > 1;
 			if has_multiple_tokens & has_multiple_owners {
 				return Err(
@@ -1108,7 +1114,12 @@
 	/// @param to The new owner
 	/// @param tokens array of pairs of token ID and token URI for minted tokens
 	#[solidity(hide, rename_selector = "mintBulkWithTokenURI")]
-	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32) + <SelfWeightOf<T>>::set_token_properties(tokens.len() as u32))]
+	#[weight(
+		mint_with_props_weight::<T>(
+			<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32),
+			tokens.iter().map(|_| 1),
+		)
+	)]
 	fn mint_bulk_with_token_uri(
 		&mut self,
 		caller: Caller,
@@ -1162,7 +1173,7 @@
 	/// @param to The new owner crossAccountId
 	/// @param properties Properties of minted token
 	/// @return uint256 The id of the newly minted token
-	#[weight(<SelfWeightOf<T>>::create_item() + <SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]
+	#[weight(mint_with_props_weight::<T>(<SelfWeightOf<T>>::create_item(), [properties.len() as u32].into_iter()))]
 	fn mint_cross(
 		&mut self,
 		caller: Caller,