diff --git a/bridges/snowbridge/pallets/inbound-queue-v2/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue-v2/src/lib.rs index 0eaadcb6a3c3..d923e4211ccb 100644 --- a/bridges/snowbridge/pallets/inbound-queue-v2/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue-v2/src/lib.rs @@ -95,7 +95,8 @@ pub mod pallet { type GatewayAddress: Get; type WeightInfo: WeightInfo; - + /// AssetHub parachain ID + type AssetHubParaId: Get; #[cfg(feature = "runtime-benchmarks")] type Helper: BenchmarkHelper; } @@ -139,6 +140,8 @@ pub mod pallet { Verification(VerificationError), /// XCMP send failure Send(SendError), + /// Message conversion error + ConvertMessage(ConvertMessageError), } #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo, PalletError)] @@ -204,25 +207,7 @@ pub mod pallet { let message = MessageV2::decode_all(&mut envelope.payload.as_ref()) .map_err(|_| Error::::InvalidPayload)?; - // Decode xcm - let versioned_xcm = VersionedXcm::<()>::decode_with_depth_limit( - MAX_XCM_DECODE_DEPTH, - &mut message.xcm.as_ref(), - ) - .map_err(|_| Error::::InvalidPayload)?; - let xcm: Xcm<()> = versioned_xcm.try_into().map_err(|_| >::InvalidPayload)?; - - log::info!( - target: LOG_TARGET, - "💫 xcm decoded as {:?}", - xcm, - ); - - // Set nonce flag to true - >::try_mutate(envelope.nonce, |done| -> DispatchResult { - *done = true; - Ok(()) - })?; + let xcm = convert_message(message)?; // Todo: Deposit fee(in Ether) to RewardLeger which should cover all of: // T::RewardLeger::deposit(who, envelope.fee.into())?; @@ -233,11 +218,17 @@ pub mod pallet { // e. The reward // Attempt to forward XCM to AH - let dest = Location::new(1, [Parachain(1000)]); + let dest = Location::new(1, [Parachain(T::AssetHubParaId)]); let (message_id, _) = send_xcm::(dest, xcm).map_err(Error::::from)?; Self::deposit_event(Event::MessageReceived { nonce: envelope.nonce, message_id }); + // Set nonce flag to true + >::try_mutate(envelope.nonce, |done| -> DispatchResult { + *done = true; + Ok(()) + })?; + Ok(()) } diff --git a/bridges/snowbridge/primitives/router/src/inbound/v2.rs b/bridges/snowbridge/primitives/router/src/inbound/v2.rs index 7a9cde2ff301..08bbae3c7c6e 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/v2.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/v2.rs @@ -4,17 +4,18 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; -use frame_support::{traits::tokens::Balance as BalanceT, PalletError}; +use frame_support::PalletError; use scale_info::TypeInfo; use snowbridge_core::TokenId; use sp_core::{Get, RuntimeDebug, H160, H256}; -use sp_io::hashing::blake2_256; -use sp_runtime::{traits::MaybeEquivalence, MultiAddress}; +use sp_runtime::MultiAddress; use sp_std::prelude::*; use xcm::prelude::{Junction::AccountKey20, *}; -use xcm_executor::traits::ConvertLocation; +use xcm::MAX_XCM_DECODE_DEPTH; +use codec::DecodeLimit; const MINIMUM_DEPOSIT: u128 = 1; +const LOG_TARGET: &str = "snowbridge-router-primitives"; /// Messages from Ethereum are versioned. This is because in future, /// we may want to evolve the protocol so that the ethereum side sends XCM messages directly. @@ -54,6 +55,71 @@ pub enum Asset { } } +/// Reason why a message conversion failed. +#[derive(Copy, Clone, TypeInfo, PalletError, Encode, Decode, RuntimeDebug)] +pub enum ConvertMessageError { + /// The XCM provided with the message could not be decoded into XCM. + InvalidXCM, + /// Invalid claimer MultiAddress provided in payload. + InvalidClaimer, +} + +pub trait ConvertMessage { + fn convert( + message: Message, + ) -> Result, ConvertMessageError>; +} + +pub struct MessageToXcm< + EthereumUniversalLocation, + AssetHubLocation, +> where + EthereumUniversalLocation: Get, + AssetHubLocation: Get, +{ + _phantom: PhantomData<( + EthereumUniversalLocation, + AssetHubLocation, + )>, +} + +impl< + EthereumUniversalLocation, + AssetHubLocation, +> ConvertMessage +for MessageToXcm< + EthereumUniversalLocation, + AssetHubLocation, +> + where + EthereumUniversalLocation: Get, + AssetHubLocation: Get, +{ + fn convert(message: Message) -> Result, ConvertMessageError> { + // Decode xcm + let versioned_xcm = VersionedXcm::<()>::decode_with_depth_limit( + MAX_XCM_DECODE_DEPTH, + &mut message.xcm.as_ref(), + ).map_err(|_| ConvertMessageError::InvalidXCM)?; + let message_xcm: Xcm<()> = versioned_xcm.try_into().map_err(|_| ConvertMessageError::InvalidXCM)?; + + log::debug!(target: LOG_TARGET,"xcm decoded as {:?}", message_xcm); + + let origin_location: Location = Location::new(2, [EthereumUniversalLocation::get().into(), Junction::AccountKey20{ key: message.origin.into(), network: None}.into()]); + let instructions = vec![ + AliasOrigin(origin_location), + ]; + + if let Some(claimer) = message.claimer { + let claimer = MultiAddress::decode(&mut claimer.as_ref()).map_err(|_| ConvertMessageError::InvalidClaimer)?; + let claimer_location: Location = Location::new(1, [AssetHubLocation::get().into(), claimer.into()]); + instructions.push(SetAssetClaimer { location: claimer_location }); + } + + Ok(instructions.into()) + } +} + #[cfg(test)] mod tests { use crate::inbound::{CallIndex, GlobalConsensusEthereumConvertsFor};