mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-18 23:31:04 +00:00
49b6dfd2e5
* Cargo.lock after merge * Restore scale-info feature * Fully qualify TypeInfo derive * Skip PendingSwap T * Add missing skip_type_params attr * metadata docs features * Reduce pallet event attribute to struct * Cargo.lock * Update frame/balances/src/tests_composite.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Line widths check * Cargo.lock * Add scale-info/std * Update frame/system/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Use `skip_type_params` to remove `TypeInfo` requirements on checks * Revert "Remove unused Call metadata stuff" This reverts commit 41311f85 * Skip BalanceSwapAction type parameter * Remove unused event metadata macro * Update frame-metadata * Update primitives/npos-elections/compact/src/codec.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Manual TypeInfo for Header * Remove TypeInfo requirement for consts in BoundedVec etc. * Another TypeInfo bound removed * review: fix indentation * TypeInfo impls for Identity types * Add some todos to add custom TypeInfo impls * Update frame/support/procedural/src/pallet/expand/pallet_struct.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Add some todos to add custom TypeInfo impls * Add a test for manual Data TypeInfo impl * Add custom TypeInfo impl for Vote * Era custom TypeInfo crimes * Revert finality-grandpa version to 0.14.z * review: renamed module to pallet_constants_metadata * New line at end of file * Add missing scale-info/std * Update frame/support/src/storage/types/mod.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Remove StorageEntryType::Map unused flag * Add missing scale-info dependency after merge * SignedExtension::AdditionalSigned metadata * Update frame-metadata, use abbreviated docs and args fields * Update frame/example/Cargo.toml Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Add scale_info/std and remove unused scale-info dependency * Remove scale-info dependency * Remove treasury pallet::metadata * Remove redundant Event test * Add back scale-info as dev dependency * fix error metadata when no error defined in decl_module * Add Module3 to tests * Fix metadata test * Add docs feature to frame-support test * WIP fixing pallet metadata test * Remove redundant FunctionMetadata, FunctionArgumentMetadata as per https://github.com/paritytech/frame-metadata/pull/20 * Use main branch of frame-metadata * Use patch of scale-info for latest changes * Use latest patched scale-info * Manual TypeInfo for DigestItem * Manual TypeInfo for DigestItem * Update scale-info * Skip __Ignore variants for Error, depends on https://github.com/paritytech/scale-info/pull/117 * Named fields for FRAME v2 pallet Call variants * Named fields for FRAME v1 pallet Call variants * Add missing scale-info dependency * WIP expand benchmark call variant * fix benchmark with new function create a new function for each variant of a pallet call. This function is called by benchmarking macro in order not to break call creation with unnamed argument * fix tests * more fix * Fix staking tests * Fix offchain workers calls * Cherry pick rustfmt.toml from master * cargo +nightly-2021-06-22 fmt --all * Update to new call variant structs * More call variant struct updates * Remove unused import * More call variant structs * More call variant structs * Even more call variant structs * Mooar variant structs * Evermore variant structs * Call variant structs ad infinitum * Fmt * More call variants * Last call variant * Call variants all done? * Fix SS58Prefix type * Potential workaround for BitFlags<IdentityFields> TypeInfo * Enable docs capturing for Call, Event, and Error types * Fix IdentityFields TypeInfo * Remove metadata-docs feature * Add capture_docs = true for legacy Call, Event and Error types * Fmt * Fix metadata test type * Update benchmarks with call struct variants * Fmt * More test fixes * Fmt * Fix benches * Use latest capture_docs attr * Latest scale_info * Fmt * review: change &Vec to &[] * Remove pallet metadata attr * review: remove commented out test code * review: skip_type_params trailing comma suggestion * Update to scale-info 0.10.0 * Update construct_runtime ui tests, different because of metadata TypeInfo impls * Add some TypeInfo derives for UI tests * Update storage ensure span ui stderrs * Update call argument bound ui tests Possibly changed because change from tuple to struct variants? * Add scale-info dev dependency * Update to latest finality-grandpa release * review: missing newline * review: missing scale-info/std * review: remove duplicate scale-info/std * review: remove fully qualified TypeInfo * review: add missing scale-info/std * review: remove unnecessary imports. * Fmt * Use crates.io RC version of frame-metadata * Remove scale-info/std because it is a dev dependency * Add missing scale_info dev-dependency for test * Delete empty metadata folder * Fix sp_std import * review: improve manual UncheckedExtrinsic TypeInfo impl * review: use full scale-info for dev-dependency * Remove DefaultByteGetter impl * review: derive TypeInfo for generic header * Fmt * Update primitives/runtime/src/generic/unchecked_extrinsic.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Update primitives/runtime/src/generic/unchecked_extrinsic.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Update bin/node/executor/Cargo.toml Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Update frame/identity/src/types.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Update frame/support/src/dispatch.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Remove redundant derive * Simplify scale-info dependency * Strip underscore prefix from call variant struct names * Another underscore field * More underscore fields * Another underscore field * Update to frame-metadata 14.0.0-rc.2 with combined StorageEntryType::Map * Fmt * Revert weights formatting * Fix up some tests * Fix up some tests for StorageEntryTypeMetadata * scale-info dev dependency * Fix test error * Add missing TypeInfo derives * Add back missing scale-info dependency * Add back missing scale-info dependency * Fix npos compact impls * Cargo.lock * Fmt * Fix errors * Fmt * Fix renamed raw_solution field * Fix error * Fmt * Fix some benchmarks * Fmt * Stray R * Fix * Add missing TypeInfos * ui test fix * Fix line widths * Revert "ui test fix" This reverts commit 2d15ec058a216e3f92d713f1174603a2bb1eac65. * Upgrade to scale-info 0.11.0 * Revert "Upgrade to scale-info 0.11.0" This reverts commit 047bb179085a0059c36cd20ab405f55cf0867e28. * Add Runtime type * Update to scale-info 0.12 * Update to scale-info 1.0 * Update frame-metadata to version 14.0.0 * Patch finality-grandpa until release available * Fix metadata tests * Fix metadata tests * Fmt * Remove patched finality-grandpa * Fix tests, use scale_info imports * Fix pallet tests * Add BlockNumber TypeInfo bound * ui test fix * Cargo.lock * Remove pallet metadata * Cargo.lock * Add missing scale-info dependency * Remove pallet event metadata * Fix error * Fix collective errors * Semicolol * Fmt * Remove another metadata attribute * Add new variant to custom digest TypeInfo * Fmt * Cargo.lock from master * Remove comma lol * Fix example call error * Fix example call error properly Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
1226 lines
43 KiB
Rust
1226 lines
43 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Macro for creating the tests for the module.
|
|
|
|
#![cfg(test)]
|
|
|
|
#[macro_export]
|
|
macro_rules! decl_tests {
|
|
($test:ty, $ext_builder:ty, $existential_deposit:expr) => {
|
|
|
|
use crate::*;
|
|
use sp_runtime::{ArithmeticError, FixedPointNumber, traits::{SignedExtension, BadOrigin}};
|
|
use frame_support::{
|
|
assert_noop, assert_storage_noop, assert_ok, assert_err,
|
|
traits::{
|
|
LockableCurrency, LockIdentifier, WithdrawReasons,
|
|
Currency, ReservableCurrency, ExistenceRequirement::AllowDeath
|
|
}
|
|
};
|
|
use pallet_transaction_payment::{ChargeTransactionPayment, Multiplier};
|
|
use frame_system::RawOrigin;
|
|
|
|
const ID_1: LockIdentifier = *b"1 ";
|
|
const ID_2: LockIdentifier = *b"2 ";
|
|
|
|
pub const CALL: &<$test as frame_system::Config>::Call =
|
|
&Call::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 });
|
|
|
|
/// 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() }
|
|
}
|
|
|
|
fn events() -> Vec<Event> {
|
|
let evt = System::events().into_iter().map(|evt| evt.event).collect::<Vec<_>>();
|
|
|
|
System::reset_events();
|
|
|
|
evt
|
|
}
|
|
|
|
#[test]
|
|
fn basic_locking_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
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
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn account_should_be_reaped() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
assert_eq!(Balances::free_balance(1), 10);
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 10, AllowDeath));
|
|
// Check that the account is dead.
|
|
assert!(!frame_system::Account::<Test>::contains_key(&1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reap_failed_due_to_provider_and_consumer() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
// SCENARIO: only one provider and there are remaining consumers.
|
|
assert_ok!(System::inc_consumers(&1));
|
|
assert!(!System::can_dec_provider(&1));
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 10, AllowDeath),
|
|
Error::<$test, _>::KeepAlive
|
|
);
|
|
assert!(System::account_exists(&1));
|
|
assert_eq!(Balances::free_balance(1), 10);
|
|
|
|
// SCENARIO: more than one provider, but will not kill account due to other provider.
|
|
assert_eq!(System::inc_providers(&1), frame_system::IncRefStatus::Existed);
|
|
assert_eq!(System::providers(&1), 2);
|
|
assert!(System::can_dec_provider(&1));
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 10, AllowDeath));
|
|
assert_eq!(System::providers(&1), 1);
|
|
assert!(System::account_exists(&1));
|
|
assert_eq!(Balances::free_balance(1), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn partial_locking_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lock_removal_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all());
|
|
Balances::remove_lock(ID_1, &1);
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lock_replacement_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::all());
|
|
Balances::set_lock(ID_1, &1, 5, WithdrawReasons::all());
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn double_locking_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
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));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn combination_locking_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
Balances::set_lock(ID_1, &1, u64::MAX, WithdrawReasons::empty());
|
|
Balances::set_lock(ID_2, &1, 0, WithdrawReasons::all());
|
|
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lock_value_extension_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
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, WithdrawReasons::all());
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
Balances::extend_lock(ID_1, &1, 8, WithdrawReasons::all());
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 3, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lock_reasons_should_work() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(1)
|
|
.monied(true)
|
|
.build()
|
|
.execute_with(|| {
|
|
pallet_transaction_payment::NextFeeMultiplier::<$test>::put(
|
|
Multiplier::saturating_from_integer(1)
|
|
);
|
|
Balances::set_lock(ID_1, &1, 10, WithdrawReasons::RESERVE);
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 1, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
assert_noop!(
|
|
<Balances as ReservableCurrency<_>>::reserve(&1, 1),
|
|
Error::<$test, _>::LiquidityRestrictions,
|
|
);
|
|
assert!(<ChargeTransactionPayment<$test> as SignedExtension>::pre_dispatch(
|
|
ChargeTransactionPayment::from(1),
|
|
&1,
|
|
CALL,
|
|
&info_from_weight(1),
|
|
1,
|
|
).is_err());
|
|
assert_ok!(<ChargeTransactionPayment<$test> as SignedExtension>::pre_dispatch(
|
|
ChargeTransactionPayment::from(0),
|
|
&1,
|
|
CALL,
|
|
&info_from_weight(1),
|
|
1,
|
|
));
|
|
|
|
Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSACTION_PAYMENT);
|
|
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(
|
|
ChargeTransactionPayment::from(1),
|
|
&1,
|
|
CALL,
|
|
&info_from_weight(1),
|
|
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_extension_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
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, 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, WithdrawReasons::all());
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 3, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn lock_reasons_extension_should_work() {
|
|
<$ext_builder>::default().existential_deposit(1).monied(true).build().execute_with(|| {
|
|
Balances::set_lock(ID_1, &1, 10, WithdrawReasons::TRANSFER);
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::empty());
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
Balances::extend_lock(ID_1, &1, 10, WithdrawReasons::RESERVE);
|
|
assert_noop!(
|
|
<Balances as Currency<_>>::transfer(&1, &2, 6, AllowDeath),
|
|
Error::<$test, _>::LiquidityRestrictions
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn default_indexing_on_new_accounts_should_not_work2() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(10)
|
|
.monied(true)
|
|
.build()
|
|
.execute_with(|| {
|
|
// account 5 should not exist
|
|
// ext_deposit is 10, value is 9, not satisfies for ext_deposit
|
|
assert_noop!(
|
|
Balances::transfer(Some(1).into(), 5, 9),
|
|
Error::<$test, _>::ExistentialDeposit,
|
|
);
|
|
assert_eq!(Balances::free_balance(1), 100);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reserved_balance_should_prevent_reclaim_count() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(256 * 1)
|
|
.monied(true)
|
|
.build()
|
|
.execute_with(|| {
|
|
System::inc_account_nonce(&2);
|
|
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), 255); // "free" account deleted."
|
|
assert_eq!(Balances::total_balance(&2), 256 * 20); // reserve still exists.
|
|
assert_eq!(System::account_nonce(&2), 1);
|
|
|
|
// account 4 tries to take index 1 for account 5.
|
|
assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69));
|
|
assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69);
|
|
|
|
assert!(Balances::slash(&2, 256 * 19 + 2).1.is_zero()); // account 2 gets slashed
|
|
// "reserve" account reduced to 255 (below ED) so account deleted
|
|
assert_eq!(Balances::total_balance(&2), 0);
|
|
assert_eq!(System::account_nonce(&2), 0); // nonce zero
|
|
|
|
// account 4 tries to take index 1 again for account 6.
|
|
assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69));
|
|
assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reward_should_work() {
|
|
<$ext_builder>::default().monied(true).build().execute_with(|| {
|
|
assert_eq!(Balances::total_balance(&1), 10);
|
|
assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop));
|
|
assert_eq!(Balances::total_balance(&1), 20);
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 120);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn dust_account_removal_should_work() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.monied(true)
|
|
.build()
|
|
.execute_with(|| {
|
|
System::inc_account_nonce(&2);
|
|
assert_eq!(System::account_nonce(&2), 1);
|
|
assert_eq!(Balances::total_balance(&2), 2000);
|
|
// index 1 (account 2) becomes zombie
|
|
assert_ok!(Balances::transfer(Some(2).into(), 5, 1901));
|
|
assert_eq!(Balances::total_balance(&2), 0);
|
|
assert_eq!(Balances::total_balance(&5), 1901);
|
|
assert_eq!(System::account_nonce(&2), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn balance_works() {
|
|
<$ext_builder>::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::total_balance(&1), 42);
|
|
assert_eq!(Balances::free_balance(2), 0);
|
|
assert_eq!(Balances::reserved_balance(2), 0);
|
|
assert_eq!(Balances::total_balance(&2), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn balance_transfer_works() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
assert_ok!(Balances::transfer(Some(1).into(), 2, 69));
|
|
assert_eq!(Balances::total_balance(&1), 42);
|
|
assert_eq!(Balances::total_balance(&2), 69);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn force_transfer_works() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
assert_noop!(
|
|
Balances::force_transfer(Some(2).into(), 1, 2, 69),
|
|
BadOrigin,
|
|
);
|
|
assert_ok!(Balances::force_transfer(RawOrigin::Root.into(), 1, 2, 69));
|
|
assert_eq!(Balances::total_balance(&1), 42);
|
|
assert_eq!(Balances::total_balance(&2), 69);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn reserving_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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_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);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn balance_transfer_when_reserved_should_not_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
assert_ok!(Balances::reserve(&1, 69));
|
|
assert_noop!(
|
|
Balances::transfer(Some(1).into(), 2, 69),
|
|
Error::<$test, _>::InsufficientBalance,
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn deducting_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
assert_ok!(Balances::reserve(&1, 69));
|
|
assert_eq!(Balances::free_balance(1), 42);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn refunding_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 42);
|
|
assert_ok!(Balances::mutate_account(&1, |a| a.reserved = 69));
|
|
Balances::unreserve(&1, 69);
|
|
assert_eq!(Balances::free_balance(1), 111);
|
|
assert_eq!(Balances::reserved_balance(1), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slashing_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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!(<TotalIssuance<$test>>::get(), 42);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slashing_incomplete_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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!(<TotalIssuance<$test>>::get(), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn unreserving_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slashing_reserved_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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!(<TotalIssuance<$test>>::get(), 69);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slashing_incomplete_reserved_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
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!(<TotalIssuance<$test>>::get(), 69);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repatriating_reserved_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 110);
|
|
let _ = Balances::deposit_creating(&2, 1);
|
|
assert_ok!(Balances::reserve(&1, 110));
|
|
assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Free), 0);
|
|
System::assert_last_event(
|
|
Event::Balances(crate::Event::ReserveRepatriated(1, 2, 41, Status::Free))
|
|
);
|
|
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);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transferring_reserved_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 110);
|
|
let _ = Balances::deposit_creating(&2, 1);
|
|
assert_ok!(Balances::reserve(&1, 110));
|
|
assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Reserved), 0);
|
|
assert_eq!(Balances::reserved_balance(1), 69);
|
|
assert_eq!(Balances::free_balance(1), 0);
|
|
assert_eq!(Balances::reserved_balance(2), 41);
|
|
assert_eq!(Balances::free_balance(2), 1);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transferring_reserved_balance_to_nonexistent_should_fail() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
assert_ok!(Balances::reserve(&1, 111));
|
|
assert_noop!(Balances::repatriate_reserved(&1, &2, 42, Status::Free), Error::<$test, _>::DeadAccount);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transferring_incomplete_reserved_balance_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 110);
|
|
let _ = Balances::deposit_creating(&2, 1);
|
|
assert_ok!(Balances::reserve(&1, 41));
|
|
assert_ok!(Balances::repatriate_reserved(&1, &2, 69, Status::Free), 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);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transferring_too_high_value_should_not_panic() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
Balances::make_free_balance_be(&1, u64::MAX);
|
|
Balances::make_free_balance_be(&2, 1);
|
|
|
|
assert_err!(
|
|
Balances::transfer(Some(1).into(), 2, u64::MAX),
|
|
ArithmeticError::Overflow,
|
|
);
|
|
|
|
assert_eq!(Balances::free_balance(1), u64::MAX);
|
|
assert_eq!(Balances::free_balance(2), 1);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn account_create_on_free_too_low_with_other() {
|
|
<$ext_builder>::default().existential_deposit(100).build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 100);
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 100);
|
|
|
|
// No-op.
|
|
let _ = Balances::deposit_creating(&2, 50);
|
|
assert_eq!(Balances::free_balance(2), 0);
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 100);
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
fn account_create_on_free_too_low() {
|
|
<$ext_builder>::default().existential_deposit(100).build().execute_with(|| {
|
|
// No-op.
|
|
let _ = Balances::deposit_creating(&2, 50);
|
|
assert_eq!(Balances::free_balance(2), 0);
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 0);
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
fn account_removal_on_free_too_low() {
|
|
<$ext_builder>::default().existential_deposit(100).build().execute_with(|| {
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 0);
|
|
|
|
// Setup two accounts with free balance above the existential threshold.
|
|
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!(<TotalIssuance<$test>>::get(), 220);
|
|
|
|
// Transfer funds from account 1 of such amount that after this transfer
|
|
// the balance of account 1 will be below the existential threshold.
|
|
// This should lead to the removal of all balance of this account.
|
|
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);
|
|
|
|
// Verify that TotalIssuance tracks balance removal when free balance is too low.
|
|
assert_eq!(<TotalIssuance<$test>>::get(), 130);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn burn_must_work() {
|
|
<$ext_builder>::default().monied(true).build().execute_with(|| {
|
|
let init_total_issuance = Balances::total_issuance();
|
|
let imbalance = Balances::burn(10);
|
|
assert_eq!(Balances::total_issuance(), init_total_issuance - 10);
|
|
drop(imbalance);
|
|
assert_eq!(Balances::total_issuance(), init_total_issuance);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transfer_keep_alive_works() {
|
|
<$ext_builder>::default().existential_deposit(1).build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 100);
|
|
assert_noop!(
|
|
Balances::transfer_keep_alive(Some(1).into(), 2, 100),
|
|
Error::<$test, _>::KeepAlive
|
|
);
|
|
assert_eq!(Balances::total_balance(&1), 100);
|
|
assert_eq!(Balances::total_balance(&2), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic = "the balance of any account should always be at least the existential deposit."]
|
|
fn cannot_set_genesis_value_below_ed() {
|
|
($existential_deposit).with(|v| *v.borrow_mut() = 11);
|
|
let mut t = frame_system::GenesisConfig::default().build_storage::<$test>().unwrap();
|
|
let _ = pallet_balances::GenesisConfig::<$test> {
|
|
balances: vec![(1, 10)],
|
|
}.assimilate_storage(&mut t).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic = "duplicate balances in genesis."]
|
|
fn cannot_set_genesis_value_twice() {
|
|
let mut t = frame_system::GenesisConfig::default().build_storage::<$test>().unwrap();
|
|
let _ = pallet_balances::GenesisConfig::<$test> {
|
|
balances: vec![(1, 10), (2, 20), (1, 15)],
|
|
}.assimilate_storage(&mut t).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn dust_moves_between_free_and_reserved() {
|
|
<$ext_builder>::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, 0));
|
|
// Check balance
|
|
assert_eq!(Balances::free_balance(1), 100);
|
|
assert_eq!(Balances::reserved_balance(1), 0);
|
|
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
// 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() {
|
|
<$ext_builder>::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 res = Balances::slash(&1, 1);
|
|
assert_eq!(res, (NegativeImbalance::new(1), 0));
|
|
|
|
// The account should be dead.
|
|
assert_eq!(Balances::free_balance(1), 0);
|
|
assert_eq!(Balances::reserved_balance(1), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn emit_events_with_reserve_and_unreserve() {
|
|
<$ext_builder>::default()
|
|
.build()
|
|
.execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 100);
|
|
|
|
System::set_block_number(2);
|
|
assert_ok!(Balances::reserve(&1, 10));
|
|
|
|
System::assert_last_event(Event::Balances(crate::Event::Reserved(1, 10)));
|
|
|
|
System::set_block_number(3);
|
|
assert!(Balances::unreserve(&1, 5).is_zero());
|
|
|
|
System::assert_last_event(Event::Balances(crate::Event::Unreserved(1, 5)));
|
|
|
|
System::set_block_number(4);
|
|
assert_eq!(Balances::unreserve(&1, 6), 1);
|
|
|
|
// should only unreserve 5
|
|
System::assert_last_event(Event::Balances(crate::Event::Unreserved(1, 5)));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn emit_events_with_existential_deposit() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.build()
|
|
.execute_with(|| {
|
|
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0));
|
|
|
|
assert_eq!(
|
|
events(),
|
|
[
|
|
Event::System(system::Event::NewAccount(1)),
|
|
Event::Balances(crate::Event::Endowed(1, 100)),
|
|
Event::Balances(crate::Event::BalanceSet(1, 100, 0)),
|
|
]
|
|
);
|
|
|
|
let res = Balances::slash(&1, 1);
|
|
assert_eq!(res, (NegativeImbalance::new(1), 0));
|
|
|
|
assert_eq!(
|
|
events(),
|
|
[
|
|
Event::System(system::Event::KilledAccount(1)),
|
|
Event::Balances(crate::Event::DustLost(1, 99)),
|
|
]
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn emit_events_with_no_existential_deposit_suicide() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(1)
|
|
.build()
|
|
.execute_with(|| {
|
|
assert_ok!(Balances::set_balance(RawOrigin::Root.into(), 1, 100, 0));
|
|
|
|
assert_eq!(
|
|
events(),
|
|
[
|
|
Event::System(system::Event::NewAccount(1)),
|
|
Event::Balances(crate::Event::Endowed(1, 100)),
|
|
Event::Balances(crate::Event::BalanceSet(1, 100, 0)),
|
|
]
|
|
);
|
|
|
|
let res = Balances::slash(&1, 100);
|
|
assert_eq!(res, (NegativeImbalance::new(100), 0));
|
|
|
|
assert_eq!(
|
|
events(),
|
|
[
|
|
Event::System(system::Event::KilledAccount(1))
|
|
]
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slash_loop_works() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.build()
|
|
.execute_with(|| {
|
|
/* User has no reference counter, so they can die in these scenarios */
|
|
|
|
// SCENARIO: Slash would not kill account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Slash will kill account because not enough balance left.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(950), 0));
|
|
// Account is killed
|
|
assert!(!System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash will kill account, and report missing slash amount.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
// Slashed full free_balance, and reports 300 not slashed
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1000), 300));
|
|
// Account is dead
|
|
assert!(!System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take from reserved, but keep alive.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400));
|
|
// Slashed full free_balance and 300 of reserved balance
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take from reserved, and kill.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350));
|
|
// Slashed full free_balance and 300 of reserved balance
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0));
|
|
// Account is dead because 50 reserved balance is not enough to keep alive
|
|
assert!(!System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take as much as possible from reserved, kill, and report missing amount.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250));
|
|
// Slashed full free_balance and 300 of reserved balance
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50));
|
|
// Account is super dead
|
|
assert!(!System::account_exists(&1));
|
|
|
|
/* User will now have a reference counter on them, keeping them alive in these scenarios */
|
|
|
|
// SCENARIO: Slash would not kill account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Slash will take as much as possible without killing account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(900), 50));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash will not kill account, and report missing slash amount.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0));
|
|
// Slashed full free_balance minus ED, and reports 400 not slashed
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(900), 400));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take from reserved, but keep alive.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400));
|
|
// Slashed full free_balance and 300 of reserved balance
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take from reserved, but keep alive.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350));
|
|
// Slashed full free_balance and 250 of reserved balance to leave ED
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash can take as much as possible from reserved and report missing amount.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250));
|
|
// Slashed full free_balance and 300 of reserved balance
|
|
assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1150), 150));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// Slash on non-existent account is okay.
|
|
assert_eq!(Balances::slash(&12345, 1_300), (NegativeImbalance::new(0), 1300));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slash_reserved_loop_works() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.build()
|
|
.execute_with(|| {
|
|
/* User has no reference counter, so they can die in these scenarios */
|
|
|
|
// SCENARIO: Slash would not kill account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Slash would kill account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(1_000), 0));
|
|
// Account is dead
|
|
assert!(!System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash would kill account, and reports left over slash.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300));
|
|
// Account is dead
|
|
assert!(!System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash does not take from free balance.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 300, 1_000));
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300));
|
|
// Account is alive because of free balance
|
|
assert!(System::account_exists(&1));
|
|
|
|
/* User has a reference counter, so they cannot die */
|
|
|
|
// SCENARIO: Slash would not kill account.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests
|
|
// Slashed completed in full
|
|
assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Slash as much as possible without killing.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
// Slashed as much as possible
|
|
assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(950), 50));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash reports correctly, where reserved is needed to keep alive.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000));
|
|
// Slashed as much as possible
|
|
assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(950), 350));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// SCENARIO: Over-slash reports correctly, where full reserved is removed.
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 1_000));
|
|
// Slashed as much as possible
|
|
assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300));
|
|
// Account is still alive
|
|
assert!(System::account_exists(&1));
|
|
|
|
// Slash on non-existent account is okay.
|
|
assert_eq!(Balances::slash_reserved(&12345, 1_300), (NegativeImbalance::new(0), 1300));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn operations_on_dead_account_should_not_change_state() {
|
|
// These functions all use `mutate_account` which may introduce a storage change when
|
|
// the account never existed to begin with, and shouldn't exist in the end.
|
|
<$ext_builder>::default()
|
|
.existential_deposit(0)
|
|
.build()
|
|
.execute_with(|| {
|
|
assert!(!frame_system::Account::<Test>::contains_key(&1337));
|
|
|
|
// Unreserve
|
|
assert_storage_noop!(assert_eq!(Balances::unreserve(&1337, 42), 42));
|
|
// Reserve
|
|
assert_noop!(Balances::reserve(&1337, 42), Error::<Test, _>::InsufficientBalance);
|
|
// Slash Reserve
|
|
assert_storage_noop!(assert_eq!(Balances::slash_reserved(&1337, 42).1, 42));
|
|
// Repatriate Reserve
|
|
assert_noop!(Balances::repatriate_reserved(&1337, &1338, 42, Status::Free), Error::<Test, _>::DeadAccount);
|
|
// Slash
|
|
assert_storage_noop!(assert_eq!(Balances::slash(&1337, 42).1, 42));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transfer_keep_alive_all_free_succeed() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.build()
|
|
.execute_with(|| {
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 100, 100));
|
|
assert_ok!(Balances::transfer_keep_alive(Some(1).into(), 2, 100));
|
|
assert_eq!(Balances::total_balance(&1), 100);
|
|
assert_eq!(Balances::total_balance(&2), 100);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn transfer_all_works() {
|
|
<$ext_builder>::default()
|
|
.existential_deposit(100)
|
|
.build()
|
|
.execute_with(|| {
|
|
// setup
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0));
|
|
assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0));
|
|
// transfer all and allow death
|
|
assert_ok!(Balances::transfer_all(Some(1).into(), 2, false));
|
|
assert_eq!(Balances::total_balance(&1), 0);
|
|
assert_eq!(Balances::total_balance(&2), 200);
|
|
|
|
// setup
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0));
|
|
assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0));
|
|
// transfer all and keep alive
|
|
assert_ok!(Balances::transfer_all(Some(1).into(), 2, true));
|
|
assert_eq!(Balances::total_balance(&1), 100);
|
|
assert_eq!(Balances::total_balance(&2), 100);
|
|
|
|
// setup
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10));
|
|
assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0));
|
|
// transfer all and allow death w/ reserved
|
|
assert_ok!(Balances::transfer_all(Some(1).into(), 2, false));
|
|
assert_eq!(Balances::total_balance(&1), 0);
|
|
assert_eq!(Balances::total_balance(&2), 200);
|
|
|
|
// setup
|
|
assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10));
|
|
assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0));
|
|
// transfer all and keep alive w/ reserved
|
|
assert_ok!(Balances::transfer_all(Some(1).into(), 2, true));
|
|
assert_eq!(Balances::total_balance(&1), 100);
|
|
assert_eq!(Balances::total_balance(&2), 110);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn named_reserve_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
|
|
let id_1 = [1u8; 8];
|
|
let id_2 = [2u8; 8];
|
|
let id_3 = [3u8; 8];
|
|
|
|
// reserve
|
|
|
|
assert_noop!(Balances::reserve_named(&id_1, &1, 112), Error::<Test, _>::InsufficientBalance);
|
|
|
|
assert_ok!(Balances::reserve_named(&id_1, &1, 12));
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 12);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 12);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0);
|
|
|
|
assert_ok!(Balances::reserve_named(&id_1, &1, 2));
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 14);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0);
|
|
|
|
assert_ok!(Balances::reserve_named(&id_2, &1, 23));
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 37);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23);
|
|
|
|
assert_ok!(Balances::reserve(&1, 34));
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 71);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 14);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23);
|
|
|
|
assert_eq!(Balances::total_balance(&1), 111);
|
|
assert_eq!(Balances::free_balance(1), 40);
|
|
|
|
assert_noop!(Balances::reserve_named(&id_3, &1, 2), Error::<Test, _>::TooManyReserves);
|
|
|
|
// unreserve
|
|
|
|
assert_eq!(Balances::unreserve_named(&id_1, &1, 10), 0);
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 61);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 4);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23);
|
|
|
|
assert_eq!(Balances::unreserve_named(&id_1, &1, 5), 1);
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 57);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 23);
|
|
|
|
assert_eq!(Balances::unreserve_named(&id_2, &1, 3), 0);
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 54);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20);
|
|
|
|
assert_eq!(Balances::total_balance(&1), 111);
|
|
assert_eq!(Balances::free_balance(1), 57);
|
|
|
|
// slash_reserved_named
|
|
|
|
assert_ok!(Balances::reserve_named(&id_1, &1, 10));
|
|
|
|
assert_eq!(Balances::slash_reserved_named(&id_1, &1, 25).1, 15);
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 54);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 20);
|
|
assert_eq!(Balances::total_balance(&1), 101);
|
|
|
|
assert_eq!(Balances::slash_reserved_named(&id_2, &1, 5).1, 0);
|
|
|
|
assert_eq!(Balances::reserved_balance(1), 49);
|
|
assert_eq!(Balances::reserved_balance_named(&id_1, &1), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15);
|
|
assert_eq!(Balances::total_balance(&1), 96);
|
|
|
|
// repatriate_reserved_named
|
|
|
|
let _ = Balances::deposit_creating(&2, 100);
|
|
|
|
assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Status::Reserved).unwrap(), 0);
|
|
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &2), 10);
|
|
assert_eq!(Balances::reserved_balance(&2), 10);
|
|
|
|
assert_eq!(Balances::repatriate_reserved_named(&id_2, &2, &1, 11, Status::Reserved).unwrap(), 1);
|
|
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 15);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0);
|
|
assert_eq!(Balances::reserved_balance(&2), 0);
|
|
|
|
assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &2, 10, Status::Free).unwrap(), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &2), 0);
|
|
assert_eq!(Balances::free_balance(&2), 110);
|
|
|
|
// repatriate_reserved_named to self
|
|
|
|
assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 10, Status::Reserved).unwrap(), 5);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 5);
|
|
|
|
assert_eq!(Balances::free_balance(&1), 47);
|
|
|
|
assert_eq!(Balances::repatriate_reserved_named(&id_2, &1, &1, 15, Status::Free).unwrap(), 10);
|
|
assert_eq!(Balances::reserved_balance_named(&id_2, &1), 0);
|
|
|
|
assert_eq!(Balances::free_balance(&1), 52);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn ensure_reserved_named_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
|
|
let id = [1u8; 8];
|
|
|
|
assert_ok!(Balances::ensure_reserved_named(&id, &1, 15));
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 15);
|
|
|
|
assert_ok!(Balances::ensure_reserved_named(&id, &1, 10));
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 10);
|
|
|
|
assert_ok!(Balances::ensure_reserved_named(&id, &1, 20));
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 20);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn unreserve_all_named_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
|
|
let id = [1u8; 8];
|
|
|
|
assert_ok!(Balances::reserve_named(&id, &1, 15));
|
|
|
|
assert_eq!(Balances::unreserve_all_named(&id, &1), 15);
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 0);
|
|
assert_eq!(Balances::free_balance(&1), 111);
|
|
|
|
assert_eq!(Balances::unreserve_all_named(&id, &1), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn slash_all_reserved_named_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
|
|
let id = [1u8; 8];
|
|
|
|
assert_ok!(Balances::reserve_named(&id, &1, 15));
|
|
|
|
assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 15);
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 0);
|
|
assert_eq!(Balances::free_balance(&1), 96);
|
|
|
|
assert_eq!(Balances::slash_all_reserved_named(&id, &1).peek(), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn repatriate_all_reserved_named_should_work() {
|
|
<$ext_builder>::default().build().execute_with(|| {
|
|
let _ = Balances::deposit_creating(&1, 111);
|
|
let _ = Balances::deposit_creating(&2, 10);
|
|
let _ = Balances::deposit_creating(&3, 10);
|
|
|
|
let id = [1u8; 8];
|
|
|
|
assert_ok!(Balances::reserve_named(&id, &1, 15));
|
|
|
|
assert_ok!(Balances::repatriate_all_reserved_named(&id, &1, &2, Status::Reserved));
|
|
assert_eq!(Balances::reserved_balance_named(&id, &1), 0);
|
|
assert_eq!(Balances::reserved_balance_named(&id, &2), 15);
|
|
|
|
assert_ok!(Balances::repatriate_all_reserved_named(&id, &2, &3, Status::Free));
|
|
assert_eq!(Balances::reserved_balance_named(&id, &2), 0);
|
|
assert_eq!(Balances::free_balance(&3), 25);
|
|
});
|
|
}
|
|
}
|
|
}
|