mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Balances: repatriate_reserved should respect freezes (#13885)
* repatriate_reserved should respect freezes * Docs * Fix and clean * Formatting * Update frame/balances/src/types.rs Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> * Fix * Simplify * Fixes * Fixes --------- Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
This commit is contained in:
@@ -22,7 +22,7 @@ use frame_support::{
|
|||||||
ensure,
|
ensure,
|
||||||
pallet_prelude::DispatchResult,
|
pallet_prelude::DispatchResult,
|
||||||
traits::{
|
traits::{
|
||||||
tokens::{fungible, BalanceStatus as Status},
|
tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort},
|
||||||
Currency, DefensiveSaturating, ExistenceRequirement,
|
Currency, DefensiveSaturating, ExistenceRequirement,
|
||||||
ExistenceRequirement::AllowDeath,
|
ExistenceRequirement::AllowDeath,
|
||||||
Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency,
|
Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency,
|
||||||
@@ -590,13 +590,18 @@ where
|
|||||||
/// Is a no-op if:
|
/// Is a no-op if:
|
||||||
/// - the value to be moved is zero; or
|
/// - the value to be moved is zero; or
|
||||||
/// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`.
|
/// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`.
|
||||||
|
///
|
||||||
|
/// This is `Polite` and thus will not repatriate any funds which would lead the total balance
|
||||||
|
/// to be less than the frozen amount. Returns `Ok` with the actual amount of funds moved,
|
||||||
|
/// which may be less than `value` since the operation is done an a `BestEffort` basis.
|
||||||
fn repatriate_reserved(
|
fn repatriate_reserved(
|
||||||
slashed: &T::AccountId,
|
slashed: &T::AccountId,
|
||||||
beneficiary: &T::AccountId,
|
beneficiary: &T::AccountId,
|
||||||
value: Self::Balance,
|
value: Self::Balance,
|
||||||
status: Status,
|
status: Status,
|
||||||
) -> Result<Self::Balance, DispatchError> {
|
) -> Result<Self::Balance, DispatchError> {
|
||||||
let actual = Self::do_transfer_reserved(slashed, beneficiary, value, true, status)?;
|
let actual =
|
||||||
|
Self::do_transfer_reserved(slashed, beneficiary, value, BestEffort, Polite, status)?;
|
||||||
Ok(value.saturating_sub(actual))
|
Ok(value.saturating_sub(actual))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,10 @@ type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup
|
|||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use super::*;
|
use super::*;
|
||||||
use frame_support::{pallet_prelude::*, traits::fungible::Credit};
|
use frame_support::{
|
||||||
|
pallet_prelude::*,
|
||||||
|
traits::{fungible::Credit, tokens::Precision},
|
||||||
|
};
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
|
|
||||||
pub type CreditOf<T, I> = Credit<<T as frame_system::Config>::AccountId, Pallet<T, I>>;
|
pub type CreditOf<T, I> = Credit<<T as frame_system::Config>::AccountId, Pallet<T, I>>;
|
||||||
@@ -1100,43 +1103,43 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Move the reserved balance of one account into the balance of another, according to
|
/// Move the reserved balance of one account into the balance of another, according to
|
||||||
/// `status`.
|
/// `status`. This will respect freezes/locks only if `fortitude` is `Polite`.
|
||||||
///
|
///
|
||||||
/// Is a no-op if:
|
/// Is a no-op if the value to be moved is zero.
|
||||||
/// - the value to be moved is zero; or
|
|
||||||
/// - the `slashed` id equal to `beneficiary` and the `status` is `Reserved`.
|
|
||||||
///
|
///
|
||||||
/// NOTE: returns actual amount of transferred value in `Ok` case.
|
/// NOTE: returns actual amount of transferred value in `Ok` case.
|
||||||
pub(crate) fn do_transfer_reserved(
|
pub(crate) fn do_transfer_reserved(
|
||||||
slashed: &T::AccountId,
|
slashed: &T::AccountId,
|
||||||
beneficiary: &T::AccountId,
|
beneficiary: &T::AccountId,
|
||||||
value: T::Balance,
|
value: T::Balance,
|
||||||
best_effort: bool,
|
precision: Precision,
|
||||||
|
fortitude: Fortitude,
|
||||||
status: Status,
|
status: Status,
|
||||||
) -> Result<T::Balance, DispatchError> {
|
) -> Result<T::Balance, DispatchError> {
|
||||||
if value.is_zero() {
|
if value.is_zero() {
|
||||||
return Ok(Zero::zero())
|
return Ok(Zero::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let max = <Self as fungible::InspectHold<_>>::reducible_total_balance_on_hold(
|
||||||
|
slashed, fortitude,
|
||||||
|
);
|
||||||
|
let actual = match precision {
|
||||||
|
Precision::BestEffort => value.min(max),
|
||||||
|
Precision::Exact => value,
|
||||||
|
};
|
||||||
|
ensure!(actual <= max, TokenError::FundsUnavailable);
|
||||||
if slashed == beneficiary {
|
if slashed == beneficiary {
|
||||||
return match status {
|
return match status {
|
||||||
Status::Free => Ok(value.saturating_sub(Self::unreserve(slashed, value))),
|
Status::Free => Ok(actual.saturating_sub(Self::unreserve(slashed, actual))),
|
||||||
Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance(slashed))),
|
Status::Reserved => Ok(actual),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ((actual, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account(
|
let ((_, maybe_dust_1), maybe_dust_2) = Self::try_mutate_account(
|
||||||
beneficiary,
|
beneficiary,
|
||||||
|to_account, is_new| -> Result<(T::Balance, Option<T::Balance>), DispatchError> {
|
|to_account, is_new| -> Result<((), Option<T::Balance>), DispatchError> {
|
||||||
ensure!(!is_new, Error::<T, I>::DeadAccount);
|
ensure!(!is_new, Error::<T, I>::DeadAccount);
|
||||||
Self::try_mutate_account(
|
Self::try_mutate_account(slashed, |from_account, _| -> DispatchResult {
|
||||||
slashed,
|
|
||||||
|from_account, _| -> Result<T::Balance, DispatchError> {
|
|
||||||
let actual = cmp::min(from_account.reserved, value);
|
|
||||||
ensure!(
|
|
||||||
best_effort || actual == value,
|
|
||||||
Error::<T, I>::InsufficientBalance
|
|
||||||
);
|
|
||||||
match status {
|
match status {
|
||||||
Status::Free =>
|
Status::Free =>
|
||||||
to_account.free = to_account
|
to_account.free = to_account
|
||||||
@@ -1149,10 +1152,9 @@ pub mod pallet {
|
|||||||
.checked_add(&actual)
|
.checked_add(&actual)
|
||||||
.ok_or(ArithmeticError::Overflow)?,
|
.ok_or(ArithmeticError::Overflow)?,
|
||||||
}
|
}
|
||||||
from_account.reserved -= actual;
|
from_account.reserved.saturating_reduce(actual);
|
||||||
Ok(actual)
|
Ok(())
|
||||||
},
|
})
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ pub struct AccountData<Balance> {
|
|||||||
/// This is the sum of all individual holds together with any sums still under the (deprecated)
|
/// This is the sum of all individual holds together with any sums still under the (deprecated)
|
||||||
/// reserves API.
|
/// reserves API.
|
||||||
pub reserved: Balance,
|
pub reserved: Balance,
|
||||||
/// The amount that `free` may not drop below when reducing the balance, except for actions
|
/// The amount that `free + reserved` may not drop below when reducing the balance, except for
|
||||||
/// where the account owner cannot reasonably benefit from thr balance reduction, such as
|
/// actions where the account owner cannot reasonably benefit from the balance reduction, such
|
||||||
/// slashing.
|
/// as slashing.
|
||||||
pub frozen: Balance,
|
pub frozen: Balance,
|
||||||
/// Extra information about this account. The MSB is a flag indicating whether the new ref-
|
/// Extra information about this account. The MSB is a flag indicating whether the new ref-
|
||||||
/// counting logic is in place for this account.
|
/// counting logic is in place for this account.
|
||||||
|
|||||||
Reference in New Issue
Block a user