Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Implement default types for Balanced trait #14506

Open
@Chralt98

Description

@Chralt98

Is there an existing issue?

  • I have searched the existing issues

Experiencing problems? Have you tried our Stack Exchange first?

  • This is not a support question.

Motivation

In polkadot-v0.9.36 you find a full default implementation (with types) for Balanced.

impl<AccountId, U: Unbalanced<AccountId>> Balanced<AccountId> for U {
type OnDropCredit = DecreaseIssuance<AccountId, U>;
type OnDropDebt = IncreaseIssuance<AccountId, U>;
fn rescind(amount: Self::Balance) -> Debt<AccountId, Self> {
let old = U::total_issuance();
let new = old.saturating_sub(amount);
U::set_total_issuance(new);
debt(old - new)
}
fn issue(amount: Self::Balance) -> Credit<AccountId, Self> {
let old = U::total_issuance();
let new = old.saturating_add(amount);
U::set_total_issuance(new);
credit(new - old)
}
fn slash(who: &AccountId, amount: Self::Balance) -> (Credit<AccountId, Self>, Self::Balance) {
let slashed = U::decrease_balance_at_most(who, amount);
// `slashed` could be less than, greater than or equal to `amount`.
// If slashed == amount, it means the account had at least amount in it and it could all be
// removed without a problem.
// If slashed > amount, it means the account had more than amount in it, but not enough more
// to push it over minimum_balance.
// If slashed < amount, it means the account didn't have enough in it to be reduced by
// `amount` without being destroyed.
(credit(slashed), amount.saturating_sub(slashed))
}
fn deposit(
who: &AccountId,
amount: Self::Balance,
) -> Result<Debt<AccountId, Self>, DispatchError> {
let increase = U::increase_balance(who, amount)?;
Ok(debt(increase))
}
fn withdraw(
who: &AccountId,
amount: Self::Balance,
// TODO: liveness: ExistenceRequirement,
) -> Result<Credit<AccountId, Self>, DispatchError> {
let decrease = U::decrease_balance(who, amount)?;
Ok(credit(decrease))
}
}

For polkadot-v0.9.42 there are default trait implementations for the methods, but not for the two types "OnDropDebt" and "OnDropCredit".

