git.delta.rocks / unique-network / refs/commits / 086739e0956b

difftreelog

source

pallets/foreign-assets/src/impl_fungibles.rs15.4 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/>.1617//! Implementations for fungibles trait.1819use frame_support::traits::tokens::{20	DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,21};22use frame_system::Config as SystemConfig;23use pallet_common::{CollectionHandle, CommonCollectionOperations};24use pallet_fungible::FungibleHandle;25use sp_runtime::traits::{CheckedAdd, CheckedSub};26use up_data_structs::budget;2728use super::*;2930impl<T: Config> fungibles::Inspect<<T as SystemConfig>::AccountId> for Pallet<T>31where32	T: orml_tokens::Config<CurrencyId = AssetId>,33	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,34	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,35	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,36	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,37{38	type AssetId = AssetId;39	type Balance = BalanceOf<T>;4041	fn total_issuance(asset: Self::AssetId) -> Self::Balance {42		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible total_issuance");4344		match asset {45			AssetId::NativeAssetId(NativeCurrency::Here) => {46				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::total_issuance()47					.into()48			}49			AssetId::NativeAssetId(NativeCurrency::Parent) => {50				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::total_issuance(51					AssetId::NativeAssetId(NativeCurrency::Parent),52				)53				.into()54			}55			AssetId::ForeignAssetId(fid) => {56				let target_collection_id = match <AssetBinding<T>>::get(fid) {57					Some(v) => v,58					None => return Zero::zero(),59				};60				let collection_handle = match <CollectionHandle<T>>::try_get(target_collection_id) {61					Ok(v) => v,62					Err(_) => return Zero::zero(),63				};64				let collection = FungibleHandle::cast(collection_handle);65				Self::Balance::try_from(collection.total_supply()).unwrap_or(Zero::zero())66			}67		}68	}6970	fn minimum_balance(asset: Self::AssetId) -> Self::Balance {71		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible minimum_balance");72		match asset {73			AssetId::NativeAssetId(NativeCurrency::Here) => {74				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::minimum_balance()75					.into()76			}77			AssetId::NativeAssetId(NativeCurrency::Parent) => {78				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::minimum_balance(79					AssetId::NativeAssetId(NativeCurrency::Parent),80				)81				.into()82			}83			AssetId::ForeignAssetId(fid) => AssetMetadatas::<T>::get(AssetId::ForeignAssetId(fid))84				.map(|x| x.minimal_balance)85				.unwrap_or_else(Zero::zero),86		}87	}8889	fn balance(asset: Self::AssetId, who: &<T as SystemConfig>::AccountId) -> Self::Balance {90		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible balance");91		match asset {92			AssetId::NativeAssetId(NativeCurrency::Here) => {93				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::balance(who).into()94			}95			AssetId::NativeAssetId(NativeCurrency::Parent) => {96				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::balance(97					AssetId::NativeAssetId(NativeCurrency::Parent),98					who,99				)100				.into()101			}102			AssetId::ForeignAssetId(fid) => {103				let target_collection_id = match <AssetBinding<T>>::get(fid) {104					Some(v) => v,105					None => return Zero::zero(),106				};107				let collection_handle = match <CollectionHandle<T>>::try_get(target_collection_id) {108					Ok(v) => v,109					Err(_) => return Zero::zero(),110				};111				let collection = FungibleHandle::cast(collection_handle);112				Self::Balance::try_from(113					collection.balance(T::CrossAccountId::from_sub(who.clone()), TokenId(0)),114				)115				.unwrap_or(Zero::zero())116			}117		}118	}119120	fn total_balance(asset: Self::AssetId, who: &<T as SystemConfig>::AccountId) -> Self::Balance {121		Self::balance(asset, who)122	}123124	fn reducible_balance(125		asset: Self::AssetId,126		who: &<T as SystemConfig>::AccountId,127		preservation: Preservation,128		fortitude: Fortitude,129	) -> Self::Balance {130		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible reducible_balance");131132		match asset {133			AssetId::NativeAssetId(NativeCurrency::Here) => {134				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::reducible_balance(135					who,136					preservation,137					fortitude,138				)139				.into()140			}141			AssetId::NativeAssetId(NativeCurrency::Parent) => {142				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::reducible_balance(143					AssetId::NativeAssetId(NativeCurrency::Parent),144					who,145					preservation,146					fortitude,147				)148				.into()149			}150			_ => Self::balance(asset, who),151		}152	}153154	fn can_deposit(155		asset: Self::AssetId,156		who: &<T as SystemConfig>::AccountId,157		amount: Self::Balance,158		provenance: Provenance,159	) -> DepositConsequence {160		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_deposit");161162		match asset {163			AssetId::NativeAssetId(NativeCurrency::Here) => {164				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::can_deposit(165					who,166					amount.into(),167					provenance,168				)169			}170			AssetId::NativeAssetId(NativeCurrency::Parent) => {171				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::can_deposit(172					AssetId::NativeAssetId(NativeCurrency::Parent),173					who,174					amount.into(),175					provenance,176				)177			}178			_ => {179				if amount.is_zero() {180					return DepositConsequence::Success;181				}182183				let extential_deposit_value = T::ExistentialDeposit::get();184				let ed_value: u128 = match extential_deposit_value.try_into() {185					Ok(val) => val,186					Err(_) => return DepositConsequence::CannotCreate,187				};188				let extential_deposit: Self::Balance = match ed_value.try_into() {189					Ok(val) => val,190					Err(_) => return DepositConsequence::CannotCreate,191				};192193				let new_total_balance = match Self::balance(asset, who).checked_add(&amount) {194					Some(x) => x,195					None => return DepositConsequence::Overflow,196				};197198				if new_total_balance < extential_deposit {199					return DepositConsequence::BelowMinimum;200				}201202				DepositConsequence::Success203			}204		}205	}206207	fn can_withdraw(208		asset: Self::AssetId,209		who: &<T as SystemConfig>::AccountId,210		amount: Self::Balance,211	) -> WithdrawConsequence<Self::Balance> {212		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_withdraw");213		let value: u128 = match amount.try_into() {214			Ok(val) => val,215			Err(_) => return WithdrawConsequence::UnknownAsset,216		};217218		match asset {219			AssetId::NativeAssetId(NativeCurrency::Here) => {220				let this_amount: <T as pallet_balances::Config>::Balance = match value.try_into() {221					Ok(val) => val,222					Err(_) => {223						return WithdrawConsequence::UnknownAsset;224					}225				};226				match <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::can_withdraw(227					who,228					this_amount,229				) {230					WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow,231					WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie,232					WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset,233					WithdrawConsequence::Underflow => WithdrawConsequence::Underflow,234					WithdrawConsequence::Overflow => WithdrawConsequence::Overflow,235					WithdrawConsequence::Frozen => WithdrawConsequence::Frozen,236					WithdrawConsequence::Success => WithdrawConsequence::Success,237					_ => WithdrawConsequence::BalanceLow,238				}239			}240			AssetId::NativeAssetId(NativeCurrency::Parent) => {241				let parent_amount: <T as orml_tokens::Config>::Balance = match value.try_into() {242					Ok(val) => val,243					Err(_) => {244						return WithdrawConsequence::UnknownAsset;245					}246				};247				match <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::can_withdraw(248					AssetId::NativeAssetId(NativeCurrency::Parent),249					who,250					parent_amount,251				) {252					WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow,253					WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie,254					WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset,255					WithdrawConsequence::Underflow => WithdrawConsequence::Underflow,256					WithdrawConsequence::Overflow => WithdrawConsequence::Overflow,257					WithdrawConsequence::Frozen => WithdrawConsequence::Frozen,258					WithdrawConsequence::Success => WithdrawConsequence::Success,259					_ => WithdrawConsequence::BalanceLow,260				}261			}262			_ => match Self::balance(asset, who).checked_sub(&amount) {263				Some(_) => WithdrawConsequence::Success,264				None => WithdrawConsequence::BalanceLow,265			},266		}267	}268269	fn asset_exists(asset: AssetId) -> bool {270		match asset {271			AssetId::NativeAssetId(_) => true,272			AssetId::ForeignAssetId(fid) => <AssetBinding<T>>::contains_key(fid),273		}274	}275}276277impl<T: Config> fungibles::Mutate<<T as SystemConfig>::AccountId> for Pallet<T>278where279	T: orml_tokens::Config<CurrencyId = AssetId>,280	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,281	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,282	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,283	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,284	u128: From<BalanceOf<T>>,285{286	fn mint_into(287		asset: Self::AssetId,288		who: &<T as SystemConfig>::AccountId,289		amount: Self::Balance,290	) -> Result<BalanceOf<T>, DispatchError> {291		//Self::do_mint(asset, who, amount, None)292		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible mint_into {:?}", asset);293294		match asset {295			AssetId::NativeAssetId(NativeCurrency::Here) => {296				<pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::mint_into(297					who,298					amount.into(),299				)300				.map(Into::into)301			}302			AssetId::NativeAssetId(NativeCurrency::Parent) => {303				<orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::mint_into(304					AssetId::NativeAssetId(NativeCurrency::Parent),305					who,306					amount.into(),307				)308				.map(Into::into)309			}310			AssetId::ForeignAssetId(fid) => {311				let target_collection_id = match <AssetBinding<T>>::get(fid) {312					Some(v) => v,313					None => {314						return Err(DispatchError::Other(315							"Associated collection not found for asset",316						))317					}318				};319				let collection =320					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);321				let account = T::CrossAccountId::from_sub(who.clone());322323				let amount_data: pallet_fungible::CreateItemData<T> =324					(account.clone(), amount.into());325326				pallet_fungible::Pallet::<T>::create_item_foreign(327					&collection,328					&account,329					amount_data,330					&budget::Value::new(0),331				)?;332333				Ok(amount)334			}335		}336	}337338	fn burn_from(339		asset: Self::AssetId,340		who: &<T as SystemConfig>::AccountId,341		amount: Self::Balance,342		precision: Precision,343		fortitude: Fortitude,344	) -> Result<Self::Balance, DispatchError> {345		// let f = DebitFlags { keep_alive: false, best_effort: false };346		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible burn_from");347348		match asset {349			AssetId::NativeAssetId(NativeCurrency::Here) => {350				<pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::burn_from(351					who,352					amount.into(),353					precision,354					fortitude,355				)356				.map(Into::into)357			}358			AssetId::NativeAssetId(NativeCurrency::Parent) => {359				<orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::burn_from(360					AssetId::NativeAssetId(NativeCurrency::Parent),361					who,362					amount.into(),363					precision,364					fortitude,365				)366				.map(Into::into)367			}368			AssetId::ForeignAssetId(fid) => {369				let target_collection_id = match <AssetBinding<T>>::get(fid) {370					Some(v) => v,371					None => {372						return Err(DispatchError::Other(373							"Associated collection not found for asset",374						))375					}376				};377				let collection =378					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);379				pallet_fungible::Pallet::<T>::burn_foreign(380					&collection,381					&T::CrossAccountId::from_sub(who.clone()),382					amount.into(),383				)?;384385				Ok(amount)386			}387		}388	}389390	fn transfer(391		asset: Self::AssetId,392		source: &<T as SystemConfig>::AccountId,393		dest: &<T as SystemConfig>::AccountId,394		amount: Self::Balance,395		preservation: Preservation,396	) -> Result<Self::Balance, DispatchError> {397		// let f = TransferFlags { keep_alive, best_effort: false, burn_dust: false };398		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible transfer");399400		match asset {401			AssetId::NativeAssetId(NativeCurrency::Here) => {402				match <pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::transfer(403					source,404					dest,405					amount.into(),406					preservation,407				) {408					Ok(_) => Ok(amount),409					Err(_) => Err(DispatchError::Other(410						"Bad amount to relay chain value conversion",411					)),412				}413			}414			AssetId::NativeAssetId(NativeCurrency::Parent) => {415				match <orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::transfer(416					AssetId::NativeAssetId(NativeCurrency::Parent),417					source,418					dest,419					amount.into(),420					preservation,421				) {422					Ok(_) => Ok(amount),423					Err(e) => Err(e),424				}425			}426			AssetId::ForeignAssetId(fid) => {427				let target_collection_id = match <AssetBinding<T>>::get(fid) {428					Some(v) => v,429					None => {430						return Err(DispatchError::Other(431							"Associated collection not found for asset",432						))433					}434				};435				let collection =436					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);437438				pallet_fungible::Pallet::<T>::transfer(439					&collection,440					&T::CrossAccountId::from_sub(source.clone()),441					&T::CrossAccountId::from_sub(dest.clone()),442					amount.into(),443					&budget::Value::new(0),444				)445				.map_err(|e| e.error)?;446447				Ok(amount)448			}449		}450	}451}452453#[cfg(not(debug_assertions))]454extern "C" {455	// This function does not exists, thus compilation will fail, if its call is456	// not optimized away, which is only possible if it's not called at all.457	//458	// not(debug_assertions) is used to ensure compiler is dropping unused functions, as459	// this option is enabled in release by defailt460	//461	// FIXME: maybe use build.rs, to ensure it will fail even in release with debug_assertions462	// enabled?463	fn unbalanced_fungible_is_called();464}465macro_rules! ensure_balanced {466	() => {{467		#[cfg(debug_assertions)]468		panic!("unbalanced fungible methods should not be used");469		#[cfg(not(debug_assertions))]470		{471			unsafe { unbalanced_fungible_is_called() };472			unreachable!();473		}474	}};475}476477impl<T: Config> fungibles::Unbalanced<<T as SystemConfig>::AccountId> for Pallet<T>478where479	T: orml_tokens::Config<CurrencyId = AssetId>,480	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,481	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,482	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,483	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,484	u128: From<BalanceOf<T>>,485{486	fn handle_dust(_dust: fungibles::Dust<<T as SystemConfig>::AccountId, Self>) {487		ensure_balanced!();488	}489	fn write_balance(490		_asset: Self::AssetId,491		_who: &<T as SystemConfig>::AccountId,492		_amount: Self::Balance,493	) -> Result<Option<Self::Balance>, DispatchError> {494		ensure_balanced!();495	}496	fn set_total_issuance(_asset: Self::AssetId, _amount: Self::Balance) {497		ensure_balanced!();498	}499}