mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 05:47:58 +00:00
0b74812ce8
Introduces `UnionOf` types, crafted to merge `fungible` and `fungibles` implementations or two `fungibles` implementations into a single type implementing `fungibles`. This also addresses an issue where `ItemOf` initiates a double drop for an imbalance type, leading to inaccurate total issuance accounting. Find the application of these types in this PR - [link](https://github.com/paritytech/polkadot-sdk/pull/2031), places in code - [1](https://github.com/paritytech/polkadot-sdk/blob/4ec7496fa2632385b08fae860fcf28a523a7b5de/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs#L327), [2](https://github.com/paritytech/polkadot-sdk/blob/4ec7496fa2632385b08fae860fcf28a523a7b5de/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs#L343). --------- Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: joepetrowski <joe@parity.io>
347 lines
12 KiB
Rust
347 lines
12 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// 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 [`ItemOf`], [`fungible::UnionOf`] and [`fungibles::UnionOf`] set types.
|
|
|
|
use super::*;
|
|
use frame_support::{
|
|
parameter_types,
|
|
traits::{
|
|
fungible,
|
|
fungible::ItemOf,
|
|
fungibles,
|
|
tokens::{
|
|
fungibles::{
|
|
Balanced as FungiblesBalanced, Create as FungiblesCreate,
|
|
Inspect as FungiblesInspect, Mutate as FungiblesMutate,
|
|
},
|
|
Fortitude, Precision, Preservation,
|
|
},
|
|
},
|
|
};
|
|
use sp_runtime::{traits::ConvertToValue, Either};
|
|
|
|
const FIRST_ASSET: u32 = 0;
|
|
const UNKNOWN_ASSET: u32 = 10;
|
|
|
|
parameter_types! {
|
|
pub const LeftAsset: Either<(), u32> = Either::Left(());
|
|
pub const RightAsset: Either<u32, ()> = Either::Right(());
|
|
pub const RightUnitAsset: Either<(), ()> = Either::Right(());
|
|
}
|
|
|
|
/// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a
|
|
/// single asset class from [`T`] identified by [`FIRST_ASSET`].
|
|
type FirstFungible<T> = ItemOf<T, frame_support::traits::ConstU32<{ FIRST_ASSET }>, u64>;
|
|
|
|
/// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a
|
|
/// single asset class from [`T`] identified by [`UNKNOWN_ASSET`].
|
|
type UnknownFungible<T> = ItemOf<T, frame_support::traits::ConstU32<{ UNKNOWN_ASSET }>, u64>;
|
|
|
|
/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes
|
|
/// the [`FirstFungible`] from the left.
|
|
type LeftFungible<T> = fungible::UnionOf<FirstFungible<T>, T, ConvertToValue<LeftAsset>, (), u64>;
|
|
|
|
/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes
|
|
/// the [`LeftFungible`] from the right.
|
|
type RightFungible<T> =
|
|
fungible::UnionOf<UnknownFungible<T>, LeftFungible<T>, ConvertToValue<RightUnitAsset>, (), u64>;
|
|
|
|
/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes
|
|
/// the [`RightFungible`] from the left.
|
|
type LeftFungibles<T> = fungibles::UnionOf<RightFungible<T>, T, ConvertToValue<LeftAsset>, (), u64>;
|
|
|
|
/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes
|
|
/// the [`LeftFungibles`] from the right.
|
|
///
|
|
/// By using this type, we can navigate through each branch of [`fungible::UnionOf`],
|
|
/// [`fungibles::UnionOf`], and [`ItemOf`] to access the underlying `fungibles::*`
|
|
/// implementation provided by the pallet.
|
|
type First<T> = fungibles::UnionOf<T, LeftFungibles<T>, ConvertToValue<RightAsset>, (), u64>;
|
|
|
|
#[test]
|
|
fn deposit_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1 = 0;
|
|
let account1 = 1;
|
|
let account2 = 2;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, 1));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::deposit((), &account2, 50, Precision::Exact).unwrap();
|
|
assert_eq!(First::<Assets>::balance((), &account2), 50);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
|
|
assert_eq!(imb.peek(), 50);
|
|
|
|
let (imb1, imb2) = imb.split(30);
|
|
assert_eq!(imb1.peek(), 30);
|
|
assert_eq!(imb2.peek(), 20);
|
|
|
|
drop(imb2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 120);
|
|
|
|
assert!(First::<Assets>::settle(&account1, imb1, Preservation::Preserve).is_ok());
|
|
assert_eq!(First::<Assets>::balance((), &account1), 70);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 50);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 120);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn issue_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1: u32 = 0;
|
|
let account1: u64 = 1;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, 1));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
|
|
assert_eq!(First::<Assets>::balance((), &account1), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::issue((), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
assert_eq!(imb.peek(), 100);
|
|
|
|
let (imb1, imb2) = imb.split(30);
|
|
assert_eq!(imb1.peek(), 30);
|
|
assert_eq!(imb2.peek(), 70);
|
|
|
|
drop(imb2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 130);
|
|
|
|
assert!(First::<Assets>::resolve(&account1, imb1).is_ok());
|
|
assert_eq!(First::<Assets>::balance((), &account1), 130);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 130);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn pair_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1: u32 = 0;
|
|
let account1: u64 = 1;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, 1));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
|
|
assert_eq!(First::<Assets>::balance((), &account1), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let (debt, credit) = First::<Assets>::pair((), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(debt.peek(), 100);
|
|
assert_eq!(credit.peek(), 100);
|
|
|
|
let (debt1, debt2) = debt.split(30);
|
|
assert_eq!(debt1.peek(), 30);
|
|
assert_eq!(debt2.peek(), 70);
|
|
|
|
drop(debt2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 170);
|
|
|
|
assert!(First::<Assets>::settle(&account1, debt1, Preservation::Preserve).is_ok());
|
|
assert_eq!(First::<Assets>::balance((), &account1), 70);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 170);
|
|
|
|
let (credit1, credit2) = credit.split(40);
|
|
assert_eq!(credit1.peek(), 40);
|
|
assert_eq!(credit2.peek(), 60);
|
|
|
|
drop(credit2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 110);
|
|
|
|
assert!(First::<Assets>::resolve(&account1, credit1).is_ok());
|
|
assert_eq!(First::<Assets>::balance((), &account1), 110);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 110);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn rescind_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1: u32 = 0;
|
|
let account1: u64 = 1;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, 1));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::rescind((), 20);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 80);
|
|
|
|
assert_eq!(imb.peek(), 20);
|
|
|
|
let (imb1, imb2) = imb.split(15);
|
|
assert_eq!(imb1.peek(), 15);
|
|
assert_eq!(imb2.peek(), 5);
|
|
|
|
drop(imb2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 85);
|
|
|
|
assert!(First::<Assets>::settle(&account1, imb1, Preservation::Preserve).is_ok());
|
|
assert_eq!(First::<Assets>::balance((), &account1), 85);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 85);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1: u32 = 0;
|
|
let account1: u64 = 1;
|
|
let account2: u64 = 2;
|
|
let ed = 11;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, ed));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
|
|
assert_eq!(First::<Assets>::balance((), &account1), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::issue((), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
assert_eq!(imb.peek(), 100);
|
|
|
|
let (imb1, imb2) = imb.split(10);
|
|
assert_eq!(imb1.peek(), 10);
|
|
assert_eq!(imb2.peek(), 90);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
|
|
// ed requirements not met.
|
|
let imb1 = First::<Assets>::resolve(&account2, imb1).unwrap_err();
|
|
assert_eq!(imb1.peek(), 10);
|
|
drop(imb1);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 190);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 0);
|
|
|
|
// resolve to new account `2`.
|
|
assert_ok!(First::<Assets>::resolve(&account2, imb2));
|
|
assert_eq!(First::<Assets>::total_issuance(()), 190);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 90);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn settle_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1: u32 = 0;
|
|
let account1: u64 = 1;
|
|
let account2: u64 = 2;
|
|
let ed = 11;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, ed));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
assert_ok!(Assets::mint_into(asset1, &account2, 100));
|
|
|
|
assert_eq!(First::<Assets>::balance((), &account2), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::rescind((), 100);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
assert_eq!(imb.peek(), 100);
|
|
|
|
let (imb1, imb2) = imb.split(10);
|
|
assert_eq!(imb1.peek(), 10);
|
|
assert_eq!(imb2.peek(), 90);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
|
|
// ed requirements not met.
|
|
let imb2 = First::<Assets>::settle(&account2, imb2, Preservation::Preserve).unwrap_err();
|
|
assert_eq!(imb2.peek(), 90);
|
|
drop(imb2);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 190);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 100);
|
|
|
|
// settle to account `1`.
|
|
assert_ok!(First::<Assets>::settle(&account2, imb1, Preservation::Preserve));
|
|
assert_eq!(First::<Assets>::total_issuance(()), 190);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 90);
|
|
|
|
let imb = First::<Assets>::rescind((), 85);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 105);
|
|
assert_eq!(imb.peek(), 85);
|
|
|
|
// settle to account `1` and expect some dust.
|
|
let imb = First::<Assets>::settle(&account2, imb, Preservation::Expendable).unwrap();
|
|
assert_eq!(imb.peek(), 5);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 105);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 0);
|
|
|
|
drop(imb);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 100);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn withdraw_from_set_types_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let asset1 = 0;
|
|
let account1 = 1;
|
|
let account2 = 2;
|
|
|
|
assert_ok!(<Assets as FungiblesCreate<u64>>::create(asset1, account1, true, 1));
|
|
assert_ok!(Assets::mint_into(asset1, &account1, 100));
|
|
assert_ok!(Assets::mint_into(asset1, &account2, 100));
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
|
|
let imb = First::<Assets>::withdraw(
|
|
(),
|
|
&account2,
|
|
50,
|
|
Precision::Exact,
|
|
Preservation::Preserve,
|
|
Fortitude::Polite,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(First::<Assets>::balance((), &account2), 50);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 200);
|
|
|
|
assert_eq!(imb.peek(), 50);
|
|
drop(imb);
|
|
assert_eq!(First::<Assets>::total_issuance(()), 150);
|
|
assert_eq!(First::<Assets>::balance((), &account2), 50);
|
|
|
|
assert_eq!(First::<Assets>::total_issuance(()), Assets::total_issuance(asset1));
|
|
});
|
|
}
|