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

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 super::*;20use frame_system::Config as SystemConfig;2122use frame_support::traits::tokens::{23	DepositConsequence, WithdrawConsequence, Preservation, Fortitude, Provenance, Precision,24};25use pallet_common::CollectionHandle;26use pallet_fungible::FungibleHandle;27use pallet_common::CommonCollectionOperations;28use up_data_structs::budget::Value;29use sp_runtime::traits::{CheckedAdd, CheckedSub};3031impl<T: Config> fungibles::Inspect<<T as SystemConfig>::AccountId> for Pallet<T>32where33	T: orml_tokens::Config<CurrencyId = AssetId>,34	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,35	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,36	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,37	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,38{39	type AssetId = AssetId;40	type Balance = BalanceOf<T>;4142	fn total_issuance(asset: Self::AssetId) -> Self::Balance {43		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible total_issuance");4445		match asset {46			AssetId::NativeAssetId(NativeCurrency::Here) => {47				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::total_issuance()48					.into()49			}50			AssetId::NativeAssetId(NativeCurrency::Parent) => {51				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::total_issuance(52					AssetId::NativeAssetId(NativeCurrency::Parent),53				)54				.into()55			}56			AssetId::ForeignAssetId(fid) => {57				let target_collection_id = match <AssetBinding<T>>::get(fid) {58					Some(v) => v,59					None => return Zero::zero(),60				};61				let collection_handle = match <CollectionHandle<T>>::try_get(target_collection_id) {62					Ok(v) => v,63					Err(_) => return Zero::zero(),64				};65				let collection = FungibleHandle::cast(collection_handle);66				Self::Balance::try_from(collection.total_supply()).unwrap_or(Zero::zero())67			}68		}69	}7071	fn minimum_balance(asset: Self::AssetId) -> Self::Balance {72		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible minimum_balance");73		match asset {74			AssetId::NativeAssetId(NativeCurrency::Here) => {75				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::minimum_balance()76					.into()77			}78			AssetId::NativeAssetId(NativeCurrency::Parent) => {79				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::minimum_balance(80					AssetId::NativeAssetId(NativeCurrency::Parent),81				)82				.into()83			}84			AssetId::ForeignAssetId(fid) => AssetMetadatas::<T>::get(AssetId::ForeignAssetId(fid))85				.map(|x| x.minimal_balance)86				.unwrap_or_else(Zero::zero),87		}88	}8990	fn balance(asset: Self::AssetId, who: &<T as SystemConfig>::AccountId) -> Self::Balance {91		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible balance");92		match asset {93			AssetId::NativeAssetId(NativeCurrency::Here) => {94				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::balance(who).into()95			}96			AssetId::NativeAssetId(NativeCurrency::Parent) => {97				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::balance(98					AssetId::NativeAssetId(NativeCurrency::Parent),99					who,100				)101				.into()102			}103			AssetId::ForeignAssetId(fid) => {104				let target_collection_id = match <AssetBinding<T>>::get(fid) {105					Some(v) => v,106					None => return Zero::zero(),107				};108				let collection_handle = match <CollectionHandle<T>>::try_get(target_collection_id) {109					Ok(v) => v,110					Err(_) => return Zero::zero(),111				};112				let collection = FungibleHandle::cast(collection_handle);113				Self::Balance::try_from(114					collection.balance(T::CrossAccountId::from_sub(who.clone()), TokenId(0)),115				)116				.unwrap_or(Zero::zero())117			}118		}119	}120121	fn total_balance(asset: Self::AssetId, who: &<T as SystemConfig>::AccountId) -> Self::Balance {122		Self::balance(asset, who)123	}124125	fn reducible_balance(126		asset: Self::AssetId,127		who: &<T as SystemConfig>::AccountId,128		preservation: Preservation,129		fortitude: Fortitude,130	) -> Self::Balance {131		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible reducible_balance");132133		match asset {134			AssetId::NativeAssetId(NativeCurrency::Here) => {135				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::reducible_balance(136					who,137					preservation,138					fortitude,139				)140				.into()141			}142			AssetId::NativeAssetId(NativeCurrency::Parent) => {143				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::reducible_balance(144					AssetId::NativeAssetId(NativeCurrency::Parent),145					who,146					preservation,147					fortitude,148				)149				.into()150			}151			_ => Self::balance(asset, who),152		}153	}154155	fn can_deposit(156		asset: Self::AssetId,157		who: &<T as SystemConfig>::AccountId,158		amount: Self::Balance,159		provenance: Provenance,160	) -> DepositConsequence {161		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_deposit");162163		match asset {164			AssetId::NativeAssetId(NativeCurrency::Here) => {165				<pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::can_deposit(166					who,167					amount.into(),168					provenance,169				)170			}171			AssetId::NativeAssetId(NativeCurrency::Parent) => {172				<orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::can_deposit(173					AssetId::NativeAssetId(NativeCurrency::Parent),174					who,175					amount.into(),176					provenance,177				)178			}179			_ => {180				if amount.is_zero() {181					return DepositConsequence::Success;182				}183184				let extential_deposit_value = T::ExistentialDeposit::get();185				let ed_value: u128 = match extential_deposit_value.try_into() {186					Ok(val) => val,187					Err(_) => return DepositConsequence::CannotCreate,188				};189				let extential_deposit: Self::Balance = match ed_value.try_into() {190					Ok(val) => val,191					Err(_) => return DepositConsequence::CannotCreate,192				};193194				let new_total_balance = match Self::balance(asset, who).checked_add(&amount) {195					Some(x) => x,196					None => return DepositConsequence::Overflow,197				};198199				if new_total_balance < extential_deposit {200					return DepositConsequence::BelowMinimum;201				}202203				DepositConsequence::Success204			}205		}206	}207208	fn can_withdraw(209		asset: Self::AssetId,210		who: &<T as SystemConfig>::AccountId,211		amount: Self::Balance,212	) -> WithdrawConsequence<Self::Balance> {213		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible can_withdraw");214		let value: u128 = match amount.try_into() {215			Ok(val) => val,216			Err(_) => return WithdrawConsequence::UnknownAsset,217		};218219		match asset {220			AssetId::NativeAssetId(NativeCurrency::Here) => {221				let this_amount: <T as pallet_balances::Config>::Balance = match value.try_into() {222					Ok(val) => val,223					Err(_) => {224						return WithdrawConsequence::UnknownAsset;225					}226				};227				match <pallet_balances::Pallet<T> as fungible::Inspect<T::AccountId>>::can_withdraw(228					who,229					this_amount,230				) {231					WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow,232					WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie,233					WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset,234					WithdrawConsequence::Underflow => WithdrawConsequence::Underflow,235					WithdrawConsequence::Overflow => WithdrawConsequence::Overflow,236					WithdrawConsequence::Frozen => WithdrawConsequence::Frozen,237					WithdrawConsequence::Success => WithdrawConsequence::Success,238					_ => WithdrawConsequence::BalanceLow,239				}240			}241			AssetId::NativeAssetId(NativeCurrency::Parent) => {242				let parent_amount: <T as orml_tokens::Config>::Balance = match value.try_into() {243					Ok(val) => val,244					Err(_) => {245						return WithdrawConsequence::UnknownAsset;246					}247				};248				match <orml_tokens::Pallet<T> as fungibles::Inspect<T::AccountId>>::can_withdraw(249					AssetId::NativeAssetId(NativeCurrency::Parent),250					who,251					parent_amount,252				) {253					WithdrawConsequence::BalanceLow => WithdrawConsequence::BalanceLow,254					WithdrawConsequence::WouldDie => WithdrawConsequence::WouldDie,255					WithdrawConsequence::UnknownAsset => WithdrawConsequence::UnknownAsset,256					WithdrawConsequence::Underflow => WithdrawConsequence::Underflow,257					WithdrawConsequence::Overflow => WithdrawConsequence::Overflow,258					WithdrawConsequence::Frozen => WithdrawConsequence::Frozen,259					WithdrawConsequence::Success => WithdrawConsequence::Success,260					_ => WithdrawConsequence::BalanceLow,261				}262			}263			_ => match Self::balance(asset, who).checked_sub(&amount) {264				Some(_) => WithdrawConsequence::Success,265				None => WithdrawConsequence::BalanceLow,266			},267		}268	}269270	fn asset_exists(asset: AssetId) -> bool {271		match asset {272			AssetId::NativeAssetId(_) => true,273			AssetId::ForeignAssetId(fid) => <AssetBinding<T>>::contains_key(fid),274		}275	}276}277278impl<T: Config> fungibles::Mutate<<T as SystemConfig>::AccountId> for Pallet<T>279where280	T: orml_tokens::Config<CurrencyId = AssetId>,281	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,282	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,283	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,284	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,285	u128: From<BalanceOf<T>>,286{287	fn mint_into(288		asset: Self::AssetId,289		who: &<T as SystemConfig>::AccountId,290		amount: Self::Balance,291	) -> Result<BalanceOf<T>, DispatchError> {292		//Self::do_mint(asset, who, amount, None)293		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible mint_into {:?}", asset);294295		match asset {296			AssetId::NativeAssetId(NativeCurrency::Here) => {297				<pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::mint_into(298					who,299					amount.into(),300				)301				.map(Into::into)302			}303			AssetId::NativeAssetId(NativeCurrency::Parent) => {304				<orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::mint_into(305					AssetId::NativeAssetId(NativeCurrency::Parent),306					who,307					amount.into(),308				)309				.map(Into::into)310			}311			AssetId::ForeignAssetId(fid) => {312				let target_collection_id = match <AssetBinding<T>>::get(fid) {313					Some(v) => v,314					None => {315						return Err(DispatchError::Other(316							"Associated collection not found for asset",317						))318					}319				};320				let collection =321					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);322				let account = T::CrossAccountId::from_sub(who.clone());323324				let amount_data: pallet_fungible::CreateItemData<T> =325					(account.clone(), amount.into());326327				pallet_fungible::Pallet::<T>::create_item_foreign(328					&collection,329					&account,330					amount_data,331					&Value::new(0),332				)?;333334				Ok(amount)335			}336		}337	}338339	fn burn_from(340		asset: Self::AssetId,341		who: &<T as SystemConfig>::AccountId,342		amount: Self::Balance,343		precision: Precision,344		fortitude: Fortitude,345	) -> Result<Self::Balance, DispatchError> {346		// let f = DebitFlags { keep_alive: false, best_effort: false };347		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible burn_from");348349		match asset {350			AssetId::NativeAssetId(NativeCurrency::Here) => {351				<pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::burn_from(352					who,353					amount.into(),354					precision,355					fortitude,356				)357				.map(Into::into)358			}359			AssetId::NativeAssetId(NativeCurrency::Parent) => {360				<orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::burn_from(361					AssetId::NativeAssetId(NativeCurrency::Parent),362					who,363					amount.into(),364					precision,365					fortitude,366				)367				.map(Into::into)368			}369			AssetId::ForeignAssetId(fid) => {370				let target_collection_id = match <AssetBinding<T>>::get(fid) {371					Some(v) => v,372					None => {373						return Err(DispatchError::Other(374							"Associated collection not found for asset",375						))376					}377				};378				let collection =379					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);380				pallet_fungible::Pallet::<T>::burn_foreign(381					&collection,382					&T::CrossAccountId::from_sub(who.clone()),383					amount.into(),384				)?;385386				Ok(amount)387			}388		}389	}390391	fn transfer(392		asset: Self::AssetId,393		source: &<T as SystemConfig>::AccountId,394		dest: &<T as SystemConfig>::AccountId,395		amount: Self::Balance,396		preservation: Preservation,397	) -> Result<Self::Balance, DispatchError> {398		// let f = TransferFlags { keep_alive, best_effort: false, burn_dust: false };399		log::trace!(target: "fassets::impl_foreign_assets", "impl_fungible transfer");400401		match asset {402			AssetId::NativeAssetId(NativeCurrency::Here) => {403				match <pallet_balances::Pallet<T> as fungible::Mutate<T::AccountId>>::transfer(404					source,405					dest,406					amount.into(),407					preservation,408				) {409					Ok(_) => Ok(amount),410					Err(_) => Err(DispatchError::Other(411						"Bad amount to relay chain value conversion",412					)),413				}414			}415			AssetId::NativeAssetId(NativeCurrency::Parent) => {416				match <orml_tokens::Pallet<T> as fungibles::Mutate<T::AccountId>>::transfer(417					AssetId::NativeAssetId(NativeCurrency::Parent),418					source,419					dest,420					amount.into(),421					preservation,422				) {423					Ok(_) => Ok(amount),424					Err(e) => Err(e),425				}426			}427			AssetId::ForeignAssetId(fid) => {428				let target_collection_id = match <AssetBinding<T>>::get(fid) {429					Some(v) => v,430					None => {431						return Err(DispatchError::Other(432							"Associated collection not found for asset",433						))434					}435				};436				let collection =437					FungibleHandle::cast(<CollectionHandle<T>>::try_get(target_collection_id)?);438439				pallet_fungible::Pallet::<T>::transfer(440					&collection,441					&T::CrossAccountId::from_sub(source.clone()),442					&T::CrossAccountId::from_sub(dest.clone()),443					amount.into(),444					&Value::new(0),445				)446				.map_err(|e| e.error)?;447448				Ok(amount)449			}450		}451	}452}453454#[cfg(not(debug_assertions))]455extern "C" {456	// This function does not exists, thus compilation will fail, if its call is457	// not optimized away, which is only possible if it's not called at all.458	//459	// not(debug_assertions) is used to ensure compiler is dropping unused functions, as460	// this option is enabled in release by defailt461	//462	// FIXME: maybe use build.rs, to ensure it will fail even in release with debug_assertions463	// enabled?464	fn unbalanced_fungible_is_called();465}466macro_rules! ensure_balanced {467	() => {{468		#[cfg(debug_assertions)]469		panic!("unbalanced fungible methods should not be used");470		#[cfg(not(debug_assertions))]471		{472			unsafe { unbalanced_fungible_is_called() };473			unreachable!();474		}475	}};476}477478impl<T: Config> fungibles::Unbalanced<<T as SystemConfig>::AccountId> for Pallet<T>479where480	T: orml_tokens::Config<CurrencyId = AssetId>,481	BalanceOf<T>: From<<T as pallet_balances::Config>::Balance>,482	BalanceOf<T>: From<<T as orml_tokens::Config>::Balance>,483	<T as pallet_balances::Config>::Balance: From<BalanceOf<T>>,484	<T as orml_tokens::Config>::Balance: From<BalanceOf<T>>,485	u128: From<BalanceOf<T>>,486{487	fn handle_dust(_dust: fungibles::Dust<<T as SystemConfig>::AccountId, Self>) {488		ensure_balanced!();489	}490	fn write_balance(491		_asset: Self::AssetId,492		_who: &<T as SystemConfig>::AccountId,493		_amount: Self::Balance,494	) -> Result<Option<Self::Balance>, DispatchError> {495		ensure_balanced!();496	}497	fn set_total_issuance(_asset: Self::AssetId, _amount: Self::Balance) {498		ensure_balanced!();499	}500}