pallet-xcm: enhance reserve_transfer_assets to support remote reserves (#1672)

## Motivation

`pallet-xcm` is the main user-facing interface for XCM functionality,
including assets manipulation functions like `teleportAssets()` and
`reserve_transfer_assets()` calls.

While `teleportAsset()` works both ways, `reserve_transfer_assets()`
works only for sending reserve-based assets to a remote destination and
beneficiary when the reserve is the _local chain_.

## Solution

This PR enhances `pallet_xcm::(limited_)reserve_withdraw_assets` to
support transfers when reserves are other chains.
This will allow complete, **bi-directional** reserve-based asset
transfers user stories using `pallet-xcm`.

Enables following scenarios:
- transferring assets with local reserve (was previously supported iff
asset used as fee also had local reserve - now it works in all cases),
- transferring assets with reserve on destination,
- transferring assets with reserve on remote/third-party chain (iff
assets and fees have same remote reserve),
- transferring assets with reserve different than the reserve of the
asset to be used as fees - meaning can be used to transfer random asset
with local/dest reserve while using DOT for fees on all involved chains,
even if DOT local/dest reserve doesn't match asset reserve,
- transferring assets with any type of local/dest reserve while using
fees which can be teleported between involved chains.

All of the above is done by pallet inner logic without the user having
to specify which scenario/reserves/teleports/etc. The correct scenario
and corresponding XCM programs are identified, and respectively, built
automatically based on runtime configuration of trusted teleporters and
trusted reserves.

#### Current limitations:
- while `fees` and "non-fee" `assets` CAN have different reserves (or
fees CAN be teleported), the remaining "non-fee" `assets` CANNOT, among
themselves, have different reserve locations (this is also implicitly
enforced by `MAX_ASSETS_FOR_TRANSFER=2`, but this can be safely
increased in the future).
- `fees` and "non-fee" `assets` CANNOT have **different remote**
reserves (this could also be supported in the future, but adds even more
complexity while possibly not being worth it - we'll see what the future
holds).

Fixes https://github.com/paritytech/polkadot-sdk/issues/1584
Fixes https://github.com/paritytech/polkadot-sdk/issues/2055

---------

Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
This commit is contained in:
Adrian Catangiu
2023-11-13 17:16:55 +02:00
committed by GitHub
parent 29654a4d71
commit 18257373b3
80 changed files with 3679 additions and 1466 deletions
Generated
+5
View File
@@ -901,9 +901,11 @@ dependencies = [
"pallet-asset-conversion", "pallet-asset-conversion",
"pallet-assets", "pallet-assets",
"pallet-balances", "pallet-balances",
"pallet-message-queue",
"pallet-xcm", "pallet-xcm",
"parachains-common", "parachains-common",
"parity-scale-codec", "parity-scale-codec",
"penpal-runtime",
"rococo-runtime", "rococo-runtime",
"rococo-system-emulated-network", "rococo-system-emulated-network",
"sp-runtime", "sp-runtime",
@@ -11183,6 +11185,7 @@ dependencies = [
"frame-support", "frame-support",
"frame-system", "frame-system",
"log", "log",
"pallet-assets",
"pallet-balances", "pallet-balances",
"parity-scale-codec", "parity-scale-codec",
"polkadot-parachain-primitives", "polkadot-parachain-primitives",
@@ -11630,6 +11633,7 @@ dependencies = [
"frame-support", "frame-support",
"parachains-common", "parachains-common",
"penpal-runtime", "penpal-runtime",
"rococo-emulated-chain",
"serde_json", "serde_json",
"sp-core", "sp-core",
"sp-runtime", "sp-runtime",
@@ -18416,6 +18420,7 @@ dependencies = [
"impl-trait-for-tuples", "impl-trait-for-tuples",
"log", "log",
"parity-scale-codec", "parity-scale-codec",
"scale-info",
"sp-arithmetic", "sp-arithmetic",
"sp-core", "sp-core",
"sp-io", "sp-io",
@@ -150,11 +150,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -180,8 +175,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize;
// Cumulus // Cumulus
use emulated_integration_tests_common::{ use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
}; };
use rococo_emulated_chain::Rococo; use rococo_emulated_chain::Rococo;
@@ -51,5 +51,5 @@ decl_test_parachains! {
// AssetHubRococo implementation // AssetHubRococo implementation
impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_accounts_helpers_for_parachain!(AssetHubRococo);
impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo, false);
impl_assets_helpers_for_system_parachain!(AssetHubRococo, Rococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo);
@@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize;
// Cumulus // Cumulus
use emulated_integration_tests_common::{ use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
}; };
use westend_emulated_chain::Westend; use westend_emulated_chain::Westend;
@@ -51,5 +51,5 @@ decl_test_parachains! {
// AssetHubWestend implementation // AssetHubWestend implementation
impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_accounts_helpers_for_parachain!(AssetHubWestend);
impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend, false);
impl_assets_helpers_for_system_parachain!(AssetHubWestend, Westend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend);
@@ -19,7 +19,7 @@ use frame_support::traits::OnInitialize;
// Cumulus // Cumulus
use emulated_integration_tests_common::{ use emulated_integration_tests_common::{
impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_system_parachain, xcm_emulator::decl_test_parachains, impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
}; };
use wococo_emulated_chain::Wococo; use wococo_emulated_chain::Wococo;
@@ -49,5 +49,5 @@ decl_test_parachains! {
// AssetHubWococo implementation // AssetHubWococo implementation
impl_accounts_helpers_for_parachain!(AssetHubWococo); impl_accounts_helpers_for_parachain!(AssetHubWococo);
impl_assert_events_helpers_for_parachain!(AssetHubWococo); impl_assert_events_helpers_for_parachain!(AssetHubWococo, false);
impl_assets_helpers_for_system_parachain!(AssetHubWococo, Wococo); impl_assets_helpers_for_parachain!(AssetHubWococo, Wococo);
@@ -46,4 +46,4 @@ decl_test_parachains! {
// BridgeHubRococo implementation // BridgeHubRococo implementation
impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_accounts_helpers_for_parachain!(BridgeHubRococo);
impl_assert_events_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo, false);
@@ -46,4 +46,4 @@ decl_test_parachains! {
// BridgeHubWestend implementation // BridgeHubWestend implementation
impl_accounts_helpers_for_parachain!(BridgeHubWestend); impl_accounts_helpers_for_parachain!(BridgeHubWestend);
impl_assert_events_helpers_for_parachain!(BridgeHubWestend); impl_assert_events_helpers_for_parachain!(BridgeHubWestend, false);
@@ -44,4 +44,4 @@ decl_test_parachains! {
// BridgeHubWococo implementation // BridgeHubWococo implementation
impl_accounts_helpers_for_parachain!(BridgeHubWococo); impl_accounts_helpers_for_parachain!(BridgeHubWococo);
impl_assert_events_helpers_for_parachain!(BridgeHubWococo); impl_assert_events_helpers_for_parachain!(BridgeHubWococo, false);
@@ -22,3 +22,4 @@ parachains-common = { path = "../../../../../../../parachains/common" }
cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false }
emulated-integration-tests-common = { path = "../../../../common", default-features = false } emulated-integration-tests-common = { path = "../../../../common", default-features = false }
penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" } penpal-runtime = { path = "../../../../../../runtimes/testing/penpal" }
rococo-emulated-chain = { path = "../../../relays/rococo" }
@@ -21,8 +21,10 @@ use frame_support::traits::OnInitialize;
// Cumulus // Cumulus
use emulated_integration_tests_common::{ use emulated_integration_tests_common::{
impl_assert_events_helpers_for_parachain, xcm_emulator::decl_test_parachains, impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain,
impl_assets_helpers_for_parachain, xcm_emulator::decl_test_parachains,
}; };
use rococo_emulated_chain::Rococo;
// Penpal Parachain declaration // Penpal Parachain declaration
decl_test_parachains! { decl_test_parachains! {
@@ -40,6 +42,7 @@ decl_test_parachains! {
pallets = { pallets = {
PolkadotXcm: penpal_runtime::PolkadotXcm, PolkadotXcm: penpal_runtime::PolkadotXcm,
Assets: penpal_runtime::Assets, Assets: penpal_runtime::Assets,
Balances: penpal_runtime::Balances,
} }
}, },
pub struct PenpalB { pub struct PenpalB {
@@ -56,10 +59,13 @@ decl_test_parachains! {
pallets = { pallets = {
PolkadotXcm: penpal_runtime::PolkadotXcm, PolkadotXcm: penpal_runtime::PolkadotXcm,
Assets: penpal_runtime::Assets, Assets: penpal_runtime::Assets,
Balances: penpal_runtime::Balances,
} }
}, },
} }
// Penpal implementation // Penpal implementation
impl_assert_events_helpers_for_parachain!(PenpalA); impl_accounts_helpers_for_parachain!(PenpalA);
impl_assert_events_helpers_for_parachain!(PenpalB); impl_assets_helpers_for_parachain!(PenpalA, Rococo);
impl_assert_events_helpers_for_parachain!(PenpalA, true);
impl_assert_events_helpers_for_parachain!(PenpalB, true);
@@ -30,7 +30,7 @@ decl_test_relay_chains! {
on_init = (), on_init = (),
runtime = westend_runtime, runtime = westend_runtime,
core = { core = {
SovereignAccountOf: westend_runtime::xcm_config::LocationConverter, //TODO: rename to SovereignAccountOf, SovereignAccountOf: westend_runtime::xcm_config::LocationConverter,
}, },
pallets = { pallets = {
XcmPallet: westend_runtime::XcmPallet, XcmPallet: westend_runtime::XcmPallet,
@@ -399,7 +399,7 @@ macro_rules! impl_accounts_helpers_for_parachain {
#[macro_export] #[macro_export]
macro_rules! impl_assert_events_helpers_for_parachain { macro_rules! impl_assert_events_helpers_for_parachain {
( $chain:ident ) => { ( $chain:ident, $ignore_weight:expr ) => {
$crate::impls::paste::paste! { $crate::impls::paste::paste! {
type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent; type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
@@ -412,7 +412,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::PolkadotXcm( [<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) } $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
) => { ) => {
weight: $crate::impls::weight_within_threshold( weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight), expected_weight.unwrap_or(*weight),
*weight *weight
@@ -434,7 +434,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::PolkadotXcm( [<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) } $crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
) => { ) => {
weight: $crate::impls::weight_within_threshold( weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight), expected_weight.unwrap_or(*weight),
*weight *weight
@@ -490,7 +490,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { [<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: true, weight_used: weight, .. success: true, weight_used: weight, ..
}) => { }) => {
weight: $crate::impls::weight_within_threshold( weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight), expected_weight.unwrap_or(*weight),
*weight *weight
@@ -510,7 +510,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { [<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
success: false, weight_used: weight, .. success: false, weight_used: weight, ..
}) => { }) => {
weight: $crate::impls::weight_within_threshold( weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight), expected_weight.unwrap_or(*weight),
*weight *weight
@@ -541,7 +541,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
vec![ vec![
[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. } [<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }
) => { ) => {
weight: $crate::impls::weight_within_threshold( weight: $ignore_weight || $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD), ($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight), expected_weight.unwrap_or(*weight),
*weight *weight
@@ -556,7 +556,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
} }
#[macro_export] #[macro_export]
macro_rules! impl_assets_helpers_for_system_parachain { macro_rules! impl_assets_helpers_for_parachain {
( $chain:ident, $relay_chain:ident ) => { ( $chain:ident, $relay_chain:ident ) => {
$crate::impls::paste::paste! { $crate::impls::paste::paste! {
impl<N: $crate::impls::Network> $chain<N> { impl<N: $crate::impls::Network> $chain<N> {
@@ -17,6 +17,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default
pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false} pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false}
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false} pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false}
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false} pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false}
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false }
# Polkadot # Polkadot
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false} xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false}
@@ -28,5 +29,6 @@ rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" }
asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
parachains-common = { path = "../../../../../../parachains/common" } parachains-common = { path = "../../../../../../parachains/common" }
asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" }
emulated-integration-tests-common = { path = "../../../common", default-features = false} emulated-integration-tests-common = { path = "../../../common", default-features = false }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
rococo-system-emulated-network ={ path = "../../../networks/rococo-system" } rococo-system-emulated-network ={ path = "../../../networks/rococo-system" }
@@ -61,18 +61,20 @@ pub const ASSET_MIN_BALANCE: u128 = 1000;
pub const ASSETS_PALLET_ID: u8 = 50; pub const ASSETS_PALLET_ID: u8 = 50;
pub type RelayToSystemParaTest = Test<Rococo, AssetHubRococo>; pub type RelayToSystemParaTest = Test<Rococo, AssetHubRococo>;
pub type RelayToParaTest = Test<Rococo, PenpalA>;
pub type SystemParaToRelayTest = Test<AssetHubRococo, Rococo>; pub type SystemParaToRelayTest = Test<AssetHubRococo, Rococo>;
pub type SystemParaToParaTest = Test<AssetHubRococo, PenpalA>; pub type SystemParaToParaTest = Test<AssetHubRococo, PenpalA>;
pub type ParaToSystemParaTest = Test<PenpalA, AssetHubRococo>;
/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests /// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests
pub fn relay_test_args(amount: Balance) -> TestArgs { pub fn relay_test_args(
dest: MultiLocation,
beneficiary_id: AccountId32,
amount: Balance,
) -> TestArgs {
TestArgs { TestArgs {
dest: Rococo::child_location_of(AssetHubRococo::para_id()), dest,
beneficiary: AccountId32Junction { beneficiary: AccountId32Junction { network: None, id: beneficiary_id.into() }.into(),
network: None,
id: AssetHubRococoReceiver::get().into(),
}
.into(),
amount, amount,
assets: (Here, amount).into(), assets: (Here, amount).into(),
asset_id: None, asset_id: None,
@@ -81,13 +83,14 @@ pub fn relay_test_args(amount: Balance) -> TestArgs {
} }
} }
/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests /// Returns a `TestArgs` instance to be used by parachains across integration tests
pub fn system_para_test_args( pub fn para_test_args(
dest: MultiLocation, dest: MultiLocation,
beneficiary_id: AccountId32, beneficiary_id: AccountId32,
amount: Balance, amount: Balance,
assets: MultiAssets, assets: MultiAssets,
asset_id: Option<u32>, asset_id: Option<u32>,
fee_asset_item: u32,
) -> TestArgs { ) -> TestArgs {
TestArgs { TestArgs {
dest, dest,
@@ -95,7 +98,7 @@ pub fn system_para_test_args(
amount, amount,
assets, assets,
asset_id, asset_id,
fee_asset_item: 0, fee_asset_item,
weight_limit: WeightLimit::Unlimited, weight_limit: WeightLimit::Unlimited,
} }
} }
@@ -15,37 +15,45 @@
use crate::*; use crate::*;
use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig;
use penpal_runtime::xcm_config::XcmConfig as PenpalRococoXcmConfig;
use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn relay_to_para_sender_assertions(t: RelayToParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent; type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(630_092_000, 6_196))); Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799)));
assert_expected_events!( assert_expected_events!(
Rococo, Rococo,
vec![ vec![
// Amount to reserve transfer is transferred to System Parachain's Sovereign account // Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => { RuntimeEvent::Balances(
pallet_balances::Event::Transfer { from, to, amount }
) => {
from: *from == t.sender.account_id, from: *from == t.sender.account_id,
to: *to == Rococo::sovereign_account_id_of( to: *to == Rococo::sovereign_account_id_of(
t.args.dest t.args.dest
), ),
amount: *amount == t.args.amount, amount: *amount == t.args.amount,
}, },
] ]
); );
} }
fn system_para_dest_assertions_incomplete(_t: RelayToSystemParaTest) { fn relay_to_para_receiver_assertions<Test>(_: Test) {
AssetHubRococo::assert_dmp_queue_incomplete(Some(Weight::from_parts(57_185_000, 3504))); type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
} }
fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) { fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) {
AssetHubRococo::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier))
}
fn system_para_to_para_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent; type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
@@ -56,7 +64,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) {
assert_expected_events!( assert_expected_events!(
AssetHubRococo, AssetHubRococo,
vec![ vec![
// Amount to reserve transfer is transferred to Parachain's Sovereing account // Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Balances( RuntimeEvent::Balances(
pallet_balances::Event::Transfer { from, to, amount } pallet_balances::Event::Transfer { from, to, amount }
) => { ) => {
@@ -70,7 +78,64 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) {
); );
} }
fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { fn system_para_to_para_receiver_assertions<Test>(_: Test) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799)));
assert_expected_events!(
PenpalA,
vec![
// Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Balances(
pallet_balances::Event::Withdraw { who, amount }
) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
},
]
);
}
fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(
AssetHubRococo::sibling_location_of(PenpalA::para_id()),
);
assert_expected_events!(
AssetHubRococo,
vec![
// Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Balances(
pallet_balances::Event::Withdraw { who, amount }
) => {
who: *who == sov_penpal_on_ahr.clone().into(),
amount: *amount == t.args.amount,
},
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent; type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
@@ -81,7 +146,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) {
assert_expected_events!( assert_expected_events!(
AssetHubRococo, AssetHubRococo,
vec![ vec![
// Amount to reserve transfer is transferred to Parachain's Sovereing account // Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Assets( RuntimeEvent::Assets(
pallet_assets::Event::Transferred { asset_id, from, to, amount } pallet_assets::Event::Transferred { asset_id, from, to, amount }
) => { ) => {
@@ -96,7 +161,21 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) {
); );
} }
fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult { fn system_para_to_para_assets_receiver_assertions<Test>(_: Test) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::Assets(pallet_assets::Event::Issued { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult {
<Rococo as RococoPallet>::XcmPallet::limited_reserve_transfer_assets( <Rococo as RococoPallet>::XcmPallet::limited_reserve_transfer_assets(
t.signed_origin, t.signed_origin,
bx!(t.args.dest.into()), bx!(t.args.dest.into()),
@@ -107,37 +186,6 @@ fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchRe
) )
} }
fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Rococo as RococoPallet>::XcmPallet::reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
)
}
fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
)
}
fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets( <AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin, t.signed_origin,
@@ -149,183 +197,123 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest)
) )
} }
fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::reserve_transfer_assets( <PenpalA as PenpalAPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin, t.signed_origin,
bx!(t.args.dest.into()), bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()), bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()), bx!(t.args.assets.into()),
t.args.fee_asset_item, t.args.fee_asset_item,
t.args.weight_limit,
) )
} }
/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't
/// work
#[test]
fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() {
// Init values for Relay Chain
let amount_to_send: Balance = ROCOCO_ED * 1000;
let test_args = TestContext {
sender: RococoSender::get(),
receiver: AssetHubRococoReceiver::get(),
args: relay_test_args(amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<Rococo>(relay_origin_assertions);
test.set_assertion::<AssetHubRococo>(system_para_dest_assertions_incomplete);
test.set_dispatchable::<Rococo>(relay_limited_reserve_transfer_assets);
test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig 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;
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work
#[test]
fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() {
// Init values for System Parachain
let destination = AssetHubRococo::parent_location();
let beneficiary_id = RococoReceiver::get();
let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000;
let assets = (Parent, amount_to_send).into();
let test_args = TestContext {
sender: AssetHubRococoSender::get(),
receiver: RococoReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None),
};
let mut test = SystemParaToRelayTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<AssetHubRococo>(system_para_to_relay_assertions);
test.set_dispatchable::<AssetHubRococo>(system_para_limited_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work
#[test] #[test]
fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { fn reserve_transfer_native_asset_from_relay_to_system_para_fails() {
// Init values for Relay Chain let signed_origin = <Rococo as Chain>::RuntimeOrigin::signed(RococoSender::get().into());
let destination = Rococo::child_location_of(AssetHubRococo::para_id());
let beneficiary: MultiLocation =
AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into();
let amount_to_send: Balance = ROCOCO_ED * 1000; let amount_to_send: Balance = ROCOCO_ED * 1000;
let test_args = TestContext { let assets: MultiAssets = (Here, amount_to_send).into();
sender: RococoSender::get(), let fee_asset_item = 0;
receiver: AssetHubRococoReceiver::get(),
args: relay_test_args(amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args); // this should fail
Rococo::execute_with(|| {
let sender_balance_before = test.sender.balance; let result = <Rococo as RococoPallet>::XcmPallet::limited_reserve_transfer_assets(
let receiver_balance_before = test.receiver.balance; signed_origin,
bx!(destination.into()),
test.set_assertion::<Rococo>(relay_origin_assertions); bx!(beneficiary.into()),
test.set_assertion::<AssetHubRococo>(system_para_dest_assertions_incomplete); bx!(assets.into()),
test.set_dispatchable::<Rococo>(relay_reserve_transfer_assets); fee_asset_item,
test.assert(); WeightLimit::Unlimited,
);
let delivery_fees = Rococo::execute_with(|| { assert_err!(
xcm_helpers::transfer_assets_delivery_fees::< result,
<RococoXcmConfig as xcm_executor::Config>::XcmSender, DispatchError::Module(sp_runtime::ModuleError {
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) index: 99,
error: [2, 0, 0, 0],
message: Some("Filtered")
})
);
}); });
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
} }
/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work /// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work
#[test] #[test]
fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { fn reserve_transfer_native_asset_from_system_para_to_relay_fails() {
// Init values for System Parachain // Init values for System Parachain
let signed_origin =
<AssetHubRococo as Chain>::RuntimeOrigin::signed(AssetHubRococoSender::get().into());
let destination = AssetHubRococo::parent_location(); let destination = AssetHubRococo::parent_location();
let beneficiary_id = RococoReceiver::get(); let beneficiary_id = RococoReceiver::get();
let beneficiary: MultiLocation =
AccountId32Junction { network: None, id: beneficiary_id.into() }.into();
let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000;
let assets = (Parent, amount_to_send).into();
let assets: MultiAssets = (Parent, amount_to_send).into();
let fee_asset_item = 0;
// this should fail
AssetHubRococo::execute_with(|| {
let result =
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets(
signed_origin,
bx!(destination.into()),
bx!(beneficiary.into()),
bx!(assets.into()),
fee_asset_item,
WeightLimit::Unlimited,
);
assert_err!(
result,
DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [2, 0, 0, 0],
message: Some("Filtered")
})
);
});
}
/// Reserve Transfers of native asset from Relay to Parachain should work
#[test]
fn reserve_transfer_native_asset_from_relay_to_para() {
// Init values for Relay
let destination = Rococo::child_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get();
let amount_to_send: Balance = ROCOCO_ED * 1000;
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: RococoSender::get(),
receiver: RococoReceiver::get(), receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: relay_test_args(destination, beneficiary_id, amount_to_send),
}; };
let mut test = SystemParaToRelayTest::new(test_args); let mut test = RelayToParaTest::new(test_args);
let sender_balance_before = test.sender.balance; let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance; let receiver_balance_before = test.receiver.balance;
test.set_assertion::<AssetHubRococo>(system_para_to_relay_assertions); test.set_assertion::<Rococo>(relay_to_para_sender_assertions);
test.set_dispatchable::<AssetHubRococo>(system_para_reserve_transfer_assets); test.set_assertion::<PenpalA>(relay_to_para_receiver_assertions);
test.set_dispatchable::<Rococo>(relay_to_para_limited_reserve_transfer_assets);
test.assert(); test.assert();
let delivery_fees = Rococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<RococoXcmConfig 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 sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance; let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before, sender_balance_after); // Sender's balance is reduced
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work
#[test]
fn limited_reserve_transfer_native_asset_from_system_para_to_para() {
// Init values for System Parachain
let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get();
let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000;
let assets = (Parent, amount_to_send).into();
let test_args = TestContext {
sender: AssetHubRococoSender::get(),
receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None),
};
let mut test = SystemParaToParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
test.set_assertion::<AssetHubRococo>(system_para_to_para_assertions);
// TODO: Add assertion for Penpal runtime. Right now message is failing with
// `UntrustedReserveLocation`
test.set_dispatchable::<AssetHubRococo>(system_para_to_para_limited_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<AssetHubRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // Receiver's balance is increased
// transfers assert!(receiver_balance_after > receiver_balance_before);
} }
/// Reserve Transfers of native asset from System Parachain to Parachain should work /// Reserve Transfers of native asset from System Parachain to Parachain should work
@@ -340,20 +328,21 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: PenpalAReceiver::get(), receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
}; };
let mut test = SystemParaToParaTest::new(test_args); let mut test = SystemParaToParaTest::new(test_args);
let sender_balance_before = test.sender.balance; let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<AssetHubRococo>(system_para_to_para_assertions); test.set_assertion::<AssetHubRococo>(system_para_to_para_sender_assertions);
// TODO: Add assertion for Penpal runtime. Right now message is failing with test.set_assertion::<PenpalA>(system_para_to_para_receiver_assertions);
// `UntrustedReserveLocation` test.set_dispatchable::<AssetHubRococo>(system_para_to_para_limited_reserve_transfer_assets);
test.set_dispatchable::<AssetHubRococo>(system_para_to_para_reserve_transfer_assets);
test.assert(); test.assert();
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubRococo::execute_with(|| { let delivery_fees = AssetHubRococo::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::< xcm_helpers::transfer_assets_delivery_fees::<
@@ -361,79 +350,153 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
}); });
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // Receiver's balance is increased
// transfers assert!(receiver_balance_after > receiver_balance_before);
} }
/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work /// Reserve Transfers of native asset from Parachain to System Parachain should work
#[test] #[test]
fn limited_reserve_transfer_asset_from_system_para_to_para() { fn reserve_transfer_native_asset_from_para_to_system_para() {
// Force create asset from Relay Chain and mint assets for System Parachain's sender account // Init values for Penpal Parachain
let destination = PenpalA::sibling_location_of(AssetHubRococo::para_id());
let beneficiary_id = AssetHubRococoReceiver::get();
let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000;
let assets = (Parent, amount_to_send).into();
let test_args = TestContext {
sender: PenpalASender::get(),
receiver: AssetHubRococoReceiver::get(),
args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
};
let mut test = ParaToSystemParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr);
// fund the Penpal's SA on AHR with the native tokens held in reserve
AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), amount_to_send * 2)]);
test.set_assertion::<PenpalA>(para_to_system_para_sender_assertions);
test.set_assertion::<AssetHubRococo>(para_to_system_para_receiver_assertions);
test.set_dispatchable::<PenpalA>(para_to_system_para_limited_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = PenpalA::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<PenpalRococoXcmConfig as xcm_executor::Config>::XcmSender,
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest)
});
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// Receiver's balance is increased
assert!(receiver_balance_after > receiver_balance_before);
}
/// Reserve Transfers of a local asset and native asset from System Parachain to Parachain should
/// work
#[test]
fn reserve_transfer_assets_from_system_para_to_para() {
// Force create asset on AssetHubRococo and PenpalA from Relay Chain
AssetHubRococo::force_create_and_mint_asset( AssetHubRococo::force_create_and_mint_asset(
ASSET_ID, ASSET_ID,
ASSET_MIN_BALANCE, ASSET_MIN_BALANCE,
true, false,
AssetHubRococoSender::get(), AssetHubRococoSender::get(),
Some(Weight::from_parts(1_019_445_000, 200_000)), Some(Weight::from_parts(1_019_445_000, 200_000)),
ASSET_MIN_BALANCE * 1000000, ASSET_MIN_BALANCE * 1_000_000,
);
PenpalA::force_create_and_mint_asset(
ASSET_ID,
ASSET_MIN_BALANCE,
false,
PenpalASender::get(),
Some(Weight::from_parts(1_019_445_000, 200_000)),
0,
); );
// Init values for System Parachain // Init values for System Parachain
let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get(); let beneficiary_id = PenpalAReceiver::get();
let amount_to_send = ASSET_MIN_BALANCE * 1000; let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 1000;
let assets = let asset_amount_to_send = ASSET_MIN_BALANCE * 1000;
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) let assets: MultiAssets = vec![
.into(); (Parent, fee_amount_to_send).into(),
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), asset_amount_to_send)
.into(),
]
.into();
let fee_asset_index = assets
.inner()
.iter()
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
let system_para_test_args = TestContext { let para_test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: PenpalAReceiver::get(), receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(
destination,
beneficiary_id,
asset_amount_to_send,
assets,
None,
fee_asset_index,
),
}; };
let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); let mut test = SystemParaToParaTest::new(para_test_args);
system_para_test.set_assertion::<AssetHubRococo>(system_para_to_para_assets_assertions); // Create SA-of-Penpal-on-AHR with ED.
// TODO: Add assertions when Penpal is able to manage assets let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id());
system_para_test let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location);
.set_dispatchable::<AssetHubRococo>(system_para_to_para_limited_reserve_transfer_assets); AssetHubRococo::fund_accounts(vec![(sov_penpal_on_ahr.into(), ROCOCO_ED)]);
system_para_test.assert();
} let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
/// Reserve Transfers of a local asset from System Parachain to Parachain should work
#[test] let sender_assets_before = AssetHubRococo::execute_with(|| {
fn reserve_transfer_asset_from_system_para_to_para() { type Assets = <AssetHubRococo as AssetHubRococoPallet>::Assets;
// Force create asset from Relay Chain and mint assets for System Parachain's sender account <Assets as Inspect<_>>::balance(ASSET_ID, &AssetHubRococoSender::get())
AssetHubRococo::force_create_and_mint_asset( });
ASSET_ID, let receiver_assets_before = PenpalA::execute_with(|| {
ASSET_MIN_BALANCE, type Assets = <PenpalA as PenpalAPallet>::Assets;
true, <Assets as Inspect<_>>::balance(ASSET_ID, &PenpalAReceiver::get())
AssetHubRococoSender::get(), });
Some(Weight::from_parts(1_019_445_000, 200_000)),
ASSET_MIN_BALANCE * 1000000, test.set_assertion::<AssetHubRococo>(system_para_to_para_assets_sender_assertions);
); test.set_assertion::<PenpalA>(system_para_to_para_assets_receiver_assertions);
test.set_dispatchable::<AssetHubRococo>(system_para_to_para_limited_reserve_transfer_assets);
// Init values for System Parachain test.assert();
let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get(); let sender_balance_after = test.sender.balance;
let amount_to_send = ASSET_MIN_BALANCE * 1000; let receiver_balance_after = test.receiver.balance;
let assets =
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send) // Sender's balance is reduced
.into(); assert!(sender_balance_after < sender_balance_before);
// Receiver's balance is increased
let system_para_test_args = TestContext { assert!(receiver_balance_after > receiver_balance_before);
sender: AssetHubRococoSender::get(),
receiver: PenpalAReceiver::get(), let sender_assets_after = AssetHubRococo::execute_with(|| {
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), type Assets = <AssetHubRococo as AssetHubRococoPallet>::Assets;
}; <Assets as Inspect<_>>::balance(ASSET_ID, &AssetHubRococoSender::get())
});
let mut system_para_test = SystemParaToParaTest::new(system_para_test_args); let receiver_assets_after = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
system_para_test.set_assertion::<AssetHubRococo>(system_para_to_para_assets_assertions); <Assets as Inspect<_>>::balance(ASSET_ID, &PenpalAReceiver::get())
// TODO: Add assertions when Penpal is able to manage assets });
system_para_test
.set_dispatchable::<AssetHubRococo>(system_para_to_para_reserve_transfer_assets); // Sender's balance is reduced
system_para_test.assert(); assert_eq!(sender_assets_before - asset_amount_to_send, sender_assets_after);
// Receiver's balance is increased
assert!(receiver_assets_after > receiver_assets_before);
} }
@@ -51,7 +51,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) {
assert_expected_events!( assert_expected_events!(
Rococo, Rococo,
vec![ vec![
// Amount is witdrawn from Relay Chain's `CheckAccount` // Amount is withdrawn from Relay Chain's `CheckAccount`
RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => {
who: *who == <Rococo as RococoPallet>::XcmPallet::check_account(), who: *who == <Rococo as RococoPallet>::XcmPallet::check_account(),
amount: *amount == t.args.amount, amount: *amount == t.args.amount,
@@ -157,10 +157,12 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
fn limited_teleport_native_assets_from_relay_to_system_para_works() { fn limited_teleport_native_assets_from_relay_to_system_para_works() {
// Init values for Relay Chain // Init values for Relay Chain
let amount_to_send: Balance = ROCOCO_ED * 1000; let amount_to_send: Balance = ROCOCO_ED * 1000;
let dest = Rococo::child_location_of(AssetHubRococo::para_id());
let beneficiary_id = AssetHubRococoReceiver::get();
let test_args = TestContext { let test_args = TestContext {
sender: RococoSender::get(), sender: RococoSender::get(),
receiver: AssetHubRococoReceiver::get(), receiver: AssetHubRococoReceiver::get(),
args: relay_test_args(amount_to_send), args: relay_test_args(dest, beneficiary_id, amount_to_send),
}; };
let mut test = RelayToSystemParaTest::new(test_args); let mut test = RelayToSystemParaTest::new(test_args);
@@ -204,7 +206,7 @@ fn limited_teleport_native_assets_back_from_system_para_to_relay_works() {
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: RococoReceiver::get(), receiver: RococoReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
}; };
let mut test = SystemParaToRelayTest::new(test_args); let mut test = SystemParaToRelayTest::new(test_args);
@@ -245,7 +247,7 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: RococoReceiver::get(), receiver: RococoReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
}; };
let mut test = SystemParaToRelayTest::new(test_args); let mut test = SystemParaToRelayTest::new(test_args);
@@ -278,10 +280,12 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() {
fn teleport_native_assets_from_relay_to_system_para_works() { fn teleport_native_assets_from_relay_to_system_para_works() {
// Init values for Relay Chain // Init values for Relay Chain
let amount_to_send: Balance = ROCOCO_ED * 1000; let amount_to_send: Balance = ROCOCO_ED * 1000;
let dest = Rococo::child_location_of(AssetHubRococo::para_id());
let beneficiary_id = AssetHubRococoReceiver::get();
let test_args = TestContext { let test_args = TestContext {
sender: RococoSender::get(), sender: RococoSender::get(),
receiver: AssetHubRococoReceiver::get(), receiver: AssetHubRococoReceiver::get(),
args: relay_test_args(amount_to_send), args: relay_test_args(dest, beneficiary_id, amount_to_send),
}; };
let mut test = RelayToSystemParaTest::new(test_args); let mut test = RelayToSystemParaTest::new(test_args);
@@ -325,7 +329,7 @@ fn teleport_native_assets_back_from_system_para_to_relay_works() {
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: RococoReceiver::get(), receiver: RococoReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
}; };
let mut test = SystemParaToRelayTest::new(test_args); let mut test = SystemParaToRelayTest::new(test_args);
@@ -366,7 +370,7 @@ fn teleport_native_assets_from_system_para_to_relay_fails() {
let test_args = TestContext { let test_args = TestContext {
sender: AssetHubRococoSender::get(), sender: AssetHubRococoSender::get(),
receiver: RococoReceiver::get(), receiver: RococoReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), args: para_test_args(destination, beneficiary_id, amount_to_send, assets, None, 0),
}; };
let mut test = SystemParaToRelayTest::new(test_args); let mut test = SystemParaToRelayTest::new(test_args);
@@ -65,7 +65,7 @@ pub type RelayToSystemParaTest = Test<Westend, AssetHubWestend>;
pub type SystemParaToRelayTest = Test<AssetHubWestend, Westend>; pub type SystemParaToRelayTest = Test<AssetHubWestend, Westend>;
pub type SystemParaToParaTest = Test<AssetHubWestend, PenpalA>; pub type SystemParaToParaTest = Test<AssetHubWestend, PenpalA>;
/// Returns a `TestArgs` instance to de used for the Relay Chain accross integraton tests /// Returns a `TestArgs` instance to be used for the Relay Chain across integration tests
pub fn relay_test_args(amount: Balance) -> TestArgs { pub fn relay_test_args(amount: Balance) -> TestArgs {
TestArgs { TestArgs {
dest: Westend::child_location_of(AssetHubWestend::para_id()), dest: Westend::child_location_of(AssetHubWestend::para_id()),
@@ -82,7 +82,7 @@ pub fn relay_test_args(amount: Balance) -> TestArgs {
} }
} }
/// Returns a `TestArgs` instance to de used for the System Parachain accross integraton tests /// Returns a `TestArgs` instance to be used for the System Parachain across integration tests
pub fn system_para_test_args( pub fn system_para_test_args(
dest: MultiLocation, dest: MultiLocation,
beneficiary_id: AccountId32, beneficiary_id: AccountId32,
@@ -15,37 +15,8 @@
use crate::*; use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig; use asset_hub_westend_runtime::xcm_config::XcmConfig;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
fn relay_origin_assertions(t: RelayToSystemParaTest) { fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
Westend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(629_384_000, 6_196)));
assert_expected_events!(
Westend,
vec![
// Amount to reserve transfer is transferred to System Parachain's Sovereign account
RuntimeEvent::Balances(pallet_balances::Event::Transfer { from, to, amount }) => {
from: *from == t.sender.account_id,
to: *to == Westend::sovereign_account_id_of(
t.args.dest
),
amount: *amount == t.args.amount,
},
]
);
}
fn system_para_dest_assertions(_t: RelayToSystemParaTest) {
AssetHubWestend::assert_dmp_queue_incomplete(Some(Weight::from_parts(31_352_000, 1489)));
}
fn system_para_to_relay_assertions(_t: SystemParaToRelayTest) {
AssetHubWestend::assert_xcm_pallet_attempted_error(Some(XcmError::Barrier))
}
fn system_para_to_para_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( AssetHubWestend::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
@@ -56,7 +27,7 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) {
assert_expected_events!( assert_expected_events!(
AssetHubWestend, AssetHubWestend,
vec![ vec![
// Amount to reserve transfer is transferred to Parachain's Sovereing account // Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Balances( RuntimeEvent::Balances(
pallet_balances::Event::Transfer { from, to, amount } pallet_balances::Event::Transfer { from, to, amount }
) => { ) => {
@@ -70,6 +41,19 @@ fn system_para_to_para_assertions(t: SystemParaToParaTest) {
); );
} }
fn para_receiver_assertions<Test>(_: Test) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) { fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent; type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
@@ -81,7 +65,7 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) {
assert_expected_events!( assert_expected_events!(
AssetHubWestend, AssetHubWestend,
vec![ vec![
// Amount to reserve transfer is transferred to Parachain's Sovereing account // Amount to reserve transfer is transferred to Parachain's Sovereign account
RuntimeEvent::Assets( RuntimeEvent::Assets(
pallet_assets::Event::Transferred { asset_id, from, to, amount } pallet_assets::Event::Transferred { asset_id, from, to, amount }
) => { ) => {
@@ -96,48 +80,6 @@ fn system_para_to_para_assets_assertions(t: SystemParaToParaTest) {
); );
} }
fn relay_limited_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Westend as WestendPallet>::XcmPallet::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn relay_reserve_transfer_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Westend as WestendPallet>::XcmPallet::reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
)
}
fn system_para_limited_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn system_para_reserve_transfer_assets(t: SystemParaToRelayTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
)
}
fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets( <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin, t.signed_origin,
@@ -149,187 +91,72 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest)
) )
} }
fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
)
}
/// Limited Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't
/// work
#[test]
fn limited_reserve_transfer_native_asset_from_relay_to_system_para_fails() {
// Init values for Relay Chain
let amount_to_send: Balance = WESTEND_ED * 1000;
let test_args = TestContext {
sender: WestendSender::get(),
receiver: AssetHubWestendReceiver::get(),
args: relay_test_args(amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<Westend>(relay_origin_assertions);
test.set_assertion::<AssetHubWestend>(system_para_dest_assertions);
test.set_dispatchable::<Westend>(relay_limited_reserve_transfer_assets);
test.assert();
let delivery_fees = Westend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<
<WestendXcmConfig 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;
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Limited Reserve Transfers of native asset from System Parachain to Relay Chain shoudln't work
#[test]
fn limited_reserve_transfer_native_asset_from_system_para_to_relay_fails() {
// Init values for System Parachain
let destination = AssetHubWestend::parent_location();
let beneficiary_id = WestendReceiver::get();
let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000;
let assets = (Parent, amount_to_send).into();
let test_args = TestContext {
sender: AssetHubWestendSender::get(),
receiver: WestendReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None),
};
let mut test = SystemParaToRelayTest::new(test_args);
let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<AssetHubWestend>(system_para_to_relay_assertions);
test.set_dispatchable::<AssetHubWestend>(system_para_limited_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work /// Reserve Transfers of native asset from Relay Chain to the System Parachain shouldn't work
#[test] #[test]
fn reserve_transfer_native_asset_from_relay_to_system_para_fails() { fn reserve_transfer_native_asset_from_relay_to_system_para_fails() {
// Init values for Relay Chain let signed_origin = <Westend as Chain>::RuntimeOrigin::signed(WestendSender::get().into());
let destination = Westend::child_location_of(AssetHubWestend::para_id());
let beneficiary: MultiLocation =
AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into();
let amount_to_send: Balance = WESTEND_ED * 1000; let amount_to_send: Balance = WESTEND_ED * 1000;
let test_args = TestContext { let assets: MultiAssets = (Here, amount_to_send).into();
sender: WestendSender::get(), let fee_asset_item = 0;
receiver: AssetHubWestendReceiver::get(),
args: relay_test_args(amount_to_send),
};
let mut test = RelayToSystemParaTest::new(test_args); // this should fail
Westend::execute_with(|| {
let sender_balance_before = test.sender.balance; let result = <Westend as WestendPallet>::XcmPallet::limited_reserve_transfer_assets(
let receiver_balance_before = test.receiver.balance; signed_origin,
bx!(destination.into()),
test.set_assertion::<Westend>(relay_origin_assertions); bx!(beneficiary.into()),
test.set_assertion::<AssetHubWestend>(system_para_dest_assertions); bx!(assets.into()),
test.set_dispatchable::<Westend>(relay_reserve_transfer_assets); fee_asset_item,
test.assert(); WeightLimit::Unlimited,
);
let delivery_fees = Westend::execute_with(|| { assert_err!(
xcm_helpers::transfer_assets_delivery_fees::< result,
<WestendXcmConfig as xcm_executor::Config>::XcmSender, DispatchError::Module(sp_runtime::ModuleError {
>(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) index: 99,
error: [2, 0, 0, 0],
message: Some("Filtered")
})
);
}); });
let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
assert_eq!(receiver_balance_before, receiver_balance_after);
} }
/// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work /// Reserve Transfers of native asset from System Parachain to Relay Chain shouldn't work
#[test] #[test]
fn reserve_transfer_native_asset_from_system_para_to_relay_fails() { fn reserve_transfer_native_asset_from_system_para_to_relay_fails() {
// Init values for System Parachain // Init values for System Parachain
let signed_origin =
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get().into());
let destination = AssetHubWestend::parent_location(); let destination = AssetHubWestend::parent_location();
let beneficiary_id = WestendReceiver::get(); let beneficiary_id = WestendReceiver::get();
let beneficiary: MultiLocation =
AccountId32Junction { network: None, id: beneficiary_id.into() }.into();
let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000;
let assets = (Parent, amount_to_send).into(); let assets: MultiAssets = (Parent, amount_to_send).into();
let fee_asset_item = 0;
let test_args = TestContext { // this should fail
sender: AssetHubWestendSender::get(), AssetHubWestend::execute_with(|| {
receiver: WestendReceiver::get(), let result =
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None), <AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets(
}; signed_origin,
bx!(destination.into()),
let mut test = SystemParaToRelayTest::new(test_args); bx!(beneficiary.into()),
bx!(assets.into()),
let sender_balance_before = test.sender.balance; fee_asset_item,
let receiver_balance_before = test.receiver.balance; WeightLimit::Unlimited,
);
test.set_assertion::<AssetHubWestend>(system_para_to_relay_assertions); assert_err!(
test.set_dispatchable::<AssetHubWestend>(system_para_reserve_transfer_assets); result,
test.assert(); DispatchError::Module(sp_runtime::ModuleError {
index: 31,
let sender_balance_after = test.sender.balance; error: [2, 0, 0, 0],
let receiver_balance_after = test.receiver.balance; message: Some("Filtered")
})
assert_eq!(sender_balance_before, sender_balance_after); );
assert_eq!(receiver_balance_before, receiver_balance_after);
}
/// Limited Reserve Transfers of native asset from System Parachain to Parachain should work
#[test]
fn limited_reserve_transfer_native_asset_from_system_para_to_para() {
// Init values for System Parachain
let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get();
let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000;
let assets = (Parent, amount_to_send).into();
let test_args = TestContext {
sender: AssetHubWestendSender::get(),
receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None),
};
let mut test = SystemParaToParaTest::new(test_args);
let sender_balance_before = test.sender.balance;
test.set_assertion::<AssetHubWestend>(system_para_to_para_assertions);
// TODO: Add assertion for Penpal runtime. Right now message is failing with
// `UntrustedReserveLocation`
test.set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<<XcmConfig as xcm_executor::Config>::XcmSender>(
test.args.assets.clone(),
0,
test.args.weight_limit,
test.args.beneficiary,
test.args.dest,
)
}); });
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve
// transfers
} }
/// Reserve Transfers of native asset from System Parachain to Parachain should work /// Reserve Transfers of native asset from System Parachain to Parachain should work
@@ -350,14 +177,15 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
let mut test = SystemParaToParaTest::new(test_args); let mut test = SystemParaToParaTest::new(test_args);
let sender_balance_before = test.sender.balance; let sender_balance_before = test.sender.balance;
let receiver_balance_before = test.receiver.balance;
test.set_assertion::<AssetHubWestend>(system_para_to_para_assertions); test.set_assertion::<AssetHubWestend>(system_para_to_para_sender_assertions);
// TODO: Add assertion for Penpal runtime. Right now message is failing with test.set_assertion::<PenpalA>(para_receiver_assertions);
// `UntrustedReserveLocation` test.set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets);
test.set_dispatchable::<AssetHubWestend>(system_para_to_para_reserve_transfer_assets);
test.assert(); test.assert();
let sender_balance_after = test.sender.balance; let sender_balance_after = test.sender.balance;
let receiver_balance_after = test.receiver.balance;
let delivery_fees = AssetHubWestend::execute_with(|| { let delivery_fees = AssetHubWestend::execute_with(|| {
xcm_helpers::transfer_assets_delivery_fees::<<XcmConfig as xcm_executor::Config>::XcmSender>( xcm_helpers::transfer_assets_delivery_fees::<<XcmConfig as xcm_executor::Config>::XcmSender>(
@@ -369,45 +197,10 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
) )
}); });
// Sender's balance is reduced
assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after);
// TODO: Check receiver balance when Penpal runtime is improved to propery handle reserve // Receiver's balance is increased
// transfers assert!(receiver_balance_after > receiver_balance_before);
}
/// Limited Reserve Transfers of a local asset from System Parachain to Parachain should work
#[test]
fn limited_reserve_transfer_asset_from_system_para_to_para() {
// Force create asset from Relay Chain and mint assets for System Parachain's sender account
AssetHubWestend::force_create_and_mint_asset(
ASSET_ID,
ASSET_MIN_BALANCE,
true,
AssetHubWestendSender::get(),
Some(Weight::from_parts(1_019_445_000, 200_000)),
ASSET_MIN_BALANCE * 1000000,
);
// Init values for System Parachain
let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id());
let beneficiary_id = PenpalAReceiver::get();
let amount_to_send = ASSET_MIN_BALANCE * 1000;
let assets =
(X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), amount_to_send)
.into();
let system_para_test_args = TestContext {
sender: AssetHubWestendSender::get(),
receiver: PenpalAReceiver::get(),
args: system_para_test_args(destination, beneficiary_id, amount_to_send, assets, None),
};
let mut system_para_test = SystemParaToParaTest::new(system_para_test_args);
system_para_test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_assertions);
// TODO: Add assertions when Penpal is able to manage assets
system_para_test
.set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets);
system_para_test.assert();
} }
/// Reserve Transfers of a local asset from System Parachain to Parachain should work /// Reserve Transfers of a local asset from System Parachain to Parachain should work
@@ -442,6 +235,6 @@ fn reserve_transfer_asset_from_system_para_to_para() {
system_para_test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_assertions); system_para_test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_assertions);
// TODO: Add assertions when Penpal is able to manage assets // TODO: Add assertions when Penpal is able to manage assets
system_para_test system_para_test
.set_dispatchable::<AssetHubWestend>(system_para_to_para_reserve_transfer_assets); .set_dispatchable::<AssetHubWestend>(system_para_to_para_limited_reserve_transfer_assets);
system_para_test.assert(); system_para_test.assert();
} }
@@ -51,7 +51,7 @@ fn relay_dest_assertions(t: SystemParaToRelayTest) {
assert_expected_events!( assert_expected_events!(
Westend, Westend,
vec![ vec![
// Amount is witdrawn from Relay Chain's `CheckAccount` // Amount is withdrawn from Relay Chain's `CheckAccount`
RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => { RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who, amount }) => {
who: *who == <Westend as WestendPallet>::XcmPallet::check_account(), who: *who == <Westend as WestendPallet>::XcmPallet::check_account(),
amount: *amount == t.args.amount, amount: *amount == t.args.amount,
@@ -962,7 +962,7 @@ mod benches {
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -1200,6 +1200,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -1243,6 +1244,39 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between AH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// AH can reserve transfer native token to some random parachain.
let random_para_id = 43211234;
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
random_para_id.into()
);
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
ParentThen(Parachain(random_para_id).into()).into(),
))
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::{KsmLocation, MaxAssetsIntoHolding}; use xcm_config::{KsmLocation, MaxAssetsIntoHolding};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
@@ -552,11 +552,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -586,8 +581,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -18,13 +18,14 @@
//! Tests for the Statemine (Kusama Assets Hub) chain. //! Tests for the Statemine (Kusama Assets Hub) chain.
use asset_hub_kusama_runtime::xcm_config::{ use asset_hub_kusama_runtime::xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, TrustBackedAssetsPalletLocation, AssetFeeAsExistentialDepositMultiplierFeeCharger, KsmLocation, LocationToAccountId,
TrustBackedAssetsPalletLocation,
}; };
pub use asset_hub_kusama_runtime::{ pub use asset_hub_kusama_runtime::{
xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig}, xcm_config::{CheckingAccount, ForeignCreatorsSovereignAccountOf, XcmConfig},
AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime,
RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue,
}; };
use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use asset_test_utils::{CollatorSessionKeys, ExtBuilder};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -518,12 +519,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000 1000
); );
@@ -632,3 +627,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p
assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1); assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1);
}) })
); );
#[test]
fn reserve_transfer_native_asset_to_non_teleport_para_works() {
asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
XcmpQueue,
LocationToAccountId,
>(
collator_session_keys(),
ExistentialDeposit::get(),
AccountId::from(ALICE),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
WeightLimit::Unlimited,
);
}
@@ -868,7 +868,7 @@ mod benches {
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -1082,6 +1082,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -1124,6 +1125,39 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between AH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// AH can reserve transfer native token to some random parachain.
let random_para_id = 43211234;
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
random_para_id.into()
);
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
ParentThen(Parachain(random_para_id).into()).into(),
))
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::{DotLocation, MaxAssetsIntoHolding}; use xcm_config::{DotLocation, MaxAssetsIntoHolding};
use pallet_xcm_benchmarks::asset_instance_from; use pallet_xcm_benchmarks::asset_instance_from;
@@ -476,11 +476,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -510,8 +505,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -19,12 +19,13 @@
use asset_hub_polkadot_runtime::xcm_config::{ use asset_hub_polkadot_runtime::xcm_config::{
AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, DotLocation,
ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation, XcmConfig, ForeignCreatorsSovereignAccountOf, LocationToAccountId, TrustBackedAssetsPalletLocation,
XcmConfig,
}; };
pub use asset_hub_polkadot_runtime::{ pub use asset_hub_polkadot_runtime::{
AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets,
ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime,
RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue,
}; };
use asset_test_utils::{CollatorSessionKeys, ExtBuilder}; use asset_test_utils::{CollatorSessionKeys, ExtBuilder};
use codec::{Decode, Encode}; use codec::{Decode, Encode};
@@ -531,12 +532,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000 1000
); );
@@ -657,3 +652,32 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p
assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1); assert_eq!(ForeignAssets::asset_ids().collect::<Vec<_>>().len(), 1);
}) })
); );
#[test]
fn reserve_transfer_native_asset_to_non_teleport_para_works() {
asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
XcmpQueue,
LocationToAccountId,
>(
collator_session_keys(),
ExistentialDeposit::get(),
AccountId::from(ALICE),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
WeightLimit::Unlimited,
);
}
@@ -1077,7 +1077,7 @@ mod benches {
[pallet_xcm_bridge_hub_router, ToWestend] [pallet_xcm_bridge_hub_router, ToWestend]
[pallet_xcm_bridge_hub_router, ToRococo] [pallet_xcm_bridge_hub_router, ToRococo]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -1315,6 +1315,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
@@ -1368,6 +1369,39 @@ impl_runtime_apis! {
Config as XcmBridgeHubRouterConfig, Config as XcmBridgeHubRouterConfig,
}; };
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between AH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// AH can reserve transfer native token to some random parachain.
let random_para_id = 43211234;
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
random_para_id.into()
);
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
ParentThen(Parachain(random_para_id).into()).into(),
))
}
}
impl XcmBridgeHubRouterConfig<ToWococoXcmRouterInstance> for Runtime { impl XcmBridgeHubRouterConfig<ToWococoXcmRouterInstance> for Runtime {
fn make_congested() { fn make_congested() {
cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::<Runtime>( cumulus_pallet_xcmp_queue::bridging::suspend_channel_for_benchmarks::<Runtime>(
@@ -667,11 +667,6 @@ pub type XcmRouter = WithUniqueTopic<(
ToRococoXcmRouter, ToRococoXcmRouter,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -701,8 +696,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -529,12 +529,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000 1000
); );
@@ -930,6 +924,35 @@ mod asset_hub_rococo_tests {
actual actual
); );
} }
#[test]
fn reserve_transfer_native_asset_to_non_teleport_para_works() {
asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
XcmpQueue,
LocationToAccountId,
>(
collator_session_keys(),
ExistentialDeposit::get(),
AccountId::from(ALICE),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
WeightLimit::Unlimited,
);
}
} }
mod asset_hub_wococo_tests { mod asset_hub_wococo_tests {
@@ -1013,7 +1013,7 @@ mod benches {
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
[pallet_xcm_bridge_hub_router, ToRococo] [pallet_xcm_bridge_hub_router, ToRococo]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -1297,6 +1297,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
@@ -1343,6 +1344,39 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between AH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// AH can reserve transfer native token to some random parachain.
let random_para_id = 43211234;
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
random_para_id.into()
);
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
ParentThen(Parachain(random_para_id).into()).into(),
))
}
}
use pallet_xcm_bridge_hub_router::benchmarking::{ use pallet_xcm_bridge_hub_router::benchmarking::{
Pallet as XcmBridgeHubRouterBench, Pallet as XcmBridgeHubRouterBench,
Config as XcmBridgeHubRouterConfig, Config as XcmBridgeHubRouterConfig,
@@ -636,11 +636,6 @@ pub type XcmRouter = WithUniqueTopic<(
ToRococoXcmRouter, ToRococoXcmRouter,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -666,8 +661,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -525,12 +525,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000 1000
); );
@@ -815,3 +809,32 @@ fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() {
}, },
) )
} }
#[test]
fn reserve_transfer_native_asset_to_non_teleport_para_works() {
asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
ParachainSystem,
XcmpQueue,
LocationToAccountId,
>(
collator_session_keys(),
ExistentialDeposit::get(),
AccountId::from(ALICE),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::PolkadotXcm(event)) => Some(event),
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
WeightLimit::Unlimited,
);
}
@@ -27,6 +27,21 @@ use std::fmt::Debug;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{CreateMatcher, MatchXcm}; use xcm_builder::{CreateMatcher, MatchXcm};
/// Given a message, a sender, and a destination, it returns the delivery fees
fn get_fungible_delivery_fees<S: SendXcm>(destination: MultiLocation, message: Xcm<()>) -> u128 {
let Ok((_, delivery_fees)) = validate_send::<S>(destination, message) else {
unreachable!("message can be sent; qed")
};
if let Some(delivery_fee) = delivery_fees.inner().first() {
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
unreachable!("asset is fungible; qed");
};
delivery_fee_amount
} else {
0
}
}
/// Helper function to verify `xcm` contains all relevant instructions expected on destination /// Helper function to verify `xcm` contains all relevant instructions expected on destination
/// chain as part of a reserve-asset-transfer. /// chain as part of a reserve-asset-transfer.
pub(crate) fn assert_matches_reserve_asset_deposited_instructions<RuntimeCall: Debug>( pub(crate) fn assert_matches_reserve_asset_deposited_instructions<RuntimeCall: Debug>(
@@ -16,25 +16,28 @@
//! Module contains predefined test-case scenarios for `Runtime` with various assets. //! Module contains predefined test-case scenarios for `Runtime` with various assets.
use super::xcm_helpers; use super::xcm_helpers;
use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees};
use codec::Encode; use codec::Encode;
use cumulus_primitives_core::XcmpMessageSource;
use frame_support::{ use frame_support::{
assert_noop, assert_ok, assert_noop, assert_ok,
traits::{ traits::{
fungible::Mutate, fungibles::InspectEnumerable, Get, OnFinalize, OnInitialize, OriginTrait, fungible::Mutate, fungibles::InspectEnumerable, Currency, Get, OnFinalize, OnInitialize,
OriginTrait,
}, },
weights::Weight, weights::Weight,
}; };
use frame_system::pallet_prelude::BlockNumberFor; use frame_system::pallet_prelude::BlockNumberFor;
use parachains_common::{AccountId, Balance}; use parachains_common::{AccountId, Balance};
use parachains_runtimes_test_utils::{ use parachains_runtimes_test_utils::{
assert_metadata, assert_total, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, assert_metadata, assert_total, mock_open_hrmp_channel, AccountIdOf, BalanceOf,
ValidatorIdOf, XcmReceivedFrom, CollatorSessionKeys, ExtBuilder, ValidatorIdOf, XcmReceivedFrom,
}; };
use sp_runtime::{ use sp_runtime::{
traits::{MaybeEquivalence, StaticLookup, Zero}, traits::{MaybeEquivalence, StaticLookup, Zero},
DispatchError, Saturating, DispatchError, Saturating,
}; };
use xcm::latest::prelude::*; use xcm::{latest::prelude::*, VersionedMultiAssets};
use xcm_executor::{traits::ConvertLocation, XcmExecutor}; use xcm_executor::{traits::ConvertLocation, XcmExecutor};
type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> = type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
@@ -43,8 +46,8 @@ type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
// Re-export test_case from `parachains-runtimes-test-utils` // Re-export test_case from `parachains-runtimes-test-utils`
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
/// Test-case makes sure that `Runtime` can receive native asset from relay chain /// Test-case makes sure that `Runtime` can receive native asset from relay chain and can teleport
/// and can teleport it back and to the other parachains /// it back
pub fn teleports_for_native_asset_works< pub fn teleports_for_native_asset_works<
Runtime, Runtime,
AllPalletsWithoutSystem, AllPalletsWithoutSystem,
@@ -57,9 +60,6 @@ pub fn teleports_for_native_asset_works<
existential_deposit: BalanceOf<Runtime>, existential_deposit: BalanceOf<Runtime>,
target_account: AccountIdOf<Runtime>, target_account: AccountIdOf<Runtime>,
unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>, unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
unwrap_xcmp_queue_event: Box<
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
>,
runtime_para_id: u32, runtime_para_id: u32,
) where ) where
Runtime: frame_system::Config Runtime: frame_system::Config
@@ -164,12 +164,13 @@ pub fn teleports_for_native_asset_works<
// 2. try to teleport asset back to the relaychain // 2. try to teleport asset back to the relaychain
{ {
let dest = MultiLocation::parent(); let dest = MultiLocation::parent();
let dest_beneficiary = MultiLocation::parent() let mut dest_beneficiary = MultiLocation::parent()
.appended_with(AccountId32 { .appended_with(AccountId32 {
network: None, network: None,
id: sp_runtime::AccountId32::new([3; 32]).into(), id: sp_runtime::AccountId32::new([3; 32]).into(),
}) })
.unwrap(); .unwrap();
dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap();
let target_account_balance_before_teleport = let target_account_balance_before_teleport =
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account); <pallet_balances::Pallet<Runtime>>::free_balance(&target_account);
@@ -223,65 +224,53 @@ pub fn teleports_for_native_asset_works<
); );
} }
// 3. try to teleport asset away to other parachain (1234) // 3. try to teleport assets away to other parachain (2345): should not work as we don't
// trust `IsTeleporter` for `(relay-native-asset, para(2345))` pair
{ {
let other_para_id = 1234; let other_para_id = 2345;
let dest = MultiLocation::new(1, X1(Parachain(other_para_id))); let dest = MultiLocation::new(1, X1(Parachain(other_para_id)));
let dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id))) let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id)))
.appended_with(AccountId32 { .appended_with(AccountId32 {
network: None, network: None,
id: sp_runtime::AccountId32::new([3; 32]).into(), id: sp_runtime::AccountId32::new([3; 32]).into(),
}) })
.unwrap(); .unwrap();
dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap();
let target_account_balance_before_teleport = let target_account_balance_before_teleport =
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account); <pallet_balances::Pallet<Runtime>>::free_balance(&target_account);
let native_asset_to_teleport_away = native_asset_amount_unit * 3.into(); let native_asset_to_teleport_away = native_asset_amount_unit * 3.into();
assert!( assert!(
native_asset_to_teleport_away < native_asset_to_teleport_away <
target_account_balance_before_teleport - existential_deposit target_account_balance_before_teleport - existential_deposit
); );
assert_eq!(
assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>( RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
RuntimeHelper::<Runtime>::origin_of(target_account.clone()), RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
dest,
dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
Some((runtime_para_id, other_para_id)),
included_head,
&alice,
));
let delivery_fees =
xcm_helpers::transfer_assets_delivery_fees::<XcmConfig::XcmSender>(
(native_asset_id, native_asset_to_teleport_away.into()).into(),
0,
Unlimited,
dest_beneficiary,
dest, dest,
); dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
Some((runtime_para_id, other_para_id)),
included_head,
&alice,
),
Err(DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [2, 0, 0, 0,],
message: Some("Filtered",),
},),)
);
// check balances // check balances
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
target_account_balance_before_teleport - target_account_balance_before_teleport
native_asset_to_teleport_away -
delivery_fees.into()
); );
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()), <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
0.into() 0.into()
); );
// check events
RuntimeHelper::<Runtime>::assert_pallet_xcm_event_outcome(
&unwrap_pallet_xcm_event,
|outcome| {
assert_ok!(outcome.ensure_complete());
},
);
assert!(RuntimeHelper::<Runtime>::xcmp_queue_message_sent(unwrap_xcmp_queue_event)
.is_some());
} }
}) })
} }
@@ -298,7 +287,6 @@ macro_rules! include_teleports_for_native_asset_works(
$collator_session_key:expr, $collator_session_key:expr,
$existential_deposit:expr, $existential_deposit:expr,
$unwrap_pallet_xcm_event:expr, $unwrap_pallet_xcm_event:expr,
$unwrap_xcmp_queue_event:expr,
$runtime_para_id:expr $runtime_para_id:expr
) => { ) => {
#[test] #[test]
@@ -318,15 +306,14 @@ macro_rules! include_teleports_for_native_asset_works(
$existential_deposit, $existential_deposit,
target_account, target_account,
$unwrap_pallet_xcm_event, $unwrap_pallet_xcm_event,
$unwrap_xcmp_queue_event,
$runtime_para_id $runtime_para_id
) )
} }
} }
); );
/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain relay /// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain, and
/// chain /// can teleport it back
pub fn teleports_for_foreign_assets_works< pub fn teleports_for_foreign_assets_works<
Runtime, Runtime,
AllPalletsWithoutSystem, AllPalletsWithoutSystem,
@@ -381,7 +368,7 @@ pub fn teleports_for_foreign_assets_works<
<Runtime as frame_system::Config>::AccountId: From<AccountId>, <Runtime as frame_system::Config>::AccountId: From<AccountId>,
ForeignAssetsPalletInstance: 'static, ForeignAssetsPalletInstance: 'static,
{ {
// foreign parachain with the same consenus currency as asset // foreign parachain with the same consensus currency as asset
let foreign_para_id = 2222; let foreign_para_id = 2222;
let foreign_asset_id_multilocation = MultiLocation { let foreign_asset_id_multilocation = MultiLocation {
parents: 1, parents: 1,
@@ -473,7 +460,7 @@ pub fn teleports_for_foreign_assets_works<
>(foreign_asset_id_multilocation, 0, 0); >(foreign_asset_id_multilocation, 0, 0);
assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance); assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance);
// 1. process received teleported assets from relaychain // 1. process received teleported assets from sibling parachain (foreign_para_id)
let xcm = Xcm(vec![ let xcm = Xcm(vec![
// BuyExecution with relaychain native token // BuyExecution with relaychain native token
WithdrawAsset(buy_execution_fee.clone().into()), WithdrawAsset(buy_execution_fee.clone().into()),
@@ -551,12 +538,13 @@ pub fn teleports_for_foreign_assets_works<
// 2. try to teleport asset back to source parachain (foreign_para_id) // 2. try to teleport asset back to source parachain (foreign_para_id)
{ {
let dest = MultiLocation::new(1, X1(Parachain(foreign_para_id))); let dest = MultiLocation::new(1, X1(Parachain(foreign_para_id)));
let dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id))) let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(foreign_para_id)))
.appended_with(AccountId32 { .appended_with(AccountId32 {
network: None, network: None,
id: sp_runtime::AccountId32::new([3; 32]).into(), id: sp_runtime::AccountId32::new([3; 32]).into(),
}) })
.unwrap(); .unwrap();
dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap();
let target_account_balance_before_teleport = let target_account_balance_before_teleport =
<pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance( <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
@@ -1108,7 +1096,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
AssetId: Clone + Copy, AssetId: Clone + Copy,
AssetIdConverter: MaybeEquivalence<MultiLocation, AssetId>, AssetIdConverter: MaybeEquivalence<MultiLocation, AssetId>,
{ {
// foreign parachain with the same consenus currency as asset // foreign parachain with the same consensus currency as asset
let foreign_asset_id_multilocation = let foreign_asset_id_multilocation =
MultiLocation { parents: 1, interior: X2(Parachain(2222), GeneralIndex(1234567)) }; MultiLocation { parents: 1, interior: X2(Parachain(2222), GeneralIndex(1234567)) };
let asset_id = AssetIdConverter::convert(&foreign_asset_id_multilocation).unwrap(); let asset_id = AssetIdConverter::convert(&foreign_asset_id_multilocation).unwrap();
@@ -1388,3 +1376,199 @@ macro_rules! include_create_and_manage_foreign_assets_for_local_consensus_parach
} }
} }
); );
/// Test-case makes sure that `Runtime` can reserve-transfer asset to other parachains (where
/// teleport is not trusted)
pub fn reserve_transfer_native_asset_to_non_teleport_para_works<
Runtime,
AllPalletsWithoutSystem,
XcmConfig,
HrmpChannelOpener,
HrmpChannelSource,
LocationToAccountId,
>(
collator_session_keys: CollatorSessionKeys<Runtime>,
existential_deposit: BalanceOf<Runtime>,
alice_account: AccountIdOf<Runtime>,
unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
unwrap_xcmp_queue_event: Box<
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
>,
weight_limit: WeightLimit,
) where
Runtime: frame_system::Config
+ pallet_balances::Config
+ pallet_session::Config
+ pallet_xcm::Config
+ parachain_info::Config
+ pallet_collator_selection::Config
+ cumulus_pallet_parachain_system::Config
+ cumulus_pallet_xcmp_queue::Config,
AllPalletsWithoutSystem:
OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
AccountIdOf<Runtime>: Into<[u8; 32]>,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
BalanceOf<Runtime>: From<Balance>,
<Runtime as pallet_balances::Config>::Balance: From<Balance> + Into<u128>,
XcmConfig: xcm_executor::Config,
LocationToAccountId: ConvertLocation<AccountIdOf<Runtime>>,
<Runtime as frame_system::Config>::AccountId:
Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
<<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
From<<Runtime as frame_system::Config>::AccountId>,
<Runtime as frame_system::Config>::AccountId: From<AccountId>,
HrmpChannelOpener: frame_support::inherent::ProvideInherent<
Call = cumulus_pallet_parachain_system::Call<Runtime>,
>,
HrmpChannelSource: XcmpMessageSource,
{
let runtime_para_id = 1000;
ExtBuilder::<Runtime>::default()
.with_collators(collator_session_keys.collators())
.with_session_keys(collator_session_keys.session_keys())
.with_tracing()
.with_safe_xcm_version(3)
.with_para_id(runtime_para_id.into())
.build()
.execute_with(|| {
let mut alice = [0u8; 32];
alice[0] = 1;
let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
2,
AccountId::from(alice).into(),
);
// reserve-transfer native asset with local reserve to remote parachain (2345)
let other_para_id = 2345;
let native_asset = MultiLocation::parent();
let dest = MultiLocation::new(1, X1(Parachain(other_para_id)));
let mut dest_beneficiary = MultiLocation::new(1, X1(Parachain(other_para_id)))
.appended_with(AccountId32 {
network: None,
id: sp_runtime::AccountId32::new([3; 32]).into(),
})
.unwrap();
dest_beneficiary.reanchor(&dest, XcmConfig::UniversalLocation::get()).unwrap();
let reserve_account = LocationToAccountId::convert_location(&dest)
.expect("Sovereign account for reserves");
let balance_to_transfer = 1_000_000_000_000_u128;
// open HRMP to other parachain
mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
runtime_para_id.into(),
other_para_id.into(),
included_head,
&alice,
);
// we calculate exact delivery fees _after_ sending the message by weighing the sent
// xcm, and this delivery fee varies for different runtimes, so just add enough buffer,
// then verify the arithmetics check out on final balance.
let delivery_fees_buffer = 40_000_000_000u128;
// drip 2xED + transfer_amount + delivery_fees_buffer to Alice account
let alice_account_init_balance = existential_deposit.saturating_mul(2.into()) +
balance_to_transfer.into() +
delivery_fees_buffer.into();
let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating(
&alice_account,
alice_account_init_balance,
);
// SA of target location needs to have at least ED, otherwise making reserve fails
let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating(
&reserve_account,
existential_deposit,
);
// we just check here, that user retains enough balance after withdrawal
// and also we check if `balance_to_transfer` is more than `existential_deposit`,
assert!(
(<pallet_balances::Pallet<Runtime>>::free_balance(&alice_account) -
balance_to_transfer.into()) >=
existential_deposit
);
// SA has just ED
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
existential_deposit
);
// local native asset (pallet_balances)
let asset_to_transfer = MultiAsset {
fun: Fungible(balance_to_transfer.into()),
id: Concrete(native_asset),
};
// pallet_xcm call reserve transfer
assert_ok!(<pallet_xcm::Pallet<Runtime>>::limited_reserve_transfer_assets(
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()),
Box::new(dest.into_versioned()),
Box::new(dest_beneficiary.into_versioned()),
Box::new(VersionedMultiAssets::from(MultiAssets::from(asset_to_transfer))),
0,
weight_limit,
));
// check events
// check pallet_xcm attempted
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::assert_pallet_xcm_event_outcome(
&unwrap_pallet_xcm_event,
|outcome| {
assert_ok!(outcome.ensure_complete());
},
);
// check that xcm was sent
let xcm_sent_message_hash = <frame_system::Pallet<Runtime>>::events()
.into_iter()
.filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
.find_map(|e| match e {
cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
Some(message_hash),
_ => None,
});
// read xcm
let xcm_sent = RuntimeHelper::<HrmpChannelSource, AllPalletsWithoutSystem>::take_xcm(
other_para_id.into(),
)
.unwrap();
let delivery_fees = get_fungible_delivery_fees::<
<XcmConfig as xcm_executor::Config>::XcmSender,
>(dest, Xcm::try_from(xcm_sent.clone()).unwrap());
assert_eq!(
xcm_sent_message_hash,
Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256))
);
let mut xcm_sent: Xcm<()> = xcm_sent.try_into().expect("versioned xcm");
// check sent XCM Program to other parachain
println!("reserve_transfer_native_asset_works sent xcm: {:?}", xcm_sent);
let reserve_assets_deposited = MultiAssets::from(vec![MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(1000000000000),
}]);
assert_matches_reserve_asset_deposited_instructions(
&mut xcm_sent,
&reserve_assets_deposited,
&dest_beneficiary,
);
// check alice account decreased by balance_to_transfer ( + delivery_fees)
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
alice_account_init_balance - balance_to_transfer.into() - delivery_fees.into()
);
// check reserve account
// check reserve account increased by balance_to_transfer
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
existential_deposit + balance_to_transfer.into()
);
})
}
@@ -16,7 +16,7 @@
//! Module contains predefined test-case scenarios for `Runtime` with various assets transferred //! Module contains predefined test-case scenarios for `Runtime` with various assets transferred
//! over a bridge. //! over a bridge.
use crate::assert_matches_reserve_asset_deposited_instructions; use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees};
use codec::Encode; use codec::Encode;
use cumulus_primitives_core::XcmpMessageSource; use cumulus_primitives_core::XcmpMessageSource;
use frame_support::{ use frame_support::{
@@ -32,10 +32,7 @@ use parachains_runtimes_test_utils::{
use sp_runtime::{traits::StaticLookup, Saturating}; use sp_runtime::{traits::StaticLookup, Saturating};
use xcm::{latest::prelude::*, VersionedMultiAssets}; use xcm::{latest::prelude::*, VersionedMultiAssets};
use xcm_builder::{CreateMatcher, MatchXcm}; use xcm_builder::{CreateMatcher, MatchXcm};
use xcm_executor::{ use xcm_executor::{traits::ConvertLocation, XcmExecutor};
traits::{ConvertLocation, TransactAsset},
XcmExecutor,
};
pub struct TestBridgingConfig { pub struct TestBridgingConfig {
pub bridged_network: NetworkId, pub bridged_network: NetworkId,
@@ -129,8 +126,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
&alice, &alice,
); );
// drip ED to account // we calculate exact delivery fees _after_ sending the message by weighing the sent
let alice_account_init_balance = existential_deposit + balance_to_transfer.into(); // xcm, and this delivery fee varies for different runtimes, so just add enough buffer,
// then verify the arithmetics check out on final balance.
let delivery_fees_buffer = 8_000_000_000_000u128;
// drip ED + transfer_amount + delivery_fees_buffer to Alice account
let alice_account_init_balance =
existential_deposit + balance_to_transfer.into() + delivery_fees_buffer.into();
let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating( let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating(
&alice_account, &alice_account,
alice_account_init_balance, alice_account_init_balance,
@@ -183,56 +185,6 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
let expected_beneficiary = target_destination_account; let expected_beneficiary = target_destination_account;
// Make sure sender has enough funds for paying delivery fees
let handling_delivery_fees = {
// Probable XCM with `ReserveAssetDeposited`.
let mut expected_reserve_asset_deposited_message = Xcm(vec![
ReserveAssetDeposited(MultiAssets::from(expected_assets.clone())),
ClearOrigin,
BuyExecution {
fees: MultiAsset {
id: Concrete(Default::default()),
fun: Fungible(balance_to_transfer),
},
weight_limit: Unlimited,
},
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: expected_beneficiary },
SetTopic([
220, 188, 144, 32, 213, 83, 111, 175, 44, 210, 111, 19, 90, 165, 191, 112,
140, 247, 192, 124, 42, 17, 153, 141, 114, 34, 189, 20, 83, 69, 237, 173,
]),
]);
assert_matches_reserve_asset_deposited_instructions(
&mut expected_reserve_asset_deposited_message,
&expected_assets,
&expected_beneficiary,
);
// Call `SendXcm::validate` to get delivery fees.
let (_, delivery_fees): (_, MultiAssets) = XcmConfig::XcmSender::validate(
&mut Some(target_location_from_different_consensus),
&mut Some(expected_reserve_asset_deposited_message),
)
.expect("validate passes");
// Drip delivery fee to Alice account.
let mut delivery_fees_added = false;
for delivery_fee in delivery_fees.inner() {
assert_ok!(<XcmConfig::AssetTransactor as TransactAsset>::deposit_asset(
&delivery_fee,
&MultiLocation {
parents: 0,
interior: X1(AccountId32 {
network: None,
id: alice_account.clone().into(),
}),
},
None,
));
delivery_fees_added = true;
}
delivery_fees_added
};
// do pallet_xcm call reserve transfer // do pallet_xcm call reserve transfer
assert_ok!(<pallet_xcm::Pallet<Runtime>>::limited_reserve_transfer_assets( assert_ok!(<pallet_xcm::Pallet<Runtime>>::limited_reserve_transfer_assets(
RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()), RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()),
@@ -275,6 +227,7 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
// check sent XCM ExportMessage to BridgeHub // check sent XCM ExportMessage to BridgeHub
let mut delivery_fees = 0;
// 1. check paid or unpaid // 1. check paid or unpaid
if let Some(expected_fee_asset_id) = maybe_paid_export_message { if let Some(expected_fee_asset_id) = maybe_paid_export_message {
xcm_sent xcm_sent
@@ -315,6 +268,10 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
.split_global() .split_global()
.expect("split works"); .expect("split works");
assert_eq!(destination, &target_location_junctions_without_global_consensus); assert_eq!(destination, &target_location_junctions_without_global_consensus);
// Call `SendXcm::validate` to get delivery fees.
delivery_fees = get_fungible_delivery_fees::<
<XcmConfig as xcm_executor::Config>::XcmSender,
>(target_location_from_different_consensus, inner_xcm.clone());
assert_matches_reserve_asset_deposited_instructions( assert_matches_reserve_asset_deposited_instructions(
inner_xcm, inner_xcm,
&expected_assets, &expected_assets,
@@ -330,8 +287,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
assert_eq!( assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&alice_account), <pallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
alice_account_init_balance alice_account_init_balance
.saturating_sub(existential_deposit)
.saturating_sub(balance_to_transfer.into()) .saturating_sub(balance_to_transfer.into())
.saturating_sub(delivery_fees.into())
); );
// check reserve account increased by balance_to_transfer // check reserve account increased by balance_to_transfer
@@ -341,14 +298,13 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
); );
// check dedicated account increased by delivery fees (if configured) // check dedicated account increased by delivery fees (if configured)
if handling_delivery_fees { if let Some(delivery_fees_account) = delivery_fees_account {
if let Some(delivery_fees_account) = delivery_fees_account { let delivery_fees_account_balance_after =
let delivery_fees_account_balance_after = <pallet_balances::Pallet<Runtime>>::free_balance(&delivery_fees_account);
<pallet_balances::Pallet<Runtime>>::free_balance(&delivery_fees_account); assert!(
assert!( delivery_fees_account_balance_after - delivery_fees.into() >=
delivery_fees_account_balance_after > delivery_fees_account_balance_before delivery_fees_account_balance_before
); );
}
} }
}) })
} }
@@ -270,7 +270,7 @@ cd <polkadot-sdk-git-repo-dir>
### Send messages - transfer asset over bridge (ROCs/WNDs) ### Send messages - transfer asset over bridge (ROCs/WNDs)
Do (asset) transfers: Do reserve-backed transfers:
``` ```
cd <polkadot-sdk-git-repo-dir> cd <polkadot-sdk-git-repo-dir>
@@ -291,6 +291,20 @@ cd <polkadot-sdk-git-repo-dir>
- AssetHubWestend (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer - AssetHubWestend (see `foreignAssets.Issued`, `xcmpQueue.Success`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer
- BridgeHubRocococ (see `bridgeWestendMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer - BridgeHubRocococ (see `bridgeWestendMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer
Do reserve withdraw transfers: (when previous is finished)
```
cd <polkadot-sdk-git-repo-dir>
# wrappedWNDs from Rococo's Asset Hub to Westend's.
./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-rococo-local
```
```
cd <polkadot-sdk-git-repo-dir>
# wrappedROCs from Westend's Asset Hub to Rococo's.
./cumulus/scripts/bridges_rococo_westend.sh withdraw-reserve-assets-from-asset-hub-westend-local
```
### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend ### Claim relayer's rewards on BridgeHubRococo and BridgeHubWestend
**Accounts of BridgeHub parachains:** **Accounts of BridgeHub parachains:**
@@ -490,7 +490,7 @@ mod benches {
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -670,6 +670,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -705,6 +706,29 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between BH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on BH.
None
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::KsmRelayLocation; use xcm_config::KsmRelayLocation;
@@ -241,11 +241,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -274,8 +269,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1002 1002
); );
@@ -491,7 +491,7 @@ mod benches {
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -671,6 +671,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -706,6 +707,29 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between BH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on BH.
None
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::DotRelayLocation; use xcm_config::DotRelayLocation;
@@ -245,11 +245,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -278,8 +273,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1002 1002
); );
@@ -595,7 +595,7 @@ mod benches {
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -933,6 +933,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -980,6 +981,29 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between BH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on BH.
None
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::TokenLocation; use xcm_config::TokenLocation;
@@ -349,11 +349,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmRouter = XcmRouter; type XcmRouter = XcmRouter;
@@ -381,8 +376,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -133,12 +133,6 @@ mod bridge_hub_rococo_tests {
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID
); );
@@ -517,12 +511,6 @@ mod bridge_hub_wococo_tests {
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID
); );
@@ -544,7 +544,7 @@ mod benches {
[pallet_collator_selection, CollatorSelection] [pallet_collator_selection, CollatorSelection]
[cumulus_pallet_xcmp_queue, XcmpQueue] [cumulus_pallet_xcmp_queue, XcmpQueue]
// XCM // XCM
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -772,6 +772,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
// This is defined once again in dispatch_benchmark, because list_benchmarks! // This is defined once again in dispatch_benchmark, because list_benchmarks!
// and add_benchmarks! are macros exported by define_benchmarks! macros and those types // and add_benchmarks! are macros exported by define_benchmarks! macros and those types
@@ -813,6 +814,29 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between BH and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on BH.
None
}
}
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::WestendLocation; use xcm_config::WestendLocation;
@@ -284,11 +284,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type XcmRouter = XcmRouter; type XcmRouter = XcmRouter;
@@ -316,8 +311,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -118,12 +118,6 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
_ => None, _ => None,
} }
}), }),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID
); );
@@ -751,7 +751,7 @@ mod benches {
[cumulus_pallet_dmp_queue, DmpQueue] [cumulus_pallet_dmp_queue, DmpQueue]
[pallet_alliance, Alliance] [pallet_alliance, Alliance]
[pallet_collective, AllianceMotion] [pallet_collective, AllianceMotion]
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
[pallet_preimage, Preimage] [pallet_preimage, Preimage]
[pallet_scheduler, Scheduler] [pallet_scheduler, Scheduler]
[pallet_referenda, FellowshipReferenda] [pallet_referenda, FellowshipReferenda]
@@ -939,6 +939,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
let mut list = Vec::<BenchmarkList>::new(); let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra); list_benchmarks!(list, extra);
@@ -968,6 +969,29 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between Collectives and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
}.into(),
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on Collectives.
None
}
}
let whitelist: Vec<TrackedStorageKey> = vec![ let whitelist: Vec<TrackedStorageKey> = vec![
// Block Number // Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
@@ -293,11 +293,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
/// Type to convert the Fellows origin to a Plurality `MultiLocation` value. /// Type to convert the Fellows origin to a Plurality `MultiLocation` value.
pub type FellowsToPlurality = OriginToPluralityVoice<RuntimeOrigin, Fellows, FellowsBodyId>; pub type FellowsToPlurality = OriginToPluralityVoice<RuntimeOrigin, Fellows, FellowsBodyId>;
@@ -325,8 +320,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -433,7 +433,7 @@ mod benches {
[pallet_timestamp, Timestamp] [pallet_timestamp, Timestamp]
[pallet_collator_selection, CollatorSelection] [pallet_collator_selection, CollatorSelection]
[pallet_contracts, Contracts] [pallet_contracts, Contracts]
[pallet_xcm, PolkadotXcm] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
); );
} }
@@ -678,6 +678,7 @@ impl_runtime_apis! {
use frame_support::traits::StorageInfoTrait; use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
let mut list = Vec::<BenchmarkList>::new(); let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra); list_benchmarks!(list, extra);
@@ -707,6 +708,30 @@ impl_runtime_apis! {
use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {} impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use xcm::latest::prelude::*;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported between Contracts-System-Para and Relay.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Reserve transfers are disabled on Contracts-System-Para.
None
}
}
let whitelist: Vec<TrackedStorageKey> = vec![ let whitelist: Vec<TrackedStorageKey> = vec![
// Block Number // Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
@@ -227,11 +227,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
// We want to disallow users sending (arbitrary) XCMs from this chain. // We want to disallow users sending (arbitrary) XCMs from this chain.
@@ -258,8 +253,6 @@ impl pallet_xcm::Config for Runtime {
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
// FIXME: Replace with benchmarked weight info // FIXME: Replace with benchmarked weight info
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -434,7 +434,7 @@ parameter_types! {
// pub type AssetsForceOrigin = // pub type AssetsForceOrigin =
// EnsureOneOf<EnsureRoot<AccountId>, EnsureXcm<IsMajorityOfBody<KsmLocation, ExecutiveBody>>>; // EnsureOneOf<EnsureRoot<AccountId>, EnsureXcm<IsMajorityOfBody<KsmLocation, ExecutiveBody>>>;
impl pallet_assets::Config for Runtime { impl pallet_assets::Config<pallet_assets::Instance1> for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type Balance = Balance; type Balance = Balance;
type AssetId = AssetId; type AssetId = AssetId;
@@ -577,7 +577,12 @@ impl pallet_asset_tx_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type Fungibles = Assets; type Fungibles = Assets;
type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter<
pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>, pallet_assets::BalanceToAssetBalance<
Balances,
Runtime,
ConvertInto,
pallet_assets::Instance1,
>,
AssetsToBlockAuthor<Runtime>, AssetsToBlockAuthor<Runtime>,
>; >;
} }
@@ -619,7 +624,7 @@ construct_runtime!(
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 34, MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 34,
// The main stage. // The main stage.
Assets: pallet_assets::{Pallet, Call, Storage, Event<T>} = 50, Assets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 50,
Sudo: pallet_sudo::{Pallet, Call, Storage, Event<T>, Config<T>} = 255, Sudo: pallet_sudo::{Pallet, Call, Storage, Event<T>, Config<T>} = 255,
} }
@@ -38,6 +38,7 @@ use frame_support::{
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
use pallet_asset_tx_payment::HandleCredit; use pallet_asset_tx_payment::HandleCredit;
use pallet_assets::Instance1;
use pallet_xcm::XcmPassthrough; use pallet_xcm::XcmPassthrough;
use polkadot_parachain_primitives::primitives::Sibling; use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::impls::ToAuthor; use polkadot_runtime_common::impls::ToAuthor;
@@ -48,9 +49,10 @@ use xcm_builder::{
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, ConvertedConcreteId, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry,
EnsureXcmOrigin, FixedWeightBounds, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, EnsureXcmOrigin, FixedWeightBounds, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WithComputedOrigin, WithUniqueTopic,
}; };
use xcm_executor::{traits::JustTry, XcmExecutor}; use xcm_executor::{traits::JustTry, XcmExecutor};
@@ -126,6 +128,9 @@ pub type XcmOriginToTransactDispatchOrigin = (
// Native converter for sibling Parachains; will convert to a `SiblingPara` origin when // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
// recognized. // recognized.
SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>, SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
// Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a
// transaction from the Root origin.
ParentAsSuperuser<RuntimeOrigin>,
// Native signed account converter; this just converts an `AccountId32` origin into a normal // Native signed account converter; this just converts an `AccountId32` origin into a normal
// `RuntimeOrigin::Signed` origin of the same 32-byte value. // `RuntimeOrigin::Signed` origin of the same 32-byte value.
SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>, SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
@@ -182,14 +187,25 @@ pub type Barrier = TrailingSetTopicAsId<
/// Type alias to conveniently refer to `frame_system`'s `Config::AccountId`. /// Type alias to conveniently refer to `frame_system`'s `Config::AccountId`.
pub type AccountIdOf<R> = <R as frame_system::Config>::AccountId; pub type AccountIdOf<R> = <R as frame_system::Config>::AccountId;
/// Asset filter that allows all assets from a certain location. /// Asset filter that allows all assets from a certain location matching asset id.
pub struct AssetsFrom<T>(PhantomData<T>); pub struct AssetsFrom<T>(PhantomData<T>);
impl<T: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> for AssetsFrom<T> { impl<T: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> for AssetsFrom<T> {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
let loc = T::get(); let loc = T::get();
&loc == origin && &loc == origin &&
matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) }
if asset_loc.match_and_split(&loc).is_some()) if asset_loc.starts_with(&loc))
}
}
/// Asset filter that allows native/relay asset if coming from a certain location.
pub struct NativeAssetFrom<T>(PhantomData<T>);
impl<T: Get<MultiLocation>> ContainsPair<MultiAsset, MultiLocation> for NativeAssetFrom<T> {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
let loc = T::get();
&loc == origin &&
matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) }
if *asset_loc == MultiLocation::from(Parent))
} }
} }
@@ -208,56 +224,19 @@ where
/// A `HandleCredit` implementation that naively transfers the fees to the block author. /// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails. /// Will drop and burn the assets in case the transfer fails.
pub struct AssetsToBlockAuthor<R>(PhantomData<R>); pub struct AssetsToBlockAuthor<R>(PhantomData<R>);
impl<R> HandleCredit<AccountIdOf<R>, pallet_assets::Pallet<R>> for AssetsToBlockAuthor<R> impl<R> HandleCredit<AccountIdOf<R>, pallet_assets::Pallet<R, Instance1>> for AssetsToBlockAuthor<R>
where where
R: pallet_authorship::Config + pallet_assets::Config, R: pallet_authorship::Config + pallet_assets::Config<Instance1>,
AccountIdOf<R>: From<polkadot_primitives::AccountId> + Into<polkadot_primitives::AccountId>, AccountIdOf<R>: From<polkadot_primitives::AccountId> + Into<polkadot_primitives::AccountId>,
{ {
fn handle_credit(credit: Credit<AccountIdOf<R>, pallet_assets::Pallet<R>>) { fn handle_credit(credit: Credit<AccountIdOf<R>, pallet_assets::Pallet<R, Instance1>>) {
if let Some(author) = pallet_authorship::Pallet::<R>::author() { if let Some(author) = pallet_authorship::Pallet::<R>::author() {
// In case of error: Will drop the result triggering the `OnDrop` of the imbalance. // In case of error: Will drop the result triggering the `OnDrop` of the imbalance.
let _ = pallet_assets::Pallet::<R>::resolve(&author, credit); let _ = pallet_assets::Pallet::<R, Instance1>::resolve(&author, credit);
} }
} }
} }
pub trait Reserve {
/// Returns assets reserve location.
fn reserve(&self) -> Option<MultiLocation>;
}
// Takes the chain part of a MultiAsset
impl Reserve for MultiAsset {
fn reserve(&self) -> Option<MultiLocation> {
if let AssetId::Concrete(location) = self.id {
let first_interior = location.first_interior();
let parents = location.parent_count();
match (parents, first_interior) {
(0, Some(Parachain(id))) => Some(MultiLocation::new(0, X1(Parachain(*id)))),
(1, Some(Parachain(id))) => Some(MultiLocation::new(1, X1(Parachain(*id)))),
(1, _) => Some(MultiLocation::parent()),
_ => None,
}
} else {
None
}
}
}
/// A `FilterAssetLocation` implementation. Filters multi native assets whose
/// reserve is same with `origin`.
pub struct MultiNativeAsset;
impl ContainsPair<MultiAsset, MultiLocation> for MultiNativeAsset {
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
if let Some(ref reserve) = asset.reserve() {
if reserve == origin {
return true
}
}
false
}
}
parameter_types! { parameter_types! {
/// The location that this chain recognizes as the Relay network's Asset Hub. /// The location that this chain recognizes as the Relay network's Asset Hub.
pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000)));
@@ -268,7 +247,8 @@ parameter_types! {
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub CheckingAccount: AccountId = PolkadotXcm::check_account();
} }
pub type Reserves = (NativeAsset, AssetsFrom<SystemAssetHubLocation>); pub type Reserves =
(NativeAsset, AssetsFrom<SystemAssetHubLocation>, NativeAssetFrom<SystemAssetHubLocation>);
pub struct XcmConfig; pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig { impl xcm_executor::Config for XcmConfig {
@@ -277,7 +257,8 @@ impl xcm_executor::Config for XcmConfig {
// How to withdraw and deposit an asset. // How to withdraw and deposit an asset.
type AssetTransactor = AssetTransactors; type AssetTransactor = AssetTransactors;
type OriginConverter = XcmOriginToTransactDispatchOrigin; type OriginConverter = XcmOriginToTransactDispatchOrigin;
type IsReserve = MultiNativeAsset; // TODO: maybe needed to be replaced by Reserves type IsReserve = Reserves;
// no teleport trust established with other chains
type IsTeleporter = NativeAsset; type IsTeleporter = NativeAsset;
type UniversalLocation = UniversalLocation; type UniversalLocation = UniversalLocation;
type Barrier = Barrier; type Barrier = Barrier;
@@ -312,11 +293,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -342,8 +318,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
@@ -492,11 +492,6 @@ pub type XcmRouter = WithUniqueTopic<(
XcmpQueue, XcmpQueue,
)>; )>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -518,8 +513,6 @@ impl pallet_xcm::Config for Runtime {
type SovereignAccountOf = LocationToAccountId; type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>; type MaxLockers = ConstU32<8>;
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
+27 -1
View File
@@ -301,9 +301,21 @@ case "$1" in
0 \ 0 \
"Unlimited" "Unlimited"
;; ;;
withdraw-reserve-assets-from-asset-hub-rococo-local)
ensure_polkadot_js_api
# send back only 100000000000 wrappedWNDs to Alice account on AHW
limited_reserve_transfer_assets \
"ws://127.0.0.1:9910" \
"//Alice" \
"$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \
"$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \
"$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": 140000000000 } } ] }')" \
0 \
"Unlimited"
;;
reserve-transfer-assets-from-asset-hub-westend-local) reserve-transfer-assets-from-asset-hub-westend-local)
ensure_polkadot_js_api ensure_polkadot_js_api
# send WOCs to Alice account on AHR # send WNDs to Alice account on AHR
limited_reserve_transfer_assets \ limited_reserve_transfer_assets \
"ws://127.0.0.1:9010" \ "ws://127.0.0.1:9010" \
"//Alice" \ "//Alice" \
@@ -313,6 +325,18 @@ case "$1" in
0 \ 0 \
"Unlimited" "Unlimited"
;; ;;
withdraw-reserve-assets-from-asset-hub-westend-local)
ensure_polkadot_js_api
# send back only 100000000000 wrappedROCs to Alice account on AHR
limited_reserve_transfer_assets \
"ws://127.0.0.1:9010" \
"//Alice" \
"$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \
"$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \
"$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": 100000000000 } } ] }')" \
0 \
"Unlimited"
;;
claim-rewards-bridge-hub-rococo-local) claim-rewards-bridge-hub-rococo-local)
ensure_polkadot_js_api ensure_polkadot_js_api
# bhwd -> [62, 68, 77, 64] -> 0x62687764 # bhwd -> [62, 68, 77, 64] -> 0x62687764
@@ -360,7 +384,9 @@ case "$1" in
- init-asset-hub-westend-local - init-asset-hub-westend-local
- init-bridge-hub-westend-local - init-bridge-hub-westend-local
- reserve-transfer-assets-from-asset-hub-rococo-local - reserve-transfer-assets-from-asset-hub-rococo-local
- withdraw-reserve-assets-from-asset-hub-rococo-local
- reserve-transfer-assets-from-asset-hub-westend-local - reserve-transfer-assets-from-asset-hub-westend-local
- withdraw-reserve-assets-from-asset-hub-westend-local
- claim-rewards-bridge-hub-rococo-local - claim-rewards-bridge-hub-rococo-local
- claim-rewards-bridge-hub-westend-local"; - claim-rewards-bridge-hub-westend-local";
exit 1 exit 1
+4 -4
View File
@@ -1443,9 +1443,9 @@ pub struct TestContext<T, Origin: Chain, Destination: Chain> {
/// These arguments can be easily reused and shared between the assertion functions /// These arguments can be easily reused and shared between the assertion functions
/// and dispatchable functions, which are also stored in `Test`. /// and dispatchable functions, which are also stored in `Test`.
/// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution. /// `Origin` corresponds to the chain where the XCM interaction starts with an initial execution.
/// `Destination` corresponds to the last chain where an effect of the intial execution is expected /// `Destination` corresponds to the last chain where an effect of the initial execution is expected
/// happen. `Hops` refer all the ordered intermediary chains an initial XCM execution can provoke /// to happen. `Hops` refer to all the ordered intermediary chains an initial XCM execution can
/// some effect. /// provoke some effect on.
#[derive(Clone)] #[derive(Clone)]
pub struct Test<Origin, Destination, Hops = (), Args = TestArgs> pub struct Test<Origin, Destination, Hops = (), Args = TestArgs>
where where
@@ -1499,7 +1499,7 @@ where
let chain_name = std::any::type_name::<Hop>(); let chain_name = std::any::type_name::<Hop>();
self.hops_assertion.insert(chain_name.to_string(), assertion); self.hops_assertion.insert(chain_name.to_string(), assertion);
} }
/// Stores an assertion in a particular Chain /// Stores a dispatchable in a particular Chain
pub fn set_dispatchable<Hop>(&mut self, dispatchable: fn(Self) -> DispatchResult) { pub fn set_dispatchable<Hop>(&mut self, dispatchable: fn(Self) -> DispatchResult) {
let chain_name = std::any::type_name::<Hop>(); let chain_name = std::any::type_name::<Hop>();
self.hops_dispatchable.insert(chain_name.to_string(), dispatchable); self.hops_dispatchable.insert(chain_name.to_string(), dispatchable);
+1 -1
View File
@@ -2064,7 +2064,7 @@ impl<T: Config> Pallet<T> {
} }
/// Submits a given PVF check statement with corresponding signature as an unsigned transaction /// Submits a given PVF check statement with corresponding signature as an unsigned transaction
/// into the memory pool. Ultimately, that disseminates the transaction accross the network. /// into the memory pool. Ultimately, that disseminates the transaction across the network.
/// ///
/// This function expects an offchain context and cannot be callable from the on-chain logic. /// This function expects an offchain context and cannot be callable from the on-chain logic.
/// ///
+31 -1
View File
@@ -1588,7 +1588,7 @@ mod benches {
[pallet_asset_rate, AssetRate] [pallet_asset_rate, AssetRate]
[pallet_whitelist, Whitelist] [pallet_whitelist, Whitelist]
// XCM // XCM
[pallet_xcm, XcmPallet] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
[pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>] [pallet_xcm_benchmarks::fungible, pallet_xcm_benchmarks::fungible::Pallet::<Runtime>]
[pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>] [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
); );
@@ -2064,6 +2064,8 @@ sp_api::impl_runtime_apis! {
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline; use frame_benchmarking::baseline::Pallet as Baseline;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
let mut list = Vec::<BenchmarkList>::new(); let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra); list_benchmarks!(list, extra);
@@ -2081,6 +2083,7 @@ sp_api::impl_runtime_apis! {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError};
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use frame_benchmarking::baseline::Pallet as Baseline; use frame_benchmarking::baseline::Pallet as Baseline;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use sp_storage::TrackedStorageKey; use sp_storage::TrackedStorageKey;
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_config::{ use xcm_config::{
@@ -2097,6 +2100,33 @@ sp_api::impl_runtime_apis! {
impl frame_system_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {}
impl frame_benchmarking::baseline::Config for Runtime {} impl frame_benchmarking::baseline::Config for Runtime {}
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(crate::xcm_config::AssetHub::get())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported to/from AH.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Here.into())
},
crate::xcm_config::AssetHub::get(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay can reserve transfer native token to some random parachain.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Here.into())
},
Parachain(43211234).into(),
))
}
}
impl pallet_xcm_benchmarks::Config for Runtime { impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = XcmConfig; type XcmConfig = XcmConfig;
type AccountIdConverter = LocationConverter; type AccountIdConverter = LocationConverter;
@@ -211,11 +211,6 @@ parameter_types! {
pub const FellowsBodyId: BodyId = BodyId::Technical; pub const FellowsBodyId: BodyId = BodyId::Technical;
} }
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
}
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior
/// location of this chain. /// location of this chain.
pub type LocalOriginToLocation = ( pub type LocalOriginToLocation = (
@@ -269,7 +264,5 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
@@ -127,11 +127,6 @@ impl xcm_executor::Config for XcmConfig {
type Aliasers = Nothing; type Aliasers = Nothing;
} }
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(xcm::latest::Junctions::Here.into());
}
impl pallet_xcm::Config for crate::Runtime { impl pallet_xcm::Config for crate::Runtime {
// The config types here are entirely configurable, since the only one that is sorely needed // The config types here are entirely configurable, since the only one that is sorely needed
// is `XcmExecutor`, which will be used in unit tests located in xcm-executor. // is `XcmExecutor`, which will be used in unit tests located in xcm-executor.
@@ -157,7 +152,5 @@ impl pallet_xcm::Config for crate::Runtime {
type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<crate::AccountId>; type AdminOrigin = EnsureRoot<crate::AccountId>;
} }
+27 -1
View File
@@ -1626,7 +1626,7 @@ mod benches {
[pallet_whitelist, Whitelist] [pallet_whitelist, Whitelist]
[pallet_asset_rate, AssetRate] [pallet_asset_rate, AssetRate]
// XCM // XCM
[pallet_xcm, XcmPallet] [pallet_xcm, PalletXcmExtrinsiscsBenchmark::<Runtime>]
// NOTE: Make sure you point to the individual modules below. // NOTE: Make sure you point to the individual modules below.
[pallet_xcm_benchmarks::fungible, XcmBalances] [pallet_xcm_benchmarks::fungible, XcmBalances]
[pallet_xcm_benchmarks::generic, XcmGeneric] [pallet_xcm_benchmarks::generic, XcmGeneric]
@@ -2145,6 +2145,7 @@ sp_api::impl_runtime_apis! {
use pallet_session_benchmarking::Pallet as SessionBench; use pallet_session_benchmarking::Pallet as SessionBench;
use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_offences_benchmarking::Pallet as OffencesBench;
use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
@@ -2172,12 +2173,37 @@ sp_api::impl_runtime_apis! {
use pallet_session_benchmarking::Pallet as SessionBench; use pallet_session_benchmarking::Pallet as SessionBench;
use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_offences_benchmarking::Pallet as OffencesBench;
use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench;
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsiscsBenchmark;
use frame_system_benchmarking::Pallet as SystemBench; use frame_system_benchmarking::Pallet as SystemBench;
use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench;
impl pallet_session_benchmarking::Config for Runtime {} impl pallet_session_benchmarking::Config for Runtime {}
impl pallet_offences_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {}
impl pallet_election_provider_support_benchmarking::Config for Runtime {} impl pallet_election_provider_support_benchmarking::Config for Runtime {}
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
Some(crate::xcm_config::AssetHub::get())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay/native token can be teleported to/from AH.
Some((
MultiAsset { fun: Fungible(EXISTENTIAL_DEPOSIT), id: Concrete(Here.into()) },
crate::xcm_config::AssetHub::get(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
// Relay can reserve transfer native token to some random parachain.
Some((
MultiAsset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Here.into())
},
crate::Junction::Parachain(43211234).into(),
))
}
}
impl frame_system_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {}
impl pallet_nomination_pools_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {}
impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} impl runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {}
@@ -119,11 +119,6 @@ parameter_types! {
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
} }
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(ASSET_HUB_ID).into());
}
pub type TrustedTeleporters = ( pub type TrustedTeleporters = (
xcm_builder::Case<WndForAssetHub>, xcm_builder::Case<WndForAssetHub>,
xcm_builder::Case<WndForCollectives>, xcm_builder::Case<WndForCollectives>,
@@ -265,7 +260,5 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>; type WeightInfo = crate::weights::pallet_xcm::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
+8 -2
View File
@@ -13,7 +13,6 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive
serde = { version = "1.0.188", optional = true, features = ["derive"] } serde = { version = "1.0.188", optional = true, features = ["derive"] }
log = { version = "0.4.17", default-features = false } log = { version = "0.4.17", default-features = false }
frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true }
frame-support = { path = "../../../substrate/frame/support", default-features = false} frame-support = { path = "../../../substrate/frame/support", default-features = false}
frame-system = { path = "../../../substrate/frame/system", default-features = false} frame-system = { path = "../../../substrate/frame/system", default-features = false}
sp-core = { path = "../../../substrate/primitives/core", default-features = false} sp-core = { path = "../../../substrate/primitives/core", default-features = false}
@@ -25,8 +24,12 @@ xcm = { package = "staging-xcm", path = "..", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false }
xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false }
# marked optional, used in benchmarking
frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true }
pallet-balances = { path = "../../../substrate/frame/balances", default-features = false, optional = true }
[dev-dependencies] [dev-dependencies]
pallet-balances = { path = "../../../substrate/frame/balances" } pallet-assets = { path = "../../../substrate/frame/assets" }
polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-runtime-parachains = { path = "../../runtime/parachains" }
polkadot-parachain-primitives = { path = "../../parachain" } polkadot-parachain-primitives = { path = "../../parachain" }
@@ -39,6 +42,7 @@ std = [
"frame-support/std", "frame-support/std",
"frame-system/std", "frame-system/std",
"log/std", "log/std",
"pallet-balances/std",
"scale-info/std", "scale-info/std",
"serde", "serde",
"sp-core/std", "sp-core/std",
@@ -53,6 +57,7 @@ runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks", "pallet-balances/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks",
@@ -63,6 +68,7 @@ runtime-benchmarks = [
try-runtime = [ try-runtime = [
"frame-support/try-runtime", "frame-support/try-runtime",
"frame-system/try-runtime", "frame-system/try-runtime",
"pallet-assets/try-runtime",
"pallet-balances/try-runtime", "pallet-balances/try-runtime",
"polkadot-runtime-parachains/try-runtime", "polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime", "sp-runtime/try-runtime",
+122 -43
View File
@@ -16,15 +16,56 @@
use super::*; use super::*;
use bounded_collections::{ConstU32, WeakBoundedVec}; use bounded_collections::{ConstU32, WeakBoundedVec};
use frame_benchmarking::{benchmarks, BenchmarkError, BenchmarkResult}; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult};
use frame_support::weights::Weight; use frame_support::{traits::Currency, weights::Weight};
use frame_system::RawOrigin; use frame_system::RawOrigin;
use sp_std::prelude::*; use sp_std::prelude::*;
use xcm::{latest::prelude::*, v2}; use xcm::{latest::prelude::*, v2};
type RuntimeOrigin<T> = <T as frame_system::Config>::RuntimeOrigin; type RuntimeOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
// existential deposit multiplier
const ED_MULTIPLIER: u32 = 100;
/// Pallet we're benchmarking here.
pub struct Pallet<T: Config>(crate::Pallet<T>);
/// Trait that must be implemented by runtime to be able to benchmark pallet properly.
pub trait Config: crate::Config {
/// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks.
///
/// If `None`, the benchmarks that depend on a reachable destination will be skipped.
fn reachable_dest() -> Option<MultiLocation> {
None
}
/// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be
/// teleported to. Used only in benchmarks.
///
/// Implementation should also make sure `dest` is reachable/connected.
///
/// If `None`, the benchmarks that depend on this will be skipped.
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
None
}
/// A `(MultiAsset, MultiLocation)` pair representing asset and the destination it can be
/// reserve-transferred to. Used only in benchmarks.
///
/// Implementation should also make sure `dest` is reachable/connected.
///
/// If `None`, the benchmarks that depend on this will be skipped.
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
None
}
}
benchmarks! { benchmarks! {
where_clause {
where
T: pallet_balances::Config,
<T as pallet_balances::Config>::Balance: From<u128> + Into<u128>,
}
send { send {
let send_origin = let send_origin =
T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
@@ -32,7 +73,7 @@ benchmarks! {
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
} }
let msg = Xcm(vec![ClearOrigin]); let msg = Xcm(vec![ClearOrigin]);
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( let versioned_dest: VersionedMultiLocation = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)? )?
.into(); .into();
@@ -40,44 +81,82 @@ benchmarks! {
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) }: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg))
teleport_assets { teleport_assets {
let asset: MultiAsset = (Here, 10).into(); let (asset, destination) = T::teleportable_asset_and_dest().ok_or(
let send_origin = BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; )?;
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone())
let transferred_amount = match &asset.fun {
Fungible(amount) => *amount,
_ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")),
}.into();
let assets: MultiAssets = asset.into();
let existential_deposit = T::ExistentialDeposit::get();
let caller = whitelisted_caller();
// Give some multiple of the existential deposit
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
assert!(balance >= transferred_amount);
let _ = <pallet_balances::Pallet<T> as Currency<_>>::make_free_balance_be(&caller, balance);
// verify initial balance
assert_eq!(pallet_balances::Pallet::<T>::free_balance(&caller), balance);
let send_origin = RawOrigin::Signed(caller.clone());
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
if !T::XcmTeleportFilter::contains(&(origin_location, vec![asset.clone()])) { if !T::XcmTeleportFilter::contains(&(origin_location, assets.clone().into_inner())) {
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
} }
let recipient = [0u8; 32]; let recipient = [0u8; 32];
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( let versioned_dest: VersionedMultiLocation = destination.into();
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?
.into();
let versioned_beneficiary: VersionedMultiLocation = let versioned_beneficiary: VersionedMultiLocation =
AccountId32 { network: None, id: recipient.into() }.into(); AccountId32 { network: None, id: recipient.into() }.into();
let versioned_assets: VersionedMultiAssets = asset.into(); let versioned_assets: VersionedMultiAssets = assets.into();
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) }: _<RuntimeOrigin<T>>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0)
verify {
// verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees)
assert!(pallet_balances::Pallet::<T>::free_balance(&caller) <= balance - transferred_amount);
}
reserve_transfer_assets { reserve_transfer_assets {
let asset: MultiAsset = (Here, 10).into(); let (asset, destination) = T::reserve_transferable_asset_and_dest().ok_or(
let send_origin = BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; )?;
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone())
let transferred_amount = match &asset.fun {
Fungible(amount) => *amount,
_ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")),
}.into();
let assets: MultiAssets = asset.into();
let existential_deposit = T::ExistentialDeposit::get();
let caller = whitelisted_caller();
// Give some multiple of the existential deposit
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
assert!(balance >= transferred_amount);
let _ = <pallet_balances::Pallet<T> as Currency<_>>::make_free_balance_be(&caller, balance);
// verify initial balance
assert_eq!(pallet_balances::Pallet::<T>::free_balance(&caller), balance);
let send_origin = RawOrigin::Signed(caller.clone());
let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
if !T::XcmReserveTransferFilter::contains(&(origin_location, vec![asset.clone()])) { if !T::XcmReserveTransferFilter::contains(&(origin_location, assets.clone().into_inner())) {
return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))
} }
let recipient = [0u8; 32]; let recipient = [0u8; 32];
let versioned_dest: VersionedMultiLocation = T::ReachableDest::get().ok_or( let versioned_dest: VersionedMultiLocation = destination.into();
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?
.into();
let versioned_beneficiary: VersionedMultiLocation = let versioned_beneficiary: VersionedMultiLocation =
AccountId32 { network: None, id: recipient.into() }.into(); AccountId32 { network: None, id: recipient.into() }.into();
let versioned_assets: VersionedMultiAssets = asset.into(); let versioned_assets: VersionedMultiAssets = assets.into();
}: _<RuntimeOrigin<T>>(send_origin, Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) }: _<RuntimeOrigin<T>>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0)
verify {
// verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees)
assert!(pallet_balances::Pallet::<T>::free_balance(&caller) <= balance - transferred_amount);
}
execute { execute {
let execute_origin = let execute_origin =
@@ -92,7 +171,7 @@ benchmarks! {
}: _<RuntimeOrigin<T>>(execute_origin, Box::new(versioned_msg), Weight::zero()) }: _<RuntimeOrigin<T>>(execute_origin, Box::new(versioned_msg), Weight::zero())
force_xcm_version { force_xcm_version {
let loc = T::ReachableDest::get().ok_or( let loc = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?; )?;
let xcm_version = 2; let xcm_version = 2;
@@ -101,18 +180,18 @@ benchmarks! {
force_default_xcm_version {}: _(RawOrigin::Root, Some(2)) force_default_xcm_version {}: _(RawOrigin::Root, Some(2))
force_subscribe_version_notify { force_subscribe_version_notify {
let versioned_loc: VersionedMultiLocation = T::ReachableDest::get().ok_or( let versioned_loc: VersionedMultiLocation = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)? )?
.into(); .into();
}: _(RawOrigin::Root, Box::new(versioned_loc)) }: _(RawOrigin::Root, Box::new(versioned_loc))
force_unsubscribe_version_notify { force_unsubscribe_version_notify {
let loc = T::ReachableDest::get().ok_or( let loc = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?; )?;
let versioned_loc: VersionedMultiLocation = loc.into(); let versioned_loc: VersionedMultiLocation = loc.into();
let _ = Pallet::<T>::request_version_notify(loc); let _ = crate::Pallet::<T>::request_version_notify(loc);
}: _(RawOrigin::Root, Box::new(versioned_loc)) }: _(RawOrigin::Root, Box::new(versioned_loc))
force_suspension {}: _(RawOrigin::Root, true) force_suspension {}: _(RawOrigin::Root, true)
@@ -122,7 +201,7 @@ benchmarks! {
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
SupportedVersion::<T>::insert(old_version, loc, old_version); SupportedVersion::<T>::insert(old_version, loc, old_version);
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateSupportedVersion, Weight::zero());
} }
migrate_version_notifiers { migrate_version_notifiers {
@@ -130,22 +209,22 @@ benchmarks! {
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
VersionNotifiers::<T>::insert(old_version, loc, 0); VersionNotifiers::<T>::insert(old_version, loc, 0);
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateVersionNotifiers, Weight::zero());
} }
already_notified_target { already_notified_target {
let loc = T::ReachableDest::get().ok_or( let loc = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))), BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads(1))),
)?; )?;
let loc = VersionedMultiLocation::from(loc); let loc = VersionedMultiLocation::from(loc);
let current_version = T::AdvertisedXcmVersion::get(); let current_version = T::AdvertisedXcmVersion::get();
VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), current_version)); VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), current_version));
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero());
} }
notify_current_targets { notify_current_targets {
let loc = T::ReachableDest::get().ok_or( let loc = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))),
)?; )?;
let loc = VersionedMultiLocation::from(loc); let loc = VersionedMultiLocation::from(loc);
@@ -153,7 +232,7 @@ benchmarks! {
let old_version = current_version - 1; let old_version = current_version - 1;
VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), old_version)); VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), old_version));
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::NotifyCurrentTargets(None), Weight::zero());
} }
notify_target_migration_fail { notify_target_migration_fail {
@@ -167,7 +246,7 @@ benchmarks! {
let current_version = T::AdvertisedXcmVersion::get(); let current_version = T::AdvertisedXcmVersion::get();
VersionNotifyTargets::<T>::insert(current_version, bad_loc, (0, Weight::zero(), current_version)); VersionNotifyTargets::<T>::insert(current_version, bad_loc, (0, Weight::zero(), current_version));
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
} }
migrate_version_notify_targets { migrate_version_notify_targets {
@@ -176,18 +255,18 @@ benchmarks! {
let loc = VersionedMultiLocation::from(MultiLocation::from(Parent)); let loc = VersionedMultiLocation::from(MultiLocation::from(Parent));
VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), current_version)); VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), current_version));
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
} }
migrate_and_notify_old_targets { migrate_and_notify_old_targets {
let loc = T::ReachableDest::get().ok_or( let loc = T::reachable_dest().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))), BenchmarkError::Override(BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3))),
)?; )?;
let loc = VersionedMultiLocation::from(loc); let loc = VersionedMultiLocation::from(loc);
let old_version = T::AdvertisedXcmVersion::get() - 1; let old_version = T::AdvertisedXcmVersion::get() - 1;
VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), old_version)); VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), old_version));
}: { }: {
Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero()); crate::Pallet::<T>::check_xcm_version_change(VersionMigrationStage::MigrateAndNotifyOldTargets, Weight::zero());
} }
new_query { new_query {
@@ -195,14 +274,14 @@ benchmarks! {
let timeout = 1u32.into(); let timeout = 1u32.into();
let match_querier = MultiLocation::from(Here); let match_querier = MultiLocation::from(Here);
}: { }: {
Pallet::<T>::new_query(responder, timeout, match_querier); crate::Pallet::<T>::new_query(responder, timeout, match_querier);
} }
take_response { take_response {
let responder = MultiLocation::from(Parent); let responder = MultiLocation::from(Parent);
let timeout = 1u32.into(); let timeout = 1u32.into();
let match_querier = MultiLocation::from(Here); let match_querier = MultiLocation::from(Here);
let query_id = Pallet::<T>::new_query(responder, timeout, match_querier); let query_id = crate::Pallet::<T>::new_query(responder, timeout, match_querier);
let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new( let infos = (0 .. xcm::v3::MaxPalletsInfo::get()).map(|_| PalletInfo::new(
u32::MAX, u32::MAX,
(0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::<Vec<_>>().try_into().unwrap(), (0..xcm::v3::MaxPalletNameLen::get()).map(|_| 97u8).collect::<Vec<_>>().try_into().unwrap(),
@@ -211,10 +290,10 @@ benchmarks! {
u32::MAX, u32::MAX,
u32::MAX, u32::MAX,
).unwrap()).collect::<Vec<_>>(); ).unwrap()).collect::<Vec<_>>();
Pallet::<T>::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap())); crate::Pallet::<T>::expect_response(query_id, Response::PalletsInfo(infos.try_into().unwrap()));
}: { }: {
<Pallet::<T> as QueryHandler>::take_response(query_id); <crate::Pallet::<T> as QueryHandler>::take_response(query_id);
} }
impl_benchmark_test_suite!( impl_benchmark_test_suite!(
+492 -59
View File
@@ -19,7 +19,7 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benchmarking; pub mod benchmarking;
#[cfg(test)] #[cfg(test)]
mod mock; mod mock;
#[cfg(test)] #[cfg(test)]
@@ -55,9 +55,9 @@ use xcm_builder::{
}; };
use xcm_executor::{ use xcm_executor::{
traits::{ traits::{
CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, DropAssets, MatchesFungible, AssetTransferError, CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin,
OnResponse, Properties, QueryHandler, QueryResponseStatus, VersionChangeNotifier, DropAssets, MatchesFungible, OnResponse, Properties, QueryHandler, QueryResponseStatus,
WeightBounds, TransactAsset, TransferType, VersionChangeNotifier, WeightBounds, XcmAssetTransfers,
}, },
Assets, Assets,
}; };
@@ -222,7 +222,7 @@ pub mod pallet {
type XcmExecuteFilter: Contains<(MultiLocation, Xcm<<Self as Config>::RuntimeCall>)>; type XcmExecuteFilter: Contains<(MultiLocation, Xcm<<Self as Config>::RuntimeCall>)>;
/// Something to execute an XCM message. /// Something to execute an XCM message.
type XcmExecutor: ExecuteXcm<<Self as Config>::RuntimeCall>; type XcmExecutor: ExecuteXcm<<Self as Config>::RuntimeCall> + XcmAssetTransfers;
/// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass. /// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass.
type XcmTeleportFilter: Contains<(MultiLocation, Vec<MultiAsset>)>; type XcmTeleportFilter: Contains<(MultiLocation, Vec<MultiAsset>)>;
@@ -275,12 +275,6 @@ pub mod pallet {
/// Weight information for extrinsics in this pallet. /// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo; type WeightInfo: WeightInfo;
/// A `MultiLocation` that can be reached via `XcmRouter`. Used only in benchmarks.
///
/// If `None`, the benchmarks that depend on a reachable destination will be skipped.
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest: Get<Option<MultiLocation>>;
} }
impl<T: Config> ExecuteControllerWeightInfo for Pallet<T> { impl<T: Config> ExecuteControllerWeightInfo for Pallet<T> {
@@ -531,8 +525,8 @@ pub mod pallet {
NoSubscription, NoSubscription,
/// The location is invalid since it already has a subscription from us. /// The location is invalid since it already has a subscription from us.
AlreadySubscribed, AlreadySubscribed,
/// Invalid asset for the operation. /// Could not check-out the assets for teleportation to the destination chain.
InvalidAsset, CannotCheckOutTeleport,
/// The owner does not own (all) of the asset that they wish to do the operation on. /// The owner does not own (all) of the asset that they wish to do the operation on.
LowBalance, LowBalance,
/// The asset owner has too many locks on the asset. /// The asset owner has too many locks on the asset.
@@ -545,6 +539,16 @@ pub mod pallet {
LockNotFound, LockNotFound,
/// The unlock operation cannot succeed because there are still consumers of the lock. /// The unlock operation cannot succeed because there are still consumers of the lock.
InUse, InUse,
/// Invalid non-concrete asset.
InvalidAssetNotConcrete,
/// Invalid asset, reserve chain could not be determined for it.
InvalidAssetUnknownReserve,
/// Invalid asset, do not support remote asset reserves with different fees reserves.
InvalidAssetUnsupportedReserve,
/// Too many assets with different reserve locations have been attempted for transfer.
TooManyReserves,
/// Local XCM execution of asset transfer incomplete.
LocalExecutionIncomplete,
} }
impl<T: Config> From<SendError> for Error<T> { impl<T: Config> From<SendError> for Error<T> {
@@ -557,6 +561,15 @@ pub mod pallet {
} }
} }
impl<T: Config> From<AssetTransferError> for Error<T> {
fn from(e: AssetTransferError) -> Self {
match e {
AssetTransferError::NotConcrete => Error::<T>::InvalidAssetNotConcrete,
AssetTransferError::UnknownReserve => Error::<T>::InvalidAssetUnknownReserve,
}
}
}
/// The status of a query. /// The status of a query.
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum QueryStatus<BlockNumber> { pub enum QueryStatus<BlockNumber> {
@@ -907,11 +920,7 @@ pub mod pallet {
let mut message = Xcm(vec![ let mut message = Xcm(vec![
WithdrawAsset(assets), WithdrawAsset(assets),
SetFeesMode { jit_withdraw: true }, SetFeesMode { jit_withdraw: true },
InitiateTeleport { InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) },
assets: Wild(AllCounted(count)),
dest,
xcm: Xcm(vec![]),
},
]); ]);
T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w))
} }
@@ -954,6 +963,8 @@ pub mod pallet {
match (maybe_assets, maybe_dest) { match (maybe_assets, maybe_dest) {
(Ok(assets), Ok(dest)) => { (Ok(assets), Ok(dest)) => {
use sp_std::vec; use sp_std::vec;
// heaviest version of locally executed XCM program: equivalent in weight to
// transfer assets to SA, reanchor them, extend XCM program, and send onward XCM
let mut message = Xcm(vec![ let mut message = Xcm(vec![
SetFeesMode { jit_withdraw: true }, SetFeesMode { jit_withdraw: true },
TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) }
@@ -1114,6 +1125,8 @@ pub mod pallet {
match (maybe_assets, maybe_dest) { match (maybe_assets, maybe_dest) {
(Ok(assets), Ok(dest)) => { (Ok(assets), Ok(dest)) => {
use sp_std::vec; use sp_std::vec;
// heaviest version of locally executed XCM program: equivalent in weight to
// transfer assets to SA, reanchor them, extend XCM program, and send onward XCM
let mut message = Xcm(vec![ let mut message = Xcm(vec![
SetFeesMode { jit_withdraw: true }, SetFeesMode { jit_withdraw: true },
TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) }
@@ -1273,6 +1286,33 @@ impl<T: Config> QueryHandler for Pallet<T> {
} }
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// Validate `assets` to be reserve-transferred and return their reserve location.
fn validate_assets_and_find_reserve(
assets: &[MultiAsset],
dest: &MultiLocation,
) -> Result<TransferType, Error<T>> {
let mut reserve = None;
for asset in assets.iter() {
if let Fungible(x) = asset.fun {
// If fungible asset, ensure non-zero amount.
ensure!(!x.is_zero(), Error::<T>::Empty);
}
let transfer_type =
T::XcmExecutor::determine_for(&asset, dest).map_err(Error::<T>::from)?;
// Ensure asset is not teleportable to `dest`.
ensure!(transfer_type != TransferType::Teleport, Error::<T>::Filtered);
if let Some(reserve) = reserve.as_ref() {
// Ensure transfer for multiple assets uses same reserve location (only fee may have
// different reserve location)
ensure!(reserve == &transfer_type, Error::<T>::TooManyReserves);
} else {
// asset reserve identified
reserve = Some(transfer_type);
}
}
reserve.ok_or(Error::<T>::Empty)
}
fn do_reserve_transfer_assets( fn do_reserve_transfer_assets(
origin: OriginFor<T>, origin: OriginFor<T>,
dest: Box<VersionedMultiLocation>, dest: Box<VersionedMultiLocation>,
@@ -1286,35 +1326,75 @@ impl<T: Config> Pallet<T> {
let beneficiary: MultiLocation = let beneficiary: MultiLocation =
(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?; (*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?; let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
log::trace!(
target: "xcm::pallet_xcm::do_reserve_transfer_assets",
"origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}",
origin_location, dest, beneficiary, assets, fee_asset_item,
);
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let value = (origin_location, assets.into_inner()); let value = (origin_location, assets.into_inner());
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value; let (origin_location, mut assets) = value;
let context = T::UniversalLocation::get();
let fees = assets if fee_asset_item as usize >= assets.len() {
.get(fee_asset_item as usize) return Err(Error::<T>::Empty.into())
.ok_or(Error::<T>::Empty)? }
.clone() let fees = assets.swap_remove(fee_asset_item as usize);
.reanchored(&dest, context) let fees_transfer_type =
.map_err(|_| Error::<T>::CannotReanchor)?; T::XcmExecutor::determine_for(&fees, &dest).map_err(Error::<T>::from)?;
let max_assets = assets.len() as u32; let assets_transfer_type = if assets.is_empty() {
let assets: MultiAssets = assets.into(); // Single asset to transfer (one used for fees where transfer type is determined above).
let xcm = Xcm(vec![ ensure!(fees_transfer_type != TransferType::Teleport, Error::<T>::Filtered);
BuyExecution { fees, weight_limit }, fees_transfer_type
DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, } else {
]); // Find reserve for non-fee assets.
let mut message = Xcm(vec![ Self::validate_assets_and_find_reserve(&assets, &dest)?
SetFeesMode { jit_withdraw: true }, };
TransferReserveAsset { assets, dest, xcm },
]); // local and remote XCM programs to potentially handle fees separately
let weight = let separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>;
T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?; if fees_transfer_type == assets_transfer_type {
let hash = message.using_encoded(sp_io::hashing::blake2_256); // Same reserve location (fees not teleportable), we can batch together fees and assets
let outcome = // in same reserve-based-transfer.
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); assets.push(fees.clone());
Self::deposit_event(Event::Attempted { outcome }); // no need for custom fees instructions, fees are batched with assets
Ok(()) separate_fees_instructions = None;
} else {
// Disallow _remote reserves_ unless assets & fees have same remote reserve (covered by
// branch above). The reason for this is that we'd need to send XCMs to separate chains
// with no guarantee of delivery order on final destination; therefore we cannot
// guarantee to have fees in place on final destination chain to pay for assets
// transfer.
ensure!(
!matches!(assets_transfer_type, TransferType::RemoteReserve(_)),
Error::<T>::InvalidAssetUnsupportedReserve
);
let fees = fees.clone();
let weight_limit = weight_limit.clone();
// build fees transfer instructions to be added to assets transfers XCM programs
separate_fees_instructions = Some(match fees_transfer_type {
TransferType::LocalReserve =>
Self::local_reserve_fees_instructions(dest, fees, weight_limit)?,
TransferType::DestinationReserve =>
Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?,
TransferType::Teleport =>
Self::teleport_fees_instructions(dest, fees, weight_limit)?,
TransferType::RemoteReserve(_) =>
return Err(Error::<T>::InvalidAssetUnsupportedReserve.into()),
});
};
Self::build_and_execute_xcm_transfer_type(
origin_location,
dest,
beneficiary,
assets,
assets_transfer_type,
fees,
separate_fees_instructions,
weight_limit,
)
} }
fn do_teleport_assets( fn do_teleport_assets(
@@ -1335,31 +1415,384 @@ impl<T: Config> Pallet<T> {
let value = (origin_location, assets.into_inner()); let value = (origin_location, assets.into_inner());
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered); ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value; let (origin_location, assets) = value;
for asset in assets.iter() {
let transfer_type =
T::XcmExecutor::determine_for(asset, &dest).map_err(Error::<T>::from)?;
ensure!(matches!(transfer_type, TransferType::Teleport), Error::<T>::Filtered);
}
let fees = assets.get(fee_asset_item as usize).ok_or(Error::<T>::Empty)?.clone();
Self::build_and_execute_xcm_transfer_type(
origin_location,
dest,
beneficiary,
assets,
TransferType::Teleport,
fees,
None,
weight_limit,
)
}
fn build_and_execute_xcm_transfer_type(
origin: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
transfer_type: TransferType,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
weight_limit: WeightLimit,
) -> DispatchResult {
log::trace!(
target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type",
"origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \
fees {:?}, fees_xcm: {:?}, weight_limit: {:?}",
origin, dest, beneficiary, assets, transfer_type, fees, separate_fees_instructions, weight_limit,
);
let (mut local_xcm, remote_xcm) = match transfer_type {
TransferType::LocalReserve => {
let (local, remote) = Self::local_reserve_transfer_programs(
dest,
beneficiary,
assets,
fees,
separate_fees_instructions,
weight_limit,
)?;
(local, Some(remote))
},
TransferType::DestinationReserve => {
let (local, remote) = Self::destination_reserve_transfer_programs(
dest,
beneficiary,
assets,
fees,
separate_fees_instructions,
weight_limit,
)?;
(local, Some(remote))
},
TransferType::RemoteReserve(reserve) => (
Self::remote_reserve_transfer_program(
reserve,
dest,
beneficiary,
assets,
fees,
weight_limit,
)?,
None,
),
TransferType::Teleport => (
Self::teleport_assets_program(dest, beneficiary, assets, fees, weight_limit)?,
None,
),
};
let weight =
T::Weigher::weight(&mut local_xcm).map_err(|()| Error::<T>::UnweighableMessage)?;
let hash = local_xcm.using_encoded(sp_io::hashing::blake2_256);
let outcome =
T::XcmExecutor::execute_xcm_in_credit(origin, local_xcm, hash, weight, weight);
Self::deposit_event(Event::Attempted { outcome: outcome.clone() });
if let Some(remote_xcm) = remote_xcm {
outcome.ensure_complete().map_err(|_| Error::<T>::LocalExecutionIncomplete)?;
let (ticket, price) = validate_send::<T::XcmRouter>(dest, remote_xcm.clone())
.map_err(Error::<T>::from)?;
if origin != Here.into_location() {
Self::charge_fees(origin, price).map_err(|_| Error::<T>::FeesNotMet)?;
}
let message_id = T::XcmRouter::deliver(ticket).map_err(Error::<T>::from)?;
let e = Event::Sent { origin, destination: dest, message: remote_xcm, message_id };
Self::deposit_event(e);
}
Ok(())
}
fn local_reserve_fees_instructions(
dest: MultiLocation,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let context = T::UniversalLocation::get(); let context = T::UniversalLocation::get();
let fees = assets let reanchored_fees = fees
.get(fee_asset_item as usize)
.ok_or(Error::<T>::Empty)?
.clone() .clone()
.reanchored(&dest, context) .reanchored(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?; .map_err(|_| Error::<T>::CannotReanchor)?;
let max_assets = assets.len() as u32;
let local_execute_xcm = Xcm(vec![
// move `fees` to `dest`s local sovereign account
TransferAsset { assets: fees.into(), beneficiary: dest },
]);
let xcm_on_dest = Xcm(vec![
// let (dest) chain know `fees` are in its SA on reserve
ReserveAssetDeposited(reanchored_fees.clone().into()),
// buy exec using `fees` in holding deposited in above instruction
BuyExecution { fees: reanchored_fees, weight_limit },
]);
Ok((local_execute_xcm, xcm_on_dest))
}
fn local_reserve_transfer_programs(
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
// max assets is `assets` (+ potentially separately handled fee)
let max_assets =
assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0);
let assets: MultiAssets = assets.into(); let assets: MultiAssets = assets.into();
let xcm = Xcm(vec![ let context = T::UniversalLocation::get();
let mut reanchored_assets = assets.clone();
reanchored_assets
.reanchor(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
// fees are either handled through dedicated instructions, or batched together with assets
let fees_already_handled = separate_fees_instructions.is_some();
let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions
.map(|(local, remote)| (local.into_inner(), remote.into_inner()))
.unwrap_or_default();
// start off with any necessary local fees specific instructions
let mut local_execute_xcm = fees_local_xcm;
// move `assets` to `dest`s local sovereign account
local_execute_xcm.push(TransferAsset { assets, beneficiary: dest });
// on destination chain, start off with custom fee instructions
let mut xcm_on_dest = fees_remote_xcm;
// continue with rest of assets
xcm_on_dest.extend_from_slice(&[
// let (dest) chain know assets are in its SA on reserve
ReserveAssetDeposited(reanchored_assets),
// following instructions are not exec'ed on behalf of origin chain anymore
ClearOrigin,
]);
if !fees_already_handled {
// no custom fees instructions, they are batched together with `assets` transfer;
// BuyExecution happens after receiving all `assets`
let reanchored_fees =
fees.reanchored(&dest, context).map_err(|_| Error::<T>::CannotReanchor)?;
// buy execution using `fees` batched together with above `reanchored_assets`
xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit });
}
// deposit all remaining assets in holding to `beneficiary` location
xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest)))
}
fn destination_reserve_fees_instructions(
dest: MultiLocation,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let context = T::UniversalLocation::get();
let reanchored_fees = fees
.clone()
.reanchored(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
let fees: MultiAssets = fees.into();
let local_execute_xcm = Xcm(vec![
// withdraw reserve-based fees (derivatives)
WithdrawAsset(fees.clone()),
// burn derivatives
BurnAsset(fees),
]);
let xcm_on_dest = Xcm(vec![
// withdraw `fees` from origin chain's sovereign account
WithdrawAsset(reanchored_fees.clone().into()),
// buy exec using `fees` in holding withdrawn in above instruction
BuyExecution { fees: reanchored_fees, weight_limit },
]);
Ok((local_execute_xcm, xcm_on_dest))
}
fn destination_reserve_transfer_programs(
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
// max assets is `assets` (+ potentially separately handled fee)
let max_assets =
assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0);
let assets: MultiAssets = assets.into();
let context = T::UniversalLocation::get();
let mut reanchored_assets = assets.clone();
reanchored_assets
.reanchor(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
// fees are either handled through dedicated instructions, or batched together with assets
let fees_already_handled = separate_fees_instructions.is_some();
let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions
.map(|(local, remote)| (local.into_inner(), remote.into_inner()))
.unwrap_or_default();
// start off with any necessary local fees specific instructions
let mut local_execute_xcm = fees_local_xcm;
// continue with rest of assets
local_execute_xcm.extend_from_slice(&[
// withdraw reserve-based assets
WithdrawAsset(assets.clone()),
// burn reserve-based assets
BurnAsset(assets),
]);
// on destination chain, start off with custom fee instructions
let mut xcm_on_dest = fees_remote_xcm;
// continue with rest of assets
xcm_on_dest.extend_from_slice(&[
// withdraw `assets` from origin chain's sovereign account
WithdrawAsset(reanchored_assets),
// following instructions are not exec'ed on behalf of origin chain anymore
ClearOrigin,
]);
if !fees_already_handled {
// no custom fees instructions, they are batched together with `assets` transfer;
// BuyExecution happens after receiving all `assets`
let reanchored_fees =
fees.reanchored(&dest, context).map_err(|_| Error::<T>::CannotReanchor)?;
// buy execution using `fees` batched together with above `reanchored_assets`
xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit });
}
// deposit all remaining assets in holding to `beneficiary` location
xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest)))
}
// function assumes fees and assets have the same remote reserve
fn remote_reserve_transfer_program(
reserve: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<Xcm<<T as Config>::RuntimeCall>, Error<T>> {
let max_assets = assets.len() as u32;
let context = T::UniversalLocation::get();
// we spend up to half of fees for execution on reserve and other half for execution on
// destination
let (fees_half_1, fees_half_2) = Self::halve_fees(fees)?;
// identifies fee item as seen by `reserve` - to be used at reserve chain
let reserve_fees = fees_half_1
.reanchored(&reserve, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
// identifies fee item as seen by `dest` - to be used at destination chain
let dest_fees =
fees_half_2.reanchored(&dest, context).map_err(|_| Error::<T>::CannotReanchor)?;
// identifies `dest` as seen by `reserve`
let dest = dest.reanchored(&reserve, context).map_err(|_| Error::<T>::CannotReanchor)?;
// xcm to be executed at dest
let xcm_on_dest = Xcm(vec![
BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() },
DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary },
]);
// xcm to be executed on reserve
let xcm_on_reserve = Xcm(vec![
BuyExecution { fees: reserve_fees, weight_limit },
DepositReserveAsset { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest },
]);
Ok(Xcm(vec![
WithdrawAsset(assets.into()),
InitiateReserveWithdraw {
assets: Wild(AllCounted(max_assets)),
reserve,
xcm: xcm_on_reserve,
},
]))
}
fn teleport_fees_instructions(
dest: MultiLocation,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let context = T::UniversalLocation::get();
let reanchored_fees = fees
.clone()
.reanchored(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
// XcmContext irrelevant in teleports checks
let dummy_context =
XcmContext { origin: None, message_id: Default::default(), topic: None };
// We should check that the asset can actually be teleported out (for this to
// be in error, there would need to be an accounting violation by ourselves,
// so it's unlikely, but we don't want to allow that kind of bug to leak into
// a trusted chain.
<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::can_check_out(
&dest,
&fees,
&dummy_context,
)
.map_err(|_| Error::<T>::CannotCheckOutTeleport)?;
<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::check_out(
&dest,
&fees,
&dummy_context,
);
let fees: MultiAssets = fees.into();
let local_execute_xcm = Xcm(vec![
// withdraw fees
WithdrawAsset(fees.clone()),
// burn fees
BurnAsset(fees),
]);
let xcm_on_dest = Xcm(vec![
// (dest) chain receive teleported assets burned on origin chain
ReceiveTeleportedAsset(reanchored_fees.clone().into()),
// buy exec using `fees` in holding received in above instruction
BuyExecution { fees: reanchored_fees, weight_limit },
]);
Ok((local_execute_xcm, xcm_on_dest))
}
fn teleport_assets_program(
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
mut fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<Xcm<<T as Config>::RuntimeCall>, Error<T>> {
let context = T::UniversalLocation::get();
fees.reanchor(&dest, context).map_err(|_| Error::<T>::CannotReanchor)?;
let max_assets = assets.len() as u32;
let xcm_on_dest = Xcm(vec![
BuyExecution { fees, weight_limit }, BuyExecution { fees, weight_limit },
DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary },
]); ]);
let mut message = Xcm(vec![ Ok(Xcm(vec![
WithdrawAsset(assets), WithdrawAsset(assets.into()),
SetFeesMode { jit_withdraw: true }, SetFeesMode { jit_withdraw: true },
InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm }, InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest },
]); ]))
let weight = }
T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?;
let hash = message.using_encoded(sp_io::hashing::blake2_256); /// Halve `fees` fungible amount.
let outcome = pub(crate) fn halve_fees(fees: MultiAsset) -> Result<(MultiAsset, MultiAsset), Error<T>> {
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight); match fees.fun {
Self::deposit_event(Event::Attempted { outcome }); Fungible(amount) => {
Ok(()) let fee1 = amount.saturating_div(2);
let fee2 = amount.saturating_sub(fee1);
ensure!(fee1 > 0, Error::<T>::FeesNotMet);
ensure!(fee2 > 0, Error::<T>::FeesNotMet);
Ok((MultiAsset::from((fees.id, fee1)), MultiAsset::from((fees.id, fee2))))
},
NonFungible(_) => Err(Error::<T>::FeesNotMet),
}
} }
/// Will always make progress, and will do its best not to use much more than `weight_cutoff` /// Will always make progress, and will do its best not to use much more than `weight_cutoff`
+175 -28
View File
@@ -17,7 +17,9 @@
use codec::Encode; use codec::Encode;
use frame_support::{ use frame_support::{
construct_runtime, match_types, parameter_types, construct_runtime, match_types, parameter_types,
traits::{ConstU32, Everything, EverythingBut, Nothing}, traits::{
AsEnsureOriginWithArg, ConstU128, ConstU32, Equals, Everything, EverythingBut, Nothing,
},
weights::Weight, weights::Weight,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -32,11 +34,15 @@ use xcm::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, DescribeAllTerminal,
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter, HashedDescription, IsConcrete,
MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount, SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount,
}; };
use xcm_executor::XcmExecutor; use xcm_executor::{
traits::{Identity, JustTry},
XcmExecutor,
};
use crate::{self as pallet_xcm, TestWeightInfo}; use crate::{self as pallet_xcm, TestWeightInfo};
@@ -137,6 +143,7 @@ construct_runtime!(
{ {
System: frame_system::{Pallet, Call, Storage, Config<T>, Event<T>}, System: frame_system::{Pallet, Call, Storage, Config<T>, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>}, Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Assets: pallet_assets::{Pallet, Call, Storage, Config<T>, Event<T>},
ParasOrigin: origin::{Pallet, Origin}, ParasOrigin: origin::{Pallet, Origin},
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config<T>}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config<T>},
TestNotifier: pallet_test_notifier::{Pallet, Call, Event<T>}, TestNotifier: pallet_test_notifier::{Pallet, Call, Event<T>},
@@ -179,13 +186,13 @@ impl SendXcm for TestSendXcmErrX8 {
type Ticket = (MultiLocation, Xcm<()>); type Ticket = (MultiLocation, Xcm<()>);
fn validate( fn validate(
dest: &mut Option<MultiLocation>, dest: &mut Option<MultiLocation>,
msg: &mut Option<Xcm<()>>, _: &mut Option<Xcm<()>>,
) -> SendResult<(MultiLocation, Xcm<()>)> { ) -> SendResult<(MultiLocation, Xcm<()>)> {
let (dest, msg) = (dest.take().unwrap(), msg.take().unwrap()); if dest.as_ref().unwrap().len() == 8 {
if dest.len() == 8 { dest.take();
Err(SendError::Transport("Destination location full")) Err(SendError::Transport("Destination location full"))
} else { } else {
Ok(((dest, msg), MultiAssets::new())) Err(SendError::NotApplicable)
} }
} }
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> { fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
@@ -280,18 +287,135 @@ impl pallet_balances::Config for Test {
type MaxFreezes = ConstU32<0>; type MaxFreezes = ConstU32<0>;
} }
#[cfg(feature = "runtime-benchmarks")]
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
pub struct XcmBenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl pallet_assets::BenchmarkHelper<MultiLocation> for XcmBenchmarkHelper {
fn create_asset_id_parameter(id: u32) -> MultiLocation {
MultiLocation { parents: 1, interior: X1(Parachain(id)) }
}
}
impl pallet_assets::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Balance = Balance;
type AssetId = MultiLocation;
type AssetIdParameter = MultiLocation;
type Currency = Balances;
type CreateOrigin = AsEnsureOriginWithArg<frame_system::EnsureSigned<AccountId>>;
type ForceOrigin = EnsureRoot<AccountId>;
type AssetDeposit = ConstU128<1>;
type AssetAccountDeposit = ConstU128<10>;
type MetadataDepositBase = ConstU128<1>;
type MetadataDepositPerByte = ConstU128<1>;
type ApprovalDeposit = ConstU128<1>;
type StringLimit = ConstU32<50>;
type Freezer = ();
type WeightInfo = ();
type CallbackHandle = ();
type Extra = ();
type RemoveItemsLimit = ConstU32<5>;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = XcmBenchmarkHelper;
}
// This child parachain is a system parachain trusted to teleport native token.
pub const SOME_SYSTEM_PARA: u32 = 1001;
// This child parachain acts as trusted reserve for its assets in tests.
// USDT allowed to teleport to/from here.
pub const FOREIGN_ASSET_RESERVE_PARA_ID: u32 = 2001;
// Inner junction of reserve asset on `FOREIGN_ASSET_RESERVE_PARA_ID`.
pub const FOREIGN_ASSET_INNER_JUNCTION: Junction = GeneralIndex(1234567);
// This child parachain acts as trusted reserve for say.. USDC that can be used for fees.
pub const USDC_RESERVE_PARA_ID: u32 = 2002;
// Inner junction of reserve asset on `USDC_RESERVE_PARA_ID`.
pub const USDC_INNER_JUNCTION: Junction = PalletInstance(42);
// This child parachain is a trusted teleporter for say.. USDT (T from Teleport :)).
// We'll use USDT in tests that teleport fees.
pub const USDT_PARA_ID: u32 = 2003;
// This child parachain is not configured as trusted reserve or teleport location for any assets.
pub const OTHER_PARA_ID: u32 = 2009;
parameter_types! { parameter_types! {
pub const RelayLocation: MultiLocation = Here.into_location(); pub const RelayLocation: MultiLocation = Here.into_location();
pub const NativeAsset: MultiAsset = MultiAsset {
fun: Fungible(10),
id: Concrete(Here.into_location()),
};
pub const SystemParachainLocation: MultiLocation = MultiLocation {
parents: 0,
interior: X1(Parachain(SOME_SYSTEM_PARA))
};
pub const ForeignReserveLocation: MultiLocation = MultiLocation {
parents: 0,
interior: X1(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID))
};
pub const ForeignAsset: MultiAsset = MultiAsset {
fun: Fungible(10),
id: Concrete(MultiLocation {
parents: 0,
interior: X2(Parachain(FOREIGN_ASSET_RESERVE_PARA_ID), FOREIGN_ASSET_INNER_JUNCTION),
}),
};
pub const UsdcReserveLocation: MultiLocation = MultiLocation {
parents: 0,
interior: X1(Parachain(USDC_RESERVE_PARA_ID))
};
pub const Usdc: MultiAsset = MultiAsset {
fun: Fungible(10),
id: Concrete(MultiLocation {
parents: 0,
interior: X2(Parachain(USDC_RESERVE_PARA_ID), USDC_INNER_JUNCTION),
}),
};
pub const UsdtTeleportLocation: MultiLocation = MultiLocation {
parents: 0,
interior: X1(Parachain(USDT_PARA_ID))
};
pub const Usdt: MultiAsset = MultiAsset {
fun: Fungible(10),
id: Concrete(MultiLocation {
parents: 0,
interior: X1(Parachain(USDT_PARA_ID)),
}),
};
pub const AnyNetwork: Option<NetworkId> = None; pub const AnyNetwork: Option<NetworkId> = None;
pub UniversalLocation: InteriorMultiLocation = Here; pub UniversalLocation: InteriorMultiLocation = Here;
pub UnitWeightCost: u64 = 1_000; pub UnitWeightCost: u64 = 1_000;
pub CheckingAccount: AccountId = XcmPallet::check_account();
} }
pub type SovereignAccountOf = pub type SovereignAccountOf = (
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<AnyNetwork, AccountId>); ChildParachainConvertsVia<ParaId, AccountId>,
AccountId32Aliases<AnyNetwork, AccountId>,
HashedDescription<AccountId, DescribeAllTerminal>,
);
pub type LocalAssetTransactor = pub type ForeignAssetsConvertedConcreteId = MatchedConvertedConcreteId<
XcmCurrencyAdapter<Balances, IsConcrete<RelayLocation>, SovereignAccountOf, AccountId, ()>; MultiLocation,
Balance,
// Excludes relay/parent chain currency
EverythingBut<(Equals<RelayLocation>,)>,
Identity,
JustTry,
>;
pub type AssetTransactors = (
XcmCurrencyAdapter<Balances, IsConcrete<RelayLocation>, SovereignAccountOf, AccountId, ()>,
FungiblesAdapter<
Assets,
ForeignAssetsConvertedConcreteId,
SovereignAccountOf,
AccountId,
NoChecking,
CheckingAccount,
>,
);
type LocalOriginConverter = ( type LocalOriginConverter = (
SovereignSignedViaLocation<SovereignAccountOf, RuntimeOrigin>, SovereignSignedViaLocation<SovereignAccountOf, RuntimeOrigin>,
@@ -303,7 +427,12 @@ type LocalOriginConverter = (
parameter_types! { parameter_types! {
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (Concrete(RelayLocation::get()), 1, 1);
pub TrustedAssets: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into()); pub TrustedLocal: (MultiAssetFilter, MultiLocation) = (All.into(), Here.into());
pub TrustedSystemPara: (MultiAssetFilter, MultiLocation) = (NativeAsset::get().into(), SystemParachainLocation::get());
pub TrustedUsdt: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), UsdtTeleportLocation::get());
pub TeleportUsdtToForeign: (MultiAssetFilter, MultiLocation) = (Usdt::get().into(), ForeignReserveLocation::get());
pub TrustedForeign: (MultiAssetFilter, MultiLocation) = (ForeignAsset::get().into(), ForeignReserveLocation::get());
pub TrustedUsdc: (MultiAssetFilter, MultiLocation) = (Usdc::get().into(), UsdcReserveLocation::get());
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]); pub XcmFeesTargetAccount: AccountId = AccountId::new([167u8; 32]);
@@ -323,14 +452,21 @@ pub type Barrier = (
AllowSubscriptionsFrom<Everything>, AllowSubscriptionsFrom<Everything>,
); );
pub type XcmRouter = (TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm);
pub struct XcmConfig; pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig { impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
type XcmSender = (TestPaidForPara3000SendXcm, TestSendXcm); type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor; type AssetTransactor = AssetTransactors;
type OriginConverter = LocalOriginConverter; type OriginConverter = LocalOriginConverter;
type IsReserve = (); type IsReserve = (Case<TrustedForeign>, Case<TrustedUsdc>);
type IsTeleporter = Case<TrustedAssets>; type IsTeleporter = (
Case<TrustedLocal>,
Case<TrustedSystemPara>,
Case<TrustedUsdt>,
Case<TeleportUsdtToForeign>,
);
type UniversalLocation = UniversalLocation; type UniversalLocation = UniversalLocation;
type Barrier = Barrier; type Barrier = Barrier;
type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>; type Weigher = FixedWeightBounds<BaseXcmWeight, RuntimeCall, MaxInstructions>;
@@ -360,15 +496,10 @@ parameter_types! {
pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3; pub static AdvertisedXcmVersion: pallet_xcm::XcmVersion = 3;
} }
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
}
impl pallet_xcm::Config for Test { impl pallet_xcm::Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = (TestSendXcmErrX8, TestPaidForPara3000SendXcm, TestSendXcm); type XcmRouter = XcmRouter;
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Everything; type XcmExecuteFilter = Everything;
type XcmExecutor = XcmExecutor<XcmConfig>; type XcmExecutor = XcmExecutor<XcmConfig>;
@@ -380,6 +511,7 @@ impl pallet_xcm::Config for Test {
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
type AdvertisedXcmVersion = AdvertisedXcmVersion; type AdvertisedXcmVersion = AdvertisedXcmVersion;
type AdminOrigin = EnsureRoot<AccountId>;
type TrustedLockers = (); type TrustedLockers = ();
type SovereignAccountOf = AccountId32Aliases<(), AccountId32>; type SovereignAccountOf = AccountId32Aliases<(), AccountId32>;
type Currency = Balances; type Currency = Balances;
@@ -388,9 +520,6 @@ impl pallet_xcm::Config for Test {
type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = TestWeightInfo; type WeightInfo = TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>;
} }
impl origin::Config for Test {} impl origin::Config for Test {}
@@ -401,6 +530,24 @@ impl pallet_test_notifier::Config for Test {
type RuntimeCall = RuntimeCall; type RuntimeCall = RuntimeCall;
} }
#[cfg(feature = "runtime-benchmarks")]
impl super::benchmarking::Config for Test {
fn reachable_dest() -> Option<MultiLocation> {
Some(Parachain(1000).into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
Some((NativeAsset::get(), SystemParachainLocation::get()))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
Some((
MultiAsset { fun: Fungible(10), id: Concrete(Here.into_location()) },
Parachain(OTHER_PARA_ID).into(),
))
}
}
pub(crate) fn last_event() -> RuntimeEvent { pub(crate) fn last_event() -> RuntimeEvent {
System::events().pop().expect("RuntimeEvent expected").event System::events().pop().expect("RuntimeEvent expected").event
} }
@@ -416,10 +563,10 @@ pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>) -> Instruction<C> {
pub(crate) fn buy_limited_execution<C>( pub(crate) fn buy_limited_execution<C>(
fees: impl Into<MultiAsset>, fees: impl Into<MultiAsset>,
weight: Weight, weight_limit: WeightLimit,
) -> Instruction<C> { ) -> Instruction<C> {
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
BuyExecution { fees: fees.into(), weight_limit: Limited(weight) } BuyExecution { fees: fees.into(), weight_limit }
} }
pub(crate) fn new_test_ext_with_balances( pub(crate) fn new_test_ext_with_balances(
File diff suppressed because it is too large Load Diff
@@ -14,6 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
#![cfg(test)]
mod assets_transfer;
use crate::{ use crate::{
mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries,
QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, QueryStatus, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers,
@@ -35,15 +39,15 @@ use xcm_executor::{
const ALICE: AccountId = AccountId::new([0u8; 32]); const ALICE: AccountId = AccountId::new([0u8; 32]);
const BOB: AccountId = AccountId::new([1u8; 32]); const BOB: AccountId = AccountId::new([1u8; 32]);
const PARA_ID: u32 = 2000;
const INITIAL_BALANCE: u128 = 100; const INITIAL_BALANCE: u128 = 100;
const SEND_AMOUNT: u128 = 10; const SEND_AMOUNT: u128 = 10;
const FEE_AMOUNT: u128 = 2;
#[test] #[test]
fn report_outcome_notify_works() { fn report_outcome_notify_works() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into();
let mut message = let mut message =
@@ -56,7 +60,7 @@ fn report_outcome_notify_works() {
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
XcmPallet::report_outcome_notify( XcmPallet::report_outcome_notify(
&mut message, &mut message,
Parachain(PARA_ID).into_location(), Parachain(OTHER_PARA_ID).into_location(),
notify, notify,
100, 100,
) )
@@ -74,8 +78,8 @@ fn report_outcome_notify_works() {
); );
let querier: MultiLocation = Here.into(); let querier: MultiLocation = Here.into();
let status = QueryStatus::Pending { let status = QueryStatus::Pending {
responder: MultiLocation::from(Parachain(PARA_ID)).into(), responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(),
maybe_notify: Some((4, 2)), maybe_notify: Some((5, 2)),
timeout: 100, timeout: 100,
maybe_match_querier: Some(querier.into()), maybe_match_querier: Some(querier.into()),
}; };
@@ -89,7 +93,7 @@ fn report_outcome_notify_works() {
}]); }]);
let hash = fake_message_hash(&message); let hash = fake_message_hash(&message);
let r = XcmExecutor::<XcmConfig>::execute_xcm( let r = XcmExecutor::<XcmConfig>::execute_xcm(
Parachain(PARA_ID), Parachain(OTHER_PARA_ID),
message, message,
hash, hash,
Weight::from_parts(1_000_000_000, 1_000_000_000), Weight::from_parts(1_000_000_000, 1_000_000_000),
@@ -99,13 +103,13 @@ fn report_outcome_notify_works() {
last_events(2), last_events(2),
vec![ vec![
RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived( RuntimeEvent::TestNotifier(pallet_test_notifier::Event::ResponseReceived(
Parachain(PARA_ID).into(), Parachain(OTHER_PARA_ID).into(),
0, 0,
Response::ExecutionResult(None), Response::ExecutionResult(None),
)), )),
RuntimeEvent::XcmPallet(crate::Event::Notified { RuntimeEvent::XcmPallet(crate::Event::Notified {
query_id: 0, query_id: 0,
pallet_index: 4, pallet_index: 5,
call_index: 2 call_index: 2
}), }),
] ]
@@ -118,13 +122,14 @@ fn report_outcome_notify_works() {
fn report_outcome_works() { fn report_outcome_works() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into();
let mut message = let mut message =
Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]); Xcm(vec![TransferAsset { assets: (Here, SEND_AMOUNT).into(), beneficiary: sender }]);
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into_location(), 100).unwrap(); XcmPallet::report_outcome(&mut message, Parachain(OTHER_PARA_ID).into_location(), 100)
.unwrap();
assert_eq!( assert_eq!(
message, message,
Xcm(vec![ Xcm(vec![
@@ -138,7 +143,7 @@ fn report_outcome_works() {
); );
let querier: MultiLocation = Here.into(); let querier: MultiLocation = Here.into();
let status = QueryStatus::Pending { let status = QueryStatus::Pending {
responder: MultiLocation::from(Parachain(PARA_ID)).into(), responder: MultiLocation::from(Parachain(OTHER_PARA_ID)).into(),
maybe_notify: None, maybe_notify: None,
timeout: 100, timeout: 100,
maybe_match_querier: Some(querier.into()), maybe_match_querier: Some(querier.into()),
@@ -153,7 +158,7 @@ fn report_outcome_works() {
}]); }]);
let hash = fake_message_hash(&message); let hash = fake_message_hash(&message);
let r = XcmExecutor::<XcmConfig>::execute_xcm( let r = XcmExecutor::<XcmConfig>::execute_xcm(
Parachain(PARA_ID), Parachain(OTHER_PARA_ID),
message, message,
hash, hash,
Weight::from_parts(1_000_000_000, 1_000_000_000), Weight::from_parts(1_000_000_000, 1_000_000_000),
@@ -177,7 +182,7 @@ fn report_outcome_works() {
fn custom_querier_works() { fn custom_querier_works() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
let querier: MultiLocation = let querier: MultiLocation =
@@ -281,7 +286,7 @@ fn custom_querier_works() {
fn send_works() { fn send_works() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let sender: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into();
@@ -325,7 +330,7 @@ fn send_works() {
fn send_fails_when_xcm_router_blocks() { fn send_fails_when_xcm_router_blocks() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
let sender: MultiLocation = let sender: MultiLocation =
@@ -346,344 +351,6 @@ fn send_fails_when_xcm_router_blocks() {
}); });
} }
/// Test `teleport_assets`
///
/// Asserts that the sender's balance is decreased as a result of execution of
/// local effects.
#[test]
fn teleport_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 3;
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into();
assert_ok!(XcmPallet::teleport_assets(
RuntimeOrigin::signed(ALICE),
Box::new(RelayLocation::get().into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
));
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
RelayLocation::get().into(),
Xcm(vec![
ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Here, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `limited_teleport_assets`
///
/// Asserts that the sender's balance is decreased as a result of execution of
/// local effects.
#[test]
fn limited_teleport_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 3;
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into();
assert_ok!(XcmPallet::limited_teleport_assets(
RuntimeOrigin::signed(ALICE),
Box::new(RelayLocation::get().into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
WeightLimit::Limited(Weight::from_parts(5000, 5000)),
));
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
RelayLocation::get().into(),
Xcm(vec![
ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()),
ClearOrigin,
buy_limited_execution((Here, SEND_AMOUNT), Weight::from_parts(5000, 5000)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `limited_teleport_assets` with unlimited weight
///
/// Asserts that the sender's balance is decreased as a result of execution of
/// local effects.
#[test]
fn unlimited_teleport_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 3;
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
let dest: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into();
assert_ok!(XcmPallet::limited_teleport_assets(
RuntimeOrigin::signed(ALICE),
Box::new(RelayLocation::get().into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
WeightLimit::Unlimited,
));
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
RelayLocation::get().into(),
Xcm(vec![
ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Here, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `reserve_transfer_assets`
///
/// Asserts that the sender's balance is decreased and the beneficiary's balance
/// is increased. Verifies the correct message is sent and event is emitted.
#[test]
fn reserve_transfer_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 2;
let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
assert_ok!(XcmPallet::reserve_transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(Parachain(PARA_ID).into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
));
// Alice spent amount
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
// Destination account (parachain account) has amount
let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
Parachain(PARA_ID).into(),
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Parent, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `reserve_transfer_assets_with_paid_router_works`
///
/// Asserts that the sender's balance is decreased and the beneficiary's balance
/// is increased. Verifies the correct message is sent and event is emitted.
/// Verifies that XCM router fees (`SendXcm::validate` -> `MultiAssets`) are withdrawn from correct
/// user account and deposited to a correct target account (`XcmFeesTargetAccount`).
#[test]
fn reserve_transfer_assets_with_paid_router_works() {
let user_account = AccountId::from(XCM_FEES_NOT_WAIVED_USER_ACCOUNT);
let paid_para_id = Para3000::get();
let balances = vec![
(user_account.clone(), INITIAL_BALANCE),
(ParaId::from(paid_para_id).into_account_truncating(), INITIAL_BALANCE),
(XcmFeesTargetAccount::get(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let xcm_router_fee_amount = Para3000PaymentAmount::get();
let weight = BaseXcmWeight::get() * 2;
let dest: MultiLocation =
Junction::AccountId32 { network: None, id: user_account.clone().into() }.into();
assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE);
assert_ok!(XcmPallet::reserve_transfer_assets(
RuntimeOrigin::signed(user_account.clone()),
Box::new(Parachain(paid_para_id).into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
));
// check event
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
// XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount
assert_eq!(
Balances::free_balance(user_account),
INITIAL_BALANCE - SEND_AMOUNT - xcm_router_fee_amount
);
// Destination account (parachain account) has amount
let para_acc: AccountId = ParaId::from(paid_para_id).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
// XcmFeesTargetAccount where should lend xcm_router_fee_amount
assert_eq!(
Balances::free_balance(XcmFeesTargetAccount::get()),
INITIAL_BALANCE + xcm_router_fee_amount
);
assert_eq!(
sent_xcm(),
vec![(
Parachain(paid_para_id).into(),
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Parent, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `limited_reserve_transfer_assets`
///
/// Asserts that the sender's balance is decreased and the beneficiary's balance
/// is increased. Verifies the correct message is sent and event is emitted.
#[test]
fn limited_reserve_transfer_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 2;
let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
assert_ok!(XcmPallet::limited_reserve_transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(Parachain(PARA_ID).into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
WeightLimit::Limited(Weight::from_parts(5000, 5000)),
));
// Alice spent amount
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
// Destination account (parachain account) has amount
let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
Parachain(PARA_ID).into(),
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_limited_execution((Parent, SEND_AMOUNT), Weight::from_parts(5000, 5000)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1);
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test `limited_reserve_transfer_assets` with unlimited weight purchasing
///
/// Asserts that the sender's balance is decreased and the beneficiary's balance
/// is increased. Verifies the correct message is sent and event is emitted.
#[test]
fn unlimited_reserve_transfer_assets_works() {
let balances = vec![
(ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE),
];
new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 2;
let dest: MultiLocation = Junction::AccountId32 { network: None, id: ALICE.into() }.into();
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE);
assert_ok!(XcmPallet::limited_reserve_transfer_assets(
RuntimeOrigin::signed(ALICE),
Box::new(Parachain(PARA_ID).into()),
Box::new(dest.into()),
Box::new((Here, SEND_AMOUNT).into()),
0,
WeightLimit::Unlimited,
));
// Alice spent amount
assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT);
// Destination account (parachain account) has amount
let para_acc: AccountId = ParaId::from(PARA_ID).into_account_truncating();
assert_eq!(Balances::free_balance(para_acc), INITIAL_BALANCE + SEND_AMOUNT);
assert_eq!(
sent_xcm(),
vec![(
Parachain(PARA_ID).into(),
Xcm(vec![
ReserveAssetDeposited((Parent, SEND_AMOUNT).into()),
ClearOrigin,
buy_execution((Parent, SEND_AMOUNT)),
DepositAsset { assets: AllCounted(1).into(), beneficiary: dest },
]),
)]
);
assert_eq!(
last_event(),
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
);
});
}
/// Test local execution of XCM /// Test local execution of XCM
/// ///
/// Asserts that the sender's balance is decreased and the beneficiary's balance /// Asserts that the sender's balance is decreased and the beneficiary's balance
@@ -692,7 +359,7 @@ fn unlimited_reserve_transfer_assets_works() {
fn execute_withdraw_to_deposit_works() { fn execute_withdraw_to_deposit_works() {
let balances = vec![ let balances = vec![
(ALICE, INITIAL_BALANCE), (ALICE, INITIAL_BALANCE),
(ParaId::from(PARA_ID).into_account_truncating(), INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE),
]; ];
new_test_ext_with_balances(balances).execute_with(|| { new_test_ext_with_balances(balances).execute_with(|| {
let weight = BaseXcmWeight::get() * 3; let weight = BaseXcmWeight::get() * 3;
+66
View File
@@ -444,6 +444,21 @@ impl MultiLocation {
} }
} }
} }
/// Return the MultiLocation subsection identifying the chain that `self` points to.
pub fn chain_location(&self) -> MultiLocation {
let mut clone = *self;
// start popping junctions until we reach chain identifier
while let Some(j) = clone.last() {
if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
// return chain subsection
return clone
} else {
(clone, _) = clone.split_last_interior();
}
}
MultiLocation::new(clone.parents, Junctions::Here)
}
} }
impl TryFrom<OldMultiLocation> for MultiLocation { impl TryFrom<OldMultiLocation> for MultiLocation {
@@ -674,6 +689,57 @@ mod tests {
assert_eq!(iter.next_back(), None); assert_eq!(iter.next_back(), None);
} }
#[test]
fn chain_location_works() {
// Relay-chain or parachain context pointing to local resource,
let relay_to_local = MultiLocation::new(0, (PalletInstance(42), GeneralIndex(42)));
assert_eq!(relay_to_local.chain_location(), MultiLocation::here());
// Relay-chain context pointing to child parachain,
let relay_to_child =
MultiLocation::new(0, (Parachain(42), PalletInstance(42), GeneralIndex(42)));
let expected = MultiLocation::new(0, Parachain(42));
assert_eq!(relay_to_child.chain_location(), expected);
// Relay-chain context pointing to different consensus relay,
let relay_to_remote_relay =
MultiLocation::new(1, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42)));
let expected = MultiLocation::new(1, GlobalConsensus(Kusama));
assert_eq!(relay_to_remote_relay.chain_location(), expected);
// Relay-chain context pointing to different consensus parachain,
let relay_to_remote_para = MultiLocation::new(
1,
(GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)),
);
let expected = MultiLocation::new(1, (GlobalConsensus(Kusama), Parachain(42)));
assert_eq!(relay_to_remote_para.chain_location(), expected);
// Parachain context pointing to relay chain,
let para_to_relay = MultiLocation::new(1, (PalletInstance(42), GeneralIndex(42)));
assert_eq!(para_to_relay.chain_location(), MultiLocation::parent());
// Parachain context pointing to sibling parachain,
let para_to_sibling =
MultiLocation::new(1, (Parachain(42), PalletInstance(42), GeneralIndex(42)));
let expected = MultiLocation::new(1, Parachain(42));
assert_eq!(para_to_sibling.chain_location(), expected);
// Parachain context pointing to different consensus relay,
let para_to_remote_relay =
MultiLocation::new(2, (GlobalConsensus(Kusama), PalletInstance(42), GeneralIndex(42)));
let expected = MultiLocation::new(2, GlobalConsensus(Kusama));
assert_eq!(para_to_remote_relay.chain_location(), expected);
// Parachain context pointing to different consensus parachain,
let para_to_remote_para = MultiLocation::new(
2,
(GlobalConsensus(Kusama), Parachain(42), PalletInstance(42), GeneralIndex(42)),
);
let expected = MultiLocation::new(2, (GlobalConsensus(Kusama), Parachain(42)));
assert_eq!(para_to_remote_para.chain_location(), expected);
}
#[test] #[test]
fn conversion_from_other_types_works() { fn conversion_from_other_types_works() {
use crate::v2; use crate::v2;
+9 -4
View File
@@ -81,10 +81,15 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
instructions[..end] instructions[..end]
.matcher() .matcher()
.match_next_inst(|inst| match inst { .match_next_inst(|inst| match inst {
ReceiveTeleportedAsset(..) | ReserveAssetDeposited(..) => Ok(()), ReceiveTeleportedAsset(ref assets) |
WithdrawAsset(ref assets) if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => Ok(()), ReserveAssetDeposited(ref assets) |
ClaimAsset { ref assets, .. } if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION => WithdrawAsset(ref assets) |
Ok(()), ClaimAsset { ref assets, .. } =>
if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION {
Ok(())
} else {
Err(ProcessMessageError::BadFormat)
},
_ => Err(ProcessMessageError::BadFormat), _ => Err(ProcessMessageError::BadFormat),
})? })?
.skip_inst_while(|inst| matches!(inst, ClearOrigin))? .skip_inst_while(|inst| matches!(inst, ClearOrigin))?
@@ -246,11 +246,6 @@ type SovereignAccountOf = (
HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>, HashedDescription<AccountId, DescribeFamily<DescribeAllTerminal>>,
); );
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1000).into());
}
impl pallet_xcm::Config for Test { impl pallet_xcm::Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -274,8 +269,6 @@ impl pallet_xcm::Config for Test {
type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
@@ -210,11 +210,6 @@ impl xcm_executor::Config for XcmConfig {
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Here.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type UniversalLocation = UniversalLocation; type UniversalLocation = UniversalLocation;
@@ -239,8 +234,6 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
+2
View File
@@ -10,6 +10,7 @@ version = "1.0.0"
impl-trait-for-tuples = "0.2.2" impl-trait-for-tuples = "0.2.2"
environmental = { version = "1.1.4", default-features = false } environmental = { version = "1.1.4", default-features = false }
parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] }
scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] }
xcm = { package = "staging-xcm", path = "..", default-features = false } xcm = { package = "staging-xcm", path = "..", default-features = false }
sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false }
sp-io = { path = "../../../substrate/primitives/io", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false }
@@ -34,6 +35,7 @@ std = [
"frame-support/std", "frame-support/std",
"log/std", "log/std",
"parity-scale-codec/std", "parity-scale-codec/std",
"scale-info/std",
"sp-arithmetic/std", "sp-arithmetic/std",
"sp-core/std", "sp-core/std",
"sp-io/std", "sp-io/std",
+7 -1
View File
@@ -32,7 +32,7 @@ pub mod traits;
use traits::{ use traits::{
validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute, DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute,
TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers,
}; };
mod assets; mod assets;
@@ -254,6 +254,12 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
} }
} }
impl<Config: config::Config> XcmAssetTransfers for XcmExecutor<Config> {
type IsReserve = Config::IsReserve;
type IsTeleporter = Config::IsTeleporter;
type AssetTransactor = Config::AssetTransactor;
}
#[derive(Debug)] #[derive(Debug)]
pub struct ExecutorError { pub struct ExecutorError {
pub index: u32, pub index: u32,
@@ -0,0 +1,90 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use crate::traits::TransactAsset;
use frame_support::traits::ContainsPair;
use scale_info::TypeInfo;
use sp_runtime::codec::{Decode, Encode};
use xcm::prelude::*;
/// Errors related to determining asset transfer support.
#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
pub enum Error {
/// Invalid non-concrete asset.
NotConcrete,
/// Reserve chain could not be determined for assets.
UnknownReserve,
}
/// Specify which type of asset transfer is required for a particular `(asset, dest)` combination.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum TransferType {
/// should teleport `asset` to `dest`
Teleport,
/// should reserve-transfer `asset` to `dest`, using local chain as reserve
LocalReserve,
/// should reserve-transfer `asset` to `dest`, using `dest` as reserve
DestinationReserve,
/// should reserve-transfer `asset` to `dest`, using remote chain `MultiLocation` as reserve
RemoteReserve(MultiLocation),
}
/// A trait for identifying asset transfer type based on `IsTeleporter` and `IsReserve`
/// configurations.
pub trait XcmAssetTransfers {
/// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning
/// reserve-based-transfers are to be used for assets matching this filter.
type IsReserve: ContainsPair<MultiAsset, MultiLocation>;
/// Combinations of (Asset, Location) pairs which we trust as teleporters. Meaning teleports are
/// to be used for assets matching this filter.
type IsTeleporter: ContainsPair<MultiAsset, MultiLocation>;
/// How to withdraw and deposit an asset.
type AssetTransactor: TransactAsset;
/// Determine transfer type to be used for transferring `asset` from local chain to `dest`.
fn determine_for(asset: &MultiAsset, dest: &MultiLocation) -> Result<TransferType, Error> {
if Self::IsTeleporter::contains(asset, dest) {
// we trust destination for teleporting asset
return Ok(TransferType::Teleport)
} else if Self::IsReserve::contains(asset, dest) {
// we trust destination as asset reserve location
return Ok(TransferType::DestinationReserve)
}
// try to determine reserve location based on asset id/location
let asset_location = match asset.id {
Concrete(location) => Ok(location.chain_location()),
_ => Err(Error::NotConcrete),
}?;
if asset_location == MultiLocation::here() ||
Self::IsTeleporter::contains(asset, &asset_location)
{
// if the asset is local, then it's a local reserve
// it's also a local reserve if the asset's location is not `here` but it's a location
// where it can be teleported to `here` => local reserve
Ok(TransferType::LocalReserve)
} else if Self::IsReserve::contains(asset, &asset_location) {
// remote location that is recognized as reserve location for asset
Ok(TransferType::RemoteReserve(asset_location))
} else {
// remote location that is not configured either as teleporter or reserve => cannot
// determine asset reserve
Err(Error::UnknownReserve)
}
}
}
+4 -2
View File
@@ -20,10 +20,12 @@ mod conversion;
pub use conversion::{CallDispatcher, ConvertLocation, ConvertOrigin, WithOriginFilter}; pub use conversion::{CallDispatcher, ConvertLocation, ConvertOrigin, WithOriginFilter};
mod drop_assets; mod drop_assets;
pub use drop_assets::{ClaimAssets, DropAssets}; pub use drop_assets::{ClaimAssets, DropAssets};
mod asset_lock;
pub use asset_lock::{AssetLock, Enact, LockError};
mod asset_exchange; mod asset_exchange;
pub use asset_exchange::AssetExchange; pub use asset_exchange::AssetExchange;
mod asset_lock;
pub use asset_lock::{AssetLock, Enact, LockError};
mod asset_transfer;
pub use asset_transfer::{Error as AssetTransferError, TransferType, XcmAssetTransfers};
mod export; mod export;
pub use export::{export_xcm, validate_export, ExportXcm}; pub use export::{export_xcm, validate_export, ExportXcm};
mod fee_manager; mod fee_manager;
@@ -399,11 +399,6 @@ impl mock_msg_queue::Config for Runtime {
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
pub struct TrustedLockerCase<T>(PhantomData<T>); pub struct TrustedLockerCase<T>(PhantomData<T>);
impl<T: Get<(MultiLocation, MultiAssetFilter)>> ContainsPair<MultiLocation, MultiAsset> impl<T: Get<(MultiLocation, MultiAssetFilter)>> ContainsPair<MultiLocation, MultiAsset>
for TrustedLockerCase<T> for TrustedLockerCase<T>
@@ -443,8 +438,6 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
@@ -199,11 +199,6 @@ impl Config for XcmConfig {
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1).into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -228,8 +223,6 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
@@ -313,11 +313,6 @@ impl mock_msg_queue::Config for Runtime {
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parent.into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -341,8 +336,6 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>; type MaxRemoteLockConsumers = frame_support::traits::ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }
@@ -163,11 +163,6 @@ impl Config for XcmConfig {
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>; pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>;
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub ReachableDest: Option<MultiLocation> = Some(Parachain(1).into());
}
impl pallet_xcm::Config for Runtime { impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
@@ -192,8 +187,6 @@ impl pallet_xcm::Config for Runtime {
type MaxRemoteLockConsumers = ConstU32<0>; type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = (); type RemoteLockConsumerIdentifier = ();
type WeightInfo = pallet_xcm::TestWeightInfo; type WeightInfo = pallet_xcm::TestWeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type ReachableDest = ReachableDest;
type AdminOrigin = EnsureRoot<AccountId>; type AdminOrigin = EnsureRoot<AccountId>;
} }