From d4570a08203701dd3e391ad234c05d6d87aa7622 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 25 Jun 2024 20:26:04 +0200 Subject: [PATCH 01/28] feat(xcm): add XcmPaymentApi and DryRunApi to all runtimes --- Cargo.lock | 9 ++++ Cargo.toml | 1 + relay/kusama/Cargo.toml | 1 + relay/kusama/src/lib.rs | 51 +++++++++++++++++-- relay/polkadot/Cargo.toml | 3 ++ relay/polkadot/src/impls.rs | 1 - relay/polkadot/src/lib.rs | 51 +++++++++++++++++-- .../asset-hubs/asset-hub-kusama/Cargo.toml | 3 ++ .../asset-hubs/asset-hub-kusama/src/lib.rs | 49 +++++++++++++++++- .../asset-hubs/asset-hub-polkadot/Cargo.toml | 3 ++ .../asset-hubs/asset-hub-polkadot/src/lib.rs | 49 +++++++++++++++++- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 5 +- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 48 ++++++++++++++++- .../bridge-hub-polkadot/Cargo.toml | 5 +- .../bridge-hub-polkadot/src/lib.rs | 48 ++++++++++++++++- .../collectives-polkadot/Cargo.toml | 3 ++ .../collectives-polkadot/src/lib.rs | 48 ++++++++++++++++- system-parachains/encointer/Cargo.toml | 3 ++ system-parachains/encointer/src/lib.rs | 49 +++++++++++++++++- .../people/people-kusama/Cargo.toml | 7 ++- .../people/people-kusama/src/lib.rs | 51 ++++++++++++++++++- .../people/people-polkadot/Cargo.toml | 3 ++ .../people/people-polkadot/src/lib.rs | 51 ++++++++++++++++++- 23 files changed, 519 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be996e7cf0..2adf82c56a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -663,6 +663,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -794,6 +795,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1772,6 +1774,7 @@ dependencies = [ "substrate-wasm-builder", "system-parachains-constants", "tuplex", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1923,6 +1926,7 @@ dependencies = [ "substrate-wasm-builder", "system-parachains-constants", "tuplex", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -2432,6 +2436,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9363,6 +9368,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9465,6 +9471,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -9784,6 +9791,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "tokio", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -14023,6 +14031,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "tokio", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 066fe70f4d..a2b7665180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -234,6 +234,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" } diff --git a/relay/kusama/Cargo.toml b/relay/kusama/Cargo.toml index b2df38038f..ccd5be1507 100644 --- a/relay/kusama/Cargo.toml +++ b/relay/kusama/Cargo.toml @@ -100,6 +100,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 } diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index a12e731104..4ba563a7bb 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,9 +102,10 @@ 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_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, }; use xcm_builder::PayOverXcm; @@ -2285,6 +2286,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 c7f8c92b6b..5538600dc6 100644 --- a/relay/polkadot/Cargo.toml +++ b/relay/polkadot/Cargo.toml @@ -98,6 +98,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 } @@ -205,6 +206,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -253,6 +255,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 fd36be70e1..5c7ba85dc0 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,9 +102,10 @@ 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_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, }; use xcm_builder::PayOverXcm; @@ -2393,6 +2394,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..670220a007 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::{ @@ -82,6 +82,11 @@ use system_parachains_constants::{ AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, }; use xcm::latest::prelude::{AssetId, BodyId}; +use xcm::{VersionedXcm, VersionedLocation, VersionedAssetId, VersionedAssets}; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::{ FellowshipLocation, ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, KsmLocation, KsmLocationV3, PoolAssetsConvertedConcreteId, @@ -1283,6 +1288,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..b89f3f1807 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -79,6 +79,10 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, Permill, }; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::TrustBackedAssetsPalletLocationV3; use sp_std::prelude::*; @@ -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::{ @@ -117,6 +121,7 @@ use system_parachains_constants::{ AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, }; use xcm::latest::prelude::{AssetId, BodyId}; +use xcm::{VersionedLocation, VersionedAssets, VersionedAssetId, VersionedXcm}; use xcm_config::{ DotLocation, DotLocationV3, FellowshipLocation, ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, PoolAssetsConvertedConcreteId, @@ -1244,6 +1249,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/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..be68811ab6 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::{ @@ -104,6 +104,11 @@ use system_parachains_constants::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::latest::prelude::{AssetId as XcmAssetId, BodyId}; +use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; +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 +921,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 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..7e562f357d 100644 --- a/system-parachains/people/people-kusama/src/lib.rs +++ b/system-parachains/people/people-kusama/src/lib.rs @@ -35,7 +35,7 @@ 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,7 +69,12 @@ 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}; +use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, StakingPot, XcmConfig, XcmOriginToTransactDispatchOrigin, @@ -783,6 +788,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..f4ee771a9f 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,7 +66,12 @@ 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}; +use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; +use xcm_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::{ FellowshipLocation, GovernanceLocation, PriceForSiblingParachainDelivery, StakingPot, XcmConfig, XcmOriginToTransactDispatchOrigin, @@ -735,6 +740,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) From c44c69f946865dde5795440feb364e1e9798c62c Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 11:59:34 +0200 Subject: [PATCH 02/28] fix: fmt --- relay/kusama/src/lib.rs | 2 +- relay/polkadot/src/lib.rs | 2 +- .../asset-hubs/asset-hub-kusama/src/lib.rs | 12 +++++++----- .../asset-hubs/asset-hub-polkadot/src/lib.rs | 8 +++++--- system-parachains/encointer/src/lib.rs | 6 ++++-- .../people/people-kusama/src/lib.rs | 16 ++++++++++------ .../people/people-polkadot/src/lib.rs | 12 +++++++----- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index 4ba563a7bb..d66f9293e7 100644 --- a/relay/kusama/src/lib.rs +++ b/relay/kusama/src/lib.rs @@ -103,11 +103,11 @@ use sp_staking::SessionIndex; use sp_version::NativeVersion; use sp_version::RuntimeVersion; use xcm::prelude::*; +use xcm_builder::PayOverXcm; use xcm_fee_payment_runtime_api::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; -use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; diff --git a/relay/polkadot/src/lib.rs b/relay/polkadot/src/lib.rs index 5c7ba85dc0..15ce7ff842 100644 --- a/relay/polkadot/src/lib.rs +++ b/relay/polkadot/src/lib.rs @@ -103,11 +103,11 @@ use sp_std::{ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use xcm::prelude::*; +use xcm_builder::PayOverXcm; use xcm_fee_payment_runtime_api::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, }; -use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; 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 670220a007..42b4befc18 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs @@ -81,17 +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::{VersionedXcm, VersionedLocation, VersionedAssetId, VersionedAssets}; -use xcm_fee_payment_runtime_api::{ - dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, - fees::Error as XcmPaymentApiError, +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; 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 b89f3f1807..db4537a508 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/lib.rs @@ -79,11 +79,11 @@ use sp_runtime::{ transaction_validity::{TransactionSource, TransactionValidity}, 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 xcm_config::TrustBackedAssetsPalletLocationV3; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -120,8 +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::{VersionedLocation, VersionedAssets, VersionedAssetId, VersionedXcm}; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; use xcm_config::{ DotLocation, DotLocationV3, FellowshipLocation, ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, PoolAssetsConvertedConcreteId, diff --git a/system-parachains/encointer/src/lib.rs b/system-parachains/encointer/src/lib.rs index be68811ab6..f9899d9909 100644 --- a/system-parachains/encointer/src/lib.rs +++ b/system-parachains/encointer/src/lib.rs @@ -103,8 +103,10 @@ use system_parachains_constants::{ SLOT_DURATION, }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::{AssetId as XcmAssetId, BodyId}; -use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; +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, diff --git a/system-parachains/people/people-kusama/src/lib.rs b/system-parachains/people/people-kusama/src/lib.rs index 7e562f357d..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, WeightToFee as _}, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFee as _, + }, PalletId, }; use frame_system::{ @@ -69,16 +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::{AssetId, BodyId}; -use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; -use xcm_fee_payment_runtime_api::{ - dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, - fees::Error as XcmPaymentApiError, +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 diff --git a/system-parachains/people/people-polkadot/src/lib.rs b/system-parachains/people/people-polkadot/src/lib.rs index f4ee771a9f..3208474c6e 100644 --- a/system-parachains/people/people-polkadot/src/lib.rs +++ b/system-parachains/people/people-polkadot/src/lib.rs @@ -66,16 +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::{AssetId, BodyId}; -use xcm::{VersionedXcm, VersionedLocation, VersionedAssets, VersionedAssetId}; -use xcm_fee_payment_runtime_api::{ - dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, - fees::Error as XcmPaymentApiError, +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; From 2e748fb4b97386da74b9f5eda1e2eda8b52bc835 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 26 Jun 2024 14:31:35 +0200 Subject: [PATCH 03/28] feat(coretime-kusama-runtime): add XcmPaymentApi and DryRunApi --- Cargo.lock | 1 + .../asset-hub-polkadot/src/xcm_config.rs | 6 +++ .../coretime/coretime-kusama/Cargo.toml | 3 ++ .../coretime/coretime-kusama/src/lib.rs | 50 ++++++++++++++++++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2adf82c56a..6a95f7b7ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2641,6 +2641,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs index 66fbf44c88..dc935f0a15 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs @@ -105,6 +105,12 @@ pub type LocationToAccountId = ( GlobalConsensusEthereumConvertsFor, ); +#[test] +fn convert_hydradx_location_to_account_id() { + let location = Location::new(1, [Parachain(2034)]); + dbg!(&LocationToAccountId::convert_location(&location)); +} + /// Means for transacting the native currency on this chain. pub type FungibleTransactor = FungibleAdapter< // Use this currency: 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..94dd26136a 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,7 +72,11 @@ 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_fee_payment_runtime_api::{ + dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use xcm_config::{ FellowshipLocation, GovernanceLocation, KsmRelayLocation, StakingPot, XcmOriginToTransactDispatchOrigin, @@ -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) From ee2e8708fe73c7feb0b55a74c53fcb6ad420c011 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 12:00:40 +0200 Subject: [PATCH 04/28] fix: fmt --- system-parachains/coretime/coretime-kusama/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system-parachains/coretime/coretime-kusama/src/lib.rs b/system-parachains/coretime/coretime-kusama/src/lib.rs index 94dd26136a..a2b87a2509 100644 --- a/system-parachains/coretime/coretime-kusama/src/lib.rs +++ b/system-parachains/coretime/coretime-kusama/src/lib.rs @@ -73,14 +73,14 @@ use system_parachains_constants::{ }; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::prelude::*; -use xcm_fee_payment_runtime_api::{ - dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, - fees::Error as XcmPaymentApiError, -}; 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; From 555eb1a9a2ab4a9558dffe10f9b9515170c0c3a3 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 12:03:46 +0200 Subject: [PATCH 05/28] fix(encointer): AssetId -> XcmAssetId --- system-parachains/encointer/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system-parachains/encointer/src/lib.rs b/system-parachains/encointer/src/lib.rs index f9899d9909..61ea918c8c 100644 --- a/system-parachains/encointer/src/lib.rs +++ b/system-parachains/encointer/src/lib.rs @@ -925,12 +925,12 @@ 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())]; + 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::() { + match asset.try_as::() { Ok(asset_id) if asset_id.0 == xcm_config::KsmLocation::get() => { // for native token Ok(WeightToFee::weight_to_fee(&weight)) From f1cf7f9177cd9540690d4126179ea0c47a854cc8 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 12:04:42 +0200 Subject: [PATCH 06/28] feat(xcm-fee-payment-runtime-api): update Cargo.lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 6a95f7b7ef..516b340eb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3832,6 +3832,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] From 7d867b5082237b491892a8db41ebb3246dc19222 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 12:06:10 +0200 Subject: [PATCH 07/28] fix(kusama-runtime): feature propagation --- relay/kusama/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/relay/kusama/Cargo.toml b/relay/kusama/Cargo.toml index ccd5be1507..a487d08f94 100644 --- a/relay/kusama/Cargo.toml +++ b/relay/kusama/Cargo.toml @@ -209,6 +209,7 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", + "xcm-fee-payment-runtime-api/std" ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -259,6 +260,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", From 6b05e7d8d67ac870c41e772af9c8bf98b6d6bafd Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 25 Jun 2024 20:45:25 +0200 Subject: [PATCH 08/28] doc: update CHANGELOG --- CHANGELOG.md | 1 + .../asset-hubs/asset-hub-polkadot/src/xcm_config.rs | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5af3b2d71c..d9f97064f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - New call `hrmp.establish_channel_with_system` to allow parachains to establish a channel with a system parachain ([SDK v1.11 #3721](https://github.com/paritytech/polkadot-sdk/pull/3721)). - New runtime api to check if a validator has pending pages of rewards for an era ([SDK v1.12 #4301](https://github.com/paritytech/polkadot-sdk/pull/4301)). - Pallet-xcm: add new extrinsic for asset transfers using explicit reserve ([SDK v1.11 #3695](https://github.com/paritytech/polkadot-sdk/pull/3695)). +- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#359](https://github.com/polkadot-fellows/runtimes/pull/359)) - Ranked collective introduce `Add` and `Remove` origins ([SDK v1.8 #3212](https://github.com/paritytech/polkadot-sdk/pull/3212)). - Runtime apis to help with delegate-stake based Nomination Pools ([SDK v1.13 #4537](https://github.com/paritytech/polkadot-sdk/pull/4537)). - Kusama system chains: enable PoV-reclaim. diff --git a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs index dc935f0a15..66fbf44c88 100644 --- a/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs +++ b/system-parachains/asset-hubs/asset-hub-polkadot/src/xcm_config.rs @@ -105,12 +105,6 @@ pub type LocationToAccountId = ( GlobalConsensusEthereumConvertsFor, ); -#[test] -fn convert_hydradx_location_to_account_id() { - let location = Location::new(1, [Parachain(2034)]); - dbg!(&LocationToAccountId::convert_location(&location)); -} - /// Means for transacting the native currency on this chain. pub type FungibleTransactor = FungibleAdapter< // Use this currency: From 5e3e2dbfdd65cefcafc9be1d793d87b2cc52d38b Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Fri, 12 Jul 2024 12:38:33 +0200 Subject: [PATCH 09/28] doc: update CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f97064f8..e86ec6cab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added +### From [#380](https://github.com/polkadot-fellows/runtimes/pull/380): +- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#359](https://github.com/polkadot-fellows/runtimes/pull/359)) + #### 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)). @@ -30,7 +33,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - New call `hrmp.establish_channel_with_system` to allow parachains to establish a channel with a system parachain ([SDK v1.11 #3721](https://github.com/paritytech/polkadot-sdk/pull/3721)). - New runtime api to check if a validator has pending pages of rewards for an era ([SDK v1.12 #4301](https://github.com/paritytech/polkadot-sdk/pull/4301)). - Pallet-xcm: add new extrinsic for asset transfers using explicit reserve ([SDK v1.11 #3695](https://github.com/paritytech/polkadot-sdk/pull/3695)). -- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#359](https://github.com/polkadot-fellows/runtimes/pull/359)) - Ranked collective introduce `Add` and `Remove` origins ([SDK v1.8 #3212](https://github.com/paritytech/polkadot-sdk/pull/3212)). - Runtime apis to help with delegate-stake based Nomination Pools ([SDK v1.13 #4537](https://github.com/paritytech/polkadot-sdk/pull/4537)). - Kusama system chains: enable PoV-reclaim. From 138c5cc106ee73cabb023201543eab6541c84147 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Sat, 13 Jul 2024 00:00:46 +0200 Subject: [PATCH 10/28] test(asset-hub-polkadot): add XCM fee estimation test (not working) --- Cargo.lock | 1 + .../assets/asset-hub-polkadot/Cargo.toml | 1 + .../asset-hub-polkadot/src/tests/mod.rs | 1 + .../src/tests/xcm_fee_estimation.rs | 231 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs diff --git a/Cargo.lock b/Cargo.lock index 516b340eb3..3ddf27d66d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,6 +710,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] 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..8e656e115f 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 @@ -19,6 +19,7 @@ mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; +mod xcm_fee_estimation; mod swap; mod teleport; mod treasury; 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..198543c8e9 --- /dev/null +++ b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs @@ -0,0 +1,231 @@ +// 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::{ + AssetHubPolkadot, PenpalA, PenpalB, PenpalAPallet, PenpalAssetOwner, + ParaToParaThroughAHTest, PenpalBPallet, TransferType, + TestArgs, PenpalBReceiver, TestContext, PenpalASender, Chain, bx, +}; +use emulated_integration_tests_common::impls::{TestExt, Parachain, RelayChain}; +use frame_support::{ + sp_runtime::DispatchResult, + traits::fungibles::Inspect, + dispatch::RawOrigin, +}; +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; // 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(PenpalA::para_id()); + let sov_of_sender_on_ah = AssetHubPolkadot::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. + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), amount_to_send * 2)]); + + // Init values for Parachain Destination + let beneficiary_id = PenpalBReceiver::get(); + let beneficiary: Location = AccountId32 { + id: beneficiary_id.clone().into(), + network: None, // Test doesn't allow specifying a network here. + } + .into(); + + // 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 RuntimeCall = ::RuntimeCall; + // type OriginCaller = ::OriginCaller; + + // let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { + // dest: Box::new(VersionedLocation::V4(destination.clone())), + // beneficiary: Box::new(VersionedLocation::V4(beneficiary)), + // assets: Box::new(VersionedAssets::V4(assets.clone())), + // fee_asset_item: 0, + // weight_limit: Unlimited, + // }); + // let origin = OriginCaller::system(RawOrigin::Signed(PenpalASender::get())); + // let result = Runtime::dry_run_call(origin, call).unwrap(); + // assert_eq!(result.forwarded_xcms.len(), 1); + // let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + // 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); + // }); + + // // This is set in the Polkadot 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(Here.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[0]; + // // 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(); + AssetHubPolkadot::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, + ); + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.into(), amount_to_send * 2)]); + + // Actually run the extrinsic. + let test_args = TestContext { + sender: PenpalASender::get(), // Alice. + receiver: PenpalBReceiver::get(), // Bob in PenpalB. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + 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_dispatchable::(transfer_assets_para_to_para); + 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 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(test: ParaToParaThroughAHTest) -> DispatchResult { + let fee_index = test.args.fee_asset_item as usize; + let fee: Asset = test.args.assets.inner().get(fee_index).cloned().unwrap(); + let asset_hub_location: Location = PenpalA::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, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( + test.signed_origin, + bx!(test.args.dest.into()), + bx!(test.args.assets.clone().into()), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), + bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + test.args.weight_limit, + ) +} From 5fbe49a7695532091b2dfe2c1005840fec63d825 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 15 Jul 2024 13:34:23 +0200 Subject: [PATCH 11/28] fix(asset-hub-polkadot-integration-tests): reverse order A -> B to B -> A --- .../src/tests/xcm_fee_estimation.rs | 320 ++++++++++-------- 1 file changed, 187 insertions(+), 133 deletions(-) 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 index 198543c8e9..c1418cfd80 100644 --- 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 @@ -16,11 +16,12 @@ use crate::{ AssetHubPolkadot, PenpalA, PenpalB, PenpalAPallet, PenpalAssetOwner, ParaToParaThroughAHTest, PenpalBPallet, TransferType, - TestArgs, PenpalBReceiver, TestContext, PenpalASender, Chain, bx, + TestArgs, PenpalBSender, TestContext, PenpalAReceiver, Chain, bx, + assert_expected_events, }; -use emulated_integration_tests_common::impls::{TestExt, Parachain, RelayChain}; +use emulated_integration_tests_common::impls::{TestExt, Parachain}; use frame_support::{ - sp_runtime::DispatchResult, + sp_runtime::{DispatchResult, traits::Dispatchable}, traits::fungibles::Inspect, dispatch::RawOrigin, }; @@ -31,22 +32,22 @@ use xcm_fee_payment_runtime_api::{ }; /// 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. +/// 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 = PenpalA::sibling_location_of(PenpalB::para_id()); - let sender = PenpalASender::get(); + 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(PenpalA::para_id()); + 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 - PenpalA::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner.clone()), + PenpalB::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), relay_native_asset_location.clone(), sender.clone(), amount_to_send * 2, @@ -56,85 +57,89 @@ fn multi_hop_works() { AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone().into(), amount_to_send * 2)]); // Init values for Parachain Destination - let beneficiary_id = PenpalBReceiver::get(); - let beneficiary: Location = AccountId32 { - id: beneficiary_id.clone().into(), - network: None, // Test doesn't allow specifying a network here. - } - .into(); - - // 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 RuntimeCall = ::RuntimeCall; - // type OriginCaller = ::OriginCaller; - - // let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { - // dest: Box::new(VersionedLocation::V4(destination.clone())), - // beneficiary: Box::new(VersionedLocation::V4(beneficiary)), - // assets: Box::new(VersionedAssets::V4(assets.clone())), - // fee_asset_item: 0, - // weight_limit: Unlimited, - // }); - // let origin = OriginCaller::system(RawOrigin::Signed(PenpalASender::get())); - // let result = Runtime::dry_run_call(origin, call).unwrap(); - // assert_eq!(result.forwarded_xcms.len(), 1); - // let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; - // 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); - // }); + 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); + }); // // This is set in the Polkadot 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(Here.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[0]; - // // 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); - // }); + 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 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(); - // }); + 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(); @@ -142,7 +147,7 @@ fn multi_hop_works() { PenpalB::reset_ext(); // Fund accounts again. - PenpalA::mint_foreign_asset( + PenpalB::mint_foreign_asset( ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location.clone(), sender.clone(), @@ -151,55 +156,95 @@ fn multi_hop_works() { AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.into(), amount_to_send * 2)]); // Actually run the extrinsic. - let test_args = TestContext { - sender: PenpalASender::get(), // Alice. - receiver: PenpalBReceiver::get(), // Bob in PenpalB. - args: TestArgs::new_para( - destination, - beneficiary_id.clone(), - amount_to_send, - assets, - None, - 0, - ), - }; - let mut test = ParaToParaThroughAHTest::new(test_args); - - let sender_assets_before = PenpalA::execute_with(|| { - type ForeignAssets = ::ForeignAssets; + let sender_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; >::balance(relay_native_asset_location.clone(), &sender) }); - let receiver_assets_before = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; >::balance(relay_native_asset_location.clone(), &beneficiary_id) }); - test.set_dispatchable::(transfer_assets_para_to_para); + 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; + let sender_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; >::balance(relay_native_asset_location.clone(), &sender) }); - let receiver_assets_after = PenpalB::execute_with(|| { - type ForeignAssets = ::ForeignAssets; + 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 - // ); + 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; + 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; + 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 { @@ -210,22 +255,31 @@ fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { amount } -fn transfer_assets_para_to_para(test: ParaToParaThroughAHTest) -> DispatchResult { - let fee_index = test.args.fee_asset_item as usize; - let fee: Asset = test.args.assets.inner().get(fee_index).cloned().unwrap(); - let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubPolkadot::para_id()); +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.into()) { + 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, }]); - ::PolkadotXcm::transfer_assets_using_type_and_then( - test.signed_origin, - bx!(test.args.dest.into()), - bx!(test.args.assets.clone().into()), - bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(VersionedAssetId::V4(AssetId(Location::new(1, [])))), - bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - test.args.weight_limit, + 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, + } ) } From 57df0884c91cc923662965525c2d239a218bfcf3 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 15 Jul 2024 13:34:44 +0200 Subject: [PATCH 12/28] fix: fmt --- .../asset-hub-polkadot/src/tests/mod.rs | 2 +- .../src/tests/xcm_fee_estimation.rs | 69 +++++++++++-------- 2 files changed, 43 insertions(+), 28 deletions(-) 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 8e656e115f..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 @@ -19,7 +19,7 @@ mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; -mod xcm_fee_estimation; 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 index c1418cfd80..e04532e0dd 100644 --- 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 @@ -14,16 +14,15 @@ // limitations under the License. use crate::{ - AssetHubPolkadot, PenpalA, PenpalB, PenpalAPallet, PenpalAssetOwner, - ParaToParaThroughAHTest, PenpalBPallet, TransferType, - TestArgs, PenpalBSender, TestContext, PenpalAReceiver, Chain, bx, - assert_expected_events, + assert_expected_events, bx, AssetHubPolkadot, Chain, ParaToParaThroughAHTest, PenpalA, + PenpalAPallet, PenpalAReceiver, PenpalAssetOwner, PenpalB, PenpalBPallet, PenpalBSender, + TestArgs, TestContext, TransferType, }; -use emulated_integration_tests_common::impls::{TestExt, Parachain}; +use emulated_integration_tests_common::impls::{Parachain, TestExt}; use frame_support::{ - sp_runtime::{DispatchResult, traits::Dispatchable}, + dispatch::RawOrigin, + sp_runtime::{traits::Dispatchable, DispatchResult}, traits::fungibles::Inspect, - dispatch::RawOrigin, }; use xcm::prelude::*; use xcm_fee_payment_runtime_api::{ @@ -43,7 +42,8 @@ fn multi_hop_works() { 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()); + 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( @@ -84,8 +84,13 @@ fn multi_hop_works() { 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(); + 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 = @@ -104,8 +109,11 @@ fn multi_hop_works() { // 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(); + 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 = @@ -114,8 +122,13 @@ fn multi_hop_works() { // 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(); + 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. @@ -255,7 +268,9 @@ fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { amount } -fn transfer_assets_para_to_para_through_ah_dispatchable(test: ParaToParaThroughAHTest) -> DispatchResult { +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.into()) { Ok(_) => Ok(()), @@ -263,7 +278,9 @@ fn transfer_assets_para_to_para_through_ah_dispatchable(test: ParaToParaThroughA } } -fn transfer_assets_para_to_para_through_ah_call(test: ParaToParaThroughAHTest) -> ::RuntimeCall { +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()); @@ -271,15 +288,13 @@ fn transfer_assets_para_to_para_through_ah_call(test: ParaToParaThroughAHTest) - 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, - } - ) + 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, + }) } From d4642525c74e93981458ef8aa55d0b5ec765b65b Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 15 Jul 2024 14:01:11 +0200 Subject: [PATCH 13/28] feat(asset-hub-kusama-integration-tests): add test for XCM fee estimation --- Cargo.lock | 1 + .../tests/assets/asset-hub-kusama/Cargo.toml | 1 + .../assets/asset-hub-kusama/src/tests/mod.rs | 1 + .../src/tests/xcm_fee_estimation.rs | 301 ++++++++++++++++++ .../src/tests/xcm_fee_estimation.rs | 26 +- 5 files changed, 318 insertions(+), 12 deletions(-) create mode 100644 integration-tests/emulated/tests/assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs diff --git a/Cargo.lock b/Cargo.lock index 3ddf27d66d..eb165980d0 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]] 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..813c469698 --- /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; // 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 = 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); + }); + + // // This is set in the AssetHubKusama 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/src/tests/xcm_fee_estimation.rs b/integration-tests/emulated/tests/assets/asset-hub-polkadot/src/tests/xcm_fee_estimation.rs index e04532e0dd..bb25347534 100644 --- 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 @@ -13,6 +13,8 @@ // 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, @@ -54,7 +56,7 @@ fn multi_hop_works() { ); // 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().into(), amount_to_send * 2)]); + AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.clone(), amount_to_send * 2)]); // Init values for Parachain Destination let beneficiary_id = PenpalAReceiver::get(); @@ -155,18 +157,18 @@ fn multi_hop_works() { }); // Dry-running is done. - PenpalA::reset_ext(); - AssetHubPolkadot::reset_ext(); PenpalB::reset_ext(); + AssetHubPolkadot::reset_ext(); + PenpalA::reset_ext(); // Fund accounts again. PenpalB::mint_foreign_asset( - ::RuntimeOrigin::signed(asset_owner), + ::RuntimeOrigin::signed(asset_owner), relay_native_asset_location.clone(), sender.clone(), amount_to_send * 2, ); - AssetHubPolkadot::fund_accounts(vec![(sov_of_sender_on_ah.into(), 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(|| { @@ -210,11 +212,11 @@ fn multi_hop_works() { } fn sender_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(None); + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcm_pallet_attempted_complete(None); assert_expected_events!( - PenpalA, + PenpalB, vec![ RuntimeEvent::ForeignAssets( pallet_assets::Event::Burned { asset_id, owner, balance } @@ -244,11 +246,11 @@ fn hop_assertions(test: ParaToParaThroughAHTest) { } fn receiver_assertions(test: ParaToParaThroughAHTest) { - type RuntimeEvent = ::RuntimeEvent; - PenpalB::assert_xcmp_queue_success(None); + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcmp_queue_success(None); assert_expected_events!( - PenpalB, + PenpalA, vec![ RuntimeEvent::ForeignAssets( pallet_assets::Event::Issued { asset_id, owner, .. } @@ -272,7 +274,7 @@ 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.into()) { + match call.dispatch(test.signed_origin) { Ok(_) => Ok(()), Err(error_with_post_info) => Err(error_with_post_info.error), } From 4a53b10da04fa0b4162d34cd18e1c3a537c79ce1 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 15 Jul 2024 22:33:16 +0200 Subject: [PATCH 14/28] chore: address feedback --- CHANGELOG.md | 3 +-- .../assets/asset-hub-kusama/src/tests/xcm_fee_estimation.rs | 6 +++--- .../asset-hub-polkadot/src/tests/xcm_fee_estimation.rs | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e86ec6cab3..755d9d092d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added -### From [#380](https://github.com/polkadot-fellows/runtimes/pull/380): -- All runtimes: XcmPaymentApi and DryRunApi ([polkadot-fellows/runtimes#359](https://github.com/polkadot-fellows/runtimes/pull/359)) +- 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): 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 index 813c469698..eebb6b9cb4 100644 --- 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 @@ -39,7 +39,7 @@ use xcm_fee_payment_runtime_api::{ 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; // One DOT is 10 decimals but it's configured in Penpal as 12. + 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(); @@ -100,7 +100,7 @@ fn multi_hop_works() { delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); - // // This is set in the AssetHubKusama closure. + // 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())); @@ -144,7 +144,7 @@ fn multi_hop_works() { intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); - // // Get the final execution fees in the destination. + // Get the final execution fees in the destination. let mut final_execution_fees = 0; ::execute_with(|| { type Runtime = ::Runtime; 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 index bb25347534..8588e60846 100644 --- 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 @@ -101,7 +101,7 @@ fn multi_hop_works() { delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); - // // This is set in the Polkadot closure. + // 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())); @@ -145,7 +145,7 @@ fn multi_hop_works() { intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); }); - // // Get the final execution fees in the destination. + // Get the final execution fees in the destination. let mut final_execution_fees = 0; ::execute_with(|| { type Runtime = ::Runtime; From 1c215b195d4d2b4889ffbf6cf80d72726956c11b Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 15 Jul 2024 23:21:48 +0200 Subject: [PATCH 15/28] feat(integration-tests-helpers): use XCM runtime apis to estimate delivery fees --- Cargo.lock | 1 + integration-tests/emulated/helpers/src/lib.rs | 60 ++++++++++++++----- .../collectives-polkadot/Cargo.toml | 1 + .../src/tests/teleport.rs | 5 +- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb165980d0..addf77b9fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2363,6 +2363,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index 7f29c0e16b..e48a05f29e 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 and 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 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..9e58c69251 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,12 @@ 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}; 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::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; +use xcm_fee_payment_runtime_api::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; #[test] fn teleport_from_and_to_relay() { From 7a2fd64daa625d4c3cff6f67855d6bcf8561dfbc Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 00:03:25 +0200 Subject: [PATCH 16/28] feat(integration-tests-helpers): use XCM runtime apis to estimate delivery fees, back --- integration-tests/emulated/helpers/src/lib.rs | 65 ++++++++++++++++--- .../src/tests/teleport.rs | 2 +- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index e48a05f29e..850011f425 100644 --- a/integration-tests/emulated/helpers/src/lib.rs +++ b/integration-tests/emulated/helpers/src/lib.rs @@ -90,7 +90,7 @@ macro_rules! test_relay_is_trusted_teleporter { delivery_fees_amount = inner_delivery_fees_amount; }); - // Reset and send actual message. + // Reset to send actual message. <$sender_relay>::reset_ext(); <$receiver_para>::reset_ext(); @@ -172,16 +172,63 @@ 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(); + 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_para>::reset_ext(); + <$receiver_relay>::reset_ext(); + + // Since we reset everything, 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, )); + }); + + // 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; 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 9e58c69251..9ae4ac5cd1 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,7 +16,7 @@ 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, dispatch::RawOrigin, sp_runtime::traits::Dispatchable}; +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, }; From 5aa919ab55f2df38dc064ebd700f38e8bb32a630 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 00:04:36 +0200 Subject: [PATCH 17/28] fix: fmt --- .../collectives-polkadot/src/tests/teleport.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 9ae4ac5cd1..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,12 +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, dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate}; +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 xcm_fee_payment_runtime_api::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; -use xcm_fee_payment_runtime_api::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; +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() { From 181b9d4bfe6759d98642fed60a1e5ecd4972e038 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 11:37:15 +0200 Subject: [PATCH 18/28] feat(people): add delivery fees --- system-parachains/people/people-kusama/src/xcm_config.rs | 2 +- system-parachains/people/people-polkadot/src/xcm_config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system-parachains/people/people-kusama/src/xcm_config.rs b/system-parachains/people/people-kusama/src/xcm_config.rs index 2512cb7db1..a2e3e9c173 100644 --- a/system-parachains/people/people-kusama/src/xcm_config.rs +++ b/system-parachains/people/people-kusama/src/xcm_config.rs @@ -243,7 +243,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/system-parachains/people/people-polkadot/src/xcm_config.rs b/system-parachains/people/people-polkadot/src/xcm_config.rs index e3f1a6c245..c0af93c27c 100644 --- a/system-parachains/people/people-polkadot/src/xcm_config.rs +++ b/system-parachains/people/people-polkadot/src/xcm_config.rs @@ -266,7 +266,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From e59f4a18fb89c471ea06adf9b07a92c2a4a67a91 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 11:37:38 +0200 Subject: [PATCH 19/28] feat(people-kusama-integration-tests): teleport tests with delivery fees --- Cargo.lock | 3 + integration-tests/emulated/helpers/src/lib.rs | 41 +++-- .../tests/people/people-kusama/Cargo.toml | 3 + .../people-kusama/src/tests/teleport.rs | 174 +++--------------- 4 files changed, 57 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index addf77b9fc..9fe164879d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9292,11 +9292,13 @@ dependencies = [ "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", "people-kusama-runtime", @@ -9305,6 +9307,7 @@ dependencies = [ "staging-kusama-runtime", "staging-xcm", "staging-xcm-executor", + "xcm-fee-payment-runtime-api", ] [[package]] diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index 850011f425..05a22de138 100644 --- a/integration-tests/emulated/helpers/src/lib.rs +++ b/integration-tests/emulated/helpers/src/lib.rs @@ -157,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()); @@ -164,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; @@ -213,10 +232,15 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { <$sender_para>::reset_ext(); <$receiver_relay>::reset_ext(); - // Since we reset everything, 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. + // 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( @@ -270,13 +294,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/tests/people/people-kusama/Cargo.toml b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml index d14a9f43a9..140732df73 100644 --- a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml @@ -19,8 +19,10 @@ 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 } @@ -31,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..76c4471f55 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,54 +14,13 @@ // 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 people_kusama_runtime::xcm_config::XcmConfig as PeopleKusamaXcmConfig; - -fn relay_origin_assertions(t: RelayToSystemParaTest) { - type RuntimeEvent = ::RuntimeEvent; - Kusama::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(627_959_000, 7_200))); - - assert_expected_events!( - 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)), - ); - - assert_expected_events!( - 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, - }, - ] - ); -} +use integration_tests_helpers::{ + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, +}; +use xcm_fee_payment_runtime_api::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; +use xcm_fee_payment_runtime_api::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Kusama::assert_ump_queue_processed( @@ -93,33 +52,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,88 +63,24 @@ 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)]); +fn teleport_from_and_to_relay() { + let amount = KUSAMA_ED * 1000; + let native_asset: Assets = (Here, amount).into(); - 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) - }); + test_relay_is_trusted_teleporter!( + Kusama, + KusamaXcmConfig, + vec![PeopleKusama], + (native_asset, amount) + ); - // 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); + test_parachain_is_trusted_teleporter_for_relay!( + PeopleKusama, + PeopleKusamaXcmConfig, + Kusama, + amount + ); } /// Limited Teleport of native asset from System Parachain to Relay Chain From 708aa26024694ff59302f0ed5a1285a0454effc7 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 11:45:30 +0200 Subject: [PATCH 20/28] revert(people): delivery fees --- integration-tests/emulated/helpers/src/lib.rs | 12 ++++++++---- .../people/people-kusama/src/xcm_config.rs | 2 +- .../people/people-polkadot/src/xcm_config.rs | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/integration-tests/emulated/helpers/src/lib.rs b/integration-tests/emulated/helpers/src/lib.rs index 05a22de138..096e91b3b7 100644 --- a/integration-tests/emulated/helpers/src/lib.rs +++ b/integration-tests/emulated/helpers/src/lib.rs @@ -222,10 +222,14 @@ macro_rules! test_parachain_is_trusted_teleporter_for_relay { 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; + 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. diff --git a/system-parachains/people/people-kusama/src/xcm_config.rs b/system-parachains/people/people-kusama/src/xcm_config.rs index a2e3e9c173..2512cb7db1 100644 --- a/system-parachains/people/people-kusama/src/xcm_config.rs +++ b/system-parachains/people/people-kusama/src/xcm_config.rs @@ -243,7 +243,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; diff --git a/system-parachains/people/people-polkadot/src/xcm_config.rs b/system-parachains/people/people-polkadot/src/xcm_config.rs index c0af93c27c..e3f1a6c245 100644 --- a/system-parachains/people/people-polkadot/src/xcm_config.rs +++ b/system-parachains/people/people-polkadot/src/xcm_config.rs @@ -266,7 +266,7 @@ pub type LocalOriginToLocation = SignedToAccountId32, + cumulus_primitives_utility::ParentAsUmp, // ..and XCMP to communicate with the sibling chains. XcmpQueue, )>; From 0d1794c095a73d1fef9aa0d1eb03b09a53ed0b4d Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 11:45:59 +0200 Subject: [PATCH 21/28] fix: fmt --- .../tests/people/people-kusama/src/tests/teleport.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 76c4471f55..8a77ebb7b9 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,13 +14,17 @@ // limitations under the License. use crate::*; -use frame_support::{dispatch::RawOrigin, sp_runtime::traits::Dispatchable, traits::fungible::Mutate}; -use people_kusama_runtime::xcm_config::XcmConfig as PeopleKusamaXcmConfig; +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::fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1; -use xcm_fee_payment_runtime_api::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; +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_dest_assertions_fail(_t: SystemParaToRelayTest) { Kusama::assert_ump_queue_processed( From 92ff22c40e7340592d848f127670565f77d71ed6 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 12:01:07 +0200 Subject: [PATCH 22/28] feat(people-polkadot): teleport test with delivery fees --- Cargo.lock | 3 + .../people-kusama/src/tests/teleport.rs | 40 ++-- .../tests/people/people-polkadot/Cargo.toml | 3 + .../people-polkadot/src/tests/teleport.rs | 172 +++--------------- 4 files changed, 48 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fe164879d..b6b51bdbcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9400,9 +9400,11 @@ dependencies = [ "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", + "integration-tests-helpers", "pallet-balances", "pallet-identity", "pallet-message-queue", + "pallet-xcm", "parachains-common", "parity-scale-codec", "people-polkadot-runtime", @@ -9413,6 +9415,7 @@ dependencies = [ "sp-runtime 38.0.0", "staging-xcm", "staging-xcm-executor", + "xcm-fee-payment-runtime-api", ] [[package]] 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 8a77ebb7b9..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 @@ -26,6 +26,26 @@ use xcm_fee_payment_runtime_api::{ 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![PeopleKusama], + (native_asset, amount) + ); + + test_parachain_is_trusted_teleporter_for_relay!( + PeopleKusama, + PeopleKusamaXcmConfig, + Kusama, + amount + ); +} + fn relay_dest_assertions_fail(_t: SystemParaToRelayTest) { Kusama::assert_ump_queue_processed( false, @@ -67,26 +87,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -#[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![PeopleKusama], - (native_asset, amount) - ); - - test_parachain_is_trusted_teleporter_for_relay!( - PeopleKusama, - PeopleKusamaXcmConfig, - Kusama, - amount - ); -} - /// 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 ed9fef5f81..de541e552b 100644 --- a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml @@ -19,8 +19,10 @@ 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 } @@ -31,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] From ffc6c1b6af7258c34c75c3ebb4d23321af0c1bcb Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 12:25:29 +0200 Subject: [PATCH 23/28] feat(coretime-kusama-integration-tests): initial setup and test --- Cargo.lock | 39 +++++++++++ Cargo.toml | 3 + .../coretime/coretime-kusama/Cargo.toml | 22 ++++++ .../coretime/coretime-kusama/src/genesis.rs | 67 +++++++++++++++++++ .../coretime/coretime-kusama/src/lib.rs | 50 ++++++++++++++ .../networks/kusama-system/Cargo.toml | 1 + .../networks/kusama-system/src/lib.rs | 6 +- .../tests/coretime/coretime-kusama/Cargo.toml | 38 +++++++++++ .../tests/coretime/coretime-kusama/src/lib.rs | 54 +++++++++++++++ .../coretime/coretime-kusama/src/tests/mod.rs | 16 +++++ .../coretime-kusama/src/tests/teleport.rs | 46 +++++++++++++ 11 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/Cargo.toml create mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs create mode 100644 integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/lib.rs create mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/Cargo.toml create mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs create mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/mod.rs create mode 100644 integration-tests/emulated/tests/coretime/coretime-kusama/src/tests/teleport.rs diff --git a/Cargo.lock b/Cargo.lock index b6b51bdbcd..bc34a0c555 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2578,6 +2578,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" @@ -5754,6 +5792,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", diff --git a/Cargo.toml b/Cargo.toml index a2b7665180..52f531d053 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 } @@ -251,6 +252,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 +267,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..2e1bea3cdc --- /dev/null +++ b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs @@ -0,0 +1,67 @@ +// 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/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..d0a98c8ba9 100644 --- a/integration-tests/emulated/networks/kusama-system/src/lib.rs +++ b/integration-tests/emulated/networks/kusama-system/src/lib.rs @@ -18,12 +18,14 @@ pub use bridge_hub_kusama_emulated_chain; pub use kusama_emulated_chain; pub use penpal_emulated_chain; pub use people_kusama_emulated_chain; +pub use coretime_kusama_emulated_chain; use asset_hub_kusama_emulated_chain::AssetHubKusama; use bridge_hub_kusama_emulated_chain::BridgeHubKusama; use kusama_emulated_chain::Kusama; use penpal_emulated_chain::{PenpalA, PenpalB}; use people_kusama_emulated_chain::PeopleKusama; +use coretime_kusama_emulated_chain::CoretimeKusama; // Cumulus use emulated_integration_tests_common::{ @@ -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/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..f06fcb2d20 --- /dev/null +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs @@ -0,0 +1,54 @@ +// 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::{ + kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, + coretime_kusama_emulated_chain::{ + genesis::ED as CORETIME_KUSAMA_ED, CoretimeKusamaParaPallet as CoretimeKusamaPallet, + }, + KusamaRelay as Kusama, KusamaRelayReceiver as KusamaReceiver, + KusamaRelaySender as KusamaSender, PenpalAPara as PenpalA, CoretimeKusamaPara as CoretimeKusama, + CoretimeKusamaParaReceiver as CoretimeKusamaReceiver, CoretimeKusamaParaSender as CoretimeKusamaSender, +}; +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 + ); +} From c1cc4c3a0748cafe9db0fcdb7a5dbdbae24558c3 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 12:25:41 +0200 Subject: [PATCH 24/28] fix: fmt --- .../parachains/coretime/coretime-kusama/src/genesis.rs | 7 +++---- .../emulated/networks/kusama-system/src/lib.rs | 4 ++-- .../emulated/tests/coretime/coretime-kusama/src/lib.rs | 9 +++++---- 3 files changed, 10 insertions(+), 10 deletions(-) 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 index 2e1bea3cdc..1144e62497 100644 --- a/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs +++ b/integration-tests/emulated/chains/parachains/coretime/coretime-kusama/src/genesis.rs @@ -45,8 +45,8 @@ pub fn genesis() -> Storage { .into_iter() .map(|(acc, aura)| { ( - acc.clone(), // account id - acc, // validator id + acc.clone(), // account id + acc, // validator id coretime_kusama_runtime::SessionKeys { aura }, // session keys ) }) @@ -61,7 +61,6 @@ pub fn genesis() -> Storage { build_genesis_storage( &genesis_config, - coretime_kusama_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), + coretime_kusama_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), ) } diff --git a/integration-tests/emulated/networks/kusama-system/src/lib.rs b/integration-tests/emulated/networks/kusama-system/src/lib.rs index d0a98c8ba9..ed785d60af 100644 --- a/integration-tests/emulated/networks/kusama-system/src/lib.rs +++ b/integration-tests/emulated/networks/kusama-system/src/lib.rs @@ -15,17 +15,17 @@ 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; -pub use coretime_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; -use coretime_kusama_emulated_chain::CoretimeKusama; // Cumulus use emulated_integration_tests_common::{ diff --git a/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs index f06fcb2d20..0d3e3ac75c 100644 --- a/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs +++ b/integration-tests/emulated/tests/coretime/coretime-kusama/src/lib.rs @@ -40,13 +40,14 @@ pub use emulated_integration_tests_common::{ PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, XCM_V3, }; pub use kusama_system_emulated_network::{ - kusama_emulated_chain::{genesis::ED as KUSAMA_ED, KusamaRelayPallet as KusamaPallet}, coretime_kusama_emulated_chain::{ genesis::ED as CORETIME_KUSAMA_ED, CoretimeKusamaParaPallet as CoretimeKusamaPallet, }, - KusamaRelay as Kusama, KusamaRelayReceiver as KusamaReceiver, - KusamaRelaySender as KusamaSender, PenpalAPara as PenpalA, CoretimeKusamaPara as CoretimeKusama, - CoretimeKusamaParaReceiver as CoretimeKusamaReceiver, CoretimeKusamaParaSender as CoretimeKusamaSender, + 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}; From 59ed358bbd48e689c2a8a0a5f95b13c915e23921 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 12:34:45 +0200 Subject: [PATCH 25/28] feat(bridge-hub-kusama-integration-tests): teleport test with delivery fees --- Cargo.lock | 1 + .../bridges/bridge-hub-kusama/Cargo.toml | 1 + .../bridge-hub-kusama/src/tests/teleport.rs | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index bc34a0c555..16952fa48f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1672,6 +1672,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] 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/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 + ); +} From 9b22b37332dae06aba89e495dd797c6e6f5c1907 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 16 Jul 2024 12:39:21 +0200 Subject: [PATCH 26/28] feat(bridge-hub-polkadot-integration-tests): add teleport test with delivery fees --- Cargo.lock | 1 + .../bridges/bridge-hub-polkadot/Cargo.toml | 1 + .../bridges/bridge-hub-polkadot/src/lib.rs | 1 + .../bridge-hub-polkadot/src/tests/teleport.rs | 30 +++++++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 16952fa48f..fb89d92edf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1827,6 +1827,7 @@ dependencies = [ "staging-xcm", "staging-xcm-executor", "system-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] 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 + ); +} From 55b5191f8941293706bf51b61575bb61fab57543 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Wed, 17 Jul 2024 16:58:08 +0200 Subject: [PATCH 27/28] WIP --- .../bridges/bridge-hub-kusama/src/lib.rs | 2 +- .../src/tests/asset_transfers.rs | 119 +++++++++++++++++- .../bridge-hub-kusama/src/tests/mod.rs | 28 +++-- 3 files changed, 138 insertions(+), 11 deletions(-) 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..f2fa7ad7e0 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,107 @@ 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 +166,9 @@ 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 +197,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..8d0505be0a 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,14 +49,26 @@ 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, }) } From 899dcd74dda9eae3d0baf2bb9512ce9b4de7540f Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Mon, 22 Jul 2024 12:03:33 +0200 Subject: [PATCH 28/28] fix: fmt --- .../src/tests/asset_transfers.rs | 19 ++++++++++++++----- .../bridge-hub-kusama/src/tests/mod.rs | 19 +++++++++++-------- .../tests/people/people-kusama/Cargo.toml | 1 - .../tests/people/people-polkadot/Cargo.toml | 1 - 4 files changed, 25 insertions(+), 15 deletions(-) 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 f2fa7ad7e0..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 @@ -36,7 +36,10 @@ 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 { +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 @@ -50,7 +53,8 @@ fn dry_run_send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(id: 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 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(|| { @@ -90,7 +94,8 @@ fn dry_run_send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(id: Location, // 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(); + 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 = @@ -99,7 +104,8 @@ fn dry_run_send_asset_from_asset_hub_kusama_to_asset_hub_polkadot(id: Location, // 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(); + 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); @@ -167,7 +173,10 @@ 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); + 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(|| { 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 8d0505be0a..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,7 +49,8 @@ pub(crate) fn send_asset_from_asset_hub_kusama( let fee_asset_item = 0; AssetHubKusama::execute_with(|| { - let call = send_asset_from_asset_hub_kusama_call(destination, beneficiary, assets, fee_asset_item); + 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), @@ -63,13 +64,15 @@ pub(crate) fn send_asset_from_asset_hub_kusama_call( 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, - }) + ::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) { diff --git a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml index 011c53f015..140732df73 100644 --- a/integration-tests/emulated/tests/people/people-kusama/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-kusama/Cargo.toml @@ -21,7 +21,6 @@ pallet-identity = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true } xcm-fee-payment-runtime-api = { workspace = true, default-features = true } diff --git a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml index 3774cda59d..de541e552b 100644 --- a/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml +++ b/integration-tests/emulated/tests/people/people-polkadot/Cargo.toml @@ -21,7 +21,6 @@ pallet-identity = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } -pallet-xcm = { workspace = true, default-features = true } xcm-executor = { workspace = true } xcm-fee-payment-runtime-api = { workspace = true, default-features = true }