mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 21:41:12 +00:00
Balance to Asset Balance Conversion (#9076)
* add BalanceConversion trait and implementation * derive some useful traits on Imbalance * Update frame/support/src/traits/tokens/fungibles/imbalance.rs Co-authored-by: Xiliang Chen <xlchen1291@gmail.com> * make BalanceConversion error type configurable * add RuntimeDebug import and derive traits on other Imbalance * formatting * move BalanceConversion trait to frame-support * add necessary trait import Co-authored-by: Xiliang Chen <xlchen1291@gmail.com>
This commit is contained in:
@@ -144,7 +144,7 @@ use sp_runtime::{
|
||||
traits::{AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub, CheckedAdd, Bounded}
|
||||
};
|
||||
use codec::HasCompact;
|
||||
use frame_support::{ensure, dispatch::{DispatchError, DispatchResult}};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_support::traits::{Currency, ReservableCurrency, BalanceStatus::Reserved, StoredMap};
|
||||
use frame_support::traits::tokens::{WithdrawConsequence, DepositConsequence, fungibles};
|
||||
use frame_system::Config as SystemConfig;
|
||||
@@ -154,10 +154,6 @@ pub use pallet::*;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use frame_support::{
|
||||
dispatch::DispatchResult,
|
||||
pallet_prelude::*,
|
||||
};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
use super::*;
|
||||
use crate::{Error, mock::*};
|
||||
use sp_runtime::TokenError;
|
||||
use sp_runtime::{TokenError, traits::ConvertInto};
|
||||
use frame_support::{assert_ok, assert_noop, traits::Currency};
|
||||
use pallet_balances::Error as BalancesError;
|
||||
|
||||
@@ -699,3 +699,29 @@ fn force_asset_status_should_work(){
|
||||
assert_eq!(Assets::total_supply(0), 200);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn balance_conversion_should_work() {
|
||||
new_test_ext().execute_with(|| {
|
||||
use frame_support::traits::tokens::BalanceConversion;
|
||||
|
||||
let id = 42;
|
||||
assert_ok!(Assets::force_create(Origin::root(), id, 1, true, 10));
|
||||
let not_sufficient = 23;
|
||||
assert_ok!(Assets::force_create(Origin::root(), not_sufficient, 1, false, 10));
|
||||
|
||||
assert_eq!(
|
||||
BalanceToAssetBalance::<Balances, Test, ConvertInto>::to_asset_balance(100, 1234),
|
||||
Err(ConversionError::AssetMissing)
|
||||
);
|
||||
assert_eq!(
|
||||
BalanceToAssetBalance::<Balances, Test, ConvertInto>::to_asset_balance(100, not_sufficient),
|
||||
Err(ConversionError::AssetNotSufficient)
|
||||
);
|
||||
// 10 / 1 == 10 -> the conversion should 10x the value
|
||||
assert_eq!(
|
||||
BalanceToAssetBalance::<Balances, Test, ConvertInto>::to_asset_balance(100, id),
|
||||
Ok(100 * 10)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
use frame_support::traits::{fungible, tokens::BalanceConversion};
|
||||
use sp_runtime::{FixedPointNumber, FixedPointOperand, FixedU128};
|
||||
use sp_runtime::traits::Convert;
|
||||
|
||||
pub(super) type DepositBalanceOf<T, I = ()> =
|
||||
<<T as Config<I>>::Currency as Currency<<T as SystemConfig>::AccountId>>::Balance;
|
||||
|
||||
@@ -177,3 +181,58 @@ impl From<TransferFlags> for DebitFlags {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible errors when converting between external and asset balances.
|
||||
#[derive(Eq, PartialEq, Copy, Clone, RuntimeDebug, Encode, Decode)]
|
||||
pub enum ConversionError {
|
||||
/// The external minimum balance must not be zero.
|
||||
MinBalanceZero,
|
||||
/// The asset is not present in storage.
|
||||
AssetMissing,
|
||||
/// The asset is not sufficient and thus does not have a reliable `min_balance` so it cannot be converted.
|
||||
AssetNotSufficient,
|
||||
}
|
||||
|
||||
// Type alias for `frame_system`'s account id.
|
||||
type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
|
||||
// This pallet's asset id and balance type.
|
||||
type AssetIdOf<T, I> = <T as Config<I>>::AssetId;
|
||||
type AssetBalanceOf<T, I> = <T as Config<I>>::Balance;
|
||||
// Generic fungible balance type.
|
||||
type BalanceOf<F, T> = <F as fungible::Inspect<AccountIdOf<T>>>::Balance;
|
||||
|
||||
/// Converts a balance value into an asset balance based on the ratio between the fungible's
|
||||
/// minimum balance and the minimum asset balance.
|
||||
pub struct BalanceToAssetBalance<F, T, CON, I = ()>(PhantomData<(F, T, CON, I)>);
|
||||
impl<F, T, CON, I> BalanceConversion<BalanceOf<F, T>, AssetIdOf<T, I>, AssetBalanceOf<T, I>>
|
||||
for BalanceToAssetBalance<F, T, CON, I>
|
||||
where
|
||||
F: fungible::Inspect<AccountIdOf<T>>,
|
||||
T: Config<I>,
|
||||
I: 'static,
|
||||
CON: Convert<BalanceOf<F, T>, AssetBalanceOf<T, I>>,
|
||||
BalanceOf<F, T>: FixedPointOperand + Zero,
|
||||
AssetBalanceOf<T, I>: FixedPointOperand + Zero,
|
||||
{
|
||||
type Error = ConversionError;
|
||||
|
||||
/// Convert the given balance value into an asset balance based on the ratio between the fungible's
|
||||
/// minimum balance and the minimum asset balance.
|
||||
///
|
||||
/// Will return `Err` if the asset is not found, not sufficient or the fungible's minimum balance is zero.
|
||||
fn to_asset_balance(
|
||||
balance: BalanceOf<F, T>,
|
||||
asset_id: AssetIdOf<T, I>,
|
||||
) -> Result<AssetBalanceOf<T, I>, ConversionError> {
|
||||
let asset = Asset::<T, I>::get(asset_id).ok_or(ConversionError::AssetMissing)?;
|
||||
// only sufficient assets have a min balance with reliable value
|
||||
ensure!(asset.is_sufficient, ConversionError::AssetNotSufficient);
|
||||
let min_balance = CON::convert(F::minimum_balance());
|
||||
// make sure we don't divide by zero
|
||||
ensure!(!min_balance.is_zero(), ConversionError::MinBalanceZero);
|
||||
let balance = CON::convert(balance);
|
||||
// balance * asset.min_balance / min_balance
|
||||
Ok(FixedU128::saturating_from_rational(asset.min_balance, min_balance)
|
||||
.saturating_mul_int(balance))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ pub mod nonfungible;
|
||||
pub mod nonfungibles;
|
||||
mod misc;
|
||||
pub use misc::{
|
||||
WithdrawConsequence, DepositConsequence, ExistenceRequirement, BalanceStatus, WithdrawReasons,
|
||||
BalanceConversion, BalanceStatus, DepositConsequence,
|
||||
ExistenceRequirement, WithdrawConsequence, WithdrawReasons,
|
||||
};
|
||||
pub use imbalance::Imbalance;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
use super::*;
|
||||
use sp_std::marker::PhantomData;
|
||||
use sp_runtime::traits::Zero;
|
||||
use sp_runtime::{RuntimeDebug, traits::Zero};
|
||||
use super::misc::Balance;
|
||||
use super::balanced::Balanced;
|
||||
use crate::traits::misc::{TryDrop, SameOrOther};
|
||||
@@ -39,6 +39,7 @@ pub trait HandleImbalanceDrop<Balance> {
|
||||
///
|
||||
/// Importantly, it has a special `Drop` impl, and cannot be created outside of this module.
|
||||
#[must_use]
|
||||
#[derive(RuntimeDebug, Eq, PartialEq)]
|
||||
pub struct Imbalance<
|
||||
B: Balance,
|
||||
OnDrop: HandleImbalanceDrop<B>,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
use super::*;
|
||||
use sp_std::marker::PhantomData;
|
||||
use sp_runtime::traits::Zero;
|
||||
use sp_runtime::{RuntimeDebug, traits::Zero};
|
||||
use super::fungibles::{AssetId, Balance};
|
||||
use super::balanced::Balanced;
|
||||
use crate::traits::misc::{TryDrop, SameOrOther};
|
||||
@@ -37,6 +37,7 @@ pub trait HandleImbalanceDrop<AssetId, Balance> {
|
||||
///
|
||||
/// Importantly, it has a special `Drop` impl, and cannot be created outside of this module.
|
||||
#[must_use]
|
||||
#[derive(RuntimeDebug, Eq, PartialEq)]
|
||||
pub struct Imbalance<
|
||||
A: AssetId,
|
||||
B: Balance,
|
||||
|
||||
@@ -167,3 +167,9 @@ impl<T: FullCodec + Copy + Eq + PartialEq + Debug> AssetId for T {}
|
||||
/// Simple amalgamation trait to collect together properties for a Balance under one roof.
|
||||
pub trait Balance: AtLeast32BitUnsigned + FullCodec + Copy + Default + Debug {}
|
||||
impl<T: AtLeast32BitUnsigned + FullCodec + Copy + Default + Debug> Balance for T {}
|
||||
|
||||
/// Converts a balance value into an asset balance.
|
||||
pub trait BalanceConversion<InBalance, AssetId, OutBalance> {
|
||||
type Error;
|
||||
fn to_asset_balance(balance: InBalance, asset_id: AssetId) -> Result<OutBalance, Self::Error>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user