Skip to content

Commit

Permalink
fungible::Unbalanced::decrease_balance: Handle precision properly (
Browse files Browse the repository at this point in the history
  • Loading branch information
bkchr committed Jan 5, 2024
1 parent 19de1c9 commit 1c95310
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
11 changes: 11 additions & 0 deletions prdoc/pr_2823.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title: "`fungible::Unbalanced::decrease_balance`: Handle `precision` properly"

doc:
- audience: Runtime Dev
description: |
`fungible::Unbalanced::decrease_balance` will now handle `precision` properly. This means when
passing `Exact`, it will ensure that the available balance is bigger or equal to the `amount`
that should be deducted.

crates:
- name: "frame-support"
27 changes: 26 additions & 1 deletion substrate/frame/balances/src/tests/fungible_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn unbalanced_trait_decrease_balance_works_2() {
assert_eq!(Balances::total_balance_on_hold(&1337), 60);
assert_noop!(
Balances::decrease_balance(&1337, 40, Exact, Expendable, Polite),
Error::<Test>::InsufficientBalance
TokenError::FundsUnavailable
);
assert_eq!(Balances::decrease_balance(&1337, 39, Exact, Expendable, Polite), Ok(39));
assert_eq!(<Balances as fungible::Inspect<_>>::balance(&1337), 1);
Expand Down Expand Up @@ -468,3 +468,28 @@ fn emit_events_with_changing_freezes() {
assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Thawed { who: 1, amount: 15 })]);
});
}

#[test]
fn withdraw_precision_exact_works() {
ExtBuilder::default()
.existential_deposit(1)
.monied(true)
.build_and_execute_with(|| {
assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 10));
assert_eq!(Balances::account(&1).free, 10);
assert_eq!(Balances::account(&1).frozen, 10);

// `BestEffort` will not reduce anything
assert_ok!(<Balances as fungible::Balanced<_>>::withdraw(
&1, 5, BestEffort, Preserve, Polite
));

assert_eq!(Balances::account(&1).free, 10);
assert_eq!(Balances::account(&1).frozen, 10);

assert_noop!(
<Balances as fungible::Balanced<_>>::withdraw(&1, 5, Exact, Preserve, Polite),
TokenError::FundsUnavailable
);
});
}
11 changes: 9 additions & 2 deletions substrate/frame/support/src/traits/tokens/fungible/regular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,16 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
) -> Result<Self::Balance, DispatchError> {
let old_balance = Self::balance(who);
let free = Self::reducible_balance(who, preservation, force);
if let BestEffort = precision {
amount = amount.min(free);
match precision {
BestEffort => {
amount = amount.min(free);
},
Exact =>
if free < amount {
return Err(TokenError::FundsUnavailable.into())
},
}

let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
if let Some(dust) = Self::write_balance(who, new_balance)? {
Self::handle_dust(Dust(dust));
Expand Down

0 comments on commit 1c95310

Please sign in to comment.