This repository was archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Documentation for balances module #1943
Merged
Merged
Changes from 10 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
74bcfcb
comment updates
joepetrowski a544d4a
Merge branch 'master' into joe-balances-docs
joepetrowski 1cc5721
added rustdoc and readme
joepetrowski e4a3bf7
clarified LockableCurrency trait
joepetrowski 3e4b5e4
Currency trait rustdocs
joepetrowski 077cde2
fixed typo
joepetrowski dd16fd6
fixed suggestions round 1
joepetrowski ceeb172
UpdateBalanceOutcome docs (open for discussion)
joepetrowski 05894ab
rm description of enum, consolidation, rm ReclaimRebate
joepetrowski a654735
type clarification, examples overhaul, adoc formatting
joepetrowski 02110b2
adoc to md
joepetrowski 53680af
format change for rustdoc
joepetrowski f1b62a4
update links and fix typos
joepetrowski 499c239
typos and links
joepetrowski cf750f8
Merge remote-tracking branch 'origin/master' into joe-balances-docs
joepetrowski 2cf4009
updates according to comments
joepetrowski d863ff6
new example
joepetrowski 5e28748
small clarifications
joepetrowski c8ec45a
trait implementation section
joepetrowski 36b1689
missing ```
joepetrowski 3c157e4
small changes, ready for review
joepetrowski a0ef9b7
line width update
joepetrowski 2d28117
Merge branch 'master' into joe-balances-docs
joepetrowski df3ced9
Merge branch 'master' into joe-balances-docs
joepetrowski e42f6b6
small tweaks
joepetrowski e000871
Update srml/balances/src/lib.rs
gui1117 faccdbf
Update srml/balances/src/lib.rs
gui1117 513b377
Update srml/balances/src/lib.rs
gui1117 ce29349
Update srml/balances/src/lib.rs
gui1117 fa9f215
Update lib.rs
joepetrowski 28a1d33
address review by thiolliere
joepetrowski aa43b56
remove common warning
joepetrowski 191ecc0
Merge remote-tracking branch 'origin/master' into joe-balances-docs
gavofyork 665fa6b
Update docs
gavofyork 5f391ae
updated srml example
joepetrowski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| = Balances Module | ||
|
|
||
| The balances module provides the functionality for handling balances. | ||
|
|
||
| == Overview | ||
|
|
||
| The balances module provides functions for: | ||
|
|
||
| - Getting and setting free balance | ||
| - Retrieving total, reserved, and unreserved balances | ||
| - Repatriating a reserved balance to a beneficiary account that exists | ||
| - Transfering a balance between accounts (when not reserved) | ||
| - Slashing an account balance | ||
| - Account removal | ||
| - Lookup of an index to reclaim an account | ||
| - Increasing or decreasing total stake | ||
| - Setting and removing locks on chains that implement `LockableCurrency` | ||
|
|
||
| The dispatchable function `transfer` ensures that the sender has signed the transaction. When using the publicly exposed functions in the implementation, you will need to do these checks in your runtime, as many functions will affect storage without ensuring, for example, that the sender is the signer. | ||
|
|
||
| == Public Interface | ||
|
|
||
| === Types | ||
|
|
||
| - Balance | ||
| - OnFreeBalanceZero | ||
| - OnNewAccount | ||
| - Event | ||
|
|
||
| These are link:https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types[associated types] and must be implemented in your `runtime/src/lib.rs`. For example: | ||
|
|
||
| ```rust | ||
| impl balances::Trait for Runtime { | ||
| /// The type for recording an account's balance. | ||
| type Balance = u128; | ||
| /// What to do if an account's free balance gets zeroed. | ||
| type OnFreeBalanceZero = (); | ||
| /// What to do if a new account is created. | ||
| type OnNewAccount = Indices; | ||
| /// The uniquitous event type. | ||
| type Event = Event; | ||
| } | ||
| ``` | ||
|
|
||
| === Dispatchable Functions | ||
|
|
||
| // TODO: Add link to rust docs (https://github.com/paritytech/substrate-developer-hub/issues/24) | ||
| - `transfer` - Transfer some liquid free balance to another staker. | ||
| - `set_balance` - Set the balances of a given account. Only dispatchable by a user with root priviledges. | ||
|
|
||
| == Usage | ||
|
|
||
| The following example shows how to use the balances module in your custom module. | ||
|
|
||
| === Importing into your runtime | ||
|
|
||
| Import the `balances` module and derive your module configuration trait with the balances trait. | ||
|
|
||
| Include in your `runtime/Cargo.toml` | ||
|
|
||
| ```rust | ||
| [dependencies.balances] | ||
| default_features = false | ||
| git = 'https://github.com/paritytech/substrate.git' | ||
| package = 'srml-balances' | ||
| rev = '82744fbb6f4d677f2edfe9d88737c237622c97a4' | ||
| ``` | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Include in your `runtime/src/lib.rs` | ||
|
|
||
| ```rust | ||
| // Import | ||
| pub use balances::Call as BalancesCall; | ||
|
|
||
| // Implement | ||
| impl balances::Trait for Runtime { | ||
| /// The type for recording an account's balance. | ||
| type Balance = u128; | ||
| /// What to do if an account's free balance gets zeroed. | ||
| type OnFreeBalanceZero = (); | ||
| /// What to do if a new account is created. | ||
| type OnNewAccount = Indices; | ||
| /// The ubiquitous event type. | ||
| type Event = Event; | ||
| } | ||
|
|
||
| // Include in your `construct_runtime` | ||
| construct_runtime!( | ||
| pub enum Runtime with Log(InternalLog: DigestItem<Hash, Ed25519AuthorityId>) where | ||
| Block = Block, | ||
| NodeBlock = opaque::Block, | ||
| UncheckedExtrinsic = UncheckedExtrinsic | ||
| { | ||
| // snip | ||
| Indices: indices, | ||
| Balances: balances, | ||
| Sudo: sudo, | ||
| // snip | ||
| } | ||
| ); | ||
| ``` | ||
|
|
||
| Derive your module configuration trait in your `runtime/src/<your-node-name>.rs` | ||
|
|
||
| ```rust | ||
| pub trait Trait: balances::Trait { | ||
| type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>; | ||
| } | ||
| ``` | ||
|
|
||
| ==== Example of getters | ||
|
|
||
| You now have access to the functions in `balances`. In your module, call the getters: | ||
|
|
||
| ```rust | ||
| // Get existential deposit | ||
| let ed = Balances::existential_deposit(); | ||
|
|
||
| // Get transfer fee for the network | ||
| let tf = Balances::transfer_fee(); | ||
| ``` | ||
|
|
||
| ==== Real Use Example | ||
|
|
||
| Use a balance transfer to buy a link:https://github.com/shawntabrizi/substrate-collectables-workshop/blob/master/3/assets/3.5-finished-code.rs#L105[SubstrateKitty]: | ||
|
|
||
| ```rust | ||
| fn buy_kitty(origin, kitty_id: T::Hash, max_price: T::Balance) -> Result { | ||
| let sender = ensure_signed(origin)?; | ||
|
|
||
| ensure!(<Kitties<T>>::exists(kitty_id), "This kitty does not exist"); | ||
|
|
||
| let owner = Self::owner_of(kitty_id).ok_or("No owner for this kitty")?; | ||
| ensure!(owner != sender, "You can't buy your own kitty"); | ||
|
|
||
| let mut kitty = Self::kitty(kitty_id); | ||
|
|
||
| let kitty_price = kitty.price; | ||
| ensure!(!kitty_price.is_zero(), "The kitty you want to buy is not for sale"); | ||
| ensure!(kitty_price <= max_price, "The kitty you want to buy costs more than your max price"); | ||
|
|
||
| // Make a balance transfer | ||
| <balances::Module<T>>::make_transfer(&sender, &owner, kitty_price)?; | ||
|
|
||
| Self::_transfer_from(owner.clone(), sender.clone(), kitty_id)?; | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| kitty.price = <T::Balance as As<u64>>::sa(0); | ||
| <Kitties<T>>::insert(kitty_id, kitty); | ||
|
|
||
| Self::deposit_event(RawEvent::Bought(sender, owner, kitty_id, kitty_price)); | ||
|
|
||
| Ok(()) | ||
| } | ||
| ``` | ||
|
|
||
| == Dependencies | ||
|
|
||
| The balances module depends on the `system` and `srml_support` modules as well as Substrate Core libraries and the Rust standard library. | ||
|
|
||
| === Genesis config | ||
|
|
||
| Configuration is in `<your-node-name>/src/chain_spec.rs`. The following storage items are configurable: | ||
|
|
||
| - `TotalIssuance` | ||
| - `ExistentialDeposit` | ||
| - `TransferFee` | ||
| - `CreationFee` | ||
| - `Vesting` | ||
| - `FreeBalance` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,12 +15,15 @@ | |
| // along with Substrate. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| //! Balances: Handles setting and retrieval of free balance, | ||
| //! retrieving total balance, reserve and unreserve balance, | ||
| //! retrieving total, reserved, and unreserved balances, | ||
| //! repatriating a reserved balance to a beneficiary account that exists, | ||
| //! transfering a balance between accounts (when not reserved), | ||
| //! slashing an account balance, account removal, rewards, | ||
| //! lookup of an index to reclaim an account (when not balance not reserved), | ||
| //! lookup of an index to reclaim an account (when balance not reserved), | ||
| //! increasing total stake. | ||
| //! | ||
| //! Implements functions for `Currency`, `LockableCurrency`, `TransferAsset`, | ||
| //! and `IsDeadAccount` traits. | ||
|
|
||
| #![cfg_attr(not(feature = "std"), no_std)] | ||
|
|
||
|
|
@@ -108,15 +111,15 @@ pub struct BalanceLock<Balance, BlockNumber> { | |
|
|
||
| decl_storage! { | ||
| trait Store for Module<T: Trait> as Balances { | ||
| /// The total amount of stake on the system. | ||
| /// The total amount of stake in the system. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig<T>| { | ||
| config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n) | ||
| }): T::Balance; | ||
| /// The minimum amount allowed to keep an account open. | ||
| /// The minimum amount required to keep an account open. | ||
| pub ExistentialDeposit get(existential_deposit) config(): T::Balance; | ||
| /// The fee required to make a transfer. | ||
| pub TransferFee get(transfer_fee) config(): T::Balance; | ||
| /// The fee required to create an account. At least as big as ReclaimRebate. | ||
| /// The fee required to create an account. | ||
| pub CreationFee get(creation_fee) config(): T::Balance; | ||
|
|
||
| /// Information regarding the vesting of a given account. | ||
|
|
@@ -143,15 +146,18 @@ decl_storage! { | |
|
|
||
| /// The 'free' balance of a given account. | ||
| /// | ||
| /// This is the only balance that matters in terms of most operations on tokens. It is | ||
| /// alone used to determine the balance when in the contract execution environment. When this | ||
| /// This is the only balance that matters in terms of most operations on tokens. It | ||
| /// alone is used to determine the balance when in the contract execution environment. When this | ||
| /// balance falls below the value of `ExistentialDeposit`, then the 'current account' is | ||
| /// deleted: specifically `FreeBalance`. Furthermore, `OnFreeBalanceZero` callback | ||
| /// is invoked, giving a chance to external modules to cleanup data associated with | ||
| /// is invoked, giving a chance to external modules to clean up data associated with | ||
| /// the deleted account. | ||
| /// | ||
| /// This is orthogonal to the `Bondage` value that an account has, a high value of which | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// makes even the `free_balance` unspendable. | ||
| /// | ||
| /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets | ||
| /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. | ||
| /// collapsed to zero if it ever becomes less than `ExistentialDeposit`.) | ||
| pub FreeBalance get(free_balance) build(|config: &GenesisConfig<T>| config.balances.clone()): map T::AccountId => T::Balance; | ||
|
|
||
| /// The amount of the balance of a given account that is externally reserved; this can still get | ||
|
|
@@ -165,7 +171,7 @@ decl_storage! { | |
| /// is deleted: specifically, `ReservedBalance`. | ||
| /// | ||
| /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets | ||
| /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. | ||
| /// collapsed to zero if it ever becomes less than `ExistentialDeposit`.) | ||
| pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; | ||
|
|
||
| /// Any liquidity locks on some account balances. | ||
|
|
@@ -182,6 +188,10 @@ decl_module! { | |
| fn deposit_event<T>() = default; | ||
|
|
||
| /// Transfer some liquid free balance to another staker. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// `transfer` will set the `FreeBalance` of the sender and receiver. | ||
| /// It will decrease the total stake of the system by the `TransferFee`. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// If the sender's account is below the existential deposit as a result | ||
| /// of the transfer, the account will be reaped. | ||
| pub fn transfer( | ||
| origin, | ||
| dest: <T::Lookup as StaticLookup>::Source, | ||
|
|
@@ -192,7 +202,11 @@ decl_module! { | |
| Self::make_transfer(&transactor, &dest, value)?; | ||
| } | ||
|
|
||
| /// Set the balances of a given account. | ||
| /// Set the balances of a given account. Only dispatchable by root. | ||
| /// This will alter `FreeBalance` and `ReservedBalance` in storage. | ||
| /// If the new free or reserved balance is below the existential deposit, | ||
| /// it will also decrease the total stake of the system (`TotalIssuance`) | ||
| /// and reset the account nonce (`system::AccountNonce`). | ||
joepetrowski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| fn set_balance( | ||
| who: <T::Lookup as StaticLookup>::Source, | ||
| #[compact] free: T::Balance, | ||
|
|
@@ -205,7 +219,7 @@ decl_module! { | |
| } | ||
| } | ||
|
|
||
| // For funding methods, see Currency trait | ||
| // For funding methods, see `Currency` trait | ||
| impl<T: Trait> Module<T> { | ||
|
|
||
| /// Get the amount that is currently being vested and cannot be transfered out of this account. | ||
|
|
@@ -217,10 +231,11 @@ impl<T: Trait> Module<T> { | |
| } | ||
| } | ||
|
|
||
| /// Set the free balance of an account to some new value. | ||
| /// Set the reserved balance of an account to some new value. Will enforce `ExistentialDeposit` | ||
| /// law, annulling the account as needed. | ||
| /// | ||
| /// Will enforce ExistentialDeposit law, anulling the account as needed. | ||
| /// In that case it will return `AccountKilled`. | ||
| /// Doesn't do any preparatory work for creating a new account, so should only be used when it | ||
| /// is known that the account already exists. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better to have a standardized preconditions documentation section, many method here have preconditions that have to be meet in order to ensure consistency. |
||
| pub fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { | ||
| if balance < Self::existential_deposit() { | ||
| <ReservedBalance<T>>::insert(who, balance); | ||
|
|
@@ -232,15 +247,13 @@ impl<T: Trait> Module<T> { | |
| } | ||
| } | ||
|
|
||
| /// Set the free balance of an account to some new value. Will enforce ExistentialDeposit | ||
| /// law anulling the account as needed. | ||
| /// Set the free balance of an account to some new value. Will enforce `ExistentialDeposit` | ||
| /// law, annulling the account as needed. | ||
| /// | ||
| /// Doesn't do any preparatory work for creating a new account, so should only be used when it | ||
| /// is known that the account already exists. | ||
| /// | ||
| /// Returns if the account was successfully updated or update has led to killing of the account. | ||
| pub fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { | ||
| // Commented out for no - but consider it instructive. | ||
| // Commented out for now - but consider it instructive. | ||
| // assert!(!Self::total_balance(who).is_zero()); | ||
| if balance < Self::existential_deposit() { | ||
| <FreeBalance<T>>::insert(who, balance); | ||
|
|
@@ -252,25 +265,16 @@ impl<T: Trait> Module<T> { | |
| } | ||
| } | ||
|
|
||
| /// Set the free balance on an account to some new value. | ||
| /// Set the free balance on an account to some new value. Will enforce `ExistentialDeposit` | ||
| /// law, annulling the account as needed. | ||
| /// | ||
| /// Same as [`set_free_balance`], but will create a new account. | ||
| /// Same as `set_free_balance`, but will create a new account. | ||
| /// | ||
| /// Returns if the account was successfully updated or update has led to killing of the account. | ||
| /// #NOTES | ||
| /// | ||
| /// [`set_free_balance`]: #method.set_free_balance | ||
| /// See documentation on `FreeBalance` and `ReservedBalance` storage items for their differences | ||
| pub fn set_free_balance_creating(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { | ||
| let ed = <Module<T>>::existential_deposit(); | ||
| // If the balance is too low, then the account is reaped. | ||
| // NOTE: There are two balances for every account: `reserved_balance` and | ||
| // `free_balance`. This contract subsystem only cares about the latter: whenever | ||
| // the term "balance" is used *here* it should be assumed to mean "free balance" | ||
| // in the rest of the module. | ||
| // Free balance can never be less than ED. If that happens, it gets reduced to zero | ||
| // and the account information relevant to this subsystem is deleted (i.e. the | ||
| // account is reaped). | ||
| // NOTE: This is orthogonal to the `Bondage` value that an account has, a high | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // value of which makes even the `free_balance` unspendable. | ||
| if balance < ed { | ||
| Self::set_free_balance(who, balance); | ||
| UpdateBalanceOutcome::AccountKilled | ||
|
|
@@ -284,7 +288,14 @@ impl<T: Trait> Module<T> { | |
| } | ||
| } | ||
|
|
||
| /// Transfer some liquid free balance to another staker. | ||
| /// Transfer some liquid free balance from one account to another. | ||
| /// | ||
| /// Enforces `ExistentialDeposit` law, reaping the sender's account if its balance is | ||
| /// too low as a result of the transfer. | ||
| /// | ||
| /// #NOTES | ||
| /// | ||
| /// Will create a new account for the destination if the account does not exist. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub fn make_transfer(transactor: &T::AccountId, dest: &T::AccountId, value: T::Balance) -> Result { | ||
| let from_balance = Self::free_balance(transactor); | ||
| let to_balance = Self::free_balance(dest); | ||
|
|
@@ -327,6 +338,7 @@ impl<T: Trait> Module<T> { | |
| Self::deposit_event(RawEvent::NewAccount(who.clone(), balance.clone())); | ||
| } | ||
|
|
||
| /// Remove an account whose balance is below the existential deposit. | ||
| fn reap_account(who: &T::AccountId) { | ||
| <system::AccountNonce<T>>::remove(who); | ||
| Self::deposit_event(RawEvent::ReapedAccount(who.clone())); | ||
|
|
@@ -355,13 +367,14 @@ impl<T: Trait> Module<T> { | |
| } | ||
| } | ||
|
|
||
| /// Increase TotalIssuance by Value. | ||
| /// Increase stake by `value`. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub fn increase_total_stake_by(value: T::Balance) { | ||
| if let Some(v) = <Module<T>>::total_issuance().checked_add(&value) { | ||
| <TotalIssuance<T>>::put(v); | ||
| } | ||
| } | ||
| /// Decrease TotalIssuance by Value. | ||
|
|
||
| /// Decrease stake by `value`. | ||
joepetrowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub fn decrease_total_stake_by(value: T::Balance) { | ||
| if let Some(v) = <Module<T>>::total_issuance().checked_sub(&value) { | ||
| <TotalIssuance<T>>::put(v); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.