referrerpolicy=no-referrer-when-downgrade

pallet_staking_async/
asset.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking
19//! asset.
20
21use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf};
22use frame_support::traits::{
23	fungible::{
24		hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate},
25		Balanced, Inspect as FunInspect,
26	},
27	tokens::{Fortitude, Precision, Preservation},
28};
29use sp_runtime::{DispatchResult, Saturating};
30
31/// Existential deposit for the chain.
32pub fn existential_deposit<T: Config>() -> BalanceOf<T> {
33	T::Currency::minimum_balance()
34}
35
36/// Total issuance of the chain.
37pub fn total_issuance<T: Config>() -> BalanceOf<T> {
38	T::Currency::total_issuance()
39}
40
41/// Total balance of `who`. Includes both free and staked.
42pub fn total_balance<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
43	T::Currency::total_balance(who)
44}
45
46/// Stakeable balance of `who`.
47///
48/// This includes balance free to stake along with any balance that is already staked.
49pub fn stakeable_balance<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
50	free_to_stake::<T>(who).saturating_add(staked::<T>(who))
51}
52
53/// Balance of `who` that is currently at stake.
54///
55/// The staked amount is on hold and cannot be transferred out of `who`s account.
56pub fn staked<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
57	T::Currency::balance_on_hold(&HoldReason::Staking.into(), who)
58}
59
60/// Balance of who that can be staked additionally.
61///
62/// Does not include the current stake.
63pub fn free_to_stake<T: Config>(who: &T::AccountId) -> BalanceOf<T> {
64	// since we want to be able to use frozen funds for staking, we force the reduction.
65	T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Force)
66}
67
68/// Update `amount` at stake for `who`.
69///
70/// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the
71/// difference is unlocked.
72pub fn update_stake<T: Config>(who: &T::AccountId, amount: BalanceOf<T>) -> DispatchResult {
73	T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount)
74}
75
76/// Release all staked amount to `who`.
77///
78/// Fails if there are consumers left on `who` that restricts it from being reaped.
79pub fn kill_stake<T: Config>(who: &T::AccountId) -> DispatchResult {
80	T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ())
81}
82
83/// Slash the value from `who`.
84///
85/// A negative imbalance is returned which can be resolved to deposit the slashed value.
86pub fn slash<T: Config>(
87	who: &T::AccountId,
88	value: BalanceOf<T>,
89) -> (NegativeImbalanceOf<T>, BalanceOf<T>) {
90	T::Currency::slash(&HoldReason::Staking.into(), who, value)
91}
92
93/// Mint `value` into an existing account `who`.
94///
95/// This does not increase the total issuance.
96pub fn mint_into_existing<T: Config>(
97	who: &T::AccountId,
98	value: BalanceOf<T>,
99) -> Option<PositiveImbalanceOf<T>> {
100	// since the account already exists, we mint exact value even if value is below ED.
101	T::Currency::deposit(who, value, Precision::Exact).ok()
102}
103
104/// Mint `value` and create account for `who` if it does not exist.
105///
106/// If value is below existential deposit, the account is not created.
107///
108/// Note: This does not increase the total issuance.
109pub fn mint_creating<T: Config>(who: &T::AccountId, value: BalanceOf<T>) -> PositiveImbalanceOf<T> {
110	T::Currency::deposit(who, value, Precision::BestEffort).unwrap_or_default()
111}
112
113/// Deposit newly issued or slashed `value` into `who`.
114pub fn deposit_slashed<T: Config>(who: &T::AccountId, value: NegativeImbalanceOf<T>) {
115	let _ = T::Currency::resolve(who, value);
116}
117
118/// Issue `value` increasing total issuance.
119///
120/// Creates a negative imbalance.
121pub fn issue<T: Config>(value: BalanceOf<T>) -> NegativeImbalanceOf<T> {
122	T::Currency::issue(value)
123}
124
125/// Burn the amount from the total issuance.
126#[cfg(feature = "runtime-benchmarks")]
127pub fn burn<T: Config>(amount: BalanceOf<T>) -> PositiveImbalanceOf<T> {
128	T::Currency::rescind(amount)
129}
130
131/// Set balance that can be staked for `who`.
132///
133/// If `Value` is lower than the current staked balance, the difference is unlocked.
134///
135/// Should only be used with test.
136#[cfg(any(test, feature = "runtime-benchmarks"))]
137pub fn set_stakeable_balance<T: Config>(who: &T::AccountId, value: BalanceOf<T>) {
138	use frame_support::traits::fungible::Mutate;
139
140	// minimum free balance (non-staked) required to keep the account alive.
141	let ed = existential_deposit::<T>();
142	// currently on stake
143	let staked_balance = staked::<T>(who);
144
145	// if new value is greater than staked balance, mint some free balance.
146	if value > staked_balance {
147		let _ = T::Currency::set_balance(who, value - staked_balance + ed);
148	} else {
149		// else reduce the staked balance.
150		update_stake::<T>(who, value).expect("can remove from what is staked");
151		// burn all free, only leaving ED.
152		let _ = T::Currency::set_balance(who, ed);
153	}
154
155	// ensure new stakeable balance same as desired `value`.
156	assert_eq!(stakeable_balance::<T>(who), value);
157}
158
159/// Return the amount staked and available to stake in one tuple.
160#[cfg(test)]
161pub fn staked_and_not<T: Config>(who: &T::AccountId) -> (BalanceOf<T>, BalanceOf<T>) {
162	(staked::<T>(who), free_to_stake::<T>(who))
163}