Improve Penpal runtime + emulated tests (#3543)

Issues addressed in this PR:
- Improve *Penpal* runtime:
- Properly handled received assets. Previously, it treated `(1, Here)`
as the local native currency, whereas it should be treated as a
`ForeignAsset`. This wasn't a great example of standard Parachain
behaviour, as no Parachain treats the system asset as the local
currency.
- Remove `AllowExplicitUnpaidExecutionFrom` the system. Again, this
wasn't a great example of standard Parachain behaviour.
- Move duplicated
`ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger` to
`assets_common` crate.
- Improve emulated tests:
  - Update *Penpal* tests to new runtime.
- To simplify tests, register the reserve transferred, teleported, and
system assets in *Penpal* and *AssetHub* genesis. This saves us from
having to create the assets repeatedly for each test
- Add missing test case:
`reserve_transfer_assets_from_para_to_system_para`.
  - Cleanup.
- Prevent integration tests crates imports from being re-exported, as
they were polluting the `polkadot-sdk` docs.

There is still a test case missing for reserve transfers:
- Reserve transfer of system asset from *Parachain* to *Parachain*
trough *AssetHub*.
- This is not yet possible with `pallet-xcm` due to the reasons
explained in https://github.com/paritytech/polkadot-sdk/pull/3339

---------

Co-authored-by: command-bot <>
This commit is contained in:
Ignacio Palacios
2024-03-14 11:29:24 +01:00
committed by GitHub
parent 606664e1bd
commit cfc4050d6b
47 changed files with 2581 additions and 1200 deletions
@@ -33,6 +33,7 @@ westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" }
# Cumulus
parachains-common = { path = "../../../../../../parachains/common" }
testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" }
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" }
@@ -13,67 +13,83 @@
// See the License for the specific language governing permissions and
// limitations under the License.
pub use codec::Encode;
#[cfg(test)]
mod imports {
pub use codec::Encode;
// Substrate
pub use frame_support::{
assert_err, assert_ok,
instances::Instance2,
pallet_prelude::Weight,
sp_runtime::{AccountId32, DispatchError, DispatchResult, ModuleError},
traits::fungibles::Inspect,
BoundedVec,
};
// Substrate
pub use frame_support::{
assert_err, assert_ok,
pallet_prelude::Weight,
sp_runtime::{DispatchError, DispatchResult, ModuleError},
traits::fungibles::Inspect,
};
// Polkadot
pub use xcm::{
prelude::{AccountId32 as AccountId32Junction, *},
v3::{self, Error, NetworkId::Westend as WestendId},
};
// Polkadot
pub use xcm::{
prelude::{AccountId32 as AccountId32Junction, *},
v3,
};
// Cumulus
pub use asset_test_utils::xcm_helpers;
pub use emulated_integration_tests_common::{
test_parachain_is_trusted_teleporter,
xcm_emulator::{
assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para,
RelayChain as Relay, Test, TestArgs, TestContext, TestExt,
},
xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution},
PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3,
};
pub use parachains_common::{AccountId, Balance};
pub use westend_system_emulated_network::{
asset_hub_westend_emulated_chain::{
genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet,
},
collectives_westend_emulated_chain::{
genesis::ED as COLLECTIVES_WESTEND_ED,
CollectivesWestendParaPallet as CollectivesWestendPallet,
},
penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet,
westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet},
AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver,
AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend,
BridgeHubWestendParaReceiver as BridgeHubWestendReceiver,
CollectivesWestendPara as CollectivesWestend, PenpalAPara as PenpalA,
PenpalAParaReceiver as PenpalAReceiver, PenpalBPara as PenpalB,
PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender,
WestendRelay as Westend, WestendRelayReceiver as WestendReceiver,
WestendRelaySender as WestendSender,
};
// Cumulus
pub use asset_test_utils::xcm_helpers;
pub use emulated_integration_tests_common::{
test_parachain_is_trusted_teleporter,
xcm_emulator::{
assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test,
TestArgs, TestContext, TestExt,
},
xcm_helpers::{non_fee_asset, xcm_transact_paid_execution},
ASSETS_PALLET_ID, RESERVABLE_ASSET_ID, XCM_V3,
};
pub use parachains_common::{AccountId, Balance};
pub use westend_system_emulated_network::{
asset_hub_westend_emulated_chain::{
genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED},
AssetHubWestendParaPallet as AssetHubWestendPallet,
},
collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet,
penpal_emulated_chain::{
PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner,
PenpalBParaPallet as PenpalBPallet,
},
westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet},
AssetHubWestendPara as AssetHubWestend,
AssetHubWestendParaReceiver as AssetHubWestendReceiver,
AssetHubWestendParaSender as AssetHubWestendSender,
BridgeHubWestendPara as BridgeHubWestend,
BridgeHubWestendParaReceiver as BridgeHubWestendReceiver,
CollectivesWestendPara as CollectivesWestend, PenpalAPara as PenpalA,
PenpalAParaReceiver as PenpalAReceiver, PenpalAParaSender as PenpalASender,
PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, WestendRelay as Westend,
WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender,
};
pub const ASSET_ID: u32 = 1;
pub const ASSET_MIN_BALANCE: u128 = 1000;
// `Assets` pallet index
pub const ASSETS_PALLET_ID: u8 = 50;
// Runtimes
pub use asset_hub_westend_runtime::xcm_config::{
UniversalLocation as AssetHubWestendUniversalLocation, WestendLocation as RelayLocation,
XcmConfig as AssetHubWestendXcmConfig,
};
pub use penpal_runtime::xcm_config::{
LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub,
LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub,
UniversalLocation as PenpalUniversalLocation, XcmConfig as PenpalWestendXcmConfig,
};
pub use westend_runtime::xcm_config::{
UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig,
};
pub type RelayToSystemParaTest = Test<Westend, AssetHubWestend>;
pub type RelayToParaTest = Test<Westend, PenpalB>;
pub type SystemParaToRelayTest = Test<AssetHubWestend, Westend>;
pub type SystemParaToParaTest = Test<AssetHubWestend, PenpalB>;
pub type ParaToSystemParaTest = Test<PenpalB, AssetHubWestend>;
pub type ParaToParaTest = Test<PenpalB, PenpalA, Westend>;
pub const ASSET_ID: u32 = 3;
pub const ASSET_MIN_BALANCE: u128 = 1000;
pub type RelayToSystemParaTest = Test<Westend, AssetHubWestend>;
pub type RelayToParaTest = Test<Westend, PenpalA>;
pub type ParaToRelayTest = Test<PenpalA, Westend>;
pub type SystemParaToRelayTest = Test<AssetHubWestend, Westend>;
pub type SystemParaToParaTest = Test<AssetHubWestend, PenpalA>;
pub type ParaToSystemParaTest = Test<PenpalA, AssetHubWestend>;
pub type ParaToParaThroughRelayTest = Test<PenpalA, PenpalB, Westend>;
}
#[cfg(test)]
mod tests;
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use crate::imports::*;
use emulated_integration_tests_common::accounts::{ALICE, BOB};
use frame_support::traits::fungibles::{Create, Inspect, Mutate};
use polkadot_runtime_common::impls::VersionedLocatableAsset;
@@ -20,11 +20,3 @@ mod set_xcm_versions;
mod swap;
mod teleport;
mod treasury;
use crate::*;
emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!(
PenpalB,
AssetHubWestend,
WESTEND_ED,
testnet_parachains_constants::westend::fee::WeightToFee
);
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use crate::imports::*;
/// Relay Chain should be able to execute `Transact` instructions in System Parachain
/// when `OriginKind::Superuser`.
@@ -28,12 +28,99 @@ fn send_transact_as_superuser_from_relay_to_system_para_works() {
)
}
/// Parachain should be able to send XCM paying its fee with sufficient asset
/// in the System Parachain
/// We tests two things here:
/// - Parachain should be able to send XCM paying its fee with system asset in the System Parachain
/// - Parachain should be able to create a new Foreign Asset in the System Parachain
#[test]
fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() {
let para_sovereign_account = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalA::para_id()),
);
let asset_location_on_penpal = v3::Location::new(
0,
[
v3::Junction::PalletInstance(ASSETS_PALLET_ID),
v3::Junction::GeneralIndex(ASSET_ID.into()),
],
);
let foreign_asset_at_asset_hub =
v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())])
.appended_with(asset_location_on_penpal)
.unwrap();
// Encoded `create_asset` call to be executed in AssetHub
let call = AssetHubWestend::create_foreign_asset_call(
foreign_asset_at_asset_hub,
ASSET_MIN_BALANCE,
para_sovereign_account.clone(),
);
let origin_kind = OriginKind::Xcm;
let fee_amount = ASSET_HUB_WESTEND_ED * 1000000;
let system_asset = (Parent, fee_amount).into();
let root_origin = <PenpalA as Chain>::RuntimeOrigin::root();
let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
origin_kind,
system_asset,
para_sovereign_account.clone(),
);
// SA-of-Penpal-on-AHR needs to have balance to pay for fees and asset creation deposit
AssetHubWestend::fund_accounts(vec![(
para_sovereign_account.clone().into(),
ASSET_HUB_WESTEND_ED * 10000000000,
)]);
PenpalA::execute_with(|| {
assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
root_origin,
bx!(system_para_destination),
bx!(xcm),
));
PenpalA::assert_xcm_pallet_sent();
});
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts(
15_594_564_000,
562_893,
)));
assert_expected_events!(
AssetHubWestend,
vec![
// Burned the fee
RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => {
who: *who == para_sovereign_account,
amount: *amount == fee_amount,
},
// Foreign Asset created
RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => {
asset_id: *asset_id == foreign_asset_at_asset_hub,
creator: *creator == para_sovereign_account.clone(),
owner: *owner == para_sovereign_account,
},
]
);
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub));
});
}
/// We tests two things here:
/// - Parachain should be able to send XCM paying its fee with system assets in the System Parachain
/// - Parachain should be able to create a new Asset in the System Parachain
#[test]
fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
let para_sovereign_account = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalB::para_id()),
AssetHubWestend::sibling_location_of(PenpalA::para_id()),
);
// Force create and mint assets for Parachain's sovereign account
@@ -46,57 +133,63 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() {
ASSET_MIN_BALANCE * 1000000000,
);
// We just need a call that can pass the `SafeCallFilter`
// Call values are not relevant
let call = AssetHubWestend::force_create_asset_call(
ASSET_ID,
para_sovereign_account.clone(),
true,
// Just a different `asset_id`` that does not exist yet
let new_asset_id = ASSET_ID + 1;
// Encoded `create_asset` call to be executed in AssetHub
let call = AssetHubWestend::create_asset_call(
new_asset_id,
ASSET_MIN_BALANCE,
para_sovereign_account.clone(),
);
let origin_kind = OriginKind::SovereignAccount;
let fee_amount = ASSET_MIN_BALANCE * 1000000;
let native_asset =
let asset =
([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into();
let root_origin = <PenpalB as Chain>::RuntimeOrigin::root();
let system_para_destination = PenpalB::sibling_location_of(AssetHubWestend::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
origin_kind,
native_asset,
para_sovereign_account.clone(),
);
let root_origin = <PenpalA as Chain>::RuntimeOrigin::root();
let system_para_destination = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into();
let xcm = xcm_transact_paid_execution(call, origin_kind, asset, para_sovereign_account.clone());
PenpalB::execute_with(|| {
assert_ok!(<PenpalB as PenpalBPallet>::PolkadotXcm::send(
// SA-of-Penpal-on-AHR needs to have balance to pay for asset creation deposit
AssetHubWestend::fund_accounts(vec![(
para_sovereign_account.clone().into(),
ASSET_HUB_WESTEND_ED * 10000000000,
)]);
PenpalA::execute_with(|| {
assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
root_origin,
bx!(system_para_destination),
bx!(xcm),
));
PenpalB::assert_xcm_pallet_sent();
PenpalA::assert_xcm_pallet_sent();
});
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcmp_queue_success(Some(Weight::from_parts(
16_290_336_000,
15_594_564_000,
562_893,
)));
assert_expected_events!(
AssetHubWestend,
vec![
// Burned the fee
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == ASSET_ID,
owner: *owner == para_sovereign_account,
balance: *balance == fee_amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, .. }) => {
asset_id: *asset_id == ASSET_ID,
// Asset created
RuntimeEvent::Assets(pallet_assets::Event::Created { asset_id, creator, owner }) => {
asset_id: *asset_id == new_asset_id,
creator: *creator == para_sovereign_account.clone(),
owner: *owner == para_sovereign_account,
},
]
);
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use crate::imports::*;
#[test]
fn relay_sets_system_para_xcm_supported_version() {
@@ -13,8 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3;
use crate::imports::*;
#[test]
fn swap_locally_on_chain_using_local_assets() {
@@ -112,49 +111,39 @@ fn swap_locally_on_chain_using_local_assets() {
#[test]
fn swap_locally_on_chain_using_foreign_assets() {
let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocationV3::get());
let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get();
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(v3::Junction::GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalBSender::get();
let asset_native =
Box::new(v3::Location::try_from(RelayLocation::get()).expect("conversion works"));
let asset_location_on_penpal =
v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion_works");
let foreign_asset_at_asset_hub_westend =
v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())])
v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())])
.appended_with(asset_location_on_penpal)
.unwrap();
// 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_westend
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_westend,
ah_as_seen_by_penpal,
true,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id());
let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah);
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah);
AssetHubWestend::fund_accounts(vec![
(AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), /* An account to swap dot
* for something else. */
// An account to swap dot for something else.
(AssetHubWestendSender::get().into(), 5_000_000 * ASSET_HUB_WESTEND_ED),
// Penpal's sovereign account in AH should have some balance
(sov_penpal_on_ahr.clone().into(), 100_000_000 * ASSET_HUB_WESTEND_ED),
]);
AssetHubWestend::execute_with(|| {
// 3: Mint foreign asset on asset_hub_westend:
// 0: No need to create foreign asset as it exists in genesis.
//
// 1: Mint foreign asset on asset_hub_westend:
//
// (While it might be nice to use batch,
// currently that's disabled due to safe call filters.)
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
// 3. Mint foreign asset (in reality this should be a teleport or some such)
// 1. Mint foreign asset (in reality this should be a teleport or some such)
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::ForeignAssets::mint(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone().into()),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()),
foreign_asset_at_asset_hub_westend,
sov_penpal_on_ahw.clone().into(),
3_000_000_000_000,
sov_penpal_on_ahr.clone().into(),
ASSET_HUB_WESTEND_ED * 3_000_000_000_000,
));
assert_expected_events!(
@@ -164,7 +153,7 @@ fn swap_locally_on_chain_using_foreign_assets() {
]
);
// 4. Create pool:
// 2. Create pool:
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
asset_native.clone(),
@@ -178,58 +167,60 @@ fn swap_locally_on_chain_using_foreign_assets() {
]
);
// 5. Add liquidity:
// 3. Add liquidity:
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
asset_native.clone(),
Box::new(foreign_asset_at_asset_hub_westend),
1_000_000_000_000,
2_000_000_000_000,
1_000_000_000_000_000,
2_000_000_000_000_000,
0,
0,
sov_penpal_on_ahw.clone().into()
sov_penpal_on_ahr.clone().into()
));
assert_expected_events!(
AssetHubWestend,
vec![
RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded {lp_token_minted, .. }) => {
lp_token_minted: *lp_token_minted == 1414213562273,
lp_token_minted: *lp_token_minted == 1414213562372995,
},
]
);
// 6. Swap!
// 4. Swap!
let path = vec![asset_native.clone(), Box::new(foreign_asset_at_asset_hub_westend)];
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::swap_exact_tokens_for_tokens(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
path,
100000,
1000,
AssetHubWestendSender::get().into(),
true
));
assert_ok!(
<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::swap_exact_tokens_for_tokens(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
path,
100000 * ASSET_HUB_WESTEND_ED,
1000 * ASSET_HUB_WESTEND_ED,
AssetHubWestendSender::get().into(),
true
)
);
assert_expected_events!(
AssetHubWestend,
vec![
RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::SwapExecuted { amount_in, amount_out, .. },) => {
amount_in: *amount_in == 100000,
amount_out: *amount_out == 199399,
amount_in: *amount_in == 100000000000000,
amount_out: *amount_out == 181322178776029,
},
]
);
// 7. Remove liquidity
// 5. Remove liquidity
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::remove_liquidity(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
asset_native.clone(),
Box::new(foreign_asset_at_asset_hub_westend),
1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved.
1414213562372995 - ASSET_HUB_WESTEND_ED * 2, // all but the 2 EDs can't be retrieved.
0,
0,
sov_penpal_on_ahw.into(),
sov_penpal_on_ahr.clone().into(),
));
});
}
@@ -283,7 +274,7 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
.into(),
};
let penpal = AssetHubWestend::sovereign_account_id_of(AssetHubWestend::sibling_location_of(
PenpalB::para_id(),
PenpalA::para_id(),
));
AssetHubWestend::execute_with(|| {
@@ -356,7 +347,7 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
));
});
PenpalB::execute_with(|| {
PenpalA::execute_with(|| {
// send xcm transact from `penpal` account which as only `ASSET_ID` tokens on
// `AssetHubWestend`
let call = AssetHubWestend::force_create_asset_call(
@@ -366,11 +357,11 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
ASSET_MIN_BALANCE,
);
let penpal_root = <PenpalB as Chain>::RuntimeOrigin::root();
let penpal_root = <PenpalA as Chain>::RuntimeOrigin::root();
let fee_amount = 4_000_000_000_000u128;
let asset_one =
([PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())], fee_amount).into();
let asset_hub_location = PenpalB::sibling_location_of(AssetHubWestend::para_id()).into();
let asset_hub_location = PenpalA::sibling_location_of(AssetHubWestend::para_id()).into();
let xcm = xcm_transact_paid_execution(
call,
OriginKind::SovereignAccount,
@@ -378,13 +369,13 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() {
penpal.clone(),
);
assert_ok!(<PenpalB as PenpalBPallet>::PolkadotXcm::send(
assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
penpal_root,
bx!(asset_hub_location),
bx!(xcm),
));
PenpalB::assert_xcm_pallet_sent();
PenpalA::assert_xcm_pallet_sent();
});
AssetHubWestend::execute_with(|| {
@@ -13,16 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig;
use emulated_integration_tests_common::xcm_helpers::non_fee_asset;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHubV3 as PenpalLocalTeleportableToAssetHubV3;
use crate::imports::*;
fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(632_207_000, 7_186)));
Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(631_531_000, 7_186)));
assert_expected_events!(
Westend,
@@ -47,7 +43,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) {
Westend::assert_ump_queue_processed(
true,
Some(AssetHubWestend::para_id()),
Some(Weight::from_parts(308_222_000, 7_186)),
Some(Weight::from_parts(307_225_000, 7_186)),
);
assert_expected_events!(
@@ -70,7 +66,7 @@ fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) {
Westend::assert_ump_queue_processed(
false,
Some(AssetHubWestend::para_id()),
Some(Weight::from_parts(148_705_000, 3_593)),
Some(Weight::from_parts(157_718_000, 3_593)),
);
}
@@ -78,8 +74,8 @@ fn para_origin_assertions(t: SystemParaToRelayTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
533_910_000,
7167,
720_053_000,
7_203,
)));
AssetHubWestend::assert_parachain_system_ump_sent();
@@ -99,7 +95,7 @@ fn para_origin_assertions(t: SystemParaToRelayTest) {
fn para_dest_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(164_793_000, 3593)));
AssetHubWestend::assert_dmp_queue_complete(Some(Weight::from_parts(157_718_000, 3593)));
assert_expected_events!(
AssetHubWestend,
@@ -113,19 +109,22 @@ fn para_dest_assertions(t: RelayToSystemParaTest) {
}
fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
PenpalB::assert_xcm_pallet_attempted_complete(None);
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
let system_para_native_asset_location =
v3::Location::try_from(RelayLocation::get()).expect("conversion works");
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
PenpalA::assert_xcm_pallet_attempted_complete(None);
assert_expected_events!(
PenpalB,
PenpalA,
vec![
RuntimeEvent::Balances(
pallet_balances::Event::Burned { who, amount }
RuntimeEvent::ForeignAssets(
pallet_assets::Event::Burned { asset_id, owner, .. }
) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
asset_id: *asset_id == system_para_native_asset_location,
owner: *owner == t.sender.account_id,
},
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_asset_id,
@@ -139,11 +138,14 @@ fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) {
fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalB::para_id()),
AssetHubWestend::sibling_location_of(PenpalA::para_id()),
);
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
let expected_foreign_asset_id_v3: v3::Location = expected_foreign_asset_id.try_into().unwrap();
AssetHubWestend::assert_xcmp_queue_success(None);
assert_expected_events!(
AssetHubWestend,
vec![
@@ -163,9 +165,6 @@ fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) {
amount: *amount == expected_foreign_asset_amount,
},
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
@@ -200,13 +199,18 @@ fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) {
}
fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
let checking_account = <PenpalB as PenpalBPallet>::PolkadotXcm::check_account();
let checking_account = <PenpalA as PenpalAPallet>::PolkadotXcm::check_account();
let system_para_native_asset_location =
v3::Location::try_from(RelayLocation::get()).expect("conversion works");
PenpalA::assert_xcmp_queue_success(None);
assert_expected_events!(
PenpalB,
PenpalA,
vec![
// checking account burns local asset as part of incoming teleport
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
@@ -221,12 +225,11 @@ fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) {
amount: *amount == expected_asset_amount,
},
// native asset for fee is deposited to receiver
RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => {
who: *who == t.receiver.account_id,
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => {
asset_id: *asset_id == system_para_native_asset_location,
owner: *owner == t.receiver.account_id,
amount: *amount == expected_asset_amount,
},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
@@ -273,8 +276,8 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
)
}
fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::transfer_assets(
fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalA as PenpalAPallet>::PolkadotXcm::transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
@@ -284,8 +287,8 @@ fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResul
)
}
fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalB as PenpalBPallet>::PolkadotXcm::transfer_assets(
fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
@@ -301,11 +304,11 @@ fn limited_teleport_native_assets_from_relay_to_system_para_works() {
// Init values for Relay Chain
let amount_to_send: Balance = WESTEND_ED * 1000;
let dest = Westend::child_location_of(AssetHubWestend::para_id());
let beneficiary = AssetHubWestendReceiver::get();
let beneficiary_id = AssetHubWestendReceiver::get();
let test_args = TestContext {
sender: WestendSender::get(),
receiver: beneficiary.clone(),
args: TestArgs::new_relay(dest, beneficiary, amount_to_send),
receiver: AssetHubWestendReceiver::get(),
args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args);
@@ -424,11 +427,11 @@ fn teleport_native_assets_from_relay_to_system_para_works() {
// Init values for Relay Chain
let amount_to_send: Balance = WESTEND_ED * 1000;
let dest = Westend::child_location_of(AssetHubWestend::para_id());
let beneficiary = AssetHubWestendReceiver::get();
let beneficiary_id = AssetHubWestendReceiver::get();
let test_args = TestContext {
sender: WestendSender::get(),
receiver: beneficiary.clone(),
args: TestArgs::new_relay(dest, beneficiary, amount_to_send),
receiver: AssetHubWestendReceiver::get(),
args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args);
@@ -485,15 +488,15 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() {
test.set_dispatchable::<AssetHubWestend>(system_para_teleport_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubWestendXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased
@@ -558,30 +561,21 @@ fn teleport_to_other_system_parachains_works() {
/// (using native reserve-based transfer for fees)
#[test]
fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHubV3::get();
// Init values for Parachain
let fee_amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 100;
let asset_location_on_penpal =
v3::Location::try_from(PenpalLocalTeleportableToAssetHub::get()).expect("conversion works");
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(v3::Junction::GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalBSender::get();
let foreign_asset_at_asset_hub_westend =
v3::Location::new(1, [v3::Junction::Parachain(PenpalB::para_id().into())])
.appended_with(asset_location_on_penpal)
.unwrap();
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_westend,
ah_as_seen_by_penpal.clone(),
false,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get();
let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000;
let asset_amount_to_send = ASSET_MIN_BALANCE * 1000;
let asset_amount_to_send = ASSET_HUB_WESTEND_ED * 100;
let asset_owner = PenpalAssetOwner::get();
let system_para_native_asset_location =
v3::Location::try_from(RelayLocation::get()).expect("conversion works");
let sender = PenpalASender::get();
let penpal_check_account = <PenpalA as PenpalAPallet>::PolkadotXcm::check_account();
let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubWestend::para_id());
let asset_location_on_penpal_latest: Location = asset_location_on_penpal.try_into().unwrap();
let penpal_assets: Assets = vec![
(Parent, fee_amount_to_send).into(),
@@ -594,9 +588,44 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
// fund Parachain's sender account
PenpalA::mint_foreign_asset(
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
system_para_native_asset_location,
sender.clone(),
fee_amount_to_send,
);
// No need to create the asset (only mint) as it exists in genesis.
PenpalA::mint_asset(
<PenpalA as Chain>::RuntimeOrigin::signed(asset_owner.clone()),
asset_id_on_penpal,
sender.clone(),
asset_amount_to_send,
);
// fund Parachain's check account to be able to teleport
PenpalA::fund_accounts(vec![(
penpal_check_account.clone().into(),
ASSET_HUB_WESTEND_ED * 1000,
)]);
// prefund SA of Penpal on AssetHub with enough native tokens to pay for fees
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ah = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah);
AssetHubWestend::fund_accounts(vec![(
sov_penpal_on_ah.clone().into(),
ASSET_HUB_WESTEND_ED * 100_000_000_000,
)]);
// Init values for System Parachain
let foreign_asset_at_asset_hub_westend =
v3::Location::new(1, [v3::Junction::Parachain(PenpalA::para_id().into())])
.appended_with(asset_location_on_penpal)
.unwrap();
let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get();
// Penpal to AH test args
let penpal_to_ah_test_args = TestContext {
sender: PenpalBSender::get(),
sender: PenpalASender::get(),
receiver: AssetHubWestendReceiver::get(),
args: TestArgs::new_para(
ah_as_seen_by_penpal,
@@ -608,13 +637,19 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
),
};
let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args);
let penpal_sender_balance_before = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
system_para_native_asset_location,
&PenpalASender::get(),
)
});
let penpal_sender_balance_before = penpal_to_ah.sender.balance;
let ah_receiver_balance_before = penpal_to_ah.receiver.balance;
let penpal_sender_assets_before = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBSender::get())
let penpal_sender_assets_before = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
});
let ah_receiver_assets_before = AssetHubWestend::execute_with(|| {
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
@@ -624,17 +659,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
)
});
penpal_to_ah.set_assertion::<PenpalB>(penpal_to_ah_foreign_assets_sender_assertions);
penpal_to_ah.set_assertion::<PenpalA>(penpal_to_ah_foreign_assets_sender_assertions);
penpal_to_ah.set_assertion::<AssetHubWestend>(penpal_to_ah_foreign_assets_receiver_assertions);
penpal_to_ah.set_dispatchable::<PenpalB>(para_to_system_para_transfer_assets);
penpal_to_ah.set_dispatchable::<PenpalA>(para_to_system_para_transfer_assets);
penpal_to_ah.assert();
let penpal_sender_balance_after = penpal_to_ah.sender.balance;
let penpal_sender_balance_after = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
system_para_native_asset_location,
&PenpalASender::get(),
)
});
let ah_receiver_balance_after = penpal_to_ah.receiver.balance;
let penpal_sender_assets_after = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBSender::get())
let penpal_sender_assets_after = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
});
let ah_receiver_assets_after = AssetHubWestend::execute_with(|| {
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
@@ -675,8 +717,8 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
let foreign_asset_at_asset_hub_westend_latest: Location =
foreign_asset_at_asset_hub_westend.try_into().unwrap();
let ah_to_penpal_beneficiary_id = PenpalBReceiver::get();
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id());
let ah_to_penpal_beneficiary_id = PenpalAReceiver::get();
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id());
let ah_assets: Assets = vec![
(Parent, fee_amount_to_send).into(),
(foreign_asset_at_asset_hub_westend_latest, asset_amount_to_send).into(),
@@ -691,7 +733,7 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
// AH to Penpal test args
let ah_to_penpal_test_args = TestContext {
sender: AssetHubWestendSender::get(),
receiver: PenpalBReceiver::get(),
receiver: PenpalAReceiver::get(),
args: TestArgs::new_para(
penpal_as_seen_by_ah,
ah_to_penpal_beneficiary_id,
@@ -704,7 +746,13 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args);
let ah_sender_balance_before = ah_to_penpal.sender.balance;
let penpal_receiver_balance_before = ah_to_penpal.receiver.balance;
let penpal_receiver_balance_before = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
system_para_native_asset_location,
&PenpalAReceiver::get(),
)
});
let ah_sender_assets_before = AssetHubWestend::execute_with(|| {
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
@@ -713,18 +761,24 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
&AssetHubWestendSender::get(),
)
});
let penpal_receiver_assets_before = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBReceiver::get())
let penpal_receiver_assets_before = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
});
ah_to_penpal.set_assertion::<AssetHubWestend>(ah_to_penpal_foreign_assets_sender_assertions);
ah_to_penpal.set_assertion::<PenpalB>(ah_to_penpal_foreign_assets_receiver_assertions);
ah_to_penpal.set_assertion::<PenpalA>(ah_to_penpal_foreign_assets_receiver_assertions);
ah_to_penpal.set_dispatchable::<AssetHubWestend>(system_para_to_para_transfer_assets);
ah_to_penpal.assert();
let ah_sender_balance_after = ah_to_penpal.sender.balance;
let penpal_receiver_balance_after = ah_to_penpal.receiver.balance;
let penpal_receiver_balance_after = PenpalA::execute_with(|| {
type ForeignAssets = <PenpalA as PenpalAPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
system_para_native_asset_location,
&PenpalAReceiver::get(),
)
});
let ah_sender_assets_after = AssetHubWestend::execute_with(|| {
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
@@ -733,9 +787,9 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
&AssetHubWestendSender::get(),
)
});
let penpal_receiver_assets_after = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBReceiver::get())
let penpal_receiver_assets_after = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
});
// Sender's balance is reduced
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::*;
use crate::imports::*;
use emulated_integration_tests_common::accounts::{ALICE, BOB};
use frame_support::traits::fungibles::{Create, Inspect, Mutate};
use polkadot_runtime_common::impls::VersionedLocatableAsset;