diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc50064b4..1c05a8ca37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added +- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#380](https://github.com/polkadot-fellows/runtimes/pull/380)) + #### From [#322](https://github.com/polkadot-fellows/runtimes/pull/322): - Add `claim_assets` extrinsic to `pallet-xcm` ([SDK v1.9 #3403](https://github.com/paritytech/polkadot-sdk/pull/3403)). diff --git a/Cargo.lock b/Cargo.lock index 34ff7ec38c..94caf224ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,6 +575,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -663,6 +664,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -709,6 +711,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -794,6 +797,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1668,6 +1672,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1772,6 +1777,7 @@ dependencies = [ "substrate-wasm-builder", "system-parachains-constants", "tuplex", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1821,6 +1827,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1923,6 +1930,7 @@ dependencies = [ "substrate-wasm-builder", "system-parachains-constants", "tuplex", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -2357,6 +2365,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -2432,6 +2441,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -2570,6 +2580,44 @@ dependencies = [ "memchr", ] +[[package]] +name = "coretime-kusama-emulated-chain" +version = "0.0.0" +dependencies = [ + "coretime-kusama-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "sp-core 34.0.0", +] + +[[package]] +name = "coretime-kusama-integration-tests" +version = "1.0.0" +dependencies = [ + "asset-test-utils", + "coretime-kusama-runtime", + "cumulus-pallet-parachain-system", + "emulated-integration-tests-common", + "frame-support", + "integration-tests-helpers", + "kusama-runtime-constants", + "kusama-system-emulated-network", + "pallet-balances", + "pallet-identity", + "pallet-message-queue", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "polkadot-runtime-common", + "sp-runtime 38.0.0", + "staging-kusama-runtime", + "staging-xcm", + "staging-xcm-executor", + "xcm-fee-payment-runtime-api", +] + [[package]] name = "coretime-kusama-runtime" version = "1.0.0" @@ -2636,6 +2684,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -3826,6 +3875,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -5744,6 +5794,7 @@ version = "1.0.0" dependencies = [ "asset-hub-kusama-emulated-chain", "bridge-hub-kusama-emulated-chain", + "coretime-kusama-emulated-chain", "emulated-integration-tests-common", "kusama-emulated-chain", "penpal-emulated-chain", @@ -9282,6 +9333,7 @@ dependencies = [ "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", + "integration-tests-helpers", "kusama-runtime-constants", "kusama-system-emulated-network", "pallet-balances", @@ -9296,6 +9348,7 @@ dependencies = [ "staging-kusama-runtime", "staging-xcm", "staging-xcm-executor", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9364,6 +9417,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9387,6 +9441,7 @@ dependencies = [ "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", + "integration-tests-helpers", "pallet-balances", "pallet-identity", "pallet-message-queue", @@ -9401,6 +9456,7 @@ dependencies = [ "sp-runtime 38.0.0", "staging-xcm", "staging-xcm-executor", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9467,6 +9523,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9787,6 +9844,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "tokio", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -14027,6 +14085,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "tokio", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 505e163b92..6cfc0c6c6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ codec = { package = "parity-scale-codec", version = "3.6.9", default-features = collectives-polkadot-emulated-chain = { path = "integration-tests/emulated/chains/parachains/collectives/collectives-polkadot" } collectives-polkadot-runtime = { path = "system-parachains/collectives/collectives-polkadot" } collectives-polkadot-runtime-constants = { path = "system-parachains/collectives/collectives-polkadot/constants" } +coretime-kusama-emulated-chain = { path = "integration-tests/emulated/chains/parachains/coretime/coretime-kusama" } coretime-kusama-runtime = { path = "system-parachains/coretime/coretime-kusama" } cumulus-pallet-aura-ext = { version = "0.14.0", default-features = false } cumulus-pallet-dmp-queue = { version = "0.14.0", default-features = false } @@ -235,6 +236,7 @@ xcm = { version = "14.0.0", default-features = false, package = "staging-xcm" } xcm-builder = { version = "14.0.0", default-features = false, package = "staging-xcm-builder" } xcm-emulator = { version = "0.12.0" } xcm-executor = { version = "14.0.0", default-features = false, package = "staging-xcm-executor" } +xcm-fee-payment-runtime-api = { version = "0.4.0", default-features = false } anyhow = { version = "1.0.82" } subxt = { version = "0.35.0", default-features = false } tracing-subscriber = { version = "0.3.18" } @@ -251,6 +253,7 @@ members = [ "integration-tests/emulated/chains/parachains/bridges/bridge-hub-kusama", "integration-tests/emulated/chains/parachains/bridges/bridge-hub-polkadot", "integration-tests/emulated/chains/parachains/collectives/collectives-polkadot", + "integration-tests/emulated/chains/parachains/coretime/coretime-kusama", "integration-tests/emulated/chains/parachains/people/people-kusama", "integration-tests/emulated/chains/parachains/people/people-polkadot", "integration-tests/emulated/chains/parachains/testing/penpal", @@ -265,6 +268,7 @@ members = [ "integration-tests/emulated/tests/bridges/bridge-hub-kusama", "integration-tests/emulated/tests/bridges/bridge-hub-polkadot", "integration-tests/emulated/tests/collectives/collectives-polkadot", + "integration-tests/emulated/tests/coretime/coretime-kusama", "integration-tests/emulated/tests/people/people-kusama", "integration-tests/emulated/tests/people/people-polkadot", "relay/kusama", diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml new file mode 100644 index 0000000000..0c24f8320b --- /dev/null +++ b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "coretime-kusama-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Kusama emulated chain used for integration tests" +publish = false + +[dependencies] + +# Substrate +sp-core = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } + +# Cumulus +parachains-common = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } + +# Runtimes +coretime-kusama-runtime = { workspace = true } diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs new file mode 100644 index 0000000000..1144e62497 --- /dev/null +++ b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs @@ -0,0 +1,66 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Substrate +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1001; +pub const ED: Balance = coretime_kusama_runtime::ExistentialDeposit::get(); + +pub fn genesis() -> Storage { + let genesis_config = coretime_kusama_runtime::RuntimeGenesisConfig { + system: coretime_kusama_runtime::SystemConfig::default(), + balances: coretime_kusama_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: coretime_kusama_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: coretime_kusama_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: coretime_kusama_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + coretime_kusama_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: coretime_kusama_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage( + &genesis_config, + coretime_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), + ) +} diff --git a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs new file mode 100644 index 0000000000..2876d1886b --- /dev/null +++ b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs @@ -0,0 +1,50 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impls::Parachain, xcm_emulator::decl_test_parachains, +}; + +// CollectivesPolkadot Parachain declaration +decl_test_parachains! { + pub struct CoretimeKusama { + genesis = genesis::genesis(), + on_init = { + coretime_kusama_runtime::AuraExt::on_initialize(1); + }, + runtime = coretime_kusama_runtime, + core = { + XcmpMessageHandler: coretime_kusama_runtime::XcmpQueue, + LocationToAccountId: coretime_kusama_runtime::xcm_config::LocationToAccountId, + ParachainInfo: coretime_kusama_runtime::ParachainInfo, + MessageOrigin: cumulus_primitives_core::AggregateMessageOrigin, + }, + pallets = { + PolkadotXcm: coretime_kusama_runtime::PolkadotXcm, + Balances: coretime_kusama_runtime::Balances, + } + }, +} + +// CoretimeKusama implementation +impl_accounts_helpers_for_parachain!(CoretimeKusama); +impl_assert_events_helpers_for_parachain!(CoretimeKusama); diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index 7f29c0e16b..096e91b3b7 100644 --- a/integration-tests/emulated/helpers/src/lib.rs +++ b/integration-tests/emulated/helpers/src/lib.rs @@ -40,7 +40,6 @@ macro_rules! test_relay_is_trusted_teleporter { let sender = [<$sender_relay Sender>]::get(); let mut relay_sender_balance_before = <$sender_relay as $crate::Chain>::account_data_of(sender.clone()).free; - let origin = <$sender_relay as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); let fee_asset_item = 0; let weight_limit = $crate::WeightLimit::Unlimited; @@ -55,16 +54,50 @@ macro_rules! test_relay_is_trusted_teleporter { let beneficiary: Location = $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - // Send XCM message from Relay + // Dry-run first. + let call = <$sender_relay as Chain>::RuntimeCall::XcmPallet(pallet_xcm::Call::limited_teleport_assets { + dest: bx!(para_destination.clone().into()), + beneficiary: bx!(beneficiary.clone().into()), + assets: bx!($assets.clone().into()), + fee_asset_item: fee_asset_item, + weight_limit: weight_limit.clone(), + }); + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + <$sender_relay>::execute_with(|| { + type Runtime = <$sender_relay as Chain>::Runtime; + type OriginCaller = <$sender_relay as Chain>::OriginCaller; + + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call.clone()).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(0, [Parachain(<$receiver_para>::para_id().into())])) + }) + .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 latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); + let Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + delivery_fees_amount = inner_delivery_fees_amount; + }); + + // Reset to send actual message. + <$sender_relay>::reset_ext(); + <$receiver_para>::reset_ext(); + + // Send XCM message from Relay. <$sender_relay>::execute_with(|| { - assert_ok!(<$sender_relay as [<$sender_relay Pallet>]>::XcmPallet::limited_teleport_assets( - origin.clone(), - bx!(para_destination.clone().into()), - bx!(beneficiary.clone().into()), - bx!($assets.clone().into()), - fee_asset_item, - weight_limit.clone(), - )); + let origin = <$sender_relay as Chain>::RuntimeOrigin::signed(sender.clone()); + assert_ok!(call.dispatch(origin)); type RuntimeEvent = <$sender_relay as $crate::Chain>::RuntimeEvent; @@ -106,13 +139,8 @@ macro_rules! test_relay_is_trusted_teleporter { <$sender_relay as $crate::Chain>::account_data_of(sender.clone()).free; let para_receiver_balance_after = <$receiver_para as $crate::Chain>::account_data_of(receiver.clone()).free; - let delivery_fees = <$sender_relay>::execute_with(|| { - $crate::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< - <$sender_xcm_config as xcm_executor::Config>::XcmSender, - >($assets.clone(), fee_asset_item, weight_limit.clone(), beneficiary, para_destination) - }); - assert_eq!(relay_sender_balance_before - $amount - delivery_fees, relay_sender_balance_after); + assert_eq!(relay_sender_balance_before - $amount - delivery_fees_amount, relay_sender_balance_after); assert!(para_receiver_balance_after > para_receiver_balance_before); // Update sender balance @@ -129,6 +157,13 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { $crate::paste::paste! { // init Origin variables let sender = [<$sender_para Sender>]::get(); + // Mint assets to `$sender_para` to succeed with teleport. + <$sender_para>::execute_with(|| { + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::Balances::mint_into( + &sender, + $amount + 10_000_000_000, // Some extra for delivery fees. + )); + }); let mut para_sender_balance_before = <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; let origin = <$sender_para as $crate::Chain>::RuntimeOrigin::signed(sender.clone()); @@ -136,7 +171,19 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { let fee_asset_item = 0; let weight_limit = $crate::WeightLimit::Unlimited; - // init Destination variables + // We need to mint funds into the checking account of `$receiver_relay` + // for it to accept a teleport from `$sender_para`. + // Else we'd get a `NotWithdrawable` error since it tries to reduce the check account balance, which + // would be 0. + <$receiver_relay>::execute_with(|| { + let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account(); + assert_ok!(<$receiver_relay as [<$receiver_relay Pallet>]>::Balances::mint_into( + &check_account, + $amount, + )); + }); + + // Init destination variables. let receiver = [<$receiver_relay Receiver>]::get(); let relay_receiver_balance_before = <$receiver_relay as $crate::Chain>::account_data_of(receiver.clone()).free; @@ -144,16 +191,72 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { let beneficiary: Location = $crate::AccountId32 { network: None, id: receiver.clone().into() }.into(); - // Send XCM message from Parachain + // Dry-run first. + let call = <$sender_para as Chain>::RuntimeCall::PolkadotXcm(pallet_xcm::Call::limited_teleport_assets { + dest: bx!(relay_destination.clone().into()), + beneficiary: bx!(beneficiary.clone().into()), + assets: bx!(assets.clone().into()), + fee_asset_item: fee_asset_item, + weight_limit: weight_limit.clone(), + }); + // These will be filled in the closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); <$sender_para>::execute_with(|| { - assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets( - origin.clone(), - bx!(relay_destination.clone().into()), - bx!(beneficiary.clone().into()), - bx!(assets.clone().into()), - fee_asset_item, - weight_limit.clone(), + type Runtime = <$sender_para as Chain>::Runtime; + type OriginCaller = <$sender_para as Chain>::OriginCaller; + + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call.clone()).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [])) + }) + .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 latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); + delivery_fees_amount = if let Some(first_asset) = latest_delivery_fees.inner().first() { + let Fungible(inner_delivery_fees_amount) = first_asset.fun else { + unreachable!("asset is fungible"); + }; + inner_delivery_fees_amount + } else { + 0 + } + }); + + // Reset to send actual message. + <$sender_para>::reset_ext(); + <$receiver_relay>::reset_ext(); + + // Mint assets to `$sender_para` to succeed with teleport. + <$sender_para>::execute_with(|| { + assert_ok!(<$sender_para as [<$sender_para Pallet>]>::Balances::mint_into( + &sender, + $amount + 10_000_000_000, // Some extra for delivery fees. + )); + }); + + // Since we reset everything, we need to mint funds into the checking account again. + <$receiver_relay>::execute_with(|| { + let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account(); + assert_ok!(<$receiver_relay as [<$receiver_relay Pallet>]>::Balances::mint_into( + &check_account, + $amount, )); + }); + + // Send XCM message from Parachain. + <$sender_para>::execute_with(|| { + let origin = <$sender_para as Chain>::RuntimeOrigin::signed(sender.clone()); + assert_ok!(call.dispatch(origin)); type RuntimeEvent = <$sender_para as $crate::Chain>::RuntimeEvent; @@ -195,13 +298,8 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { <$sender_para as $crate::Chain>::account_data_of(sender.clone()).free; let relay_receiver_balance_after = <$receiver_relay as $crate::Chain>::account_data_of(receiver.clone()).free; - let delivery_fees = <$sender_para>::execute_with(|| { - $crate::asset_test_utils::xcm_helpers::teleport_assets_delivery_fees::< - <$sender_xcm_config as xcm_executor::Config>::XcmSender, - >(assets, fee_asset_item, weight_limit.clone(), beneficiary, relay_destination) - }); - assert_eq!(para_sender_balance_before - $amount - delivery_fees, para_sender_balance_after); + assert_eq!(para_sender_balance_before - $amount - delivery_fees_amount, para_sender_balance_after); assert!(relay_receiver_balance_after > relay_receiver_balance_before); // Update sender balance diff --git a/integration-tests/emulated/networks/kusama-system/Cargo.toml b/integration-tests/emulated/networks/kusama-system/Cargo.toml index 50f09c6512..4f8c90bded 100644 --- a/integration-tests/emulated/networks/kusama-system/Cargo.toml +++ b/integration-tests/emulated/networks/kusama-system/Cargo.toml @@ -18,3 +18,4 @@ bridge-hub-kusama-emulated-chain = { workspace = true } kusama-emulated-chain = { workspace = true } penpal-emulated-chain = { workspace = true } people-kusama-emulated-chain = { workspace = true } +coretime-kusama-emulated-chain = { workspace = true } diff --git a/integration-tests/emulated/networks/kusama-system/src/lib.rs b/integration-tests/emulated/networks/kusama-system/src/lib.rs index 775d7ece4e..ed785d60af 100644 --- a/integration-tests/emulated/networks/kusama-system/src/lib.rs +++ b/integration-tests/emulated/networks/kusama-system/src/lib.rs @@ -15,12 +15,14 @@ pub use asset_hub_kusama_emulated_chain; pub use bridge_hub_kusama_emulated_chain; +pub use coretime_kusama_emulated_chain; pub use kusama_emulated_chain; pub use penpal_emulated_chain; pub use people_kusama_emulated_chain; use asset_hub_kusama_emulated_chain::AssetHubKusama; use bridge_hub_kusama_emulated_chain::BridgeHubKusama; +use coretime_kusama_emulated_chain::CoretimeKusama; use kusama_emulated_chain::Kusama; use penpal_emulated_chain::{PenpalA, PenpalB}; use people_kusama_emulated_chain::PeopleKusama; @@ -40,6 +42,7 @@ decl_test_networks! { PenpalA, PenpalB, PeopleKusama, + CoretimeKusama, ], bridge = () }, @@ -51,5 +54,6 @@ decl_test_sender_receiver_accounts_parameter_types! { BridgeHubKusamaPara { sender: ALICE, receiver: BOB }, PenpalAPara { sender: ALICE, receiver: BOB }, PenpalBPara { sender: ALICE, receiver: BOB }, - PeopleKusamaPara { sender: ALICE, receiver: BOB } + PeopleKusamaPara { sender: ALICE, receiver: BOB }, + CoretimeKusamaPara { sender: ALICE, receiver: BOB } } diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml b/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml index 18fdb9675a..e858c2ffe2 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/Cargo.toml @@ -26,6 +26,7 @@ xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true } pallet-xcm = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus parachains-common = { workspace = true, default-features = true } diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs index 8fffec23d7..88fa379c40 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/mod.rs @@ -21,3 +21,4 @@ mod set_xcm_versions; mod swap; mod teleport; mod treasury; +mod xcm_fee_estimation; diff --git a/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs new file mode 100644 index 0000000000..eebb6b9cb4 --- /dev/null +++ b/integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs @@ -0,0 +1,301 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for XCM fee estimation in the runtime. + +use crate::{ + assert_expected_events, bx, AssetHubKusama, Chain, ParaToParaThroughAHTest, PenpalA, + PenpalAPallet, PenpalASender, PenpalAssetOwner, PenpalB, PenpalBPallet, PenpalBReceiver, + TestArgs, TestContext, TransferType, +}; +use emulated_integration_tests_common::impls::{Parachain, TestExt}; +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::{traits::Dispatchable, DispatchResult}, + traits::fungibles::Inspect, +}; +use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; + +/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. +/// Scenario: Alice on PenpalA has some DOTs and wants to send them to PenpalB. +/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. +#[test] +fn multi_hop_works() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send = 1_000_000_000_000; + let asset_owner = PenpalAssetOwner::get(); + let assets: Assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = Location::parent(); + let sender_as_seen_by_ah = AssetHubKusama::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubKusama::sovereign_account_id_of(sender_as_seen_by_ah.clone()); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. + AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); + + // Init values for Parachain Destination + let beneficiary_id = PenpalBReceiver::get(); + + let test_args = TestContext { + sender: PenpalASender::get(), // Bob in PenpalB. + receiver: PenpalBReceiver::get(), // Alice. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // We get them from the PenpalA closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type OriginCaller = ::OriginCaller; + + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + }) + .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(); + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // These are set in the AssetHub closure. + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees_amount = 0; + let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::V4(Location::new(1, []).into()), + ) + .unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let result = + Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(2001)])) + }) + .unwrap(); + // There's actually two messages here. + // One created when the message we sent from PenpalA arrived and was executed. + // The second one when we dry-run the xcm. + // 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 = Runtime::query_delivery_fees( + destination_to_query.clone(), + intermediate_remote_message.clone(), + ) + .unwrap(); + intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // Get the final execution fees in the destination. + let mut final_execution_fees = 0; + ::execute_with(|| { + type Runtime = ::Runtime; + + let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); + final_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + }); + + // Dry-running is done. + PenpalA::reset_ext(); + AssetHubKusama::reset_ext(); + PenpalB::reset_ext(); + + // Fund accounts again. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + AssetHubKusama::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); + + // Actually run the extrinsic. + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &beneficiary_id) + }); + + test.set_assertion::(sender_assertions); + test.set_assertion::(hop_assertions); + test.set_assertion::(receiver_assertions); + test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); + test.assert(); + + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &beneficiary_id) + }); + + // We know the exact fees on every hop. + assert_eq!( + sender_assets_after, + sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly + * from the sender's + * account. */ + ); + assert_eq!( + receiver_assets_after, + receiver_assets_before + amount_to_send - + intermediate_execution_fees - + intermediate_delivery_fees_amount - + final_execution_fees + ); +} + +fn sender_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(None); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.sender.account_id, + balance: *balance == test.args.amount, + }, + ] + ); +} + +fn hop_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubKusama::assert_xcmp_queue_success(None); + + assert_expected_events!( + AssetHubKusama, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Burned { amount, .. } + ) => { + amount: *amount == test.args.amount, + }, + ] + ); +} + +fn receiver_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcmp_queue_success(None); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, .. } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.receiver.account_id, + }, + ] + ); +} + +fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { + let latest_assets: Assets = assets.try_into().unwrap(); + let Fungible(amount) = latest_assets.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + amount +} + +fn transfer_assets_para_to_para_through_ah_dispatchable( + test: ParaToParaThroughAHTest, +) -> DispatchResult { + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + match call.dispatch(test.signed_origin) { + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } +} + +fn transfer_assets_para_to_para_through_ah_call( + test: ParaToParaThroughAHTest, +) -> ::RuntimeCall { + type RuntimeCall = ::RuntimeCall; + + let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubKusama::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(test.args.assets.len() as u32)), + beneficiary: test.args.beneficiary, + }]); + 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::V4(AssetId(Location::new(1, [])))), + 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, + }) +} diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml b/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml index 3c15a06834..3b6420f7a6 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/Cargo.toml @@ -25,6 +25,7 @@ polkadot-runtime-common = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true, default-features = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus asset-test-utils = { workspace = true } diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs index 564257ab0d..73b73b239a 100644 --- a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/mod.rs @@ -22,3 +22,4 @@ mod set_xcm_versions; mod swap; mod teleport; mod treasury; +mod xcm_fee_estimation; diff --git a/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs new file mode 100644 index 0000000000..8588e60846 --- /dev/null +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs @@ -0,0 +1,302 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for XCM fee estimation in the runtime. + +use crate::{ + assert_expected_events, bx, AssetHubPolkadot, Chain, ParaToParaThroughAHTest, PenpalA, + PenpalAPallet, PenpalAReceiver, PenpalAssetOwner, PenpalB, PenpalBPallet, PenpalBSender, + TestArgs, TestContext, TransferType, +}; +use emulated_integration_tests_common::impls::{Parachain, TestExt}; +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::{traits::Dispatchable, DispatchResult}, + traits::fungibles::Inspect, +}; +use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; + +/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. +/// Scenario: Alice on PenpalB has some DOTs and wants to send them to PenpalA. +/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`. +#[test] +fn multi_hop_works() { + let destination = PenpalB::sibling_location_of(PenpalA::para_id()); + let sender = PenpalBSender::get(); + let amount_to_send = 1_000_000_000_000; // One DOT is 10 decimals but it's configured in Penpal as 12. + let asset_owner = PenpalAssetOwner::get(); + let assets: Assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = Location::parent(); + let sender_as_seen_by_ah = AssetHubPolkadot::sibling_location_of(PenpalB::para_id()); + let sov_of_sender_on_ah = + AssetHubPolkadot::sovereign_account_id_of(sender_as_seen_by_ah.clone()); + + // fund Parachain's sender account + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // fund the Parachain Origin's SA on AssetHub with the native tokens held in reserve. + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); + + // Init values for Parachain Destination + let beneficiary_id = PenpalAReceiver::get(); + + let test_args = TestContext { + sender: PenpalBSender::get(), // Bob in PenpalB. + receiver: PenpalAReceiver::get(), // Alice. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // We get them from the PenpalB closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type OriginCaller = ::OriginCaller; + + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + let origin = OriginCaller::system(RawOrigin::Signed(sender.clone())); + let result = Runtime::dry_run_call(origin, call).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1000)])) + }) + .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(); + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // These are set in the AssetHub closure. + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees_amount = 0; + let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = Runtime::query_weight_to_asset_fee( + weight, + VersionedAssetId::V4(Location::new(1, []).into()), + ) + .unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let result = + Runtime::dry_run_xcm(sender_as_seen_by_ah.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(2000)])) + }) + .unwrap(); + // There's actually two messages here. + // One created when the message we sent from PenpalA arrived and was executed. + // The second one when we dry-run the xcm. + // 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 = Runtime::query_delivery_fees( + destination_to_query.clone(), + intermediate_remote_message.clone(), + ) + .unwrap(); + intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // Get the final execution fees in the destination. + let mut final_execution_fees = 0; + ::execute_with(|| { + type Runtime = ::Runtime; + + let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); + final_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + }); + + // Dry-running is done. + PenpalB::reset_ext(); + AssetHubPolkadot::reset_ext(); + PenpalA::reset_ext(); + + // Fund accounts again. + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah, amount_to_send * 2)]); + + // Actually run the extrinsic. + let sender_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &beneficiary_id) + }); + + test.set_assertion::(sender_assertions); + test.set_assertion::(hop_assertions); + test.set_assertion::(receiver_assertions); + test.set_dispatchable::(transfer_assets_para_to_para_through_ah_dispatchable); + test.assert(); + + let sender_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &beneficiary_id) + }); + + // We know the exact fees on every hop. + assert_eq!( + sender_assets_after, + sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly + * from the sender's + * account. */ + ); + assert_eq!( + receiver_assets_after, + receiver_assets_before + amount_to_send - + intermediate_execution_fees - + intermediate_delivery_fees_amount - + final_execution_fees + ); +} + +fn sender_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcm_pallet_attempted_complete(None); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Burned { asset_id, owner, balance } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.sender.account_id, + balance: *balance == test.args.amount, + }, + ] + ); +} + +fn hop_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubPolkadot::assert_xcmp_queue_success(None); + + assert_expected_events!( + AssetHubPolkadot, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Burned { amount, .. } + ) => { + amount: *amount == test.args.amount, + }, + ] + ); +} + +fn receiver_assertions(test: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcmp_queue_success(None); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets( + pallet_assets::Event::Issued { asset_id, owner, .. } + ) => { + asset_id: *asset_id == Location::new(1, []), + owner: *owner == test.receiver.account_id, + }, + ] + ); +} + +fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { + let latest_assets: Assets = assets.try_into().unwrap(); + let Fungible(amount) = latest_assets.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + amount +} + +fn transfer_assets_para_to_para_through_ah_dispatchable( + test: ParaToParaThroughAHTest, +) -> DispatchResult { + let call = transfer_assets_para_to_para_through_ah_call(test.clone()); + match call.dispatch(test.signed_origin) { + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } +} + +fn transfer_assets_para_to_para_through_ah_call( + test: ParaToParaThroughAHTest, +) -> ::RuntimeCall { + type RuntimeCall = ::RuntimeCall; + + let asset_hub_location: Location = PenpalB::sibling_location_of(AssetHubPolkadot::para_id()); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(test.args.assets.len() as u32)), + beneficiary: test.args.beneficiary, + }]); + 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::V4(AssetId(Location::new(1, [])))), + 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, + }) +} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml index b3385f8dfb..7076d34d39 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/Cargo.toml @@ -25,6 +25,7 @@ pallet-message-queue = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true, default-features = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus emulated-integration-tests-common = { workspace = true } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs index c930e54f2c..674bf32bb9 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/lib.rs @@ -15,7 +15,7 @@ // Substrate pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; -pub use sp_runtime::DispatchError; +pub use sp_runtime::{traits::Dispatchable, DispatchError}; // Polkadot pub use xcm::{ diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs index 5c94dde5b2..9304093e39 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/asset_transfers.rs @@ -14,7 +14,11 @@ // limitations under the License. use crate::tests::*; -use frame_support::traits::fungible::Mutate; +use frame_support::{dispatch::RawOrigin, traits::fungible::Mutate}; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; fn send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(id: Location, amount: u128) { let destination = asset_hub_polkadot_location(); @@ -32,6 +36,113 @@ fn send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(id: Location, amount: assert_bridge_hub_polkadot_message_received(); } +fn dry_run_send_asset_from_asset_hub_kusama_to_asset_hub_polkadot( + id: Location, + amount: u128, +) -> u128 { + let destination = asset_hub_polkadot_location(); + + // fund the AHK's SA on BHK for paying bridge transport fees + BridgeHubKusama::fund_para_sovereign(AssetHubKusama::para_id(), 10_000_000_000_000u128); + + // set XCM versions + AssetHubKusama::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubKusama::force_xcm_version(bridge_hub_polkadot_location(), XCM_VERSION); + + let beneficiary: Location = + AccountId32Junction { id: AssetHubPolkadotReceiver::get().into(), network: None }.into(); + let assets: Assets = (id, amount).into(); + let fee_asset_item = 0; + let call = + send_asset_from_asset_hub_kusama_call(destination, beneficiary, assets, fee_asset_item); + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + AssetHubKusama::execute_with(|| { + type Runtime = ::Runtime; + type OriginCaller = ::OriginCaller; + + let origin = OriginCaller::system(RawOrigin::Signed(AssetHubKusamaSender::get())); + let result = Runtime::dry_run_call(origin, call).unwrap(); + // We filter the result to get only the messages we are interested in. + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1002)])) + }) + .unwrap(); + dbg!(&result.forwarded_xcms); + 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 latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); + let Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + delivery_fees_amount = inner_delivery_fees_amount; + }); + + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees_amount = 0; + let mut intermediate_remote_message = VersionedXcm::V4(Xcm(Vec::new())); + BridgeHubKusama::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let asset_hub_as_seen_by_bridge_hub: Location = Location::new(1, [Parachain(1000)]); + let result = + Runtime::dry_run_xcm(asset_hub_as_seen_by_bridge_hub.clone().into(), xcm_program) + .unwrap(); + + // We filter the result to get only the messages we are interested in. + // dbg!(&result.forwarded_xcms); + let (destination_to_query, messages_to_query) = &result + .forwarded_xcms + .iter() + .find(|(destination, _)| { + *destination == VersionedLocation::V4(Location::new(1, [Parachain(1002)])) + }) + .unwrap(); + // There's actually two messages here. + // One created when the message we sent from PenpalA arrived and was executed. + // The second one when we dry-run the xcm. + // 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 = + Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) + .unwrap(); + let latest_delivery_fees: Assets = delivery_fees.clone().try_into().unwrap(); + let Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + intermediate_delivery_fees_amount = inner_delivery_fees_amount; + }); + + dbg!(&delivery_fees_amount); + dbg!(&intermediate_execution_fees); + dbg!(&intermediate_delivery_fees_amount); + + // After dry-running we reset. + AssetHubKusama::reset_ext(); + BridgeHubKusama::reset_ext(); + + delivery_fees_amount +} + #[test] fn send_ksms_from_asset_hub_kusama_to_asset_hub_polkadot() { let ksm_at_asset_hub_kusama: v3::Location = v3::Parent.into(); @@ -61,6 +172,12 @@ fn send_ksms_from_asset_hub_kusama_to_asset_hub_polkadot() { let ksm_at_asset_hub_kusama_latest: Location = ksm_at_asset_hub_kusama.try_into().unwrap(); let amount = ASSET_HUB_KUSAMA_ED * 1_000; + // First dry-run. + let delivery_fees = dry_run_send_asset_from_asset_hub_kusama_to_asset_hub_polkadot( + ksm_at_asset_hub_kusama_latest.clone(), + amount, + ); + // Then send. send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(ksm_at_asset_hub_kusama_latest, amount); AssetHubPolkadot::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; @@ -89,8 +206,15 @@ fn send_ksms_from_asset_hub_kusama_to_asset_hub_polkadot() { let ksms_in_reserve_on_ahk_after = ::account_data_of(sov_ahp_on_ahk.clone()).free; + dbg!(&sender_ksms_after); + dbg!(&sender_ksms_before); + dbg!(&amount); + dbg!(&delivery_fees); + dbg!(&receiver_ksms_after); + dbg!(&receiver_ksms_before); + // Sender's balance is reduced - assert!(sender_ksms_before > sender_ksms_after); + assert_eq!(sender_ksms_after, sender_ksms_before - amount - delivery_fees); // Receiver's balance is increased assert!(receiver_ksms_after > receiver_ksms_before); // Reserve balance is reduced by sent amount diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs index 9d5d7a9f38..fee51267b6 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/mod.rs @@ -49,17 +49,32 @@ pub(crate) fn send_asset_from_asset_hub_kusama( let fee_asset_item = 0; AssetHubKusama::execute_with(|| { - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) + let call = + send_asset_from_asset_hub_kusama_call(destination, beneficiary, assets, fee_asset_item); + match call.dispatch(signed_origin) { + Ok(_) => Ok(()), + Err(error_with_post_info) => Err(error_with_post_info.error), + } }) } +pub(crate) fn send_asset_from_asset_hub_kusama_call( + destination: Location, + beneficiary: Location, + assets: Assets, + fee_asset_item: u32, +) -> ::RuntimeCall { + ::RuntimeCall::PolkadotXcm( + pallet_xcm::Call::limited_reserve_transfer_assets { + dest: bx!(destination.into()), + beneficiary: bx!(beneficiary.into()), + assets: bx!(assets.into()), + fee_asset_item, + weight_limit: WeightLimit::Unlimited, + }, + ) +} + pub(crate) fn assert_bridge_hub_kusama_message_accepted(expected_processed: bool) { BridgeHubKusama::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs index c1aebaabfc..58179e8c53 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-kusama/src/tests/teleport.rs @@ -15,6 +15,16 @@ use crate::*; use bridge_hub_kusama_runtime::xcm_config::XcmConfig; +use frame_support::{ + dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; #[test] fn teleport_to_other_system_parachains_works() { @@ -28,3 +38,23 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +#[test] +fn teleport_from_and_to_relay() { + let amount = KUSAMA_ED * 1000; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Kusama, + KusamaXcmConfig, + vec![BridgeHubKusama], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + BridgeHubKusama, + BridgeHubKusamaXcmConfig, + Kusama, + amount + ); +} diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml index c4034d7913..bb9ffdf9bb 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/Cargo.toml @@ -25,6 +25,7 @@ pallet-message-queue = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true, default-features = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus emulated-integration-tests-common = { workspace = true } diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs index 9aefaed933..5ab2ff4e60 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/lib.rs @@ -60,6 +60,7 @@ pub use kusama_polkadot_system_emulated_network::{ AssetHubPolkadotParaSender as AssetHubPolkadotSender, BridgeHubKusamaPara as BridgeHubKusama, BridgeHubPolkadotPara as BridgeHubPolkadot, BridgeHubPolkadotParaSender as BridgeHubPolkadotSender, PolkadotRelay as Polkadot, + PolkadotRelayReceiver as PolkadotReceiver, PolkadotRelaySender as PolkadotSender, }; pub use parachains_common::{AccountId, Balance}; pub use polkadot_system_emulated_network::{ diff --git a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs index 76eec63125..07664c0d28 100644 --- a/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/bridges/bridge-hub-polkadot/src/tests/teleport.rs @@ -15,6 +15,16 @@ use crate::*; use bridge_hub_polkadot_runtime::xcm_config::XcmConfig; +use frame_support::{ + dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; #[test] fn teleport_to_other_system_parachains_works() { @@ -28,3 +38,23 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +#[test] +fn teleport_from_and_to_relay() { + let amount = BRIDGE_HUB_POLKADOT_ED * 1000; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Polkadot, + PolkadotXcmConfig, + vec![BridgeHubPolkadot], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + BridgeHubPolkadot, + BridgeHubPolkadotXcmConfig, + Polkadot, + amount + ); +} diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml b/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml index 9888f770f9..6a9e80de9b 100644 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/collectives/collectives-polkadot/Cargo.toml @@ -28,6 +28,7 @@ polkadot-runtime-common = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true, default-features = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus asset-test-utils = { workspace = true } diff --git a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs index 27ccd27b55..d292fd195b 100644 --- a/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/collectives/collectives-polkadot/src/tests/teleport.rs @@ -16,11 +16,16 @@ use crate::*; use asset_hub_polkadot_runtime::xcm_config::XcmConfig as AssetHubPolkadotXcmConfig; use collectives_polkadot_runtime::xcm_config::XcmConfig as CollectivesPolkadotXcmConfig; -use frame_support::assert_ok; +use frame_support::{ + assert_ok, dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; use integration_tests_helpers::{ test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, }; -use polkadot_runtime::xcm_config::XcmConfig as PolkadotXcmConfig; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; #[test] fn teleport_from_and_to_relay() { diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml b/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml new file mode 100644 index 0000000000..45acad6728 --- /dev/null +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "coretime-kusama-integration-tests" +version.workspace = true +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Coretime Kusama runtime integration tests with xcm-emulator" +publish = false + +[dependencies] +codec = { workspace = true, default-features = true } + +# Substrate +sp-runtime = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true, default-features = true } +pallet-identity = { workspace = true, default-features = true } + +# Polkadot +polkadot-runtime-common = { workspace = true, default-features = true } +pallet-xcm = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } +xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } + +# Cumulus +parachains-common = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +asset-test-utils = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true, default-features = true } + +# Local +kusama-runtime-constants = { workspace = true, default-features = true } +kusama-runtime = { workspace = true } +integration-tests-helpers = { workspace = true } +coretime-kusama-runtime = { workspace = true } +kusama-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs new file mode 100644 index 0000000000..0d3e3ac75c --- /dev/null +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs @@ -0,0 +1,55 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub use codec::Encode; + +// Substrate +pub use frame_support::{ + assert_err, assert_ok, + pallet_prelude::Weight, + sp_runtime::{AccountId32, DispatchError, DispatchResult}, + traits::fungibles::Inspect, +}; + +// Polkadot +pub use xcm::{ + prelude::{AccountId32 as AccountId32Junction, *}, + v3::{Error, NetworkId::Kusama as KusamaId}, +}; + +// Cumulus +pub use asset_test_utils::xcm_helpers; +pub use emulated_integration_tests_common::{ + xcm_emulator::{ + assert_expected_events, bx, helpers::weight_within_threshold, Chain, Parachain as Para, + RelayChain as Relay, Test, TestArgs, TestContext, TestExt, + }, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, +}; +pub use kusama_system_emulated_network::{ + coretime_kusama_emulated_chain::{ + genesis::ED as CORETIME_KUSAMA_ED, CoretimeKusamaParaPallet as CoretimeKusamaPallet, + }, + kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, + CoretimeKusamaPara as CoretimeKusama, CoretimeKusamaParaReceiver as CoretimeKusamaReceiver, + CoretimeKusamaParaSender as CoretimeKusamaSender, KusamaRelay as Kusama, + KusamaRelayReceiver as KusamaReceiver, KusamaRelaySender as KusamaSender, + PenpalAPara as PenpalA, +}; +pub use parachains_common::{AccountId, Balance}; + +#[cfg(test)] +mod tests; diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs new file mode 100644 index 0000000000..516ec37cc1 --- /dev/null +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod teleport; diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs new file mode 100644 index 0000000000..0e36821279 --- /dev/null +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs @@ -0,0 +1,46 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::*; +use frame_support::{ + dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; + +#[test] +fn teleport_from_and_to_relay() { + let amount = KUSAMA_ED * 1000; + let native_asset: Assets = (Here, amount).into(); + + test_relay_is_trusted_teleporter!( + Kusama, + KusamaXcmConfig, + vec![CoretimeKusama], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + CoretimeKusama, + CoretimeKusamaXcmConfig, + Kusama, + amount + ); +} diff --git a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml index 58b1a66d8b..140732df73 100644 --- a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml @@ -19,9 +19,10 @@ pallet-identity = { workspace = true, default-features = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus parachains-common = { workspace = true, default-features = true } @@ -32,5 +33,6 @@ cumulus-pallet-parachain-system = { workspace = true, default-features = true } # Local kusama-runtime-constants = { workspace = true, default-features = true } kusama-runtime = { workspace = true } +integration-tests-helpers = { workspace = true } people-kusama-runtime = { workspace = true } kusama-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs b/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs index 33647a3c43..33eb8d2bb8 100644 --- a/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/people/people-kusama/src/tests/teleport.rs @@ -14,52 +14,35 @@ // limitations under the License. use crate::*; -use kusama_runtime::xcm_config::XcmConfig as KusamaXcmConfig; +use frame_support::{ + dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; use people_kusama_runtime::xcm_config::XcmConfig as PeopleKusamaXcmConfig; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200))); +#[test] +fn teleport_from_and_to_relay() { + let amount = KUSAMA_ED * 1000; + let native_asset: Assets = (Here, amount).into(); - assert_expected_events!( + test_relay_is_trusted_teleporter!( Kusama, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Kusama::assert_ump_queue_processed( - true, - Some(PeopleKusama::para_id()), - Some(Weight::from_parts(304_266_000, 7_186)), + KusamaXcmConfig, + vec![PeopleKusama], + (native_asset, amount) ); - assert_expected_events!( + test_parachain_is_trusted_teleporter_for_relay!( + PeopleKusama, + PeopleKusamaXcmConfig, Kusama, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] + amount ); } @@ -93,33 +76,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeopleKusama::assert_dmp_queue_complete(Some(Weight::from_parts(162_456_000, 0))); - - assert_expected_events!( - PeopleKusama, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_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_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -131,90 +87,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -/// 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() { - // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; - let dest = Kusama::child_location_of(PeopleKusama::para_id()); - let beneficiary_id = PeopleKusamaReceiver::get(); - let test_args = TestContext { - sender: KusamaSender::get(), - receiver: PeopleKusamaReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Kusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - let amount_to_send: Balance = PEOPLE_KUSAMA_ED * 1000; - let destination = PeopleKusama::parent_location(); - let beneficiary_id = KusamaReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeopleKusama::fund_accounts(vec![(PeopleKusamaSender::get(), KUSAMA_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeopleKusamaSender::get(), - receiver: KusamaReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeopleKusama::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - /// Limited Teleport of native asset from System Parachain to Relay Chain /// should't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] diff --git a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml index 5276c94e56..de541e552b 100644 --- a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml @@ -19,9 +19,10 @@ pallet-identity = { workspace = true, default-features = true } # Polkadot polkadot-runtime-common = { workspace = true, default-features = true } -xcm = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } +xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true, default-features = true } # Cumulus parachains-common = { workspace = true, default-features = true } @@ -32,5 +33,6 @@ cumulus-pallet-parachain-system = { workspace = true, default-features = true } # Local polkadot-runtime-constants = { workspace = true, default-features = true } polkadot-runtime = { workspace = true } +integration-tests-helpers = { workspace = true } people-polkadot-runtime = { workspace = true } polkadot-system-emulated-network = { workspace = true } diff --git a/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs b/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs index 3907a941a5..1904e53405 100644 --- a/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs +++ b/integration-tests/emulated/tests/people/people-polkadot/src/tests/teleport.rs @@ -14,52 +14,35 @@ // limitations under the License. use crate::*; +use frame_support::{ + dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate, +}; +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; use people_polkadot_runtime::xcm_config::XcmConfig as PeoplePolkadotXcmConfig; -use polkadot_runtime::xcm_config::XcmConfig as PolkadotXcmConfig; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_dry_run_api::DryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Polkadot::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200))); +#[test] +fn teleport_from_and_to_relay() { + let amount = KUSAMA_ED * 1000; + let native_asset: Assets = (Here, amount).into(); - assert_expected_events!( + test_relay_is_trusted_teleporter!( Polkadot, - vec![ - // Amount to teleport is withdrawn from Sender - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == t.sender.account_id, - amount: *amount == t.args.amount, - }, - // Amount to teleport is deposited in Relay's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - ] - ); -} - -fn relay_dest_assertions(t: SystemParaToRelayTest) { - type RuntimeEvent = ::RuntimeEvent; - - Polkadot::assert_ump_queue_processed( - true, - Some(PeoplePolkadot::para_id()), - Some(Weight::from_parts(304_266_000, 7_186)), + PolkadotXcmConfig, + vec![PeoplePolkadot], + (native_asset, amount) ); - assert_expected_events!( + test_parachain_is_trusted_teleporter_for_relay!( + PeoplePolkadot, + PeoplePolkadotXcmConfig, Polkadot, - vec![ - // Amount is withdrawn from Relay Chain's `CheckAccount` - RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { - who: *who == ::XcmPallet::check_account(), - amount: *amount == t.args.amount, - }, - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] + amount ); } @@ -93,33 +76,6 @@ fn para_origin_assertions(t: SystemParaToRelayTest) { ); } -fn para_dest_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - - PeoplePolkadot::assert_dmp_queue_complete(Some(Weight::from_parts(162_456_000, 0))); - - assert_expected_events!( - PeoplePolkadot, - vec![ - // Amount minus fees are deposited in Receiver's account - RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { - who: *who == t.receiver.account_id, - }, - ] - ); -} - -fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::limited_teleport_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_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -131,90 +87,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -/// 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() { - // Init values for Relay Chain - let amount_to_send: Balance = KUSAMA_ED * 1000; - let dest = Polkadot::child_location_of(PeoplePolkadot::para_id()); - let beneficiary_id = PeoplePolkadotReceiver::get(); - let test_args = TestContext { - sender: PolkadotSender::get(), - receiver: PeoplePolkadotReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_limited_teleport_assets); - test.assert(); - - let delivery_fees = Polkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Limited Teleport of native asset from System Parachain to Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn limited_teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - limited_teleport_native_assets_from_relay_to_system_para_works(); - - let amount_to_send: Balance = PEOPLE_KUSAMA_ED * 1000; - let destination = PeoplePolkadot::parent_location(); - let beneficiary_id = PolkadotReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - // Fund a sender - PeoplePolkadot::fund_accounts(vec![(PeoplePolkadotSender::get(), KUSAMA_ED * 2_000u128)]); - - let test_args = TestContext { - sender: PeoplePolkadotSender::get(), - receiver: PolkadotReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_limited_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = PeoplePolkadot::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - /// Limited Teleport of native asset from System Parachain to Relay Chain /// should't work when there is not enough balance in Relay Chain's `CheckAccount` #[test] diff --git a/relay/kusama/Cargo.toml b/relay/kusama/Cargo.toml index 7c0cf5d39b..e5c7b53bcb 100644 --- a/relay/kusama/Cargo.toml +++ b/relay/kusama/Cargo.toml @@ -101,6 +101,7 @@ polkadot-primitives = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } sp-debug-derive = { workspace = true } @@ -210,6 +211,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -261,6 +263,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks" ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index b2949c5585..a37f74740e 100644 --- a/relay/kusama/src/lib.rs +++ b/relay/kusama/src/lib.rs @@ -81,7 +81,7 @@ use frame_support::{ InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons, }, - weights::{ConstantMultiplier, WeightMeter}, + weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, }; use frame_system::EnsureRoot; @@ -102,11 +102,12 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::{ - latest::{InteriorLocation, Junction, Junction::PalletInstance}, - VersionedLocation, -}; +use xcm::prelude::*; use xcm_builder::PayOverXcm; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -2237,6 +2238,48 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; + XcmPallet::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + XcmPallet::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + XcmPallet::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + XcmPallet::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + XcmPallet::dry_run_xcm::(origin_location, xcm) + } + } + impl pallet_nomination_pools_runtime_api::NominationPoolsApi< Block, AccountId, diff --git a/relay/polkadot/Cargo.toml b/relay/polkadot/Cargo.toml index f11edec300..968bac44d0 100644 --- a/relay/polkadot/Cargo.toml +++ b/relay/polkadot/Cargo.toml @@ -99,6 +99,7 @@ polkadot-primitives = { workspace = true } xcm = { workspace = true } xcm-executor = { workspace = true } xcm-builder = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } sp-debug-derive = { workspace = true } @@ -207,6 +208,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -256,6 +258,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/relay/polkadot/src/impls.rs b/relay/polkadot/src/impls.rs index efce64c99a..fa690a1a8d 100644 --- a/relay/polkadot/src/impls.rs +++ b/relay/polkadot/src/impls.rs @@ -26,7 +26,6 @@ use frame_system::RawOrigin; use polkadot_primitives::Id as ParaId; use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; use polkadot_runtime_constants::system_parachain::PEOPLE_ID; -use xcm::{latest::prelude::*, VersionedXcm}; use xcm_builder::IsChildSystemParachain; use xcm_executor::traits::TransactAsset; diff --git a/relay/polkadot/src/lib.rs b/relay/polkadot/src/lib.rs index b45360a8b7..631fcc9cdc 100644 --- a/relay/polkadot/src/lib.rs +++ b/relay/polkadot/src/lib.rs @@ -65,7 +65,7 @@ use frame_support::{ Get, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, WithdrawReasons, }, - weights::{ConstantMultiplier, WeightMeter}, + weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, }; use frame_system::EnsureRoot; @@ -102,11 +102,12 @@ use sp_std::{ #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::{ - latest::{InteriorLocation, Junction, Junction::PalletInstance}, - VersionedLocation, -}; +use xcm::prelude::*; use xcm_builder::PayOverXcm; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -2336,6 +2337,48 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; + XcmPallet::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + XcmPallet::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + XcmPallet::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + XcmPallet::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + XcmPallet::dry_run_xcm::(origin_location, xcm) + } + } + impl sp_genesis_builder::GenesisBuilder for Runtime { fn build_state(config: Vec) -> sp_genesis_builder::Result { build_state::(config) diff --git a/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml b/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml index 1184dfc2f2..2e7bd9d438 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml +++ b/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml @@ -81,6 +81,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -157,6 +158,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -272,6 +274,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] # Enable metadata hash generation at compile time for the `CheckMetadataHash` extension. diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs index 09be6931df..42b4befc18 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs @@ -63,7 +63,7 @@ use frame_support::{ ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, Equals, InstanceFilter, TransformOrigin, WithdrawReasons, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, }; use frame_system::{ @@ -81,12 +81,19 @@ use system_parachains_constants::{ kusama::{consensus::*, currency::*, fee::WeightToFee}, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, }; -use xcm::latest::prelude::{AssetId, BodyId}; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; use xcm_config::{ FellowshipLocation, ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, KsmLocation, KsmLocationV3, PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocationV3, }; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -1283,6 +1290,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::KsmLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::KsmLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl assets_common::runtime_api::FungiblesApi< Block, AccountId, diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/Cargo.toml b/system-parachains/asset-hubs/asset-hub-polkadot/Cargo.toml index 4dce9f6a45..081e61c224 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/Cargo.toml +++ b/system-parachains/asset-hubs/asset-hub-polkadot/Cargo.toml @@ -81,6 +81,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -145,6 +146,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -254,6 +256,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] # Enable metadata hash generation at compile time for the `CheckMetadataHash` extension. diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs index f163a6bcfa..db4537a508 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -80,6 +80,10 @@ use sp_runtime::{ ApplyExtrinsicResult, Perbill, Permill, }; use xcm_config::TrustBackedAssetsPalletLocationV3; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -97,7 +101,7 @@ use frame_support::{ ConstU32, ConstU64, ConstU8, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, Equals, InstanceFilter, NeverEnsureOrigin, TransformOrigin, WithdrawReasons, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -116,7 +120,10 @@ use system_parachains_constants::{ polkadot::{consensus::*, currency::*, fee::WeightToFee}, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, }; -use xcm::latest::prelude::{AssetId, BodyId}; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; use xcm_config::{ DotLocation, DotLocationV3, FellowshipLocation, ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, PoolAssetsConvertedConcreteId, @@ -1244,6 +1251,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::DotLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::DotLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl assets_common::runtime_api::FungiblesApi< Block, AccountId, diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml b/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml index 6eb8dea2a9..3d972459a8 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -70,6 +70,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -221,7 +222,8 @@ std = [ "xcm-executor/std", "xcm/std", "bp-polkadot-bulletin/std", - "tuplex/std" + "tuplex/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ @@ -264,6 +266,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/system-parachains/bridge-hubs/bridge-hub-kusama/src/lib.rs b/system-parachains/bridge-hubs/bridge-hub-kusama/src/lib.rs index 48fa7da454..96784c165d 100644 --- a/system-parachains/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/system-parachains/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -60,7 +60,7 @@ use frame_support::{ tokens::imbalance::ResolveTo, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -91,6 +91,10 @@ use system_parachains_constants::{ // XCM Imports use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -739,6 +743,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::KsmRelayLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::KsmRelayLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 7ce786eb5b..d683b0c496 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -70,6 +70,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -217,7 +218,8 @@ std = [ "xcm-executor/std", "xcm/std", "bp-polkadot-bulletin/std", - "tuplex/std" + "tuplex/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ @@ -259,6 +261,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 7adceeecf3..2c41fa5ee3 100644 --- a/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/system-parachains/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -60,7 +60,7 @@ use frame_support::{ tokens::imbalance::ResolveTo, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -93,6 +93,10 @@ use system_parachains_constants::{ // XCM Imports use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -748,6 +752,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::DotRelayLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::DotRelayLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/collectives/collectives-polkadot/Cargo.toml b/system-parachains/collectives/collectives-polkadot/Cargo.toml index 83d9d08b1c..48e4e56133 100644 --- a/system-parachains/collectives/collectives-polkadot/Cargo.toml +++ b/system-parachains/collectives/collectives-polkadot/Cargo.toml @@ -68,6 +68,7 @@ polkadot-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -125,6 +126,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -229,6 +231,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] # Enable metadata hash generation at compile time for the `CheckMetadataHash` extension. diff --git a/system-parachains/collectives/collectives-polkadot/src/lib.rs b/system-parachains/collectives/collectives-polkadot/src/lib.rs index e7b06c621f..7fb5fc5dfa 100644 --- a/system-parachains/collectives/collectives-polkadot/src/lib.rs +++ b/system-parachains/collectives/collectives-polkadot/src/lib.rs @@ -73,7 +73,7 @@ use frame_support::{ fungible::HoldConsideration, tokens::imbalance::ResolveTo, ConstBool, ConstU16, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, LinearStoragePrice, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -101,6 +101,10 @@ pub use sp_runtime::BuildStorage; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -951,6 +955,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::DotLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::DotLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/coretime/coretime-kusama/Cargo.toml b/system-parachains/coretime/coretime-kusama/Cargo.toml index 810e50bffd..6af63bf4e1 100644 --- a/system-parachains/coretime/coretime-kusama/Cargo.toml +++ b/system-parachains/coretime/coretime-kusama/Cargo.toml @@ -63,6 +63,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } @@ -147,6 +148,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ @@ -175,6 +177,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/system-parachains/coretime/coretime-kusama/src/lib.rs b/system-parachains/coretime/coretime-kusama/src/lib.rs index aefd31d6f8..a2b87a2509 100644 --- a/system-parachains/coretime/coretime-kusama/src/lib.rs +++ b/system-parachains/coretime/coretime-kusama/src/lib.rs @@ -40,7 +40,7 @@ use frame_support::{ tokens::imbalance::ResolveTo, ConstBool, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, EverythingBut, InstanceFilter, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -72,11 +72,15 @@ use system_parachains_constants::{ AVERAGE_ON_INITIALIZE_RATIO, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::*; +use xcm::prelude::*; use xcm_config::{ FellowshipLocation, GovernanceLocation, KsmRelayLocation, StakingPot, XcmOriginToTransactDispatchOrigin, }; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -796,6 +800,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::KsmRelayLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::KsmRelayLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/encointer/Cargo.toml b/system-parachains/encointer/Cargo.toml index 0f75e3365b..0a5082c3d9 100644 --- a/system-parachains/encointer/Cargo.toml +++ b/system-parachains/encointer/Cargo.toml @@ -84,6 +84,7 @@ polkadot-runtime-common = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus dependencies cumulus-pallet-aura-ext = { workspace = true } @@ -150,6 +151,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] std = [ "codec/std", @@ -224,6 +226,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] diff --git a/system-parachains/encointer/src/lib.rs b/system-parachains/encointer/src/lib.rs index 0cce8191c3..61ea918c8c 100644 --- a/system-parachains/encointer/src/lib.rs +++ b/system-parachains/encointer/src/lib.rs @@ -61,7 +61,7 @@ use frame_support::{ ConstBool, ConstU64, Contains, EitherOfDiverse, EqualPrivilegeOnly, InstanceFilter, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -103,7 +103,14 @@ use system_parachains_constants::{ SLOT_DURATION, }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::{AssetId as XcmAssetId, BodyId}; +use xcm::{ + latest::prelude::{AssetId as XcmAssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::{KsmLocation, StakingPot, XcmOriginToTransactDispatchOrigin}; @@ -916,6 +923,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![XcmAssetId(xcm_config::KsmLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::KsmLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/people/people-kusama/Cargo.toml b/system-parachains/people/people-kusama/Cargo.toml index 9ebd65ac38..321df5d416 100644 --- a/system-parachains/people/people-kusama/Cargo.toml +++ b/system-parachains/people/people-kusama/Cargo.toml @@ -61,6 +61,7 @@ kusama-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-primitives-aura = { workspace = true } @@ -143,7 +144,8 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", - "polkadot-primitives/std" + "polkadot-primitives/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ @@ -172,7 +174,8 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks" + "polkadot-primitives/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/system-parachains/people/people-kusama/src/lib.rs b/system-parachains/people/people-kusama/src/lib.rs index 5e82749ca7..0585af8e62 100644 --- a/system-parachains/people/people-kusama/src/lib.rs +++ b/system-parachains/people/people-kusama/src/lib.rs @@ -35,7 +35,9 @@ use frame_support::{ tokens::imbalance::ResolveTo, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, InstanceFilter, TransformOrigin, }, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight}, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFee as _, + }, PalletId, }; use frame_system::{ @@ -69,11 +71,18 @@ use system_parachains_constants::kusama::{ consensus::RELAY_CHAIN_SLOT_DURATION_MILLIS, currency::*, fee::WeightToFee, }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::BodyId; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, StakingPot, XcmConfig, XcmOriginToTransactDispatchOrigin, }; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// This determines the average expected block time that we are targeting. Blocks will be /// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by @@ -783,6 +792,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::RelayLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::RelayLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) diff --git a/system-parachains/people/people-polkadot/Cargo.toml b/system-parachains/people/people-polkadot/Cargo.toml index 5fbf1bc4d0..56eb9e8810 100644 --- a/system-parachains/people/people-polkadot/Cargo.toml +++ b/system-parachains/people/people-polkadot/Cargo.toml @@ -60,6 +60,7 @@ polkadot-runtime-constants = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +xcm-fee-payment-runtime-api = { workspace = true } # Cumulus cumulus-primitives-aura = { workspace = true } @@ -140,6 +141,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ @@ -168,6 +170,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/system-parachains/people/people-polkadot/src/lib.rs b/system-parachains/people/people-polkadot/src/lib.rs index 001115df32..3208474c6e 100644 --- a/system-parachains/people/people-polkadot/src/lib.rs +++ b/system-parachains/people/people-polkadot/src/lib.rs @@ -34,7 +34,7 @@ use frame_support::{ tokens::imbalance::ResolveTo, ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, InstanceFilter, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; use frame_system::{ @@ -66,11 +66,18 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use system_parachains_constants::polkadot::{consensus::*, currency::*, fee::WeightToFee}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::BodyId; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, StakingPot, XcmConfig, XcmOriginToTransactDispatchOrigin, }; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -735,6 +742,48 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable_assets = vec![AssetId(xcm_config::RelayLocation::get())]; + PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::RelayLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::DryRunApi for Runtime { + fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_call::(origin, call) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + PolkadotXcm::dry_run_xcm::(origin_location, xcm) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header)