Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
e89dff9
First steps to stash/controller separation
gavofyork Feb 7, 2019
8e9c2d5
Merge remote-tracking branch 'origin/master' into gav-new-staking
gavofyork Feb 13, 2019
29d1b20
More drafting
gavofyork Feb 14, 2019
ac5d897
More drafting
gavofyork Feb 14, 2019
bfc089f
Finish draft.
gavofyork Feb 14, 2019
fe19f73
Optimisation
gavofyork Feb 14, 2019
24cedfb
Remove accidental commit
gavofyork Feb 14, 2019
0876c86
Make it build.
gavofyork Feb 15, 2019
c9f643f
Fix linked map for traits.
tomusdrw Feb 15, 2019
9190f7d
Fix Option<_> variant.
tomusdrw Feb 15, 2019
4b5274e
Merge branch 'master' into td-fixlinked
tomusdrw Feb 15, 2019
5354a2e
Improve naming a tad
tomusdrw Feb 15, 2019
00ba07e
Rebuild runtime
tomusdrw Feb 15, 2019
78bcf1a
Merge remote-tracking branch 'origin/master' into gav-new-staking2
gavofyork Feb 15, 2019
5ec3741
Merge remote-tracking branch 'origin/td-fixlinked' into gav-new-staking2
gavofyork Feb 15, 2019
ca18c79
Builds!
gavofyork Feb 15, 2019
a24dd8a
First test.
gavofyork Feb 15, 2019
15a3100
Bump RT version
gavofyork Feb 15, 2019
bd0a3de
Minor fix
gavofyork Feb 15, 2019
68f5405
Update Mock
shawntabrizi Feb 19, 2019
001a665
adds the correct reward testcase (+staking eras which was already ok)
kianenigma Feb 19, 2019
7042842
fixes the basic staking testcase to work properly (along with a small…
kianenigma Feb 20, 2019
75bf9d7
New logic to avoid controller transferring stash.
gavofyork Feb 20, 2019
f4ba1d6
Fix some build issues.
gavofyork Feb 20, 2019
a008ee1
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
gavofyork Feb 20, 2019
27ad50e
adding some comments to tests
shawntabrizi Feb 20, 2019
93d0eb0
Merge branch 'gav-new-staking' of https://github.com/paritytech/subst…
shawntabrizi Feb 20, 2019
9f7ba25
Merge remote-tracking branch 'origin/master' into gav-new-staking
gavofyork Feb 20, 2019
b755466
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
gavofyork Feb 20, 2019
50a212c
Fix impls.
gavofyork Feb 20, 2019
1eb43f7
adds a few more lines to explain the test case
kianenigma Feb 20, 2019
6eaddd1
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Feb 20, 2019
e8661b2
More fixes.
gavofyork Feb 20, 2019
7284530
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Feb 20, 2019
7e9d469
gets the basic test up and running again
kianenigma Feb 20, 2019
31bed92
Fix rest of build
gavofyork Feb 20, 2019
cadce5e
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
gavofyork Feb 20, 2019
37adc08
Rebuild wasm
gavofyork Feb 20, 2019
039f4ea
Fix docs.
gavofyork Feb 20, 2019
4e67748
fix staking test with new chnages
kianenigma Feb 21, 2019
7fe7e01
updating some tests, pending questions
shawntabrizi Feb 21, 2019
a911ee9
Merge branch 'gav-new-staking' of https://github.com/paritytech/subst…
shawntabrizi Feb 21, 2019
514d5a6
More working tests
shawntabrizi Feb 21, 2019
1808869
adds double staking test
kianenigma Feb 21, 2019
2c4f738
Docs
gavofyork Feb 21, 2019
a163f87
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
gavofyork Feb 21, 2019
1296562
Merge remote-tracking branch 'origin/master' into gav-new-staking
gavofyork Feb 22, 2019
200eea1
remove invalid slashing test
kianenigma Feb 23, 2019
15b9da0
Payee stuff.
gavofyork Feb 25, 2019
634ab7b
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
gavofyork Feb 25, 2019
94a46d4
Fix build
gavofyork Feb 25, 2019
1a2ec9e
Docs
gavofyork Feb 25, 2019
dd7fba6
Fix test
gavofyork Feb 25, 2019
4b0e1e6
Fix a couple of tests
gavofyork Feb 25, 2019
61224f6
Layout plan for finishing tests before Pragmen
shawntabrizi Feb 25, 2019
e4ea05f
Merge branch 'gav-new-staking' of https://github.com/paritytech/subst…
shawntabrizi Feb 25, 2019
3b9917a
Add some working tests
shawntabrizi Feb 25, 2019
6f8f93d
re-build staking and reward tests
kianenigma Feb 25, 2019
4029139
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Feb 25, 2019
cc8f195
Add more tests
shawntabrizi Feb 25, 2019
b0129a0
Merge branch 'gav-new-staking' of https://github.com/paritytech/subst…
shawntabrizi Feb 25, 2019
92c0621
fix offline grace test
shawntabrizi Feb 26, 2019
16a9239
Nominator should have payee checked for cleanup
shawntabrizi Feb 26, 2019
1064cfc
adds more nomination tets
kianenigma Feb 26, 2019
6865917
merged
kianenigma Feb 26, 2019
937c89c
adds validator prefs tests
kianenigma Feb 26, 2019
f606db2
Fix and clean up some TODOs
shawntabrizi Feb 27, 2019
6bf11f9
Fix a couple of issues
gavofyork Feb 27, 2019
9a02201
Fix tests
shawntabrizi Feb 27, 2019
be9f4f6
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Feb 27, 2019
4ddaa42
noting warnings from tests
shawntabrizi Feb 28, 2019
54ee55b
final fix of local tests
kianenigma Feb 28, 2019
a53c3fd
Merge branch 'gav-new-staking' of https://github.com/paritytech/subst…
shawntabrizi Feb 28, 2019
93da8d8
Fix slot_stake bug
shawntabrizi Feb 28, 2019
4603cfe
Half baked test
shawntabrizi Feb 28, 2019
8bb2e43
fix a few gobal tests
kianenigma Feb 28, 2019
2f43287
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Feb 28, 2019
a4ca045
Add logic to limit `unstake_threshold` set in storage
shawntabrizi Feb 28, 2019
ee54da0
Make sure to check before writing!
shawntabrizi Feb 28, 2019
51d25ed
Move a couple of comments
gavofyork Mar 1, 2019
231a02d
devops-parity updated wasm runtime blobs b58d9517 and merged in maste…
devops-parity Mar 1, 2019
68b5938
fix last broken slot_stake test
kianenigma Mar 1, 2019
3a74b73
Merge branch 'gav-new-staking' of github.com:paritytech/substrate int…
kianenigma Mar 1, 2019
ae1e1e5
Merge remote-tracking branch 'origin/master' into gav-new-staking
gavofyork Mar 1, 2019
da9cb52
Ignore broken test
gavofyork Mar 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
First test.
  • Loading branch information
gavofyork committed Feb 15, 2019
commit a24dd8a7cb5430f3880fae25aea0b701fcefc834
2 changes: 1 addition & 1 deletion srml/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ impl<T: Trait> TransferAsset<T::AccountId> for Module<T> {
}

fn remove_from(who: &T::AccountId, value: T::Balance) -> Result {
T::EnsureAccountLiquid::ensure_account_liquid(who)?;
T::EnsureAccountLiquid::ensure_account_can_transfer(who)?;
let b = Self::free_balance(who);
ensure!(b >= value, "account has too few funds");
Self::set_free_balance(who, b - value);
Expand Down
129 changes: 89 additions & 40 deletions srml/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,30 +87,56 @@ impl<B: Default + HasCompact + Copy> Default for ValidatorPrefs<B> {
}
}

/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct UnlockChunk<Balance: HasCompact, BlockNumber: HasCompact> {
/// Amount of funds to be unlocked.
#[codec(compact)]
value: Balance,
/// Era number at which point it'll be unlocked.
#[codec(compact)]
era: BlockNumber,
}

/// The ledger of a (bonded) stash.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct StakingLedger<AccountId, Balance, BlockNumber> {
pub struct StakingLedger<AccountId, Balance: HasCompact, BlockNumber: HasCompact> {
/// The stash account whose balance is actually locked and at stake.
pub stash: AccountId,
/// The total amount of the stash's balance that will be at stake in any forthcoming
/// rounds.
#[codec(compact)]
pub active: Balance,
/// Any balance that is becoming (or has become) free, which may be transferred out
/// of the stash.
pub inactive: Vec<(Balance, BlockNumber)>,
pub inactive: Vec<UnlockChunk<Balance, BlockNumber>>,
}

/// The amount of exposure (to slashing) than an individual nominator has.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct IndividualExposure<AccountId, Balance: HasCompact> {
/// Which nominator.
who: AccountId,
/// Amount of funds exposed.
#[codec(compact)]
value: Balance,
}

