From 3404a99a6c38dce5958a5a2d5a7256db6ccadf94 Mon Sep 17 00:00:00 2001 From: dnjscksdn98 Date: Thu, 26 Oct 2023 13:35:05 +0900 Subject: [PATCH] feature: add transferrable balance to currency trait --- substrate/frame/balances/src/impl_currency.rs | 25 ++++++++++++++++++- .../support/src/traits/tokens/currency.rs | 11 +++++++- .../src/traits/tokens/currency/reservable.rs | 5 +++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 1ac882ade70d..0056c9c0b81e 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -25,7 +25,12 @@ use frame_support::{ ensure, pallet_prelude::DispatchResult, traits::{ - tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort}, + tokens::{ + fungible, BalanceStatus as Status, + Fortitude::Polite, + Precision::BestEffort, + Preservation::{self, Preserve, Protect}, + }, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::AllowDeath, Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, @@ -487,6 +492,24 @@ where ) .unwrap_or_else(|_| SignedImbalance::Positive(Self::PositiveImbalance::zero())) } + + fn transferrable_balance(who: &T::AccountId, preservation: Preservation) -> Self::Balance { + let a = Self::account(who); + let mut untouchable = a.frozen; + // If we want to keep our provider ref.. + if preservation == Preserve + // ..or we don't want the account to die and our provider ref is needed for it to live.. + || preservation == Protect && !a.free.is_zero() && + frame_system::Pallet::::providers(who) == 1 + // ..or we don't care about the account dying but our provider ref is required.. + || preservation == Expendable && !a.free.is_zero() && + !frame_system::Pallet::::can_dec_provider(who) + { + // ..then the ED needed.. + untouchable = untouchable.max(T::ExistentialDeposit::get()); + } + a.free.saturating_sub(untouchable) + } } impl, I: 'static> ReservableCurrency for Pallet diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 0030e1261dac..4175dbc363d2 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -19,7 +19,7 @@ use super::{ imbalance::{Imbalance, SignedImbalance}, - misc::{Balance, ExistenceRequirement, WithdrawReasons}, + misc::{Balance, ExistenceRequirement, Preservation, WithdrawReasons}, }; use crate::{dispatch::DispatchResult, traits::Get}; use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; @@ -207,6 +207,12 @@ pub trait Currency { who: &AccountId, balance: Self::Balance, ) -> SignedImbalance; + + /// Get the maximum amount that `who` can withdraw/transfer successfully based on whether the + /// account should be kept alive (`preservation`) or whether we are willing to force the + /// reduction and potentially go below user-level restrictions on the minimum amount of the + /// account. + fn transferrable_balance(who: &AccountId, preservation: Preservation) -> Self::Balance; } /// A non-const `Get` implementation parameterised by a `Currency` impl which provides the result @@ -313,4 +319,7 @@ impl Currency for () { ) -> SignedImbalance { SignedImbalance::Positive(()) } + fn transferrable_balance(_: &AccountId, _: Preservation) -> u32 { + 0 + } } diff --git a/substrate/frame/support/src/traits/tokens/currency/reservable.rs b/substrate/frame/support/src/traits/tokens/currency/reservable.rs index ff8b0c6eea83..c42614b2c6ef 100644 --- a/substrate/frame/support/src/traits/tokens/currency/reservable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/reservable.rs @@ -23,7 +23,7 @@ use sp_core::Get; use super::{super::misc::BalanceStatus, Currency}; use crate::{ dispatch::DispatchResult, - traits::{ExistenceRequirement, SignedImbalance, WithdrawReasons}, + traits::{tokens::Preservation, ExistenceRequirement, SignedImbalance, WithdrawReasons}, }; use sp_runtime::DispatchError; @@ -338,6 +338,9 @@ impl< ) -> SignedImbalance { NamedReservable::make_free_balance_be(who, balance) } + fn transferrable_balance(who: &AccountId, preservation: Preservation) -> Self::Balance { + NamedReservable::transferrable_balance(who, preservation) + } } impl< NamedReservable: NamedReservableCurrency,