/// A fungible token class where any creation and deletion of tokens is semi-explicit and where the
/// total supply is maintained automatically.
///
/// This is auto-implemented when a token class has `Unbalanced` implemented.
pub trait Balanced<AccountId>: Inspect<AccountId> + Unbalanced<AccountId> {
/// The type for managing what happens when an instance of `Debt` is dropped without being used.
type OnDropDebt: HandleImbalanceDrop<Self::Balance>;
/// The type for managing what happens when an instance of `Credit` is dropped without being
/// used.
type OnDropCredit: HandleImbalanceDrop<Self::Balance>;
/// Reduce the total issuance by `amount` and return the according imbalance. The imbalance will
/// typically be used to reduce an account by the same amount with e.g. `settle`.
///
/// This is infallible, but doesn't guarantee that the entire `amount` is burnt, for example
/// in the case of underflow.
fn rescind(amount: Self::Balance) -> Debt<AccountId, Self> {
let old = Self::total_issuance();
let new = old.saturating_sub(amount);
Self::set_total_issuance(new);
let delta = old - new;
Self::done_rescind(delta);
Imbalance::<Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(delta)
}
/// Increase the total issuance by `amount` and return the according imbalance. The imbalance
/// will typically be used to increase an account by the same amount with e.g.
/// `resolve_into_existing` or `resolve_creating`.
///
/// This is infallible, but doesn't guarantee that the entire `amount` is issued, for example
/// in the case of overflow.
fn issue(amount: Self::Balance) -> Credit<AccountId, Self> {
let old = Self::total_issuance();
let new = old.saturating_add(amount);
Self::set_total_issuance(new);
let delta = new - old;
Self::done_issue(delta);
Imbalance::<Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(delta)
}
/// Produce a pair of imbalances that cancel each other out exactly.
///
/// This is just the same as burning and issuing the same amount and has no effect on the
/// total issuance.
fn pair(amount: Self::Balance) -> (Debt<AccountId, Self>, Credit<AccountId, Self>) {
(Self::rescind(amount), Self::issue(amount))
}
/// Mints `value` into the account of `who`, creating it as needed.
///
/// If `precision` is `BestEffort` and `value` in full could not be minted (e.g. due to
/// overflow), then the maximum is minted, up to `value`. If `precision` is `Exact`, then
/// exactly `value` must be minted into the account of `who` or the operation will fail with an
/// `Err` and nothing will change.
///
/// If the operation is successful, this will return `Ok` with a `Debt` of the total value
/// added to the account.
fn deposit(
who: &AccountId,
value: Self::Balance,
precision: Precision,
) -> Result<Debt<AccountId, Self>, DispatchError> {
let increase = Self::increase_balance(who, value, precision)?;
Self::done_deposit(who, increase);
Ok(Imbalance::<Self::Balance, Self::OnDropDebt, Self::OnDropCredit>::new(increase))
}
/// Removes `value` balance from `who` account if possible.
///
/// If `precision` is `BestEffort` and `value` in full could not be removed (e.g. due to
/// underflow), then the maximum is removed, up to `value`. If `precision` is `Exact`, then
/// exactly `value` must be removed from the account of `who` or the operation will fail with an
/// `Err` and nothing will change.
///
/// If the removal is needed but not possible, then it returns `Err` and nothing is changed.
/// If the account needed to be deleted, then slightly more than `value` may be removed from the
/// account owning since up to (but not including) minimum balance may also need to be removed.
///
/// If the operation is successful, this will return `Ok` with a `Credit` of the total value
/// removed from the account.
fn withdraw(
who: &AccountId,
value: Self::Balance,
precision: Precision,
preservation: Preservation,
force: Fortitude,
) -> Result<Credit<AccountId, Self>, DispatchError> {
let decrease = Self::decrease_balance(who, value, precision, preservation, force)?;
Self::done_withdraw(who, decrease);
Ok(Imbalance::<Self::Balance, Self::OnDropCredit, Self::OnDropDebt>::new(decrease))
}
/// The balance of `who` is increased in order to counter `credit`. If the whole of `credit`
/// cannot be countered, then nothing is changed and the original `credit` is returned in an
/// `Err`.
///
/// Please note: If `credit.peek()` is less than `Self::minimum_balance()`, then `who` must
/// already exist for this to succeed.
fn resolve(
who: &AccountId,
credit: Credit<AccountId, Self>,
) -> Result<(), Credit<AccountId, Self>> {
let v = credit.peek();
let debt = match Self::deposit(who, v, Exact) {
Err(_) => return Err(credit),
Ok(d) => d,
};
let result = credit.offset(debt).try_drop();
debug_assert!(result.is_ok(), "ok deposit return must be equal to credit value; qed");
Ok(())
}
/// The balance of `who` is decreased in order to counter `debt`. If the whole of `debt`
/// cannot be countered, then nothing is changed and the original `debt` is returned in an
/// `Err`.
fn settle(
who: &AccountId,
debt: Debt<AccountId, Self>,
preservation: Preservation,
) -> Result<Credit<AccountId, Self>, Debt<AccountId, Self>> {
let amount = debt.peek();
let credit = match Self::withdraw(who, amount, Exact, preservation, Polite) {
Err(_) => return Err(debt),
Ok(d) => d,
};
match credit.offset(debt) {
SameOrOther::None => Ok(Credit::<AccountId, Self>::zero()),
SameOrOther::Same(dust) => Ok(dust),
SameOrOther::Other(rest) => {
debug_assert!(false, "ok withdraw return must be at least debt value; qed");
Err(rest)
},
}
}
fn done_rescind(_amount: Self::Balance) {}
fn done_issue(_amount: Self::Balance) {}
fn done_deposit(_who: &AccountId, _amount: Self::Balance) {}
fn done_withdraw(_who: &AccountId, _amount: Self::Balance) {}
}

This means that if I put in orml_tokens into Fungibles of "pallet-asset-tx-payment", it throws me a compiler error, because Balanced is not fully implemented for orml_tokens (the default implementation is not present for the mentioned types).

type Fungibles: Balanced<Self::AccountId>;

Request

Can you provide a full default implementation, so that orml_tokens, which just implements "fungibles::Inspect", can work as "Balanced"?

Solution

pub struct DefaultBalancedToken<AccountId, U>(PhantomData<(AccountId, U)>);

impl<AccountId, U: Unbalanced<AccountId>> Balanced<AccountId> for DefaultBalancedToken<AccountId, U> {
    type OnDropDebt = IncreaseIssuance<AccountId, U>;
    type OnDropCredit = DecreaseIssuance<AccountId, U>;
    // No need to provide implementations for the methods, as they all have default implementations
}

Are you willing to help with this request?

Maybe (please elaborate above)

Metadata

Metadata

Assignees

No one assigned

    Labels

    J0-enhancementAn additional feature request.J2-unconfirmedIssue might be valid, but it’s not yet known.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions