Tokens in FRAME Docs (#2802)

Closes https://github.com/paritytech/polkadot-sdk-docs/issues/70

WIP PR for an overview of how to develop tokens in FRAME. 

- [x] Tokens in Substrate Ref Doc
  - High-level overview of the token-related logic in FRAME
- Improve docs with better explanation of how holds, freezes, ed, free
balance, etc, all work
- [x] Update `pallet_balances` docs
  - Clearly mark what is deprecated (currency)
- [x] Write fungible trait docs
- [x] Evaluate and if required update `pallet_assets`, `pallet_uniques`,
`pallet_nfts` docs
- [x] Absorb https://github.com/paritytech/polkadot-sdk/pull/2683/
- [x] Audit individual trait method docs, and improve if possible

Feel free to suggest additional TODOs for this PR in the comments

---------

Co-authored-by: Bill Laboon <laboon@users.noreply.github.com>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
This commit is contained in:
Liam Aharon
2024-03-31 20:59:33 +11:00
committed by GitHub
parent 0d93248473
commit 41257069b0
28 changed files with 378 additions and 84 deletions
@@ -16,6 +16,9 @@
// limitations under the License.
//! The Currency trait and associated types.
//!
//! Note Currency and related traits are deprecated, instead
//! [`fungible`](frame_support::traits::fungible) traits should be used.
use super::{
imbalance::{Imbalance, SignedImbalance},
@@ -16,6 +16,9 @@
// limitations under the License.
//! The traits for putting freezes within a single fungible token class.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits
//! including the place of the Freezes in FRAME.
use scale_info::TypeInfo;
use sp_arithmetic::{
@@ -35,7 +38,7 @@ pub trait Inspect<AccountId>: super::Inspect<AccountId> {
/// An identifier for a freeze.
type Id: codec::Encode + TypeInfo + 'static;
/// Amount of funds held in reserve by `who` for the given `id`.
/// Amount of funds frozen in reserve by `who` for the given `id`.
fn balance_frozen(id: &Self::Id, who: &AccountId) -> Self::Balance;
/// The amount of the balance which can become frozen. Defaults to `total_balance()`.
@@ -45,11 +48,11 @@ pub trait Inspect<AccountId>: super::Inspect<AccountId> {
/// Returns `true` if it's possible to introduce a freeze for the given `id` onto the
/// account of `who`. This will be true as long as the implementor supports as many
/// concurrent freeze locks as there are possible values of `id`.
/// concurrent freezes as there are possible values of `id`.
fn can_freeze(id: &Self::Id, who: &AccountId) -> bool;
}
/// Trait for introducing, altering and removing locks to freeze an account's funds so they never
/// Trait for introducing, altering and removing freezes for an account for its funds never
/// go below a set minimum.
pub trait Mutate<AccountId>: Inspect<AccountId> {
/// Prevent actions which would reduce the balance of the account of `who` below the given
@@ -66,16 +69,16 @@ pub trait Mutate<AccountId>: Inspect<AccountId> {
/// counteract any pre-existing freezes in place for `who` under the `id`. Also unlike
/// `set_freeze`, in the case that `amount` is zero, this is no-op and never fails.
///
/// Note that more funds can be locked than the total balance, if desired.
/// Note that more funds can be frozen than the total balance, if desired.
fn extend_freeze(id: &Self::Id, who: &AccountId, amount: Self::Balance) -> DispatchResult;
/// Remove an existing lock.
/// Remove an existing freeze.
fn thaw(id: &Self::Id, who: &AccountId) -> DispatchResult;
/// Attempt to alter the amount frozen under the given `id` to `amount`.
///
/// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is
/// `Fortitude::Force`.
/// [`Fortitude::Force`].
fn set_frozen(
id: &Self::Id,
who: &AccountId,
@@ -91,7 +94,7 @@ pub trait Mutate<AccountId>: Inspect<AccountId> {
/// the amount frozen under `id`. Do nothing otherwise.
///
/// Fail if the account of `who` has fewer freezable funds than `amount`, unless `fortitude` is
/// `Fortitude::Force`.
/// [`Fortitude::Force`].
fn ensure_frozen(
id: &Self::Id,
who: &AccountId,
@@ -16,6 +16,9 @@
// limitations under the License.
//! The traits for putting holds within a single fungible token class.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits
//! including the place of the Holds in FRAME.
use crate::{
ensure,
@@ -214,8 +217,8 @@ pub trait Mutate<AccountId>:
///
/// The actual amount released is returned with `Ok`.
///
/// If `precision` is `BestEffort`, then the amount actually unreserved and returned as the
/// inner value of `Ok` may be smaller than the `amount` passed.
/// If `precision` is [`Precision::BestEffort`], then the amount actually unreserved and
/// returned as the inner value of `Ok` may be smaller than the `amount` passed.
///
/// NOTE! The inner of the `Ok` result variant returns the *actual* amount released. This is the
/// opposite of the `ReservableCurrency::unreserve()` result, which gives the amount not able
@@ -17,6 +17,8 @@
//! The imbalance type and its associates, which handles keeps everything adding up properly with
//! unbalanced operations.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
use super::{super::Imbalance as ImbalanceT, Balanced, *};
use crate::traits::{
@@ -16,6 +16,11 @@
// limitations under the License.
//! Adapter to use `fungibles::*` implementations as `fungible::*`.
//!
//! This allows for a `fungibles` asset, e.g. from the `pallet_assets` pallet, to be used when a
//! `fungible` asset is expected.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
use super::*;
use crate::traits::{
@@ -17,26 +17,135 @@
//! The traits for dealing with a single fungible token class and any associated types.
//!
//! ### User-implememted traits
//! - `Inspect`: Regular balance inspector functions.
//! - `Unbalanced`: Low-level balance mutating functions. Does not guarantee proper book-keeping and
//! so should not be called into directly from application code. Other traits depend on this and
//! provide default implementations based on it.
//! - `UnbalancedHold`: Low-level balance mutating functions for balances placed on hold. Does not
//! Also see the [`frame_tokens`] reference docs for more information about the place of
//! `fungible` traits in Substrate.
//!
//! # Avaliable Traits
//! - [`Inspect`]: Regular balance inspector functions.
//! - [`Unbalanced`]: Low-level balance mutating functions. Does not guarantee proper book-keeping
//! and so should not be called into directly from application code. Other traits depend on this
//! and provide default implementations based on it.
//! - [`UnbalancedHold`]: Low-level balance mutating functions for balances placed on hold. Does not
//! guarantee proper book-keeping and so should not be called into directly from application code.
//! Other traits depend on this and provide default implementations based on it.
//! - `Mutate`: Regular balance mutator functions. Pre-implemented using `Unbalanced`, though the
//! `done_*` functions should likely be reimplemented in case you want to do something following
//! the operation such as emit events.
//! - `InspectHold`: Inspector functions for balances on hold.
//! - `MutateHold`: Mutator functions for balances on hold. Mostly pre-implemented using
//! `UnbalancedHold`.
//! - `InspectFreeze`: Inspector functions for frozen balance.
//! - `MutateFreeze`: Mutator functions for frozen balance.
//! - `Balanced`: One-sided mutator functions for regular balances, which return imbalance objects
//! - [`Mutate`]: Regular balance mutator functions. Pre-implemented using [`Unbalanced`], though
//! the `done_*` functions should likely be reimplemented in case you want to do something
//! following the operation such as emit events.
//! - [`InspectHold`]: Inspector functions for balances on hold.
//! - [`MutateHold`]: Mutator functions for balances on hold. Mostly pre-implemented using
//! [`UnbalancedHold`].
//! - [`InspectFreeze`]: Inspector functions for frozen balance.
//! - [`MutateFreeze`]: Mutator functions for frozen balance.
//! - [`Balanced`]: One-sided mutator functions for regular balances, which return imbalance objects
//! which guarantee eventual book-keeping. May be useful for some sophisticated operations where
//! funds must be removed from an account before it is known precisely what should be done with
//! them.
//!
//! ## Terminology
//!
//! - **Total Issuance**: The total number of units in existence in a system.
//!
//! - **Total Balance**: The sum of an account's free and held balances.
//!
//! - **Free Balance**: A portion of an account's total balance that is not held. Note this is
//! distinct from the Spendable Balance, which represents how much Balance the user can actually
//! transfer.
//!
//! - **Held Balance**: Held balance still belongs to the account holder, but is suspended. It can
//! be slashed, but only after all the free balance has been slashed.
//!
//! Multiple holds stack rather than overlay. This means that if an account has
//! 3 holds for 100 units, the account can spend its funds for any reason down to 300 units, at
//! which point the holds will start to come into play.
//!
//! - **Frozen Balance**: A freeze on a specified amount of an account's free balance until a
//! specified block number.
//!
//! Multiple freezes always operate over the same funds, so they "overlay" rather than
//! "stack". This means that if an account has 3 freezes for 100 units, the account can spend its
//! funds for any reason down to 100 units, at which point the freezes will start to come into
//! play.
//!
//! - **Minimum Balance (a.k.a. Existential Deposit, a.k.a. ED)**: The minimum balance required to
//! create or keep an account open. This is to prevent "dust accounts" from filling storage. When
//! the free plus the held balance (i.e. the total balance) falls below this, then the account is
//! said to be dead. It loses its functionality as well as any prior history and all information
//! on it is removed from the chain's state. No account should ever have a total balance that is
//! strictly between 0 and the existential deposit (exclusive). If this ever happens, it indicates
//! either a bug in the implementation of this trait or an erroneous raw mutation of storage.
//!
//! - **Untouchable Balance**: The part of a user's free balance they cannot spend, due to ED or
//! Freeze(s).
//!
//! - **Spendable Balance**: The part of a user's free balance they can actually transfer, after
//! accounting for Holds and Freezes.
//!
//! - **Imbalance**: A condition when some funds were credited or debited without equal and opposite
//! accounting (i.e. a difference between total issuance and account balances). Functions that
//! result in an imbalance will return an object of the [`imbalance::Credit`] or
//! [`imbalance::Debt`] traits that can be managed within your runtime logic.
//!
//! If an imbalance is simply dropped, it should automatically maintain any book-keeping such as
//! total issuance.
//!
//! ## Visualising Balance Components Together 💫
//!
//! ```ignore
//! |__total__________________________________|
//! |__on_hold__|_____________free____________|
//! |__________frozen___________|
//! |__on_hold__|__ed__|
//! |__untouchable__|__spendable__|
//! ```
//!
//! ## Holds and Freezes
//!
//! Both holds and freezes are used to prevent an account from using some of its balance.
//!
//! The primary distinction between the two are that:
//! - Holds are cumulative (do not overlap) and are distinct from the free balance
//! - Freezes are not cumulative, and can overlap with each other or with holds
//!
//! ```ignore
//! |__total_____________________________|
//! |__hold_a__|__hold_b__|_____free_____|
//! |__on_hold____________| // <- the sum of all holds
//! |__freeze_a_______________|
//! |__freeze_b____|
//! |__freeze_c________|
//! |__frozen_________________| // <- the max of all freezes
//! ```
//!
//! Holds are designed to be infallibly slashed, meaning that any logic using a `Freeze`
//! must handle the possibility of the frozen amount being reduced, potentially to zero. A
//! permissionless function should be provided in order to allow bookkeeping to be updated in this
//! instance. E.g. some balance is frozen when it is used for voting, one could use held balance for
//! voting, but nothing prevents this frozen balance from being reduced if the overlapping hold is
//! slashed.
//!
//! Every Hold and Freeze is accompanied by a unique `Reason`, making it clear for each instance
//! what the originating pallet and purpose is. These reasons are amalgomated into a single enum
//! `RuntimeHoldReason` and `RuntimeFreezeReason` respectively, when the runtime is compiled.
//!
//! Note that `Hold` and `Freeze` reasons should remain in your runtime for as long as storage
//! could exist in your runtime with those reasons, otherwise your runtime state could become
//! undecodable.
//!
//! ### Should I use a Hold or Freeze?
//!
//! If you require a balance to be infaillibly slashed, then you should use Holds.
//!
//! If you require setting a minimum account balance amount, then you should use a Freezes. Note
//! Freezes do not carry the same guarantees as Holds. Although the account cannot voluntarily
//! reduce their balance below the largest freeze, if Holds on the account are slashed then the
//! balance could drop below the freeze amount.
//!
//! ## Sets of Tokens
//!
//! For managing sets of tokens, see the [`fungibles`](`frame_support::traits::fungibles`) trait
//! which is a wrapper around this trait but supporting multiple asset instances.
//!
//! [`frame_tokens`]: ../../../../polkadot_sdk_docs/reference_docs/frame_tokens/index.html
pub mod conformance_tests;
pub mod freeze;
@@ -16,6 +16,8 @@
// limitations under the License.
//! `Inspect` and `Mutate` traits for working with regular balances.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
use crate::{
ensure,
@@ -17,6 +17,8 @@
//! Types to combine some `fungible::*` and `fungibles::*` implementations into one union
//! `fungibles::*` implementation.
//!
//! See the [`crate::traits::fungible`] doc for more information about fungible traits.
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::traits::{
@@ -16,6 +16,8 @@
// limitations under the License.
//! Inspect and Mutate traits for Asset approvals
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use crate::dispatch::DispatchResult;
pub trait Inspect<AccountId>: super::Inspect<AccountId> {
@@ -15,6 +15,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Contains an interface for enumerating assets in existence or owned by a given account.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
/// Interface for enumerating assets in existence or owned by a given account.
pub trait Inspect<AccountId>: super::Inspect<AccountId> {
type AssetsIterator;
@@ -16,6 +16,8 @@
// limitations under the License.
//! The traits for putting freezes within a single fungible token class.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use crate::{ensure, traits::tokens::Fortitude};
use scale_info::TypeInfo;
@@ -16,6 +16,8 @@
// limitations under the License.
//! The traits for putting holds within a single fungible token class.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use crate::{
ensure,
@@ -17,6 +17,8 @@
//! The imbalance type and its associates, which handles keeps everything adding up properly with
//! unbalanced operations.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use super::*;
use crate::traits::{
@@ -16,6 +16,8 @@
// limitations under the License.
//! Traits for creating and destroying assets.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use sp_runtime::{DispatchError, DispatchResult};
@@ -16,6 +16,8 @@
// limitations under the License.
//! Inspect and Mutate traits for Asset metadata
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use crate::dispatch::DispatchResult;
use sp_std::vec::Vec;
@@ -15,7 +15,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! The traits for sets of fungible tokens and any associated types.
//! The traits for *sets* of [`fungible`](`frame_support::traits::fungible`) tokens and any
//! associated types.
//!
//! Individual tokens in the `fungibles` set may be used when a `fungible` trait is expected using
//! [`crate::traits::tokens::fungible::ItemOf`].
//!
//! Also see the [`frame_tokens`] reference docs for more information about the place of
//! `fungible` traits in Substrate.
//!
//! [`frame_tokens`]: ../../../../polkadot_sdk_docs/reference_docs/frame_tokens/index.html
pub mod approvals;
mod enumerable;
@@ -16,6 +16,8 @@
// limitations under the License.
//! `Inspect` and `Mutate` traits for working with regular balances.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use sp_std::marker::PhantomData;
@@ -16,6 +16,8 @@
// limitations under the License.
//! Inspect traits for Asset roles
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
pub trait Inspect<AccountId>: super::Inspect<AccountId> {
// Get owner for an AssetId.
@@ -16,6 +16,8 @@
// limitations under the License.
//! Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation.
//!
//! See the [`crate::traits::fungibles`] doc for more information about fungibles traits.
use frame_support::traits::{
tokens::{