From 5cf367197e439296a8d0fe596a8fc1a939b17ac1 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 3 Oct 2025 16:41:11 -0300 Subject: [PATCH 01/17] feat: add asset_id parameter to query_delivery_fees --- .../runtimes/assets/asset-hub-rococo/src/lib.rs | 2 +- .../runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- .../assets/asset-hub-westend/tests/tests.rs | 2 +- .../runtimes/assets/test-utils/src/test_cases.rs | 6 +++--- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../collectives/collectives-westend/src/lib.rs | 2 +- .../runtimes/coretime/coretime-rococo/src/lib.rs | 2 +- .../coretime/coretime-westend/src/lib.rs | 2 +- .../runtimes/people/people-rococo/src/lib.rs | 2 +- .../runtimes/people/people-westend/src/lib.rs | 2 +- .../runtimes/test-utils/src/test_cases.rs | 4 ++-- .../runtimes/testing/penpal/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- polkadot/xcm/xcm-runtime-apis/src/fees.rs | 16 ++++++++++++++++ .../xcm/xcm-runtime-apis/tests/fee_estimation.rs | 14 ++++++++------ polkadot/xcm/xcm-runtime-apis/tests/mock.rs | 2 +- 18 files changed, 43 insertions(+), 25 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 6c598a77160b..df5fab2a8c13 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1576,7 +1576,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index b42fc1c24480..82272047561e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1944,7 +1944,7 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 54cac811d149..4912e8ce6de9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -1642,7 +1642,7 @@ fn governance_authorize_upgrade_works() { #[test] fn weight_of_message_increases_when_dealing_with_erc20s() { use xcm::VersionedXcm; - use xcm_runtime_apis::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; + use xcm_runtime_apis::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV2; let message = Xcm::<()>::builder_unsafe().withdraw_asset((Parent, 100u128)).build(); let versioned = VersionedXcm::<()>::V5(message); let regular_asset_weight = Runtime::query_xcm_weight(versioned).unwrap(); diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index e6a0aea3605e..400f7e5028db 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -44,7 +44,7 @@ use xcm_executor::{ XcmExecutor, }; use xcm_runtime_apis::fees::{ - runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError, + runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, Error as XcmPaymentApiError, }; type RuntimeHelper = @@ -1634,7 +1634,7 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works< pub fn xcm_payment_api_with_pools_works() where - Runtime: XcmPaymentApiV1 + Runtime: XcmPaymentApiV2 + frame_system::Config + pallet_balances::Config + pallet_session::Config @@ -1821,7 +1821,7 @@ pub fn xcm_payment_api_foreign_asset_pool_works< existential_deposit: Balance, another_network_genesis_hash: [u8; 32], ) where - Runtime: XcmPaymentApiV1 + Runtime: XcmPaymentApiV2 + frame_system::Config + pallet_balances::Config + pallet_session::Config diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 545473565810..e91d44049159 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -885,7 +885,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 88f49f47949c..c6d35fbeb4e0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -836,7 +836,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index a4983f96e55f..cfb58de0edc8 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -1024,7 +1024,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index dedf3532c787..9c917a47871c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -871,7 +871,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 53fae462c0ed..202975651725 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -871,7 +871,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 5be85498ab43..64bb07ec2e96 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -819,7 +819,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index f08f2db83fd0..90811831c731 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -821,7 +821,7 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index 5e4d073c9c2d..bc8a9f003b0e 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -33,7 +33,7 @@ use sp_runtime::{ }; use xcm::prelude::InstructionError; use xcm_runtime_apis::fees::{ - runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError, + runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, Error as XcmPaymentApiError, }; type RuntimeHelper = @@ -157,7 +157,7 @@ pub fn xcm_payment_api_with_native_token_works< WeightToFee, >() where - Runtime: XcmPaymentApiV1 + Runtime: XcmPaymentApiV2 + frame_system::Config + pallet_balances::Config + pallet_session::Config diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 7dff9d74ea8d..4216f76bd772 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -1078,7 +1078,7 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { PolkadotXcm::query_delivery_fees(destination, message) } } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 8ceb382b0f4e..1e0518511976 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1933,7 +1933,7 @@ sp_api::impl_runtime_apis! { XcmPallet::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { XcmPallet::query_delivery_fees(destination, message) } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 241d43d10738..631cdec8a9bf 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2730,7 +2730,7 @@ sp_api::impl_runtime_apis! { XcmPallet::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { XcmPallet::query_delivery_fees(destination, message) } } diff --git a/polkadot/xcm/xcm-runtime-apis/src/fees.rs b/polkadot/xcm/xcm-runtime-apis/src/fees.rs index a0e2dc912934..250a9237b7ce 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/fees.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/fees.rs @@ -34,6 +34,7 @@ sp_api::decl_runtime_apis! { /// /// To determine the execution weight of the calls required for /// [`xcm::latest::Instruction::Transact`] instruction, `TransactionPaymentCallApi` can be used. + #[api_version(2)] pub trait XcmPaymentApi { /// Returns a list of acceptable payment assets. /// @@ -57,6 +58,8 @@ sp_api::decl_runtime_apis! { /// * `asset`: `VersionedAssetId`. fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; + /// Query delivery fees V1. + /// /// Get delivery fees for sending a specific `message` to a `destination`. /// These always come in a specific asset, defined by the chain. /// @@ -65,7 +68,20 @@ sp_api::decl_runtime_apis! { /// size of the message. /// * `destination`: The destination to send the message to. Different destinations may use /// different senders that charge different fees. + #[changed_in(2)] fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; + + /// Query delivery fees V2. + /// + /// Get delivery fees for sending a specific `message` to a `destination`. + /// These always come in a specific asset, defined by the chain. + /// + /// # Arguments + /// * `message`: The message that'll be sent, necessary because most delivery fees are based on the + /// size of the message. + /// * `destination`: The destination to send the message to. Different destinations may use + /// different senders that charge different fees. + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result; } } diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 1307c7adaa9c..ed772f741992 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -143,13 +143,10 @@ fn fee_estimation_for_teleport() { // results. let weight = runtime_api.query_xcm_weight(H256::zero(), local_xcm.clone()).unwrap().unwrap(); + let asset_id = VersionedAssetId::from(AssetId(HereLocation::get())); assert_eq!(weight, Weight::from_parts(400, 40)); let execution_fees = runtime_api - .query_weight_to_asset_fee( - H256::zero(), - weight, - VersionedAssetId::from(AssetId(HereLocation::get())), - ) + .query_weight_to_asset_fee(H256::zero(), weight, asset_id.clone()) .unwrap() .unwrap(); assert_eq!(execution_fees, 440); @@ -160,7 +157,12 @@ fn fee_estimation_for_teleport() { let remote_message = &remote_messages[0]; let delivery_fees = runtime_api - .query_delivery_fees(H256::zero(), destination.clone(), remote_message.clone()) + .query_delivery_fees( + H256::zero(), + destination.clone(), + remote_message.clone(), + asset_id, + ) .unwrap() .unwrap(); assert_eq!(delivery_fees, VersionedAssets::from((Here, 20u128))); diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index ab0851fce688..510251567b2e 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -495,7 +495,7 @@ sp_api::mock_impl_runtime_apis! { } } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { XcmPallet::query_delivery_fees(destination, message) } } From 93c29d48ee6f0843fd1e0980319d6ecc8a8164ad Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 7 Oct 2025 17:52:12 -0300 Subject: [PATCH 02/17] feat: add asset_id to pallet-xcm helper for delivery fees --- .../emulated/common/src/macros.rs | 68 +++++++++++++------ .../src/tests/xcm_fee_estimation.rs | 14 ++-- .../src/tests/xcm_fee_estimation.rs | 14 ++-- .../assets/asset-hub-rococo/src/lib.rs | 10 ++- .../assets/asset-hub-westend/src/lib.rs | 10 ++- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 10 ++- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 10 ++- .../collectives-westend/src/lib.rs | 11 ++- .../coretime/coretime-rococo/src/lib.rs | 11 ++- .../coretime/coretime-westend/src/lib.rs | 11 ++- .../runtimes/people/people-rococo/src/lib.rs | 8 +-- .../runtimes/people/people-westend/src/lib.rs | 8 +-- .../runtimes/testing/penpal/src/lib.rs | 12 ++-- polkadot/runtime/rococo/src/lib.rs | 9 ++- polkadot/runtime/westend/src/lib.rs | 9 ++- polkadot/xcm/pallet-xcm/src/lib.rs | 47 +++++++++++-- polkadot/xcm/xcm-runtime-apis/tests/mock.rs | 4 +- 17 files changed, 159 insertions(+), 107 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 1509be680975..ee9047e450e1 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -55,7 +55,7 @@ pub use frame_support::{ }; pub use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV2, - fees::{runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError}, + fees::{runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, Error as XcmPaymentApiError}, }; pub use frame_support::traits::{fungible::Mutate, fungibles::Inspect, Currency}; @@ -124,9 +124,15 @@ macro_rules! test_parachain_is_trusted_teleporter { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); + // The native asset of every system chain. + // We want to get the delivery fees in this asset. + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(1, [])); let delivery_fees = - >::query_delivery_fees(destination_to_query.clone(), - remote_message.clone()).unwrap(); + >::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees + ).unwrap(); let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap(); let $crate::macros::Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { unreachable!("asset is non-fungible"); @@ -261,9 +267,15 @@ macro_rules! test_relay_is_trusted_teleporter { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); + // The native asset of every system chain. + // We want to get the delivery fees in this asset. + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(0, [])); let delivery_fees = - >::query_delivery_fees(destination_to_query.clone(), - remote_message.clone()).unwrap(); + >::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees + ).unwrap(); let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap(); let $crate::macros::Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { unreachable!("asset is non-fungible"); @@ -406,9 +418,15 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); + // The native asset of every system chain. + // We want to get the delivery fees in this asset. + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(1, [])); let delivery_fees = - >::query_delivery_fees(destination_to_query.clone(), - remote_message.clone()).unwrap(); + >::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees + ).unwrap(); let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap(); delivery_fees_amount = if let Some(first_asset) = latest_delivery_fees.inner().first() { let $crate::macros::Fungible(inner_delivery_fees_amount) = first_asset.fun else { @@ -689,8 +707,8 @@ macro_rules! test_can_estimate_and_pay_exact_fees { let result = >::dry_run_call(origin, call.clone(), $crate::macros::XCM_VERSION).unwrap(); let local_xcm = result.local_xcm.unwrap().clone(); - let local_xcm_weight = >::query_xcm_weight(local_xcm).unwrap(); - local_execution_fees = >::query_weight_to_asset_fee( + let local_xcm_weight = >::query_xcm_weight(local_xcm).unwrap(); + local_execution_fees = >::query_weight_to_asset_fee( local_xcm_weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::parent())), ) @@ -706,9 +724,13 @@ macro_rules! test_can_estimate_and_pay_exact_fees { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); let delivery_fees = - >::query_delivery_fees(destination_to_query.clone(), - remote_message.clone()).unwrap(); + >::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees + ).unwrap(); local_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees); }); @@ -721,8 +743,8 @@ macro_rules! test_can_estimate_and_pay_exact_fees { type RuntimeCall = <$asset_hub as $crate::macros::Chain>::RuntimeCall; // First we get the execution fees. - let weight = >::query_xcm_weight(remote_message.clone()).unwrap(); - intermediate_execution_fees = >::query_weight_to_asset_fee( + let weight = >::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = >::query_weight_to_asset_fee( weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::new(1, []))), ) @@ -750,9 +772,11 @@ macro_rules! test_can_estimate_and_pay_exact_fees { // We could've gotten the message from the queue without having to dry-run, but // offchain applications would have to dry-run, so we do it here as well. intermediate_remote_message = messages_to_query[0].clone(); - let delivery_fees = >::query_delivery_fees( + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); + let delivery_fees = >::query_delivery_fees( destination_to_query.clone(), intermediate_remote_message.clone(), + asset_id_for_delivery_fees, ) .unwrap(); intermediate_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees); @@ -763,10 +787,10 @@ macro_rules! test_can_estimate_and_pay_exact_fees { <$receiver_para as $crate::macros::TestExt>::execute_with(|| { type Runtime = <$sender_para as $crate::macros::Chain>::Runtime; - let weight = >::query_xcm_weight( + let weight = >::query_xcm_weight( intermediate_remote_message.clone()).unwrap(); final_execution_fees = - >::query_weight_to_asset_fee(weight, + >::query_weight_to_asset_fee(weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::parent()))) .unwrap(); }); @@ -903,7 +927,7 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { )); type Runtime = <$asset_hub as $crate::macros::Chain>::Runtime; - let acceptable_payment_assets = >::query_acceptable_payment_assets( + let acceptable_payment_assets = >::query_acceptable_payment_assets( $crate::macros::XCM_VERSION).unwrap(); assert_eq!(acceptable_payment_assets, vec![ $crate::macros::VersionedAssetId::from($crate::macros::AssetId(wnd.clone())), @@ -915,12 +939,12 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { .buy_execution(($crate::macros::Parent, 10u128), $crate::macros::Unlimited) .deposit_asset($crate::macros::All, [0u8; 32]) .build(); - let weight = >::query_xcm_weight( + let weight = >::query_xcm_weight( $crate::macros::VersionedXcm::from(program)).unwrap(); - let fee_in_wnd = >::query_weight_to_asset_fee(weight, + let fee_in_wnd = >::query_weight_to_asset_fee(weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId(wnd.clone()))).unwrap(); // Assets not in a pool don't work. - assert!(>::query_weight_to_asset_fee(weight, + assert!(>::query_weight_to_asset_fee(weight, $crate::macros::VersionedAssetId::from( $crate::macros::AssetId($crate::macros::Location::new(0, [$crate::macros::PalletInstance($crate::macros::ASSETS_PALLET_ID), @@ -929,7 +953,7 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { ) ) ).is_err()); - let fee_in_usdt_fail = >::query_weight_to_asset_fee(weight, + let fee_in_usdt_fail = >::query_weight_to_asset_fee(weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId(usdt.clone()))); // Weight to asset fee fails because there's not enough asset in the pool. // We just created it, there's none. @@ -953,7 +977,7 @@ macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { sender.into() )); // Now it works. - let fee_in_usdt = >::query_weight_to_asset_fee(weight, + let fee_in_usdt = >::query_weight_to_asset_fee(weight, $crate::macros::VersionedAssetId::from($crate::macros::AssetId(usdt)) ); $crate::macros::assert_ok!(fee_in_usdt); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs index 6e3b893e3f6c..843d1b38c039 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/xcm_fee_estimation.rs @@ -20,7 +20,7 @@ use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees; use frame_support::dispatch::RawOrigin; use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV2, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, }; fn sender_assertions(test: ParaToParaThroughAHTest) { @@ -157,9 +157,13 @@ fn multi_hop_works() { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees, + ) + .unwrap(); delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); @@ -200,9 +204,11 @@ fn multi_hop_works() { // We could've gotten the message from the queue without having to dry-run, but // offchain applications would have to dry-run, so we do it here as well. intermediate_remote_message = messages_to_query[0].clone(); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); let delivery_fees = Runtime::query_delivery_fees( destination_to_query.clone(), intermediate_remote_message.clone(), + asset_id_for_delivery_fees, ) .unwrap(); intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs index 7deaaa9a984f..42da14304e16 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -21,7 +21,7 @@ use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees; use frame_support::dispatch::RawOrigin; use xcm_runtime_apis::{ dry_run::runtime_decl_for_dry_run_api::DryRunApiV2, - fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, }; fn sender_assertions(test: ParaToParaThroughAHTest) { @@ -159,9 +159,13 @@ fn multi_hop_works() { .unwrap(); assert_eq!(messages_to_query.len(), 1); remote_message = messages_to_query[0].clone(); - let delivery_fees = - Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) - .unwrap(); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + asset_id_for_delivery_fees, + ) + .unwrap(); delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); @@ -202,9 +206,11 @@ fn multi_hop_works() { // We could've gotten the message from the queue without having to dry-run, but // offchain applications would have to dry-run, so we do it here as well. intermediate_remote_message = messages_to_query[0].clone(); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); let delivery_fees = Runtime::query_delivery_fees( destination_to_query.clone(), intermediate_remote_message.clone(), + asset_id_for_delivery_fees, ) .unwrap(); intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index df5fab2a8c13..7af8278e6962 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -86,7 +86,7 @@ use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::Weigh use xcm_config::{ ForeignAssetsConvertedConcreteId, GovernanceLocation, LocationToAccountId, PoolAssetsConvertedConcreteId, PoolAssetsPalletLocation, TokenLocation, - TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, + TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, XcmConfig, }; #[cfg(test)] @@ -1565,10 +1565,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -1576,8 +1573,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 82272047561e..3e625b47b14f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -95,7 +95,7 @@ use westend_runtime_constants::time::DAYS as RC_DAYS; use xcm_config::{ ForeignAssetsConvertedConcreteId, LocationToAccountId, PoolAssetsConvertedConcreteId, PoolAssetsPalletLocation, TrustBackedAssetsConvertedConcreteId, - TrustBackedAssetsPalletLocation, WestendLocation, XcmOriginToTransactDispatchOrigin, + TrustBackedAssetsPalletLocation, WestendLocation, XcmConfig, XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -1933,10 +1933,7 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -1944,8 +1941,9 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index e91d44049159..6882d3e5f2f1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -84,7 +84,7 @@ pub use sp_runtime::{MultiAddress, Perbill, Permill}; #[cfg(feature = "runtime-benchmarks")] use xcm::latest::WESTEND_GENESIS_HASH; use xcm::VersionedLocation; -use xcm_config::{TreasuryAccount, XcmOriginToTransactDispatchOrigin, XcmRouter}; +use xcm_config::{TreasuryAccount, XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -874,10 +874,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -885,8 +882,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index c6d35fbeb4e0..ac4839831a56 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -73,7 +73,7 @@ use frame_system::{ }; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{XcmOriginToTransactDispatchOrigin, XcmRouter}; +use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin, XcmRouter}; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -825,10 +825,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -836,8 +833,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index cfb58de0edc8..fa2d28929eac 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -99,7 +99,8 @@ use testnet_parachains_constants::westend::{ account::*, consensus::*, currency::*, fee::WeightToFee, time::*, }; use xcm_config::{ - GovernanceLocation, LocationToAccountId, TreasurerBodyId, XcmOriginToTransactDispatchOrigin, + GovernanceLocation, LocationToAccountId, TreasurerBodyId, XcmConfig, + XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -1013,10 +1014,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -1024,8 +1022,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 9c917a47871c..9b784f208bad 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -80,7 +80,8 @@ use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::Weigh use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::{prelude::*, Version as XcmVersion}; use xcm_config::{ - FellowshipLocation, GovernanceLocation, RocRelayLocation, XcmOriginToTransactDispatchOrigin, + FellowshipLocation, GovernanceLocation, RocRelayLocation, XcmConfig, + XcmOriginToTransactDispatchOrigin, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -860,10 +861,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -871,8 +869,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 202975651725..1984cac07777 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -80,7 +80,8 @@ use testnet_parachains_constants::westend::{consensus::*, currency::*, fee::Weig use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::{prelude::*, Version as XcmVersion}; use xcm_config::{ - FellowshipLocation, GovernanceLocation, TokenRelayLocation, XcmOriginToTransactDispatchOrigin, + FellowshipLocation, GovernanceLocation, TokenRelayLocation, XcmConfig, + XcmOriginToTransactDispatchOrigin, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -860,10 +861,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -871,8 +869,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 64bb07ec2e96..c6131044611c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -808,10 +808,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -819,8 +816,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 90811831c731..95077fcbf10e 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -810,10 +810,7 @@ impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -821,8 +818,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 4216f76bd772..536b3776c148 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -97,7 +97,9 @@ pub use sp_runtime::{traits::ConvertInto, MultiAddress, Perbill, Permill}; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm_config::{ForeignAssetsAssetId, LocationToAccountId, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{ + ForeignAssetsAssetId, LocationToAccountId, XcmConfig, XcmOriginToTransactDispatchOrigin, +}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -1067,10 +1069,7 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - PolkadotXcm::query_weight_to_asset_fee::(weight, asset) } @@ -1078,8 +1077,9 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 1e0518511976..65e17bca1392 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -150,6 +150,7 @@ use governance::{ pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer, TreasurySpender, }; +use xcm_config::XcmConfig; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, @@ -1922,10 +1923,7 @@ sp_api::impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - XcmPallet::query_weight_to_asset_fee::(weight, asset) } @@ -1933,8 +1931,9 @@ sp_api::impl_runtime_apis! { XcmPallet::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - XcmPallet::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + XcmPallet::query_delivery_fees::(destination, message, asset_id) } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 631cdec8a9bf..b483969b3c3a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -151,6 +151,7 @@ use governance::{ pallet_custom_origins, AuctionAdmin, FellowshipAdmin, GeneralAdmin, LeaseAdmin, StakingAdmin, Treasurer, TreasurySpender, }; +use xcm_config::XcmConfig; #[cfg(test)] mod tests; @@ -2719,10 +2720,7 @@ sp_api::impl_runtime_apis! { } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - use crate::xcm_config::XcmConfig; - type Trader = ::Trader; - XcmPallet::query_weight_to_asset_fee::(weight, asset) } @@ -2730,8 +2728,9 @@ sp_api::impl_runtime_apis! { XcmPallet::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - XcmPallet::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + XcmPallet::query_delivery_fees::(destination, message, asset_id) } } diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 3881356ae40f..5667b190f9d3 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -3276,9 +3276,15 @@ impl Pallet { } /// Given a `destination` and XCM `message`, return assets to be charged as XCM delivery fees. - pub fn query_delivery_fees( + /// + /// Meant to be called by the `XcmPaymentApi`. + /// It's necessary to specify the asset in which fees are desired. + /// + /// NOTE: Only use this if delivery fees consist of only 1 asset, else this function will error. + pub fn query_delivery_fees( destination: VersionedLocation, message: VersionedXcm<()>, + versioned_asset_id: VersionedAssetId, ) -> Result { let result_version = destination.identify_version().max(message.identify_version()); @@ -3301,12 +3307,39 @@ impl Pallet { XcmPaymentApiError::Unroutable })?; - VersionedAssets::from(fees) - .into_version(result_version) - .map_err(|e| { - tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?result_version, "Failed to convert fees into version"); - XcmPaymentApiError::VersionedConversionFailed - }) + let fee = fees.get(0).ok_or(XcmPaymentApiError::Unimplemented)?; + + let asset_id = versioned_asset_id.clone().try_into().map_err(|()| { + tracing::trace!( + target: "xcm::xcm_runtime_apis::query_delivery_fees", + "Failed to convert asset id: {versioned_asset_id:?}!" + ); + XcmPaymentApiError::VersionedConversionFailed + })?; + + let assets_to_pay = if fee.id == asset_id { + // If the fee asset is the same as the desired one, just return that. + vec![fee.clone()].into() + } else { + // Call AssetExchanger::quote_exchange_price() and return that. + let assets = AssetExchanger::quote_exchange_price( + &(vec![fee.clone()]).into(), + &(asset_id, Fungible(0)).into(), + true, // Maximal. + ) + .ok_or(XcmPaymentApiError::AssetNotFound)?; + assets + }; + + VersionedAssets::from(assets_to_pay).into_version(result_version).map_err(|e| { + tracing::trace!( + target: "xcm::pallet_xcm::query_delivery_fees", + ?e, + ?result_version, + "Failed to convert fees into desired version" + ); + XcmPaymentApiError::VersionedConversionFailed + }) } /// Given an Asset and a Location, returns if the provided location is a trusted reserve for the diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 510251567b2e..da9f78524173 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -495,8 +495,8 @@ sp_api::mock_impl_runtime_apis! { } } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, _asset_id: VersionedAssetId) -> Result { - XcmPallet::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + XcmPallet::query_delivery_fees::<::AssetExchanger>(destination, message, asset_id) } } From 4dad62dc5570494580ea6e4c016146c4a5db7af8 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 10 Oct 2025 19:38:06 -0300 Subject: [PATCH 03/17] test: add test in xcm-runtime-apis and asset-hub-westend-integration-tests --- .../src/tests/xcm_fee_estimation.rs | 194 +++++++++++++++++- polkadot/xcm/xcm-executor/src/lib.rs | 2 +- .../xcm-runtime-apis/tests/fee_estimation.rs | 102 +++++++++ polkadot/xcm/xcm-runtime-apis/tests/mock.rs | 120 +++++++++-- 4 files changed, 401 insertions(+), 17 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs index 42da14304e16..49eca8046d3f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -15,7 +15,7 @@ //! Tests to ensure correct XCM fee estimation for cross-chain asset transfers. -use crate::imports::*; +use crate::{create_pool_with_wnd_on, imports::*}; use emulated_integration_tests_common::test_can_estimate_and_pay_exact_fees; use frame_support::dispatch::RawOrigin; @@ -24,6 +24,57 @@ use xcm_runtime_apis::{ fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, }; +fn usdt_transfer_call( + destination: Location, + beneficiary: Location, + amount_to_send: u128, + usdt_location_on_penpal: Location, + usdt_location_on_ah: Location, +) -> ::RuntimeCall { + let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + + // Create the XCM to transfer USDT to PenpalB via Asset Hub using InitiateTransfer + let remote_xcm_on_penpal_b = + Xcm::<()>(vec![DepositAsset { assets: Wild(AllCounted(1)), beneficiary }]); + + let xcm_on_asset_hub = Xcm::<()>(vec![InitiateTransfer { + destination, + remote_fees: Some(AssetTransferFilter::ReserveDeposit( + Definite((usdt_location_on_ah, 1_000_000u128).into()), // 1 USDT for fees + )), + preserve_origin: false, + assets: BoundedVec::truncate_from(vec![AssetTransferFilter::ReserveDeposit(Wild(All))]), + remote_xcm: remote_xcm_on_penpal_b, + }]); + + let xcm = Xcm::<::RuntimeCall>(vec![ + WithdrawAsset((usdt_location_on_penpal.clone(), amount_to_send).into()), + PayFees { + asset: Asset { + id: AssetId(usdt_location_on_penpal.clone()), + fun: Fungible(1_000_000u128), // 1 USDT for local fees + }, + }, + InitiateTransfer { + destination: asset_hub_location, + remote_fees: Some(AssetTransferFilter::ReserveWithdraw( + Definite((usdt_location_on_penpal.clone(), 1_000_000u128).into()), /* 1 USDT for + * Asset Hub fees */ + )), + preserve_origin: false, + assets: BoundedVec::truncate_from(vec![AssetTransferFilter::ReserveWithdraw(Wild( + All, + ))]), + remote_xcm: xcm_on_asset_hub, + }, + ]); + + ::RuntimeCall::PolkadotXcm(pallet_xcm::Call::execute { + message: bx!(VersionedXcm::from(xcm)), + max_weight: Weight::MAX, + }) +} + fn sender_assertions(test: ParaToParaThroughAHTest) { type RuntimeEvent = ::RuntimeEvent; PenpalA::assert_xcm_pallet_attempted_complete(None); @@ -85,11 +136,20 @@ fn transfer_assets_para_to_para_through_ah_call( assets: Wild(AllCounted(test.args.assets.len() as u32)), beneficiary: test.args.beneficiary, }]); + let remote_fee_id: AssetId = test + .args + .assets + .clone() + .into_inner() + .get(test.args.fee_asset_item as usize) + .expect("asset in index fee_asset_item should exist") + .clone() + .id; RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets_using_type_and_then { dest: bx!(test.args.dest.into()), assets: bx!(test.args.assets.clone().into()), assets_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - remote_fees_id: bx!(VersionedAssetId::from(AssetId(Location::parent()))), + remote_fees_id: bx!(VersionedAssetId::from(remote_fee_id)), fees_transfer_type: bx!(TransferType::RemoteReserve(asset_hub_location.into())), custom_xcm_on_dest: bx!(VersionedXcm::from(custom_xcm_on_dest)), weight_limit: test.args.weight_limit, @@ -293,3 +353,133 @@ fn multi_hop_pay_fees_works() { Penpal ); } + +/// We are able to estimate delivery fees in USDT for a USDT transfer from PenpalA to PenpalB via +/// Asset Hub. Scenario: Alice on PenpalA has some USDT and wants to send them to PenpalB. +/// We want to estimate the delivery fees in USDT using the new `asset_id` parameter in +/// `query_delivery_fees`. +#[test] +fn usdt_fee_estimation_in_usdt_works() { + use emulated_integration_tests_common::USDT_ID; + + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send = 10_000_000; // 10 USDT (6 decimals) + + // USDT location from PenpalA's perspective + let usdt_location_on_penpal = PenpalUsdtFromAssetHub::get(); + + // USDT location from Asset Hub's perspective + let usdt_location_on_ah = + Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]); + + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_of_penpal_on_ah = + AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah.clone()); + + // fund PenpalA's sender account with USDT + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + usdt_location_on_penpal.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // fund PenpalA's sovereign account on AssetHub with USDT + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + USDT_ID, + sov_of_penpal_on_ah.clone(), + amount_to_send * 2, + ); + + // Create a liquidity pool between WND (relay token) and USDT on AssetHub + // This is needed for the asset conversion in fee estimation + create_pool_with_wnd_on!( + AssetHubWestend, + usdt_location_on_ah.clone(), + false, + AssetHubWestendSender::get(), + 1_000_000_000_000, // 1 WND + 2_000_000 // 2 USDT (1:2 ratio) + ); + + // Create a liquidity pool between WND and USDT on PenpalA as well + // This is needed for PenpalA to perform asset conversion for fee estimation + create_pool_with_wnd_on!( + PenpalA, + usdt_location_on_penpal.clone(), + true, + PenpalAssetOwner::get(), + 1_000_000_000_000, // 1 WND + 2_000_000 // 2 USDT (1:2 ratio) + ); + + let beneficiary_id = PenpalBReceiver::get(); + let assets: Assets = (usdt_location_on_penpal.clone(), amount_to_send).into(); + + // We get the delivery fees from the PenpalA closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::from(Xcm(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type OriginCaller = ::OriginCaller; + + let call = usdt_transfer_call( + destination.clone(), + beneficiary_id.clone().into(), + amount_to_send, + usdt_location_on_penpal.clone(), + usdt_location_on_ah.clone(), + ); + + let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); + + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call, xcm::prelude::XCM_VERSION).unwrap(); + + // Find the message sent to Asset Hub + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::from(asset_hub_location.clone()) + }) + .unwrap(); + + assert_eq!(messages_to_query.len(), 1); + remote_message = messages_to_query[0].clone(); + + // Query delivery fees in USDT using the new asset_id parameter + let usdt_asset_id = VersionedAssetId::from(AssetId(usdt_location_on_penpal.clone())); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + remote_message.clone(), + usdt_asset_id, + ) + .unwrap(); + + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees.clone()); + + // Verify the fees are quoted in USDT (the delivery fees should be converted from native to + // USDT) + let fee_assets = match delivery_fees { + VersionedAssets::V5(assets) => assets, + _ => panic!("Expected V5 assets"), + }; + + // Should have one asset (USDT) + assert_eq!(fee_assets.len(), 1); + let fee_asset = fee_assets.get(0).unwrap(); + + // Verify it's USDT + assert_eq!(fee_asset.id.0, usdt_location_on_penpal); + + // Verify we get a reasonable USDT amount (delivery fees should be > 0) + if let Fungible(amount) = fee_asset.fun { + assert!(amount > 0, "Delivery fees should be greater than 0"); + } else { + panic!("Expected fungible delivery fees"); + } + }); +} diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index b4efab9349a4..0fea337a4ef3 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -666,7 +666,7 @@ impl XcmExecutor { /// charged for swapping to `asset_needed_for_fees`. /// /// The calculation is done by `Config::AssetExchanger`. - /// If neither `PayFees` or `BuyExecution` were not used, or no swap is required, + /// If neither `PayFees` or `BuyExecution` were used, or no swap is required, /// it will just return `asset_needed_for_fees`. fn calculate_asset_for_delivery_fees(&self, asset_needed_for_fees: Asset) -> Asset { let Some(asset_wanted_for_fees) = diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index ed772f741992..17d3ae1c06b5 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -29,6 +29,7 @@ mod mock; use mock::{ new_test_ext_with_balances, new_test_ext_with_balances_and_assets, DeliveryFees, ExistentialDeposit, HereLocation, OriginCaller, RuntimeCall, RuntimeEvent, TestClient, + ASSET_HUB_ASSETS_PALLET_INSTANCE, ASSET_HUB_PARA_ID, USDT_ID, }; use xcm_simulator::fake_message_hash; @@ -467,3 +468,104 @@ fn calling_payment_api_with_a_lower_version_works() { .unwrap(); assert!(execution_fees.is_ok()); } + +// Test fee estimation for USDT reserve transfer with delivery fees in USDT. +// In this scenario, we're sending USDT from parachain 2000 to parachain 1000 (AssetHub). +// Since USDT is native to AssetHub, this will be a destination reserve transfer. +// We request the delivery fees to be quoted in USDT using the asset_id parameter in +// `query_delivery_fees`. +// +// Reserve Asset Transfer USDT +// Delivery fees in USDT +// Parachain(2000) -------------------------------------------> Parachain(1000) +#[test] +fn fee_estimation_for_usdt_reserve_transfer_in_usdt() { + sp_tracing::init_for_tests(); + let who = 1; // AccountId = u64. + let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())]; // Just enough for fees + let assets = vec![ + (1984, who, 1000), // USDT (asset ID 1984) - amount to transfer plus fees + ]; + new_test_ext_with_balances_and_assets(balances, assets).execute_with(|| { + let client = TestClient; + let runtime_api = client.runtime_api(); + + // USDT location from our parachain (2000) perspective + let usdt_location = Location::new( + 1, + [ + Parachain(ASSET_HUB_PARA_ID), + PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), + GeneralIndex(USDT_ID.into()), + ], + ); + // USDT location from Asset Hub's perspective + let usdt_location_ah_pov = Location::new( + 0, + [PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), GeneralIndex(USDT_ID.into())], + ); + + let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::from((Parent, Parachain(1000)))), + beneficiary: Box::new(VersionedLocation::from(AccountId32 { + id: [0u8; 32], + network: None, + })), + assets: Box::new(VersionedAssets::from(vec![ + (usdt_location.clone(), 100u128).into(), // Send 100 USDT + ])), + fee_asset_item: 0, // Fees are paid with USDT (the only asset) + weight_limit: Unlimited, + }); + let origin = OriginCaller::system(RawOrigin::Signed(who)); + let dry_run_effects = runtime_api + .dry_run_call(H256::zero(), origin, call, XCM_VERSION) + .unwrap() + .unwrap(); + + // For destination reserve transfer, we burn the assets locally + assert_eq!( + dry_run_effects.local_xcm, + Some(VersionedXcm::from( + Xcm::builder_unsafe() + .withdraw_asset((usdt_location.clone(), 100u128)) + .burn_asset((usdt_location.clone(), 100u128)) + .build() + )), + ); + + let send_destination = Location::new(1, [Parachain(1000)]); + // For destination reserve, the remote message withdraws the assets from the sovereign + // account + let send_message = Xcm::<()>::builder_unsafe() + .withdraw_asset((usdt_location_ah_pov.clone(), 100u128)) + .clear_origin() + .buy_execution((usdt_location_ah_pov.clone(), 100u128), Unlimited) + .deposit_asset(AllCounted(1), [0u8; 32]) + .build(); + assert_eq!( + dry_run_effects.forwarded_xcms, + vec![( + VersionedLocation::from(send_destination.clone()), + vec![VersionedXcm::from(send_message.clone())], + ),], + ); + + let mut forwarded_xcms_iter = dry_run_effects.forwarded_xcms.into_iter(); + let (destination, remote_messages) = forwarded_xcms_iter.next().unwrap(); + let remote_message = &remote_messages[0]; + + // Query delivery fees in USDT asset using the `asset_id` parameter. + let usdt_asset_id = VersionedAssetId::from(AssetId(usdt_location.clone())); + + let delivery_fees_usdt = runtime_api + .query_delivery_fees(H256::zero(), destination, remote_message.clone(), usdt_asset_id) + .unwrap() + .unwrap(); + + // With our MockAssetExchanger, we expect fees in USDT at a 1:2 conversion rate. + // Native delivery fee is `DeliveryFees::get()`, so USDT fee should be twice that. + let expected_usdt_fees = VersionedAssets::from((usdt_location, DeliveryFees::get() * 2)); + assert_eq!(delivery_fees_usdt, expected_usdt_fees); + }); +} diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index da9f78524173..583a923cc6d2 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -22,13 +22,14 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, sp_runtime, sp_runtime::{ traits::{Get, IdentityLookup, MaybeEquivalence, TryConvert}, - BuildStorage, SaturatedConversion, + BuildStorage, Permill, SaturatedConversion, }, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Disabled, Everything, Nothing, OriginTrait, }, weights::WeightToFee as WeightToFeeT, + PalletId, }; use frame_system::{EnsureRoot, RawOrigin as SystemRawOrigin}; use pallet_xcm::TestWeightInfo; @@ -90,6 +91,7 @@ impl pallet_balances::Config for TestRuntime { type ExistentialDeposit = ExistentialDeposit; } +// Assets instance #[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] impl pallet_assets::Config for TestRuntime { type AssetId = AssetIdForAssetsPallet; @@ -153,9 +155,9 @@ impl InspectMessageQueues for TestXcmSender { pub type XcmRouter = TestXcmSender; parameter_types! { - pub const DeliveryFees: u128 = 20; // Random value. - pub const ExistentialDeposit: u128 = 1; // Random value. - pub const BaseXcmWeight: Weight = Weight::from_parts(100, 10); // Random value. + pub const DeliveryFees: u128 = 20; // Arbitrary value. + pub const ExistentialDeposit: u128 = 1; // Arbitrary value. + pub const BaseXcmWeight: Weight = Weight::from_parts(100, 10); // Arbitrary value. pub const MaxInstructions: u32 = 100; pub const NativeTokenPerSecondPerByte: (AssetId, u128, u128) = (AssetId(HereLocation::get()), 1, 1); pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(2000)].into(); @@ -185,17 +187,29 @@ type Weigher = FixedWeightBounds; pub struct NativeTokenToAssetHub; impl ContainsPair for NativeTokenToAssetHub { fn contains(asset: &Asset, origin: &Location) -> bool { - matches!(asset.id.0.unpack(), (0, [])) && matches!(origin.unpack(), (1, [Parachain(1000)])) + matches!(asset.id.0.unpack(), (0, [])) && + matches!(origin.unpack(), (1, [Parachain(ASSET_HUB_PARA_ID)])) } } -/// Matches the pair (RelayToken, AssetHub). +/// Parachain id of Asset Hub. +pub const ASSET_HUB_PARA_ID: u32 = 1000; +/// The instance index of the trust-backed assets pallet in Asset Hub. +pub const ASSET_HUB_ASSETS_PALLET_INSTANCE: u8 = 50; +/// Id of USDT in Asset Hub. +pub const USDT_ID: u32 = 1984; + +/// Matches the pairs (RelayToken, AssetHub) and (UsdtToken, AssetHub). /// This is used in the `IsReserve` configuration item, meaning we accept the relay token /// coming from AssetHub as a reserve asset transfer. -pub struct RelayTokenToAssetHub; -impl ContainsPair for RelayTokenToAssetHub { +pub struct RelayTokenAndUsdtToAssetHub; +impl ContainsPair for RelayTokenAndUsdtToAssetHub { fn contains(asset: &Asset, origin: &Location) -> bool { - matches!(asset.id.0.unpack(), (1, [])) && matches!(origin.unpack(), (1, [Parachain(1000)])) + let is_asset_hub = matches!(origin.unpack(), (1, [Parachain(ASSET_HUB_PARA_ID)])); + let is_relay_token = matches!(asset.id.0.unpack(), (1, [])); + let is_usdt = matches!(asset.id.0.unpack(), (1, [Parachain(ASSET_HUB_PARA_ID), PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), GeneralIndex(asset_id)]) if *asset_id == USDT_ID.into()); + + is_asset_hub && (is_relay_token || is_usdt) } } @@ -243,11 +257,16 @@ pub type NativeTokenTransactor = FungibleAdapter< LocalCheckAccount, >; +/// Converter from Location to local asset id and viceversa. pub struct LocationToAssetIdForAssetsPallet; impl MaybeEquivalence for LocationToAssetIdForAssetsPallet { fn convert(location: &Location) -> Option { match location.unpack() { (1, []) => Some(1 as AssetIdForAssetsPallet), + ( + 1, + [Parachain(ASSET_HUB_PARA_ID), PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), GeneralIndex(asset_id)], + ) if *asset_id == USDT_ID.into() => Some(USDT_ID as AssetIdForAssetsPallet), _ => None, } } @@ -255,13 +274,21 @@ impl MaybeEquivalence for LocationToAssetIdFor fn convert_back(id: &AssetIdForAssetsPallet) -> Option { match id { 1 => Some(Location::new(1, [])), + asset_id if *asset_id == USDT_ID => Some(Location::new( + 1, + [ + Parachain(ASSET_HUB_PARA_ID), + PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), + GeneralIndex(USDT_ID.into()), + ], + )), _ => None, } } } -/// AssetTransactor for handling the relay chain token. -pub type RelayTokenTransactor = FungiblesAdapter< +/// AssetTransactor for handling assets other than the native one. +pub type AssetsTransactor = FungiblesAdapter< // We use pallet-assets for handling the relay token. AssetsPallet, // Matches the relay token. @@ -275,7 +302,7 @@ pub type RelayTokenTransactor = FungiblesAdapter< (), >; -pub type AssetTransactors = (NativeTokenTransactor, RelayTokenTransactor); +pub type AssetTransactors = (NativeTokenTransactor, AssetsTransactor); pub struct HereAndInnerLocations; impl Contains for HereAndInnerLocations { @@ -299,7 +326,7 @@ impl xcm_executor::Config for XcmConfig { type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = (); - type IsReserve = RelayTokenToAssetHub; + type IsReserve = RelayTokenAndUsdtToAssetHub; type IsTeleporter = NativeTokenToAssetHub; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -308,7 +335,7 @@ impl xcm_executor::Config for XcmConfig { type ResponseHandler = (); type AssetTrap = (); type AssetLocker = (); - type AssetExchanger = (); + type AssetExchanger = MockAssetExchanger; type AssetClaims = (); type SubscriptionService = (); type PalletInstancesInfo = AllPalletsWithSystem; @@ -326,6 +353,69 @@ impl xcm_executor::Config for XcmConfig { type XcmRecorder = XcmPallet; } +/// Mock AssetExchanger that recognizes USDT and provides a 1:2 exchange rate +/// (1 native token = 2 USDT tokens) +pub struct MockAssetExchanger; +impl xcm_executor::traits::AssetExchange for MockAssetExchanger { + fn exchange_asset( + _origin: Option<&Location>, + give: xcm_executor::AssetsInHolding, + want: &Assets, + _maximal: bool, + ) -> Result { + let usdt_location = Location::new( + 1, + [ + Parachain(ASSET_HUB_PARA_ID), + PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), + GeneralIndex(USDT_ID.into()), + ], + ); + + // Check if we're trying to exchange native asset for USDT + if let Some(give_asset) = give.fungible.get(&AssetId(HereLocation::get())) { + if let Some(want_asset) = want.get(0) { + if want_asset.id.0 == usdt_location { + // Convert native asset to USDT at 1:2 rate + let usdt_amount = give_asset.saturating_mul(2); + let mut result = xcm_executor::AssetsInHolding::new(); + let _ = result.subsume((AssetId(usdt_location), usdt_amount).into()); + return Ok(result); + } + } + } + + // If we can't handle the exchange, return the original assets + Err(give) + } + + fn quote_exchange_price(give: &Assets, want: &Assets, _maximal: bool) -> Option { + let usdt_location = Location::new( + 1, + [ + Parachain(ASSET_HUB_PARA_ID), + PalletInstance(ASSET_HUB_ASSETS_PALLET_INSTANCE), + GeneralIndex(USDT_ID.into()), + ], + ); + + // Check if we're trying to quote native asset for USDT + if let Some(give_asset) = give.get(0) { + if let Some(want_asset) = want.get(0) { + if give_asset.id.0 == HereLocation::get() && want_asset.id.0 == usdt_location { + if let Fungible(amount) = give_asset.fun { + // Return the USDT amount we'd get at 1:2 rate + let usdt_amount = amount.saturating_mul(2); + return Some((AssetId(usdt_location), usdt_amount).into()); + } + } + } + } + + None + } +} + /// Converts a signed origin of a u64 account into a location with only the `AccountIndex64` /// junction. pub struct SignedToAccountIndex64( @@ -408,10 +498,12 @@ pub fn new_test_ext_with_balances_and_assets( // We don't actually need this to be sufficient, since we use the native assets in // tests for the existential deposit. (1, 0, true, 1), + (1984, 0, true, 1), ], metadata: vec![ // id, name, symbol, decimals. (1, "Relay Token".into(), "RLY".into(), 12), + (1984, "Tether".into(), "USDT".into(), 6), ], accounts: assets, next_asset_id: None, From a251daea7919d58d4e862cce780ca43198b2c6cb Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 22:42:51 +0000 Subject: [PATCH 04/17] Update from github-actions[bot] running command 'prdoc --audience runtime_dev --bump major' --- prdoc/pr_9963.prdoc | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 prdoc/pr_9963.prdoc diff --git a/prdoc/pr_9963.prdoc b/prdoc/pr_9963.prdoc new file mode 100644 index 000000000000..8ba955e84766 --- /dev/null +++ b/prdoc/pr_9963.prdoc @@ -0,0 +1,49 @@ +title: Query delivery fees v2 +doc: +- audience: Runtime Dev + description: |- + Fixes https://github.com/paritytech/polkadot-sdk/issues/7061 + + Continuation of https://github.com/paritytech/polkadot-sdk/pull/8297 + + ## TODO + - [x] Add parameter to runtime API + - [x] Add parameter to pallet-xcm helper + - [x] Test querying delivery fee in an asset other than native +crates: +- name: asset-hub-rococo-runtime + bump: major +- name: asset-hub-westend-runtime + bump: major +- name: asset-test-utils + bump: major +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: major +- name: collectives-westend-runtime + bump: major +- name: coretime-rococo-runtime + bump: major +- name: coretime-westend-runtime + bump: major +- name: people-rococo-runtime + bump: major +- name: people-westend-runtime + bump: major +- name: parachains-runtimes-test-utils + bump: major +- name: penpal-runtime + bump: major +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: xcm-runtime-apis + bump: major +- name: emulated-integration-tests-common + bump: major +- name: pallet-xcm + bump: major +- name: staging-xcm-executor + bump: major From 97d6c935cd776158d9421a4c75c22522a7b8f34d Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 10 Oct 2025 19:49:17 -0300 Subject: [PATCH 05/17] Update prdoc/pr_9963.prdoc --- prdoc/pr_9963.prdoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prdoc/pr_9963.prdoc b/prdoc/pr_9963.prdoc index 8ba955e84766..d710595a7b7a 100644 --- a/prdoc/pr_9963.prdoc +++ b/prdoc/pr_9963.prdoc @@ -2,6 +2,10 @@ title: Query delivery fees v2 doc: - audience: Runtime Dev description: |- + BREAKING CHANGE + + Adds a new parameter to `XcmPaymentApi.query_delivery_fees` to specify the asset id in which you'd like to get the delivery fees. This makes it possible to estimate how much to pay for fees for assets other than the native asset. + Fixes https://github.com/paritytech/polkadot-sdk/issues/7061 Continuation of https://github.com/paritytech/polkadot-sdk/pull/8297 From 3810a16db4f568ef392c4f67d70ee1a032137074 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 10 Oct 2025 19:49:23 -0300 Subject: [PATCH 06/17] Update prdoc/pr_9963.prdoc --- prdoc/pr_9963.prdoc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/prdoc/pr_9963.prdoc b/prdoc/pr_9963.prdoc index d710595a7b7a..e8614adb8405 100644 --- a/prdoc/pr_9963.prdoc +++ b/prdoc/pr_9963.prdoc @@ -9,11 +9,6 @@ doc: Fixes https://github.com/paritytech/polkadot-sdk/issues/7061 Continuation of https://github.com/paritytech/polkadot-sdk/pull/8297 - - ## TODO - - [x] Add parameter to runtime API - - [x] Add parameter to pallet-xcm helper - - [x] Test querying delivery fee in an asset other than native crates: - name: asset-hub-rococo-runtime bump: major From d110c337e49109d9d3874ccd251f26e8f051559c Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 20 Oct 2025 12:37:49 -0300 Subject: [PATCH 07/17] fix: ci --- polkadot/node/service/src/fake_runtime_api.rs | 2 +- polkadot/xcm/xcm-runtime-apis/tests/mock.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index e761f0e84f6b..6cdcd6255aba 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -440,7 +440,7 @@ sp_api::impl_runtime_apis! { unimplemented!() } - fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { + fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>, _: VersionedAssetId) -> Result { unimplemented!() } } diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 43655641f8db..1070fb60c790 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -22,14 +22,13 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, sp_runtime, sp_runtime::{ traits::{Get, IdentityLookup, MaybeEquivalence, TryConvert}, - BuildStorage, Permill, SaturatedConversion, + BuildStorage, SaturatedConversion, }, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Disabled, Everything, Nothing, OriginTrait, }, weights::WeightToFee as WeightToFeeT, - PalletId, }; use frame_system::{EnsureRoot, RawOrigin as SystemRawOrigin}; use pallet_xcm::TestWeightInfo; From acc0134ec3b1d3d9a7e343cf724b4ccdcbf962b1 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 20 Oct 2025 12:48:34 -0300 Subject: [PATCH 08/17] fix(pallet-staking-async): add the asset_id parameter --- substrate/frame/staking-async/runtimes/parachain/src/lib.rs | 5 +++-- substrate/frame/staking-async/runtimes/rc/src/lib.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs index d587ef148e92..fce2969db40e 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs @@ -1609,8 +1609,9 @@ impl_runtime_apis! { PolkadotXcm::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { - PolkadotXcm::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/substrate/frame/staking-async/runtimes/rc/src/lib.rs b/substrate/frame/staking-async/runtimes/rc/src/lib.rs index c07a969965fd..557515cdb082 100644 --- a/substrate/frame/staking-async/runtimes/rc/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/rc/src/lib.rs @@ -2671,8 +2671,9 @@ sp_api::impl_runtime_apis! { XcmPallet::query_xcm_weight(message) } - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { - XcmPallet::query_delivery_fees(destination, message) + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { + type AssetExchanger = ::AssetExchanger; + XcmPallet::query_delivery_fees::(destination, message, asset_id) } } From c556fbf831bc01751aae220825767053e13f88c1 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 20 Oct 2025 14:13:45 -0300 Subject: [PATCH 09/17] ignore let binding --- polkadot/xcm/xcm-runtime-apis/tests/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 1070fb60c790..8aca9cce12a3 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -378,7 +378,7 @@ impl xcm_executor::traits::AssetExchange for MockAssetExchanger { // Convert native asset to USDT at 1:2 rate let usdt_amount = give_asset.saturating_mul(2); let mut result = xcm_executor::AssetsInHolding::new(); - let _ = result.subsume((AssetId(usdt_location), usdt_amount).into()); + result.subsume((AssetId(usdt_location), usdt_amount).into()); return Ok(result); } } From 3754b5c16dbe2f620360392f2b4bf731e2a1a932 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 20 Oct 2025 14:32:35 -0300 Subject: [PATCH 10/17] fix(pallet-staking-async): import XcmConfig correctly --- substrate/frame/staking-async/runtimes/parachain/src/lib.rs | 2 +- substrate/frame/staking-async/runtimes/rc/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs index fce2969db40e..1749c6c9f564 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs @@ -1610,7 +1610,7 @@ impl_runtime_apis! { } fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { - type AssetExchanger = ::AssetExchanger; + type AssetExchanger = ::AssetExchanger; PolkadotXcm::query_delivery_fees::(destination, message, asset_id) } } diff --git a/substrate/frame/staking-async/runtimes/rc/src/lib.rs b/substrate/frame/staking-async/runtimes/rc/src/lib.rs index 557515cdb082..059c6c617187 100644 --- a/substrate/frame/staking-async/runtimes/rc/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/rc/src/lib.rs @@ -2672,7 +2672,7 @@ sp_api::impl_runtime_apis! { } fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>, asset_id: VersionedAssetId) -> Result { - type AssetExchanger = ::AssetExchanger; + type AssetExchanger = ::AssetExchanger; XcmPallet::query_delivery_fees::(destination, message, asset_id) } } From 9ac267e68d6cb446c90d547477196a51982c5cab Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 20 Oct 2025 15:01:53 -0300 Subject: [PATCH 11/17] fix: clippy --- .../assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs index 49eca8046d3f..3fc49ae4e6f2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -416,7 +416,6 @@ fn usdt_fee_estimation_in_usdt_works() { ); let beneficiary_id = PenpalBReceiver::get(); - let assets: Assets = (usdt_location_on_penpal.clone(), amount_to_send).into(); // We get the delivery fees from the PenpalA closure. let mut delivery_fees_amount = 0; From b59602704a39bed2bb7213ba4fee5ed20b1ec258 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 24 Oct 2025 15:39:08 -0300 Subject: [PATCH 12/17] fix: tests --- .../parachains/integration-tests/emulated/common/src/macros.rs | 2 +- .../runtimes/coretime/coretime-rococo/src/xcm_config.rs | 2 +- .../parachains/runtimes/people/people-rococo/src/xcm_config.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index ee9047e450e1..9d0e595c47a3 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -420,7 +420,7 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { remote_message = messages_to_query[0].clone(); // The native asset of every system chain. // We want to get the delivery fees in this asset. - let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(1, [])); + let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent()); let delivery_fees = >::query_delivery_fees( destination_to_query.clone(), diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 3dcc258abb65..8cf14d103f1c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -249,7 +249,7 @@ pub type PriceForParentDelivery = /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index 4adbf02d9e58..8f2a89a268ee 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -247,7 +247,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From 18b957c6d62d4c0e422324d10b1f83b5bfa2fe5d Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 24 Oct 2025 16:24:18 -0300 Subject: [PATCH 13/17] fix: tests --- .../parachains/runtimes/people/people-westend/src/xcm_config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 9cb1a96036b4..e5203f39c881 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -288,7 +288,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From 87e85bfd5795c783af2f697c6b710eb92b56b66b Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 24 Oct 2025 20:14:09 -0300 Subject: [PATCH 14/17] fix: tests --- .../runtimes/coretime/coretime-westend/src/xcm_config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 7061f9cb1338..391972f24572 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -285,7 +285,7 @@ pub type PriceForParentDelivery = /// queues. pub type XcmRouter = WithUniqueTopic<( // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From fdaf1845e2b356b1d5af15d5d9a8bba892b7e1f7 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 27 Oct 2025 10:35:15 -0300 Subject: [PATCH 15/17] chore: feedback --- polkadot/xcm/pallet-xcm/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index e2ab0c369e1f..357f1bc9b0f7 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -3304,6 +3304,11 @@ impl Pallet { XcmPaymentApiError::Unroutable })?; + // This helper only works for routers that return 1 and only 1 asset for delivery fees. + if fees.len() != 1 { + return Err(XcmPaymentApiError::Unimplemented); + } + let fee = fees.get(0).ok_or(XcmPaymentApiError::Unimplemented)?; let asset_id = versioned_asset_id.clone().try_into().map_err(|()| { @@ -3316,11 +3321,11 @@ impl Pallet { let assets_to_pay = if fee.id == asset_id { // If the fee asset is the same as the desired one, just return that. - vec![fee.clone()].into() + fees } else { // Call AssetExchanger::quote_exchange_price() and return that. let assets = AssetExchanger::quote_exchange_price( - &(vec![fee.clone()]).into(), + &fees.into(), &(asset_id, Fungible(0)).into(), true, // Maximal. ) From 3e704fef974fbf329cea4649ad5701ffa360df18 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 28 Oct 2025 14:32:27 -0300 Subject: [PATCH 16/17] Update polkadot/xcm/pallet-xcm/src/lib.rs Co-authored-by: Branislav Kontur --- polkadot/xcm/pallet-xcm/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 357f1bc9b0f7..b2318e8a4b26 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -3323,14 +3323,13 @@ impl Pallet { // If the fee asset is the same as the desired one, just return that. fees } else { - // Call AssetExchanger::quote_exchange_price() and return that. - let assets = AssetExchanger::quote_exchange_price( + // Call AssetExchanger::quote_exchange_price(). + AssetExchanger::quote_exchange_price( &fees.into(), &(asset_id, Fungible(0)).into(), true, // Maximal. ) - .ok_or(XcmPaymentApiError::AssetNotFound)?; - assets + .ok_or(XcmPaymentApiError::AssetNotFound)? }; VersionedAssets::from(assets_to_pay).into_version(result_version).map_err(|e| { From 566c3f320841178dff2192a73547e23e740c4d3a Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 28 Oct 2025 14:44:40 -0300 Subject: [PATCH 17/17] chore: feedback --- polkadot/xcm/pallet-xcm/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index b2318e8a4b26..7d286b88493e 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -3323,10 +3323,10 @@ impl Pallet { // If the fee asset is the same as the desired one, just return that. fees } else { - // Call AssetExchanger::quote_exchange_price(). + // We get the fees in the desired asset. AssetExchanger::quote_exchange_price( &fees.into(), - &(asset_id, Fungible(0)).into(), + &(asset_id, Fungible(1)).into(), true, // Maximal. ) .ok_or(XcmPaymentApiError::AssetNotFound)?