diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 6d18410ac5485..09b68f457ec37 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -14,13 +14,158 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Balances: Handles setting and retrieval of free balance, -//! retrieving total balance, reserve and unreserve balance, -//! 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), -//! increasing total stake. +//! # Balances Module +//! +//! The balances module provides functionality for handling accounts and balances. To use the balances module, you need +//! to implement the [balances Trait](https://crates.parity.io/srml_balances/trait.Trait.html). Supported dispatchables +//! are documented in the [`Call` enum](https://crates.parity.io/srml_balances/enum.Call.html). +//! +//! ## Overview +//! +//! The balances module provides functions for: +//! +//! - Getting and setting free balances +//! - Retrieving total, reserved and unreserved balances +//! - Repatriating a reserved balance to a beneficiary account that exists +//! - Transferring a balance between accounts (when not reserved) +//! - Slashing an account balance +//! - Account creation and removal +//! - Lookup of an index to reclaim an account +//! - Managing total issuance +//! - Setting and managing locks +//! +//! ### Terminology +//! +//! - **Existential Deposit:** The minimum balance required to create or keep an account open. This prevents +//! "dust accounts" from filling storage. +//! - **Total Issuance:** The total amount of units in existence in a system. +//! - **Reaping an account:** The act of removing an account by resetting its nonce. Happens after its balance is set +//! to zero. +//! - **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. +//! - **Reserved Balance:** Reserved balance still belongs to the account holder, but is suspended. Reserved balance +//! can still be slashed, but only after all of 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. +//! - **Imbalance:** A condition when some funds were created or deducted without equal and opposite accounting. +//! Functions that result in an imbalance will return an object of the `Imbalance` trait that must be handled. +//! - **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". +//! - **Vesting:** Similar to a lock, this is another, but independent, liquidity restriction that reduces linearly +//! over time. +//! +//! ### Implementations +//! +//! The balances module provides implementations for the following traits. If these traits provide the functionality +//! that you need, then you can avoid coupling with the balances module. +//! +//! - [`Currency`](https://crates.parity.io/srml_support/traits/trait.Currency.html): Functions for dealing with a +//! fungible assets system. +//! - [`LockableCurrency`](https://crates.parity.io/srml_support/traits/trait.LockableCurrency.html): Functions for +//! dealing with accounts that allow liquidity restrictions. +//! - [`Imbalance`](https://crates.parity.io/srml_support/traits/trait.Imbalance.html): Functions for handling +//! 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). +//! - [`MakePayent`](https://crates.parity.io/srml_support/traits/trait.MakePayment.html): Simple trait designed +//! for hooking into a transaction payment. +//! - [`IsDeadAccount`](https://crates.parity.io/srml_system/trait.IsDeadAccount.html): Determiner to say whether a +//! given account is unused. +//! +//! Example of using the `Currency` trait from the treasury module: +//! +//! ```rust,ignore +//! pub trait Trait: system::Trait { +//! /// The staking balance. +//! type Currency: Currency; +//! } +//! ``` +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! The `Call` enum is documented [here](https://crates.parity.io/srml_balances/enum.Call.html). +//! +//! - `transfer` - Transfer some liquid free balance to another account. +//! - `set_balance` - Set the balances of a given account. The origin of this call must be root. +//! +//! ### Public Functions +//! +//! See the [module](https://crates.parity.io/srml_balances/struct.Module.html) for details on publicly available +//! functions. +//! +//! ## Usage +//! +//! The following examples show how to use the balances module in your custom module. +//! +//! ### Import and Balance Transfer +//! +//! Import the `balances` module and derive your module configuration trait with the balances trait. You can now call +//! functions from the module. +//! +//! ```rust,ignore +//! use support::{decl_module, dispatch::Result}; +//! use system::ensure_signed; +//! +//! pub trait Trait: balances::Trait {} +//! +//! decl_module! { +//! pub struct Module for enum Call where origin: T::Origin { +//! fn transfer_proxy(origin, to: T::AccountId, value: T::Balance) -> Result { +//! let sender = ensure_signed(origin)?; +//! >::make_transfer(&sender, &to, value)?; +//! +//! Ok(()) +//! } +//! } +//! } +//! ``` +//! +//! ### Real Use Example +//! +//! Use in the `contract` module (gas.rs): +//! +//! ```rust,ignore +//! pub fn refund_unused_gas( +//! transactor: &T::AccountId, +//! gas_meter: GasMeter, +//! imbalance: balances::NegativeImbalance, +//! ) { +//! let gas_spent = gas_meter.spent(); +//! let gas_left = gas_meter.gas_left(); +//! +//! // Increase total spent gas. +//! >::mutate(|block_gas_spent| *block_gas_spent += gas_spent); +//! +//! let refund = >::as_(gas_left) * gas_meter.gas_price; +//! // Refund gas using balances module +//! let refund_imbalance = >::deposit_creating(transactor, refund); +//! // Handle imbalance +//! if let Ok(imbalance) = imbalance.offset(refund_imbalance) { +//! T::GasPayment::on_unbalanced(imbalance); +//! } +//! } +//! ``` +//! +//! ## Genesis config +//! +//! The following storage items depend on the genesis config: +//! +//! - `TotalIssuance` +//! - `ExistentialDeposit` +//! - `TransferFee` +//! - `CreationFee` +//! - `Vesting` +//! - `FreeBalance` +//! - `TransactionBaseFee` +//! - `TransactionByteFee` +//! +//! ## Related Modules +//! +//! The balances module depends on the [`system`](https://crates.parity.io/srml_system/index.html) and +//! [`srml_support`](https://crates.parity.io/srml_support/index.html) modules as well as Substrate Core +//! libraries and the Rust standard library. #![cfg_attr(not(feature = "std"), no_std)] @@ -47,7 +192,7 @@ pub trait Subtrait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As + As + MaybeSerializeDebug; - /// A function which is invoked when the free-balance has fallen below the existential deposit and + /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. /// /// Gives a chance to clean up resources associated with the given account. @@ -61,7 +206,7 @@ pub trait Trait: system::Trait { /// The balance of an account. type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As + As + MaybeSerializeDebug; - /// A function which is invoked when the free-balance has fallen below the existential deposit and + /// A function that is invoked when the free-balance has fallen below the existential deposit and /// has been reduced to zero. /// /// Gives a chance to clean up resources associated with the given account. @@ -136,15 +281,15 @@ pub struct BalanceLock { decl_storage! { trait Store for Module, I: Instance=DefaultInstance> as Balances { - /// The total amount of stake on the system. + /// The total units issued in the system. pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig| { 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; /// The fee to be paid for making a transaction; the base. pub TransactionBaseFee get(transaction_base_fee) config(): T::Balance; @@ -175,11 +320,11 @@ 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 + /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback + /// is invoked, giving a chance to external modules to clean up data associated with /// the deleted account. /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets @@ -190,14 +335,13 @@ decl_storage! { /// slashed, but gets slashed last of all. /// /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. (This is different - /// and wholly unrelated to the `Bondage` system used in the staking module.) + /// that are still 'owned' by the account holder, but which are suspendable. /// /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' /// 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. @@ -214,7 +358,14 @@ decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { fn deposit_event() = default; - /// Transfer some liquid free balance to another staker. + /// Transfer some liquid free balance to another account. + /// + /// `transfer` will set the `FreeBalance` of the sender and receiver. + /// It will decrease the total issuance of the system by the `TransferFee`. + /// If the sender's account is below the existential deposit as a result + /// of the transfer, the account will be reaped. + /// + /// The dispatch origin for this call must be `Signed` by the transactor. pub fn transfer( origin, dest: ::Source, @@ -226,6 +377,13 @@ decl_module! { } /// Set the balances of a given account. + /// + /// 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 issuance of the system (`TotalIssuance`) + /// and reset the account nonce (`system::AccountNonce`). + /// + /// The dispatch origin for this call is `root`. fn set_balance( who: ::Source, #[compact] free: T::Balance, @@ -238,7 +396,6 @@ decl_module! { } } -// For funding methods, see Currency trait impl, I: Instance> Module { // PUBLIC IMMUTABLES @@ -254,10 +411,11 @@ impl, I: Instance> Module { // PRIVATE MUTABLES - /// 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, annulling 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. /// /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. @@ -272,14 +430,12 @@ impl, I: Instance> Module { } } - /// Set the free balance of an account to some new value. Will enforce ExistentialDeposit - /// law annulling 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. - /// /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// the caller will do this. fn set_free_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome { @@ -684,8 +840,6 @@ where // 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 - // value of which makes even the `free_balance` unspendable. let outcome = if balance < >::existential_deposit() { Self::set_free_balance(who, balance); UpdateBalanceOutcome::AccountKilled diff --git a/srml/contract/src/lib.rs b/srml/contract/src/lib.rs index a3f6faf41c963..2c2d2106a614b 100644 --- a/srml/contract/src/lib.rs +++ b/srml/contract/src/lib.rs @@ -366,7 +366,7 @@ decl_event! { decl_storage! { trait Store for Module as Contract { - /// The fee required to create a contract. At least as big as staking's ReclaimRebate. + /// The fee required to create a contract. ContractFee get(contract_fee) config(): T::Balance = T::Balance::sa(21); /// The fee charged for a call into a contract. CallBaseFee get(call_base_fee) config(): T::Gas = T::Gas::sa(135); diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 4a676c797a276..7511c8550c4a9 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -57,7 +57,7 @@ impl OnDilution for () { pub enum UpdateBalanceOutcome { /// Account balance was simply updated. Updated, - /// The update has led to killing of the account. + /// The update led to killing the account. AccountKilled, } @@ -245,7 +245,7 @@ pub trait Currency { /// The combined balance of `who`. fn total_balance(who: &AccountId) -> Self::Balance; - /// Some result as `slash(who, value)` (but without the side-effects) assuming there are no + /// Same result as `slash(who, value)` (but without the side-effects) assuming there are no /// balance changes in the meantime and only the reserved balance is not taken into account. fn can_slash(who: &AccountId, value: Self::Balance) -> bool; @@ -253,20 +253,20 @@ pub trait Currency { /// are no balance changes in the meantime. fn can_reserve(who: &AccountId, value: Self::Balance) -> bool; - /// The total amount of stake on the system. + /// The total amount of issuance in the system. fn total_issuance() -> Self::Balance; - /// The minimum balance any single account may have. This is equivalent to Balances module's - /// Existential Deposit. + /// The minimum balance any single account may have. This is equivalent to the `Balances` module's + /// `ExistentialDeposit`. fn minimum_balance() -> Self::Balance; /// 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 + /// deleted: specifically `FreeBalance`. Further, the `OnFreeBalanceZero` callback + /// is invoked, giving a chance to external modules to clean up data associated with /// the deleted account. /// /// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets @@ -277,8 +277,7 @@ pub trait Currency { /// slashed, but gets slashed last of all. /// /// This balance is a 'reserve' balance that other subsystems use in order to set aside tokens - /// that are still 'owned' by the account holder, but which are suspendable. (This is different - /// and wholly unrelated to the `Bondage` system used in the staking module.) + /// that are still 'owned' by the account holder, but which are suspendable. /// /// When this balance falls below the value of `ExistentialDeposit`, then this 'reserve account' /// is deleted: specifically, `ReservedBalance`. @@ -298,7 +297,7 @@ pub trait Currency { new_balance: Self::Balance, ) -> result::Result<(), &'static str>; - // PUBLIC MUTABLES (DANGEROUS) + // PUBLIC MUTABLES (DANGEROUS) /// Transfer some liquid free balance to another staker. /// @@ -333,7 +332,7 @@ pub trait Currency { /// Removes some free balance from `who` account for `reason` if possible. If `liveness` is `KeepAlive`, /// then no less than `ExistentialDeposit` must be left remaining. /// - /// This checks any locks, vesting and liquidity requirements. If the removal is not possible, then it + /// This checks any locks, vesting, and liquidity requirements. If the removal is not possible, then it /// returns `Err`. fn withdraw( who: &AccountId, @@ -342,7 +341,7 @@ pub trait Currency { liveness: ExistenceRequirement, ) -> result::Result; - /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created + /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created. /// /// Infallible. fn deposit_creating( @@ -363,24 +362,28 @@ pub trait Currency { UpdateBalanceOutcome, ); - /// Moves `value` from balance to reserved balance. + /// Moves `value` from balance to reserved balance. /// /// If the free balance is lower than `value`, then no funds will be moved and an `Err` will - /// be returned to notify of this. This is different behaviour to `unreserve`. + /// be returned to notify of this. This is different behavior than `unreserve`. fn reserve(who: &AccountId, value: Self::Balance) -> result::Result<(), &'static str>; - /// Moves up to `value` from reserved balance to balance. This function cannot fail. + /// Moves up to `value` from reserved balance to free balance. This function cannot fail. /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then non-zero will be returned. + /// As much funds up to `value` will be moved as possible. If the reserve balance of `who` + /// is less than `value`, then the remaining amount will be returned. + /// + /// # NOTES /// - /// NOTE: This is different to `reserve`. + /// - This is different from `reserve`. + /// - If the remaining reserved balance is less than `ExistentialDeposit`, it will + /// invoke `on_reserved_too_low` and could reap the account. fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance; /// Deducts up to `value` from reserved balance of `who`. This function cannot fail. /// - /// As much funds up to `value` will be deducted as possible. If this is less than `value`, - /// then non-zero second item will be returned. + /// As much funds up to `value` will be deducted as possible. If the reserve balance of `who` + /// is less than `value`, then a non-zero second item will be returned. fn slash_reserved( who: &AccountId, value: Self::Balance @@ -408,7 +411,12 @@ pub trait LockableCurrency: Currency { /// The quantity used to denote time; usually just a `BlockNumber`. type Moment; - /// Introduce a new lock or change an existing one. + /// Create a new balance lock on account `who`. + /// + /// If the new lock is valid (i.e. not already expired), it will push the struct to + /// the `Locks` vec in storage. Note that you can lock more funds than a user has. + /// + /// If the lock `id` already exists, this will update it. fn set_lock( id: LockIdentifier, who: &AccountId, @@ -417,8 +425,15 @@ pub trait LockableCurrency: Currency { reasons: WithdrawReasons, ); - /// Change any existing lock so that it becomes strictly less liquid in all - /// respects to the given parameters. + /// Changes a balance lock (selected by `id`) so that it becomes less liquid in all + /// parameters or creates a new one if it does not exist. + /// + /// Calling `extend_lock` on an existing lock `id` differs from `set_lock` in that it + /// applies the most severe constraints of the two, while `set_lock` replaces the lock + /// with the new parameters. As in, `extend_lock` will set: + /// - maximum `amount` + /// - farthest duration (`until`) + /// - bitwise mask of all `reasons` fn extend_lock( id: LockIdentifier, who: &AccountId, @@ -452,3 +467,4 @@ bitmask! { Fee = 0b00001000, } } +