diff --git a/Cargo.lock b/Cargo.lock index a0800d01586..9895ca71c25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -609,6 +609,7 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub-router", "parachain-info", "parachains-common", "parity-scale-codec", diff --git a/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index dd2da85bca4..510ec0c3dab 100644 --- a/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -482,7 +482,7 @@ type LocalXcmRouter = ( /// queues. pub type XcmRouter = WithUniqueTopic<( LocalXcmRouter, - // Router, which wraps and sends xcm to BridgeHub to be delivered to the Polkadot GlobalConsensus + // Router which wraps and sends xcm to BridgeHub to be delivered to the Polkadot GlobalConsensus ToPolkadotXcmRouter, )>; diff --git a/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml b/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml index c24cbfc4b70..d1e47b87975 100644 --- a/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml +++ b/parachains/runtimes/assets/asset-hub-polkadot/Cargo.toml @@ -65,7 +65,7 @@ cumulus-pallet-dmp-queue = { path = "../../../../pallets/dmp-queue", default-fea cumulus-pallet-parachain-system = { path = "../../../../pallets/parachain-system", default-features = false } cumulus-pallet-session-benchmarking = { path = "../../../../pallets/session-benchmarking", default-features = false, version = "3.0.0" } cumulus-pallet-xcm = { path = "../../../../pallets/xcm", default-features = false } -cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false } +cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-features = false, features = ["bridging"] } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-timestamp = { path = "../../../../primitives/timestamp", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } @@ -74,6 +74,9 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } +# Bridges +pallet-xcm-bridge-hub-router = { path = "../../../../bridges/modules/xcm-bridge-hub-router", default-features = false } + [dev-dependencies] hex-literal = "0.4.1" asset-test-utils = { path = "../test-utils"} @@ -107,6 +110,7 @@ runtime-benchmarks = [ "cumulus-pallet-xcmp-queue/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "assets-common/runtime-benchmarks", + "pallet-xcm-bridge-hub-router/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -133,6 +137,7 @@ try-runtime = [ "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", + "pallet-xcm-bridge-hub-router/try-runtime", ] std = [ "codec/std", @@ -188,5 +193,6 @@ std = [ "parachain-info/std", "parachains-common/std", "assets-common/std", + "pallet-xcm-bridge-hub-router/std", "substrate-wasm-builder", ] diff --git a/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs b/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs index 4571c304648..582768031e5 100644 --- a/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs +++ b/parachains/runtimes/assets/asset-hub-polkadot/src/lib.rs @@ -64,7 +64,9 @@ mod weights; pub mod xcm_config; use assets_common::{ - foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId, + foreign_creators::ForeignCreators, + matching::{Equals, FromSiblingParachain}, + MultiLocationForAssetId, }; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use sp_api::impl_runtime_apis; @@ -720,6 +722,27 @@ impl pallet_nfts::Config for Runtime { type Helper = (); } +/// XCM router instance to BridgeHub with bridging capabilities for `Kusama` global consensus with dynamic fees and back-pressure. +pub type ToKusamaXcmRouterInstance = pallet_assets::Instance1; +impl pallet_xcm_bridge_hub_router::Config for Runtime { + type WeightInfo = (); // TODO: proper weights + + type UniversalLocation = xcm_config::UniversalLocation; + type BridgedNetworkId = xcm_config::bridging::KusamaNetwork; + type Bridges = xcm_config::bridging::FilteredNetworkExportTable; + + type BridgeHubOrigin = EnsureXcm>; + type ToBridgeHubSender = XcmpQueue; + type WithBridgeHubChannel = + cumulus_pallet_xcmp_queue::bridging::InboundAndOutboundXcmpChannelCongestionStatusProvider< + xcm_config::bridging::BridgeHubPolkadotParaId, + Runtime, + >; + + type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; + type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -756,6 +779,9 @@ construct_runtime!( Multisig: pallet_multisig::{Pallet, Call, Storage, Event} = 41, Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, + // Bridge utilities. + ToKusamaXcmRouter: pallet_xcm_bridge_hub_router::::{Pallet, Storage, Call} = 43, + // The main stage. Assets: pallet_assets::::{Pallet, Call, Storage, Event} = 50, Uniques: pallet_uniques::{Pallet, Call, Storage, Event} = 51, diff --git a/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs b/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs index 0b17c3ebdf0..a7a19b53faf 100644 --- a/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs +++ b/parachains/runtimes/assets/asset-hub-polkadot/src/xcm_config.rs @@ -16,7 +16,7 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, ForeignAssets, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + ToKusamaXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, }; use crate::ForeignAssetsInstance; use assets_common::matching::{ @@ -207,6 +207,14 @@ impl Contains for SafeCallFilter { } } + // Allow to change dedicated storage items (called by governance-like) + match call { + RuntimeCall::System(frame_system::Call::set_storage { items }) + if items.iter().any(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) => + return true, + _ => (), + }; + matches!( call, RuntimeCall::PolkadotXcm(pallet_xcm::Call::force_xcm_version { .. }) | @@ -460,6 +468,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); type AssetExchanger = (); + // TODO:check-parameter: change and assert in tests when (https://github.com/paritytech/polkadot/pull/7005) merged type FeeManager = (); type MessageExporter = (); type UniversalAliases = bridging::UniversalAliases; @@ -482,7 +491,11 @@ type LocalXcmRouter = ( /// The means for routing XCM messages which are not for local execution into the right message /// queues. -pub type XcmRouter = WithUniqueTopic<(LocalXcmRouter, bridging::BridgingXcmRouter)>; +pub type XcmRouter = WithUniqueTopic<( + LocalXcmRouter, + // Router which wraps and sends XCM to BridgeHub to be delivered to the Kusama GlobalConsensus + ToKusamaXcmRouter, +)>; #[cfg(feature = "runtime-benchmarks")] parameter_types! { @@ -567,7 +580,6 @@ pub mod bridging { use assets_common::{matching, matching::*}; use parachains_common::xcm_config::LocationFilter; use sp_std::collections::btree_set::BTreeSet; - use xcm_builder::UnpaidRemoteExporter; parameter_types! { pub BridgeHubPolkadotParaId: u32 = 1002; @@ -577,7 +589,14 @@ pub mod bridging { pub AssetHubKusama: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(KusamaNetwork::get()), Parachain(1000))); pub KsmLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(KusamaNetwork::get()))); + /// Router expects payment with this `AssetId`. + /// (`AssetId` has to be aligned with `BridgeTable`) + pub XcmBridgeHubRouterFeeAssetId: AssetId = DotLocation::get().into(); + /// Price per byte - can be adjusted via governance `set_storage` call. + pub storage XcmBridgeHubRouterByteFee: Balance = TransactionByteFee::get(); + /// Set up exporters configuration. + /// `Option` represents static "base fee" which is used for total delivery fee calculation. pub BridgeTable: sp_std::vec::Vec<(NetworkId, LocationFilter, MultiLocation, Option)> = sp_std::vec![ ( KusamaNetwork::get(), @@ -586,7 +605,9 @@ pub mod bridging { .add_equals(AssetHubKusama::get().interior.split_global().expect("invalid configuration for AssetHubKusama").1), // and nothing else BridgeHubPolkadot::get(), - None + // base delivery fee to local `BridgeHub` + // (initially was calculated `51220000` + 10% by test `BridgeHubPolkadot::can_calculate_weight_for_paid_export_message_with_reserve_transfer`) + Some((XcmBridgeHubRouterFeeAssetId::get(), 56342000).into()) ) ]; @@ -637,10 +658,6 @@ pub mod bridging { pub type FilteredNetworkExportTable = parachains_common::xcm_config::FilteredNetworkExportTable; - /// Bridge router, which wraps and sends xcm to BridgeHub to be delivered to the different GlobalConsensus - pub type BridgingXcmRouter = - UnpaidRemoteExporter; - /// Reserve locations filter for `xcm_executor::Config::IsReserve`. pub type IsTrustedBridgedReserveLocationForConcreteAsset = matching::IsTrustedBridgedReserveLocationForConcreteAsset< diff --git a/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs b/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs index a8f49e1fe3d..22d038a582d 100644 --- a/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs +++ b/parachains/runtimes/assets/asset-hub-polkadot/tests/tests.rs @@ -23,9 +23,10 @@ use asset_hub_polkadot_runtime::xcm_config::{ XcmConfig, }; pub use asset_hub_polkadot_runtime::{ - constants::fee::WeightToFee, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, System, TrustBackedAssetsInstance, XcmpQueue, + constants::fee::WeightToFee, xcm_config, AssetDeposit, Assets, Balances, ExistentialDeposit, + ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, + ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, System, + TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{CollatorSessionKey, CollatorSessionKeys, ExtBuilder, RuntimeHelper}; use codec::{Decode, Encode}; @@ -692,7 +693,7 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works() { }), bridging_to_asset_hub_kusama, WeightLimit::Unlimited, - None, + Some(xcm_config::bridging::XcmBridgeHubRouterFeeAssetId::get()), ) } @@ -799,3 +800,29 @@ fn xcm_reserve_transfer_filter_works() { } }) } + +#[test] +fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { + asset_test_utils::test_cases::change_storage_constant_by_governance_works::< + Runtime, + bridging::XcmBridgeHubRouterByteFee, + Balance, + >( + collator_session_keys(), + 1000, + Box::new(|call| RuntimeCall::System(call).encode()), + || { + ( + bridging::XcmBridgeHubRouterByteFee::key().to_vec(), + bridging::XcmBridgeHubRouterByteFee::get(), + ) + }, + |old_value| { + if let Some(new_value) = old_value.checked_add(1) { + new_value + } else { + old_value.checked_sub(1).unwrap() + } + }, + ) +}