7

I'm trying to implement a feature where users who lock tokens for a certain period of time are granted some rewards. I'm using pallet-balances along with the LockableCurrency trait for this purpose.

I noticed that when calling T::Currency::set_lock(...) I have to provide a reasons parameter WithdrawReasons.

What exactly is the purpose of this parameter and how can I select which reason to select and what implication does this parameter have on the lock itself.

2 Answers 2

3

From Shawn Tabrizi Answer

An account's locked balance is another abstraction over it's free balance. In this case, it is a certain amount that is locked from withdrawing for a certain reason.

The different withdraw reasons are:

  • Transaction Payment: In order to pay for (system) transaction costs.
  • Transfer: In order to transfer ownership.
  • Reserve: In order to reserve some funds for a later return or repatriation.
  • Fee: In order to pay some other (higher-level) fees.

So if an account has a lock for 100 units with WithdrawReasons::Transfer, it cannot make a transfer which brings its free balance lower than 100 units. However, this account will be able to perform another operation like reserve taking its free balance below 100 units. A lock can have multiple reasons associated with it, in which case, those funds can only be spent for the other reasons.

Multiple different locks can be placed on an account, but these locks overlay one another rather than stack. This means that if an account has 3 locks for 100 units, the account can spend it's funds for any reason down to 100 units, at which point the locks will start to come into play.

2

This is the definition of WithdrawReasons

bitflags::bitflags! {
    /// Reasons for moving funds out of an account.
    #[derive(Encode, Decode)]
    pub struct WithdrawReasons: u8 {
        /// In order to pay for (system) transaction costs.
        const TRANSACTION_PAYMENT = 0b00000001;
        /// In order to transfer ownership.
        const TRANSFER = 0b00000010;
        /// In order to reserve some funds for a later return or repatriation.
        const RESERVE = 0b00000100;
        /// In order to pay some other (higher-level) fees.
        const FEE = 0b00001000;
        /// In order to tip a validator for transaction inclusion.
        const TIP = 0b00010000;
    }
}

Note the macro bitflags!.

The bitflags! macro generates structs that manage a set of flags. The flags should only be defined for integer types, otherwise unexpected type errors may occur at compile time.

Think of it like switches, which allow you to use operations like & or | to get or set values. WithdrawReasons can only be a set of these values after you perform some operations to set it using |. Let's say you locked some funds, you'd want to turn on the RESERVE flag like so and you deducted some fees as well in order to make that transaction, you'd use something like :

let reasons = WithdrawReasons::RESERVE | WithdrawReasons::FEE;

Now reasons hold both flags for RESERVE and FEE, which you can tell by looking at it, or performing an & operation, if or not that reason was present.

let fee_deducted : bool = reasons & WithdrawReasons::FEE
assert!(fee_deducted);

If you'd like to clear a value say remove FEE from WithdrawReasons, that's easy too

let clear_fee_deductions = reasons & -WithdrawReasons::FEE
1
  • Thank you for the answer, but what I meant is not how bitflags work but rather what implication does this field has on the lock itself, or it's just for metadata.
    – TarekkMA
    Mar 10, 2022 at 9:32

Your Answer

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

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