Skip to main content

snowbridge_inbound_queue_primitives/v2/
processor.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
3//! Message processor for inbound queue v2
4
5use super::*;
6use frame_support::traits::Get;
7use sp_runtime::traits::TryConvert;
8use sp_std::marker::PhantomData;
9use xcm::prelude::*;
10
11/// A message processor that converts messages to XCM and forwards them to AssetHub
12/// Generic parameters: T = pallet Config, Sender = XCM sender, Executor = fee handler,
13/// Converter = message converter, AccountToLocation = account-to-location converter
14pub struct XcmMessageProcessor<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>(
15	pub PhantomData<(T, Sender, Executor, Converter, AccountToLocation, TargetLocation)>,
16);
17
18impl<AccountId, T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
19	MessageProcessor<AccountId>
20	for XcmMessageProcessor<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
21where
22	T: frame_system::Config<AccountId = AccountId>,
23	Sender: SendXcm,
24	Executor: ExecuteXcm<T::RuntimeCall>,
25	Converter: ConvertMessage,
26	AccountToLocation: for<'a> TryConvert<&'a AccountId, Location>,
27	TargetLocation: Get<Location>,
28{
29	fn can_process_message(_relayer: &AccountId, _message: &Message) -> bool {
30		true
31	}
32
33	fn process_message(
34		relayer: AccountId,
35		message: Message,
36	) -> Result<[u8; 32], MessageProcessorError> {
37		// Process the message and return its ID
38		let id = Self::process_xcm(relayer, message)?;
39		Ok(id)
40	}
41}
42
43impl<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
44	XcmMessageProcessor<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
45where
46	T: frame_system::Config,
47	Sender: SendXcm,
48	Executor: ExecuteXcm<T::RuntimeCall>,
49	Converter: ConvertMessage,
50	AccountToLocation: for<'a> TryConvert<&'a T::AccountId, Location>,
51	TargetLocation: Get<Location>,
52{
53	/// Process a message and return the message ID
54	pub fn process_xcm(
55		who: T::AccountId,
56		message: Message,
57	) -> Result<XcmHash, MessageProcessorError> {
58		// Convert the message to XCM
59		let xcm = Converter::convert(message).map_err(|error| {
60			tracing::error!(target: LOG_TARGET, ?error, "XCM conversion failed with error");
61			MessageProcessorError::ConvertMessage(error)
62		})?;
63
64		// Forward XCM to a target location
65		let dest = TargetLocation::get();
66		let message_id = Self::send_xcm(dest.clone(), &who, xcm.clone()).map_err(|error| {
67			tracing::error!(target: LOG_TARGET, ?error, ?dest, ?xcm, "XCM send failed with error");
68			MessageProcessorError::SendMessage(error)
69		})?;
70
71		// Return the message_id
72		Ok(message_id)
73	}
74}
75
76impl<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
77	XcmMessageProcessor<T, Sender, Executor, Converter, AccountToLocation, TargetLocation>
78where
79	T: frame_system::Config,
80	Sender: SendXcm,
81	Executor: ExecuteXcm<T::RuntimeCall>,
82	Converter: ConvertMessage,
83	AccountToLocation: for<'a> TryConvert<&'a T::AccountId, Location>,
84	TargetLocation: Get<Location>,
85{
86	fn send_xcm(
87		dest: Location,
88		fee_payer: &T::AccountId,
89		xcm: Xcm<()>,
90	) -> Result<XcmHash, SendError> {
91		let fee_payer = AccountToLocation::try_convert(fee_payer).map_err(|err| {
92			tracing::error!(
93				target: LOG_TARGET,
94				?err,
95				"Failed to convert account to XCM location",
96			);
97			SendError::NotApplicable
98		})?;
99		let (ticket, fee) = validate_send::<Sender>(dest, xcm)?;
100		Executor::charge_fees(fee_payer, fee).map_err(|error| {
101			tracing::error!(
102				target: LOG_TARGET,
103				?error,
104				"Charging fees failed with error",
105			);
106			SendError::Fees
107		})?;
108		Sender::deliver(ticket)
109	}
110}