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

Implement default types for Balanced trait #14506

Open
2 tasks done
Chralt98 opened this issue Jul 4, 2023 · 0 comments
Open
2 tasks done

Implement default types for Balanced trait #14506

Chralt98 opened this issue Jul 4, 2023 · 0 comments
Labels
J0-enhancement An additional feature request. J2-unconfirmed Issue might be valid, but it’s not yet known.

Comments

@Chralt98
Copy link

Chralt98 commented Jul 4, 2023

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)

@Chralt98 Chralt98 added the J0-enhancement An additional feature request. label Jul 4, 2023
@github-actions github-actions bot added the J2-unconfirmed Issue might be valid, but it’s not yet known. label Jul 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
J0-enhancement An additional feature request. J2-unconfirmed Issue might be valid, but it’s not yet known.
Projects
None yet
Development

No branches or pull requests

1 participant