The Balances Pallet is a comprehensive on chain currency which has the flexibility to provide a number of different features.
Within the storage of the Balances Pallet, there are only two balances which are directly stored:
- Free Balance
- Reserved Balance
The sum of these two balances is used to calculate the total balance of an account.
Additional layers of logic are put on top of free balance in order to create abstractions like:
- Locked Balance
- Vesting Balance
So let's walk through the different types of balances managed by the Balances Pallet.
From the terminology section of the reference docs:
Free Balance: The portion of a balance that is not reserved. The free balance is the only balance that matters for most operations. When this balance falls below the existential deposit, most functionality of the account is removed. When both it and the reserved balance are deleted, then the account is said to be dead.
The free balance of an account is used whenever a
reserve is initiated. Before these operations can complete successfully,
ensure_can_withdraw is called with some
WithdrawReason and checks that a withdrawal does not interfere with some vesting balance or locked balance.
This does not prevent other operations like
slash from occurring, which does not care about any abstractions over free balance.
An account's vesting balance is an abstraction over it's free balance. More specifically, an account which has a vesting balance cannot spend from their free balance lower than that amount. Vesting balance does not care about the
amount_spendable = free_balance - vesting_balance
So even though an account may seem like it has a lot of liquid funds to spend when querying the free balance, an accounts vesting balance can prevent those funds from being withdrawn.
Vesting balance can only be set at the genesis of a Substrate chain, and decreases at a linear rate per block starting at some
starting_block for a
length of blocks, at which point vesting balance is zero. The vesting balance can be larger than the free balance in situations when the free balance is reduced by slashing. In these cases
amount_spendable is saturated to zero.
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.
Locked balance also overlays with vesting balance as these two are checked independently, but both checks must pass for
ensure_can_withdraw to be successful.
From the terminology section:
Reserved Balance: Reserved balance still belongs to the account holder, but is suspended. Reserved balance can still be slashed, but only after all the free balance has been slashed. If the reserved balance falls below the existential deposit then it and any related functionality will be deleted. When both it and the free balance are deleted, then the account is said to be dead.
Relatively speaking, reserved balance is more simple than free balance because there are no abstractions over it. Funds which are reserved from a user are not meant to be directly touched by any other logic outside of the Balances pallet. Instead, funds should first be
unreserved and then modified in the
Reserved Balance vs Locked Balance
Reserved balance and locked balance appear similar but are fundamentally different. Locked balance has an identity in terms of a lock identifier, what reasons funds are locked for, and how long they are locked for. A reserved balance has none of these traits, and are untouchable without explicit action from the runtime to unreserve those funds.
Furthermore, there could be implications about having a free balance to versus not having one. For example, if you set a lock on the full free balance of an account, it will still have a free balance, and
OnFreeBalanceZero will not be called. However, if you
reserve all the funds, the free balance will drop below the existential deposit and
OnFreeBalanceZero will be triggered for pallets who have implemented this feature.