pallet-xcm: add new flexible transfer_assets() call/extrinsic (#2388)

# Motivation (+testing)

### Enable easy `ForeignAssets` transfers using `pallet-xcm` 

We had just previously added capabilities to teleport fees during
reserve-based transfers, but what about reserve-transferring fees when
needing to teleport some non-fee asset?

This PR aligns everything under either explicit reserve-transfer,
explicit teleport, or this new flexible `transfer_assets()` which can
mix and match as needed with fewer artificial constraints imposed to the
user.

This will enable, for example, a (non-system) parachain to teleport
their `ForeignAssets` assets to AssetHub while using DOT to pay fees.
(the assets are teleported - as foreign assets should from their owner
chain - while DOT used for fees can only be reserve-based transferred
between said parachain and AssetHub).

Added `xcm-emulator` tests for this scenario ^.

# Description

Reverts `(limited_)reserve_transfer_assets` to only allow reserve-based
transfers for all `assets` including fees.

Similarly `(limited_)teleport_assets` only allows teleports for all
`assets` including fees.
    
For complex combinations of asset transfers where assets and fees may
have different reserves or different reserve/teleport trust
configurations, users can use the newly added `transfer_assets()`
extrinsic which is more flexible in allowing more complex scenarios.

`assets` (excluding `fees`) must have same reserve location or otherwise
be teleportable to `dest`.
No limitations imposed on `fees`.

- for local reserve: transfer assets to sovereign account of destination
chain and forward a notification XCM to `dest` to mint and deposit
reserve-based assets to `beneficiary`.
- for destination reserve: burn local assets and forward a notification
to `dest` chain to withdraw the reserve assets from this chain's
sovereign account and deposit them to `beneficiary`.
- for remote reserve: burn local assets, forward XCM to reserve chain to
move reserves from this chain's SA to `dest` chain's SA, and forward
another XCM to `dest` to mint and deposit reserve-based assets to
`beneficiary`.
- for teleports: burn local assets and forward XCM to `dest` chain to
mint/teleport assets and deposit them to `beneficiary`.

## Review notes

Only around 500 lines are prod code (see `pallet_xcm/src/lib.rs`), the
rest of the PR is new tests and improving existing tests.

---------

Co-authored-by: command-bot <>
This commit is contained in:
Adrian Catangiu
2023-12-06 13:18:12 +02:00
committed by GitHub
parent 066bad6329
commit e7651cf41b
38 changed files with 3320 additions and 955 deletions
Generated
-2
View File
@@ -761,7 +761,6 @@ dependencies = [
"pallet-xcm",
"parachains-common",
"parity-scale-codec",
"penpal-runtime",
"rococo-runtime",
"rococo-system-emulated-network",
"sp-runtime",
@@ -884,7 +883,6 @@ dependencies = [
"pallet-xcm",
"parachains-common",
"parity-scale-codec",
"penpal-runtime",
"polkadot-runtime-common",
"sp-runtime",
"staging-xcm",
@@ -15,6 +15,7 @@
mod genesis;
pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B};
pub use penpal_runtime::xcm_config::{LocalTeleportableToAssetHub, XcmConfig};
// Substrate
use frame_support::traits::OnInitialize;
@@ -67,6 +68,7 @@ decl_test_parachains! {
// Penpal implementation
impl_accounts_helpers_for_parachain!(PenpalA);
impl_accounts_helpers_for_parachain!(PenpalB);
impl_assets_helpers_for_parachain!(PenpalA, Rococo);
impl_assets_helpers_for_parachain!(PenpalB, Westend);
impl_assert_events_helpers_for_parachain!(PenpalA);
@@ -120,3 +120,102 @@ macro_rules! test_parachain_is_trusted_teleporter {
}
};
}
#[macro_export]
macro_rules! include_penpal_create_foreign_asset_on_asset_hub {
( $penpal:ident, $asset_hub:ident, $relay_ed:expr, $weight_to_fee:expr) => {
$crate::impls::paste::paste! {
pub fn penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal: u32,
foreign_asset_at_asset_hub: MultiLocation,
ah_as_seen_by_penpal: MultiLocation,
is_sufficient: bool,
asset_owner: AccountId,
prefund_amount: u128,
) {
use frame_support::weights::WeightToFee;
let ah_check_account = $asset_hub::execute_with(|| {
<$asset_hub as [<$asset_hub Pallet>]>::PolkadotXcm::check_account()
});
let penpal_check_account =
$penpal::execute_with(|| <$penpal as [<$penpal Pallet>]>::PolkadotXcm::check_account());
let penpal_as_seen_by_ah = $asset_hub::sibling_location_of($penpal::para_id());
// prefund SA of Penpal on AssetHub with enough native tokens to pay for creating
// new foreign asset, also prefund CheckingAccount with ED, because teleported asset
// itself might not be sufficient and CheckingAccount cannot be created otherwise
let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah);
$asset_hub::fund_accounts(vec![
(sov_penpal_on_ah.clone().into(), $relay_ed * 100_000_000_000),
(ah_check_account.clone().into(), $relay_ed * 1000),
]);
// prefund SA of AssetHub on Penpal with native asset
let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal);
$penpal::fund_accounts(vec![
(sov_ah_on_penpal.into(), $relay_ed * 1_000_000_000),
(penpal_check_account.clone().into(), $relay_ed * 1000),
]);
// Force create asset on $penpal and prefund [<$penpal Sender>]
$penpal::force_create_and_mint_asset(
asset_id_on_penpal,
ASSET_MIN_BALANCE,
is_sufficient,
asset_owner,
None,
prefund_amount,
);
let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000);
// `OriginKind::Xcm` required by ForeignCreators pallet-assets origin filter
let origin_kind = OriginKind::Xcm;
let call_create_foreign_assets =
<$asset_hub as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::<
<$asset_hub as Chain>::Runtime,
pallet_assets::Instance2,
>::create {
id: foreign_asset_at_asset_hub,
min_balance: ASSET_MIN_BALANCE,
admin: sov_penpal_on_ah.into(),
})
.encode();
let buy_execution_fee_amount = $weight_to_fee::weight_to_fee(
&Weight::from_parts(10_100_000_000_000, 300_000),
);
let buy_execution_fee = MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(buy_execution_fee_amount),
};
let xcm = VersionedXcm::from(Xcm(vec![
WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() },
BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
Transact { require_weight_at_most, origin_kind, call: call_create_foreign_assets.into() },
ExpectTransactStatus(MaybeErrorCode::Success),
RefundSurplus,
DepositAsset { assets: All.into(), beneficiary: penpal_as_seen_by_ah },
]));
// Send XCM message from penpal => asset_hub
let sudo_penpal_origin = <$penpal as Chain>::RuntimeOrigin::root();
$penpal::execute_with(|| {
assert_ok!(<$penpal as [<$penpal Pallet>]>::PolkadotXcm::send(
sudo_penpal_origin.clone(),
bx!(ah_as_seen_by_penpal.into()),
bx!(xcm),
));
type RuntimeEvent = <$penpal as Chain>::RuntimeEvent;
assert_expected_events!(
$penpal,
vec![
RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
]
);
});
$asset_hub::execute_with(|| {
type ForeignAssets = <$asset_hub as [<$asset_hub Pallet>]>::ForeignAssets;
assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub));
});
}
}
};
}
@@ -59,3 +59,17 @@ pub fn xcm_transact_unpaid_execution(
Transact { require_weight_at_most, origin_kind, call },
]))
}
/// Helper method to get the non-fee asset used in multiple assets transfer
pub fn non_fee_asset(assets: &MultiAssets, fee_idx: usize) -> Option<(MultiLocation, u128)> {
let asset = assets.inner().into_iter().enumerate().find(|a| a.0 != fee_idx)?.1.clone();
let asset_id = match asset.id {
Concrete(id) => id,
_ => return None,
};
let asset_amount = match asset.fun {
Fungible(amount) => amount,
_ => return None,
};
Some((asset_id, asset_amount))
}
@@ -30,5 +30,4 @@ asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
parachains-common = { path = "../../../../../../parachains/common" }
asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" }
emulated-integration-tests-common = { path = "../../../common", default-features = false }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
rococo-system-emulated-network = { path = "../../../networks/rococo-system" }
@@ -18,3 +18,11 @@ mod send;
mod set_xcm_versions;
mod swap;
mod teleport;
use crate::*;
emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!(
PenpalA,
AssetHubRococo,
ROCOCO_ED,
parachains_common::rococo::fee::WeightToFee
);
@@ -15,14 +15,12 @@
use crate::*;
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_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalRococoXcmConfig;
fn relay_to_para_sender_assertions(t: RelayToParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799)));
assert_expected_events!(
Rococo,
vec![
@@ -42,12 +40,10 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) {
fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
864_610_000,
8_799,
)));
assert_expected_events!(
AssetHubRococo,
vec![
@@ -80,9 +76,7 @@ fn para_receiver_assertions<Test>(_: Test) {
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![
@@ -99,15 +93,13 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) {
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
// Amount to reserve transfer is withdrawn from Parachain's Sovereign account
RuntimeEvent::Balances(
pallet_balances::Event::Withdraw { who, amount }
) => {
@@ -124,12 +116,10 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) {
fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(
864_610_000,
8799,
)));
assert_expected_events!(
AssetHubRococo,
vec![
@@ -162,7 +152,7 @@ fn system_para_to_para_assets_receiver_assertions<Test>(_: Test) {
);
}
fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult {
fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult {
<Rococo as RococoPallet>::XcmPallet::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -173,7 +163,7 @@ fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> Dispatch
)
}
fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -184,7 +174,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest)
)
}
fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalA as PenpalAPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -285,7 +275,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() {
test.set_assertion::<Rococo>(relay_to_para_sender_assertions);
test.set_assertion::<PenpalA>(para_receiver_assertions);
test.set_dispatchable::<Rococo>(relay_to_para_limited_reserve_transfer_assets);
test.set_dispatchable::<Rococo>(relay_to_para_reserve_transfer_assets);
test.assert();
let delivery_fees = Rococo::execute_with(|| {
@@ -329,7 +319,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
test.set_assertion::<AssetHubRococo>(system_para_to_para_sender_assertions);
test.set_assertion::<PenpalA>(para_receiver_assertions);
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();
let sender_balance_after = test.sender.balance;
@@ -379,7 +369,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() {
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.set_dispatchable::<PenpalA>(para_to_system_para_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
@@ -474,7 +464,7 @@ fn reserve_transfer_assets_from_system_para_to_para() {
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);
test.set_dispatchable::<AssetHubRococo>(system_para_to_para_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
@@ -14,9 +14,10 @@
// limitations under the License.
use crate::*;
use frame_support::{instances::Instance2, BoundedVec};
use frame_support::BoundedVec;
use parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT;
use sp_runtime::{DispatchError, ModuleError};
use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub;
use sp_runtime::ModuleError;
#[test]
fn swap_locally_on_chain_using_local_assets() {
@@ -112,114 +113,37 @@ fn swap_locally_on_chain_using_local_assets() {
#[test]
fn swap_locally_on_chain_using_foreign_assets() {
use frame_support::weights::WeightToFee;
let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get());
let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get();
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalASender::get();
let foreign_asset_at_asset_hub_rococo =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }
.appended_with(asset_location_on_penpal)
.unwrap();
let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation {
parents: 1,
interior: X3(
Parachain(PenpalA::para_id().into()),
PalletInstance(ASSETS_PALLET_ID),
GeneralIndex(ASSET_ID.into()),
),
});
let assets_para_destination: VersionedMultiLocation =
MultiLocation { parents: 1, interior: X1(Parachain(AssetHubRococo::para_id().into())) }
.into();
let penpal_location =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) };
// 1. Create asset on penpal:
PenpalA::execute_with(|| {
assert_ok!(<PenpalA as PenpalAPallet>::Assets::create(
<PenpalA as Chain>::RuntimeOrigin::signed(PenpalASender::get()),
ASSET_ID.into(),
PenpalASender::get().into(),
1000,
));
assert!(<PenpalA as PenpalAPallet>::Assets::asset_exists(ASSET_ID));
});
// 2. Create foreign asset on asset_hub_rococo:
let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000);
let origin_kind = OriginKind::Xcm;
let sov_penpal_on_asset_hub_rococo = AssetHubRococo::sovereign_account_id_of(penpal_location);
// 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_rococo
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_rococo,
ah_as_seen_by_penpal,
true,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_as_seen_by_ah);
AssetHubRococo::fund_accounts(vec![
(AssetHubRococoSender::get().into(), 5_000_000 * ROCOCO_ED), /* An account to swap dot
* for something else. */
(sov_penpal_on_asset_hub_rococo.clone().into(), 1000_000_000_000_000_000 * ROCOCO_ED),
]);
let sov_penpal_on_asset_hub_rococo_as_location: MultiLocation = MultiLocation {
parents: 0,
interior: X1(AccountId32Junction {
network: None,
id: sov_penpal_on_asset_hub_rococo.clone().into(),
}),
};
let call_foreign_assets_create =
<AssetHubRococo as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::<
<AssetHubRococo as Chain>::Runtime,
Instance2,
>::create {
id: *foreign_asset1_at_asset_hub_rococo,
min_balance: 1000,
admin: sov_penpal_on_asset_hub_rococo.clone().into(),
})
.encode()
.into();
let buy_execution_fee_amount = parachains_common::rococo::fee::WeightToFee::weight_to_fee(
&Weight::from_parts(10_100_000_000_000, 300_000),
);
let buy_execution_fee = MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(buy_execution_fee_amount),
};
let xcm = VersionedXcm::from(Xcm(vec![
WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() },
BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create },
RefundSurplus,
DepositAsset {
assets: All.into(),
beneficiary: sov_penpal_on_asset_hub_rococo_as_location,
},
]));
// Send XCM message from penpal => asset_hub_rococo
let sudo_penpal_origin = <PenpalA as Chain>::RuntimeOrigin::root();
PenpalA::execute_with(|| {
assert_ok!(<PenpalA as PenpalAPallet>::PolkadotXcm::send(
sudo_penpal_origin.clone(),
bx!(assets_para_destination.clone()),
bx!(xcm),
));
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
]
);
});
// Receive XCM message in Assets Parachain
AssetHubRococo::execute_with(|| {
assert!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::asset_exists(
*foreign_asset1_at_asset_hub_rococo
));
// 3: Mint foreign asset on asset_hub_rococo:
//
// (While it might be nice to use batch,
@@ -228,11 +152,9 @@ fn swap_locally_on_chain_using_foreign_assets() {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
// 3. Mint foreign asset (in reality this should be a teleport or some such)
assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::mint(
<AssetHubRococo as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_rococo.clone().into()
),
*foreign_asset1_at_asset_hub_rococo,
sov_penpal_on_asset_hub_rococo.clone().into(),
<AssetHubRococo as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()),
foreign_asset_at_asset_hub_rococo,
sov_penpal_on_ahr.clone().into(),
3_000_000_000_000,
));
@@ -243,11 +165,12 @@ fn swap_locally_on_chain_using_foreign_assets() {
]
);
let foreign_asset_at_asset_hub_rococo = Box::new(foreign_asset_at_asset_hub_rococo);
// 4. Create pool:
assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::AssetConversion::create_pool(
<AssetHubRococo as Chain>::RuntimeOrigin::signed(AssetHubRococoSender::get()),
asset_native.clone(),
foreign_asset1_at_asset_hub_rococo.clone(),
foreign_asset_at_asset_hub_rococo.clone(),
));
assert_expected_events!(
@@ -259,16 +182,14 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 5. Add liquidity:
assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::AssetConversion::add_liquidity(
<AssetHubRococo as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_rococo.clone()
),
<AssetHubRococo as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
asset_native.clone(),
foreign_asset1_at_asset_hub_rococo.clone(),
foreign_asset_at_asset_hub_rococo.clone(),
1_000_000_000_000,
2_000_000_000_000,
0,
0,
sov_penpal_on_asset_hub_rococo.clone().into()
sov_penpal_on_ahr.clone().into()
));
assert_expected_events!(
@@ -283,7 +204,7 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 6. Swap!
let path = BoundedVec::<_, _>::truncate_from(vec![
asset_native.clone(),
foreign_asset1_at_asset_hub_rococo.clone(),
foreign_asset_at_asset_hub_rococo.clone(),
]);
assert_ok!(
@@ -309,15 +230,13 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 7. Remove liquidity
assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::AssetConversion::remove_liquidity(
<AssetHubRococo as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_rococo.clone()
),
<AssetHubRococo as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()),
asset_native,
foreign_asset1_at_asset_hub_rococo,
foreign_asset_at_asset_hub_rococo,
1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved.
0,
0,
sov_penpal_on_asset_hub_rococo.clone().into(),
sov_penpal_on_ahr.clone().into(),
));
});
}
@@ -15,7 +15,9 @@
use crate::*;
use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig;
use emulated_integration_tests_common::xcm_helpers::non_fee_asset;
use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig;
use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub;
fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Rococo as Chain>::RuntimeEvent;
@@ -110,6 +112,123 @@ fn para_dest_assertions(t: RelayToSystemParaTest) {
);
}
fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
PenpalA::assert_xcm_pallet_attempted_complete(None);
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::Balances(
pallet_balances::Event::Withdraw { who, amount }
) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == t.sender.account_id,
balance: *balance == expected_asset_amount,
},
]
);
}
fn penpal_to_ah_foreign_assets_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()),
);
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
AssetHubRococo,
vec![
// native asset reserve transfer for paying fees, withdrawn from Penpal's sov 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 { who, .. }) => {
who: *who == t.receiver.account_id,
},
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => {
asset_id: *asset_id == expected_foreign_asset_id,
owner: *owner == t.receiver.account_id,
amount: *amount == expected_foreign_asset_amount,
},
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
AssetHubRococo::assert_xcm_pallet_attempted_complete(None);
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
AssetHubRococo,
vec![
// native asset used for fees is transferred to Parachain's Sovereign account as reserve
RuntimeEvent::Balances(
pallet_balances::Event::Transfer { from, to, amount }
) => {
from: *from == t.sender.account_id,
to: *to == AssetHubRococo::sovereign_account_id_of(
t.args.dest
),
amount: *amount == t.args.amount,
},
// foreign asset is burned locally as part of teleportation
RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_foreign_asset_id,
owner: *owner == t.sender.account_id,
balance: *balance == expected_foreign_asset_amount,
},
]
);
}
fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
let checking_account = <PenpalA as PenpalAPallet>::PolkadotXcm::check_account();
assert_expected_events!(
PenpalA,
vec![
// checking account burns local asset as part of incoming teleport
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == checking_account,
balance: *balance == expected_asset_amount,
},
// local asset is teleported into account of receiver
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == t.receiver.account_id,
amount: *amount == expected_asset_amount,
},
// native asset for fee is deposited to receiver
RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => {
who: *who == t.receiver.account_id,
},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Rococo as RococoPallet>::XcmPallet::limited_teleport_assets(
t.signed_origin,
@@ -152,6 +271,28 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
)
}
fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalA as PenpalAPallet>::PolkadotXcm::transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::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,
)
}
/// Limited Teleport of native asset from Relay Chain to the System Parachain should work
#[test]
fn limited_teleport_native_assets_from_relay_to_system_para_works() {
@@ -410,3 +551,199 @@ fn teleport_to_other_system_parachains_works() {
(native_asset, amount)
);
}
/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work
/// (using native reserve-based transfer for fees)
#[test]
fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get();
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalASender::get();
let foreign_asset_at_asset_hub_rococo =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }
.appended_with(asset_location_on_penpal)
.unwrap();
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_rococo,
ah_as_seen_by_penpal,
false,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_to_ah_beneficiary_id = AssetHubRococoReceiver::get();
let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000;
let asset_amount_to_send = ASSET_MIN_BALANCE * 1000;
let penpal_assets: MultiAssets = vec![
(Parent, fee_amount_to_send).into(),
(asset_location_on_penpal, asset_amount_to_send).into(),
]
.into();
let fee_asset_index = penpal_assets
.inner()
.iter()
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
// Penpal to AH test args
let penpal_to_ah_test_args = TestContext {
sender: PenpalASender::get(),
receiver: AssetHubRococoReceiver::get(),
args: para_test_args(
ah_as_seen_by_penpal,
penpal_to_ah_beneficiary_id,
asset_amount_to_send,
penpal_assets,
Some(asset_id_on_penpal),
fee_asset_index,
),
};
let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args);
let penpal_sender_balance_before = penpal_to_ah.sender.balance;
let ah_receiver_balance_before = penpal_to_ah.receiver.balance;
let penpal_sender_assets_before = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
});
let ah_receiver_assets_before = AssetHubRococo::execute_with(|| {
type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_rococo,
&AssetHubRococoReceiver::get(),
)
});
penpal_to_ah.set_assertion::<PenpalA>(penpal_to_ah_foreign_assets_sender_assertions);
penpal_to_ah.set_assertion::<AssetHubRococo>(penpal_to_ah_foreign_assets_receiver_assertions);
penpal_to_ah.set_dispatchable::<PenpalA>(para_to_system_para_transfer_assets);
penpal_to_ah.assert();
let penpal_sender_balance_after = penpal_to_ah.sender.balance;
let ah_receiver_balance_after = penpal_to_ah.receiver.balance;
let penpal_sender_assets_after = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalASender::get())
});
let ah_receiver_assets_after = AssetHubRococo::execute_with(|| {
type Assets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_rococo,
&AssetHubRococoReceiver::get(),
)
});
// Sender's balance is reduced
assert!(penpal_sender_balance_after < penpal_sender_balance_before);
// Receiver's balance is increased
assert!(ah_receiver_balance_after > ah_receiver_balance_before);
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
// should be non-zero
assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send);
// Sender's balance is reduced by exact amount
assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after);
// Receiver's balance is increased by exact amount
assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send);
///////////////////////////////////////////////////////////////////////
// Now test transferring foreign assets back from AssetHub to Penpal //
///////////////////////////////////////////////////////////////////////
// Move funds on AH from AHReceiver to AHSender
AssetHubRococo::execute_with(|| {
type ForeignAssets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
assert_ok!(ForeignAssets::transfer(
<AssetHubRococo as Chain>::RuntimeOrigin::signed(AssetHubRococoReceiver::get()),
foreign_asset_at_asset_hub_rococo,
AssetHubRococoSender::get().into(),
asset_amount_to_send,
));
});
let ah_to_penpal_beneficiary_id = PenpalAReceiver::get();
let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id());
let ah_assets: MultiAssets = vec![
(Parent, fee_amount_to_send).into(),
(foreign_asset_at_asset_hub_rococo, asset_amount_to_send).into(),
]
.into();
let fee_asset_index = ah_assets
.inner()
.iter()
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
// AH to Penpal test args
let ah_to_penpal_test_args = TestContext {
sender: AssetHubRococoSender::get(),
receiver: PenpalAReceiver::get(),
args: para_test_args(
penpal_as_seen_by_ah,
ah_to_penpal_beneficiary_id,
asset_amount_to_send,
ah_assets,
Some(asset_id_on_penpal),
fee_asset_index,
),
};
let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args);
let ah_sender_balance_before = ah_to_penpal.sender.balance;
let penpal_receiver_balance_before = ah_to_penpal.receiver.balance;
let ah_sender_assets_before = AssetHubRococo::execute_with(|| {
type ForeignAssets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_rococo,
&AssetHubRococoSender::get(),
)
});
let penpal_receiver_assets_before = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
});
ah_to_penpal.set_assertion::<AssetHubRococo>(ah_to_penpal_foreign_assets_sender_assertions);
ah_to_penpal.set_assertion::<PenpalA>(ah_to_penpal_foreign_assets_receiver_assertions);
ah_to_penpal.set_dispatchable::<AssetHubRococo>(system_para_to_para_transfer_assets);
ah_to_penpal.assert();
let ah_sender_balance_after = ah_to_penpal.sender.balance;
let penpal_receiver_balance_after = ah_to_penpal.receiver.balance;
let ah_sender_assets_after = AssetHubRococo::execute_with(|| {
type ForeignAssets = <AssetHubRococo as AssetHubRococoPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_rococo,
&AssetHubRococoSender::get(),
)
});
let penpal_receiver_assets_after = PenpalA::execute_with(|| {
type Assets = <PenpalA as PenpalAPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalAReceiver::get())
});
// Sender's balance is reduced
assert!(ah_sender_balance_after < ah_sender_balance_before);
// Receiver's balance is increased
assert!(penpal_receiver_balance_after > penpal_receiver_balance_before);
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
// should be non-zero
assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send);
// Sender's balance is reduced by exact amount
assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after);
// Receiver's balance is increased by exact amount
assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send);
}
@@ -38,5 +38,4 @@ asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" }
cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" }
cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" }
emulated-integration-tests-common = { path = "../../../common", default-features = false }
penpal-runtime = { path = "../../../../../runtimes/testing/penpal" }
westend-system-emulated-network = { path = "../../../networks/westend-system" }
@@ -19,3 +19,11 @@ mod set_xcm_versions;
mod swap;
mod teleport;
mod treasury;
use crate::*;
emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!(
PenpalB,
AssetHubWestend,
WESTEND_ED,
parachains_common::westend::fee::WeightToFee
);
@@ -15,8 +15,8 @@
use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig;
use penpal_runtime::xcm_config::XcmConfig as PenpalWestendXcmConfig;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
use westend_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalWestendXcmConfig;
fn relay_to_para_sender_assertions(t: RelayToParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
@@ -162,7 +162,7 @@ fn system_para_to_para_assets_receiver_assertions<Test>(_: Test) {
);
}
fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult {
fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult {
<Westend as WestendPallet>::XcmPallet::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -173,7 +173,7 @@ fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> Dispatch
)
}
fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -184,7 +184,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest)
)
}
fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalB as PenpalBPallet>::PolkadotXcm::limited_reserve_transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
@@ -284,7 +284,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() {
test.set_assertion::<Westend>(relay_to_para_sender_assertions);
test.set_assertion::<PenpalB>(para_receiver_assertions);
test.set_dispatchable::<Westend>(relay_to_para_limited_reserve_transfer_assets);
test.set_dispatchable::<Westend>(relay_to_para_reserve_transfer_assets);
test.assert();
let delivery_fees = Westend::execute_with(|| {
@@ -328,7 +328,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() {
test.set_assertion::<AssetHubWestend>(system_para_to_para_sender_assertions);
test.set_assertion::<PenpalB>(para_receiver_assertions);
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();
let sender_balance_after = test.sender.balance;
@@ -379,7 +379,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() {
test.set_assertion::<PenpalB>(para_to_system_para_sender_assertions);
test.set_assertion::<AssetHubWestend>(para_to_system_para_receiver_assertions);
test.set_dispatchable::<PenpalB>(para_to_system_para_limited_reserve_transfer_assets);
test.set_dispatchable::<PenpalB>(para_to_system_para_reserve_transfer_assets);
test.assert();
let sender_balance_after = test.sender.balance;
@@ -474,7 +474,7 @@ fn reserve_transfer_assets_from_system_para_to_para() {
test.set_assertion::<AssetHubWestend>(system_para_to_para_assets_sender_assertions);
test.set_assertion::<PenpalB>(system_para_to_para_assets_receiver_assertions);
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();
let sender_balance_after = test.sender.balance;
@@ -14,6 +14,7 @@
// limitations under the License.
use crate::*;
use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub;
#[test]
fn swap_locally_on_chain_using_local_assets() {
@@ -107,113 +108,37 @@ fn swap_locally_on_chain_using_local_assets() {
#[test]
fn swap_locally_on_chain_using_foreign_assets() {
use frame_support::weights::WeightToFee;
let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get());
let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get();
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalBSender::get();
let foreign_asset_at_asset_hub_westend =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) }
.appended_with(asset_location_on_penpal)
.unwrap();
let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation {
parents: 1,
interior: X3(
Parachain(PenpalB::para_id().into()),
PalletInstance(ASSETS_PALLET_ID),
GeneralIndex(ASSET_ID.into()),
),
});
let assets_para_destination: VersionedMultiLocation =
MultiLocation { parents: 1, interior: X1(Parachain(AssetHubWestend::para_id().into())) }
.into();
let penpal_location =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) };
// 1. Create asset on penpal:
PenpalB::execute_with(|| {
assert_ok!(<PenpalB as PenpalBPallet>::Assets::create(
<PenpalB as Chain>::RuntimeOrigin::signed(PenpalBSender::get()),
ASSET_ID.into(),
PenpalBSender::get().into(),
1000,
));
assert!(<PenpalB as PenpalBPallet>::Assets::asset_exists(ASSET_ID));
});
// 2. Create foreign asset on asset_hub_westend:
let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000);
let origin_kind = OriginKind::Xcm;
let sov_penpal_on_asset_hub_westend = AssetHubWestend::sovereign_account_id_of(penpal_location);
// 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_westend
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_westend,
ah_as_seen_by_penpal,
true,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id());
let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah);
AssetHubWestend::fund_accounts(vec![
(AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED),
(sov_penpal_on_asset_hub_westend.clone().into(), 1000_000_000_000_000_000 * WESTEND_ED),
(AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), /* An account to swap dot
* for something else. */
]);
let sov_penpal_on_asset_hub_westend_as_location: MultiLocation = MultiLocation {
parents: 0,
interior: X1(AccountId32Junction {
network: None,
id: sov_penpal_on_asset_hub_westend.clone().into(),
}),
};
let call_foreign_assets_create =
<AssetHubWestend as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::<
<AssetHubWestend as Chain>::Runtime,
Instance2,
>::create {
id: *foreign_asset1_at_asset_hub_westend,
min_balance: 1000,
admin: sov_penpal_on_asset_hub_westend.clone().into(),
})
.encode()
.into();
let buy_execution_fee_amount = parachains_common::westend::fee::WeightToFee::weight_to_fee(
&Weight::from_parts(10_100_000_000_000, 300_000),
);
let buy_execution_fee = MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(buy_execution_fee_amount),
};
let xcm = VersionedXcm::from(Xcm(vec![
WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() },
BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create },
RefundSurplus,
DepositAsset {
assets: All.into(),
beneficiary: sov_penpal_on_asset_hub_westend_as_location,
},
]));
// Send XCM message from penpal => asset_hub_westend
let sudo_penpal_origin = <PenpalB as Chain>::RuntimeOrigin::root();
PenpalB::execute_with(|| {
assert_ok!(<PenpalB as PenpalBPallet>::PolkadotXcm::send(
sudo_penpal_origin.clone(),
bx!(assets_para_destination.clone()),
bx!(xcm),
));
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
assert_expected_events!(
PenpalB,
vec![
RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
]
);
});
// Receive XCM message in Assets Parachain in the next block.
AssetHubWestend::execute_with(|| {
assert!(<AssetHubWestend as AssetHubWestendPallet>::ForeignAssets::asset_exists(
*foreign_asset1_at_asset_hub_westend
));
// 3: Mint foreign asset on asset_hub_westend:
//
// (While it might be nice to use batch,
@@ -222,11 +147,9 @@ fn swap_locally_on_chain_using_foreign_assets() {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
// 3. Mint foreign asset (in reality this should be a teleport or some such)
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::ForeignAssets::mint(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_westend.clone().into()
),
*foreign_asset1_at_asset_hub_westend,
sov_penpal_on_asset_hub_westend.clone().into(),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone().into()),
foreign_asset_at_asset_hub_westend,
sov_penpal_on_ahw.clone().into(),
3_000_000_000_000,
));
@@ -237,11 +160,12 @@ fn swap_locally_on_chain_using_foreign_assets() {
]
);
let foreign_asset_at_asset_hub_westend = Box::new(foreign_asset_at_asset_hub_westend);
// 4. Create pool:
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
asset_native.clone(),
foreign_asset1_at_asset_hub_westend.clone(),
foreign_asset_at_asset_hub_westend.clone(),
));
assert_expected_events!(
@@ -253,16 +177,14 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 5. Add liquidity:
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_westend.clone()
),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()),
asset_native.clone(),
foreign_asset1_at_asset_hub_westend.clone(),
foreign_asset_at_asset_hub_westend.clone(),
1_000_000_000_000,
2_000_000_000_000,
0,
0,
sov_penpal_on_asset_hub_westend.clone().into()
sov_penpal_on_ahw.clone().into()
));
assert_expected_events!(
@@ -277,7 +199,7 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 6. Swap!
let path = BoundedVec::<_, _>::truncate_from(vec![
asset_native.clone(),
foreign_asset1_at_asset_hub_westend.clone(),
foreign_asset_at_asset_hub_westend.clone(),
]);
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::swap_exact_tokens_for_tokens(
@@ -301,15 +223,13 @@ fn swap_locally_on_chain_using_foreign_assets() {
// 7. Remove liquidity
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::remove_liquidity(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(
sov_penpal_on_asset_hub_westend.clone()
),
<AssetHubWestend as Chain>::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()),
asset_native,
foreign_asset1_at_asset_hub_westend,
foreign_asset_at_asset_hub_westend,
1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved.
0,
0,
sov_penpal_on_asset_hub_westend.clone().into(),
sov_penpal_on_ahw.clone().into(),
));
});
}
@@ -15,7 +15,9 @@
use crate::*;
use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig;
use emulated_integration_tests_common::xcm_helpers::non_fee_asset;
use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig;
use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub;
fn relay_origin_assertions(t: RelayToSystemParaTest) {
type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
@@ -110,6 +112,123 @@ fn para_dest_assertions(t: RelayToSystemParaTest) {
);
}
fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
PenpalB::assert_xcm_pallet_attempted_complete(None);
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
PenpalB,
vec![
RuntimeEvent::Balances(
pallet_balances::Event::Withdraw { who, amount }
) => {
who: *who == t.sender.account_id,
amount: *amount == t.args.amount,
},
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == t.sender.account_id,
balance: *balance == expected_asset_amount,
},
]
);
}
fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of(
AssetHubWestend::sibling_location_of(PenpalB::para_id()),
);
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
AssetHubWestend,
vec![
// native asset reserve transfer for paying fees, withdrawn from Penpal's sov 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 { who, .. }) => {
who: *who == t.receiver.account_id,
},
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => {
asset_id: *asset_id == expected_foreign_asset_id,
owner: *owner == t.receiver.account_id,
amount: *amount == expected_foreign_asset_amount,
},
RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
AssetHubWestend::assert_xcm_pallet_attempted_complete(None);
let (expected_foreign_asset_id, expected_foreign_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
assert_expected_events!(
AssetHubWestend,
vec![
// native asset used for fees is transferred to Parachain's Sovereign account as reserve
RuntimeEvent::Balances(
pallet_balances::Event::Transfer { from, to, amount }
) => {
from: *from == t.sender.account_id,
to: *to == AssetHubWestend::sovereign_account_id_of(
t.args.dest
),
amount: *amount == t.args.amount,
},
// foreign asset is burned locally as part of teleportation
RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_foreign_asset_id,
owner: *owner == t.sender.account_id,
balance: *balance == expected_foreign_asset_amount,
},
]
);
}
fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) {
type RuntimeEvent = <PenpalB as Chain>::RuntimeEvent;
let expected_asset_id = t.args.asset_id.unwrap();
let (_, expected_asset_amount) =
non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap();
let checking_account = <PenpalB as PenpalBPallet>::PolkadotXcm::check_account();
assert_expected_events!(
PenpalB,
vec![
// checking account burns local asset as part of incoming teleport
RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == checking_account,
balance: *balance == expected_asset_amount,
},
// local asset is teleported into account of receiver
RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => {
asset_id: *asset_id == expected_asset_id,
owner: *owner == t.receiver.account_id,
amount: *amount == expected_asset_amount,
},
// native asset for fee is deposited to receiver
RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => {
who: *who == t.receiver.account_id,
},
RuntimeEvent::MessageQueue(
pallet_message_queue::Event::Processed { success: true, .. }
) => {},
]
);
}
fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult {
<Westend as WestendPallet>::XcmPallet::limited_teleport_assets(
t.signed_origin,
@@ -152,6 +271,28 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult {
)
}
fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult {
<AssetHubWestend as AssetHubWestendPallet>::PolkadotXcm::transfer_assets(
t.signed_origin,
bx!(t.args.dest.into()),
bx!(t.args.beneficiary.into()),
bx!(t.args.assets.into()),
t.args.fee_asset_item,
t.args.weight_limit,
)
}
fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult {
<PenpalB as PenpalBPallet>::PolkadotXcm::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,
)
}
/// Limited Teleport of native asset from Relay Chain to the System Parachain should work
#[test]
fn limited_teleport_native_assets_from_relay_to_system_para_works() {
@@ -410,3 +551,199 @@ fn teleport_to_other_system_parachains_works() {
(native_asset, amount)
);
}
/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work
/// (using native reserve-based transfer for fees)
#[test]
fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() {
let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id());
let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get();
let asset_id_on_penpal = match asset_location_on_penpal.last() {
Some(GeneralIndex(id)) => *id as u32,
_ => unreachable!(),
};
let asset_owner_on_penpal = PenpalBSender::get();
let foreign_asset_at_asset_hub_westend =
MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) }
.appended_with(asset_location_on_penpal)
.unwrap();
super::penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal,
foreign_asset_at_asset_hub_westend,
ah_as_seen_by_penpal,
false,
asset_owner_on_penpal,
ASSET_MIN_BALANCE * 1_000_000,
);
let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get();
let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000;
let asset_amount_to_send = ASSET_MIN_BALANCE * 1000;
let penpal_assets: MultiAssets = vec![
(Parent, fee_amount_to_send).into(),
(asset_location_on_penpal, asset_amount_to_send).into(),
]
.into();
let fee_asset_index = penpal_assets
.inner()
.iter()
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
// Penpal to AH test args
let penpal_to_ah_test_args = TestContext {
sender: PenpalBSender::get(),
receiver: AssetHubWestendReceiver::get(),
args: para_test_args(
ah_as_seen_by_penpal,
penpal_to_ah_beneficiary_id,
asset_amount_to_send,
penpal_assets,
Some(asset_id_on_penpal),
fee_asset_index,
),
};
let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args);
let penpal_sender_balance_before = penpal_to_ah.sender.balance;
let ah_receiver_balance_before = penpal_to_ah.receiver.balance;
let penpal_sender_assets_before = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBSender::get())
});
let ah_receiver_assets_before = AssetHubWestend::execute_with(|| {
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_westend,
&AssetHubWestendReceiver::get(),
)
});
penpal_to_ah.set_assertion::<PenpalB>(penpal_to_ah_foreign_assets_sender_assertions);
penpal_to_ah.set_assertion::<AssetHubWestend>(penpal_to_ah_foreign_assets_receiver_assertions);
penpal_to_ah.set_dispatchable::<PenpalB>(para_to_system_para_transfer_assets);
penpal_to_ah.assert();
let penpal_sender_balance_after = penpal_to_ah.sender.balance;
let ah_receiver_balance_after = penpal_to_ah.receiver.balance;
let penpal_sender_assets_after = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBSender::get())
});
let ah_receiver_assets_after = AssetHubWestend::execute_with(|| {
type Assets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
<Assets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_westend,
&AssetHubWestendReceiver::get(),
)
});
// Sender's balance is reduced
assert!(penpal_sender_balance_after < penpal_sender_balance_before);
// Receiver's balance is increased
assert!(ah_receiver_balance_after > ah_receiver_balance_before);
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
// should be non-zero
assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send);
// Sender's balance is reduced by exact amount
assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after);
// Receiver's balance is increased by exact amount
assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send);
///////////////////////////////////////////////////////////////////////
// Now test transferring foreign assets back from AssetHub to Penpal //
///////////////////////////////////////////////////////////////////////
// Move funds on AH from AHReceiver to AHSender
AssetHubWestend::execute_with(|| {
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
assert_ok!(ForeignAssets::transfer(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendReceiver::get()),
foreign_asset_at_asset_hub_westend,
AssetHubWestendSender::get().into(),
asset_amount_to_send,
));
});
let ah_to_penpal_beneficiary_id = PenpalBReceiver::get();
let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id());
let ah_assets: MultiAssets = vec![
(Parent, fee_amount_to_send).into(),
(foreign_asset_at_asset_hub_westend, asset_amount_to_send).into(),
]
.into();
let fee_asset_index = ah_assets
.inner()
.iter()
.position(|r| r == &(Parent, fee_amount_to_send).into())
.unwrap() as u32;
// AH to Penpal test args
let ah_to_penpal_test_args = TestContext {
sender: AssetHubWestendSender::get(),
receiver: PenpalBReceiver::get(),
args: para_test_args(
penpal_as_seen_by_ah,
ah_to_penpal_beneficiary_id,
asset_amount_to_send,
ah_assets,
Some(asset_id_on_penpal),
fee_asset_index,
),
};
let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args);
let ah_sender_balance_before = ah_to_penpal.sender.balance;
let penpal_receiver_balance_before = ah_to_penpal.receiver.balance;
let ah_sender_assets_before = AssetHubWestend::execute_with(|| {
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_westend,
&AssetHubWestendSender::get(),
)
});
let penpal_receiver_assets_before = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBReceiver::get())
});
ah_to_penpal.set_assertion::<AssetHubWestend>(ah_to_penpal_foreign_assets_sender_assertions);
ah_to_penpal.set_assertion::<PenpalB>(ah_to_penpal_foreign_assets_receiver_assertions);
ah_to_penpal.set_dispatchable::<AssetHubWestend>(system_para_to_para_transfer_assets);
ah_to_penpal.assert();
let ah_sender_balance_after = ah_to_penpal.sender.balance;
let penpal_receiver_balance_after = ah_to_penpal.receiver.balance;
let ah_sender_assets_after = AssetHubWestend::execute_with(|| {
type ForeignAssets = <AssetHubWestend as AssetHubWestendPallet>::ForeignAssets;
<ForeignAssets as Inspect<_>>::balance(
foreign_asset_at_asset_hub_westend,
&AssetHubWestendSender::get(),
)
});
let penpal_receiver_assets_after = PenpalB::execute_with(|| {
type Assets = <PenpalB as PenpalBPallet>::Assets;
<Assets as Inspect<_>>::balance(asset_id_on_penpal, &PenpalBReceiver::get())
});
// Sender's balance is reduced
assert!(ah_sender_balance_after < ah_sender_balance_before);
// Receiver's balance is increased
assert!(penpal_receiver_balance_after > penpal_receiver_balance_before);
// Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`;
// `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but
// should be non-zero
assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send);
// Sender's balance is reduced by exact amount
assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after);
// Receiver's balance is increased by exact amount
assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send);
}
@@ -1359,6 +1359,55 @@ impl_runtime_apis! {
ParentThen(Parachain(random_para_id).into()).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Transfer to Relay some local AH asset (local-reserve-transfer) while paying
// fees using teleported native token.
// (We don't care that Relay doesn't accept incoming unknown AH local asset)
let dest = Parent.into();
let fee_amount = EXISTENTIAL_DEPOSIT;
let fee_asset: MultiAsset = (MultiLocation::parent(), fee_amount).into();
let who = frame_benchmarking::whitelisted_caller();
// Give some multiple of the existential deposit
let balance = fee_amount + EXISTENTIAL_DEPOSIT * 1000;
let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
&who, balance,
);
// verify initial balance
assert_eq!(Balances::free_balance(&who), balance);
// set up local asset
let asset_amount = 10u128;
let initial_asset_amount = asset_amount * 10;
let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::<
Runtime,
pallet_assets::Instance1
>(true, initial_asset_amount);
let asset_location = MultiLocation::new(
0,
X2(PalletInstance(50), GeneralIndex(u32::from(asset_id).into()))
);
let transfer_asset: MultiAsset = (asset_location, asset_amount).into();
let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset].into();
let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 };
// verify transferred successfully
let verify = Box::new(move || {
// verify native balance after transfer, decreased by transferred fee amount
// (plus transport fees)
assert!(Balances::free_balance(&who) <= balance - fee_amount);
// verify asset balance decreased by exactly transferred amount
assert_eq!(
Assets::balance(asset_id.into(), &who),
initial_asset_amount - asset_amount,
);
});
Some((assets, fee_index as u32, dest, verify))
}
}
impl XcmBridgeHubRouterConfig<ToWestendXcmRouterInstance> for Runtime {
@@ -17,9 +17,9 @@
//! Autogenerated weights for `pallet_xcm`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024
// Executed Command:
@@ -64,37 +64,95 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 24_498_000 picoseconds.
Weight::from_parts(25_385_000, 0)
// Minimum execution time: 25_003_000 picoseconds.
Weight::from_parts(25_800_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn teleport_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `39`
// Estimated: `3504`
// Minimum execution time: 19_746_000 picoseconds.
Weight::from_parts(20_535_000, 0)
.saturating_add(Weight::from_parts(0, 3504))
.saturating_add(T::DbWeight::get().reads(2))
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 88_832_000 picoseconds.
Weight::from_parts(90_491_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0)
/// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0)
/// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1)
/// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn reserve_transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `39`
// Estimated: `3504`
// Minimum execution time: 15_059_000 picoseconds.
Weight::from_parts(15_386_000, 0)
.saturating_add(Weight::from_parts(0, 3504))
.saturating_add(T::DbWeight::get().reads(2))
// Measured: `400`
// Estimated: `6196`
// Minimum execution time: 138_911_000 picoseconds.
Weight::from_parts(142_483_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(T::DbWeight::get().reads(9))
.saturating_add(T::DbWeight::get().writes(5))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `Assets::Asset` (r:1 w:1)
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
/// Storage: `Assets::Account` (r:2 w:2)
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `496`
// Estimated: `6208`
// Minimum execution time: 146_932_000 picoseconds.
Weight::from_parts(153_200_000, 0)
.saturating_add(Weight::from_parts(0, 6208))
.saturating_add(T::DbWeight::get().reads(12))
.saturating_add(T::DbWeight::get().writes(7))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -112,8 +170,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 7_108_000 picoseconds.
Weight::from_parts(7_458_000, 0)
// Minimum execution time: 7_081_000 picoseconds.
Weight::from_parts(7_397_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -123,8 +181,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_205_000 picoseconds.
Weight::from_parts(2_360_000, 0)
// Minimum execution time: 2_007_000 picoseconds.
Weight::from_parts(2_183_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -150,8 +208,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 29_099_000 picoseconds.
Weight::from_parts(29_580_000, 0)
// Minimum execution time: 28_790_000 picoseconds.
Weight::from_parts(29_767_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(5))
@@ -176,8 +234,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `363`
// Estimated: `3828`
// Minimum execution time: 31_161_000 picoseconds.
Weight::from_parts(31_933_000, 0)
// Minimum execution time: 30_951_000 picoseconds.
Weight::from_parts(31_804_000, 0)
.saturating_add(Weight::from_parts(0, 3828))
.saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(4))
@@ -188,8 +246,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_158_000 picoseconds.
Weight::from_parts(2_316_000, 0)
// Minimum execution time: 2_164_000 picoseconds.
Weight::from_parts(2_311_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -199,8 +257,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `162`
// Estimated: `11052`
// Minimum execution time: 16_934_000 picoseconds.
Weight::from_parts(17_655_000, 0)
// Minimum execution time: 16_906_000 picoseconds.
Weight::from_parts(17_612_000, 0)
.saturating_add(Weight::from_parts(0, 11052))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -211,8 +269,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `166`
// Estimated: `11056`
// Minimum execution time: 17_658_000 picoseconds.
Weight::from_parts(17_973_000, 0)
// Minimum execution time: 17_443_000 picoseconds.
Weight::from_parts(18_032_000, 0)
.saturating_add(Weight::from_parts(0, 11056))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -223,8 +281,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `13538`
// Minimum execution time: 18_673_000 picoseconds.
Weight::from_parts(19_027_000, 0)
// Minimum execution time: 18_992_000 picoseconds.
Weight::from_parts(19_464_000, 0)
.saturating_add(Weight::from_parts(0, 13538))
.saturating_add(T::DbWeight::get().reads(5))
}
@@ -246,8 +304,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `212`
// Estimated: `6152`
// Minimum execution time: 27_171_000 picoseconds.
Weight::from_parts(27_802_000, 0)
// Minimum execution time: 28_011_000 picoseconds.
Weight::from_parts(28_716_000, 0)
.saturating_add(Weight::from_parts(0, 6152))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
@@ -258,8 +316,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `206`
// Estimated: `8621`
// Minimum execution time: 9_423_000 picoseconds.
Weight::from_parts(9_636_000, 0)
// Minimum execution time: 9_533_000 picoseconds.
Weight::from_parts(9_856_000, 0)
.saturating_add(Weight::from_parts(0, 8621))
.saturating_add(T::DbWeight::get().reads(3))
}
@@ -269,8 +327,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `11063`
// Minimum execution time: 17_442_000 picoseconds.
Weight::from_parts(17_941_000, 0)
// Minimum execution time: 17_628_000 picoseconds.
Weight::from_parts(18_146_000, 0)
.saturating_add(Weight::from_parts(0, 11063))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -293,8 +351,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `215`
// Estimated: `11105`
// Minimum execution time: 34_340_000 picoseconds.
Weight::from_parts(34_934_000, 0)
// Minimum execution time: 34_877_000 picoseconds.
Weight::from_parts(35_607_000, 0)
.saturating_add(Weight::from_parts(0, 11105))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4))
@@ -307,8 +365,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `103`
// Estimated: `1588`
// Minimum execution time: 5_496_000 picoseconds.
Weight::from_parts(5_652_000, 0)
// Minimum execution time: 5_370_000 picoseconds.
Weight::from_parts(5_616_000, 0)
.saturating_add(Weight::from_parts(0, 1588))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(2))
@@ -319,8 +377,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `7740`
// Estimated: `11205`
// Minimum execution time: 26_140_000 picoseconds.
Weight::from_parts(26_824_000, 0)
// Minimum execution time: 26_820_000 picoseconds.
Weight::from_parts(27_143_000, 0)
.saturating_add(Weight::from_parts(0, 11205))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
@@ -1431,6 +1431,55 @@ impl_runtime_apis! {
ParentThen(Parachain(random_para_id).into()).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Transfer to Relay some local AH asset (local-reserve-transfer) while paying
// fees using teleported native token.
// (We don't care that Relay doesn't accept incoming unknown AH local asset)
let dest = Parent.into();
let fee_amount = EXISTENTIAL_DEPOSIT;
let fee_asset: MultiAsset = (MultiLocation::parent(), fee_amount).into();
let who = frame_benchmarking::whitelisted_caller();
// Give some multiple of the existential deposit
let balance = fee_amount + EXISTENTIAL_DEPOSIT * 1000;
let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
&who, balance,
);
// verify initial balance
assert_eq!(Balances::free_balance(&who), balance);
// set up local asset
let asset_amount = 10u128;
let initial_asset_amount = asset_amount * 10;
let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::<
Runtime,
pallet_assets::Instance1
>(true, initial_asset_amount);
let asset_location = MultiLocation::new(
0,
X2(PalletInstance(50), GeneralIndex(u32::from(asset_id).into()))
);
let transfer_asset: MultiAsset = (asset_location, asset_amount).into();
let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset].into();
let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 };
// verify transferred successfully
let verify = Box::new(move || {
// verify native balance after transfer, decreased by transferred fee amount
// (plus transport fees)
assert!(Balances::free_balance(&who) <= balance - fee_amount);
// verify asset balance decreased by exactly transferred amount
assert_eq!(
Assets::balance(asset_id.into(), &who),
initial_asset_amount - asset_amount,
);
});
Some((assets, fee_index as u32, dest, verify))
}
}
use pallet_xcm_bridge_hub_router::benchmarking::{
@@ -17,9 +17,9 @@
//! Autogenerated weights for `pallet_xcm`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024
// Executed Command:
@@ -64,40 +64,102 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 25_534_000 picoseconds.
Weight::from_parts(26_413_000, 0)
// Minimum execution time: 25_482_000 picoseconds.
Weight::from_parts(26_622_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn teleport_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `1489`
// Minimum execution time: 20_513_000 picoseconds.
Weight::from_parts(20_837_000, 0)
.saturating_add(Weight::from_parts(0, 1489))
.saturating_add(T::DbWeight::get().reads(1))
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 87_319_000 picoseconds.
Weight::from_parts(89_764_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0)
/// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0)
/// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1)
/// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1)
/// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn reserve_transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `1489`
// Minimum execution time: 14_977_000 picoseconds.
Weight::from_parts(15_207_000, 0)
.saturating_add(Weight::from_parts(0, 1489))
.saturating_add(T::DbWeight::get().reads(1))
// Measured: `367`
// Estimated: `6196`
// Minimum execution time: 139_133_000 picoseconds.
Weight::from_parts(141_507_000, 0)
.saturating_add(Weight::from_parts(0, 6196))
.saturating_add(T::DbWeight::get().reads(9))
.saturating_add(T::DbWeight::get().writes(5))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `Assets::Asset` (r:1 w:1)
/// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`)
/// Storage: `Assets::Account` (r:2 w:2)
/// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`)
/// Storage: `System::Account` (r:2 w:2)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `496`
// Estimated: `6208`
// Minimum execution time: 144_241_000 picoseconds.
Weight::from_parts(149_709_000, 0)
.saturating_add(Weight::from_parts(0, 6208))
.saturating_add(T::DbWeight::get().reads(12))
.saturating_add(T::DbWeight::get().writes(7))
}
fn execute() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 7_440_000 picoseconds.
Weight::from_parts(7_651_000, 0)
// Minimum execution time: 10_392_000 picoseconds.
Weight::from_parts(10_779_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1)
@@ -106,8 +168,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 7_253_000 picoseconds.
Weight::from_parts(7_584_000, 0)
// Minimum execution time: 7_088_000 picoseconds.
Weight::from_parts(7_257_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -117,8 +179,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_299_000 picoseconds.
Weight::from_parts(2_435_000, 0)
// Minimum execution time: 2_095_000 picoseconds.
Weight::from_parts(2_136_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -144,8 +206,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 29_440_000 picoseconds.
Weight::from_parts(30_675_000, 0)
// Minimum execution time: 28_728_000 picoseconds.
Weight::from_parts(29_349_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(5))
@@ -170,8 +232,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `363`
// Estimated: `3828`
// Minimum execution time: 31_876_000 picoseconds.
Weight::from_parts(32_588_000, 0)
// Minimum execution time: 30_605_000 picoseconds.
Weight::from_parts(31_477_000, 0)
.saturating_add(Weight::from_parts(0, 3828))
.saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(4))
@@ -182,8 +244,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_385_000 picoseconds.
Weight::from_parts(2_607_000, 0)
// Minimum execution time: 2_137_000 picoseconds.
Weight::from_parts(2_303_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -193,8 +255,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `162`
// Estimated: `11052`
// Minimum execution time: 16_927_000 picoseconds.
Weight::from_parts(17_554_000, 0)
// Minimum execution time: 16_719_000 picoseconds.
Weight::from_parts(17_329_000, 0)
.saturating_add(Weight::from_parts(0, 11052))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -205,8 +267,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `166`
// Estimated: `11056`
// Minimum execution time: 16_965_000 picoseconds.
Weight::from_parts(17_807_000, 0)
// Minimum execution time: 16_687_000 picoseconds.
Weight::from_parts(17_405_000, 0)
.saturating_add(Weight::from_parts(0, 11056))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -217,8 +279,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `13538`
// Minimum execution time: 18_763_000 picoseconds.
Weight::from_parts(19_359_000, 0)
// Minimum execution time: 18_751_000 picoseconds.
Weight::from_parts(19_130_000, 0)
.saturating_add(Weight::from_parts(0, 13538))
.saturating_add(T::DbWeight::get().reads(5))
}
@@ -240,8 +302,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `212`
// Estimated: `6152`
// Minimum execution time: 27_371_000 picoseconds.
Weight::from_parts(28_185_000, 0)
// Minimum execution time: 27_189_000 picoseconds.
Weight::from_parts(27_760_000, 0)
.saturating_add(Weight::from_parts(0, 6152))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
@@ -252,8 +314,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `206`
// Estimated: `8621`
// Minimum execution time: 9_165_000 picoseconds.
Weight::from_parts(9_539_000, 0)
// Minimum execution time: 9_307_000 picoseconds.
Weight::from_parts(9_691_000, 0)
.saturating_add(Weight::from_parts(0, 8621))
.saturating_add(T::DbWeight::get().reads(3))
}
@@ -263,8 +325,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `11063`
// Minimum execution time: 17_384_000 picoseconds.
Weight::from_parts(17_777_000, 0)
// Minimum execution time: 17_607_000 picoseconds.
Weight::from_parts(18_090_000, 0)
.saturating_add(Weight::from_parts(0, 11063))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -287,8 +349,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `215`
// Estimated: `11105`
// Minimum execution time: 34_260_000 picoseconds.
Weight::from_parts(35_428_000, 0)
// Minimum execution time: 34_322_000 picoseconds.
Weight::from_parts(35_754_000, 0)
.saturating_add(Weight::from_parts(0, 11105))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4))
@@ -301,8 +363,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `103`
// Estimated: `1588`
// Minimum execution time: 4_710_000 picoseconds.
Weight::from_parts(4_900_000, 0)
// Minimum execution time: 4_513_000 picoseconds.
Weight::from_parts(4_754_000, 0)
.saturating_add(Weight::from_parts(0, 1588))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(2))
@@ -313,8 +375,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `7740`
// Estimated: `11205`
// Minimum execution time: 26_843_000 picoseconds.
Weight::from_parts(27_404_000, 0)
// Minimum execution time: 27_860_000 picoseconds.
Weight::from_parts(28_279_000, 0)
.saturating_add(Weight::from_parts(0, 11205))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
@@ -823,6 +823,18 @@ impl_runtime_apis! {
// Reserve transfers are disabled on BH.
None
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// BH only supports teleports to system parachain.
// Relay/native token can be teleported between BH and Relay.
let native_location = Parent.into();
let dest = Parent.into();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
use xcm::latest::prelude::*;
@@ -17,9 +17,9 @@
//! Autogenerated weights for `pallet_xcm`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024
// Executed Command:
@@ -62,26 +62,39 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn send() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `3540`
// Minimum execution time: 24_179_000 picoseconds.
Weight::from_parts(24_684_000, 0)
.saturating_add(Weight::from_parts(0, 3540))
// Measured: `38`
// Estimated: `3503`
// Minimum execution time: 23_683_000 picoseconds.
Weight::from_parts(24_199_000, 0)
.saturating_add(Weight::from_parts(0, 3503))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0)
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn teleport_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `38`
// Estimated: `3503`
// Minimum execution time: 21_093_000 picoseconds.
Weight::from_parts(21_523_000, 0)
.saturating_add(Weight::from_parts(0, 3503))
.saturating_add(T::DbWeight::get().reads(2))
// Measured: `70`
// Estimated: `3593`
// Minimum execution time: 89_524_000 picoseconds.
Weight::from_parts(91_401_000, 0)
.saturating_add(Weight::from_parts(0, 3593))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -93,6 +106,32 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
Weight::from_parts(18_446_744_073_709_551_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `70`
// Estimated: `3593`
// Minimum execution time: 91_890_000 picoseconds.
Weight::from_parts(93_460_000, 0)
.saturating_add(Weight::from_parts(0, 3593))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn execute() -> Weight {
@@ -109,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 6_938_000 picoseconds.
Weight::from_parts(7_243_000, 0)
// Minimum execution time: 7_152_000 picoseconds.
Weight::from_parts(7_355_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -120,8 +159,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_159_000 picoseconds.
Weight::from_parts(2_290_000, 0)
// Minimum execution time: 2_081_000 picoseconds.
Weight::from_parts(2_258_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -145,11 +184,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn force_subscribe_version_notify() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `3540`
// Minimum execution time: 28_337_000 picoseconds.
Weight::from_parts(29_265_000, 0)
.saturating_add(Weight::from_parts(0, 3540))
// Measured: `38`
// Estimated: `3503`
// Minimum execution time: 28_067_000 picoseconds.
Weight::from_parts(28_693_000, 0)
.saturating_add(Weight::from_parts(0, 3503))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(5))
}
@@ -171,11 +210,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn force_unsubscribe_version_notify() -> Weight {
// Proof Size summary in bytes:
// Measured: `292`
// Estimated: `3757`
// Minimum execution time: 30_599_000 picoseconds.
Weight::from_parts(31_272_000, 0)
.saturating_add(Weight::from_parts(0, 3757))
// Measured: `255`
// Estimated: `3720`
// Minimum execution time: 30_420_000 picoseconds.
Weight::from_parts(31_373_000, 0)
.saturating_add(Weight::from_parts(0, 3720))
.saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(4))
}
@@ -185,8 +224,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_132_000 picoseconds.
Weight::from_parts(2_280_000, 0)
// Minimum execution time: 2_087_000 picoseconds.
Weight::from_parts(2_243_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -194,11 +233,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_supported_version() -> Weight {
// Proof Size summary in bytes:
// Measured: `187`
// Estimated: `11077`
// Minimum execution time: 18_262_000 picoseconds.
Weight::from_parts(18_640_000, 0)
.saturating_add(Weight::from_parts(0, 11077))
// Measured: `95`
// Estimated: `10985`
// Minimum execution time: 15_142_000 picoseconds.
Weight::from_parts(15_598_000, 0)
.saturating_add(Weight::from_parts(0, 10985))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -206,11 +245,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_version_notifiers() -> Weight {
// Proof Size summary in bytes:
// Measured: `191`
// Estimated: `11081`
// Minimum execution time: 18_512_000 picoseconds.
Weight::from_parts(18_888_000, 0)
.saturating_add(Weight::from_parts(0, 11081))
// Measured: `99`
// Estimated: `10989`
// Minimum execution time: 15_041_000 picoseconds.
Weight::from_parts(15_493_000, 0)
.saturating_add(Weight::from_parts(0, 10989))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -218,11 +257,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn already_notified_target() -> Weight {
// Proof Size summary in bytes:
// Measured: `198`
// Estimated: `13563`
// Minimum execution time: 19_362_000 picoseconds.
Weight::from_parts(20_056_000, 0)
.saturating_add(Weight::from_parts(0, 13563))
// Measured: `106`
// Estimated: `13471`
// Minimum execution time: 16_624_000 picoseconds.
Weight::from_parts(17_031_000, 0)
.saturating_add(Weight::from_parts(0, 13471))
.saturating_add(T::DbWeight::get().reads(5))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1)
@@ -241,11 +280,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn notify_current_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `142`
// Estimated: `6082`
// Minimum execution time: 27_318_000 picoseconds.
Weight::from_parts(28_075_000, 0)
.saturating_add(Weight::from_parts(0, 6082))
// Measured: `106`
// Estimated: `6046`
// Minimum execution time: 26_398_000 picoseconds.
Weight::from_parts(26_847_000, 0)
.saturating_add(Weight::from_parts(0, 6046))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
@@ -253,22 +292,22 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn notify_target_migration_fail() -> Weight {
// Proof Size summary in bytes:
// Measured: `172`
// Estimated: `8587`
// Minimum execution time: 9_930_000 picoseconds.
Weight::from_parts(10_192_000, 0)
.saturating_add(Weight::from_parts(0, 8587))
// Measured: `136`
// Estimated: `8551`
// Minimum execution time: 8_741_000 picoseconds.
Weight::from_parts(8_954_000, 0)
.saturating_add(Weight::from_parts(0, 8551))
.saturating_add(T::DbWeight::get().reads(3))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2)
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_version_notify_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `198`
// Estimated: `11088`
// Minimum execution time: 18_305_000 picoseconds.
Weight::from_parts(18_738_000, 0)
.saturating_add(Weight::from_parts(0, 11088))
// Measured: `106`
// Estimated: `10996`
// Minimum execution time: 15_306_000 picoseconds.
Weight::from_parts(15_760_000, 0)
.saturating_add(Weight::from_parts(0, 10996))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -288,11 +327,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn migrate_and_notify_old_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `204`
// Estimated: `11094`
// Minimum execution time: 34_559_000 picoseconds.
Weight::from_parts(35_241_000, 0)
.saturating_add(Weight::from_parts(0, 11094))
// Measured: `112`
// Estimated: `11002`
// Minimum execution time: 33_127_000 picoseconds.
Weight::from_parts(33_938_000, 0)
.saturating_add(Weight::from_parts(0, 11002))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4))
}
@@ -302,11 +341,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn new_query() -> Weight {
// Proof Size summary in bytes:
// Measured: `69`
// Estimated: `1554`
// Minimum execution time: 4_512_000 picoseconds.
Weight::from_parts(4_671_000, 0)
.saturating_add(Weight::from_parts(0, 1554))
// Measured: `32`
// Estimated: `1517`
// Minimum execution time: 4_290_000 picoseconds.
Weight::from_parts(4_450_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -314,11 +353,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn take_response() -> Weight {
// Proof Size summary in bytes:
// Measured: `7706`
// Estimated: `11171`
// Minimum execution time: 26_473_000 picoseconds.
Weight::from_parts(26_960_000, 0)
.saturating_add(Weight::from_parts(0, 11171))
// Measured: `7669`
// Estimated: `11134`
// Minimum execution time: 26_408_000 picoseconds.
Weight::from_parts(26_900_000, 0)
.saturating_add(Weight::from_parts(0, 11134))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -813,6 +813,18 @@ impl_runtime_apis! {
// Reserve transfers are disabled on BH.
None
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// BH only supports teleports to system parachain.
// Relay/native token can be teleported between BH and Relay.
let native_location = Parent.into();
let dest = Parent.into();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
use xcm::latest::prelude::*;
@@ -17,27 +17,25 @@
//! Autogenerated weights for `pallet_xcm`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024
//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024
// Executed Command:
// ./target/production/polkadot-parachain
// target/production/polkadot-parachain
// benchmark
// pallet
// --chain=bridge-hub-rococo-dev
// --wasm-execution=compiled
// --pallet=pallet_xcm
// --no-storage-info
// --no-median-slopes
// --no-min-squares
// --extrinsic=*
// --steps=50
// --repeat=20
// --json
// --header=./file_header.txt
// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/
// --extrinsic=*
// --wasm-execution=compiled
// --heap-pages=4096
// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
// --pallet=pallet_xcm
// --chain=bridge-hub-westend-dev
// --header=./cumulus/file_header.txt
// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
@@ -50,6 +48,8 @@ use core::marker::PhantomData;
/// Weight functions for `pallet_xcm`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
@@ -62,24 +62,39 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn send() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `3540`
// Minimum execution time: 29_724_000 picoseconds.
Weight::from_parts(30_440_000, 0)
.saturating_add(Weight::from_parts(0, 3540))
.saturating_add(T::DbWeight::get().reads(5))
// Measured: `38`
// Estimated: `3503`
// Minimum execution time: 23_219_000 picoseconds.
Weight::from_parts(23_818_000, 0)
.saturating_add(Weight::from_parts(0, 3503))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn teleport_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1489`
// Minimum execution time: 26_779_000 picoseconds.
Weight::from_parts(27_249_000, 0)
.saturating_add(Weight::from_parts(0, 1489))
.saturating_add(T::DbWeight::get().reads(1))
// Measured: `70`
// Estimated: `3593`
// Minimum execution time: 90_120_000 picoseconds.
Weight::from_parts(92_545_000, 0)
.saturating_add(Weight::from_parts(0, 3593))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -91,6 +106,32 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
Weight::from_parts(18_446_744_073_709_551_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `70`
// Estimated: `3593`
// Minimum execution time: 91_339_000 picoseconds.
Weight::from_parts(93_204_000, 0)
.saturating_add(Weight::from_parts(0, 3593))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn execute() -> Weight {
@@ -107,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 9_170_000 picoseconds.
Weight::from_parts(9_629_000, 0)
// Minimum execution time: 6_976_000 picoseconds.
Weight::from_parts(7_284_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -118,8 +159,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_769_000 picoseconds.
Weight::from_parts(2_933_000, 0)
// Minimum execution time: 2_044_000 picoseconds.
Weight::from_parts(2_223_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -127,6 +168,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1)
/// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
@@ -141,16 +184,18 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn force_subscribe_version_notify() -> Weight {
// Proof Size summary in bytes:
// Measured: `75`
// Estimated: `3540`
// Minimum execution time: 34_547_000 picoseconds.
Weight::from_parts(35_653_000, 0)
.saturating_add(Weight::from_parts(0, 3540))
.saturating_add(T::DbWeight::get().reads(7))
// Measured: `38`
// Estimated: `3503`
// Minimum execution time: 27_778_000 picoseconds.
Weight::from_parts(28_318_000, 0)
.saturating_add(Weight::from_parts(0, 3503))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(5))
}
/// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
@@ -165,12 +210,12 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn force_unsubscribe_version_notify() -> Weight {
// Proof Size summary in bytes:
// Measured: `292`
// Estimated: `3757`
// Minimum execution time: 36_274_000 picoseconds.
Weight::from_parts(37_281_000, 0)
.saturating_add(Weight::from_parts(0, 3757))
.saturating_add(T::DbWeight::get().reads(6))
// Measured: `255`
// Estimated: `3720`
// Minimum execution time: 30_446_000 picoseconds.
Weight::from_parts(31_925_000, 0)
.saturating_add(Weight::from_parts(0, 3720))
.saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1)
@@ -179,8 +224,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_749_000 picoseconds.
Weight::from_parts(2_917_000, 0)
// Minimum execution time: 2_037_000 picoseconds.
Weight::from_parts(2_211_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -188,11 +233,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_supported_version() -> Weight {
// Proof Size summary in bytes:
// Measured: `187`
// Estimated: `11077`
// Minimum execution time: 17_649_000 picoseconds.
Weight::from_parts(17_964_000, 0)
.saturating_add(Weight::from_parts(0, 11077))
// Measured: `95`
// Estimated: `10985`
// Minimum execution time: 15_620_000 picoseconds.
Weight::from_parts(15_984_000, 0)
.saturating_add(Weight::from_parts(0, 10985))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -200,11 +245,11 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_version_notifiers() -> Weight {
// Proof Size summary in bytes:
// Measured: `191`
// Estimated: `11081`
// Minimum execution time: 17_551_000 picoseconds.
Weight::from_parts(18_176_000, 0)
.saturating_add(Weight::from_parts(0, 11081))
// Measured: `99`
// Estimated: `10989`
// Minimum execution time: 15_689_000 picoseconds.
Weight::from_parts(16_093_000, 0)
.saturating_add(Weight::from_parts(0, 10989))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
@@ -212,15 +257,17 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn already_notified_target() -> Weight {
// Proof Size summary in bytes:
// Measured: `198`
// Estimated: `13563`
// Minimum execution time: 19_261_000 picoseconds.
Weight::from_parts(19_714_000, 0)
.saturating_add(Weight::from_parts(0, 13563))
// Measured: `106`
// Estimated: `13471`
// Minimum execution time: 16_946_000 picoseconds.
Weight::from_parts(17_192_000, 0)
.saturating_add(Weight::from_parts(0, 13471))
.saturating_add(T::DbWeight::get().reads(5))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1)
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
@@ -233,39 +280,41 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn notify_current_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `142`
// Estimated: `6082`
// Minimum execution time: 31_630_000 picoseconds.
Weight::from_parts(32_340_000, 0)
.saturating_add(Weight::from_parts(0, 6082))
.saturating_add(T::DbWeight::get().reads(7))
// Measured: `106`
// Estimated: `6046`
// Minimum execution time: 27_164_000 picoseconds.
Weight::from_parts(27_760_000, 0)
.saturating_add(Weight::from_parts(0, 6046))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0)
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn notify_target_migration_fail() -> Weight {
// Proof Size summary in bytes:
// Measured: `172`
// Estimated: `8587`
// Minimum execution time: 9_218_000 picoseconds.
Weight::from_parts(9_558_000, 0)
.saturating_add(Weight::from_parts(0, 8587))
// Measured: `136`
// Estimated: `8551`
// Minimum execution time: 8_689_000 picoseconds.
Weight::from_parts(8_874_000, 0)
.saturating_add(Weight::from_parts(0, 8551))
.saturating_add(T::DbWeight::get().reads(3))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2)
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn migrate_version_notify_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `198`
// Estimated: `11088`
// Minimum execution time: 18_133_000 picoseconds.
Weight::from_parts(18_663_000, 0)
.saturating_add(Weight::from_parts(0, 11088))
// Measured: `106`
// Estimated: `10996`
// Minimum execution time: 15_944_000 picoseconds.
Weight::from_parts(16_381_000, 0)
.saturating_add(Weight::from_parts(0, 10996))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2)
/// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
@@ -278,12 +327,12 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn migrate_and_notify_old_targets() -> Weight {
// Proof Size summary in bytes:
// Measured: `204`
// Estimated: `11094`
// Minimum execution time: 38_878_000 picoseconds.
Weight::from_parts(39_779_000, 0)
.saturating_add(Weight::from_parts(0, 11094))
.saturating_add(T::DbWeight::get().reads(9))
// Measured: `112`
// Estimated: `11002`
// Minimum execution time: 33_826_000 picoseconds.
Weight::from_parts(34_784_000, 0)
.saturating_add(Weight::from_parts(0, 11002))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1)
@@ -294,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1517`
// Minimum execution time: 4_142_000 picoseconds.
Weight::from_parts(4_308_000, 0)
// Minimum execution time: 4_257_000 picoseconds.
Weight::from_parts(4_383_000, 0)
.saturating_add(Weight::from_parts(0, 1517))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(2))
@@ -306,11 +355,10 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `7669`
// Estimated: `11134`
// Minimum execution time: 25_814_000 picoseconds.
Weight::from_parts(26_213_000, 0)
// Minimum execution time: 26_924_000 picoseconds.
Weight::from_parts(27_455_000, 0)
.saturating_add(Weight::from_parts(0, 11134))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
}
@@ -969,6 +969,18 @@ impl_runtime_apis! {
// Reserve transfers are disabled on Collectives.
None
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Collectives only supports teleports to system parachain.
// Relay/native token can be teleported between Collectives and Relay.
let native_location = Parent.into();
let dest = Parent.into();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
let whitelist: Vec<TrackedStorageKey> = vec![
@@ -17,9 +17,9 @@
//! Autogenerated weights for `pallet_xcm`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024
// Executed Command:
@@ -64,22 +64,37 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 25_746_000 picoseconds.
Weight::from_parts(26_349_000, 0)
// Minimum execution time: 24_540_000 picoseconds.
Weight::from_parts(25_439_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(6))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn teleport_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `69`
// Estimated: `1489`
// Minimum execution time: 22_660_000 picoseconds.
Weight::from_parts(23_173_000, 0)
.saturating_add(Weight::from_parts(0, 1489))
.saturating_add(T::DbWeight::get().reads(1))
// Measured: `214`
// Estimated: `3679`
// Minimum execution time: 86_614_000 picoseconds.
Weight::from_parts(88_884_000, 0)
.saturating_add(Weight::from_parts(0, 3679))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
@@ -91,6 +106,32 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
Weight::from_parts(18_446_744_073_709_551_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: `ParachainInfo::ParachainId` (r:1 w:0)
/// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0)
/// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1)
/// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0)
/// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `System::Account` (r:1 w:1)
/// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`)
/// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0)
/// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1)
/// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn transfer_assets() -> Weight {
// Proof Size summary in bytes:
// Measured: `214`
// Estimated: `3679`
// Minimum execution time: 87_915_000 picoseconds.
Weight::from_parts(90_219_000, 0)
.saturating_add(Weight::from_parts(0, 3679))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: `Benchmark::Override` (r:0 w:0)
/// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn execute() -> Weight {
@@ -107,8 +148,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 7_321_000 picoseconds.
Weight::from_parts(7_542_000, 0)
// Minimum execution time: 6_872_000 picoseconds.
Weight::from_parts(7_110_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -118,8 +159,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_232_000 picoseconds.
Weight::from_parts(2_395_000, 0)
// Minimum execution time: 2_009_000 picoseconds.
Weight::from_parts(2_163_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -145,8 +186,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `145`
// Estimated: `3610`
// Minimum execution time: 29_006_000 picoseconds.
Weight::from_parts(29_777_000, 0)
// Minimum execution time: 28_858_000 picoseconds.
Weight::from_parts(29_355_000, 0)
.saturating_add(Weight::from_parts(0, 3610))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(5))
@@ -171,8 +212,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `363`
// Estimated: `3828`
// Minimum execution time: 31_245_000 picoseconds.
Weight::from_parts(32_125_000, 0)
// Minimum execution time: 30_598_000 picoseconds.
Weight::from_parts(31_168_000, 0)
.saturating_add(Weight::from_parts(0, 3828))
.saturating_add(T::DbWeight::get().reads(7))
.saturating_add(T::DbWeight::get().writes(4))
@@ -183,8 +224,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 2_255_000 picoseconds.
Weight::from_parts(2_399_000, 0)
// Minimum execution time: 2_090_000 picoseconds.
Weight::from_parts(2_253_000, 0)
.saturating_add(Weight::from_parts(0, 0))
.saturating_add(T::DbWeight::get().writes(1))
}
@@ -194,8 +235,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `162`
// Estimated: `11052`
// Minimum execution time: 16_521_000 picoseconds.
Weight::from_parts(17_001_000, 0)
// Minimum execution time: 16_133_000 picoseconds.
Weight::from_parts(16_433_000, 0)
.saturating_add(Weight::from_parts(0, 11052))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -206,8 +247,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `166`
// Estimated: `11056`
// Minimum execution time: 16_486_000 picoseconds.
Weight::from_parts(16_729_000, 0)
// Minimum execution time: 16_012_000 picoseconds.
Weight::from_parts(16_449_000, 0)
.saturating_add(Weight::from_parts(0, 11056))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -218,8 +259,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `13538`
// Minimum execution time: 18_037_000 picoseconds.
Weight::from_parts(18_310_000, 0)
// Minimum execution time: 17_922_000 picoseconds.
Weight::from_parts(18_426_000, 0)
.saturating_add(Weight::from_parts(0, 13538))
.saturating_add(T::DbWeight::get().reads(5))
}
@@ -241,8 +282,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `212`
// Estimated: `6152`
// Minimum execution time: 27_901_000 picoseconds.
Weight::from_parts(28_566_000, 0)
// Minimum execution time: 27_280_000 picoseconds.
Weight::from_parts(28_026_000, 0)
.saturating_add(Weight::from_parts(0, 6152))
.saturating_add(T::DbWeight::get().reads(8))
.saturating_add(T::DbWeight::get().writes(3))
@@ -253,8 +294,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `206`
// Estimated: `8621`
// Minimum execution time: 9_299_000 picoseconds.
Weight::from_parts(9_547_000, 0)
// Minimum execution time: 9_387_000 picoseconds.
Weight::from_parts(9_644_000, 0)
.saturating_add(Weight::from_parts(0, 8621))
.saturating_add(T::DbWeight::get().reads(3))
}
@@ -264,8 +305,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `173`
// Estimated: `11063`
// Minimum execution time: 16_768_000 picoseconds.
Weight::from_parts(17_215_000, 0)
// Minimum execution time: 16_649_000 picoseconds.
Weight::from_parts(17_025_000, 0)
.saturating_add(Weight::from_parts(0, 11063))
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(2))
@@ -288,8 +329,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `215`
// Estimated: `11105`
// Minimum execution time: 35_134_000 picoseconds.
Weight::from_parts(35_883_000, 0)
// Minimum execution time: 34_355_000 picoseconds.
Weight::from_parts(35_295_000, 0)
.saturating_add(Weight::from_parts(0, 11105))
.saturating_add(T::DbWeight::get().reads(10))
.saturating_add(T::DbWeight::get().writes(4))
@@ -302,8 +343,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `103`
// Estimated: `1588`
// Minimum execution time: 4_562_000 picoseconds.
Weight::from_parts(4_802_000, 0)
// Minimum execution time: 4_527_000 picoseconds.
Weight::from_parts(4_699_000, 0)
.saturating_add(Weight::from_parts(0, 1588))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(2))
@@ -314,8 +355,8 @@ impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
// Proof Size summary in bytes:
// Measured: `7740`
// Estimated: `11205`
// Minimum execution time: 26_865_000 picoseconds.
Weight::from_parts(27_400_000, 0)
// Minimum execution time: 27_011_000 picoseconds.
Weight::from_parts(27_398_000, 0)
.saturating_add(Weight::from_parts(0, 11205))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
@@ -723,6 +723,18 @@ impl_runtime_apis! {
// Reserve transfers are disabled on Contracts-System-Para.
None
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Contracts-System-Para only supports teleports to system parachain.
// Relay/native token can be teleported between Contracts-System-Para and Relay.
let native_location = Parent.into();
let dest = Parent.into();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
let whitelist: Vec<TrackedStorageKey> = vec![
@@ -94,12 +94,24 @@ pub type FungiblesTransactor = FungiblesAdapter<
// Use this fungibles implementation:
Assets,
// Use this currency when it is a fungible asset matching the given location or name:
ConvertedConcreteId<
AssetIdPalletAssets,
Balance,
AsPrefixedGeneralIndex<SystemAssetHubAssetsPalletLocation, AssetIdPalletAssets, JustTry>,
JustTry,
>,
(
ConvertedConcreteId<
AssetIdPalletAssets,
Balance,
AsPrefixedGeneralIndex<AssetsPalletLocation, AssetIdPalletAssets, JustTry>,
JustTry,
>,
ConvertedConcreteId<
AssetIdPalletAssets,
Balance,
AsPrefixedGeneralIndex<
SystemAssetHubAssetsPalletLocation,
AssetIdPalletAssets,
JustTry,
>,
JustTry,
>,
),
// Convert an XCM MultiLocation into a local account id:
LocationToAccountId,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
@@ -237,6 +249,8 @@ where
}
}
// This asset can be added to AH as ForeignAsset and teleported between Penpal and AH
pub const TELEPORTABLE_ASSET_ID: u32 = 2;
parameter_types! {
/// The location that this chain recognizes as the Relay network's Asset Hub.
pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000)));
@@ -244,11 +258,30 @@ parameter_types! {
// the Relay Chain's Asset Hub's Assets pallet index
pub SystemAssetHubAssetsPalletLocation: MultiLocation =
MultiLocation::new(1, X2(Parachain(1000), PalletInstance(50)));
pub AssetsPalletLocation: MultiLocation =
MultiLocation::new(0, X1(PalletInstance(50)));
pub CheckingAccount: AccountId = PolkadotXcm::check_account();
pub LocalTeleportableToAssetHub: MultiLocation = MultiLocation::new(
0,
X2(PalletInstance(50), GeneralIndex(TELEPORTABLE_ASSET_ID.into()))
);
}
/// Accepts asset with ID `AssetLocation` and is coming from `Origin` chain.
pub struct AssetFromChain<AssetLocation, Origin>(PhantomData<(AssetLocation, Origin)>);
impl<AssetLocation: Get<MultiLocation>, Origin: Get<MultiLocation>>
ContainsPair<MultiAsset, MultiLocation> for AssetFromChain<AssetLocation, Origin>
{
fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool {
log::trace!(target: "xcm::contains", "AssetFromChain asset: {:?}, origin: {:?}", asset, origin);
*origin == Origin::get() && matches!(asset.id, Concrete(id) if id == AssetLocation::get())
}
}
pub type Reserves =
(NativeAsset, AssetsFrom<SystemAssetHubLocation>, NativeAssetFrom<SystemAssetHubLocation>);
pub type TrustedTeleporters =
(AssetFromChain<LocalTeleportableToAssetHub, SystemAssetHubLocation>,);
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
@@ -259,7 +292,7 @@ impl xcm_executor::Config for XcmConfig {
type OriginConverter = XcmOriginToTransactDispatchOrigin;
type IsReserve = Reserves;
// no teleport trust established with other chains
type IsTeleporter = NativeAsset;
type IsTeleporter = TrustedTeleporters;
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
+14
View File
@@ -2261,6 +2261,20 @@ sp_api::impl_runtime_apis! {
Parachain(43211234).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Relay supports only native token, either reserve transfer it to non-system parachains,
// or teleport it to system parachain. Use the teleport case for benchmarking as it's
// slightly heavier.
// Relay/native token can be teleported to/from AH.
let native_location = Here.into();
let dest = crate::xcm_config::AssetHub::get();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
impl pallet_xcm_benchmarks::Config for Runtime {
type XcmConfig = XcmConfig;
@@ -48,6 +48,10 @@ use core::marker::PhantomData;
/// Weight functions for `pallet_xcm`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
fn transfer_assets() -> Weight {
// TODO: run benchmarks
Weight::zero()
}
/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+15
View File
@@ -2295,6 +2295,21 @@ sp_api::impl_runtime_apis! {
crate::Junction::Parachain(43211234).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
// Relay supports only native token, either reserve transfer it to non-system parachains,
// or teleport it to system parachain. Use the teleport case for benchmarking as it's
// slightly heavier.
// Relay/native token can be teleported to/from AH.
let native_location = Here.into();
let dest = crate::xcm_config::AssetHub::get();
pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::<Runtime>(
native_location,
dest
)
}
}
impl frame_system_benchmarking::Config for Runtime {}
impl pallet_nomination_pools_benchmarking::Config for Runtime {}
@@ -50,6 +50,10 @@ use core::marker::PhantomData;
/// Weight functions for `pallet_xcm`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_xcm::WeightInfo for WeightInfo<T> {
fn transfer_assets() -> Weight {
// TODO: run benchmarks
Weight::zero()
}
/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0)
/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `XcmPallet::SupportedVersion` (r:1 w:0)
+69 -2
View File
@@ -44,7 +44,7 @@ pub trait Config: crate::Config {
///
/// Implementation should also make sure `dest` is reachable/connected.
///
/// If `None`, the benchmarks that depend on this will be skipped.
/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
None
}
@@ -54,10 +54,27 @@ pub trait Config: crate::Config {
///
/// Implementation should also make sure `dest` is reachable/connected.
///
/// If `None`, the benchmarks that depend on this will be skipped.
/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
None
}
/// Sets up a complex transfer (usually consisting of a teleport and reserve-based transfer), so
/// that runtime can properly benchmark `transfer_assets()` extrinsic. Should return a tuple
/// `(MultiAsset, u32, MultiLocation, dyn FnOnce())` representing the assets to transfer, the
/// `u32` index of the asset to be used for fees, the destination chain for the transfer, and a
/// `verify()` closure to verify the intended transfer side-effects.
///
/// Implementation should make sure the provided assets can be transacted by the runtime, there
/// are enough balances in the involved accounts, and that `dest` is reachable/connected.
///
/// Used only in benchmarks.
///
/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
None
}
}
benchmarks! {
@@ -158,6 +175,23 @@ benchmarks! {
assert!(pallet_balances::Pallet::<T>::free_balance(&caller) <= balance - transferred_amount);
}
transfer_assets {
let (assets, fee_index, destination, verify) = T::set_up_complex_asset_transfer().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?;
let caller: T::AccountId = whitelisted_caller();
let send_origin = RawOrigin::Signed(caller.clone());
let recipient = [0u8; 32];
let versioned_dest: VersionedMultiLocation = destination.into();
let versioned_beneficiary: VersionedMultiLocation =
AccountId32 { network: None, id: recipient.into() }.into();
let versioned_assets: VersionedMultiAssets = assets.into();
}: _<RuntimeOrigin<T>>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0, WeightLimit::Unlimited)
verify {
// run provided verification function
verify();
}
execute {
let execute_origin =
T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
@@ -302,3 +336,36 @@ benchmarks! {
crate::mock::Test
);
}
pub mod helpers {
use super::*;
pub fn native_teleport_as_asset_transfer<T>(
native_asset_location: MultiLocation,
destination: MultiLocation,
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)>
where
T: Config + pallet_balances::Config,
u128: From<<T as pallet_balances::Config>::Balance>,
{
// Relay/native token can be teleported to/from AH.
let amount = T::ExistentialDeposit::get() * 100u32.into();
let assets: MultiAssets =
MultiAsset { fun: Fungible(amount.into()), id: Concrete(native_asset_location) }.into();
let fee_index = 0u32;
// Give some multiple of transferred amount
let balance = amount * 10u32.into();
let who = whitelisted_caller();
let _ =
<pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
// verify initial balance
assert_eq!(pallet_balances::Pallet::<T>::free_balance(&who), balance);
// verify transferred successfully
let verify = Box::new(move || {
// verify balance after transfer, decreased by transferred amount (and delivery fees)
assert!(pallet_balances::Pallet::<T>::free_balance(&who) <= balance - amount);
});
Some((assets, fee_index, destination, verify))
}
}
+406 -162
View File
@@ -66,6 +66,7 @@ pub trait WeightInfo {
fn send() -> Weight;
fn teleport_assets() -> Weight;
fn reserve_transfer_assets() -> Weight;
fn transfer_assets() -> Weight;
fn execute() -> Weight;
fn force_xcm_version() -> Weight;
fn force_default_xcm_version() -> Weight;
@@ -98,6 +99,10 @@ impl WeightInfo for TestWeightInfo {
Weight::from_parts(100_000_000, 0)
}
fn transfer_assets() -> Weight {
Weight::from_parts(100_000_000, 0)
}
fn execute() -> Weight {
Weight::from_parts(100_000_000, 0)
}
@@ -905,8 +910,8 @@ pub mod pallet {
/// from relay to parachain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. The first item should be the currency used to to
/// pay the fee on the `dest` side. May not be empty.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` chain.
/// - `fee_asset_item`: The index into `assets` of the item which should be used to pay
/// fees.
#[pallet::call_index(1)]
@@ -937,8 +942,19 @@ pub mod pallet {
Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item, Unlimited)
}
/// Transfer some assets from the local chain to the sovereign account of a destination
/// chain and forward a notification XCM.
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve.
///
/// `assets` must have same reserve location and may not be teleportable to `dest`.
/// - `assets` have local reserve: transfer assets to sovereign account of destination
/// chain and forward a notification XCM to `dest` to mint and deposit reserve-based
/// assets to `beneficiary`.
/// - `assets` have destination reserve: burn local assets and forward a notification to
/// `dest` chain to withdraw the reserve assets from this chain's sovereign account and
/// deposit them to `beneficiary`.
/// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move
/// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest`
/// to mint and deposit reserve-based assets to `beneficiary`.
///
/// **This function is deprecated: Use `limited_reserve_transfer_assets` instead.**
///
@@ -953,7 +969,7 @@ pub mod pallet {
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` side.
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_item`: The index into `assets` of the item which should be used to pay
/// fees.
#[pallet::call_index(2)]
@@ -1105,8 +1121,19 @@ pub mod pallet {
})
}
/// Transfer some assets from the local chain to the sovereign account of a destination
/// chain and forward a notification XCM.
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve.
///
/// `assets` must have same reserve location and may not be teleportable to `dest`.
/// - `assets` have local reserve: transfer assets to sovereign account of destination
/// chain and forward a notification XCM to `dest` to mint and deposit reserve-based
/// assets to `beneficiary`.
/// - `assets` have destination reserve: burn local assets and forward a notification to
/// `dest` chain to withdraw the reserve assets from this chain's sovereign account and
/// deposit them to `beneficiary`.
/// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move
/// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest`
/// to mint and deposit reserve-based assets to `beneficiary`.
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight
@@ -1120,7 +1147,7 @@ pub mod pallet {
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` side.
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_item`: The index into `assets` of the item which should be used to pay
/// fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
@@ -1173,8 +1200,8 @@ pub mod pallet {
/// from relay to parachain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. The first item should be the currency used to to
/// pay the fee on the `dest` side. May not be empty.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` chain.
/// - `fee_asset_item`: The index into `assets` of the item which should be used to pay
/// fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
@@ -1225,12 +1252,162 @@ pub mod pallet {
XcmExecutionSuspended::<T>::set(suspended);
Ok(())
}
/// Transfer some assets from the local chain to the destination chain through their local,
/// destination or remote reserve, or through teleports.
///
/// Fee payment on the destination side is made from the asset in the `assets` vector of
/// index `fee_asset_item` (hence referred to as `fees`), up to enough to pay for
/// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the
/// operation will fail and the assets sent may be at risk.
///
/// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable
/// to `dest`, no limitations imposed on `fees`.
/// - for local reserve: transfer assets to sovereign account of destination chain and
/// forward a notification XCM to `dest` to mint and deposit reserve-based assets to
/// `beneficiary`.
/// - for destination reserve: burn local assets and forward a notification to `dest` chain
/// to withdraw the reserve assets from this chain's sovereign account and deposit them
/// to `beneficiary`.
/// - for remote reserve: burn local assets, forward XCM to reserve chain to move reserves
/// from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` to mint
/// and deposit reserve-based assets to `beneficiary`.
/// - for teleports: burn local assets and forward XCM to `dest` chain to mint/teleport
/// assets and deposit them to `beneficiary`.
///
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
/// - `dest`: Destination context for the assets. Will typically be `X2(Parent,
/// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send
/// from relay to parachain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will
/// generally be an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the
/// fee on the `dest` (and possibly reserve) chains.
/// - `fee_asset_item`: The index into `assets` of the item which should be used to pay
/// fees.
/// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase.
#[pallet::call_index(11)]
#[pallet::weight({
let maybe_assets: Result<MultiAssets, ()> = (*assets.clone()).try_into();
let maybe_dest: Result<MultiLocation, ()> = (*dest.clone()).try_into();
match (maybe_assets, maybe_dest) {
(Ok(assets), Ok(dest)) => {
use sp_std::vec;
// heaviest version of locally executed XCM program: equivalent in weight to withdrawing fees,
// burning them, transferring rest of assets to SA, reanchoring them, extending XCM program,
// and sending onward XCM
let mut message = Xcm(vec![
SetFeesMode { jit_withdraw: true },
WithdrawAsset(assets.clone()),
BurnAsset(assets.clone()),
TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) }
]);
T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::transfer_assets().saturating_add(w))
}
_ => Weight::MAX,
}
})]
pub fn transfer_assets(
origin: OriginFor<T>,
dest: Box<VersionedMultiLocation>,
beneficiary: Box<VersionedMultiLocation>,
assets: Box<VersionedMultiAssets>,
fee_asset_item: u32,
weight_limit: WeightLimit,
) -> DispatchResult {
let origin = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let dest = (*dest).try_into().map_err(|()| Error::<T>::BadVersion)?;
let beneficiary: MultiLocation =
(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
log::debug!(
target: "xcm::pallet_xcm::transfer_assets",
"origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}",
origin, dest, beneficiary, assets, fee_asset_item, weight_limit,
);
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let mut assets = assets.into_inner();
let fee_asset_item = fee_asset_item as usize;
let fees = assets.get(fee_asset_item as usize).ok_or(Error::<T>::Empty)?.clone();
// Find transfer types for fee and non-fee assets.
let (fees_transfer_type, assets_transfer_type) =
Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?;
// local and remote XCM programs to potentially handle fees separately
let fees = if fees_transfer_type == assets_transfer_type {
// no need for custom fees instructions, fees are batched with assets
FeesHandling::Batched { fees }
} 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 weight_limit = weight_limit.clone();
// remove `fees` from `assets` and build separate fees transfer instructions to be
// added to assets transfers XCM programs
let fees = assets.remove(fee_asset_item);
let (local_xcm, remote_xcm) = match fees_transfer_type {
TransferType::LocalReserve =>
Self::local_reserve_fees_instructions(origin, dest, fees, weight_limit)?,
TransferType::DestinationReserve =>
Self::destination_reserve_fees_instructions(
origin,
dest,
fees,
weight_limit,
)?,
TransferType::Teleport =>
Self::teleport_fees_instructions(origin, dest, fees, weight_limit)?,
TransferType::RemoteReserve(_) =>
return Err(Error::<T>::InvalidAssetUnsupportedReserve.into()),
};
FeesHandling::Separate { local_xcm, remote_xcm }
};
Self::build_and_execute_xcm_transfer_type(
origin,
dest,
beneficiary,
assets,
assets_transfer_type,
fees,
weight_limit,
)
}
}
}
/// The maximum number of distinct assets allowed to be transferred in a single helper extrinsic.
const MAX_ASSETS_FOR_TRANSFER: usize = 2;
/// Specify how assets used for fees are handled during asset transfers.
#[derive(Clone, PartialEq)]
enum FeesHandling<T: Config> {
/// `fees` asset can be batch-transferred with rest of assets using same XCM instructions.
Batched { fees: MultiAsset },
/// fees cannot be batched, they are handled separately using XCM programs here.
Separate { local_xcm: Xcm<<T as Config>::RuntimeCall>, remote_xcm: Xcm<()> },
}
impl<T: Config> sp_std::fmt::Debug for FeesHandling<T> {
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
match self {
Self::Batched { fees } => write!(f, "FeesHandling::Batched({:?})", fees),
Self::Separate { local_xcm, remote_xcm } => write!(
f,
"FeesHandling::Separate(local: {:?}, remote: {:?})",
local_xcm, remote_xcm
),
}
}
}
impl<T: Config> QueryHandler for Pallet<T> {
type QueryId = u64;
type BlockNumber = BlockNumberFor<T>;
@@ -1292,31 +1469,45 @@ impl<T: Config> QueryHandler for Pallet<T> {
}
impl<T: Config> Pallet<T> {
/// Validate `assets` to be reserve-transferred and return their reserve location.
fn validate_assets_and_find_reserve(
/// Find `TransferType`s for `assets` and fee identified through `fee_asset_item`, when
/// transferring to `dest`.
///
/// Validate `assets` to all have same `TransferType`.
fn find_fee_and_assets_transfer_types(
assets: &[MultiAsset],
fee_asset_item: usize,
dest: &MultiLocation,
) -> Result<TransferType, Error<T>> {
let mut reserve = None;
for asset in assets.iter() {
) -> Result<(TransferType, TransferType), Error<T>> {
let mut fees_transfer_type = None;
let mut assets_transfer_type = None;
for (idx, asset) in assets.iter().enumerate() {
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);
if idx == fee_asset_item {
fees_transfer_type = Some(transfer_type);
} else {
// asset reserve identified
reserve = Some(transfer_type);
if let Some(existing) = assets_transfer_type.as_ref() {
// Ensure transfer for multiple assets uses same transfer type (only fee may
// have different transfer type/path)
ensure!(existing == &transfer_type, Error::<T>::TooManyReserves);
} else {
// asset reserve identified
assets_transfer_type = Some(transfer_type);
}
}
}
reserve.ok_or(Error::<T>::Empty)
// single asset also marked as fee item
if assets.len() == 1 {
assets_transfer_type = fees_transfer_type
}
Ok((
fees_transfer_type.ok_or(Error::<T>::Empty)?,
assets_transfer_type.ok_or(Error::<T>::Empty)?,
))
}
fn do_reserve_transfer_assets(
@@ -1332,7 +1523,7 @@ impl<T: Config> Pallet<T> {
let beneficiary: MultiLocation =
(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
log::trace!(
log::debug!(
target: "xcm::pallet_xcm::do_reserve_transfer_assets",
"origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}",
origin_location, dest, beneficiary, assets, fee_asset_item,
@@ -1341,64 +1532,26 @@ impl<T: Config> Pallet<T> {
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let value = (origin_location, assets.into_inner());
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, mut assets) = value;
let (origin, assets) = value;
if fee_asset_item as usize >= assets.len() {
return Err(Error::<T>::Empty.into())
}
let fees = assets.swap_remove(fee_asset_item as usize);
let fees_transfer_type =
T::XcmExecutor::determine_for(&fees, &dest).map_err(Error::<T>::from)?;
let assets_transfer_type = if assets.is_empty() {
// Single asset to transfer (one used for fees where transfer type is determined above).
ensure!(fees_transfer_type != TransferType::Teleport, Error::<T>::Filtered);
fees_transfer_type
} else {
// Find reserve for non-fee assets.
Self::validate_assets_and_find_reserve(&assets, &dest)?
};
let fee_asset_item = fee_asset_item as usize;
let fees = assets.get(fee_asset_item as usize).ok_or(Error::<T>::Empty)?.clone();
// local and remote XCM programs to potentially handle fees separately
let separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>;
if fees_transfer_type == assets_transfer_type {
// Same reserve location (fees not teleportable), we can batch together fees and assets
// in same reserve-based-transfer.
assets.push(fees.clone());
// no need for custom fees instructions, fees are batched with assets
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(origin_location, dest, fees, weight_limit)?,
TransferType::RemoteReserve(_) =>
return Err(Error::<T>::InvalidAssetUnsupportedReserve.into()),
});
};
// Find transfer types for fee and non-fee assets.
let (fees_transfer_type, assets_transfer_type) =
Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?;
// Ensure assets (and fees according to check below) are not teleportable to `dest`.
ensure!(assets_transfer_type != TransferType::Teleport, Error::<T>::Filtered);
// Ensure all assets (including fees) have same reserve location.
ensure!(assets_transfer_type == fees_transfer_type, Error::<T>::TooManyReserves);
Self::build_and_execute_xcm_transfer_type(
origin_location,
origin,
dest,
beneficiary,
assets,
assets_transfer_type,
fees,
separate_fees_instructions,
FeesHandling::Batched { fees },
weight_limit,
)
}
@@ -1416,6 +1569,11 @@ impl<T: Config> Pallet<T> {
let beneficiary: MultiLocation =
(*beneficiary).try_into().map_err(|()| Error::<T>::BadVersion)?;
let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::<T>::BadVersion)?;
log::debug!(
target: "xcm::pallet_xcm::do_teleport_assets",
"origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}",
origin_location, dest, beneficiary, assets, fee_asset_item, weight_limit,
);
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let value = (origin_location, assets.into_inner());
@@ -1424,7 +1582,7 @@ impl<T: Config> Pallet<T> {
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);
ensure!(transfer_type == TransferType::Teleport, Error::<T>::Filtered);
}
let fees = assets.get(fee_asset_item as usize).ok_or(Error::<T>::Empty)?.clone();
@@ -1434,8 +1592,7 @@ impl<T: Config> Pallet<T> {
beneficiary,
assets,
TransferType::Teleport,
fees,
None,
FeesHandling::Batched { fees },
weight_limit,
)
}
@@ -1446,54 +1603,65 @@ impl<T: Config> Pallet<T> {
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
transfer_type: TransferType,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
fees: FeesHandling<T>,
weight_limit: WeightLimit,
) -> DispatchResult {
log::trace!(
log::debug!(
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,
fees_handling {:?}, weight_limit: {:?}",
origin, dest, beneficiary, assets, transfer_type, fees, weight_limit,
);
let (mut local_xcm, remote_xcm) = match transfer_type {
TransferType::LocalReserve => {
let (local, remote) = Self::local_reserve_transfer_programs(
origin,
dest,
beneficiary,
assets,
fees,
separate_fees_instructions,
weight_limit,
)?;
(local, Some(remote))
},
TransferType::DestinationReserve => {
let (local, remote) = Self::destination_reserve_transfer_programs(
origin,
dest,
beneficiary,
assets,
fees,
separate_fees_instructions,
weight_limit,
)?;
(local, Some(remote))
},
TransferType::RemoteReserve(reserve) => (
Self::remote_reserve_transfer_program(
TransferType::RemoteReserve(reserve) => {
let fees = match fees {
FeesHandling::Batched { fees } => fees,
_ => return Err(Error::<T>::InvalidAssetUnsupportedReserve.into()),
};
let local = Self::remote_reserve_transfer_program(
origin,
reserve,
dest,
beneficiary,
assets,
fees,
weight_limit,
)?,
None,
),
TransferType::Teleport => (
Self::teleport_assets_program(dest, beneficiary, assets, fees, weight_limit)?,
None,
),
)?;
(local, None)
},
TransferType::Teleport => {
let (local, remote) = Self::teleport_assets_program(
origin,
dest,
beneficiary,
assets,
fees,
weight_limit,
)?;
(local, Some(remote))
},
};
let weight =
T::Weigher::weight(&mut local_xcm).map_err(|()| Error::<T>::UnweighableMessage)?;
@@ -1529,11 +1697,45 @@ impl<T: Config> Pallet<T> {
Ok(())
}
fn add_fees_to_xcm(
dest: MultiLocation,
fees: FeesHandling<T>,
weight_limit: WeightLimit,
local: &mut Xcm<<T as Config>::RuntimeCall>,
remote: &mut Xcm<()>,
) -> Result<(), Error<T>> {
match fees {
FeesHandling::Batched { fees } => {
let context = T::UniversalLocation::get();
// 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`
remote.inner_mut().push(BuyExecution { fees: reanchored_fees, weight_limit });
},
FeesHandling::Separate { local_xcm: mut local_fees, remote_xcm: mut remote_fees } => {
// fees are handled by separate XCM instructions, prepend fees instructions (for
// remote XCM they have to be prepended instead of appended to pass barriers).
sp_std::mem::swap(local, &mut local_fees);
sp_std::mem::swap(remote, &mut remote_fees);
// these are now swapped so fees actually go first
local.inner_mut().append(&mut local_fees.into_inner());
remote.inner_mut().append(&mut remote_fees.into_inner());
},
}
Ok(())
}
fn local_reserve_fees_instructions(
origin: MultiLocation,
dest: MultiLocation,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let value = (origin, vec![fees.clone()]);
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let context = T::UniversalLocation::get();
let reanchored_fees = fees
.clone()
@@ -1554,16 +1756,20 @@ impl<T: Config> Pallet<T> {
}
fn local_reserve_transfer_programs(
origin: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
fees: FeesHandling<T>,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let value = (origin, assets);
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (_, assets) = value;
// 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);
assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 };
let assets: MultiAssets = assets.into();
let context = T::UniversalLocation::get();
let mut reanchored_assets = assets.clone();
@@ -1571,45 +1777,37 @@ impl<T: Config> Pallet<T> {
.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(&[
// XCM instructions to be executed on local chain
let mut local_execute_xcm = Xcm(vec![
// locally move `assets` to `dest`s local sovereign account
TransferAsset { assets, beneficiary: dest },
]);
// XCM instructions to be executed on destination chain
let mut xcm_on_dest = Xcm(vec![
// 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 });
}
// handle fees
Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?;
// deposit all remaining assets in holding to `beneficiary` location
xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
xcm_on_dest
.inner_mut()
.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest)))
Ok((local_execute_xcm, xcm_on_dest))
}
fn destination_reserve_fees_instructions(
origin: MultiLocation,
dest: MultiLocation,
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let value = (origin, vec![fees.clone()]);
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let context = T::UniversalLocation::get();
let reanchored_fees = fees
.clone()
@@ -1633,16 +1831,20 @@ impl<T: Config> Pallet<T> {
}
fn destination_reserve_transfer_programs(
origin: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
fees: MultiAsset,
separate_fees_instructions: Option<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>)>,
fees: FeesHandling<T>,
weight_limit: WeightLimit,
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let value = (origin, assets);
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (_, assets) = value;
// 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);
assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 };
let assets: MultiAssets = assets.into();
let context = T::UniversalLocation::get();
let mut reanchored_assets = assets.clone();
@@ -1650,47 +1852,33 @@ impl<T: Config> Pallet<T> {
.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(&[
// XCM instructions to be executed on local chain
let mut local_execute_xcm = Xcm(vec![
// 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(&[
// XCM instructions to be executed on destination chain
let mut xcm_on_dest = Xcm(vec![
// 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 });
}
// handle fees
Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?;
// deposit all remaining assets in holding to `beneficiary` location
xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
xcm_on_dest
.inner_mut()
.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest)))
Ok((local_execute_xcm, xcm_on_dest))
}
// function assumes fees and assets have the same remote reserve
fn remote_reserve_transfer_program(
origin: MultiLocation,
reserve: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
@@ -1698,6 +1886,10 @@ impl<T: Config> Pallet<T> {
fees: MultiAsset,
weight_limit: WeightLimit,
) -> Result<Xcm<<T as Config>::RuntimeCall>, Error<T>> {
let value = (origin, assets);
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (_, assets) = value;
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
@@ -1760,6 +1952,8 @@ impl<T: Config> Pallet<T> {
&dummy_context,
)
.map_err(|_| Error::<T>::CannotCheckOutTeleport)?;
// safe to do this here, we're in a transactional call that will be reverted on any
// errors down the line
<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::check_out(
&dest,
&fees,
@@ -1783,24 +1977,74 @@ impl<T: Config> Pallet<T> {
}
fn teleport_assets_program(
origin: MultiLocation,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
mut fees: MultiAsset,
fees: FeesHandling<T>,
weight_limit: WeightLimit,
) -> Result<Xcm<<T as Config>::RuntimeCall>, Error<T>> {
) -> Result<(Xcm<<T as Config>::RuntimeCall>, Xcm<()>), Error<T>> {
let value = (origin, assets);
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
let (_, assets) = value;
// max assets is `assets` (+ potentially separately handled fee)
let max_assets =
assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 };
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 },
DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary },
let assets: MultiAssets = assets.into();
let mut reanchored_assets = assets.clone();
reanchored_assets
.reanchor(&dest, context)
.map_err(|_| Error::<T>::CannotReanchor)?;
// XcmContext irrelevant in teleports checks
let dummy_context =
XcmContext { origin: None, message_id: Default::default(), topic: None };
for asset in assets.inner() {
// 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,
asset,
&dummy_context,
)
.map_err(|_| Error::<T>::CannotCheckOutTeleport)?;
}
for asset in assets.inner() {
// safe to do this here, we're in a transactional call that will be reverted on any
// errors down the line
<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::check_out(
&dest,
asset,
&dummy_context,
);
}
// XCM instructions to be executed on local chain
let mut local_execute_xcm = Xcm(vec![
// withdraw assets to be teleported
WithdrawAsset(assets.clone()),
// burn assets on local chain
BurnAsset(assets),
]);
Ok(Xcm(vec![
WithdrawAsset(assets.into()),
SetFeesMode { jit_withdraw: true },
InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest },
]))
// XCM instructions to be executed on destination chain
let mut xcm_on_dest = Xcm(vec![
// teleport `assets` in from origin chain
ReceiveTeleportedAsset(reanchored_assets),
// following instructions are not exec'ed on behalf of origin chain anymore
ClearOrigin,
]);
// handle fees
Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?;
// deposit all remaining assets in holding to `beneficiary` location
xcm_on_dest
.inner_mut()
.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary });
Ok((local_execute_xcm, xcm_on_dest))
}
/// Halve `fees` fungible amount.
+45
View File
@@ -579,6 +579,51 @@ impl super::benchmarking::Config for Test {
Parachain(OTHER_PARA_ID).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
use crate::tests::assets_transfer::{into_multiassets_checked, set_up_foreign_asset};
// Transfer native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for
// fees.
let asset_amount = 10u128;
let fee_amount = 2u128;
// create sufficient foreign asset USDT
let usdt_initial_local_amount = fee_amount * 10;
let (usdt_chain, _, usdt_id_multilocation) =
set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true);
// native assets transfer destination is USDT chain (teleport trust only for USDT)
let dest = usdt_chain;
let (assets, fee_index, _, _) = into_multiassets_checked(
// USDT for fees (is sufficient on local chain too) - teleported
(usdt_id_multilocation, fee_amount).into(),
// native asset to transfer (not used for fees) - local reserve
(MultiLocation::here(), asset_amount).into(),
);
let existential_deposit = ExistentialDeposit::get();
let caller = frame_benchmarking::whitelisted_caller();
// Give some multiple of the existential deposit
let balance = asset_amount + existential_deposit * 1000;
let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
&caller, balance,
);
// verify initial balance
assert_eq!(Balances::free_balance(&caller), balance);
// verify transferred successfully
let verify = Box::new(move || {
// verify balance after transfer, decreased by transferred amount
assert_eq!(Balances::free_balance(&caller), balance - asset_amount);
assert_eq!(
Assets::balance(usdt_id_multilocation, &caller),
usdt_initial_local_amount - fee_amount
);
});
Some((assets, fee_index as u32, dest, verify))
}
}
pub(crate) fn last_event() -> RuntimeEvent {
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -16,7 +16,7 @@
#![cfg(test)]
mod assets_transfer;
pub(crate) mod assets_transfer;
use crate::{
mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries,
+26
View File
@@ -0,0 +1,26 @@
# Schema: Parity PR Documentation Schema (prdoc)
# See doc at https://github.com/paritytech/prdoc
title: Add new flexible `pallet_xcm::transfer_assets()` call/extrinsic
doc:
- audience: Builder
description: |
For complex combinations of asset transfers where assets and fees may have different reserves or
different reserve/teleport trust configurations, users can use the newly added `transfer_assets()`
extrinsic which is more flexible in allowing more complex scenarios.
The new extrinsic enables, for example, a (non-system) parachain to teleport their `ForeignAssets`
assets to `AssetHub` while using (reserve-based) `DOT` to pay fees.
notes:
- Now `(limited_)reserve_transfer_assets()` only allow reserve-based transfers for all assets
including fees, similarly `(limited_)teleport_assets()` only allows teleports for all assets
including fees.
migrations:
db: []
runtime: []
crates: pallet-xcm
host_functions: []
+1 -1
View File
@@ -54,7 +54,7 @@ fn create_default_asset<T: Config<I>, I: 'static>(
(asset_id, caller, caller_lookup)
}
fn create_default_minted_asset<T: Config<I>, I: 'static>(
pub fn create_default_minted_asset<T: Config<I>, I: 'static>(
is_sufficient: bool,
amount: T::Balance,
) -> (T::AssetIdParameter, T::AccountId, AccountIdLookupOf<T>) {
+1 -1
View File
@@ -141,7 +141,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod benchmarking;
pub mod migration;
#[cfg(test)]
pub mod mock;