Files
pezkuwi-sdk/bizinikiwi/pezframe/assets-holder/src/tests.rs
T
pezkuwichain 90fd044766 fix: Complete snowbridge pezpallet rebrand and critical bug fixes
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs)
- pallet/ directories → pezpallet/ (4 locations)
- Fixed pezpallet.rs self-include recursion bug
- Fixed sc-chain-spec hardcoded crate name in derive macro
- Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API)
- Added BizinikiwiConfig type alias for zombienet tests
- Deleted obsolete session state files

Verified: pezsnowbridge-pezpallet-*, pezpallet-staking,
pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
2025-12-16 09:57:23 +03:00

559 lines
15 KiB
Rust

// This file is part of Bizinikiwi.
// Copyright (C) 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.
//! Tests for pezpallet-assets-holder.
use crate::mock::*;
use pezframe_support::{
assert_noop, assert_ok,
traits::tokens::fungibles::{Inspect, InspectHold, MutateHold, UnbalancedHold},
};
use pezpallet_assets::BalanceOnHold;
const WHO: AccountId = 1;
const ASSET_ID: AssetId = 1;
fn test_hold(id: DummyHoldReason, amount: Balance) {
assert_ok!(AssetsHolder::set_balance_on_hold(ASSET_ID, &id, &WHO, amount));
}
fn test_release(id: DummyHoldReason) {
assert_ok!(AssetsHolder::set_balance_on_hold(ASSET_ID, &id, &WHO, 0));
}
mod impl_balance_on_hold {
use super::*;
#[test]
fn balance_on_hold_works() {
new_test_ext(|| {
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
None
);
test_hold(DummyHoldReason::Governance, 1);
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
Some(1u64)
);
test_hold(DummyHoldReason::Staking, 3);
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
Some(4u64)
);
test_hold(DummyHoldReason::Governance, 2);
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
Some(5u64)
);
// also test releasing works to reduce a balance, and finally releasing everything
// resets to None
test_release(DummyHoldReason::Governance);
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
Some(3u64)
);
test_release(DummyHoldReason::Staking);
assert_eq!(
<AssetsHolder as BalanceOnHold<_, _, _>>::balance_on_hold(ASSET_ID, &WHO),
None
);
});
}
#[test]
#[should_panic = "The list of Holds should be empty before allowing an account to die"]
fn died_fails_if_holds_exist() {
new_test_ext(|| {
test_hold(DummyHoldReason::Governance, 1);
AssetsHolder::died(ASSET_ID, &WHO);
});
}
#[test]
fn died_works() {
new_test_ext(|| {
test_hold(DummyHoldReason::Governance, 1);
test_release(DummyHoldReason::Governance);
AssetsHolder::died(ASSET_ID, &WHO);
assert!(BalancesOnHold::<Test>::get(ASSET_ID, WHO).is_none());
assert!(Holds::<Test>::get(ASSET_ID, WHO).is_empty());
});
}
}
mod impl_hold_inspect {
use super::*;
#[test]
fn total_balance_on_hold_works() {
new_test_ext(|| {
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 0u64);
test_hold(DummyHoldReason::Governance, 1);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 1u64);
test_hold(DummyHoldReason::Staking, 3);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 4u64);
test_hold(DummyHoldReason::Governance, 2);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 5u64);
// also test release to reduce a balance, and finally releasing everything resets to
// 0
test_release(DummyHoldReason::Governance);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 3u64);
test_release(DummyHoldReason::Staking);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 0u64);
});
}
#[test]
fn balance_on_hold_works() {
new_test_ext(|| {
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
0u64
);
test_hold(DummyHoldReason::Governance, 1);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
1u64
);
test_hold(DummyHoldReason::Staking, 3);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO
),
3u64
);
test_hold(DummyHoldReason::Staking, 2);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO
),
2u64
);
// also test release to reduce a balance, and finally releasing everything resets to
// 0
test_release(DummyHoldReason::Governance);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
0u64
);
test_release(DummyHoldReason::Staking);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO
),
0u64
);
});
}
}
mod impl_hold_unbalanced {
use super::*;
// Note: Tests for `handle_dust`, `write_balance`, `set_total_issuance`, `decrease_balance`
// and `increase_balance` are intentionally left out without testing, since:
// 1. It is expected these methods are tested within `pezpallet-assets`, and
// 2. There are no valid cases that can be directly asserted using those methods in
// the scope of this pezpallet.
#[test]
fn set_balance_on_hold_works() {
new_test_ext(|| {
assert_eq!(Holds::<Test>::get(ASSET_ID, WHO).to_vec(), vec![]);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), None);
// Adding balance on hold works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
1
));
assert_eq!(
Holds::<Test>::get(ASSET_ID, WHO).to_vec(),
vec![IdAmount { id: DummyHoldReason::Governance, amount: 1 }]
);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), Some(1));
// Increasing hold works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
3
));
assert_eq!(
Holds::<Test>::get(ASSET_ID, WHO).to_vec(),
vec![IdAmount { id: DummyHoldReason::Governance, amount: 3 }]
);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), Some(3));
// Adding new balance on hold works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO,
2
));
assert_eq!(
Holds::<Test>::get(ASSET_ID, WHO).to_vec(),
vec![
IdAmount { id: DummyHoldReason::Governance, amount: 3 },
IdAmount { id: DummyHoldReason::Staking, amount: 2 }
]
);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), Some(5));
// Note: Assertion skipped to meet @gavofyork's suggestion of matching the number of
// variant count with the number of enum's variants.
// // Adding more than max holds fails
// assert_noop!(
// AssetsHolder::set_balance_on_hold(ASSET_ID, &DummyHoldReason::Other, &WHO, 1),
// Error::<Test>::TooManyHolds
// );
// Decreasing balance on hold works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO,
1
));
assert_eq!(
Holds::<Test>::get(ASSET_ID, WHO).to_vec(),
vec![
IdAmount { id: DummyHoldReason::Governance, amount: 3 },
IdAmount { id: DummyHoldReason::Staking, amount: 1 }
]
);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), Some(4));
// Decreasing until removal of balance on hold works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
0
));
assert_eq!(
Holds::<Test>::get(ASSET_ID, WHO).to_vec(),
vec![IdAmount { id: DummyHoldReason::Staking, amount: 1 }]
);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), Some(1));
// Clearing ol all holds works
assert_ok!(AssetsHolder::set_balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO,
0
));
assert_eq!(Holds::<Test>::get(ASSET_ID, WHO).to_vec(), vec![]);
assert_eq!(BalancesOnHold::<Test>::get(ASSET_ID, WHO), None);
});
}
}
mod impl_hold_mutate {
use super::*;
use pezframe_support::traits::tokens::{Fortitude, Precision, Preservation};
use pezsp_runtime::TokenError;
#[test]
fn hold_works() {
super::new_test_ext(|| {
// Holding some `amount` would decrease the asset account balance and change the
// reducible balance, while total issuance is preserved.
assert_ok!(AssetsHolder::hold(ASSET_ID, &DummyHoldReason::Governance, &WHO, 10));
assert_eq!(Assets::balance(ASSET_ID, &WHO), 90);
// Reducible balance is tested once to ensure token balance model is compliant.
assert_eq!(
Assets::reducible_balance(
ASSET_ID,
&WHO,
Preservation::Expendable,
Fortitude::Force
),
89
);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
10
);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 10);
// Holding preserves `total_balance`
assert_eq!(Assets::total_balance(ASSET_ID, &WHO), 100);
// Holding preserves `total_issuance`
assert_eq!(Assets::total_issuance(ASSET_ID), 100);
// Increasing the amount on hold for the same reason has the same effect as described
// above in `set_balance_on_hold_works`, while total issuance is preserved.
// Consideration: holding for an amount `x` will increase the already amount on hold by
// `x`.
assert_ok!(AssetsHolder::hold(ASSET_ID, &DummyHoldReason::Governance, &WHO, 20));
assert_eq!(Assets::balance(ASSET_ID, &WHO), 70);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
30
);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 30);
assert_eq!(Assets::total_issuance(ASSET_ID), 100);
// Holding some amount for a different reason has the same effect as described above in
// `set_balance_on_hold_works`, while total issuance is preserved.
assert_ok!(AssetsHolder::hold(ASSET_ID, &DummyHoldReason::Staking, &WHO, 20));
assert_eq!(Assets::balance(ASSET_ID, &WHO), 50);
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Staking,
&WHO
),
20
);
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 50);
assert_eq!(Assets::total_issuance(ASSET_ID), 100);
});
}
fn new_test_ext() -> pezsp_io::TestExternalities {
super::new_test_ext(|| {
assert_ok!(AssetsHolder::hold(ASSET_ID, &DummyHoldReason::Governance, &WHO, 30));
assert_ok!(AssetsHolder::hold(ASSET_ID, &DummyHoldReason::Staking, &WHO, 20));
})
}
#[test]
fn release_works() {
// Releasing up to some amount will increase the balance by the released
// amount, while preserving total issuance.
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::release(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
20,
Precision::Exact,
));
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
10
);
assert_eq!(Assets::balance(ASSET_ID, WHO), 70);
});
// Releasing over the max amount on hold with `BestEffort` will increase the
// balance by the previously amount on hold, while preserving total issuance.
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::release(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
31,
Precision::BestEffort,
));
assert_eq!(
<AssetsHolder as InspectHold<_>>::balance_on_hold(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO
),
0
);
assert_eq!(Assets::balance(ASSET_ID, WHO), 80);
});
// Releasing over the max amount on hold with `Exact` will fail.
new_test_ext().execute_with(|| {
assert_noop!(
AssetsHolder::release(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
31,
Precision::Exact,
),
TokenError::FundsUnavailable
);
});
}
#[test]
fn burn_held_works() {
// Burning works, reducing total issuance and `total_balance`.
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::burn_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
1,
Precision::BestEffort,
Fortitude::Polite
));
assert_eq!(Assets::total_balance(ASSET_ID, &WHO), 99);
assert_eq!(Assets::total_issuance(ASSET_ID), 99);
});
// Burning by an amount up to the balance on hold with `Exact` works, reducing balance on
// hold up to the given amount.
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::burn_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
10,
Precision::Exact,
Fortitude::Polite
));
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 40);
assert_eq!(Assets::balance(ASSET_ID, WHO), 50);
});
// Burning by an amount over the balance on hold with `BestEffort` works, reducing balance
// on hold up to the given amount.
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::burn_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
31,
Precision::BestEffort,
Fortitude::Polite
));
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 20);
assert_eq!(Assets::balance(ASSET_ID, WHO), 50);
});
// Burning by an amount over the balance on hold with `Exact` fails.
new_test_ext().execute_with(|| {
assert_noop!(
AssetsHolder::burn_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
31,
Precision::Exact,
Fortitude::Polite
),
TokenError::FundsUnavailable
);
});
}
#[test]
fn burn_all_held_works() {
new_test_ext().execute_with(|| {
// Burning all balance on hold works as burning passing it as amount with `BestEffort`
assert_ok!(AssetsHolder::burn_all_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
Precision::BestEffort,
Fortitude::Polite,
));
assert_eq!(AssetsHolder::total_balance_on_hold(ASSET_ID, &WHO), 20);
assert_eq!(Assets::balance(ASSET_ID, WHO), 50);
});
}
#[test]
fn done_held_works() {
new_test_ext().execute_with(|| {
System::assert_has_event(
Event::<Test>::Held {
who: WHO,
asset_id: ASSET_ID,
reason: DummyHoldReason::Governance,
amount: 30,
}
.into(),
);
});
}
#[test]
fn done_release_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::release(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
31,
Precision::BestEffort
));
System::assert_has_event(
Event::<Test>::Released {
who: WHO,
asset_id: ASSET_ID,
reason: DummyHoldReason::Governance,
amount: 30,
}
.into(),
);
});
}
#[test]
fn done_burn_held_works() {
new_test_ext().execute_with(|| {
assert_ok!(AssetsHolder::burn_all_held(
ASSET_ID,
&DummyHoldReason::Governance,
&WHO,
Precision::BestEffort,
Fortitude::Polite,
));
System::assert_has_event(
Event::<Test>::Burned {
who: WHO,
asset_id: ASSET_ID,
reason: DummyHoldReason::Governance,
amount: 30,
}
.into(),
);
});
}
}