Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Statemine more test #2381

Merged
merged 7 commits into from
Oct 18, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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