git.delta.rocks / unique-network / refs/commits / 85427bc1a7e4

difftreelog

CORE-386 Fix create item with public minting

Trubnikov Sergey2022-06-02parent: #5a98909.patch.diff
in: master

4 files changed

modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
before · pallets/nonfungible/src/common.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/>.1617use core::marker::PhantomData;1819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use up_data_structs::{21	TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,22	PropertyKeyPermission, PropertyValue,23};24use pallet_common::{25	CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,26};27use sp_runtime::DispatchError;28use sp_std::vec::Vec;2930use crate::{31	AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,32	SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted,33};3435pub struct CommonWeights<T: Config>(PhantomData<T>);36impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {37	fn create_item() -> Weight {38		<SelfWeightOf<T>>::create_item()39	}4041	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {42		match data {43			CreateItemExData::NFT(t) => {44				<SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)45					+ t.iter()46						.map(|t| {47							if t.properties.len() > 0 {48								Self::set_token_properties(t.properties.len() as u32)49							} else {50								051							}52						})53						.sum::<u64>()54			}55			_ => 0,56		}57	}5859	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {60		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32)61			+ data62				.iter()63				.filter_map(|t| match t {64					up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => {65						Some(Self::set_token_properties(n.properties.len() as u32))66					}67					_ => None,68				})69				.sum::<u64>()70	}7172	fn burn_item() -> Weight {73		<SelfWeightOf<T>>::burn_item()74	}7576	fn set_collection_properties(amount: u32) -> Weight {77		<pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)78	}7980	fn delete_collection_properties(amount: u32) -> Weight {81		<pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)82	}8384	fn set_token_properties(amount: u32) -> Weight {85		<SelfWeightOf<T>>::set_token_properties(amount)86	}8788	fn delete_token_properties(amount: u32) -> Weight {89		<SelfWeightOf<T>>::delete_token_properties(amount)90	}9192	fn set_property_permissions(amount: u32) -> Weight {93		<SelfWeightOf<T>>::set_property_permissions(amount)94	}9596	fn transfer() -> Weight {97		<SelfWeightOf<T>>::transfer()98	}99100	fn approve() -> Weight {101		<SelfWeightOf<T>>::approve()102	}103104	fn transfer_from() -> Weight {105		<SelfWeightOf<T>>::transfer_from()106	}107108	fn burn_from() -> Weight {109		<SelfWeightOf<T>>::burn_from()110	}111112	fn burn_recursively_self_raw() -> Weight {113		<SelfWeightOf<T>>::burn_recursively_self_raw()114	}115116	fn burn_recursively_breadth_raw(amount: u32) -> Weight {117		<SelfWeightOf<T>>::burn_recursively_breadth_plus_self_plus_self_per_each_raw(amount)118			.saturating_sub(Self::burn_recursively_self_raw().saturating_mul(amount as u64 + 1))119	}120}121122fn map_create_data<T: Config>(123	data: up_data_structs::CreateItemData,124	to: &T::CrossAccountId,125) -> Result<CreateItemData<T>, DispatchError> {126	match data {127		up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {128			properties: data.properties,129			owner: to.clone(),130		}),131		_ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),132	}133}134135impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {136	fn create_item(137		&self,138		sender: T::CrossAccountId,139		to: T::CrossAccountId,140		data: up_data_structs::CreateItemData,141		nesting_budget: &dyn Budget,142	) -> DispatchResultWithPostInfo {143		with_weight(144			<Pallet<T>>::create_item(145				self,146				&sender,147				map_create_data::<T>(data, &to)?,148				nesting_budget,149			),150			<CommonWeights<T>>::create_item(),151		)152	}153154	fn create_multiple_items(155		&self,156		sender: T::CrossAccountId,157		to: T::CrossAccountId,158		data: Vec<up_data_structs::CreateItemData>,159		nesting_budget: &dyn Budget,160	) -> DispatchResultWithPostInfo {161		let weight = <CommonWeights<T>>::create_multiple_items(&data);162		let data = data163			.into_iter()164			.map(|d| map_create_data::<T>(d, &to))165			.collect::<Result<Vec<_>, DispatchError>>()?;166167		with_weight(168			<Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),169			weight,170		)171	}172173	fn create_multiple_items_ex(174		&self,175		sender: <T>::CrossAccountId,176		data: up_data_structs::CreateItemExData<<T>::CrossAccountId>,177		nesting_budget: &dyn Budget,178	) -> DispatchResultWithPostInfo {179		let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);180		let data = match data {181			up_data_structs::CreateItemExData::NFT(nft) => nft,182			_ => fail!(Error::<T>::NotNonfungibleDataUsedToMintFungibleCollectionToken),183		};184185		with_weight(186			<Pallet<T>>::create_multiple_items(self, &sender, data.into_inner(), nesting_budget),187			weight,188		)189	}190191	fn set_collection_properties(192		&self,193		sender: T::CrossAccountId,194		properties: Vec<Property>,195	) -> DispatchResultWithPostInfo {196		let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);197198		with_weight(199			<Pallet<T>>::set_collection_properties(self, &sender, properties),200			weight,201		)202	}203204	fn delete_collection_properties(205		&self,206		sender: &T::CrossAccountId,207		property_keys: Vec<PropertyKey>,208	) -> DispatchResultWithPostInfo {209		let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);210211		with_weight(212			<Pallet<T>>::delete_collection_properties(self, sender, property_keys),213			weight,214		)215	}216217	fn set_token_properties(218		&self,219		sender: T::CrossAccountId,220		token_id: TokenId,221		properties: Vec<Property>,222	) -> DispatchResultWithPostInfo {223		let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);224225		with_weight(226			<Pallet<T>>::set_token_properties(self, &sender, token_id, properties),227			weight,228		)229	}230231	fn delete_token_properties(232		&self,233		sender: T::CrossAccountId,234		token_id: TokenId,235		property_keys: Vec<PropertyKey>,236	) -> DispatchResultWithPostInfo {237		let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);238239		with_weight(240			<Pallet<T>>::delete_token_properties(self, &sender, token_id, property_keys),241			weight,242		)243	}244245	fn set_property_permissions(246		&self,247		sender: &T::CrossAccountId,248		property_permissions: Vec<PropertyKeyPermission>,249	) -> DispatchResultWithPostInfo {250		let weight =251			<CommonWeights<T>>::set_property_permissions(property_permissions.len() as u32);252253		with_weight(254			<Pallet<T>>::set_property_permissions(self, sender, property_permissions),255			weight,256		)257	}258259	fn burn_item(260		&self,261		sender: T::CrossAccountId,262		token: TokenId,263		amount: u128,264	) -> DispatchResultWithPostInfo {265		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);266		if amount == 1 {267			with_weight(268				<Pallet<T>>::burn(self, &sender, token),269				<CommonWeights<T>>::burn_item(),270			)271		} else {272			Ok(().into())273		}274	}275276	fn burn_item_recursively(277		&self,278		sender: T::CrossAccountId,279		token: TokenId,280		self_budget: &dyn Budget,281		breadth_budget: &dyn Budget,282	) -> DispatchResultWithPostInfo {283		<Pallet<T>>::burn_recursively(self, &sender, token, self_budget, breadth_budget)284	}285286	fn transfer(287		&self,288		from: T::CrossAccountId,289		to: T::CrossAccountId,290		token: TokenId,291		amount: u128,292		nesting_budget: &dyn Budget,293	) -> DispatchResultWithPostInfo {294		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);295		if amount == 1 {296			with_weight(297				<Pallet<T>>::transfer(self, &from, &to, token, nesting_budget),298				<CommonWeights<T>>::transfer(),299			)300		} else {301			Ok(().into())302		}303	}304305	fn approve(306		&self,307		sender: T::CrossAccountId,308		spender: T::CrossAccountId,309		token: TokenId,310		amount: u128,311	) -> DispatchResultWithPostInfo {312		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);313314		with_weight(315			if amount == 1 {316				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))317			} else {318				<Pallet<T>>::set_allowance(self, &sender, token, None)319			},320			<CommonWeights<T>>::approve(),321		)322	}323324	fn transfer_from(325		&self,326		sender: T::CrossAccountId,327		from: T::CrossAccountId,328		to: T::CrossAccountId,329		token: TokenId,330		amount: u128,331		nesting_budget: &dyn Budget,332	) -> DispatchResultWithPostInfo {333		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);334335		if amount == 1 {336			with_weight(337				<Pallet<T>>::transfer_from(self, &sender, &from, &to, token, nesting_budget),338				<CommonWeights<T>>::transfer_from(),339			)340		} else {341			Ok(().into())342		}343	}344345	fn burn_from(346		&self,347		sender: T::CrossAccountId,348		from: T::CrossAccountId,349		token: TokenId,350		amount: u128,351		nesting_budget: &dyn Budget,352	) -> DispatchResultWithPostInfo {353		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);354355		if amount == 1 {356			with_weight(357				<Pallet<T>>::burn_from(self, &sender, &from, token, nesting_budget),358				<CommonWeights<T>>::burn_from(),359			)360		} else {361			Ok(().into())362		}363	}364365	fn check_nesting(366		&self,367		sender: T::CrossAccountId,368		from: (CollectionId, TokenId),369		under: TokenId,370		budget: &dyn Budget,371	) -> sp_runtime::DispatchResult {372		<Pallet<T>>::check_nesting(self, sender, from, under, budget)373	}374375	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId)) {376		<Pallet<T>>::nest((self.id, under), to_nest);377	}378379	fn unnest(&self, under: TokenId, to_unnest: (CollectionId, TokenId)) {380		<Pallet<T>>::unnest((self.id, under), to_unnest);381	}382383	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {384		<Owned<T>>::iter_prefix((self.id, account))385			.map(|(id, _)| id)386			.collect()387	}388389	fn collection_tokens(&self) -> Vec<TokenId> {390		<TokenData<T>>::iter_prefix((self.id,))391			.map(|(id, _)| id)392			.collect()393	}394395	fn token_exists(&self, token: TokenId) -> bool {396		<Pallet<T>>::token_exists(self, token)397	}398399	fn last_token_id(&self) -> TokenId {400		TokenId(<TokensMinted<T>>::get(self.id))401	}402403	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {404		<TokenData<T>>::get((self.id, token)).map(|t| t.owner)405	}406407	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {408		<Pallet<T>>::token_properties((self.id, token_id))409			.get(key)410			.cloned()411	}412413	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {414		let properties = <Pallet<T>>::token_properties((self.id, token_id));415416		keys.map(|keys| {417			keys.into_iter()418				.filter_map(|key| {419					properties.get(&key).map(|value| Property {420						key,421						value: value.clone(),422					})423				})424				.collect()425		})426		.unwrap_or_else(|| {427			properties428				.into_iter()429				.map(|(key, value)| Property { key, value })430				.collect()431		})432	}433434	fn total_supply(&self) -> u32 {435		<Pallet<T>>::total_supply(self)436	}437438	fn account_balance(&self, account: T::CrossAccountId) -> u32 {439		<AccountBalance<T>>::get((self.id, account))440	}441442	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {443		if <TokenData<T>>::get((self.id, token))444			.map(|a| a.owner == account)445			.unwrap_or(false)446		{447			1448		} else {449			0450		}451	}452453	fn allowance(454		&self,455		sender: T::CrossAccountId,456		spender: T::CrossAccountId,457		token: TokenId,458	) -> u128 {459		if <TokenData<T>>::get((self.id, token))460			.map(|a| a.owner != sender)461			.unwrap_or(true)462		{463			0464		} else if <Allowance<T>>::get((self.id, token)) == Some(spender) {465			1466		} else {467			0468		}469	}470}
after · pallets/nonfungible/src/common.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/>.1617use core::marker::PhantomData;1819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use up_data_structs::{21	TokenId, CreateItemExData, CollectionId, budget::Budget, Property, PropertyKey,22	PropertyKeyPermission, PropertyValue,23};24use pallet_common::{25	CommonCollectionOperations, CommonWeightInfo, with_weight, weights::WeightInfo as _,26};27use sp_runtime::DispatchError;28use sp_std::vec::Vec;2930use crate::{31	AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,32	SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted,33};3435pub struct CommonWeights<T: Config>(PhantomData<T>);36impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {37	fn create_item() -> Weight {38		<SelfWeightOf<T>>::create_item()39	}4041	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {42		match data {43			CreateItemExData::NFT(t) => {44				<SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)45					+ t.iter()46						.map(|t| {47							if t.properties.len() > 0 {48								Self::set_token_properties(t.properties.len() as u32)49							} else {50								051							}52						})53						.sum::<u64>()54			}55			_ => 0,56		}57	}5859	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {60		<SelfWeightOf<T>>::create_multiple_items(data.len() as u32)61			+ data62				.iter()63				.filter_map(|t| match t {64					up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => {65						Some(Self::set_token_properties(n.properties.len() as u32))66					}67					_ => None,68				})69				.sum::<u64>()70	}7172	fn burn_item() -> Weight {73		<SelfWeightOf<T>>::burn_item()74	}7576	fn set_collection_properties(amount: u32) -> Weight {77		<pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)78	}7980	fn delete_collection_properties(amount: u32) -> Weight {81		<pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)82	}8384	fn set_token_properties(amount: u32) -> Weight {85		<SelfWeightOf<T>>::set_token_properties(amount)86	}8788	fn delete_token_properties(amount: u32) -> Weight {89		<SelfWeightOf<T>>::delete_token_properties(amount)90	}9192	fn set_property_permissions(amount: u32) -> Weight {93		<SelfWeightOf<T>>::set_property_permissions(amount)94	}9596	fn transfer() -> Weight {97		<SelfWeightOf<T>>::transfer()98	}99100	fn approve() -> Weight {101		<SelfWeightOf<T>>::approve()102	}103104	fn transfer_from() -> Weight {105		<SelfWeightOf<T>>::transfer_from()106	}107108	fn burn_from() -> Weight {109		<SelfWeightOf<T>>::burn_from()110	}111112	fn burn_recursively_self_raw() -> Weight {113		<SelfWeightOf<T>>::burn_recursively_self_raw()114	}115116	fn burn_recursively_breadth_raw(amount: u32) -> Weight {117		<SelfWeightOf<T>>::burn_recursively_breadth_plus_self_plus_self_per_each_raw(amount)118			.saturating_sub(Self::burn_recursively_self_raw().saturating_mul(amount as u64 + 1))119	}120}121122fn map_create_data<T: Config>(123	data: up_data_structs::CreateItemData,124	to: &T::CrossAccountId,125) -> Result<CreateItemData<T>, DispatchError> {126	match data {127		up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {128			properties: data.properties,129			owner: to.clone(),130		}),131		_ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),132	}133}134135impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {136	fn create_item(137		&self,138		sender: T::CrossAccountId,139		to: T::CrossAccountId,140		data: up_data_structs::CreateItemData,141		nesting_budget: &dyn Budget,142	) -> DispatchResultWithPostInfo {143		with_weight(144			<Pallet<T>>::create_item(145				self,146				&sender,147				map_create_data::<T>(data, &to)?,148				nesting_budget,149			),150			<CommonWeights<T>>::create_item(),151		)152	}153154	fn create_multiple_items(155		&self,156		sender: T::CrossAccountId,157		to: T::CrossAccountId,158		data: Vec<up_data_structs::CreateItemData>,159		nesting_budget: &dyn Budget,160	) -> DispatchResultWithPostInfo {161		let weight = <CommonWeights<T>>::create_multiple_items(&data);162		let data = data163			.into_iter()164			.map(|d| map_create_data::<T>(d, &to))165			.collect::<Result<Vec<_>, DispatchError>>()?;166167		with_weight(168			<Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),169			weight,170		)171	}172173	fn create_multiple_items_ex(174		&self,175		sender: <T>::CrossAccountId,176		data: up_data_structs::CreateItemExData<<T>::CrossAccountId>,177		nesting_budget: &dyn Budget,178	) -> DispatchResultWithPostInfo {179		let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);180		let data = match data {181			up_data_structs::CreateItemExData::NFT(nft) => nft,182			_ => fail!(Error::<T>::NotNonfungibleDataUsedToMintFungibleCollectionToken),183		};184185		with_weight(186			<Pallet<T>>::create_multiple_items(self, &sender, data.into_inner(), nesting_budget),187			weight,188		)189	}190191	fn set_collection_properties(192		&self,193		sender: T::CrossAccountId,194		properties: Vec<Property>,195	) -> DispatchResultWithPostInfo {196		let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);197198		with_weight(199			<Pallet<T>>::set_collection_properties(self, &sender, properties),200			weight,201		)202	}203204	fn delete_collection_properties(205		&self,206		sender: &T::CrossAccountId,207		property_keys: Vec<PropertyKey>,208	) -> DispatchResultWithPostInfo {209		let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);210211		with_weight(212			<Pallet<T>>::delete_collection_properties(self, sender, property_keys),213			weight,214		)215	}216217	fn set_token_properties(218		&self,219		sender: T::CrossAccountId,220		token_id: TokenId,221		properties: Vec<Property>,222	) -> DispatchResultWithPostInfo {223		let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);224225		with_weight(226			<Pallet<T>>::set_token_properties(self, &sender, token_id, properties, false),227			weight,228		)229	}230231	fn delete_token_properties(232		&self,233		sender: T::CrossAccountId,234		token_id: TokenId,235		property_keys: Vec<PropertyKey>,236	) -> DispatchResultWithPostInfo {237		let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);238239		with_weight(240			<Pallet<T>>::delete_token_properties(self, &sender, token_id, property_keys),241			weight,242		)243	}244245	fn set_property_permissions(246		&self,247		sender: &T::CrossAccountId,248		property_permissions: Vec<PropertyKeyPermission>,249	) -> DispatchResultWithPostInfo {250		let weight =251			<CommonWeights<T>>::set_property_permissions(property_permissions.len() as u32);252253		with_weight(254			<Pallet<T>>::set_property_permissions(self, sender, property_permissions),255			weight,256		)257	}258259	fn burn_item(260		&self,261		sender: T::CrossAccountId,262		token: TokenId,263		amount: u128,264	) -> DispatchResultWithPostInfo {265		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);266		if amount == 1 {267			with_weight(268				<Pallet<T>>::burn(self, &sender, token),269				<CommonWeights<T>>::burn_item(),270			)271		} else {272			Ok(().into())273		}274	}275276	fn burn_item_recursively(277		&self,278		sender: T::CrossAccountId,279		token: TokenId,280		self_budget: &dyn Budget,281		breadth_budget: &dyn Budget,282	) -> DispatchResultWithPostInfo {283		<Pallet<T>>::burn_recursively(self, &sender, token, self_budget, breadth_budget)284	}285286	fn transfer(287		&self,288		from: T::CrossAccountId,289		to: T::CrossAccountId,290		token: TokenId,291		amount: u128,292		nesting_budget: &dyn Budget,293	) -> DispatchResultWithPostInfo {294		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);295		if amount == 1 {296			with_weight(297				<Pallet<T>>::transfer(self, &from, &to, token, nesting_budget),298				<CommonWeights<T>>::transfer(),299			)300		} else {301			Ok(().into())302		}303	}304305	fn approve(306		&self,307		sender: T::CrossAccountId,308		spender: T::CrossAccountId,309		token: TokenId,310		amount: u128,311	) -> DispatchResultWithPostInfo {312		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);313314		with_weight(315			if amount == 1 {316				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))317			} else {318				<Pallet<T>>::set_allowance(self, &sender, token, None)319			},320			<CommonWeights<T>>::approve(),321		)322	}323324	fn transfer_from(325		&self,326		sender: T::CrossAccountId,327		from: T::CrossAccountId,328		to: T::CrossAccountId,329		token: TokenId,330		amount: u128,331		nesting_budget: &dyn Budget,332	) -> DispatchResultWithPostInfo {333		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);334335		if amount == 1 {336			with_weight(337				<Pallet<T>>::transfer_from(self, &sender, &from, &to, token, nesting_budget),338				<CommonWeights<T>>::transfer_from(),339			)340		} else {341			Ok(().into())342		}343	}344345	fn burn_from(346		&self,347		sender: T::CrossAccountId,348		from: T::CrossAccountId,349		token: TokenId,350		amount: u128,351		nesting_budget: &dyn Budget,352	) -> DispatchResultWithPostInfo {353		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);354355		if amount == 1 {356			with_weight(357				<Pallet<T>>::burn_from(self, &sender, &from, token, nesting_budget),358				<CommonWeights<T>>::burn_from(),359			)360		} else {361			Ok(().into())362		}363	}364365	fn check_nesting(366		&self,367		sender: T::CrossAccountId,368		from: (CollectionId, TokenId),369		under: TokenId,370		budget: &dyn Budget,371	) -> sp_runtime::DispatchResult {372		<Pallet<T>>::check_nesting(self, sender, from, under, budget)373	}374375	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId)) {376		<Pallet<T>>::nest((self.id, under), to_nest);377	}378379	fn unnest(&self, under: TokenId, to_unnest: (CollectionId, TokenId)) {380		<Pallet<T>>::unnest((self.id, under), to_unnest);381	}382383	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {384		<Owned<T>>::iter_prefix((self.id, account))385			.map(|(id, _)| id)386			.collect()387	}388389	fn collection_tokens(&self) -> Vec<TokenId> {390		<TokenData<T>>::iter_prefix((self.id,))391			.map(|(id, _)| id)392			.collect()393	}394395	fn token_exists(&self, token: TokenId) -> bool {396		<Pallet<T>>::token_exists(self, token)397	}398399	fn last_token_id(&self) -> TokenId {400		TokenId(<TokensMinted<T>>::get(self.id))401	}402403	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId> {404		<TokenData<T>>::get((self.id, token)).map(|t| t.owner)405	}406407	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {408		<Pallet<T>>::token_properties((self.id, token_id))409			.get(key)410			.cloned()411	}412413	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {414		let properties = <Pallet<T>>::token_properties((self.id, token_id));415416		keys.map(|keys| {417			keys.into_iter()418				.filter_map(|key| {419					properties.get(&key).map(|value| Property {420						key,421						value: value.clone(),422					})423				})424				.collect()425		})426		.unwrap_or_else(|| {427			properties428				.into_iter()429				.map(|(key, value)| Property { key, value })430				.collect()431		})432	}433434	fn total_supply(&self) -> u32 {435		<Pallet<T>>::total_supply(self)436	}437438	fn account_balance(&self, account: T::CrossAccountId) -> u32 {439		<AccountBalance<T>>::get((self.id, account))440	}441442	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {443		if <TokenData<T>>::get((self.id, token))444			.map(|a| a.owner == account)445			.unwrap_or(false)446		{447			1448		} else {449			0450		}451	}452453	fn allowance(454		&self,455		sender: T::CrossAccountId,456		spender: T::CrossAccountId,457		token: TokenId,458	) -> u128 {459		if <TokenData<T>>::get((self.id, token))460			.map(|a| a.owner != sender)461			.unwrap_or(true)462		{463			0464		} else if <Allowance<T>>::get((self.id, token)) == Some(spender) {465			1466		} else {467			0468		}469	}470}
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -82,7 +82,7 @@
 			.map_err(|_| "key too long")?;
 		let value = value.try_into().map_err(|_| "value too long")?;
 
