diff --git a/Cargo.lock b/Cargo.lock index 413bd28abe037..81eb682a27d7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13390,11 +13390,14 @@ dependencies = [ "pallet-example-single-block-migrations", "pallet-examples", "pallet-multisig", + "pallet-nfts", + "pallet-preimage", "pallet-proxy", "pallet-referenda", "pallet-scheduler", "pallet-timestamp", "pallet-transaction-payment", + "pallet-uniques", "pallet-utility", "parity-scale-codec", "sc-cli", diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 434202ed69365..3b8f45d7756e9 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -66,6 +66,7 @@ pallet-aura = { path = "../../substrate/frame/aura", default-features = false } pallet-timestamp = { path = "../../substrate/frame/timestamp" } pallet-balances = { path = "../../substrate/frame/balances" } pallet-assets = { path = "../../substrate/frame/assets" } +pallet-preimage = { path = "../../substrate/frame/preimage" } pallet-transaction-payment = { path = "../../substrate/frame/transaction-payment" } pallet-utility = { path = "../../substrate/frame/utility" } pallet-multisig = { path = "../../substrate/frame/multisig" } @@ -73,6 +74,8 @@ pallet-proxy = { path = "../../substrate/frame/proxy" } pallet-authorship = { path = "../../substrate/frame/authorship" } pallet-collective = { path = "../../substrate/frame/collective" } pallet-democracy = { path = "../../substrate/frame/democracy" } +pallet-uniques = { path = "../../substrate/frame/uniques" } +pallet-nfts = { path = "../../substrate/frame/nfts" } pallet-scheduler = { path = "../../substrate/frame/scheduler" } # Primitives diff --git a/docs/sdk/src/reference_docs/frame_currency.rs b/docs/sdk/src/reference_docs/frame_currency.rs deleted file mode 100644 index 6987d51aec824..0000000000000 --- a/docs/sdk/src/reference_docs/frame_currency.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! FRAME Currency Abstractions and Traits -//! -//! Notes: -//! -//! - History, `Currency` trait. -//! - `Hold` and `Freeze` with diagram. -//! - `HoldReason` and `FreezeReason` -//! - This footgun: diff --git a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs index cca7f9feb3f40..be464bbbf8359 100644 --- a/docs/sdk/src/reference_docs/frame_pallet_coupling.rs +++ b/docs/sdk/src/reference_docs/frame_pallet_coupling.rs @@ -143,7 +143,7 @@ //! For example, all pallets in `polkadot-sdk` that needed to work with currencies could have been //! tightly coupled with [`pallet_balances`]. But, `polkadot-sdk` also provides [`pallet_assets`] //! (and more implementations by the community), therefore all pallets use traits to loosely couple -//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_currency`]. +//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_tokens`]. //! //! ## Further References //! diff --git a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs index cbbf611f9dc4a..f9a69b892a315 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_upgrades_and_migrations.rs @@ -131,7 +131,6 @@ //! //! TODO: Link to multi block migration example/s once PR is merged (). //! -//! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion //! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade //! [`StorageVersion`]: frame_support::traits::StorageVersion //! [`set_code`]: frame_system::Call::set_code diff --git a/docs/sdk/src/reference_docs/frame_tokens.rs b/docs/sdk/src/reference_docs/frame_tokens.rs new file mode 100644 index 0000000000000..c9d34e2091d89 --- /dev/null +++ b/docs/sdk/src/reference_docs/frame_tokens.rs @@ -0,0 +1,131 @@ +// This file is part of polkadot-sdk. +// +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # FRAME Tokens +//! +//! This reference doc serves as a high-level overview of the token-related logic in FRAME, and +//! how to properly apply it to your use case. +//! +//! On completion of reading this doc, you should have a good understanding of: +//! - The distinction between token traits and trait implementations in FRAME, and why this +//! distinction is helpful +//! - Token-related traits avaliable in FRAME +//! - Token-related trait implementations in FRAME +//! - How to choose the right trait or trait implementation for your use case +//! - Where to go next +//! +//! ## Getting Started +//! +//! The most ubiquitous way to add a token to a FRAME runtime is [`pallet_balances`]. Read +//! more about pallets [here](crate::polkadot_sdk::frame_runtime#pallets). +//! +//! You may then write custom pallets that interact with [`pallet_balances`]. The fastest way to +//! get started with that is by +//! [tightly coupling](crate::reference_docs::frame_pallet_coupling#tight-coupling-pallets) your +//! custom pallet to [`pallet_balances`]. +//! +//! However, to keep pallets flexible and modular, it is often prefered to +//! [loosely couple](crate::reference_docs::frame_pallet_coupling#loosely--coupling-pallets). +//! +//! To achieve loose coupling, +//! we separate token logic into traits and trait implementations. +//! +//! ## Traits and Trait Implementations +//! +//! Broadly speaking, token logic in FRAME can be divided into two categories: traits and +//! trait implementations. +//! +//! **Traits** define common interfaces that types of tokens should implement. For example, the +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) trait specifies an interface +//! for *inspecting* token state such as the total issuance of the token, the balance of individual +//! accounts, etc. +//! +//! **Trait implementations** are concrete implementations of these traits. For example, one of the +//! many traits [`pallet_balances`] implements is +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)*. It provides the concrete way +//! of inspecting the total issuance, balance of accounts, etc. There can be many implementations of +//! the same traits. +//! +//! The distinction between traits and trait implementations is helpful because it allows pallets +//! and other logic to be generic over their dependencies, avoiding tight coupling. +//! +//! To illustrate this with an example let's consider [`pallet_preimage`]. This pallet takes a +//! deposit in exchange for storing a preimage for later use. A naive implementation of the +//! pallet may use [`pallet_balances`] in a tightly coupled manner, directly calling methods +//! on the pallet to reserve and unreserve deposits. This approach works well, +//! until someone has a use case requiring that an asset from a different pallet such as +//! [`pallet_assets`] is used for the deposit. Rather than tightly couple [`pallet_preimage`] to +//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet a user +//! could possibly specify, [`pallet_preimage`] does not specify a concrete pallet as a dependency +//! but instead accepts any dependency which implements the +//! [`currency::ReservableCurrency`](`frame_support::traits::tokens::currency::ReservableCurrency`) +//! trait, namely via its [`Config::Currency`](`pallet_preimage::pallet::Config::Currency`) +//! associated type. This allows [`pallet_preimage`] to support any arbitrary pallet implementing +//! this trait, without needing any knowledge of what those pallets may be or requiring changes to +//! support new pallets which may be written in the future. +//! +//! Read more about coupling, and the benefits of loose coupling +//! [here](crate::reference_docs::frame_pallet_coupling). +//! +//! ##### *Rust Advanced Tip +//! +//! The knowledge that [`pallet_balances`] implements +//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge +//! that you have to know by heart or memorize. One can simply look at the list of the implementors +//! of any trait in the Rust Doc to find all implementors (e.g. +//! ), +//! or use the `rust-analyzer` `Implementations` action. +//! +//! ## Fungible Token Traits in FRAME +//! +//! The [`fungible`](`frame_support::traits::fungible`) crate contains the latest set of FRAME +//! fungible token traits, and is recommended to use for all new logic requiring a fungible token. +//! See the crate documentation for more info about these fungible traits. +//! +//! [`fungibles`](`frame_support::traits::fungibles`) provides very similar functionality to +//! [`fungible`](`frame_support::traits::fungible`), except it supports managing multiple tokens. +//! +//! You may notice the trait [`Currency`](`frame_support::traits::Currency`) with similar +//! functionality is also used in the codebase, however this trait is deprecated and existing logic +//! is in the process of being migrated to [`fungible`](`frame_support::traits::fungible`) ([tracking issue](https://github.com/paritytech/polkadot-sdk/issues/226)). +//! +//! ## Fungible Token Trait Implementations in FRAME +//! +//! [`pallet_balances`] implements [`fungible`](`frame_support::traits::fungible`), and is the most +//! commonly used fungible implementation in FRAME. Most of the time, it's used for managing the +//! native token of the blockchain network it's used in. +//! +//! [`pallet_assets`] implements [`fungibles`](`frame_support::traits::fungibles`), and is another +//! popular fungible token implementation. It supports the creation and management of multiple +//! assets in a single crate, making it a good choice when a network requires more assets in +//! addition to its native token. +//! +//! ## Non-Fungible Tokens in FRAME +//! +//! [`pallet_nfts`] is recommended to use for all NFT use cases in FRAME. +//! See the crate documentation for more info about this pallet. +//! +//! [`pallet_uniques`] is deprecated and should not be used. +//! +//! +//! # What Next? +//! +//! - If you are interested in implementing a single fungible token, continue reading the +//! [`fungible`](`frame_support::traits::fungible`) and [`pallet_balances`] docs. +//! - If you are interested in implementing a set of fungible tokens, continue reading the +//! [`fungibles`](`frame_support::traits::fungibles`) trait and [`pallet_assets`] docs. +//! - If you are interested in implementing an NFT, continue reading the [`pallet_nfts`] docs. diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index a0d8d05b44926..145df8844f26e 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -65,9 +65,6 @@ pub mod metadata; /// Learn about how frame-system handles `account-ids`, nonces, consumers and providers. pub mod frame_system_accounts; -/// Learn about the currency-related abstractions provided in FRAME. -pub mod frame_currency; - /// Advice for configuring your development environment for Substrate development. pub mod development_environment_advice; @@ -75,6 +72,9 @@ pub mod development_environment_advice; // TODO: @shawntabrizi @ggwpez https://github.com/paritytech/polkadot-sdk-docs/issues/50 pub mod frame_benchmarking_weight; +/// Learn about the token-related logic in FRAME and how to apply it to your use case. +pub mod frame_tokens; + /// Learn about chain specification file and the genesis state of the blockchain. // TODO: @michalkucharczyk https://github.com/paritytech/polkadot-sdk-docs/issues/51 pub mod chain_spec_genesis; diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index c5468e4237df1..e5fe2a3d1fd39 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -17,7 +17,16 @@ //! # Assets Pallet //! -//! A simple, secure module for dealing with fungible assets. +//! A simple, secure module for dealing with sets of assets implementing +//! [`fungible`](frame_support::traits::fungible) traits, via +//! [`fungibles`](frame_support::traits::fungibles) traits. +//! +//! The pallet makes heavy use of concepts such as Holds and Freezes from the +//! [`frame_support::traits::fungible`] traits, therefore you should read and understand those docs +//! as a prerequisite to understanding this pallet. +//! +//! See the [`frame_tokens`] reference docs for more information about the place of the +//! Assets pallet in FRAME. //! //! ## Overview //! @@ -133,6 +142,8 @@ //! //! * [`System`](../frame_system/index.html) //! * [`Support`](../frame_support/index.html) +//! +//! [`frame_tokens`]: ../polkadot_sdk_docs/reference_docs/frame_tokens/index.html // This recursion limit is needed because we have too many benchmarks and benchmarking will fail if // we add more without this limit. diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 80278752207de..685b12499ac0f 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -17,11 +17,15 @@ //! # Balances Pallet //! -//! The Balances pallet provides functionality for handling accounts and balances. +//! The Balances pallet provides functionality for handling accounts and balances for a single +//! token. //! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] +//! It makes heavy use of concepts such as Holds and Freezes from the +//! [`frame_support::traits::fungible`] traits, therefore you should read and understand those docs +//! as a prerequisite to understanding this pallet. +//! +//! Also see the [`frame_tokens`] reference docs for higher level information regarding the +//! place of this palet in FRAME. //! //! ## Overview //! @@ -38,42 +42,30 @@ //! //! ### Terminology //! -//! - **Existential Deposit:** The minimum balance required to create or keep an account open. This -//! prevents "dust accounts" from filling storage. When the free plus the reserved balance (i.e. -//! the total balance) fall below this, then the account is said to be dead; and 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 this -//! pallet or an erroneous raw mutation of storage. -//! -//! - **Total Issuance:** The total number of units in existence in a system. -//! //! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after -//! its total balance has become zero (or, strictly speaking, less than the Existential Deposit). -//! -//! - **Free Balance:** The portion of a balance that is not reserved. The free balance is the only -//! balance that matters for most operations. +//! its total balance has become less than the Existential Deposit. //! -//! - **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. -//! -//! - **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` trait 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.) +//! ### Implementations //! -//! - **Lock:** A freeze on a specified amount of an account's free balance until a specified block -//! number. Multiple locks always operate over the same funds, so they "overlay" rather than -//! "stack". +//! The Balances pallet provides implementations for the following [`fungible`] traits. If these +//! traits provide the functionality that you need, then you should avoid tight coupling with the +//! Balances pallet. //! -//! ### Implementations +//! - [`fungible::Inspect`] +//! - [`fungible::Mutate`] +//! - [`fungible::Unbalanced`] +//! - [`fungible::Balanced`] +//! - [`fungible::BalancedHold`] +//! - [`fungible::InspectHold`] +//! - [`fungible::MutateHold`] +//! - [`fungible::InspectFreeze`] +//! - [`fungible::MutateFreeze`] +//! - [`fungible::Imbalance`] //! -//! The Balances pallet provides implementations for the following traits. If these traits provide -//! the functionality that you need, then you can avoid coupling with the Balances pallet. +//! It also implements the following [`Currency`] related traits, however they are deprecated and +//! will eventually be removed. //! -//! - [`Currency`]: Functions for dealing with a -//! fungible assets system. +//! - [`Currency`]: Functions for dealing with a fungible assets system. //! - [`ReservableCurrency`] //! - [`NamedReservableCurrency`](frame_support::traits::NamedReservableCurrency): //! Functions for dealing with assets that can be reserved from an account. @@ -83,14 +75,6 @@ //! imbalances between total issuance in the system and account balances. Must be used when a //! function creates new funds (e.g. a reward) or destroys some funds (e.g. a system fee). //! -//! ## Interface -//! -//! ### Dispatchable Functions -//! -//! - `transfer_allow_death` - Transfer some liquid free balance to another account. -//! - `force_set_balance` - Set the balances of a given account. The origin of this call must be -//! root. -//! //! ## Usage //! //! The following examples show how to use the Balances pallet in your custom pallet. @@ -151,8 +135,11 @@ //! * Total issued balanced of all accounts should be less than `Config::Balance::max_value()`. //! * Existential Deposit is set to a value greater than zero. //! -//! Note, you may find the Balances pallet still functions with an ED of zero in some circumstances, -//! however this is not a configuration which is generally supported, nor will it be. +//! Note, you may find the Balances pallet still functions with an ED of zero when the +//! `insecure_zero_ed` cargo feature is enabled. However this is not a configuration which is +//! generally supported, nor will it be. +//! +//! [`frame_tokens`]: ../polkadot_sdk_docs/reference_docs/frame_tokens/index.html #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; @@ -308,10 +295,14 @@ pub mod pallet { /// The maximum number of locks that should exist on an account. /// Not strictly enforced, but used for weight estimation. + /// + /// Use of locks is deprecated in favour of freezes. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::constant] type MaxLocks: Get; /// The maximum number of named reserves that can exist on an account. + /// + /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::constant] type MaxReserves: Get; @@ -455,6 +446,8 @@ pub mod pallet { /// Any liquidity locks on some account balances. /// NOTE: Should only be accessed when setting, changing and freeing a lock. + /// + /// Use of locks is deprecated in favour of freezes. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::storage] #[pallet::getter(fn locks)] pub type Locks, I: 'static = ()> = StorageMap< @@ -466,6 +459,8 @@ pub mod pallet { >; /// Named reserves on some account balances. + /// + /// Use of reserves is deprecated in favour of holds. See `https://github.com/paritytech/substrate/pull/12951/` #[pallet::storage] #[pallet::getter(fn reserves)] pub type Reserves, I: 'static = ()> = StorageMap< diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 282e7f6447330..b3db4c98001d9 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -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}, diff --git a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs index 8b542ee4c6060..96efbc6ab89e1 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/freeze.rs @@ -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: super::Inspect { /// 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: super::Inspect { /// 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: Inspect { /// Prevent actions which would reduce the balance of the account of `who` below the given @@ -66,16 +69,16 @@ pub trait Mutate: Inspect { /// 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: Inspect { /// 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, diff --git a/substrate/frame/support/src/traits/tokens/fungible/hold.rs b/substrate/frame/support/src/traits/tokens/fungible/hold.rs index 6da652d2998df..28ece25c91d42 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/hold.rs @@ -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: /// /// 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 diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 0e25102197007..020dffe28c85b 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -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::{ diff --git a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs index 37749d396009d..5374cc52bab72 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -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::{ diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index ba4a2e5e21a2c..4a0cda2dbc7b7 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -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; diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 0157b08bd137b..4ed31dcf9fb1f 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -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, diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 33711d7a16cc6..575b771a61448 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -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::{ diff --git a/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs b/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs index 7a80279b01981..09e3d20756a2f 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/approvals.rs @@ -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: super::Inspect { diff --git a/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs b/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs index 08bb784a7dbf6..81dbb93b0b8d6 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/enumerable.rs @@ -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: super::Inspect { type AssetsIterator; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs index b07d20d6c41ce..244f700589945 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/freeze.rs @@ -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; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs index 1efd1594213c1..ef3fef7a300d9 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/hold.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/hold.rs @@ -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, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 54c1e900b6e36..bb0d83721a481 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -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::{ diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 0e195a52318b7..49f6c846ccdd5 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -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}; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs b/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs index ab310119e5846..ab722426dadf6 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/metadata.rs @@ -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; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 1db0706ba4fde..2122fdeaed3f2 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -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; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index 8cc97802da66e..b30e0ae3a2a36 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -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; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs index 5cd1228afbce7..4f95ad8368c2c 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs @@ -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: super::Inspect { // Get owner for an AssetId. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 9d2a783df2a4a..c8a1ec37e7818 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -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::{