diff --git a/Cargo.lock b/Cargo.lock index ac7cba187b3..0316192668b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8632,6 +8632,7 @@ dependencies = [ "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-bridge-transfer-primitives", "pallet-collator-selection", "pallet-parachain-template", "pallet-session", diff --git a/parachain-template/pallets/template/src/lib.rs b/parachain-template/pallets/template/src/lib.rs index 911896d15d4..43aa7a7dce1 100644 --- a/parachain-template/pallets/template/src/lib.rs +++ b/parachain-template/pallets/template/src/lib.rs @@ -16,7 +16,9 @@ mod benchmarking; #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; + pub const LOG_TARGET: &str = "parachain-template"; + + use frame_support::{dispatch::DispatchResultWithPostInfo, log, pallet_prelude::*}; use frame_system::pallet_prelude::*; use sp_std::boxed::Box; use xcm::{v3::prelude::*, VersionedMultiLocation, VersionedXcm}; @@ -26,7 +28,8 @@ pub mod pallet { pub trait Config: frame_system::Config + pallet_xcm::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - } + type BridgeXcmSender: SendXcm; + } #[pallet::pallet] pub struct Pallet(_); @@ -49,6 +52,8 @@ pub mod pallet { SomethingStored(u32, T::AccountId), /// XCM message sent. \[to, message\] Sent { from: T::AccountId, to: MultiLocation, message: Xcm<()> }, + /// ExportMessage message was sent + SentExportMessage {forwarded_message_id: XcmHash, sender_cost: MultiAssets, message: Xcm<()> }, } // Errors inform users that something went wrong. @@ -67,6 +72,8 @@ pub mod pallet { /// The version of the `Versioned` value used is not able to be /// interpreted. BadVersion, + /// The bridge call failed. + BridgeCallError, } #[pallet::hooks] @@ -137,5 +144,32 @@ pub mod pallet { Self::deposit_event(Event::Sent { from: who, to: dest, message }); Ok(()) } + + #[pallet::call_index(3)] + #[pallet::weight(Weight::from_parts(100_000_000, 0))] + pub fn send_export_message_xcm( + origin: OriginFor, + dest: Box, + message: Box>, + ) -> DispatchResult { + let _who = ensure_signed(origin)?; + + let dest = MultiLocation::try_from(*dest).map_err(|()| Error::::BadVersion)?; + let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; + + let (forwarded_message_id, sender_cost) = send_xcm::(dest, message.clone()) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "[T::BridgeXcmSender] SendError occurred, error: {:?}", + e + ); + Error::::BridgeCallError + })?; + + + Self::deposit_event(Event::SentExportMessage {forwarded_message_id, sender_cost, message: message }); + Ok(()) + } } } diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index 6177e435472..ca8a02e3b12 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -73,6 +73,8 @@ cumulus-primitives-utility = { path = "../../primitives/utility", default-featur pallet-collator-selection = { path = "../../pallets/collator-selection", default-features = false } parachain-info = { path = "../../parachains/pallets/parachain-info", default-features = false } +pallet-bridge-transfer-primitives = { path = "../../parachains/pallets/bridge-transfer/primitives", default-features = false } + [features] default = [ "std", @@ -122,6 +124,7 @@ std = [ "xcm-executor/std", "xcm/std", "substrate-wasm-builder", + "pallet-bridge-transfer-primitives/std", ] runtime-benchmarks = [ diff --git a/parachain-template/runtime/src/lib.rs b/parachain-template/runtime/src/lib.rs index b2d4ea9f7dd..3ea93ea086c 100644 --- a/parachain-template/runtime/src/lib.rs +++ b/parachain-template/runtime/src/lib.rs @@ -59,6 +59,7 @@ use xcm_executor::XcmExecutor; /// Import the template pallet. pub use pallet_parachain_template; +use crate::xcm_config::bridging; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. pub type Signature = MultiSignature; @@ -460,6 +461,7 @@ impl pallet_collator_selection::Config for Runtime { /// Configure the pallet template in pallets/template. impl pallet_parachain_template::Config for Runtime { type RuntimeEvent = RuntimeEvent; + type BridgeXcmSender = bridging::BridgeXcmSender; } // Create the runtime by composing the FRAME pallets that were previously configured. diff --git a/parachain-template/runtime/src/xcm_config.rs b/parachain-template/runtime/src/xcm_config.rs index ff996d4dde3..1935c6bfa7f 100644 --- a/parachain-template/runtime/src/xcm_config.rs +++ b/parachain-template/runtime/src/xcm_config.rs @@ -17,16 +17,16 @@ use xcm_builder::{ CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, + SignedToAccountId32, SovereignPaidRemoteExporter, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::XcmExecutor; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub const RelayNetwork: Option = None; + pub const RelayNetwork: Option = Some(NetworkId::Kusama); pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorMultiLocation = Parachain(ParachainInfo::parachain_id().into()).into(); + pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -191,3 +191,45 @@ impl cumulus_pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; } + +/// All configuration related to bridging +pub mod bridging { + use pallet_bridge_transfer_primitives::{ + BridgeConfig, BridgesConfig, BridgesConfigAdapter, BridgesConfigBuilder, MaybePaidLocation, + }; + + use crate::xcm_config::{ + Junction::{GlobalConsensus, Parachain}, + Junctions::X1, + MultiLocation, SovereignPaidRemoteExporter, UniversalLocation, XcmRouter, + }; + use frame_support::parameter_types; + use xcm::v3::NetworkId; + + parameter_types! { + pub BridgeHubKusamaParaId: u32 = 1013; + pub BridgeHubKusama: MultiLocation = MultiLocation::new(1, X1(Parachain(BridgeHubKusamaParaId::get()))); + // Network and location for the local Ethereum testnet. + pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 15 }; + pub EthereumLocation: MultiLocation = MultiLocation::new(2, X1(GlobalConsensus(EthereumNetwork::get()))); + pub Bridges: BridgesConfig = BridgesConfigBuilder::default() + .add_or_panic( + EthereumNetwork::get(), + BridgeConfig::new( + MaybePaidLocation { + location: BridgeHubKusama::get(), + maybe_fee: None, + } + ).add_target_location( + MaybePaidLocation { + location: EthereumLocation::get(), + maybe_fee: None, // No fees supported for ethereum + }, + None, + )) + .build(); + } + + pub type BridgeXcmSender = + SovereignPaidRemoteExporter, XcmRouter, UniversalLocation>; +}