-		<Pallet<T>>::set_token_property(self, &caller, TokenId(token_id), Property { key, value })
+		<Pallet<T>>::set_token_property(self, &caller, TokenId(token_id), Property { key, value }, false)
 			.map_err(dispatch_to_evm::<T>)
 	}
 
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -447,8 +447,9 @@
 		sender: &T::CrossAccountId,
 		token_id: TokenId,
 		property: Property,
+		is_token_create: bool,
 	) -> DispatchResult {
-		Self::check_token_change_permission(collection, sender, token_id, &property.key)?;
+		Self::check_token_change_permission(collection, sender, token_id, &property.key, is_token_create)?;
 
 		<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
 			let property = property.clone();
@@ -471,9 +472,10 @@
 		sender: &T::CrossAccountId,
 		token_id: TokenId,
 		properties: Vec<Property>,
+		is_token_create: bool,
 	) -> DispatchResult {
 		for property in properties {
-			Self::set_token_property(collection, sender, token_id, property)?;
+			Self::set_token_property(collection, sender, token_id, property, is_token_create)?;
 		}
 
 		Ok(())
@@ -485,7 +487,7 @@
 		token_id: TokenId,
 		property_key: PropertyKey,
 	) -> DispatchResult {
-		Self::check_token_change_permission(collection, sender, token_id, &property_key)?;
+		Self::check_token_change_permission(collection, sender, token_id, &property_key, false)?;
 
 		<TokenProperties<T>>::try_mutate((collection.id, token_id), |properties| {
 			properties.remove(&property_key)
@@ -506,6 +508,7 @@
 		sender: &T::CrossAccountId,
 		token_id: TokenId,
 		property_key: &PropertyKey,
+		is_token_create: bool,
 	) -> DispatchResult {
 		let permission = <PalletCommon<T>>::property_permissions(collection.id)
 			.get(property_key)
@@ -534,6 +537,10 @@
 				token_owner,
 				..
 			} => {
+				if is_token_create && (collection_admin || token_owner) {
+					return Ok(());
+				}
+
 				let mut check_result = Err(<CommonError<T>>::NoPermission.into());
 
 				if collection_admin {
@@ -772,6 +779,7 @@
 					sender,
 					TokenId(token),
 					data.properties.clone().into_inner(),
+					true,
 				) {
 					return TransactionOutcome::Rollback(Err(e));
 				}
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -221,68 +221,71 @@
     expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');
   });
 
-  //TODO: CORE-302 add eth methods
-  itWeb3.skip('Sponsoring collection from evm address via access list', async ({api, web3}) => {
+  itWeb3('Sponsoring collection from evm address via access list', async ({api, web3}) => {
     const owner = await createEthAccountWithBalance(api, web3);
     const collectionHelpers = evmCollectionHelpers(web3, owner);
     let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
     const sponsor = await createEthAccountWithBalance(api, web3);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
-    result = await collectionEvm.methods.ethSetSponsor(sponsor).send({from: owner});
+    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});
     let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
     expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;
     expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
-    await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
+    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');
 
-    await collectionEvm.methods.ethConfirmSponsorship().send({from: sponsor});
+    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
     collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;
     expect(collectionSub.sponsorship.isConfirmed).to.be.true;
     expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));
 
     const user = createEthAccount(web3);
-    const nextTokenId = await collectionEvm.methods.nextTokenId().call();
+    let nextTokenId = await collectionEvm.methods.nextTokenId().call();
     expect(nextTokenId).to.be.equal('1');
 
     const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
     expect(oldPermissions.mintMode).to.be.false;
     expect(oldPermissions.access).to.be.equal('Normal');
 
-    await collectionEvm.methods.setAccess('AllowList').send({from: owner});
-    await collectionEvm.methods.addToAllowList(user).send({from: owner});
-    await collectionEvm.methods.setMintMode(true).send({from: owner});
+    await collectionEvm.methods.setCollectionAccess('AllowList').send({from: owner});
+    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
+    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
 
     const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
     expect(newPermissions.mintMode).to.be.true;
     expect(newPermissions.access).to.be.equal('AllowList');
 
-    // const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]);
+    const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
+    const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
 
-    {
-      const nextTokenId = await collectionEvm.methods.nextTokenId().call();
-      expect(nextTokenId).to.be.equal('1');
-      const result = await collectionEvm.methods.mintWithTokenURI(
-        user,
-        nextTokenId,
-        'Test URI',
-      ).call({from: user});
-      console.log(result);
-      const events = normalizeEvents(result.events);
+    nextTokenId = await collectionEvm.methods.nextTokenId().call({from: user});
+    expect(nextTokenId).to.be.equal('1');
+    result = await collectionEvm.methods.mintWithTokenURI(
+      user,
+      nextTokenId,
+      'Test URI',
+    ).send({from: user});
+    const events = normalizeEvents(result.events);
+    events[0].address = events[0].address.toLocaleLowerCase();
 
-      expect(events).to.be.deep.equal([
-        {
-          collectionIdAddress,
-          event: 'Transfer',
-          args: {
-            from: '0x0000000000000000000000000000000000000000',
-            to: user,
-            tokenId: nextTokenId,
-          },
+    expect(events).to.be.deep.equal([
+      {
+        address: collectionIdAddress.toLocaleLowerCase(),
+        event: 'Transfer',
+        args: {
+          from: '0x0000000000000000000000000000000000000000',
+          to: user,
+          tokenId: nextTokenId,
         },
-      ]);
+      },
+    ]);
 
-      expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
-    }
+    expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
+
+    const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
+    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);
+    const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
+    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;
   });
 
   itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3}) => {
@@ -308,7 +311,6 @@
     
     const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
     const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
-    
   
     const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);
     const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();