Refactor the balances module (#4649)

* Initially scoping out of the problem

* Remove need for exiry in balance locks.

* Remove expiry from locks.

* Remove supefluous balance test

* Amalgamate pieces of balance module

* Split out vesting

* Fix tests

* Fixes for vesting.

* Docs.

* Weight docs.

* Refactor things in terms of set_balances.

* Switch out ED to be free + reserved.

* Remove on_free_balance_zero and some docs.

* Build fixes

* Update frame/vesting/src/lib.rs

Co-Authored-By: Xiliang Chen <xlchen1291@gmail.com>

* Update frame/vesting/src/lib.rs

Co-Authored-By: Xiliang Chen <xlchen1291@gmail.com>

* Migration

* Remove superfluous code.

* Test fixes

* Fix some tests

* Fix repatriate reserve

* Fixes

* Add test for migration

* Final cleanups

* Fix

* Indentation.

* Undo unneeded referencing

* Bump runtime version

* Fixes

Co-authored-by: Xiliang Chen <xlchen1291@gmail.com>
This commit is contained in:
Gavin Wood
2020-02-01 13:20:16 +00:00
committed by GitHub
parent b6e8fba179
commit d52d8692f9
46 changed files with 1748 additions and 1171 deletions
+20
View File
@@ -3683,6 +3683,7 @@ version = "2.0.0"
dependencies = [
"frame-support 2.0.0",
"frame-system 2.0.0",
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pallet-balances 2.0.0",
"parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3690,6 +3691,7 @@ dependencies = [
"sp-io 2.0.0",
"sp-runtime 2.0.0",
"sp-std 2.0.0",
"sp-storage 2.0.0",
]
[[package]]
@@ -4125,6 +4127,24 @@ dependencies = [
"sp-std 2.0.0",
]
[[package]]
name = "pallet-vesting"
version = "2.0.0"
dependencies = [
"enumflags2 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"frame-support 2.0.0",
"frame-system 2.0.0",
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pallet-balances 2.0.0",
"parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"sp-core 2.0.0",
"sp-io 2.0.0",
"sp-runtime 2.0.0",
"sp-std 2.0.0",
"sp-storage 2.0.0",
]
[[package]]
name = "parity-bytes"
version = "0.1.1"
+1
View File
@@ -99,6 +99,7 @@ members = [
"frame/transaction-payment/rpc/runtime-api",
"frame/treasury",
"frame/utility",
"frame/vesting",
"primitives/allocator",
"primitives/application-crypto",
"primitives/application-crypto/test",
@@ -196,15 +196,12 @@ impl timestamp::Trait for Runtime {
parameter_types! {
pub const ExistentialDeposit: u128 = 500;
pub const TransferFee: u128 = 0;
pub const CreationFee: u128 = 0;
}
impl balances::Trait for Runtime {
/// The type for recording an account's balance.
type Balance = Balance;
/// What to do if an account's free balance gets zeroed.
type OnFreeBalanceZero = ();
/// What to do if an account is fully reaped from the system.
type OnReapAccount = System;
/// What to do if a new account is created.
@@ -214,7 +211,6 @@ impl balances::Trait for Runtime {
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -132,7 +132,6 @@ fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>,
}),
balances: Some(BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(),
vesting: vec![],
}),
sudo: Some(SudoConfig {
key: root_key,
-1
View File
@@ -237,7 +237,6 @@ pub fn testnet_genesis(
.map(|k| (k, ENDOWMENT))
.chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
.collect(),
vesting: vec![],
}),
pallet_indices: Some(IndicesConfig {
ids: endowed_accounts.iter().cloned()
+25 -22
View File
@@ -35,8 +35,7 @@ use frame_system::{self, EventRecord, Phase};
use node_runtime::{
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
System, TransactionPayment, Event,
TransferFee, TransactionBaseFee, TransactionByteFee,
System, TransactionPayment, Event, TransactionBaseFee, TransactionByteFee, CreationFee,
constants::currency::*,
};
use node_primitives::{Balance, Hash};
@@ -62,7 +61,7 @@ fn transfer_fee<E: Encode>(extrinsic: &E, fee_multiplier: Fixed64) -> Balance {
::WeightToFee::convert(weight);
let base_fee = TransactionBaseFee::get();
base_fee + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee) + TransferFee::get()
base_fee + fee_multiplier.saturated_multiply_accumulate(length_fee + weight_fee)
}
fn xt() -> UncheckedExtrinsic {
@@ -164,8 +163,8 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
fn panic_execution_with_foreign_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
69_u128.encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(69u128, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
69_u128.encode()
@@ -203,8 +202,8 @@ fn panic_execution_with_foreign_code_gives_error() {
fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
69_u128.encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(69u128, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
69_u128.encode()
@@ -242,8 +241,8 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() {
fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS).encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
@@ -275,7 +274,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm));
let fees = transfer_fee(&xt(), fm) + CreationFee::get();
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
@@ -284,8 +284,8 @@ fn successful_execution_with_native_equivalent_code_gives_ok() {
fn successful_execution_with_foreign_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS).encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
@@ -317,7 +317,8 @@ fn successful_execution_with_foreign_code_gives_ok() {
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm));
let fees = transfer_fee(&xt(), fm) + CreationFee::get();
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
@@ -340,7 +341,8 @@ fn full_native_block_import_works() {
).0.unwrap();
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt(), fm));
let fees = transfer_fee(&xt(), fm);
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
alice_last_known_balance = Balances::total_balance(&alice());
let events = vec![
@@ -362,7 +364,7 @@ fn full_native_block_import_works() {
alice().into(),
bob().into(),
69 * DOLLARS,
1 * CENTS,
0,
)),
topics: vec![],
},
@@ -416,7 +418,7 @@ fn full_native_block_import_works() {
bob().into(),
alice().into(),
5 * DOLLARS,
1 * CENTS,
0,
)
),
topics: vec![],
@@ -440,7 +442,7 @@ fn full_native_block_import_works() {
alice().into(),
bob().into(),
15 * DOLLARS,
1 * CENTS,
0,
)
),
topics: vec![],
@@ -710,8 +712,8 @@ fn native_big_block_import_fails_on_fallback() {
fn panic_execution_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
0_u128.encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(0_u128, 0_u128, 0_u128, 0_u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
0_u128.encode()
@@ -745,8 +747,8 @@ fn panic_execution_gives_error() {
fn successful_execution_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS).encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(111 * DOLLARS, 0u128, 0u128, 0u128).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(111 * DOLLARS).encode()
@@ -779,7 +781,8 @@ fn successful_execution_gives_ok() {
.expect("Extrinsic did not fail");
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt(), fm));
let fees = transfer_fee(&xt(), fm) + CreationFee::get();
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
+6 -8
View File
@@ -30,7 +30,7 @@ use sp_runtime::{
};
use node_runtime::{
CheckedExtrinsic, Call, Runtime, Balances,
TransactionPayment, TransferFee, TransactionBaseFee, TransactionByteFee,
TransactionPayment, TransactionBaseFee, TransactionByteFee,
WeightFeeCoefficient, constants::currency::*,
};
use node_runtime::impls::LinearWeightToFee;
@@ -134,14 +134,14 @@ fn transaction_fee_is_correct_ultimate() {
// (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`)
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, Storage {
top: map![
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(alice()) => {
(100 * DOLLARS).encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(alice()) => {
(100 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
},
<pallet_balances::FreeBalance<Runtime>>::hashed_key_for(bob()) => {
(10 * DOLLARS).encode()
<pallet_balances::Account<Runtime>>::hashed_key_for(bob()) => {
(10 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
},
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec() => {
(110 * DOLLARS).encode()
(110 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS, 0 * DOLLARS).encode()
},
<pallet_indices::NextEnumSet<Runtime>>::hashed_key().to_vec() => vec![0u8; 16],
<frame_system::BlockHash<Runtime>>::hashed_key_for(0) => vec![0u8; 32]
@@ -193,9 +193,7 @@ fn transaction_fee_is_correct_ultimate() {
// we know that weight to fee multiplier is effect-less in block 1.
assert_eq!(weight_fee as Balance, MILLICENTS);
balance_alice -= weight_fee;
balance_alice -= tip;
balance_alice -= TransferFee::get();
assert_eq!(Balances::total_balance(&alice()), balance_alice);
});
@@ -167,7 +167,8 @@ fn submitted_transaction_should_be_valid() {
// add balance to the account
let author = extrinsic.signature.clone().unwrap().0;
let address = Indices::lookup(author).unwrap();
<pallet_balances::FreeBalance<Runtime, _>>::insert(&address, 5_000_000_000_000);
let account = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() };
<pallet_balances::Account<Runtime, _>>::insert(&address, account);
// check validity
let res = Executive::validate_transaction(extrinsic);
+1 -5
View File
@@ -167,20 +167,17 @@ impl pallet_indices::Trait for Runtime {
parameter_types! {
pub const ExistentialDeposit: Balance = 1 * DOLLARS;
pub const TransferFee: Balance = 1 * CENTS;
pub const CreationFee: Balance = 1 * CENTS;
}
impl pallet_balances::Trait for Runtime {
type Balance = Balance;
type OnFreeBalanceZero = ((Staking, Contracts), Session);
type OnReapAccount = (System, Recovery);
type OnReapAccount = ((((System, Staking), Contracts), Session), Recovery);
type OnNewAccount = Indices;
type Event = Event;
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -430,7 +427,6 @@ impl pallet_contracts::Trait for Runtime {
type RentByteFee = RentByteFee;
type RentDepositOffset = RentDepositOffset;
type SurchargeReward = SurchargeReward;
type TransferFee = ContractTransferFee;
type CreationFee = ContractCreationFee;
type TransactionBaseFee = ContractTransactionBaseFee;
type TransactionByteFee = ContractTransactionByteFee;
@@ -49,7 +49,6 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig
(eve(), 101 * DOLLARS),
(ferdie(), 100 * DOLLARS),
],
vesting: vec![],
}),
pallet_session: Some(SessionConfig {
keys: vec![
+3 -1
View File
@@ -9,6 +9,7 @@ license = "GPL-3.0"
serde = { version = "1.0.101", optional = true }
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" }
sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" }
sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" }
frame-support = { version = "2.0.0", default-features = false, path = "../support" }
frame-system = { version = "2.0.0", default-features = false, path = "../system" }
@@ -24,7 +25,8 @@ std = [
"serde",
"codec/std",
"sp-std/std",
"frame-support/std",
"sp-io/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",
]
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Some utilities for helping access storage with arbitrary key types.
use sp_std::prelude::*;
use codec::{Encode, Decode};
use frame_support::{StorageHasher, Twox128};
pub struct StorageIterator<T> {
prefix: [u8; 32],
previous_key: Vec<u8>,
drain: bool,
_phantom: ::sp_std::marker::PhantomData<T>,
}
impl<T> StorageIterator<T> {
pub fn new(module: &[u8], item: &[u8]) -> Self {
let mut prefix = [0u8; 32];
prefix[0..16].copy_from_slice(&Twox128::hash(module));
prefix[16..32].copy_from_slice(&Twox128::hash(item));
Self { prefix, previous_key: prefix[..].to_vec(), drain: false, _phantom: Default::default() }
}
pub fn drain(mut self) -> Self {
self.drain = true;
self
}
}
impl<T: Decode + Sized> Iterator for StorageIterator<T> {
type Item = (Vec<u8>, T);
fn next(&mut self) -> Option<(Vec<u8>, T)> {
loop {
let maybe_next = sp_io::storage::next_key(&self.previous_key)
.filter(|n| n.starts_with(&self.prefix));
break match maybe_next {
Some(next) => {
self.previous_key = next.clone();
let maybe_value = frame_support::storage::unhashed::get::<T>(&next);
match maybe_value {
Some(value) => {
if self.drain {
frame_support::storage::unhashed::kill(&next);
}
Some((self.previous_key[32..].to_vec(), value))
}
None => continue,
}
}
None => None,
}
}
}
}
pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
let mut key = vec![0u8; 32 + hash.len()];
key[0..16].copy_from_slice(&Twox128::hash(module));
key[16..32].copy_from_slice(&Twox128::hash(item));
key[32..].copy_from_slice(hash);
frame_support::storage::unhashed::get::<T>(&key)
}
pub fn put_storage_value<T: Encode>(module: &[u8], item: &[u8], hash: &[u8], value: T) {
let mut key = vec![0u8; 32 + hash.len()];
key[0..16].copy_from_slice(&Twox128::hash(module));
key[16..32].copy_from_slice(&Twox128::hash(item));
key[32..].copy_from_slice(hash);
frame_support::storage::unhashed::put(&key, &value);
}
+1 -32
View File
@@ -32,7 +32,6 @@ impl_outer_origin!{
thread_local! {
pub(crate) static EXISTENTIAL_DEPOSIT: RefCell<u64> = RefCell::new(0);
static TRANSFER_FEE: RefCell<u64> = RefCell::new(0);
static CREATION_FEE: RefCell<u64> = RefCell::new(0);
}
@@ -41,11 +40,6 @@ impl Get<u64> for ExistentialDeposit {
fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) }
}
pub struct TransferFee;
impl Get<u64> for TransferFee {
fn get() -> u64 { TRANSFER_FEE.with(|v| *v.borrow()) }
}
pub struct CreationFee;
impl Get<u64> for CreationFee {
fn get() -> u64 { CREATION_FEE.with(|v| *v.borrow()) }
@@ -92,32 +86,26 @@ impl pallet_transaction_payment::Trait for Test {
}
impl Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
pub struct ExtBuilder {
existential_deposit: u64,
transfer_fee: u64,
creation_fee: u64,
monied: bool,
vesting: bool,
}
impl Default for ExtBuilder {
fn default() -> Self {
Self {
existential_deposit: 0,
transfer_fee: 0,
creation_fee: 0,
monied: false,
vesting: false,
}
}
}
@@ -126,11 +114,6 @@ impl ExtBuilder {
self.existential_deposit = existential_deposit;
self
}
#[allow(dead_code)]
pub fn transfer_fee(mut self, transfer_fee: u64) -> Self {
self.transfer_fee = transfer_fee;
self
}
pub fn creation_fee(mut self, creation_fee: u64) -> Self {
self.creation_fee = creation_fee;
self
@@ -142,13 +125,8 @@ impl ExtBuilder {
}
self
}
pub fn vesting(mut self, vesting: bool) -> Self {
self.vesting = vesting;
self
}
pub fn set_associated_consts(&self) {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee);
CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee);
}
pub fn build(self) -> sp_io::TestExternalities {
@@ -166,15 +144,6 @@ impl ExtBuilder {
} else {
vec![]
},
vesting: if self.vesting && self.monied {
vec![
(1, 0, 10, 5 * self.existential_deposit),
(2, 10, 20, 0),
(12, 10, 20, 5 * self.existential_deposit)
]
} else {
vec![]
},
}.assimilate_storage(&mut t).unwrap();
t.into()
}
@@ -187,5 +156,5 @@ pub const CALL: &<Test as frame_system::Trait>::Call = &();
/// create a transaction info struct from weight. Handy to avoid building the whole struct.
pub fn info_from_weight(w: Weight) -> DispatchInfo {
DispatchInfo { weight: w, ..Default::default() }
DispatchInfo { weight: w, pays_fee: true, ..Default::default() }
}
+127 -280
View File
@@ -18,7 +18,7 @@
use super::*;
use mock::{Balances, ExtBuilder, Test, System, info_from_weight, CALL};
use sp_runtime::traits::{SignedExtension, BadOrigin};
use sp_runtime::{Fixed64, traits::{SignedExtension, BadOrigin}};
use frame_support::{
assert_noop, assert_ok, assert_err,
traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
@@ -29,13 +29,12 @@ use frame_system::RawOrigin;
const ID_1: LockIdentifier = *b"1 ";
const ID_2: LockIdentifier = *b"2 ";
const ID_3: LockIdentifier = *b"3 ";
#[test]
fn basic_locking_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
assert_eq!(Balances::free_balance(&1), 10);
Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all());
assert_eq!(Balances::free_balance(1), 10);
Balances::set_lock(ID_1, &1, 9, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 5, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
@@ -46,7 +45,7 @@ fn basic_locking_should_work() {
#[test]
fn partial_locking_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
}
@@ -54,7 +53,7 @@ fn partial_locking_should_work() {
#[test]
fn lock_removal_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::all());
Balances::remove_lock(ID_1, &1);
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
@@ -63,8 +62,8 @@ fn lock_removal_should_work() {
#[test]
fn lock_replacement_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
}
@@ -72,8 +71,8 @@ fn lock_replacement_should_work() {
#[test]
fn double_locking_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
Balances::set_lock(ID_2, &1, 5, WithdrawReasons::all());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
}
@@ -81,9 +80,8 @@ fn double_locking_should_work() {
#[test]
fn combination_locking_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none());
Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none());
Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all());
Balances::set_lock(ID_1, &1, u64::max_value(), WithdrawReasons::none());
Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
}
@@ -91,17 +89,17 @@ fn combination_locking_should_work() {
#[test]
fn lock_value_extension_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
Balances::extend_lock(ID_1, &1, 2, u64::max_value(), WithdrawReasons::all());
Balances::extend_lock(ID_1, &1, 2, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
Balances::extend_lock(ID_1, &1, 8, u64::max_value(), WithdrawReasons::all());
Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 3, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
@@ -116,23 +114,12 @@ fn lock_reasons_should_work() {
.monied(true)
.build()
.execute_with(|| {
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into());
pallet_transaction_payment::NextFeeMultiplier::put(Fixed64::from_natural(1));
Balances::set_lock(ID_1, &1, 10, WithdrawReason::Reserve.into());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
// NOTE: this causes a fee payment.
assert!(<ChargeTransactionPayment<Test> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(1),
&1,
CALL,
info_from_weight(1),
0,
).is_ok());
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
assert_noop!(
<Balances as ReservableCurrency<_>>::reserve(&1, 1),
Error::<Test, _>::LiquidityRestrictions
@@ -142,10 +129,17 @@ fn lock_reasons_should_work() {
&1,
CALL,
info_from_weight(1),
0,
1,
).is_err());
assert!(<ChargeTransactionPayment<Test> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(0),
&1,
CALL,
info_from_weight(1),
1,
).is_ok());
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into());
Balances::set_lock(ID_1, &1, 10, WithdrawReason::TransactionPayment.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert!(<ChargeTransactionPayment<Test> as SignedExtension>::pre_dispatch(
@@ -153,40 +147,33 @@ fn lock_reasons_should_work() {
&1,
CALL,
info_from_weight(1),
0,
1,
).is_err());
assert!(<ChargeTransactionPayment<Test> as SignedExtension>::pre_dispatch(
ChargeTransactionPayment::from(0),
&1,
CALL,
info_from_weight(1),
1,
).is_err());
});
}
#[test]
fn lock_block_number_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
System::set_block_number(2);
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
});
}
#[test]
fn lock_block_number_extension_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all());
Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
Balances::extend_lock(ID_1, &1, 10, 1, WithdrawReasons::all());
Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
System::set_block_number(2);
Balances::extend_lock(ID_1, &1, 10, 8, WithdrawReasons::all());
Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::all());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 3, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
@@ -197,17 +184,17 @@ fn lock_block_number_extension_should_work() {
#[test]
fn lock_reasons_extension_should_work() {
ExtBuilder::default().existential_deposit(1).monied(true).build().execute_with(|| {
Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into());
Balances::set_lock(ID_1, &1, 10, WithdrawReason::Transfer.into());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReasons::none());
Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::none());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
);
Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReason::Reserve.into());
Balances::extend_lock(ID_1, &1, 10, WithdrawReason::Reserve.into());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
Error::<Test, _>::LiquidityRestrictions
@@ -230,7 +217,7 @@ fn default_indexing_on_new_accounts_should_not_work2() {
Error::<Test, _>::ExistentialDeposit,
);
assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist
assert_eq!(Balances::free_balance(&1), 100);
assert_eq!(Balances::free_balance(1), 100);
});
}
@@ -247,7 +234,7 @@ fn reserved_balance_should_prevent_reclaim_count() {
assert_eq!(Balances::total_balance(&2), 256 * 20);
assert_ok!(Balances::reserve(&2, 256 * 19 + 1)); // account 2 becomes mostly reserved
assert_eq!(Balances::free_balance(&2), 0); // "free" account deleted."
assert_eq!(Balances::free_balance(2), 255); // "free" account deleted."
assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists.
assert_eq!(Balances::is_dead_account(&2), false);
assert_eq!(System::account_nonce(&2), 1);
@@ -322,11 +309,11 @@ fn dust_account_removal_should_work2() {
fn balance_works() {
ExtBuilder::default().build().execute_with(|| {
let _ = Balances::deposit_creating(&1, 42);
assert_eq!(Balances::free_balance(&1), 42);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 42);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::total_balance(&1), 42);
assert_eq!(Balances::free_balance(&2), 0);
assert_eq!(Balances::reserved_balance(&2), 0);
assert_eq!(Balances::free_balance(2), 0);
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::total_balance(&2), 0);
});
}
@@ -361,14 +348,14 @@ fn reserving_balance_should_work() {
let _ = Balances::deposit_creating(&1, 111);
assert_eq!(Balances::total_balance(&1), 111);
assert_eq!(Balances::free_balance(&1), 111);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 111);
assert_eq!(Balances::reserved_balance(1), 0);
assert_ok!(Balances::reserve(&1, 69));
assert_eq!(Balances::total_balance(&1), 111);
assert_eq!(Balances::free_balance(&1), 42);
assert_eq!(Balances::reserved_balance(&1), 69);
assert_eq!(Balances::free_balance(1), 42);
assert_eq!(Balances::reserved_balance(1), 69);
});
}
@@ -389,7 +376,7 @@ fn deducting_balance_should_work() {
ExtBuilder::default().build().execute_with(|| {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 69));
assert_eq!(Balances::free_balance(&1), 42);
assert_eq!(Balances::free_balance(1), 42);
});
}
@@ -397,10 +384,11 @@ fn deducting_balance_should_work() {
fn refunding_balance_should_work() {
ExtBuilder::default().build().execute_with(|| {
let _ = Balances::deposit_creating(&1, 42);
Balances::set_reserved_balance(&1, 69);
let account = Balances::account(&1);
Balances::set_account(&1, &AccountData { reserved: 69, ..account }, &account);
Balances::unreserve(&1, 69);
assert_eq!(Balances::free_balance(&1), 111);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 111);
assert_eq!(Balances::reserved_balance(1), 0);
});
}
@@ -410,8 +398,8 @@ fn slashing_balance_should_work() {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 69));
assert!(Balances::slash(&1, 69).1.is_zero());
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(&1), 42);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 42);
assert_eq!(<TotalIssuance<Test>>::get(), 42);
});
}
@@ -422,8 +410,8 @@ fn slashing_incomplete_balance_should_work() {
let _ = Balances::deposit_creating(&1, 42);
assert_ok!(Balances::reserve(&1, 21));
assert_eq!(Balances::slash(&1, 69).1, 27);
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 0);
});
}
@@ -434,8 +422,8 @@ fn unreserving_balance_should_work() {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 111));
Balances::unreserve(&1, 42);
assert_eq!(Balances::reserved_balance(&1), 69);
assert_eq!(Balances::free_balance(&1), 42);
assert_eq!(Balances::reserved_balance(1), 69);
assert_eq!(Balances::free_balance(1), 42);
});
}
@@ -445,8 +433,8 @@ fn slashing_reserved_balance_should_work() {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 111));
assert_eq!(Balances::slash_reserved(&1, 42).1, 0);
assert_eq!(Balances::reserved_balance(&1), 69);
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(1), 69);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 69);
});
}
@@ -457,8 +445,8 @@ fn slashing_incomplete_reserved_balance_should_work() {
let _ = Balances::deposit_creating(&1, 111);
assert_ok!(Balances::reserve(&1, 42));
assert_eq!(Balances::slash_reserved(&1, 69).1, 27);
assert_eq!(Balances::free_balance(&1), 69);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 69);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 69);
});
}
@@ -470,10 +458,10 @@ fn transferring_reserved_balance_should_work() {
let _ = Balances::deposit_creating(&2, 1);
assert_ok!(Balances::reserve(&1, 110));
assert_ok!(Balances::repatriate_reserved(&1, &2, 41), 0);
assert_eq!(Balances::reserved_balance(&1), 69);
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(&2), 0);
assert_eq!(Balances::free_balance(&2), 42);
assert_eq!(Balances::reserved_balance(1), 69);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::free_balance(2), 42);
});
}
@@ -493,26 +481,26 @@ fn transferring_incomplete_reserved_balance_should_work() {
let _ = Balances::deposit_creating(&2, 1);
assert_ok!(Balances::reserve(&1, 41));
assert_ok!(Balances::repatriate_reserved(&1, &2, 69), 28);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(&1), 69);
assert_eq!(Balances::reserved_balance(&2), 0);
assert_eq!(Balances::free_balance(&2), 42);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::free_balance(1), 69);
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::free_balance(2), 42);
});
}
#[test]
fn transferring_too_high_value_should_not_panic() {
ExtBuilder::default().build().execute_with(|| {
<FreeBalance<Test>>::insert(1, u64::max_value());
<FreeBalance<Test>>::insert(2, 1);
Account::<Test>::insert(1, AccountData { free: u64::max_value(), .. Default::default() });
Account::<Test>::insert(2, AccountData { free: 1, .. Default::default() });
assert_err!(
Balances::transfer(Some(1).into(), 2, u64::max_value()),
Error::<Test, _>::Overflow,
);
assert_eq!(Balances::free_balance(&1), u64::max_value());
assert_eq!(Balances::free_balance(&2), 1);
assert_eq!(Balances::free_balance(1), u64::max_value());
assert_eq!(Balances::free_balance(2), 1);
});
}
@@ -524,7 +512,7 @@ fn account_create_on_free_too_low_with_other() {
// No-op.
let _ = Balances::deposit_creating(&2, 50);
assert_eq!(Balances::free_balance(&2), 0);
assert_eq!(Balances::free_balance(2), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 100);
})
}
@@ -535,7 +523,7 @@ fn account_create_on_free_too_low() {
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
// No-op.
let _ = Balances::deposit_creating(&2, 50);
assert_eq!(Balances::free_balance(&2), 0);
assert_eq!(Balances::free_balance(2), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 0);
})
}
@@ -549,8 +537,8 @@ fn account_removal_on_free_too_low() {
let _ = Balances::deposit_creating(&1, 110);
let _ = Balances::deposit_creating(&2, 110);
assert_eq!(Balances::free_balance(&1), 110);
assert_eq!(Balances::free_balance(&2), 110);
assert_eq!(Balances::free_balance(1), 110);
assert_eq!(Balances::free_balance(2), 110);
assert_eq!(<TotalIssuance<Test>>::get(), 220);
// Transfer funds from account 1 of such amount that after this transfer
@@ -559,8 +547,8 @@ fn account_removal_on_free_too_low() {
assert_ok!(Balances::transfer(Some(1).into(), 2, 20));
// Verify free balance removal of account 1.
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::free_balance(&2), 130);
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::free_balance(2), 130);
// Verify that TotalIssuance tracks balance removal when free balance is too low.
assert_eq!(<TotalIssuance<Test>>::get(), 130);
@@ -580,160 +568,6 @@ fn transfer_overflow_isnt_exploitable() {
});
}
#[test]
fn check_vesting_status() {
ExtBuilder::default()
.existential_deposit(256)
.monied(true)
.vesting(true)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
let user2_free_balance = Balances::free_balance(&2);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance
assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance
assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance
let user1_vesting_schedule = VestingSchedule {
locked: 256 * 5,
per_block: 128, // Vesting over 10 blocks
starting_block: 0,
};
let user2_vesting_schedule = VestingSchedule {
locked: 256 * 20,
per_block: 256, // Vesting over 20 blocks
starting_block: 10,
};
let user12_vesting_schedule = VestingSchedule {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Balances::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule
assert_eq!(Balances::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule
assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule
// Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1
assert_eq!(Balances::vesting_balance(&1), 128 * 9);
// Account 2 has their full balance locked
assert_eq!(Balances::vesting_balance(&2), user2_free_balance);
// Account 12 has only their illiquid funds locked
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(10);
assert_eq!(System::block_number(), 10);
// Account 1 has fully vested by block 10
assert_eq!(Balances::vesting_balance(&1), 0);
// Account 2 has started vesting by block 10
assert_eq!(Balances::vesting_balance(&2), user2_free_balance);
// Account 12 has started vesting by block 10
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(30);
assert_eq!(System::block_number(), 30);
assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative
assert_eq!(Balances::vesting_balance(&2), 0); // Account 2 has fully vested by block 30
assert_eq!(Balances::vesting_balance(&12), 0); // Account 2 has fully vested by block 30
});
}
#[test]
fn unvested_balance_should_not_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.monied(true)
.vesting(true)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_noop!(
Balances::transfer(Some(1).into(), 2, 56),
Error::<Test, _>::VestingBalance,
); // Account 1 cannot send more than vested amount
});
}
#[test]
fn vested_balance_should_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.monied(true)
.vesting(true)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_ok!(Balances::transfer(Some(1).into(), 2, 55));
});
}
#[test]
fn extra_balance_should_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.monied(true)
.vesting(true)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
assert_ok!(Balances::transfer(Some(3).into(), 1, 100));
assert_ok!(Balances::transfer(Some(3).into(), 2, 100));
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal
let user2_free_balance = Balances::free_balance(&2);
assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal
// Account 1 has only 5 units vested at block 1 (plus 150 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained
// Account 2 has no units vested at block 1, but gained 100
assert_eq!(Balances::vesting_balance(&2), 200);
assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained
});
}
#[test]
fn liquid_funds_should_transfer_with_delayed_vesting() {
ExtBuilder::default()
.existential_deposit(256)
.monied(true)
.vesting(true)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user12_free_balance, 2560); // Account 12 has free balance
// Account 12 has liquid funds
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
// Account 12 has delayed vesting
let user12_vesting_schedule = VestingSchedule {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule));
// Account 12 can still send liquid funds
assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5));
});
}
#[test]
fn burn_must_work() {
ExtBuilder::default().monied(true).build().execute_with(|| {
@@ -766,45 +600,58 @@ fn cannot_set_genesis_value_below_ed() {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
let _ = GenesisConfig::<Test> {
balances: vec![(1, 10)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
}
#[test]
fn dust_moves_between_free_and_reserved() {
ExtBuilder::default()
.existential_deposit(100)
.build()
.execute_with(|| {
// Set balance to free and reserved at the existential deposit
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100));
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 100, 100));
// Check balance
assert_eq!(Balances::free_balance(1), 100);
assert_eq!(Balances::reserved_balance(1), 100);
assert_eq!(Balances::free_balance(2), 100);
assert_eq!(Balances::reserved_balance(2), 100);
.existential_deposit(100)
.build()
.execute_with(|| {
// Set balance to free and reserved at the existential deposit
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0));
// Check balance
assert_eq!(Balances::free_balance(1), 100);
assert_eq!(Balances::reserved_balance(1), 0);
// Drop 1 free_balance below ED
assert_ok!(Balances::transfer(Some(1).into(), 2, 1));
// Check balance, the other 99 should move to reserved_balance
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 199);
// Reserve some free balance
assert_ok!(Balances::reserve(&1, 50));
// Check balance, the account should be ok.
assert_eq!(Balances::free_balance(1), 50);
assert_eq!(Balances::reserved_balance(1), 50);
// Reset accounts
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 100));
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 2, 100, 100));
// Reserve the rest of the free balance
assert_ok!(Balances::reserve(&1, 50));
// Check balance, the account should be ok.
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 100);
// Drop 2 reserved_balance below ED
Balances::unreserve(&2, 1);
// Check balance, all 100 should move to free_balance
assert_eq!(Balances::free_balance(2), 200);
assert_eq!(Balances::reserved_balance(2), 0);
// An account with both too little free and reserved is completely killed
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 99, 99));
// Check balance is 0 for everything
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
});
// Unreserve everything
Balances::unreserve(&1, 100);
// Check balance, all 100 should move to free_balance
assert_eq!(Balances::free_balance(1), 100);
assert_eq!(Balances::reserved_balance(1), 0);
});
}
#[test]
fn account_deleted_when_just_dust() {
ExtBuilder::default()
.existential_deposit(100)
.build()
.execute_with(|| {
// Set balance to free and reserved at the existential deposit
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 50, 50));
// Check balance
assert_eq!(Balances::free_balance(1), 50);
assert_eq!(Balances::reserved_balance(1), 50);
// Reserve some free balance
let _ = Balances::slash(&1, 1);
// The account should be dead.
assert!(Balances::is_dead_account(&1));
assert_eq!(Balances::free_balance(1), 0);
assert_eq!(Balances::reserved_balance(1), 0);
});
}
+1 -1
View File
@@ -149,7 +149,7 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
let (imbalance, outcome) = T::Currency::make_free_balance_be(&address, balance);
total_imbalance = total_imbalance.merge(imbalance);
if let UpdateBalanceOutcome::AccountKilled = outcome {
// Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback
// Account killed. This will ultimately lead to calling `OnReapAccount` callback
// which will make removal of CodeHashOf and AccountStorage for this account.
// In order to avoid writing over the deleted properties we `continue` here.
continue;
+1 -1
View File
@@ -573,7 +573,7 @@ impl<T: Trait> Token<T> for TransferFeeToken<BalanceOf<T>> {
let balance_fee = match self.kind {
TransferFeeKind::ContractInstantiate => metadata.contract_account_instantiate_fee,
TransferFeeKind::AccountCreate => metadata.account_create_fee,
TransferFeeKind::Transfer => metadata.transfer_fee,
TransferFeeKind::Transfer => return metadata.schedule.transfer_cost,
};
approx_gas_for_balance(self.gas_price, balance_fee)
}
+7 -11
View File
@@ -125,7 +125,7 @@ use frame_support::{
parameter_types, IsSubType,
weights::DispatchInfo,
};
use frame_support::traits::{OnFreeBalanceZero, OnUnbalanced, Currency, Get, Time, Randomness};
use frame_support::traits::{OnReapAccount, OnUnbalanced, Currency, Get, Time, Randomness};
use frame_system::{self as system, ensure_signed, RawOrigin, ensure_root};
use sp_core::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
use pallet_contracts_primitives::{RentProjection, ContractAccessError};
@@ -401,9 +401,6 @@ pub trait Trait: frame_system::Trait {
/// to removal of a contract.
type SurchargeReward: Get<BalanceOf<Self>>;
/// The fee required to make a transfer.
type TransferFee: Get<BalanceOf<Self>>;
/// The fee required to create an account.
type CreationFee: Get<BalanceOf<Self>>;
@@ -520,9 +517,6 @@ decl_module! {
/// to removal of a contract.
const SurchargeReward: BalanceOf<T> = T::SurchargeReward::get();
/// The fee required to make a transfer.
const TransferFee: BalanceOf<T> = T::TransferFee::get();
/// The fee required to create an account.
const CreationFee: BalanceOf<T> = T::CreationFee::get();
@@ -953,8 +947,8 @@ decl_storage! {
}
}
impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
fn on_free_balance_zero(who: &T::AccountId) {
impl<T: Trait> OnReapAccount<T::AccountId> for Module<T> {
fn on_reap_account(who: &T::AccountId) {
if let Some(ContractInfo::Alive(info)) = <ContractInfoOf<T>>::take(who) {
child::kill_storage(&info.trie_id, info.child_trie_unique_id());
}
@@ -973,7 +967,6 @@ pub struct Config<T: Trait> {
pub max_value_size: u32,
pub contract_account_instantiate_fee: BalanceOf<T>,
pub account_create_fee: BalanceOf<T>,
pub transfer_fee: BalanceOf<T>,
}
impl<T: Trait> Config<T> {
@@ -986,7 +979,6 @@ impl<T: Trait> Config<T> {
max_value_size: T::MaxValueSize::get(),
contract_account_instantiate_fee: T::ContractFee::get(),
account_create_fee: T::CreationFee::get(),
transfer_fee: T::TransferFee::get(),
}
}
}
@@ -1031,6 +1023,9 @@ pub struct Schedule {
/// Gas cost per one byte written to the sandbox memory.
pub sandbox_data_write_cost: Gas,
/// Cost for a simple balance transfer.
pub transfer_cost: Gas,
/// The maximum number of topics supported by an event.
pub max_event_topics: u32,
@@ -1069,6 +1064,7 @@ impl Default for Schedule {
instantiate_base_cost: 175,
sandbox_data_read_cost: 1,
sandbox_data_write_cost: 1,
transfer_cost: 100,
max_event_topics: 4,
max_stack_height: 64 * 1024,
max_memory_pages: 16,
+12 -16
View File
@@ -121,14 +121,12 @@ impl frame_system::Trait for Test {
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = Contract;
type OnReapAccount = System;
type OnReapAccount = (System, Contract);
type OnNewAccount = ();
type Event = MetaEvent;
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -171,7 +169,6 @@ impl Trait for Test {
type RentByteFee = RentByteFee;
type RentDepositOffset = RentDepositOffset;
type SurchargeReward = SurchargeReward;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
@@ -278,7 +275,6 @@ impl ExtBuilder {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::<Test> {
current_schedule: Schedule {
@@ -311,7 +307,7 @@ fn refunds_unused_gas() {
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new()));
// 2 * 135 - gas price multiplied by the call base fee.
assert_eq!(Balances::free_balance(&ALICE), 100_000_000 - (2 * 135));
assert_eq!(Balances::free_balance(ALICE), 100_000_000 - (2 * 135));
});
}
@@ -1018,7 +1014,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert_eq!(ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
assert_eq!(Balances::free_balance(&BOB), 100);
assert_eq!(Balances::free_balance(BOB), 100);
// Advance blocks
initialize_block(10);
@@ -1026,7 +1022,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent through call
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
assert_eq!(Balances::free_balance(&BOB), subsistence_threshold);
assert_eq!(Balances::free_balance(BOB), subsistence_threshold);
// Advance blocks
initialize_block(20);
@@ -1034,7 +1030,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
assert_eq!(Balances::free_balance(&BOB), subsistence_threshold);
assert_eq!(Balances::free_balance(BOB), subsistence_threshold);
});
// Allowance exceeded
@@ -1052,7 +1048,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert_eq!(ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100);
assert_eq!(Balances::free_balance(&BOB), 1_000);
assert_eq!(Balances::free_balance(BOB), 1_000);
// Advance blocks
initialize_block(10);
@@ -1061,7 +1057,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
// Balance should be initial balance - initial rent_allowance
assert_eq!(Balances::free_balance(&BOB), 900);
assert_eq!(Balances::free_balance(BOB), 900);
// Advance blocks
initialize_block(20);
@@ -1069,7 +1065,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
assert_eq!(Balances::free_balance(&BOB), 900);
assert_eq!(Balances::free_balance(BOB), 900);
});
// Balance reached and inferior to subsistence threshold
@@ -1087,12 +1083,12 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert_eq!(ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
assert_eq!(Balances::free_balance(&BOB), 50 + Balances::minimum_balance());
assert_eq!(Balances::free_balance(BOB), 50 + Balances::minimum_balance());
// Transfer funds
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer()));
assert_eq!(ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance());
assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance());
// Advance blocks
initialize_block(10);
@@ -1100,7 +1096,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent through call
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).is_none());
assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance());
assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance());
// Advance blocks
initialize_block(20);
@@ -1108,7 +1104,7 @@ fn removals(trigger_call: impl Fn() -> bool) {
// Trigger rent must have no effect
assert!(trigger_call());
assert!(ContractInfoOf::<Test>::get(BOB).is_none());
assert_eq!(Balances::free_balance(&BOB), Balances::minimum_balance());
assert_eq!(Balances::free_balance(BOB), Balances::minimum_balance());
});
}
+2
View File
@@ -17,6 +17,8 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system"
[dev-dependencies]
sp-core = { version = "2.0.0", path = "../../primitives/core" }
pallet-balances = { version = "2.0.0", path = "../balances" }
sp-storage = { version = "2.0.0", path = "../../primitives/storage" }
hex-literal = "0.2.1"
[features]
default = ["std"]
+136 -47
View File
@@ -30,7 +30,7 @@ use frame_support::{
weights::SimpleDispatchInfo,
traits::{
Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier, Get,
OnFreeBalanceZero, OnUnbalanced
OnReapAccount, OnUnbalanced
}
};
use frame_system::{self as system, ensure_signed, ensure_root};
@@ -305,6 +305,10 @@ decl_storage! {
pub Delegations get(fn delegations):
linked_map hasher(blake2_256) T::AccountId => (T::AccountId, Conviction);
/// Accounts for which there are locks in action which may be removed at some point in the
/// future. The value is the block number at which the lock expires and may be removed.
pub Locks get(locks): map hasher(blake2_256) T::AccountId => Option<T::BlockNumber>;
/// True if the last referendum tabled was submitted externally. False if it was a public
/// proposal.
pub LastTabledWasExternal: bool;
@@ -364,6 +368,8 @@ decl_event! {
PreimageMissing(Hash, ReferendumIndex),
/// A registered preimage was removed and the deposit collected by the reaper (last item).
PreimageReaped(Hash, AccountId, Balance, AccountId),
/// An account has been unlocked successfully.
Unlocked(AccountId),
}
}
@@ -413,6 +419,10 @@ decl_error! {
PreimageInvalid,
/// No proposals waiting
NoneWaiting,
/// The target account does not have a lock.
NotLocked,
/// The lock on the account to be unlocked has not yet expired.
NotExpired,
}
}
@@ -701,9 +711,9 @@ decl_module! {
DEMOCRACY_ID,
&who,
Bounded::max_value(),
T::BlockNumber::max_value(),
WithdrawReason::Transfer.into()
);
Locks::<T>::remove(&who);
Self::deposit_event(RawEvent::Delegated(who, to));
}
@@ -720,12 +730,12 @@ decl_module! {
// Indefinite lock is reduced to the maximum voting lock that could be possible.
let now = <frame_system::Module<T>>::block_number();
let locked_until = now + T::EnactmentPeriod::get() * conviction.lock_periods().into();
Locks::<T>::insert(&who, locked_until);
T::Currency::set_lock(
DEMOCRACY_ID,
&who,
Bounded::max_value(),
locked_until,
WithdrawReason::Transfer.into()
WithdrawReason::Transfer.into(),
);
Self::deposit_event(RawEvent::Undelegated(who));
}
@@ -796,6 +806,18 @@ decl_module! {
<Preimages<T>>::remove(&proposal_hash);
Self::deposit_event(RawEvent::PreimageReaped(proposal_hash, old, deposit, who));
}
#[weight = SimpleDispatchInfo::FixedNormal(10_000)]
fn unlock(origin, target: T::AccountId) {
ensure_signed(origin)?;
let expiry = Locks::<T>::get(&target).ok_or(Error::<T>::NotLocked)?;
ensure!(expiry <= system::Module::<T>::block_number(), Error::<T>::NotExpired);
T::Currency::remove_lock(DEMOCRACY_ID, &target);
Locks::<T>::remove(&target);
Self::deposit_event(RawEvent::Unlocked(target));
}
}
}
@@ -1081,14 +1103,15 @@ impl<T: Trait> Module<T> {
// now plus: the base lock period multiplied by the number of periods this voter
// offered to lock should they win...
let locked_until = now + T::EnactmentPeriod::get() * conviction.lock_periods().into();
Locks::<T>::insert(&a, locked_until);
// ...extend their bondage until at least then.
T::Currency::extend_lock(
DEMOCRACY_ID,
&a,
Bounded::max_value(),
locked_until,
WithdrawReason::Transfer.into()
);
}
Self::clear_referendum(index);
@@ -1139,8 +1162,8 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
fn on_free_balance_zero(who: &T::AccountId) {
impl<T: Trait> OnReapAccount<T::AccountId> for Module<T> {
fn on_reap_account(who: &T::AccountId) {
<Proxy<T>>::remove(who)
}
}
@@ -1155,11 +1178,12 @@ mod tests {
};
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup, Bounded, BadOrigin},
traits::{BlakeTwo256, IdentityLookup, Bounded, BadOrigin, OnInitialize},
testing::Header, Perbill,
};
use pallet_balances::{BalanceLock, Error as BalancesError};
use frame_system::EnsureSignedBy;
use sp_storage::Storage;
const AYE: Vote = Vote{ aye: true, conviction: Conviction::None };
const NAY: Vote = Vote{ aye: false, conviction: Conviction::None };
@@ -1206,19 +1230,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -1273,7 +1294,6 @@ mod tests {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test>{
balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::default().assimilate_storage(&mut t).unwrap();
sp_io::TestExternalities::new(t)
@@ -1283,11 +1303,60 @@ mod tests {
type Balances = pallet_balances::Module<Test>;
type Democracy = Module<Test>;
#[test]
fn lock_info_via_migration_should_work() {
let mut s = Storage::default();
use hex_literal::hex;
// A dump of data from the previous version for which we know account 1 has 5 of its 10
// reserved and 3 of the rest is locked for misc. Account 2 has all 20 locked until block 5
// for everything and additionally 3 locked for just fees.
let data = vec![
(hex!["26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"].to_vec(), hex!["0100000000000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"].to_vec(), hex!["02000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"].to_vec(), hex!["08000000000000000000000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c11874681e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()),
(hex!["3a636f6465"].to_vec(), hex![""].to_vec()),
(hex!["3a65787472696e7369635f696e646578"].to_vec(), hex!["00000000"].to_vec()),
(hex!["3a686561707061676573"].to_vec(), hex!["0800000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc61dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["046d697363202020200300000000000000ffffffffffffffff04"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["0474786665657320200300000000000000ffffffffffffffff01"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["08616c6c20202020200300000000000000ffffffffffffffff1f64656d6f63726163ffffffffffffffff030000000000000002"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f3c22813def93ef32c365b55cb92f10f91dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"].to_vec(), hex!["d200000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f5f27b51b5ec208ee9cb25b55d8728243b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["1e0000000000000006000000000000000200000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b41dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b46cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["1e00000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["3c00000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["1400000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e96760d274653a39b429a87ebaae9d3aa4fdf58b9096cf0bebc7c4e5a4c2ed8d"].to_vec(), hex!["2800000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4effb728943197fd12e694cbf3f3ede28fbf7498b0370c6dfa0013874b417c178"].to_vec(), hex!["3200000000000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911b7f17cdfbfa73331856cca0acddd7842e"].to_vec(), hex!["00000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911bbdcb0c5143a8617ed38ae3810dd45bc6"].to_vec(), hex!["00000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911be2f6cb0456905c189bcb0458f9440f13"].to_vec(), hex!["00000000"].to_vec()),
];
s.top = data.into_iter().collect();
sp_io::TestExternalities::new(s).execute_with(|| {
Balances::on_initialize(1);
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::reserved_balance(1), 5);
assert_eq!(Balances::usable_balance(&1), 2);
assert_eq!(Balances::usable_balance_for_fees(&1), 5);
assert_eq!(Balances::free_balance(2), 20);
assert_eq!(Balances::reserved_balance(2), 0);
assert_eq!(Balances::usable_balance(&2), 0);
assert_eq!(Balances::usable_balance_for_fees(&2), 17);
fast_forward_to(5);
assert_ok!(Democracy::unlock(Origin::signed(2), 2));
assert_eq!(Balances::usable_balance(&2), 17);
});
}
#[test]
fn params_should_work() {
new_test_ext().execute_with(|| {
assert_eq!(Democracy::referendum_count(), 0);
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
assert_eq!(Balances::total_issuance(), 210);
});
}
@@ -1353,7 +1422,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
});
}
@@ -1405,8 +1474,8 @@ mod tests {
next_block();
assert_ok!(Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2)));
assert_eq!(Balances::reserved_balance(6), 0);
assert_eq!(Balances::free_balance(6), 60);
assert_eq!(Balances::reserved_balance(6), 0);
});
}
@@ -1869,7 +1938,7 @@ mod tests {
// referendum passes and wait another two blocks for enactment.
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -1942,7 +2011,7 @@ mod tests {
assert_eq!(Democracy::tally(r), (1, 0, 1));
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -1967,7 +2036,7 @@ mod tests {
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -1993,7 +2062,7 @@ mod tests {
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2020,7 +2089,7 @@ mod tests {
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2048,7 +2117,7 @@ mod tests {
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2080,7 +2149,7 @@ mod tests {
fast_forward_to(6);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2093,9 +2162,9 @@ mod tests {
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_eq!(Balances::free_balance(&1), 5);
assert_eq!(Balances::free_balance(&2), 15);
assert_eq!(Balances::free_balance(&5), 35);
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::free_balance(2), 15);
assert_eq!(Balances::free_balance(5), 35);
});
}
@@ -2109,9 +2178,9 @@ mod tests {
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
fast_forward_to(3);
assert_eq!(Balances::free_balance(&1), 10);
assert_eq!(Balances::free_balance(&2), 20);
assert_eq!(Balances::free_balance(&5), 50);
assert_eq!(Balances::free_balance(1), 10);
assert_eq!(Balances::free_balance(2), 20);
assert_eq!(Balances::free_balance(5), 50);
});
}
@@ -2179,7 +2248,7 @@ mod tests {
assert_eq!(Democracy::tally(r2), (1, 0, 1));
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
assert_ok!(Democracy::vote(Origin::signed(1), r1, AYE));
assert_eq!(Democracy::voters_for(r1), vec![1]);
@@ -2187,7 +2256,7 @@ mod tests {
assert_eq!(Democracy::tally(r1), (1, 0, 1));
next_block();
assert_eq!(Balances::free_balance(&42), 3);
assert_eq!(Balances::free_balance(42), 3);
});
}
@@ -2210,7 +2279,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2230,7 +2299,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
});
}
@@ -2253,7 +2322,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
});
}
@@ -2280,7 +2349,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2304,11 +2373,11 @@ mod tests {
assert_eq!(Democracy::tally(r), (21, 0, 21));
next_block();
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2330,14 +2399,14 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
});
}
#[test]
fn passing_low_turnout_voting_should_work() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(&42), 0);
assert_eq!(Balances::free_balance(42), 0);
assert_eq!(Balances::total_issuance(), 210);
System::set_block_number(1);
@@ -2356,7 +2425,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
@@ -2399,24 +2468,44 @@ mod tests {
assert_eq!(Balances::locks(2), vec![BalanceLock {
id: DEMOCRACY_ID,
amount: u64::max_value(),
until: 18,
reasons: WithdrawReason::Transfer.into()
reasons: pallet_balances::Reasons::Misc,
}]);
assert_eq!(Democracy::locks(2), Some(18));
assert_eq!(Balances::locks(3), vec![BalanceLock {
id: DEMOCRACY_ID,
amount: u64::max_value(),
until: 10,
reasons: WithdrawReason::Transfer.into()
reasons: pallet_balances::Reasons::Misc,
}]);
assert_eq!(Democracy::locks(3), Some(10));
assert_eq!(Balances::locks(4), vec![BalanceLock {
id: DEMOCRACY_ID,
amount: u64::max_value(),
until: 6,
reasons: WithdrawReason::Transfer.into()
reasons: pallet_balances::Reasons::Misc,
}]);
assert_eq!(Democracy::locks(4), Some(6));
assert_eq!(Balances::locks(5), vec![]);
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
assert_noop!(Democracy::unlock(Origin::signed(1), 1), Error::<Test>::NotLocked);
fast_forward_to(5);
assert_noop!(Democracy::unlock(Origin::signed(1), 4), Error::<Test>::NotExpired);
fast_forward_to(6);
assert_ok!(Democracy::unlock(Origin::signed(1), 4));
assert_noop!(Democracy::unlock(Origin::signed(1), 4), Error::<Test>::NotLocked);
fast_forward_to(9);
assert_noop!(Democracy::unlock(Origin::signed(1), 3), Error::<Test>::NotExpired);
fast_forward_to(10);
assert_ok!(Democracy::unlock(Origin::signed(1), 3));
assert_noop!(Democracy::unlock(Origin::signed(1), 3), Error::<Test>::NotLocked);
fast_forward_to(17);
assert_noop!(Democracy::unlock(Origin::signed(1), 2), Error::<Test>::NotExpired);
fast_forward_to(18);
assert_ok!(Democracy::unlock(Origin::signed(1), 2));
assert_noop!(Democracy::unlock(Origin::signed(1), 2), Error::<Test>::NotLocked);
});
}
@@ -2453,7 +2542,7 @@ mod tests {
next_block();
next_block();
assert_eq!(Balances::free_balance(&42), 2);
assert_eq!(Balances::free_balance(42), 2);
});
}
}
@@ -83,7 +83,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::prelude::*;
use sp_runtime::{print, DispatchResult, DispatchError, traits::{Zero, StaticLookup, Bounded, Convert}};
use sp_runtime::{print, DispatchResult, DispatchError, traits::{Zero, StaticLookup, Convert}};
use frame_support::{
decl_storage, decl_event, ensure, decl_module, decl_error, weights::SimpleDispatchInfo,
traits::{
@@ -260,7 +260,6 @@ decl_module! {
MODULE_ID,
&who,
locked_balance,
T::BlockNumber::max_value(),
WithdrawReasons::except(WithdrawReason::TransactionPayment),
);
<StakeOf<T>>::insert(&who, locked_balance);
@@ -816,20 +815,17 @@ mod tests {
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type Event = Event;
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -989,7 +985,6 @@ mod tests {
(5, 50 * self.balance_factor),
(6, 60 * self.balance_factor)
],
vesting: vec![],
}),
}.build_storage().unwrap().into()
}
+1 -2
View File
@@ -26,7 +26,7 @@
use sp_std::prelude::*;
use sp_runtime::{
RuntimeDebug, DispatchResult, print,
traits::{Zero, One, StaticLookup, Bounded, Saturating},
traits::{Zero, One, StaticLookup, Saturating},
};
use frame_support::{
decl_storage, decl_event, ensure, decl_module, decl_error,
@@ -894,7 +894,6 @@ impl<T: Trait> Module<T> {
MODULE_ID,
&who,
locked_balance,
T::BlockNumber::max_value(),
WithdrawReasons::all(),
);
+2 -5
View File
@@ -58,19 +58,16 @@ impl frame_system::Trait for Test {
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type Event = Event;
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -222,7 +219,6 @@ impl ExtBuilder {
(5, 50 * self.balance_factor),
(6, 60 * self.balance_factor)
],
vesting: vec![],
}),
elections: Some(elections::GenesisConfig::<Test>{
members: vec![],
@@ -270,7 +266,8 @@ pub(crate) fn create_candidate(i: u64, index: u32) {
}
pub(crate) fn balances(who: &u64) -> (u64, u64) {
(Balances::free_balance(who), Balances::reserved_balance(who))
let a = Balances::account(who);
(a.free, a.reserved)
}
pub(crate) fn locks(who: &u64) -> Vec<u64> {
+3 -3
View File
@@ -1179,14 +1179,14 @@ fn election_present_when_presenter_is_poor_should_not_work() {
// -3
assert_ok!(Elections::submit_candidacy(Origin::signed(1), 0));
assert_eq!(Balances::free_balance(&1), 12);
assert_eq!(Balances::free_balance(1), 12);
// -2 -5
assert_ok!(Elections::set_approvals(Origin::signed(1), vec![true], 0, 0, 15));
assert_ok!(Elections::end_block(System::block_number()));
System::set_block_number(6);
assert_eq!(Balances::free_balance(&1), 5);
assert_eq!(Balances::reserved_balance(&1), 5);
assert_eq!(Balances::free_balance(1), 5);
assert_eq!(Balances::reserved_balance(1), 5);
if p > 5 {
assert_noop!(Elections::present_winner(
Origin::signed(1), 1, 10, 0),
-3
View File
@@ -690,19 +690,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
impl Trait for Test {
+1 -7
View File
@@ -454,19 +454,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Runtime {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = MetaEvent;
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -528,7 +525,6 @@ mod tests {
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
pallet_balances::GenesisConfig::<Runtime> {
balances: vec![(1, 211)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
let xt = sp_runtime::testing::TestXt(sign_extra(1, 0, 0), Call::Balances(BalancesCall::transfer(2, 69)));
let weight = xt.get_dispatch_info().weight as u64;
@@ -552,7 +548,6 @@ mod tests {
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
pallet_balances::GenesisConfig::<Runtime> {
balances: vec![(1, 111 * balance_factor)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
@@ -564,7 +559,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("c6b01b27df520ba23adb96e7fc032acb7c586ba1b477c6282de43184111f2091").into(),
state_root: hex!("a0b84fec49718caf59350dab6ec2993f12db399a7cccdb80f3cf79618ed93bd8").into(),
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
digest: Digest { logs: vec![], },
},
@@ -711,7 +706,6 @@ mod tests {
id,
&1,
110,
Bounded::max_value(),
lock,
);
let xt = sp_runtime::testing::TestXt(
+9 -28
View File
@@ -427,10 +427,9 @@ decl_module! {
}
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct BalanceLock<Balance, BlockNumber> {
pub struct BalanceLock<Balance> {
pub id: LockIdentifier,
pub amount: Balance,
pub until: BlockNumber,
pub reasons: WithdrawReasons,
}
@@ -459,7 +458,7 @@ decl_storage! {
/// Any liquidity locks on some account balances.
pub Locks get(fn locks):
map hasher(blake2_256) T::AccountId => Vec<BalanceLock<T::Balance, T::BlockNumber>>;
map hasher(blake2_256) T::AccountId => Vec<BalanceLock<T::Balance>>;
/// The identity of the asset which is the one that is designated for the chain's staking system.
pub StakingAssetId get(fn staking_asset_id) config(): T::AssetId;
@@ -796,10 +795,8 @@ impl<T: Trait> Module<T> {
if locks.is_empty() {
return Ok(());
}
let now = <frame_system::Module<T>>::block_number();
if Self::locks(who)
.into_iter()
.all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.intersects(reasons))
.into_iter().all(|l| new_balance >= l.amount || !l.reasons.intersects(reasons))
{
Ok(())
} else {
@@ -825,14 +822,11 @@ impl<T: Trait> Module<T> {
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
let now = <frame_system::Module<T>>::block_number();
let mut new_lock = Some(BalanceLock {
id,
amount,
until,
reasons,
});
let mut locks = <Module<T>>::locks(who)
@@ -840,10 +834,8 @@ impl<T: Trait> Module<T> {
.filter_map(|l| {
if l.id == id {
new_lock.take()
} else if l.until > now {
Some(l)
} else {
None
Some(l)
}
})
.collect::<Vec<_>>();
@@ -857,14 +849,11 @@ impl<T: Trait> Module<T> {
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
let now = <frame_system::Module<T>>::block_number();
let mut new_lock = Some(BalanceLock {
id,
amount,
until,
reasons,
});
let mut locks = <Module<T>>::locks(who)
@@ -874,13 +863,10 @@ impl<T: Trait> Module<T> {
new_lock.take().map(|nl| BalanceLock {
id: l.id,
amount: l.amount.max(nl.amount),
until: l.until.max(nl.until),
reasons: l.reasons | nl.reasons,
})
} else if l.until > now {
Some(l)
} else {
None
Some(l)
}
})
.collect::<Vec<_>>();
@@ -891,11 +877,8 @@ impl<T: Trait> Module<T> {
}
fn remove_lock(id: LockIdentifier, who: &T::AccountId) {
let now = <frame_system::Module<T>>::block_number();
let locks = <Module<T>>::locks(who)
.into_iter()
.filter_map(|l| if l.until > now && l.id != id { Some(l) } else { None })
.collect::<Vec<_>>();
let mut locks = <Module<T>>::locks(who);
locks.retain(|l| l.id != id);
<Locks<T>>::insert(who, locks);
}
}
@@ -1339,20 +1322,18 @@ where
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
<Module<T>>::set_lock(id, who, amount, until, reasons)
<Module<T>>::set_lock(id, who, amount, reasons)
}
fn extend_lock(
id: LockIdentifier,
who: &T::AccountId,
amount: T::Balance,
until: T::BlockNumber,
reasons: WithdrawReasons,
) {
<Module<T>>::extend_lock(id, who, amount, until, reasons)
<Module<T>>::extend_lock(id, who, amount, reasons)
}
fn remove_lock(id: LockIdentifier, who: &T::AccountId) {
-4
View File
@@ -925,19 +925,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -981,7 +978,6 @@ mod tests {
(20, 100),
(30, 100),
],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
+8 -12
View File
@@ -288,19 +288,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -334,7 +331,6 @@ mod tests {
(1, 10),
(2, 10),
],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
@@ -359,9 +355,9 @@ mod tests {
);
assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec()));
assert_eq!(Balances::reserved_balance(&2), 2);
assert_eq!(Balances::reserved_balance(2), 2);
assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()));
assert_eq!(Balances::reserved_balance(&2), 2);
assert_eq!(Balances::reserved_balance(2), 2);
assert_eq!(<NameOf<Test>>::get(2).unwrap(), (b"Dr. David Brubeck, III".to_vec(), 2));
});
}
@@ -370,18 +366,18 @@ mod tests {
fn normal_operation_should_work() {
new_test_ext().execute_with(|| {
assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec()));
assert_eq!(Balances::reserved_balance(&1), 2);
assert_eq!(Balances::free_balance(&1), 8);
assert_eq!(Balances::reserved_balance(1), 2);
assert_eq!(Balances::free_balance(1), 8);
assert_eq!(<NameOf<Test>>::get(1).unwrap().0, b"Gav".to_vec());
assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec()));
assert_eq!(Balances::reserved_balance(&1), 2);
assert_eq!(Balances::free_balance(&1), 8);
assert_eq!(Balances::reserved_balance(1), 2);
assert_eq!(Balances::free_balance(1), 8);
assert_eq!(<NameOf<Test>>::get(1).unwrap().0, b"Gavin".to_vec());
assert_ok!(Nicks::clear_name(Origin::signed(1)));
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(Balances::free_balance(&1), 10);
assert_eq!(Balances::reserved_balance(1), 0);
assert_eq!(Balances::free_balance(1), 10);
});
}
-4
View File
@@ -81,20 +81,17 @@ impl frame_system::Trait for Test {
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u128;
type OnFreeBalanceZero = ();
type OnReapAccount = (System, Recovery);
type OnNewAccount = ();
type Event = TestEvent;
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -126,7 +123,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
+3 -3
View File
@@ -35,7 +35,7 @@ fn basic_setup_works() {
assert_eq!(Recovery::active_recovery(&1, &2), None);
assert_eq!(Recovery::recovery_config(&1), None);
// Everyone should have starting balance of 100
assert_eq!(Balances::free_balance(&1), 100);
assert_eq!(Balances::free_balance(1), 100);
});
}
@@ -219,7 +219,7 @@ fn initiate_recovery_handles_basic_errors() {
assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5));
assert_noop!(Recovery::initiate_recovery(Origin::signed(1), 5), Error::<Test>::AlreadyStarted);
// No double deposit
assert_eq!(Balances::reserved_balance(&1), 10);
assert_eq!(Balances::reserved_balance(1), 10);
});
}
@@ -234,7 +234,7 @@ fn initiate_recovery_works() {
// Recovery can be initiated
assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5));
// Deposit is reserved
assert_eq!(Balances::reserved_balance(&1), 10);
assert_eq!(Balances::reserved_balance(1), 10);
// Recovery status object is created correctly
let recovery_status = ActiveRecovery {
created: 1,
-4
View File
@@ -47,7 +47,6 @@ parameter_types! {
pub const AvailableBlockRatio: Perbill = Perbill::one();
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
ord_parameter_types! {
@@ -76,14 +75,12 @@ impl frame_system::Trait for Test {
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -144,7 +141,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
(40, 500_000),
(99, 1),
],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::<Test>{
pool: vec![
+7 -7
View File
@@ -30,8 +30,8 @@ type Balances = pallet_balances::Module<Test>;
fn query_membership_works() {
new_test_ext().execute_with(|| {
assert_eq!(ScoredPool::members(), vec![20, 40]);
assert_eq!(Balances::reserved_balance(&31), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(&40), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(31), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(40), CandidateDeposit::get());
assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![20, 40]);
});
}
@@ -61,7 +61,7 @@ fn submit_candidacy_works() {
assert_eq!(fetch_from_pool(15), Some((who, None)));
// then
assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get());
});
}
@@ -117,7 +117,7 @@ fn kicking_works() {
new_test_ext().execute_with(|| {
// given
let who = 40;
assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get());
assert_eq!(find_in_pool(who), Some(0));
// when
@@ -128,7 +128,7 @@ fn kicking_works() {
assert_eq!(find_in_pool(who), None);
assert_eq!(ScoredPool::members(), vec![20, 31]);
assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members());
assert_eq!(Balances::reserved_balance(&who), 0); // deposit must have been returned
assert_eq!(Balances::reserved_balance(who), 0); // deposit must have been returned
});
}
@@ -246,7 +246,7 @@ fn withdraw_scored_candidacy_must_work() {
new_test_ext().execute_with(|| {
// given
let who = 40;
assert_eq!(Balances::reserved_balance(&who), CandidateDeposit::get());
assert_eq!(Balances::reserved_balance(who), CandidateDeposit::get());
// when
let index = find_in_pool(who).expect("entity must be in pool") as u32;
@@ -255,7 +255,7 @@ fn withdraw_scored_candidacy_must_work() {
// then
assert_eq!(fetch_from_pool(who), None);
assert_eq!(ScoredPool::members(), vec![20, 31]);
assert_eq!(Balances::reserved_balance(&who), 0);
assert_eq!(Balances::reserved_balance(who), 0);
});
}
+4 -4
View File
@@ -106,7 +106,7 @@ use frame_support::weights::SimpleDispatchInfo;
use sp_runtime::traits::{Convert, Zero, Member, OpaqueKeys};
use sp_staking::SessionIndex;
use frame_support::{dispatch, ConsensusEngineId, decl_module, decl_event, decl_storage, decl_error};
use frame_support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor, ValidatorRegistration}, Parameter};
use frame_support::{ensure, traits::{OnReapAccount, Get, FindAuthor, ValidatorRegistration}, Parameter};
use frame_system::{self as system, ensure_signed};
#[cfg(test)]
@@ -676,8 +676,8 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> OnFreeBalanceZero<T::ValidatorId> for Module<T> {
fn on_free_balance_zero(who: &T::ValidatorId) {
impl<T: Trait> OnReapAccount<T::ValidatorId> for Module<T> {
fn on_reap_account(who: &T::ValidatorId) {
Self::prune_dead_keys(who);
}
}
@@ -754,7 +754,7 @@ mod tests {
let id = DUMMY;
assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1));
Session::on_free_balance_zero(&1);
Session::on_reap_account(&1);
assert_eq!(Session::load_keys(&1), None);
assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), None);
})
-4
View File
@@ -51,7 +51,6 @@ parameter_types! {
pub const AvailableBlockRatio: Perbill = Perbill::one();
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
@@ -81,13 +80,11 @@ impl frame_system::Trait for Test {
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type OnReapAccount = System;
}
@@ -146,7 +143,6 @@ impl EnvBuilder {
self.balances.push((Society::account_id(), self.balance.max(self.pot)));
pallet_balances::GenesisConfig::<Test> {
balances: self.balances,
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::<Test>{
members: self.members,
+4 -4
View File
@@ -261,7 +261,7 @@ use frame_support::{
decl_module, decl_event, decl_storage, ensure, decl_error,
weights::SimpleDispatchInfo,
traits::{
Currency, OnFreeBalanceZero, LockIdentifier, LockableCurrency,
Currency, LockIdentifier, LockableCurrency,
WithdrawReasons, OnUnbalanced, Imbalance, Get, Time
}
};
@@ -284,6 +284,7 @@ use sp_runtime::{Serialize, Deserialize};
use frame_system::{self as system, ensure_signed, ensure_root};
use sp_phragmen::ExtendedBalance;
use frame_support::traits::OnReapAccount;
const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4;
const MAX_NOMINATIONS: usize = 16;
@@ -1286,7 +1287,6 @@ impl<T: Trait> Module<T> {
STAKING_ID,
&ledger.stash,
ledger.total,
T::BlockNumber::max_value(),
WithdrawReasons::all(),
);
<Ledger<T>>::insert(controller, ledger);
@@ -1682,8 +1682,8 @@ impl<T: Trait> SessionManager<T::AccountId, Exposure<T::AccountId, BalanceOf<T>>
}
}
impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
fn on_free_balance_zero(stash: &T::AccountId) {
impl<T: Trait> OnReapAccount<T::AccountId> for Module<T> {
fn on_reap_account(stash: &T::AccountId) {
Self::ensure_storage_upgraded();
Self::kill_stash(stash);
}
+1 -5
View File
@@ -140,19 +140,16 @@ impl frame_system::Trait for Test {
type ModuleToIndex = ();
}
parameter_types! {
pub const TransferFee: Balance = 0;
pub const CreationFee: Balance = 0;
}
impl pallet_balances::Trait for Test {
type Balance = Balance;
type OnFreeBalanceZero = Staking;
type OnReapAccount = System;
type OnReapAccount = (System, Staking);
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -323,7 +320,6 @@ impl ExtBuilder {
// This allow us to have a total_payout different from 0.
(999, 1_000_000_000_000),
],
vesting: vec![],
}.assimilate_storage(&mut storage);
let stake_21 = if self.fair { 1000 } else { 2000 };
+90 -90
View File
@@ -110,8 +110,8 @@ fn basic_setup_works() {
assert_eq!(Staking::current_era(), 0);
// Account 10 has `balance_factor` free balance
assert_eq!(Balances::free_balance(&10), 1);
assert_eq!(Balances::free_balance(&10), 1);
assert_eq!(Balances::free_balance(10), 1);
assert_eq!(Balances::free_balance(10), 1);
// New era is not being forced
assert_eq!(Staking::force_era(), Forcing::NotForcing);
@@ -759,7 +759,7 @@ fn cannot_transfer_staked_balance() {
// Confirm account 11 is stashed
assert_eq!(Staking::bonded(&11), Some(10));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::stakers(&11).total, 1000);
// Confirm account 11 cannot transfer as a result
@@ -788,7 +788,7 @@ fn cannot_transfer_staked_balance_2() {
// Confirm account 21 is stashed
assert_eq!(Staking::bonded(&21), Some(20));
// Confirm account 21 has some free balance
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Balances::free_balance(21), 2000);
// Confirm account 21 (via controller 20) is totally staked
assert_eq!(Staking::stakers(&21).total, 1000);
// Confirm account 21 can transfer at most 1000
@@ -811,7 +811,7 @@ fn cannot_reserve_staked_balance() {
// Confirm account 11 is stashed
assert_eq!(Staking::bonded(&11), Some(10));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::stakers(&11).own, 1000);
// Confirm account 11 cannot transfer as a result
@@ -838,9 +838,9 @@ fn reward_destination_works() {
// Check that account 11 is a validator
assert!(Staking::current_elected().contains(&11));
// Check the balance of the validator account
assert_eq!(Balances::free_balance(&10), 1);
assert_eq!(Balances::free_balance(10), 1);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
// Check how much is at stake
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
@@ -859,7 +859,7 @@ fn reward_destination_works() {
// Check that RewardDestination is Staked (default)
assert_eq!(Staking::payee(&11), RewardDestination::Staked);
// Check that reward went to the stash account of validator
assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0);
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0);
// Check that amount at stake increased accordingly
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
@@ -881,7 +881,7 @@ fn reward_destination_works() {
// Check that RewardDestination is Stash
assert_eq!(Staking::payee(&11), RewardDestination::Stash);
// Check that reward went to the stash account
assert_eq!(Balances::free_balance(&11), 1000 + total_payout_0 + total_payout_1);
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1);
// Record this value
let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1;
// Check that amount at stake is NOT increased
@@ -896,7 +896,7 @@ fn reward_destination_works() {
<Payee<Test>>::insert(&11, RewardDestination::Controller);
// Check controller balance
assert_eq!(Balances::free_balance(&10), 1);
assert_eq!(Balances::free_balance(10), 1);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_2 = current_total_payout_for_duration(3000);
@@ -908,7 +908,7 @@ fn reward_destination_works() {
// Check that RewardDestination is Controller
assert_eq!(Staking::payee(&11), RewardDestination::Controller);
// Check that reward went to the controller account
assert_eq!(Balances::free_balance(&10), 1 + total_payout_2);
assert_eq!(Balances::free_balance(10), 1 + total_payout_2);
// Check that amount at stake is NOT increased
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
@@ -917,7 +917,7 @@ fn reward_destination_works() {
unlocking: vec![],
}));
// Check that amount in staked account is NOT increased.
assert_eq!(Balances::free_balance(&11), recorded_stash_balance);
assert_eq!(Balances::free_balance(11), recorded_stash_balance);
});
}
@@ -1422,9 +1422,9 @@ fn on_free_balance_zero_stash_removes_validator() {
// Tests that storage items are untouched when controller is empty
ExtBuilder::default().existential_deposit(10).build().execute_with(|| {
// Check the balance of the validator account
assert_eq!(Balances::free_balance(&10), 256);
assert_eq!(Balances::free_balance(10), 256);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(&11), 256000);
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are bonded
assert_eq!(Staking::bonded(&11), Some(10));
@@ -1442,7 +1442,7 @@ fn on_free_balance_zero_stash_removes_validator() {
let _ = Balances::slash(&10, u64::max_value());
// Check the balance of the stash account has not been touched
assert_eq!(Balances::free_balance(&11), 256000);
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are still bonded
assert_eq!(Staking::bonded(&11), Some(10));
@@ -1476,9 +1476,9 @@ fn on_free_balance_zero_stash_removes_nominator() {
// Check that account 10 is a nominator
assert!(<Nominators<Test>>::exists(11));
// Check the balance of the nominator account
assert_eq!(Balances::free_balance(&10), 256);
assert_eq!(Balances::free_balance(10), 256);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(&11), 256000);
assert_eq!(Balances::free_balance(11), 256000);
// Set payee information
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));
@@ -1495,7 +1495,7 @@ fn on_free_balance_zero_stash_removes_nominator() {
assert_eq!(Balances::total_balance(&10), 0);
// Check the balance of the stash account has not been touched
assert_eq!(Balances::free_balance(&11), 256000);
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are still bonded
assert_eq!(Staking::bonded(&11), Some(10));
@@ -1689,9 +1689,9 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() {
assert_eq!(Staking::slot_stake(), 1);
// Old ones are rewarded.
assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0 / 3);
assert_eq!(Balances::free_balance(10), init_balance_10 + total_payout_0 / 3);
// no rewards paid to 2. This was initial election.
assert_eq!(Balances::free_balance(&2), init_balance_2);
assert_eq!(Balances::free_balance(2), init_balance_2);
let total_payout_1 = current_total_payout_for_duration(3000);
assert!(total_payout_1 > 100); // Test is meaningfull if reward something
@@ -1701,7 +1701,7 @@ fn bond_with_little_staked_value_bounded_by_slot_stake() {
assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]);
assert_eq!(Staking::slot_stake(), 1);
assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1 / 3);
assert_eq!(Balances::free_balance(2), init_balance_2 + total_payout_1 / 3);
assert_eq!(
Balances::free_balance(&10),
init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3,
@@ -2008,7 +2008,7 @@ fn slashing_performed_according_exposure() {
);
// The stash account should be slashed for 250 (50% of 500).
assert_eq!(Balances::free_balance(&11), 1000 - 250);
assert_eq!(Balances::free_balance(11), 1000 - 250);
});
}
@@ -2102,8 +2102,8 @@ fn reporters_receive_their_slice() {
// 50% * (10% * initial_balance / 2)
let reward = (initial_balance / 20) / 2;
let reward_each = reward / 2; // split into two pieces.
assert_eq!(Balances::free_balance(&1), 10 + reward_each);
assert_eq!(Balances::free_balance(&2), 20 + reward_each);
assert_eq!(Balances::free_balance(1), 10 + reward_each);
assert_eq!(Balances::free_balance(2), 20 + reward_each);
assert_ledger_consistent(11);
});
}
@@ -2132,7 +2132,7 @@ fn subsequent_reports_in_same_span_pay_out_less() {
// F1 * (reward_proportion * slash - 0)
// 50% * (10% * initial_balance * 20%)
let reward = (initial_balance / 5) / 20;
assert_eq!(Balances::free_balance(&1), 10 + reward);
assert_eq!(Balances::free_balance(1), 10 + reward);
on_offence_now(
&[OffenceDetails {
@@ -2150,7 +2150,7 @@ fn subsequent_reports_in_same_span_pay_out_less() {
// F1 * (reward_proportion * slash - prior_payout)
// 50% * (10% * (initial_balance / 2) - prior_payout)
let reward = ((initial_balance / 20) - prior_payout) / 2;
assert_eq!(Balances::free_balance(&1), 10 + prior_payout + reward);
assert_eq!(Balances::free_balance(1), 10 + prior_payout + reward);
assert_ledger_consistent(11);
});
}
@@ -2159,8 +2159,8 @@ fn subsequent_reports_in_same_span_pay_out_less() {
fn invulnerables_are_not_slashed() {
// For invulnerable validators no slashing is performed.
ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| {
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(21), 2000);
let exposure = Staking::stakers(&21);
let initial_balance = Staking::slashable_balance_of(&21);
@@ -2183,9 +2183,9 @@ fn invulnerables_are_not_slashed() {
);
// The validator 11 hasn't been slashed, but 21 has been.
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
// 2000 - (0.2 * initial_balance)
assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10));
assert_eq!(Balances::free_balance(21), 2000 - (2 * initial_balance / 10));
// ensure that nominators were slashed as well.
for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) {
@@ -2203,7 +2203,7 @@ fn invulnerables_are_not_slashed() {
fn dont_slash_if_fraction_is_zero() {
// Don't slash if the fraction is zero.
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
on_offence_now(
&[OffenceDetails {
@@ -2217,7 +2217,7 @@ fn dont_slash_if_fraction_is_zero() {
);
// The validator hasn't been slashed. The new era is not forced.
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
assert_ledger_consistent(11);
});
}
@@ -2225,7 +2225,7 @@ fn dont_slash_if_fraction_is_zero() {
#[test]
fn only_slash_for_max_in_era() {
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
on_offence_now(
&[
@@ -2238,7 +2238,7 @@ fn only_slash_for_max_in_era() {
);
// The validator has been slashed and has been force-chilled.
assert_eq!(Balances::free_balance(&11), 500);
assert_eq!(Balances::free_balance(11), 500);
assert_eq!(Staking::force_era(), Forcing::ForceNew);
on_offence_now(
@@ -2252,7 +2252,7 @@ fn only_slash_for_max_in_era() {
);
// The validator has not been slashed additionally.
assert_eq!(Balances::free_balance(&11), 500);
assert_eq!(Balances::free_balance(11), 500);
on_offence_now(
&[
@@ -2265,7 +2265,7 @@ fn only_slash_for_max_in_era() {
);
// The validator got slashed 10% more.
assert_eq!(Balances::free_balance(&11), 400);
assert_eq!(Balances::free_balance(11), 400);
assert_ledger_consistent(11);
})
}
@@ -2273,7 +2273,7 @@ fn only_slash_for_max_in_era() {
#[test]
fn garbage_collection_after_slashing() {
ExtBuilder::default().existential_deposit(1).build().execute_with(|| {
assert_eq!(Balances::free_balance(&11), 256_000);
assert_eq!(Balances::free_balance(11), 256_000);
on_offence_now(
&[
@@ -2285,7 +2285,7 @@ fn garbage_collection_after_slashing() {
&[Perbill::from_percent(10)],
);
assert_eq!(Balances::free_balance(&11), 256_000 - 25_600);
assert_eq!(Balances::free_balance(11), 256_000 - 25_600);
assert!(<Staking as crate::Store>::SlashingSpans::get(&11).is_some());
assert_eq!(<Staking as crate::Store>::SpanSlash::get(&(11, 0)).amount_slashed(), &25_600);
@@ -2302,7 +2302,7 @@ fn garbage_collection_after_slashing() {
// validator and nominator slash in era are garbage-collected by era change,
// so we don't test those here.
assert_eq!(Balances::free_balance(&11), 0);
assert_eq!(Balances::free_balance(11), 0);
assert!(<Staking as crate::Store>::SlashingSpans::get(&11).is_none());
assert_eq!(<Staking as crate::Store>::SpanSlash::get(&(11, 0)).amount_slashed(), &0);
})
@@ -2313,10 +2313,10 @@ fn garbage_collection_on_window_pruning() {
ExtBuilder::default().build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value;
on_offence_now(
@@ -2331,8 +2331,8 @@ fn garbage_collection_on_window_pruning() {
let now = Staking::current_era();
assert_eq!(Balances::free_balance(&11), 900);
assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10));
assert_eq!(Balances::free_balance(11), 900);
assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10));
assert!(<Staking as crate::Store>::ValidatorSlashInEra::get(&now, &11).is_some());
assert!(<Staking as crate::Store>::NominatorSlashInEra::get(&now, &101).is_some());
@@ -2357,15 +2357,15 @@ fn slashing_nominators_by_span_max() {
start_era(2);
start_era(3);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(21), 2000);
assert_eq!(Balances::free_balance(101), 2000);
assert_eq!(Staking::slashable_balance_of(&21), 1000);
let exposure_11 = Staking::stakers(&11);
let exposure_21 = Staking::stakers(&21);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value;
let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value;
@@ -2380,10 +2380,10 @@ fn slashing_nominators_by_span_max() {
2,
);
assert_eq!(Balances::free_balance(&11), 900);
assert_eq!(Balances::free_balance(11), 900);
let slash_1_amount = Perbill::from_percent(10) * nominated_value_11;
assert_eq!(Balances::free_balance(&101), 2000 - slash_1_amount);
assert_eq!(Balances::free_balance(101), 2000 - slash_1_amount);
let expected_spans = vec![
slashing::SlashingSpan { index: 1, start: 4, length: None },
@@ -2415,14 +2415,14 @@ fn slashing_nominators_by_span_max() {
);
// 11 was not further slashed, but 21 and 101 were.
assert_eq!(Balances::free_balance(&11), 900);
assert_eq!(Balances::free_balance(&21), 1700);
assert_eq!(Balances::free_balance(11), 900);
assert_eq!(Balances::free_balance(21), 1700);
let slash_2_amount = Perbill::from_percent(30) * nominated_value_21;
assert!(slash_2_amount > slash_1_amount);
// only the maximum slash in a single span is taken.
assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount);
assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount);
// third slash: in same era and on same validator as first, higher
// in-era value, but lower slash value than slash 2.
@@ -2438,15 +2438,15 @@ fn slashing_nominators_by_span_max() {
);
// 11 was further slashed, but 21 and 101 were not.
assert_eq!(Balances::free_balance(&11), 800);
assert_eq!(Balances::free_balance(&21), 1700);
assert_eq!(Balances::free_balance(11), 800);
assert_eq!(Balances::free_balance(21), 1700);
let slash_3_amount = Perbill::from_percent(20) * nominated_value_21;
assert!(slash_3_amount < slash_2_amount);
assert!(slash_3_amount > slash_1_amount);
// only the maximum slash in a single span is taken.
assert_eq!(Balances::free_balance(&101), 2000 - slash_2_amount);
assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount);
});
}
@@ -2457,7 +2457,7 @@ fn slashes_are_summed_across_spans() {
start_era(2);
start_era(3);
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Balances::free_balance(21), 2000);
assert_eq!(Staking::slashable_balance_of(&21), 1000);
let get_span = |account| <Staking as crate::Store>::SlashingSpans::get(&account).unwrap();
@@ -2478,7 +2478,7 @@ fn slashes_are_summed_across_spans() {
];
assert_eq!(get_span(21).iter().collect::<Vec<_>>(), expected_spans);
assert_eq!(Balances::free_balance(&21), 1900);
assert_eq!(Balances::free_balance(21), 1900);
// 21 has been force-chilled. re-signal intent to validate.
Staking::validate(Origin::signed(20), Default::default()).unwrap();
@@ -2504,7 +2504,7 @@ fn slashes_are_summed_across_spans() {
];
assert_eq!(get_span(21).iter().collect::<Vec<_>>(), expected_spans);
assert_eq!(Balances::free_balance(&21), 1810);
assert_eq!(Balances::free_balance(21), 1810);
});
}
@@ -2513,10 +2513,10 @@ fn deferred_slashes_are_deferred() {
ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value;
on_offence_now(
@@ -2529,25 +2529,25 @@ fn deferred_slashes_are_deferred() {
&[Perbill::from_percent(10)],
);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
start_era(2);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
start_era(3);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
// at the start of era 4, slashes from era 1 are processed,
// after being deferred for at least 2 full eras.
start_era(4);
assert_eq!(Balances::free_balance(&11), 900);
assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10));
assert_eq!(Balances::free_balance(11), 900);
assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10));
})
}
@@ -2556,10 +2556,10 @@ fn remove_deferred() {
ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value;
on_offence_now(
@@ -2572,8 +2572,8 @@ fn remove_deferred() {
&[Perbill::from_percent(10)],
);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
start_era(2);
@@ -2590,21 +2590,21 @@ fn remove_deferred() {
Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0]).unwrap();
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
start_era(3);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
// at the start of era 4, slashes from era 1 are processed,
// after being deferred for at least 2 full eras.
start_era(4);
// the first slash for 10% was cancelled, so no effect.
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
start_era(5);
@@ -2616,8 +2616,8 @@ fn remove_deferred() {
let actual_slash = total_slash - initial_slash;
// 5% slash (15 - 10) processed now.
assert_eq!(Balances::free_balance(&11), 950);
assert_eq!(Balances::free_balance(&101), 2000 - actual_slash);
assert_eq!(Balances::free_balance(11), 950);
assert_eq!(Balances::free_balance(101), 2000 - actual_slash);
})
}
@@ -2626,10 +2626,10 @@ fn remove_multi_deferred() {
ExtBuilder::default().slash_defer_duration(2).build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
on_offence_now(
&[
@@ -2682,10 +2682,10 @@ fn slash_kicks_validators_not_nominators() {
ExtBuilder::default().build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value;
on_offence_now(
@@ -2698,8 +2698,8 @@ fn slash_kicks_validators_not_nominators() {
&[Perbill::from_percent(10)],
);
assert_eq!(Balances::free_balance(&11), 900);
assert_eq!(Balances::free_balance(&101), 2000 - (nominated_value / 10));
assert_eq!(Balances::free_balance(11), 900);
assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10));
// This is the best way to check that the validator was chilled; `get` will
// return default value.
@@ -2771,10 +2771,10 @@ fn zero_slash_keeps_nominators() {
ExtBuilder::default().build().execute_with(|| {
start_era(1);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::stakers(&11);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(101), 2000);
on_offence_now(
&[
@@ -2786,8 +2786,8 @@ fn zero_slash_keeps_nominators() {
&[Perbill::from_percent(0)],
);
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&101), 2000);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
// This is the best way to check that the validator was chilled; `get` will
// return default value.
+2 -1
View File
@@ -67,7 +67,8 @@ pub mod traits;
pub mod weights;
pub use self::hash::{
Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Blake2_128Concat, Hashable
Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Blake2_128Concat, Hashable,
StorageHasher
};
pub use self::storage::{
StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, StoragePrefixedMap
+17 -19
View File
@@ -64,13 +64,6 @@ pub trait Contains<T: Ord> {
fn count() -> usize { Self::sorted_members().len() }
}
/// The account with the given id was killed.
#[impl_trait_for_tuples::impl_for_tuples(30)]
pub trait OnFreeBalanceZero<AccountId> {
/// The account with the given id was killed.
fn on_free_balance_zero(who: &AccountId);
}
/// The account with the given id was reaped.
#[impl_trait_for_tuples::impl_for_tuples(30)]
pub trait OnReapAccount<AccountId> {
@@ -84,6 +77,12 @@ pub enum UpdateBalanceOutcome {
Updated,
/// The update led to killing the account.
AccountKilled,
/// Free balance became zero as a result of this update.
FreeBalanceZero,
/// Reserved balance became zero as a result of this update.
ReservedBalanceZero,
/// The account started and ended non-existent.
StillDead,
}
/// A trait for finding the author of a block header based on the `PreRuntime` digests contained
@@ -376,9 +375,7 @@ pub trait Currency<AccountId> {
/// 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`. Further, the `OnFreeBalanceZero` callback
/// is invoked, giving a chance to external modules to clean up data associated with
/// the deleted account.
/// deleted: specifically `FreeBalance`.
///
/// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets
/// collapsed to zero if it ever becomes less than `ExistentialDeposit`.
@@ -581,7 +578,6 @@ pub trait LockableCurrency<AccountId>: Currency<AccountId> {
id: LockIdentifier,
who: &AccountId,
amount: Self::Balance,
until: Self::Moment,
reasons: WithdrawReasons,
);
@@ -592,13 +588,11 @@ pub trait LockableCurrency<AccountId>: Currency<AccountId> {
/// 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,
amount: Self::Balance,
until: Self::Moment,
reasons: WithdrawReasons,
);
@@ -609,13 +603,17 @@ pub trait LockableCurrency<AccountId>: Currency<AccountId> {
);
}
/// A currency whose accounts can have balances which vest over time.
pub trait VestingCurrency<AccountId>: Currency<AccountId> {
/// A vesting schedule over a currency. This allows a particular currency to have vesting limits
/// applied to it.
pub trait VestingSchedule<AccountId> {
/// The quantity used to denote time; usually just a `BlockNumber`.
type Moment;
/// The currency that this schedule applies to.
type Currency: Currency<AccountId>;
/// Get the amount that is currently being vested and cannot be transferred out of this account.
fn vesting_balance(who: &AccountId) -> Self::Balance;
fn vesting_balance(who: &AccountId) -> <Self::Currency as Currency<AccountId>>::Balance;
/// Adds a vesting schedule to a given account.
///
@@ -623,8 +621,8 @@ pub trait VestingCurrency<AccountId>: Currency<AccountId> {
/// and nothing is updated.
fn add_vesting_schedule(
who: &AccountId,
locked: Self::Balance,
per_block: Self::Balance,
locked: <Self::Currency as Currency<AccountId>>::Balance,
per_block: <Self::Currency as Currency<AccountId>>::Balance,
starting_block: Self::Moment,
) -> DispatchResult;
@@ -644,7 +642,7 @@ bitmask! {
TransactionPayment = 0b00000001,
/// In order to transfer ownership.
Transfer = 0b00000010,
/// In order to reserve some funds for a later return or repatriation
/// In order to reserve some funds for a later return or repatriation.
Reserve = 0b00000100,
/// In order to pay some other (higher-level) fees.
Fee = 0b00001000,
+6 -12
View File
@@ -76,7 +76,7 @@ pub trait Trait: frame_system::Trait {
decl_storage! {
trait Store for Module<T: Trait> as Balances {
NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::from_parts(0);
pub NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::from_parts(0);
}
}
@@ -178,9 +178,7 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> {
let adjusted_fee = targeted_fee_adjustment.saturated_multiply_accumulate(adjustable_fee);
let base_fee = T::TransactionBaseFee::get();
let final_fee = base_fee.saturating_add(adjusted_fee).saturating_add(tip);
final_fee
base_fee.saturating_add(adjusted_fee).saturating_add(tip)
} else {
tip
}
@@ -307,21 +305,18 @@ mod tests {
}
parameter_types! {
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
pub const ExistentialDeposit: u64 = 0;
}
impl pallet_balances::Trait for Runtime {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
@@ -407,7 +402,6 @@ mod tests {
(5, 50 * self.balance_factor),
(6, 60 * self.balance_factor)
],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
@@ -432,14 +426,14 @@ mod tests {
.pre_dispatch(&1, CALL, info_from_weight(5), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 5 - 5 - 10);
assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10);
assert!(
ChargeTransactionPayment::<Runtime>::from(5 /* tipped */)
.pre_dispatch(&2, CALL, info_from_weight(3), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&2), 200 - 5 - 10 - 3 - 5);
assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 3 - 5);
});
}
@@ -474,7 +468,7 @@ mod tests {
.execute_with(||
{
// 1 ain't have a penny.
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::free_balance(1), 0);
let len = 100;
@@ -521,7 +515,7 @@ mod tests {
.pre_dispatch(&1, CALL, info_from_weight(3), len)
.is_ok()
);
assert_eq!(Balances::free_balance(&1), 100 - 10 - 5 - (10 + 3) * 3 / 2);
assert_eq!(Balances::free_balance(1), 100 - 10 - 5 - (10 + 3) * 3 / 2);
})
}
+25 -30
View File
@@ -759,19 +759,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnNewAccount = ();
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
pub struct TenToFourteen;
@@ -818,7 +815,6 @@ mod tests {
pallet_balances::GenesisConfig::<Test>{
// Total issuance will be 200 with treasury account initialized at ED.
balances: vec![(0, 100), (1, 98), (2, 1)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::default().assimilate_storage::<Test>(&mut t).unwrap();
t.into()
@@ -853,8 +849,8 @@ mod tests {
new_test_ext().execute_with(|| {
Balances::make_free_balance_be(&Treasury::account_id(), 101);
assert_ok!(Treasury::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
assert_eq!(Balances::reserved_balance(&0), 12);
assert_eq!(Balances::free_balance(&0), 88);
assert_eq!(Balances::reserved_balance(0), 12);
assert_eq!(Balances::free_balance(0), 88);
// other reports don't count.
assert_noop!(
@@ -869,9 +865,9 @@ mod tests {
assert_noop!(Treasury::tip(Origin::signed(9), h.clone(), 10), BadOrigin);
System::set_block_number(2);
assert_ok!(Treasury::close_tip(Origin::signed(100), h.into()));
assert_eq!(Balances::reserved_balance(&0), 0);
assert_eq!(Balances::free_balance(&0), 102);
assert_eq!(Balances::free_balance(&3), 8);
assert_eq!(Balances::reserved_balance(0), 0);
assert_eq!(Balances::free_balance(0), 102);
assert_eq!(Balances::free_balance(3), 8);
});
}
@@ -880,16 +876,16 @@ mod tests {
new_test_ext().execute_with(|| {
Balances::make_free_balance_be(&Treasury::account_id(), 101);
assert_ok!(Treasury::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0));
assert_eq!(Balances::reserved_balance(&0), 12);
assert_eq!(Balances::free_balance(&0), 88);
assert_eq!(Balances::reserved_balance(0), 12);
assert_eq!(Balances::free_balance(0), 88);
let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u64));
assert_ok!(Treasury::tip(Origin::signed(10), h.clone(), 10));
assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10));
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10));
System::set_block_number(2);
assert_ok!(Treasury::close_tip(Origin::signed(100), h.into()));
assert_eq!(Balances::reserved_balance(&0), 0);
assert_eq!(Balances::free_balance(&0), 110);
assert_eq!(Balances::reserved_balance(0), 0);
assert_eq!(Balances::free_balance(0), 110);
});
}
@@ -910,7 +906,7 @@ mod tests {
System::set_block_number(2);
assert_noop!(Treasury::close_tip(Origin::NONE, h.into()), BadOrigin);
assert_ok!(Treasury::close_tip(Origin::signed(0), h.into()));
assert_eq!(Balances::free_balance(&3), 10);
assert_eq!(Balances::free_balance(3), 10);
assert_noop!(Treasury::close_tip(Origin::signed(100), h.into()), Error::<Test>::UnknownTip);
});
@@ -942,7 +938,7 @@ mod tests {
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 1000000));
System::set_block_number(2);
assert_ok!(Treasury::close_tip(Origin::signed(0), h.into()));
assert_eq!(Balances::free_balance(&3), 10);
assert_eq!(Balances::free_balance(3), 10);
});
}
@@ -961,7 +957,7 @@ mod tests {
assert_ok!(Treasury::tip(Origin::signed(10), h.clone(), 10));
System::set_block_number(2);
assert_ok!(Treasury::close_tip(Origin::signed(0), h.into()));
assert_eq!(Balances::free_balance(&3), 10);
assert_eq!(Balances::free_balance(3), 10);
});
}
@@ -978,8 +974,8 @@ mod tests {
fn spend_proposal_takes_min_deposit() {
new_test_ext().execute_with(|| {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3));
assert_eq!(Balances::free_balance(&0), 99);
assert_eq!(Balances::reserved_balance(&0), 1);
assert_eq!(Balances::free_balance(0), 99);
assert_eq!(Balances::reserved_balance(0), 1);
});
}
@@ -987,8 +983,8 @@ mod tests {
fn spend_proposal_takes_proportional_deposit() {
new_test_ext().execute_with(|| {
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_eq!(Balances::free_balance(&0), 95);
assert_eq!(Balances::reserved_balance(&0), 5);
assert_eq!(Balances::free_balance(0), 95);
assert_eq!(Balances::reserved_balance(0), 5);
});
}
@@ -1011,7 +1007,7 @@ mod tests {
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0));
<Treasury as OnFinalize<u64>>::on_finalize(1);
assert_eq!(Balances::free_balance(&3), 0);
assert_eq!(Balances::free_balance(3), 0);
assert_eq!(Treasury::pot(), 100);
});
}
@@ -1038,7 +1034,7 @@ mod tests {
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
<Treasury as OnFinalize<u64>>::on_finalize(2);
assert_eq!(Balances::free_balance(&3), 0);
assert_eq!(Balances::free_balance(3), 0);
assert_eq!(Treasury::pot(), 50);
});
}
@@ -1089,7 +1085,7 @@ mod tests {
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0));
<Treasury as OnFinalize<u64>>::on_finalize(2);
assert_eq!(Balances::free_balance(&3), 100);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Treasury::pot(), 0);
});
}
@@ -1108,7 +1104,7 @@ mod tests {
let _ = Balances::deposit_into_existing(&Treasury::account_id(), 100).unwrap();
<Treasury as OnFinalize<u64>>::on_finalize(4);
assert_eq!(Balances::free_balance(&3), 150); // Fund has been spent
assert_eq!(Balances::free_balance(3), 150); // Fund has been spent
assert_eq!(Treasury::pot(), 25); // Pot has finally changed
});
}
@@ -1133,7 +1129,7 @@ mod tests {
<Treasury as OnFinalize<u64>>::on_finalize(4);
assert_eq!(Treasury::pot(), 0); // Pot is emptied
assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there
assert_eq!(Balances::free_balance(Treasury::account_id()), 1); // but the account is still there
});
}
@@ -1144,13 +1140,12 @@ mod tests {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test>{
balances: vec![(0, 100), (1, 99), (2, 1)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
// Treasury genesis config is not build thus treasury account does not exist
let mut t: sp_io::TestExternalities = t.into();
t.execute_with(|| {
assert_eq!(Balances::free_balance(&Treasury::account_id()), 0); // Account does not exist
assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist
assert_eq!(Treasury::pot(), 0); // Pot is empty
assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3));
@@ -1159,16 +1154,16 @@ mod tests {
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 1));
<Treasury as OnFinalize<u64>>::on_finalize(2);
assert_eq!(Treasury::pot(), 0); // Pot hasn't changed
assert_eq!(Balances::free_balance(&3), 0); // Balance of `3` hasn't changed
assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed
Balances::make_free_balance_be(&Treasury::account_id(), 100);
assert_eq!(Treasury::pot(), 99); // Pot now contains funds
assert_eq!(Balances::free_balance(&Treasury::account_id()), 100); // Account does exist
assert_eq!(Balances::free_balance(Treasury::account_id()), 100); // Account does exist
<Treasury as OnFinalize<u64>>::on_finalize(4);
assert_eq!(Treasury::pot(), 0); // Pot has changed
assert_eq!(Balances::free_balance(&3), 99); // Balance of `3` has changed
assert_eq!(Balances::free_balance(3), 99); // Balance of `3` has changed
});
}
}
-4
View File
@@ -703,19 +703,16 @@ mod tests {
}
parameter_types! {
pub const ExistentialDeposit: u64 = 0;
pub const TransferFee: u64 = 0;
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnFreeBalanceZero = ();
type OnReapAccount = System;
type OnNewAccount = ();
type Event = TestEvent;
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
}
parameter_types! {
@@ -742,7 +739,6 @@ mod tests {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 10)],
vesting: vec![],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
+33
View File
@@ -0,0 +1,33 @@
[package]
name = "pallet-vesting"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
serde = { version = "1.0.101", optional = true }
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
enumflags2 = { version = "0.6.2" }
sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" }
sp-io = { version = "2.0.0", default-features = false, path = "../../primitives/io" }
sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" }
frame-support = { version = "2.0.0", default-features = false, path = "../support" }
frame-system = { version = "2.0.0", default-features = false, path = "../system" }
[dev-dependencies]
sp-core = { version = "2.0.0", path = "../../primitives/core" }
pallet-balances = { version = "2.0.0", path = "../balances" }
sp-storage = { version = "2.0.0", path = "../../primitives/storage" }
hex-literal = "0.2.1"
[features]
default = ["std"]
std = [
"serde",
"codec/std",
"sp-std/std",
"sp-io/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",
]
+610
View File
@@ -0,0 +1,610 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! # Vesting Module
//!
//! - [`vesting::Trait`](./trait.Trait.html)
//! - [`Call`](./enum.Call.html)
//!
//! ## Overview
//!
//! A simple module providing a means of placing a linear curve on an account's locked balance. This
//! module ensures that there is a lock in place preventing the balance to drop below the *unvested*
//! amount for any reason other than transaction fee payment.
//!
//! As the amount vested increases over time, the amount unvested reduces. However, locks remain in
//! place and explicit action is needed on behalf of the user to ensure that the amount locked is
//! equivalent to the amount remaining to be vested. This is done through a dispatchable function,
//! either `vest` (in typical case where the sender is calling on their own behalf) or `vest_other`
//! in case the sender is calling on another account's behalf.
//!
//! ## Interface
//!
//! This module implements the `VestingSchedule` trait.
//!
//! ### Dispatchable Functions
//!
//! - `vest` - Update the lock, reducing it in line with the amount "vested" so far.
//! - `vest_other` - Update the lock of another account, reducing it in line with the amount
//! "vested" so far.
//!
//! [`Call`]: ./enum.Call.html
//! [`Trait`]: ./trait.Trait.html
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::prelude::*;
use sp_std::fmt::Debug;
use codec::{Encode, Decode};
use sp_runtime::{DispatchResult, RuntimeDebug, traits::{
StaticLookup, Zero, SimpleArithmetic, MaybeSerializeDeserialize, Saturating, Convert
}};
use frame_support::{decl_module, decl_event, decl_storage, ensure, decl_error};
use frame_support::traits::{
Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier
};
use frame_system::{self as system, ensure_signed};
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
pub trait Trait: frame_system::Trait {
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
/// The currency trait.
type Currency: LockableCurrency<Self::AccountId>;
/// Convert the block number into a balance.
type BlockNumberToBalance: Convert<Self::BlockNumber, BalanceOf<Self>>;
}
const VESTING_ID: LockIdentifier = *b"vesting ";
/// Struct to encode the vesting schedule of an individual account.
#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct VestingInfo<Balance, BlockNumber> {
/// Locked amount at genesis.
pub locked: Balance,
/// Amount that gets unlocked every block after `starting_block`.
pub per_block: Balance,
/// Starting block for unlocking(vesting).
pub starting_block: BlockNumber,
}
impl<
Balance: SimpleArithmetic + Copy,
BlockNumber: SimpleArithmetic + Copy,
> VestingInfo<Balance, BlockNumber> {
/// Amount locked at block `n`.
pub fn locked_at<
BlockNumberToBalance: Convert<BlockNumber, Balance>
>(&self, n: BlockNumber) -> Balance {
// Number of blocks that count toward vesting
// Saturating to 0 when n < starting_block
let vested_block_count = n.saturating_sub(self.starting_block);
let vested_block_count = BlockNumberToBalance::convert(vested_block_count);
// Return amount that is still locked in vesting
let maybe_balance = vested_block_count.checked_mul(&self.per_block);
if let Some(balance) = maybe_balance {
self.locked.saturating_sub(balance)
} else {
Zero::zero()
}
}
}
decl_storage! {
trait Store for Module<T: Trait> as Vesting {
/// Information regarding the vesting of a given account.
pub Vesting get(fn vesting):
map hasher(blake2_256) T::AccountId => Option<VestingInfo<BalanceOf<T>, T::BlockNumber>>;
}
add_extra_genesis {
config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, BalanceOf<T>)>;
build(|config: &GenesisConfig<T>| {
// Generate initial vesting configuration
// * who - Account which we are generating vesting configuration for
// * begin - Block when the account will start to vest
// * length - Number of blocks from `begin` until fully vested
// * liquid - Number of units which can be spent before vesting begins
for &(ref who, begin, length, liquid) in config.vesting.iter() {
let balance = T::Currency::free_balance(who);
assert!(!balance.is_zero(), "Currencies must be init'd before vesting");
// Total genesis `balance` minus `liquid` equals funds locked for vesting
let locked = balance.saturating_sub(liquid);
let length_as_balance = T::BlockNumberToBalance::convert(length);
let per_block = locked / length_as_balance.max(sp_runtime::traits::One::one());
Vesting::<T>::insert(who, VestingInfo {
locked: locked,
per_block: per_block,
starting_block: begin
});
let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve;
T::Currency::set_lock(VESTING_ID, who, locked, reasons);
}
})
}
}
decl_event!(
pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId, Balance = BalanceOf<T> {
/// The amount vested has been updated. This could indicate more funds are available. The
/// balance given is the amount which is left unvested (and thus locked).
VestingUpdated(AccountId, Balance),
/// An account (given) has become fully vested. No further vesting can happen.
VestingCompleted(AccountId),
}
);
decl_error! {
/// Error for the vesting module.
pub enum Error for Module<T: Trait> {
/// The account given is not vesting.
NotVesting,
/// An existing vesting schedule already exists for this account that cannot be clobbered.
ExistingVestingSchedule,
}
}
decl_module! {
// Simple declaration of the `Module` type. Lets the macro know what it's working on.
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
fn deposit_event() = default;
/// Unlock any vested funds of the sender account.
///
/// The dispatch origin for this call must be _Signed_ and the sender must have funds still
/// locked under this module.
///
/// Emits either `VestingCompleted` or `VestingUpdated`.
///
/// # <weight>
/// - `O(1)`.
/// - One balance-lock operation.
/// - One storage read (codec `O(1)`) and up to one removal.
/// - One event.
/// # </weight>
fn vest(origin) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::update_lock(who)
}
/// Unlock any vested funds of a `target` account.
///
/// The dispatch origin for this call must be _Signed_.
///
/// - `target`: The account whose vested funds should be unlocked. Must have funds still
/// locked under this module.
///
/// Emits either `VestingCompleted` or `VestingUpdated`.
///
/// # <weight>
/// - `O(1)`.
/// - Up to one account lookup.
/// - One balance-lock operation.
/// - One storage read (codec `O(1)`) and up to one removal.
/// - One event.
/// # </weight>
fn vest_other(origin, target: <T::Lookup as StaticLookup>::Source) -> DispatchResult {
ensure_signed(origin)?;
Self::update_lock(T::Lookup::lookup(target)?)
}
}
}
impl<T: Trait> Module<T> {
/// (Re)set or remove the module's currency lock on `who`'s account in accordance with their
/// current unvested amount.
fn update_lock(who: T::AccountId) -> DispatchResult {
ensure!(Vesting::<T>::exists(&who), Error::<T>::NotVesting);
let unvested = Self::vesting_balance(&who);
if unvested.is_zero() {
T::Currency::remove_lock(VESTING_ID, &who);
Vesting::<T>::remove(&who);
Self::deposit_event(RawEvent::VestingCompleted(who));
} else {
let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve;
T::Currency::set_lock(VESTING_ID, &who, unvested, reasons);
Self::deposit_event(RawEvent::VestingUpdated(who, unvested));
}
Ok(())
}
}
impl<T: Trait> VestingSchedule<T::AccountId> for Module<T> where
BalanceOf<T>: MaybeSerializeDeserialize + Debug
{
type Moment = T::BlockNumber;
type Currency = T::Currency;
/// Get the amount that is currently being vested and cannot be transferred out of this account.
fn vesting_balance(who: &T::AccountId) -> BalanceOf<T> {
if let Some(v) = Self::vesting(who) {
let now = <frame_system::Module<T>>::block_number();
let locked_now = v.locked_at::<T::BlockNumberToBalance>(now);
T::Currency::free_balance(who).min(locked_now)
} else {
Zero::zero()
}
}
/// Adds a vesting schedule to a given account.
///
/// If there already exists a vesting schedule for the given account, an `Err` is returned
/// and nothing is updated.
///
/// Is a no-op if the amount to be vested is zero.
fn add_vesting_schedule(
who: &T::AccountId,
locked: BalanceOf<T>,
per_block: BalanceOf<T>,
starting_block: T::BlockNumber
) -> DispatchResult {
if locked.is_zero() { return Ok(()) }
if Vesting::<T>::exists(who) {
Err(Error::<T>::ExistingVestingSchedule)?
}
let vesting_schedule = VestingInfo {
locked,
per_block,
starting_block
};
Vesting::<T>::insert(who, vesting_schedule);
// it can't fail, but even if somehow it did, we don't really care.
let _ = Self::update_lock(who.clone());
Ok(())
}
/// Remove a vesting schedule for a given account.
fn remove_vesting_schedule(who: &T::AccountId) {
Vesting::<T>::remove(who);
// it can't fail, but even if somehow it did, we don't really care.
let _ = Self::update_lock(who.clone());
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use frame_support::{
assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight,
traits::Get
};
use sp_core::H256;
// The testing primitives are very useful for avoiding having to work with signatures
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
use sp_runtime::{
Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup, Identity, OnInitialize},
};
use sp_storage::Storage;
impl_outer_origin! {
pub enum Origin for Test where system = frame_system {}
}
// For testing the module, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of modules we want to use.
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl frame_system::Trait for Test {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Call = ();
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
type ModuleToIndex = ();
}
parameter_types! {
pub const CreationFee: u64 = 0;
}
impl pallet_balances::Trait for Test {
type Balance = u64;
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type TransferPayment = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type CreationFee = CreationFee;
}
impl Trait for Test {
type Event = ();
type Currency = Balances;
type BlockNumberToBalance = Identity;
}
type System = frame_system::Module<Test>;
type Balances = pallet_balances::Module<Test>;
type Vesting = Module<Test>;
thread_local! {
static EXISTENTIAL_DEPOSIT: RefCell<u64> = RefCell::new(0);
}
pub struct ExistentialDeposit;
impl Get<u64> for ExistentialDeposit {
fn get() -> u64 { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow()) }
}
pub struct ExtBuilder {
existential_deposit: u64,
}
impl Default for ExtBuilder {
fn default() -> Self {
Self {
existential_deposit: 1,
}
}
}
impl ExtBuilder {
pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
self.existential_deposit = existential_deposit;
self
}
pub fn build(self) -> sp_io::TestExternalities {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![
(1, 10 * self.existential_deposit),
(2, 20 * self.existential_deposit),
(3, 30 * self.existential_deposit),
(4, 40 * self.existential_deposit),
(12, 10 * self.existential_deposit)
],
}.assimilate_storage(&mut t).unwrap();
GenesisConfig::<Test> {
vesting: vec![
(1, 0, 10, 5 * self.existential_deposit),
(2, 10, 20, 0),
(12, 10, 20, 5 * self.existential_deposit)
],
}.assimilate_storage(&mut t).unwrap();
t.into()
}
}
#[test]
fn vesting_info_via_migration_should_work() {
let mut s = Storage::default();
use hex_literal::hex;
// A dump of data from the previous version for which we know account 6 vests 30 of its 60
// over 5 blocks from block 3.
let data = vec![
(hex!["26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"].to_vec(), hex!["0100000000000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"].to_vec(), hex!["02000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7"].to_vec(), hex!["08000000000000000000000000"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()),
(hex!["26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c11874681e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c"].to_vec(), hex!["4545454545454545454545454545454545454545454545454545454545454545"].to_vec()),
(hex!["3a636f6465"].to_vec(), hex![""].to_vec()),
(hex!["3a65787472696e7369635f696e646578"].to_vec(), hex!["00000000"].to_vec()),
(hex!["3a686561707061676573"].to_vec(), hex!["0800000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc61dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["046d697363202020200300000000000000ffffffffffffffff04"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc66cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["0474786665657320200300000000000000ffffffffffffffff01"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["08616c6c20202020200300000000000000ffffffffffffffff1f64656d6f63726163ffffffffffffffff030000000000000002"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f3c22813def93ef32c365b55cb92f10f91dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"].to_vec(), hex!["d200000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f5f27b51b5ec208ee9cb25b55d8728243b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["1e0000000000000006000000000000000200000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b41dbd7d0b561a41d23c2a469ad42fbd70d5438bae826f6fd607413190c37c363b"].to_vec(), hex!["0500000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b46cddb367afbd583bb48f9bbd7d5ba3b1d0738b4881b1cddd38169526d8158137"].to_vec(), hex!["1e00000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4b8788bb218b185b63e3e92653953f29b6b143fb8cf5159fc908632e6fe490501"].to_vec(), hex!["3c00000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e88b43fded6323ef02ffeffbd8c40846ee09bf316271bd22369659c959dd733a"].to_vec(), hex!["1400000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4e96760d274653a39b429a87ebaae9d3aa4fdf58b9096cf0bebc7c4e5a4c2ed8d"].to_vec(), hex!["2800000000000000"].to_vec()),
(hex!["c2261276cc9d1f8598ea4b6a74b15c2f6482b9ade7bc6657aaca787ba1add3b4effb728943197fd12e694cbf3f3ede28fbf7498b0370c6dfa0013874b417c178"].to_vec(), hex!["3200000000000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911b7f17cdfbfa73331856cca0acddd7842e"].to_vec(), hex!["00000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911bbdcb0c5143a8617ed38ae3810dd45bc6"].to_vec(), hex!["00000000"].to_vec()),
(hex!["f2794c22e353e9a839f12faab03a911be2f6cb0456905c189bcb0458f9440f13"].to_vec(), hex!["00000000"].to_vec()),
];
s.top = data.into_iter().collect();
sp_io::TestExternalities::new(s).execute_with(|| {
Balances::on_initialize(1);
assert_eq!(Balances::free_balance(6), 60);
assert_eq!(Balances::usable_balance(&6), 30);
System::set_block_number(2);
assert_ok!(Vesting::vest(Origin::signed(6)));
assert_eq!(Balances::usable_balance(&6), 30);
System::set_block_number(3);
assert_ok!(Vesting::vest(Origin::signed(6)));
assert_eq!(Balances::usable_balance(&6), 36);
System::set_block_number(4);
assert_ok!(Vesting::vest(Origin::signed(6)));
assert_eq!(Balances::usable_balance(&6), 42);
});
}
#[test]
fn check_vesting_status() {
ExtBuilder::default()
.existential_deposit(256)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
let user2_free_balance = Balances::free_balance(&2);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance
assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance
assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance
let user1_vesting_schedule = VestingInfo {
locked: 256 * 5,
per_block: 128, // Vesting over 10 blocks
starting_block: 0,
};
let user2_vesting_schedule = VestingInfo {
locked: 256 * 20,
per_block: 256, // Vesting over 20 blocks
starting_block: 10,
};
let user12_vesting_schedule = VestingInfo {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Vesting::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule
assert_eq!(Vesting::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule
assert_eq!(Vesting::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule
// Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1
assert_eq!(Vesting::vesting_balance(&1), 128 * 9);
// Account 2 has their full balance locked
assert_eq!(Vesting::vesting_balance(&2), user2_free_balance);
// Account 12 has only their illiquid funds locked
assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(10);
assert_eq!(System::block_number(), 10);
// Account 1 has fully vested by block 10
assert_eq!(Vesting::vesting_balance(&1), 0);
// Account 2 has started vesting by block 10
assert_eq!(Vesting::vesting_balance(&2), user2_free_balance);
// Account 12 has started vesting by block 10
assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(30);
assert_eq!(System::block_number(), 30);
assert_eq!(Vesting::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative
assert_eq!(Vesting::vesting_balance(&2), 0); // Account 2 has fully vested by block 30
assert_eq!(Vesting::vesting_balance(&12), 0); // Account 2 has fully vested by block 30
});
}
#[test]
fn unvested_balance_should_not_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Vesting::vesting_balance(&1), 45);
assert_noop!(
Balances::transfer(Some(1).into(), 2, 56),
pallet_balances::Error::<Test, _>::LiquidityRestrictions,
); // Account 1 cannot send more than vested amount
});
}
#[test]
fn vested_balance_should_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Vesting::vesting_balance(&1), 45);
assert_ok!(Vesting::vest(Some(1).into()));
assert_ok!(Balances::transfer(Some(1).into(), 2, 55));
});
}
#[test]
fn vested_balance_should_transfer_using_vest_other() {
ExtBuilder::default()
.existential_deposit(10)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Vesting::vesting_balance(&1), 45);
assert_ok!(Vesting::vest_other(Some(2).into(), 1));
assert_ok!(Balances::transfer(Some(1).into(), 2, 55));
});
}
#[test]
fn extra_balance_should_transfer() {
ExtBuilder::default()
.existential_deposit(10)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
assert_ok!(Balances::transfer(Some(3).into(), 1, 100));
assert_ok!(Balances::transfer(Some(3).into(), 2, 100));
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal
let user2_free_balance = Balances::free_balance(&2);
assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal
// Account 1 has only 5 units vested at block 1 (plus 150 unvested)
assert_eq!(Vesting::vesting_balance(&1), 45);
assert_ok!(Vesting::vest(Some(1).into()));
assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained
// Account 2 has no units vested at block 1, but gained 100
assert_eq!(Vesting::vesting_balance(&2), 200);
assert_ok!(Vesting::vest(Some(2).into()));
assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained
});
}
#[test]
fn liquid_funds_should_transfer_with_delayed_vesting() {
ExtBuilder::default()
.existential_deposit(256)
.build()
.execute_with(|| {
assert_eq!(System::block_number(), 1);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user12_free_balance, 2560); // Account 12 has free balance
// Account 12 has liquid funds
assert_eq!(Vesting::vesting_balance(&12), user12_free_balance - 256 * 5);
// Account 12 has delayed vesting
let user12_vesting_schedule = VestingInfo {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Vesting::vesting(&12), Some(user12_vesting_schedule));
// Account 12 can still send liquid funds
assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5));
});
}
}