/// A snapshot of the stake backing a single validator in the system.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Exposure<AccountId, Balance> {
pub struct Exposure<AccountId, Balance: HasCompact> {
/// The total balance backing this validator.
#[codec(compact)]
pub total: Balance,
/// The validator's own stash that is exposed.
#[codec(compact)]
pub own: Balance,
/// The portions of nominators stashes that are exposed.
pub others: Vec<(AccountId, Balance)>,
pub others: Vec<IndividualExposure<AccountId, Balance>>,
}

type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
Expand Down Expand Up @@ -145,23 +171,37 @@ decl_storage! {
pub BondingDuration get(bonding_duration) config(): T::BlockNumber = T::BlockNumber::sa(1000);

// TODO: remove once Alex/CC updated #1785
pub Invulerables get(invulerables) config(): Vec<T::AccountId>;
pub Invulerables get(invulerables): Vec<T::AccountId>;

/// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're easy to initialise
/// and the performance hit is minimal (we expect no more than four invulnerables) and restricted to testnets.
pub Invulnerables get(invulnerables) config(): Vec<T::AccountId>;

/// Map from all locked "stash" accounts to the controller account.
pub Bonded get(bonded): map T::AccountId => Option<T::AccountId>;
pub Bonded get(bonded) build(|config: &GenesisConfig<T>| {
config.stakers.iter().map(|(stash, controller, _)| (stash.clone(), controller.clone())).collect::<Vec<_>>()
}): map T::AccountId => Option<T::AccountId>;
/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
pub Ledger get(ledger): map T::AccountId => Option<StakingLedger<T::AccountId, BalanceOf<T>, T::BlockNumber>>;

//==============================================================================================================================
pub Ledger get(ledger) build(|config: &GenesisConfig<T>| {
config.stakers.iter().map(|(stash, controller, value)| (
controller.clone(),
StakingLedger {
stash: stash.clone(),
active: *value,
inactive: Vec::<UnlockChunk<BalanceOf<T>, T::BlockNumber>>::new(),
},
)).collect::<Vec<_>>()
}): map T::AccountId => Option<StakingLedger<T::AccountId, BalanceOf<T>, T::BlockNumber>>;

/// The set of keys are all controllers that want to validate.
///
/// The value are the preferences that a validator has.
pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs<BalanceOf<T>>;
/// The values are the preferences that a validator has.
pub Validators get(validators) build(|config: &GenesisConfig<T>| {
config.stakers.iter().map(|(_stash, controller, _value)| (
controller.clone(),
ValidatorPrefs::<BalanceOf<T>>::default(),
)).collect::<Vec<_>>()
}): linked_map T::AccountId => ValidatorPrefs<BalanceOf<T>>;

/// The set of keys are all controllers that want to nominate.
///
Expand All @@ -170,18 +210,24 @@ decl_storage! {

/// Nominators for a particular account that is in action right now. You can't iterate through validators here,
/// but you can find them in the `sessions` module.
pub Stakers get(stakers): map T::AccountId => Exposure<T::AccountId, BalanceOf<T>>;

// The historical validators and their nominations for a given era. Stored as a hash of the encoded
// `(T::AccountId, Vec<(T::AccountId, BalanceOf<T>)>)`, which is the key and value of the `CurrentNominatorsFor`,
// under a key that is the tuple of `era` and `validator index`.
pub Stakers get(stakers) build(|config: &GenesisConfig<T>| {
config.stakers.iter().map(|(_stash, controller, value)| (
controller.clone(),
Exposure {
total: *value,
own: *value,
others: Vec::<IndividualExposure<T::AccountId, _>>::new(),
},
)).collect::<Vec<_>>()
}): map T::AccountId => Exposure<T::AccountId, BalanceOf<T>>;

// The historical validators and their nominations for a given era. Stored as a trie root of the mapping
// `T::AccountId` => `Exposure<T::AccountId, BalanceOf<T>>`, which is just the contents of `Stakers`,
// under a key that is the `era`.
//
// Every era change, this will be appended with the contents of `CurrentNominatorsFor`, and the oldest entry removed down to
// a specific number of entries (probably around 90 for a 3 month history). To remove all items for era N, just start at
// validator index 0: (N, 0) and remove the item, incrementing the index until it's a `None`.
// pub HistoricalStakers get(historical_stakers): map (T::BlockNumber, u32) => Option<H256>;

//==============================================================================================================================
// Every era change, this will be appended with the trie root of the contents of `Stakers`, and the oldest
// entry removed down to a specific number of entries (probably around 90 for a 3 month history).
// pub HistoricalStakers get(historical_stakers): map T::BlockNumber => Option<H256>;

/// The current era index.
pub CurrentEra get(current_era) config(): T::BlockNumber;
Expand All @@ -193,15 +239,17 @@ decl_storage! {

/// The accumulated reward for the current era. Reset to zero at the beginning of the era and
/// increased for every successfully finished session.
pub CurrentEraReward get(current_era_reward) config(): BalanceOf<T>;
pub CurrentEraReward get(current_era_reward): BalanceOf<T>;

/// The next value of sessions per era.
pub NextSessionsPerEra get(next_sessions_per_era): Option<T::BlockNumber>;
/// The session index at which the era length last changed.
pub LastEraLengthChange get(last_era_length_change): T::BlockNumber;

/// The highest and lowest staked validator slashable balances.
pub SlotStake get(slot_stake): BalanceOf<T>;
pub SlotStake get(slot_stake) build(|config: &GenesisConfig<T>| {
config.stakers.iter().map(|&(_, _, value)| value).min()
}): BalanceOf<T>;

/// The number of times a given validator has been reported offline. This gets decremented by one each era that passes.
pub SlashCount get(slash_count): map T::AccountId => u32;
Expand All @@ -212,6 +260,9 @@ decl_storage! {
/// Most recent `RECENT_OFFLINE_COUNT` instances. (who it was, when it was reported, how many instances they were offline for).
pub RecentlyOffline get(recently_offline): Vec<(T::AccountId, T::BlockNumber, u32)>;
}
add_extra_genesis {
config(stakers): Vec<(T::AccountId, T::AccountId, BalanceOf<T>)>;
}
}

decl_module! {
Expand All @@ -237,7 +288,7 @@ decl_module! {
let value = value.min(stash_balance);
let remaining_free = stash_balance - value;
let inactive = match remaining_free.is_zero() {
false => vec![(remaining_free, <system::Module<T>>::block_number())],
false => vec![UnlockChunk { value: remaining_free, era: Self::current_era()}],
true => vec![],
};

Expand All @@ -263,8 +314,8 @@ decl_module! {
ledger.active = Zero::zero();
}

let now = <system::Module<T>>::block_number();
ledger.inactive.push((value, now + Self::bonding_duration()));
let era = Self::current_era() + Self::bonding_duration();
ledger.inactive.push(UnlockChunk { value, era });
<Ledger<T>>::insert(&controller, ledger);
}
}
Expand All @@ -274,14 +325,13 @@ decl_module! {
let controller = ensure_signed(origin)?;
let mut ledger = Self::ledger(&controller).ok_or("not a controller")?;

let now = <system::Module<T>>::block_number();

let current_era = Self::current_era();
let mut total = Zero::zero();
ledger.inactive = ledger.inactive.into_iter()
.filter(|(how_much, when)| if now < *when {
.filter(|UnlockChunk { value, era }| if current_era < *era {
true
} else {
total += *how_much;
total += *value;
false
})
.collect();
Expand All @@ -298,12 +348,11 @@ decl_module! {
let mut ledger = Self::ledger(&controller).ok_or("not a controller")?;

let stash_balance = T::Currency::free_balance(&ledger.stash);
let inactive_balance = ledger.inactive.iter().fold(Zero::zero(), |acc, &(ref v, _)| acc + *v);
let inactive_balance = ledger.inactive.iter().fold(Zero::zero(), |acc, uc| acc + uc.value);

if stash_balance > inactive_balance + ledger.active {
let extra = stash_balance - inactive_balance - ledger.active;
let now = <system::Module<T>>::block_number();
ledger.inactive.push((extra, now));
ledger.inactive.push(UnlockChunk { value: extra, era: Self::current_era() });
<Ledger<T>>::insert(&controller, ledger);
}
}
Expand Down Expand Up @@ -439,8 +488,8 @@ impl<T: Trait> Module<T> {
let total = exposure.total - exposure.own;
if !total.is_zero() {
let safe_mul_rational = |b| b * rest_slash / total;// FIXME #1572 avoid overflow
for &(ref them, their_exposure) in exposure.others.iter() {
let _ = T::Currency::slash(them, safe_mul_rational(their_exposure)); // best effort - not much that can be done on fail.
for i in exposure.others.iter() {
let _ = T::Currency::slash(&i.who, safe_mul_rational(i.value)); // best effort - not much that can be done on fail.
}
}
}
Expand All @@ -457,8 +506,8 @@ impl<T: Trait> Module<T> {
let exposure = Self::stakers(who);
let total = exposure.total.max(One::one());
let safe_mul_rational = |b| b * reward / total;// FIXME #1572: avoid overflow
for &(ref them, their_exposure) in exposure.others.iter() {
let _ = T::Currency::reward(them, safe_mul_rational(their_exposure));
for i in exposure.others.iter() {
let _ = T::Currency::reward(&i.who, safe_mul_rational(i.value));
}
safe_mul_rational(exposure.own)
};
Expand Down Expand Up @@ -546,7 +595,7 @@ impl<T: Trait> Module<T> {
if let Ok(index) = candidates.binary_search_by(|i| i.0.cmp(&nominees[0])) {
let stash_balance = Self::stash_balance(&who);
candidates[index].1.total += stash_balance;
candidates[index].1.others.push((who, stash_balance));
candidates[index].1.others.push(IndividualExposure { who, value: stash_balance });
}
}

Expand All @@ -556,7 +605,7 @@ impl<T: Trait> Module<T> {
let candidates = if candidates.len() <= count {
candidates
} else {
candidates.into_iter().fold(vec![], |mut winners, entry| {
candidates.into_iter().fold(vec![], |mut winners: Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>, entry| {
if let Err(insert_point) = winners.binary_search_by_key(&entry.1.total, |i| i.1.total) {
if winners.len() < count {
winners.insert(insert_point, entry)
Expand Down
6 changes: 3 additions & 3 deletions srml/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ pub fn new_test_ext(
t.extend(balances::GenesisConfig::<Test>{
balances: if monied {
if reward > 0 {
vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor), (10, balance_factor), (20, balance_factor)]
vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor), (10, balance_factor), (11, balance_factor * 10), (20, balance_factor), (21, balance_factor * 20)]
} else {
vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor)]
}
} else {
vec![(10, balance_factor), (20, balance_factor)]
vec![(10, balance_factor), (11, balance_factor * 10), (20, balance_factor), (21, balance_factor * 20)]
},
existential_deposit: ext_deposit,
transfer_fee: 0,
Expand All @@ -112,7 +112,7 @@ pub fn new_test_ext(
t.extend(GenesisConfig::<Test>{
sessions_per_era,
current_era,
intentions: vec![10, 20],
stakers: vec![(11, 10, balance_factor * 10), (21, 20, balance_factor * 20)],
validator_count: 2,
minimum_validator_count: 0,
bonding_duration: sessions_per_era * session_length * 3,
Expand Down
26 changes: 25 additions & 1 deletion srml/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,33 @@

use super::*;
use runtime_io::with_externalities;
use srml_support::{assert_ok, assert_noop};
use srml_support::{assert_ok, assert_noop, EnumerableStorageMap};
use mock::{Balances, Session, Staking, System, Timestamp, Test, new_test_ext, Origin};
use srml_support::traits::Currency;


#[test]
fn basic_setup_works() {
with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {
assert_eq!(Staking::bonded(&11), Some(10));
assert_eq!(Staking::bonded(&21), Some(20));
assert_eq!(Staking::bonded(&1), None);

assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, active: 10, inactive: vec![] }));
assert_eq!(Staking::ledger(&20), Some(StakingLedger { stash: 21, active: 20, inactive: vec![] }));
assert_eq!(Staking::ledger(&1), None);

assert_eq!(<Validators<Test>>::enumerate().collect::<Vec<_>>(), vec![
(20, ValidatorPrefs { unstake_threshold: 3, validator_payment: 0, payee: Payee::Stash }),
(10, ValidatorPrefs { unstake_threshold: 3, validator_payment: 0, payee: Payee::Stash })
]);

assert_eq!(Staking::stakers(10), Exposure { total: 10, own: 10, others: vec![] });
assert_eq!(Staking::stakers(20), Exposure { total: 20, own: 20, others: vec![] });
});
}

/*
#[test]
fn note_null_offline_should_work() {
with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {
Expand Down Expand Up @@ -596,3 +619,4 @@ fn next_slash_value_calculation_does_not_overflow() {
assert_eq!(Balances::total_balance(&10), 0);
});
}
*/
2 changes: 2 additions & 0 deletions srml/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ pub trait Currency<AccountId> {

/// Substrates `value` from the free balance of `who`. If the whole amount cannot be
/// deducted, an error is returned.
///
/// This does *not* check for spendability, e.g. using `EnsureAccountLiquid` trait.
///
/// NOTE: This assumes that the total stake remains unchanged after this operation. If
/// you mean to actually burn value out of existence, then use `slash` instead.
Expand Down