Skip to content

Commit

Permalink
Statemine more test (#2381)
Browse files Browse the repository at this point in the history
* statemine more test

* statemine ksm transfer

* self sufficient asset as fee works

* fmt

* udpate

* Remove out of scope tests.

Co-authored-by: Shaun Wang <spxwang@gmail.com>
  • Loading branch information
zqhxuyuan and shaunxw authored Oct 18, 2022
1 parent 155a3f4 commit a50082b
Showing 1 changed file with 193 additions and 50 deletions.
243 changes: 193 additions & 50 deletions runtime/integration-tests/src/relaychain/statemine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use frame_support::assert_ok;
pub use orml_traits::GetByKey;
use polkadot_parachain::primitives::Sibling;
use primitives::currency::AssetMetadata;
use sp_runtime::traits::AccountIdConversion;
use xcm::v1::{Junction, MultiLocation};
use xcm_emulator::TestExt;

Expand All @@ -34,6 +35,8 @@ pub const TEN: Balance = 10_000_000_000_000;
pub const FEE_WEIGHT: Balance = 4_000_000_000;
pub const FEE: Balance = 20_000_000;
pub const FEE_STATEMINE: Balance = 15_450_332;
pub const FEE_KUSAMA: Balance = 11_492_737;
const ASSET_ID: u32 = 100;

fn init_statemine_xcm_interface() {
let xcm_operation =
Expand Down Expand Up @@ -74,11 +77,28 @@ fn statemine_min_xcm_fee_matched() {
}

#[test]
fn teleport_from_relay_chain() {
fn statemine_reserve_transfer_ksm_to_karura_should_not_allowed() {
TestNet::reset();
let sibling_2000: AccountId = Sibling::from(2000).into_account_truncating();
let child_2000: AccountId = ParaId::from(2000).into_account_truncating();
let child_1000: AccountId = ParaId::from(1000).into_account_truncating();

KusamaNet::execute_with(|| {
assert_ok!(kusama_runtime::XcmPallet::teleport_assets(
kusama_runtime::Origin::signed(ALICE.into()),
Box::new(Parachain(1000).into().into()),
assert_eq!(2 * UNIT, kusama_runtime::Balances::free_balance(&child_2000));
assert_eq!(0, kusama_runtime::Balances::free_balance(&child_1000));
});

Statemine::execute_with(|| {
Balances::make_free_balance_be(&ALICE.into(), 2 * UNIT);
// Suppose reserve transfer can success, then dest chain(Karura) has a sibling sovereign account on
// source chain(Statemine).
Balances::make_free_balance_be(&sibling_2000, 2 * UNIT);

assert_ok!(statemine_runtime::PolkadotXcm::reserve_transfer_assets(
statemine_runtime::Origin::signed(ALICE.into()),
// Unlike Statemine reserve transfer to relaychain is not allowed,
// Here Statemine reserve transfer to parachain. let's see what happened.
Box::new(MultiLocation::new(1, X1(Parachain(2000))).into()),
Box::new(
Junction::AccountId32 {
id: BOB,
Expand All @@ -87,21 +107,105 @@ fn teleport_from_relay_chain() {
.into()
.into()
),
Box::new((Here, dollar(KSM)).into()),
Box::new((Parent, UNIT).into()),
0
));

// In sender xcm execution is successed, sender account is withdrawn.
assert_eq!(UNIT, statemine_runtime::Balances::free_balance(&AccountId::from(ALICE)));
// And sibling parachain sovereign account on Statemine deposited.
assert_eq!(3 * UNIT, statemine_runtime::Balances::free_balance(&sibling_2000));
});

KusamaNet::execute_with(|| {
assert_eq!(2 * UNIT, kusama_runtime::Balances::free_balance(&child_2000));
assert_eq!(0, kusama_runtime::Balances::free_balance(&child_1000));
});

// Xcm execution error on receiver: UntrustedReserveLocation.
// This means Karura not consider Statemine as reserve chain of KSM.
Karura::execute_with(|| {
assert_eq!(0, Tokens::free_balance(KSM, &AccountId::from(BOB)));
});
}

#[test]
fn karura_transfer_ksm_to_statemine_should_not_allowed() {
TestNet::reset();
let child_2000: AccountId = ParaId::from(2000).into_account_truncating();
let child_1000: AccountId = ParaId::from(1000).into_account_truncating();

KusamaNet::execute_with(|| {
assert_eq!(2 * UNIT, kusama_runtime::Balances::free_balance(&child_2000));
assert_eq!(0, kusama_runtime::Balances::free_balance(&child_1000));
});

// Karura transfer KSM to Statemine, it's `NonRerserve` scene(A->[B]->C).
Karura::execute_with(|| {
assert_ok!(XTokens::transfer(
Origin::signed(ALICE.into()),
KSM,
UNIT,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(1000),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
)
)
.into()
),
4_000_000_000
));

assert_eq!(9 * UNIT, Tokens::free_balance(KSM, &AccountId::from(ALICE)));
});

// In relaychain, two parachain sovereign account balance changed.
KusamaNet::execute_with(|| {
// source parachain sovereign account withrawn.
assert_eq!(UNIT, kusama_runtime::Balances::free_balance(&child_2000));
// destination parachain sovereign account deposited.
assert_eq!(999_970_357_090, kusama_runtime::Balances::free_balance(&child_1000));
});

// In receiver, xm execution error: UntrustedReserveLocation.
// This's same as Relaychain reserve transfer to Statemine which not allowed.
Statemine::execute_with(|| {
assert_eq!(
dollar(KSM) - FEE_STATEMINE,
Balances::free_balance(&AccountId::from(BOB))
);
assert_eq!(0, Balances::free_balance(&AccountId::from(BOB)));
});
}

#[test]
fn karura_transfer_asset_to_statemine_works() {
TestNet::reset();

let para_2000: AccountId = Sibling::from(2000).into_account_truncating();

// Alice on Statemine send USDT to Bob on Karura.
statemine_transfer_asset_to_karura();

// Bob on Karura send back USDT to Bob on Statemine.
// Trying use USDT as fee when execte xcm on Statemine.
karura_transfer_asset_to_statemine(0);

Statemine::execute_with(|| {
use statemine_runtime::*;

assert_eq!(9 * UNIT, Assets::balance(ASSET_ID, &para_2000));

// https://github.com/paritytech/cumulus/pull/1278 support using self sufficient asset
// for paying xcm execution fee on Statemine.
assert_eq!(953_648_999_365, Assets::balance(ASSET_ID, &AccountId::from(BOB)));
});
}

#[test]
fn karura_statemine_transfer_works() {
fn karura_statemine_transfer_use_ksm_as_fee() {
TestNet::reset();
let para_2000: AccountId = Sibling::from(2000).into_account_truncating();
let child_2000: AccountId = ParaId::from(2000).into_account_truncating();
Expand All @@ -111,25 +215,28 @@ fn karura_statemine_transfer_works() {
// but due to current half fee, sender asset should at lease: FEE_WEIGHT + 2 * FEE_KUSAMA
let asset = FEE_WEIGHT + 2 * 31_488_122;

statemine_side(UNIT);
// Alice on Statemine send USDT to Bob on Karura
statemine_transfer_asset_to_karura();

KusamaNet::execute_with(|| {
let _ = kusama_runtime::Balances::make_free_balance_be(&child_2000, TEN);
assert_eq!(0, kusama_runtime::Balances::free_balance(&child_1000));
});

karura_side(asset);
// Bob on Karura send back USDT with KSM as fee to Bob on Statemine
karura_transfer_asset_to_statemine(asset);

KusamaNet::execute_with(|| {
assert_eq!(TEN - (asset - FEE), kusama_runtime::Balances::free_balance(&child_2000));
});

Statemine::execute_with(|| {
use statemine_runtime::*;

// Karura send back custom asset to Statemine, ensure recipient got custom asset
assert_eq!(UNIT, Assets::balance(0, &AccountId::from(BOB)));
assert_eq!(UNIT, Assets::balance(ASSET_ID, &AccountId::from(BOB)));
// and withdraw sibling parachain sovereign account
assert_eq!(9 * UNIT, Assets::balance(0, &para_2000));
assert_eq!(9 * UNIT, Assets::balance(ASSET_ID, &para_2000));

assert_eq!(
UNIT + FEE - FEE_STATEMINE,
Expand All @@ -139,8 +246,10 @@ fn karura_statemine_transfer_works() {
});
}

// transfer custom asset from Karura to Statemine
fn karura_side(fee_amount: u128) {
// Karura(ForeignAsset) transfer asset(e.g. USDT) back to Statemine(assets)
// `ksm_fee_amount` is used to indicate how much KSM paying as fee.
// If specify `ksm_fee_amount` to 0, then wouldn't use KSM as fee.
fn karura_transfer_asset_to_statemine(ksm_fee_amount: u128) {
Karura::execute_with(|| {
init_statemine_xcm_interface();

Expand All @@ -151,39 +260,65 @@ fn karura_side(fee_amount: u128) {
// ensure sender has enough KSM balance to be charged as fee
assert_ok!(Tokens::deposit(KSM, &AccountId::from(BOB), TEN));

assert_ok!(XTokens::transfer_multicurrencies(
Origin::signed(BOB.into()),
vec![(CurrencyId::ForeignAsset(0), UNIT), (KSM, fee_amount)],
1,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(1000),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
if ksm_fee_amount == 0 {
// use custom asset(USDT on Statemine) as fee
assert_ok!(XTokens::transfer(
Origin::signed(BOB.into()),
CurrencyId::ForeignAsset(0),
UNIT,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(1000),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
)
)
)
.into()
),
FEE_WEIGHT as u64
));
.into()
),
FEE_WEIGHT as u64
));
} else {
// use KSM as fee
assert_ok!(XTokens::transfer_multicurrencies(
Origin::signed(BOB.into()),
vec![(CurrencyId::ForeignAsset(0), UNIT), (KSM, ksm_fee_amount)],
1,
Box::new(
MultiLocation::new(
1,
X2(
Parachain(1000),
Junction::AccountId32 {
network: NetworkId::Any,
id: BOB.into(),
}
)
)
.into()
),
FEE_WEIGHT as u64
));
}

assert_eq!(
8_999_907_304_000,
Tokens::free_balance(CurrencyId::ForeignAsset(0), &AccountId::from(BOB))
);
assert_eq!(TEN - fee_amount, Tokens::free_balance(KSM, &AccountId::from(BOB)));
assert_eq!(TEN - ksm_fee_amount, Tokens::free_balance(KSM, &AccountId::from(BOB)));
});
}

// transfer custom asset from Statemine to Karura
fn statemine_side(para_2000_init_amount: u128) {
// Statemine(assets) transfer custom asset(e.g. USDT) to Karura(ForeignAsset)
// Alice is using reserve transfer, and Statemine is indeed the reserve chain of USDT.
// So the reserve transfer can success. On Karura side, USDT is consider as ForeignAsset.
fn statemine_transfer_asset_to_karura() {
register_asset();

let para_acc: AccountId = Sibling::from(2000).into_account_truncating();
let para_2000: AccountId = Sibling::from(2000).into_account_truncating();

Statemine::execute_with(|| {
use statemine_runtime::*;
Expand All @@ -192,24 +327,25 @@ fn statemine_side(para_2000_init_amount: u128) {
Balances::make_free_balance_be(&ALICE.into(), TEN);
Balances::make_free_balance_be(&BOB.into(), UNIT);

// create custom asset cost 0.1 KSM
assert_ok!(Assets::create(
origin.clone(),
0,
// If using non root, create custom asset cost 0.1 KSM
// We're using force_create here to make sure asset is sufficient.
assert_ok!(Assets::force_create(
Origin::root(),
ASSET_ID,
MultiAddress::Id(ALICE.into()),
true,
UNIT / 100
));
assert_eq!(9_900_000_000_000, Balances::free_balance(&AccountId::from(ALICE)));

assert_ok!(Assets::mint(
origin.clone(),
0,
ASSET_ID,
MultiAddress::Id(ALICE.into()),
1000 * UNIT
));

// need to have some KSM to be able to receive user assets
Balances::make_free_balance_be(&para_acc, para_2000_init_amount);
Balances::make_free_balance_be(&para_2000, UNIT);

assert_ok!(PolkadotXcm::reserve_transfer_assets(
origin.clone(),
Expand All @@ -222,15 +358,16 @@ fn statemine_side(para_2000_init_amount: u128) {
.into()
.into()
),
Box::new((X2(PalletInstance(50), GeneralIndex(0)), TEN).into()),
Box::new((X2(PalletInstance(50), GeneralIndex(ASSET_ID as u128)), TEN).into()),
0
));

assert_eq!(0, Assets::balance(0, &AccountId::from(BOB)));
assert_eq!(990 * UNIT, Assets::balance(ASSET_ID, &AccountId::from(ALICE)));
assert_eq!(0, Assets::balance(ASSET_ID, &AccountId::from(BOB)));

assert_eq!(TEN, Assets::balance(0, &para_acc));
assert_eq!(TEN, Assets::balance(ASSET_ID, &para_2000));
// the KSM balance of sibling parachain sovereign account is not changed
assert_eq!(para_2000_init_amount, Balances::free_balance(&para_acc));
assert_eq!(UNIT, Balances::free_balance(&para_2000));
});

// Rerun the Statemine::execute to actually send the egress message via XCM
Expand All @@ -242,7 +379,13 @@ fn register_asset() {
// register foreign asset
assert_ok!(AssetRegistry::register_foreign_asset(
Origin::root(),
Box::new(MultiLocation::new(1, X3(Parachain(1000), PalletInstance(50), GeneralIndex(0))).into()),
Box::new(
MultiLocation::new(
1,
X3(Parachain(1000), PalletInstance(50), GeneralIndex(ASSET_ID as u128))
)
.into()
),
Box::new(AssetMetadata {
name: b"Sibling Token".to_vec(),
symbol: b"ST".to_vec(),
Expand Down

0 comments on commit a50082b

Please sign in to comment.