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

difftreelog

source

pallets/nonfungible/src/common.rs14.5 KiBsourcehistory
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 pallet_common::{21	weights::WeightInfo as _, with_weight, write_token_properties_total_weight,22	CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions,23	SelfWeightOf as PalletCommonWeightOf,24};25use pallet_structure::Pallet as PalletStructure;26use sp_runtime::DispatchError;27use sp_std::{vec, vec::Vec};28use up_data_structs::{29	budget::Budget, CollectionId, CreateItemExData, Property, PropertyKey, PropertyKeyPermission,30	PropertyValue, TokenId, TokenOwnerError,31};3233use crate::{34	weights::WeightInfo, AccountBalance, Allowance, Config, CreateItemData, Error,35	NonfungibleHandle, Owned, Pallet, SelfWeightOf, TokenData, TokenProperties, TokensMinted,36};3738pub struct CommonWeights<T: Config>(PhantomData<T>);39impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {40	fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {41		match data {42			CreateItemExData::NFT(t) => mint_with_props_weight::<T>(43				<SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32),44				t.iter().map(|t| t.properties.len() as u32),45			),46			_ => Weight::zero(),47		}48	}4950	fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {51		mint_with_props_weight::<T>(52			<SelfWeightOf<T>>::create_multiple_items(data.len() as u32),53			data.iter().map(|t| match t {54				up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32,55				_ => 0,56			}),57		)58	}5960	fn burn_item() -> Weight {61		<SelfWeightOf<T>>::burn_item()62	}6364	fn set_collection_properties(amount: u32) -> Weight {65		<pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)66	}6768	fn set_token_properties(amount: u32) -> Weight {69		write_token_properties_total_weight::<T, _>([amount].into_iter(), |amount| {70			<SelfWeightOf<T>>::load_token_properties()71				.saturating_add(<SelfWeightOf<T>>::write_token_properties(amount))72		})73	}7475	fn delete_token_properties(amount: u32) -> Weight {76		Self::set_token_properties(amount)77	}7879	fn set_token_property_permissions(amount: u32) -> Weight {80		<SelfWeightOf<T>>::set_token_property_permissions(amount)81	}8283	fn transfer() -> Weight {84		<SelfWeightOf<T>>::transfer_raw()85			.saturating_add(<PalletCommonWeightOf<T>>::check_accesslist().saturating_mul(2))86	}8788	fn approve() -> Weight {89		<SelfWeightOf<T>>::approve()90	}9192	fn approve_from() -> Weight {93		<SelfWeightOf<T>>::approve_from()94	}9596	fn transfer_from() -> Weight {97		Self::transfer().saturating_add(<SelfWeightOf<T>>::check_allowed_raw())98	}99100	fn burn_from() -> Weight {101		<SelfWeightOf<T>>::burn_from()102	}103104	fn set_allowance_for_all() -> Weight {105		<SelfWeightOf<T>>::set_allowance_for_all()106	}107108	fn force_repair_item() -> Weight {109		<SelfWeightOf<T>>::repair_item()110	}111}112113pub(crate) fn mint_with_props_weight<T: Config>(114	create_no_data_weight: Weight,115	tokens: impl Iterator<Item = u32> + Clone,116) -> Weight {117	create_no_data_weight.saturating_add(write_token_properties_total_weight::<T, _>(118		tokens,119		<SelfWeightOf<T>>::write_token_properties,120	))121}122123fn map_create_data<T: Config>(124	data: up_data_structs::CreateItemData,125	to: &T::CrossAccountId,126) -> Result<CreateItemData<T>, DispatchError> {127	match data {128		up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {129			properties: data.properties,130			owner: to.clone(),131		}),132		_ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),133	}134}135136/// Implementation of `CommonCollectionOperations` for `NonfungibleHandle`. It wraps Nonfungible Pallete137/// methods and adds weight info.138impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {139	fn create_item(140		&self,141		sender: T::CrossAccountId,142		to: T::CrossAccountId,143		data: up_data_structs::CreateItemData,144		nesting_budget: &dyn Budget,145	) -> DispatchResultWithPostInfo {146		let weight = <CommonWeights<T>>::create_item(&data);147		with_weight(148			<Pallet<T>>::create_item(149				self,150				&sender,151				map_create_data::<T>(data, &to)?,152				nesting_budget,153			),154			weight,155		)156	}157158	fn create_multiple_items(159		&self,160		sender: T::CrossAccountId,161		to: T::CrossAccountId,162		data: Vec<up_data_structs::CreateItemData>,163		nesting_budget: &dyn Budget,164	) -> DispatchResultWithPostInfo {165		let weight = <CommonWeights<T>>::create_multiple_items(&data);166		let data = data167			.into_iter()168			.map(|d| map_create_data::<T>(d, &to))169			.collect::<Result<Vec<_>, DispatchError>>()?;170171		with_weight(172			<Pallet<T>>::create_multiple_items(self, &sender, data, nesting_budget),173			weight,174		)175	}176177	fn create_multiple_items_ex(178		&self,179		sender: <T>::CrossAccountId,180		data: up_data_structs::CreateItemExData<<T>::CrossAccountId>,181		nesting_budget: &dyn Budget,182	) -> DispatchResultWithPostInfo {183		let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);184		let data = match data {185			up_data_structs::CreateItemExData::NFT(nft) => nft,186			_ => fail!(Error::<T>::NotNonfungibleDataUsedToMintFungibleCollectionToken),187		};188189		with_weight(190			<Pallet<T>>::create_multiple_items(self, &sender, data.into_inner(), nesting_budget),191			weight,192		)193	}194195	fn set_collection_properties(196		&self,197		sender: T::CrossAccountId,198		properties: Vec<Property>,199	) -> DispatchResultWithPostInfo {200		let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);201202		with_weight(203			<Pallet<T>>::set_collection_properties(self, &sender, properties),204			weight,205		)206	}207208	fn delete_collection_properties(209		&self,210		sender: &T::CrossAccountId,211		property_keys: Vec<PropertyKey>,212	) -> DispatchResultWithPostInfo {213		let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);214215		with_weight(216			<Pallet<T>>::delete_collection_properties(self, sender, property_keys),217			weight,218		)219	}220221	fn set_token_properties(222		&self,223		sender: T::CrossAccountId,224		token_id: TokenId,225		properties: Vec<Property>,226		nesting_budget: &dyn Budget,227	) -> DispatchResultWithPostInfo {228		let weight = <CommonWeights<T>>::set_token_properties(properties.len() as u32);229230		with_weight(231			<Pallet<T>>::set_token_properties(232				self,233				&sender,234				token_id,235				properties.into_iter(),236				nesting_budget,237			),238			weight,239		)240	}241242	fn delete_token_properties(243		&self,244		sender: T::CrossAccountId,245		token_id: TokenId,246		property_keys: Vec<PropertyKey>,247		nesting_budget: &dyn Budget,248	) -> DispatchResultWithPostInfo {249		let weight = <CommonWeights<T>>::delete_token_properties(property_keys.len() as u32);250251		with_weight(252			<Pallet<T>>::delete_token_properties(253				self,254				&sender,255				token_id,256				property_keys.into_iter(),257				nesting_budget,258			),259			weight,260		)261	}262263	fn get_token_properties_raw(264		&self,265		token_id: TokenId,266	) -> Option<up_data_structs::TokenProperties> {267		<TokenProperties<T>>::get((self.id, token_id))268	}269270	fn set_token_properties_raw(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {271		<TokenProperties<T>>::insert((self.id, token_id), map)272	}273274	fn set_token_property_permissions(275		&self,276		sender: &T::CrossAccountId,277		property_permissions: Vec<PropertyKeyPermission>,278	) -> DispatchResultWithPostInfo {279		let weight =280			<CommonWeights<T>>::set_token_property_permissions(property_permissions.len() as u32);281282		with_weight(283			<Pallet<T>>::set_token_property_permissions(self, sender, property_permissions),284			weight,285		)286	}287288	fn burn_item(289		&self,290		sender: T::CrossAccountId,291		token: TokenId,292		amount: u128,293	) -> DispatchResultWithPostInfo {294		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);295		if amount == 1 {296			with_weight(297				<Pallet<T>>::burn(self, &sender, token),298				<CommonWeights<T>>::burn_item(),299			)300		} else {301			<Pallet<T>>::check_token_immediate_ownership(self, token, &sender)?;302			Ok(().into())303		}304	}305306	fn transfer(307		&self,308		from: T::CrossAccountId,309		to: T::CrossAccountId,310		token: TokenId,311		amount: u128,312		nesting_budget: &dyn Budget,313	) -> DispatchResultWithPostInfo {314		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);315		if amount == 1 {316			<Pallet<T>>::transfer(self, &from, &to, token, nesting_budget)317		} else {318			<Pallet<T>>::check_token_immediate_ownership(self, token, &from)?;319			Ok(().into())320		}321	}322323	fn approve(324		&self,325		sender: T::CrossAccountId,326		spender: T::CrossAccountId,327		token: TokenId,328		amount: u128,329	) -> DispatchResultWithPostInfo {330		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);331332		with_weight(333			if amount == 1 {334				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))335			} else {336				<Pallet<T>>::set_allowance(self, &sender, token, None)337			},338			<CommonWeights<T>>::approve(),339		)340	}341342	fn approve_from(343		&self,344		sender: T::CrossAccountId,345		from: T::CrossAccountId,346		to: T::CrossAccountId,347		token: TokenId,348		amount: u128,349	) -> DispatchResultWithPostInfo {350		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);351352		with_weight(353			if amount == 1 {354				<Pallet<T>>::set_allowance_from(self, &sender, &from, token, Some(&to))355			} else {356				<Pallet<T>>::set_allowance_from(self, &sender, &from, token, None)357			},358			<CommonWeights<T>>::approve_from(),359		)360	}361362	fn transfer_from(363		&self,364		sender: T::CrossAccountId,365		from: T::CrossAccountId,366		to: T::CrossAccountId,367		token: TokenId,368		amount: u128,369		nesting_budget: &dyn Budget,370	) -> DispatchResultWithPostInfo {371		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);372373		if amount == 1 {374			<Pallet<T>>::transfer_from(self, &sender, &from, &to, token, nesting_budget)375		} else {376			<Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;377378			Ok(().into())379		}380	}381382	fn burn_from(383		&self,384		sender: T::CrossAccountId,385		from: T::CrossAccountId,386		token: TokenId,387		amount: u128,388		nesting_budget: &dyn Budget,389	) -> DispatchResultWithPostInfo {390		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);391392		if amount == 1 {393			with_weight(394				<Pallet<T>>::burn_from(self, &sender, &from, token, nesting_budget),395				<CommonWeights<T>>::burn_from(),396			)397		} else {398			<Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;399400			Ok(().into())401		}402	}403404	fn check_nesting(405		&self,406		sender: T::CrossAccountId,407		from: (CollectionId, TokenId),408		under: TokenId,409		nesting_budget: &dyn Budget,410	) -> sp_runtime::DispatchResult {411		<Pallet<T>>::check_nesting(self, sender, from, under, nesting_budget)412	}413414	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId)) {415		<Pallet<T>>::nest((self.id, under), to_nest);416	}417418	fn unnest(&self, under: TokenId, to_unnest: (CollectionId, TokenId)) {419		<Pallet<T>>::unnest((self.id, under), to_unnest);420	}421422	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {423		<Owned<T>>::iter_prefix((self.id, account))424			.map(|(id, _)| id)425			.collect()426	}427428	fn collection_tokens(&self) -> Vec<TokenId> {429		<TokenData<T>>::iter_prefix((self.id,))430			.map(|(id, _)| id)431			.collect()432	}433434	fn token_exists(&self, token: TokenId) -> bool {435		<Pallet<T>>::token_exists(self, token)436	}437438	fn last_token_id(&self) -> TokenId {439		TokenId(<TokensMinted<T>>::get(self.id))440	}441442	fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError> {443		<TokenData<T>>::get((self.id, token))444			.map(|t| t.owner)445			.ok_or(TokenOwnerError::NotFound)446	}447448	fn check_token_indirect_owner(449		&self,450		token: TokenId,451		maybe_owner: &T::CrossAccountId,452		nesting_budget: &dyn Budget,453	) -> Result<bool, DispatchError> {454		<PalletStructure<T>>::check_indirectly_owned(455			maybe_owner.clone(),456			self.id,457			token,458			None,459			nesting_budget,460		)461	}462463	/// Returns token owners.464	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {465		self.token_owner(token).map_or_else(|_| vec![], |t| vec![t])466	}467468	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue> {469		<Pallet<T>>::token_properties((self.id, token_id))?470			.get(key)471			.cloned()472	}473474	fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property> {475		let Some(properties) = <Pallet<T>>::token_properties((self.id, token_id)) else {476			return vec![];477		};478479		keys.map(|keys| {480			keys.into_iter()481				.filter_map(|key| {482					properties.get(&key).map(|value| Property {483						key,484						value: value.clone(),485					})486				})487				.collect()488		})489		.unwrap_or_else(|| {490			properties491				.into_iter()492				.map(|(key, value)| Property { key, value })493				.collect()494		})495	}496497	fn total_supply(&self) -> u32 {498		<Pallet<T>>::total_supply(self)499	}500501	fn account_balance(&self, account: T::CrossAccountId) -> u32 {502		<AccountBalance<T>>::get((self.id, account))503	}504505	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {506		if <TokenData<T>>::get((self.id, token))507			.map(|a| a.owner == account)508			.unwrap_or(false)509		{510			1511		} else {512			0513		}514	}515516	fn allowance(517		&self,518		sender: T::CrossAccountId,519		spender: T::CrossAccountId,520		token: TokenId,521	) -> u128 {522		if <TokenData<T>>::get((self.id, token))523			.map(|a| a.owner != sender)524			.unwrap_or(true)525		{526			0527		} else if <Allowance<T>>::get((self.id, token)) == Some(spender) {528			1529		} else {530			0531		}532	}533534	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>> {535		None536	}537538	fn total_pieces(&self, token: TokenId) -> Option<u128> {539		if <TokenData<T>>::contains_key((self.id, token)) {540			Some(1)541		} else {542			None543		}544	}545546	fn set_allowance_for_all(547		&self,548		owner: T::CrossAccountId,549		operator: T::CrossAccountId,550		approve: bool,551	) -> DispatchResultWithPostInfo {552		with_weight(553			<Pallet<T>>::set_allowance_for_all(self, &owner, &operator, approve),554			<CommonWeights<T>>::set_allowance_for_all(),555		)556	}557558	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool {559		<Pallet<T>>::allowance_for_all(self, &owner, &operator)560	}561562	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo {563		with_weight(564			<Pallet<T>>::repair_item(self, token),565			<CommonWeights<T>>::force_repair_item(),566		)567	}568}