1

I would like to divide a Balance into two parts. One is 10% of value and another part is 90% of the value. BalanceOf<T> is the Balance of a pallet.

    type Balance: AtLeast32BitUnsigned
        + FullCodec
        + Copy
        + MaybeSerializeDeserialize
        + Debug
        + Default
        + scale_info::TypeInfo
        + MaxEncodedLen;
let value: BalanceOf<T> = some_balance;
let deposit: BalanceOf<T> = 0.1 * value;
let actual: BalanceOf<T> = value - deposit;

The error message is the following.

cannot multiply `{float}` by `<<T as pallet::Config>::Currencies as orml_traits::MultiCurrency<<T as frame_system::Config>::AccountId>>::Balance`
the trait `Mul<<<T as pallet::Config>::Currencies as orml_traits::MultiCurrency<<T as frame_system::Config>::AccountId>>::Balance>` is not implemented for `{float}`

Another approach is to use sp_runtime::traits::CheckedDiv

let value: BalanceOf<T> = some_balance;
let deposit = value
    .checked_div(&10u128.into())
    .ok_or(DispatchError::Other("Arithmetic error"))?;
let actual = value - deposit;

There I get this error.

the trait `From<u128>` is not implemented for `<<T as pallet::Config>::Currencies as orml_traits::MultiCurrency<<T as frame_system::Config>::AccountId>>::Balance`

What is the best possible way to approach this safely?

1 Answer 1

4

There is actually a function as part of the Imbalance trait to handle exactly this: ration.

You can see an example of its use to split transaction fees between the Treasury and block author in Polkadot.


EDIT: Update to do without an Imbalance.

There is a better pattern to use if you're not dealing with an imbalance (e.g. a transaction fee that's already been deducted from an account). It is from_percent.

This should work (including the option to make it configurable):

use sp_runtime::Percent;

pub type BalanceOf<T> = 
  <<T as Config<I>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

#[frame_support::pallet]
pub mod pallet {

    #[pallet::config]
    pub trait Config: frame_system::Config {

        // Only needed if you want it configurable:
        #[pallet::constant]
        type DepositFee: Get<Percent>;
    }
}

impl<T: Config> Pallet<T> {
  fn my_function(value: BalanceOf<T>) {
    // To hard code in a value, you can just use `Percent` directly:
    let deposit = Percent::from_percent(10) * value;

    // If you want it configurable, you can just `Get` the percentage from the config:
    let deposit = T::DepositFee::get() * value;

    let actual = value - deposit;

    /* do your thing... */
  }
}

Then, if configurable, you would configure your runtime like:

parameter_types! {
    pub const DepositFee: Percent = Percent::from_percent(10);
}

impl my_pallet::Config for Runtime {
    type DepositFee = DepositFee;
}
5
  • That fits my question really well. Thank you for that. How could I create an imbalance out of a balance?
    – Chralt
    May 22, 2022 at 18:08
  • Doh, read it too fast. Updated for when just dealing with balances. May 23, 2022 at 5:25
  • Is Percent::from_percent(10) * value; safe? I would expect checked_mul or saturating_mul in a production environment.
    – Chralt
    Aug 6, 2022 at 9:43
  • It's safe, because a portion of a value is always a resulting smaller value. So it's either zero or lower than the value after the multiplication. That's why there can't be an overflow with this operation.
    – Chralt
    Aug 21, 2022 at 12:10
  • I noticed this only works with the right order. let deposit = T::DepositFee::get() * value; works, but let deposit = value * T::DepositFee::get(); works not. Do you have any reason for that?
    – Chralt
    Dec 24, 2022 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.