referrerpolicy=no-referrer-when-downgrade

emulated_integration_tests_common/
impls.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16pub use codec::{Decode, Encode};
17pub use paste;
18
19pub use crate::{
20	xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution},
21	PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD,
22};
23
24// Substrate
25pub use frame_support::{
26	assert_ok,
27	sp_runtime::AccountId32,
28	traits::fungibles::Inspect,
29	weights::{Weight, WeightMeter},
30};
31pub use pallet_assets;
32pub use pallet_message_queue;
33pub use pallet_xcm;
34pub use xcm;
35
36// Polkadot
37pub use polkadot_runtime_parachains::{
38	dmp, hrmp,
39	inclusion::{AggregateMessageOrigin, UmpQueueId},
40};
41pub use xcm::{
42	prelude::{
43		Asset, InteriorLocation, Location, OriginKind, Outcome, VersionedXcm, XcmError, XcmVersion,
44	},
45	DoubleEncoded,
46};
47
48// Cumulus
49pub use cumulus_pallet_parachain_system;
50pub use cumulus_pallet_xcmp_queue;
51pub use cumulus_primitives_core::{
52	relay_chain::HrmpChannelId, DmpMessageHandler, Junction, Junctions, NetworkId, ParaId,
53	XcmpMessageHandler,
54};
55pub use parachains_common::{AccountId, Balance};
56pub use xcm_emulator::{
57	assert_expected_events, bx, helpers::weight_within_threshold, BridgeLaneId, BridgeMessage,
58	BridgeMessageDispatchError, BridgeMessageHandler, Chain, Network, Parachain, RelayChain,
59	TestExt,
60};
61
62// Bridges
63use bp_messages::{
64	target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
65	MessageKey, OutboundLaneData,
66};
67pub use bp_xcm_bridge_hub::XcmBridgeHubCall;
68use pallet_bridge_messages::{Config as BridgeMessagesConfig, LaneIdOf, OutboundLanes, Pallet};
69pub use pallet_bridge_messages::{
70	Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2,
71	Instance3 as BridgeMessagesInstance3,
72};
73use pallet_xcm_bridge_hub::XcmBlobMessageDispatchResult;
74
75pub struct BridgeHubMessageHandler<S, SI, T, TI> {
76	_marker: std::marker::PhantomData<(S, SI, T, TI)>,
77}
78
79struct LaneIdWrapper<LaneId>(LaneId);
80impl<LaneId: Encode> From<LaneIdWrapper<LaneId>> for BridgeLaneId {
81	fn from(lane_id: LaneIdWrapper<LaneId>) -> BridgeLaneId {
82		lane_id.0.encode()
83	}
84}
85impl<LaneId: Decode> From<BridgeLaneId> for LaneIdWrapper<LaneId> {
86	fn from(id: BridgeLaneId) -> LaneIdWrapper<LaneId> {
87		LaneIdWrapper(LaneId::decode(&mut &id[..]).expect("decodable"))
88	}
89}
90
91impl<S, SI, T, TI> BridgeMessageHandler for BridgeHubMessageHandler<S, SI, T, TI>
92where
93	S: BridgeMessagesConfig<SI>,
94	SI: 'static,
95	T: BridgeMessagesConfig<TI>,
96	TI: 'static,
97	<T as BridgeMessagesConfig<TI>>::InboundPayload: From<Vec<u8>>,
98	<T as BridgeMessagesConfig<TI>>::MessageDispatch:
99		MessageDispatch<DispatchLevelResult = XcmBlobMessageDispatchResult>,
100{
101	fn get_source_outbound_messages() -> Vec<BridgeMessage> {
102		// get the source active outbound lanes
103		let active_outbound_lanes = OutboundLanes::<S, SI>::iter_keys();
104
105		let mut messages: Vec<BridgeMessage> = Default::default();
106
107		// collect messages from `OutboundMessages` for each active outbound lane in the source
108		for lane in active_outbound_lanes {
109			let latest_generated_nonce =
110				OutboundLanes::<S, SI>::get(lane).unwrap().latest_generated_nonce;
111			let latest_received_nonce =
112				OutboundLanes::<S, SI>::get(lane).unwrap().latest_received_nonce;
113
114			(latest_received_nonce + 1..=latest_generated_nonce).for_each(|nonce| {
115				let encoded_payload: Vec<u8> = Pallet::<S, SI>::outbound_message_data(lane, nonce)
116					.expect("Bridge message does not exist")
117					.into();
118				let payload = Vec::<u8>::decode(&mut &encoded_payload[..])
119					.expect("Decoding XCM message failed");
120				let message = BridgeMessage { lane_id: LaneIdWrapper(lane).into(), nonce, payload };
121
122				messages.push(message);
123			});
124		}
125		messages
126	}
127
128	fn dispatch_target_inbound_message(
129		message: BridgeMessage,
130	) -> Result<(), BridgeMessageDispatchError> {
131		type TargetMessageDispatch<T, I> = <T as BridgeMessagesConfig<I>>::MessageDispatch;
132		type InboundPayload<T, I> = <T as BridgeMessagesConfig<I>>::InboundPayload;
133
134		let lane_id = LaneIdWrapper::from(message.lane_id).0;
135		let nonce = message.nonce;
136		let payload = Ok(From::from(message.payload));
137
138		// Directly dispatch outbound messages assuming everything is correct
139		// and bypassing the `Relayers`  and `InboundLane` logic
140		let dispatch_result = TargetMessageDispatch::<T, TI>::dispatch(DispatchMessage {
141			key: MessageKey { lane_id, nonce },
142			data: DispatchMessageData::<InboundPayload<T, TI>> { payload },
143		});
144
145		let result = match dispatch_result.dispatch_level_result {
146			XcmBlobMessageDispatchResult::Dispatched => Ok(()),
147			XcmBlobMessageDispatchResult::InvalidPayload => Err(BridgeMessageDispatchError(
148				Box::new(XcmBlobMessageDispatchResult::InvalidPayload),
149			)),
150			XcmBlobMessageDispatchResult::NotDispatched(e) => Err(BridgeMessageDispatchError(
151				Box::new(XcmBlobMessageDispatchResult::NotDispatched(e)),
152			)),
153		};
154		result
155	}
156
157	fn notify_source_message_delivery(lane_id: BridgeLaneId) {
158		let lane_id: LaneIdOf<S, SI> = LaneIdWrapper::from(lane_id).0;
159		let data = OutboundLanes::<S, SI>::get(lane_id).unwrap();
160		let new_data = OutboundLaneData {
161			oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1,
162			latest_received_nonce: data.latest_received_nonce + 1,
163			..data
164		};
165
166		OutboundLanes::<S, SI>::insert(lane_id, new_data);
167	}
168}
169
170#[macro_export]
171macro_rules! impl_accounts_helpers_for_relay_chain {
172	( $chain:ident ) => {
173		$crate::impls::paste::paste! {
174			impl<N: $crate::impls::Network> $chain<N> {
175				/// Fund a set of accounts with a balance
176				pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) {
177					<Self as $crate::impls::TestExt>::execute_with(|| {
178						for account in accounts {
179							let who = account.0;
180							let actual = <Self as [<$chain RelayPallet>]>::Balances::free_balance(&who);
181							let actual = actual.saturating_add(<Self as [<$chain RelayPallet>]>::Balances::reserved_balance(&who));
182
183							$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::Balances::force_set_balance(
184								<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
185								who.into(),
186								actual.saturating_add(account.1),
187							));
188						}
189					});
190				}
191				/// Fund a sovereign account based on its Parachain Id
192				pub fn fund_para_sovereign(amount: $crate::impls::Balance, para_id: $crate::impls::ParaId) -> $crate::impls::AccountId32 {
193					let sovereign_account = <Self as $crate::impls::RelayChain>::sovereign_account_id_of_child_para(para_id);
194					Self::fund_accounts(vec![(sovereign_account.clone(), amount)]);
195					sovereign_account
196				}
197			}
198		}
199	};
200}
201
202#[macro_export]
203macro_rules! impl_assert_events_helpers_for_relay_chain {
204	( $chain:ident ) => {
205		$crate::impls::paste::paste! {
206			type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
207
208			impl<N: $crate::impls::Network> $chain<N> {
209				/// Asserts a dispatchable is completely executed and XCM sent
210				pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) {
211					$crate::impls::assert_expected_events!(
212						Self,
213						vec![
214							[<$chain RuntimeEvent>]::<N>::XcmPallet(
215								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete { used: weight } }
216							) => {
217								weight: $crate::impls::weight_within_threshold(
218									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
219									expected_weight.unwrap_or(*weight),
220									*weight
221								),
222							},
223						]
224					);
225				}
226
227				/// Asserts a dispatchable is incompletely executed and XCM sent
228				pub fn assert_xcm_pallet_attempted_incomplete(
229					expected_weight: Option<$crate::impls::Weight>,
230					expected_error: Option<$crate::impls::XcmError>,
231				) {
232					$crate::impls::assert_expected_events!(
233						Self,
234						vec![
235							// Dispatchable is properly executed and XCM message sent
236							[<$chain RuntimeEvent>]::<N>::XcmPallet(
237								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete { used: weight, error: $crate::impls::xcm::prelude::InstructionError { error, .. } } }
238							) => {
239								weight: $crate::impls::weight_within_threshold(
240									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
241									expected_weight.unwrap_or(*weight),
242									*weight
243								),
244								error: *error == expected_error.unwrap_or((*error).into()).into(),
245							},
246						]
247					);
248				}
249
250				/// Asserts an XCM program is sent.
251				pub fn assert_xcm_pallet_sent() {
252					$crate::impls::assert_expected_events!(
253						Self,
254						vec![
255							[<$chain RuntimeEvent>]::<N>::XcmPallet($crate::impls::pallet_xcm::Event::Sent { .. }) => {},
256						]
257					);
258				}
259
260				/// Asserts an XCM program from a System Parachain is successfully received and
261				/// processed within expectations.
262				pub fn assert_ump_queue_processed(
263					expected_success: bool,
264					expected_id: Option<$crate::impls::ParaId>,
265					expected_weight: Option<$crate::impls::Weight>,
266				) {
267					$crate::impls::assert_expected_events!(
268						Self,
269						vec![
270							// XCM is successfully received and processed
271							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
272								origin: $crate::impls::AggregateMessageOrigin::Ump($crate::impls::UmpQueueId::Para(id)),
273								weight_used,
274								success,
275								..
276							}) => {
277								id: *id == expected_id.unwrap_or(*id),
278								weight_used: $crate::impls::weight_within_threshold(
279									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
280									expected_weight.unwrap_or(*weight_used),
281									*weight_used
282								),
283								success: *success == expected_success,
284							},
285						]
286					);
287				}
288			}
289		}
290	};
291}
292
293#[macro_export]
294macro_rules! impl_hrmp_channels_helpers_for_relay_chain {
295	( $chain:ident ) => {
296		$crate::impls::paste::paste! {
297			impl<N: $crate::impls::Network> $chain<N> {
298				/// Init open channel request with another Parachain
299				pub fn init_open_channel_call(
300					recipient_para_id: $crate::impls::ParaId,
301					max_capacity: u32,
302					max_message_size: u32,
303				) -> $crate::impls::DoubleEncoded<()> {
304					use $crate::impls::Encode;
305
306					<Self as $crate::impls::Chain>::RuntimeCall::Hrmp($crate::impls::hrmp::Call::<
307						<Self as $crate::impls::Chain>::Runtime,
308					>::hrmp_init_open_channel {
309						recipient: recipient_para_id,
310						proposed_max_capacity: max_capacity,
311						proposed_max_message_size: max_message_size,
312					})
313					.encode()
314					.into()
315				}
316				/// Recipient Parachain accept the open request from another Parachain
317				pub fn accept_open_channel_call(sender_para_id: $crate::impls::ParaId) -> $crate::impls::DoubleEncoded<()> {
318					use $crate::impls::Encode;
319
320					<Self as $crate::impls::Chain>::RuntimeCall::Hrmp($crate::impls::hrmp::Call::<
321						<Self as $crate::impls::Chain>::Runtime,
322					>::hrmp_accept_open_channel {
323						sender: sender_para_id,
324					})
325					.encode()
326					.into()
327				}
328
329				/// A root origin force to open a channel between two Parachains
330				pub fn force_process_hrmp_open(sender: $crate::impls::ParaId, recipient: $crate::impls::ParaId) {
331					use $crate::impls::Chain;
332
333					<Self as $crate::impls::TestExt>::execute_with(|| {
334						let relay_root_origin = <Self as Chain>::RuntimeOrigin::root();
335
336						// Force process HRMP open channel requests without waiting for the next session
337						$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::Hrmp::force_process_hrmp_open(
338							relay_root_origin,
339							0
340						));
341
342						let channel_id = $crate::impls::HrmpChannelId { sender, recipient };
343
344						let hrmp_channel_exist = $crate::impls::hrmp::HrmpChannels::<
345							<Self as Chain>::Runtime,
346						>::contains_key(&channel_id);
347
348						// Check the HRMP channel has been successfully registered
349						assert!(hrmp_channel_exist)
350					});
351				}
352			}
353		}
354	};
355}
356
357#[macro_export]
358macro_rules! impl_send_transact_helpers_for_relay_chain {
359	( $chain:ident ) => {
360		$crate::impls::paste::paste! {
361			impl<N: $crate::impls::Network> $chain<N> {
362				/// A root origin (as governance) sends `xcm::Transact` with `UnpaidExecution` and encoded `call` to child parachain.
363				pub fn send_unpaid_transact_to_parachain_as_root(
364					recipient: $crate::impls::ParaId,
365					call: $crate::impls::DoubleEncoded<()>
366				) {
367					use $crate::impls::{bx, Chain, RelayChain};
368
369					<Self as $crate::impls::TestExt>::execute_with(|| {
370						let root_origin = <Self as Chain>::RuntimeOrigin::root();
371						let destination:  $crate::impls::Location = <Self as RelayChain>::child_location_of(recipient);
372						let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser);
373
374						$crate::impls::dmp::Pallet::<<Self as $crate::impls::Chain>::Runtime>::make_parachain_reachable(recipient);
375
376						// Send XCM `Transact`
377						$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::XcmPallet::send(
378							root_origin,
379							bx!(destination.into()),
380							bx!(xcm),
381						));
382						Self::assert_xcm_pallet_sent();
383					});
384				}
385			}
386		}
387	};
388}
389
390#[macro_export]
391macro_rules! impl_accounts_helpers_for_parachain {
392	( $chain:ident ) => {
393		$crate::impls::paste::paste! {
394			impl<N: $crate::impls::Network> $chain<N> {
395				/// Fund a set of accounts with a balance
396				pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) {
397					<Self as $crate::impls::TestExt>::execute_with(|| {
398						for account in accounts {
399							let who = account.0;
400							let actual = <Self as [<$chain ParaPallet>]>::Balances::free_balance(&who);
401							let actual = actual.saturating_add(<Self as [<$chain ParaPallet>]>::Balances::reserved_balance(&who));
402
403							$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Balances::force_set_balance(
404								<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
405								who.into(),
406								actual.saturating_add(account.1),
407							));
408						}
409					});
410				}
411
412				/// Fund a sovereign account of sibling para.
413				pub fn fund_para_sovereign(sibling_para_id: $crate::impls::ParaId, balance: $crate::impls::Balance) {
414					let sibling_location = Self::sibling_location_of(sibling_para_id);
415					let sovereign_account = Self::sovereign_account_id_of(sibling_location);
416					Self::fund_accounts(vec![(sovereign_account.into(), balance)])
417				}
418
419				/// Return local sovereign account of `para_id` on other `network_id`
420				pub fn sovereign_account_of_parachain_on_other_global_consensus(
421					network_id: $crate::impls::NetworkId,
422					para_id: $crate::impls::ParaId,
423				) -> $crate::impls::AccountId {
424					let remote_location = $crate::impls::Location::new(
425						2,
426						[
427							$crate::impls::Junction::GlobalConsensus(network_id),
428							$crate::impls::Junction::Parachain(para_id.into()),
429						],
430					);
431					<Self as $crate::impls::TestExt>::execute_with(|| {
432						Self::sovereign_account_id_of(remote_location)
433					})
434				}
435			}
436		}
437	};
438}
439
440#[macro_export]
441macro_rules! impl_assert_events_helpers_for_parachain {
442	( $chain:ident ) => {
443		$crate::impls::paste::paste! {
444			type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
445
446			impl<N: $crate::impls::Network> $chain<N> {
447				/// Asserts a dispatchable is completely executed and XCM sent
448				pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) {
449					$crate::impls::assert_expected_events!(
450						Self,
451						vec![
452							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
453								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete { used: weight } }
454							) => {
455								weight: $crate::impls::weight_within_threshold(
456									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
457									expected_weight.unwrap_or(*weight),
458									*weight
459								),
460							},
461						]
462					);
463				}
464
465				/// Asserts a dispatchable is incompletely executed and XCM sent
466				pub fn assert_xcm_pallet_attempted_incomplete(
467					expected_weight: Option<$crate::impls::Weight>,
468					expected_error: Option<$crate::impls::XcmError>,
469				) {
470					$crate::impls::assert_expected_events!(
471						Self,
472						vec![
473							// Dispatchable is properly executed and XCM message sent
474							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
475								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete { used: weight, error: $crate::impls::xcm::prelude::InstructionError { error, .. } } }
476							) => {
477								weight: $crate::impls::weight_within_threshold(
478									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
479									expected_weight.unwrap_or(*weight),
480									*weight
481								),
482								error: *error == expected_error.unwrap_or((*error).into()).into(),
483							},
484						]
485					);
486				}
487
488				/// Asserts a dispatchable throws and error when trying to be sent
489				pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::XcmError>) {
490					$crate::impls::assert_expected_events!(
491						Self,
492						vec![
493							// Execution fails in the origin with `Barrier`
494							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
495								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error($crate::impls::xcm::prelude::InstructionError { error, .. }) }
496							) => {
497								error: *error == expected_error.unwrap_or((*error).into()).into(),
498							},
499						]
500					);
501				}
502
503				/// Asserts a XCM message is sent
504				pub fn assert_xcm_pallet_sent() {
505					$crate::impls::assert_expected_events!(
506						Self,
507						vec![
508							[<$chain RuntimeEvent>]::<N>::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {},
509						]
510					);
511				}
512
513				/// Asserts a XCM message is sent to Relay Chain
514				pub fn assert_parachain_system_ump_sent() {
515					$crate::impls::assert_expected_events!(
516						Self,
517						vec![
518							[<$chain RuntimeEvent>]::<N>::ParachainSystem(
519								$crate::impls::cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
520							) => {},
521						]
522					);
523				}
524
525				/// Asserts a XCM from Relay Chain is completely executed
526				pub fn assert_dmp_queue_complete(expected_weight: Option<$crate::impls::Weight>) {
527					$crate::impls::assert_expected_events!(
528						Self,
529						vec![
530							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
531								success: true, weight_used: weight, ..
532							}) => {
533								weight: $crate::impls::weight_within_threshold(
534									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
535									expected_weight.unwrap_or(*weight),
536									*weight
537								),
538							},
539						]
540					);
541				}
542
543				/// Asserts a XCM from Relay Chain is incompletely executed
544				pub fn assert_dmp_queue_incomplete(
545					expected_weight: Option<$crate::impls::Weight>,
546				) {
547					$crate::impls::assert_expected_events!(
548						Self,
549						vec![
550							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
551								success: false, weight_used: weight, ..
552							}) => {
553								weight: $crate::impls::weight_within_threshold(
554									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
555									expected_weight.unwrap_or(*weight),
556									*weight
557								),
558							},
559						]
560					);
561				}
562
563				/// Asserts a XCM from Relay Chain is executed with error
564				pub fn assert_dmp_queue_error() {
565					$crate::impls::assert_expected_events!(
566						Self,
567						vec![
568							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed {
569								..
570							}) => {
571
572							},
573						]
574					);
575				}
576
577				/// Asserts a XCM from another Parachain is completely executed
578				pub fn assert_xcmp_queue_success(expected_weight: Option<$crate::impls::Weight>) {
579					$crate::impls::assert_expected_events!(
580						Self,
581						vec![
582							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }
583							) => {
584								weight: $crate::impls::weight_within_threshold(
585									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
586									expected_weight.unwrap_or(*weight),
587									*weight
588								),
589							},
590						]
591					);
592				}
593			}
594		}
595	};
596}
597
598#[macro_export]
599macro_rules! impl_assets_helpers_for_system_parachain {
600	( $chain:ident, $relay_chain:ident ) => {
601		$crate::impls::paste::paste! {
602			impl<N: $crate::impls::Network> $chain<N> {
603				/// Returns the encoded call for `force_create` from the assets pallet
604				pub fn force_create_asset_call(
605					asset_id: u32,
606					owner: $crate::impls::AccountId,
607					is_sufficient: bool,
608					min_balance: $crate::impls::Balance,
609				) -> $crate::impls::DoubleEncoded<()> {
610					use $crate::impls::{Chain, Encode};
611
612					<Self as Chain>::RuntimeCall::Assets($crate::impls::pallet_assets::Call::<
613						<Self as Chain>::Runtime,
614						$crate::impls::pallet_assets::Instance1,
615					>::force_create {
616						id: asset_id.into(),
617						owner: owner.into(),
618						is_sufficient,
619						min_balance,
620					})
621					.encode()
622					.into()
623				}
624
625				/// Returns a `VersionedXcm` for `force_create` from the assets pallet
626				pub fn force_create_asset_xcm(
627					origin_kind: $crate::impls::OriginKind,
628					asset_id: u32,
629					owner: $crate::impls::AccountId,
630					is_sufficient: bool,
631					min_balance: $crate::impls::Balance,
632				) -> $crate::impls::VersionedXcm<()> {
633					let call = Self::force_create_asset_call(asset_id, owner, is_sufficient, min_balance);
634					$crate::impls::xcm_transact_unpaid_execution(call, origin_kind)
635				}
636
637				/// Force create and mint assets making use of the assets pallet
638				pub fn force_create_and_mint_asset(
639					id: u32,
640					min_balance: u128,
641					is_sufficient: bool,
642					asset_owner: $crate::impls::AccountId,
643					dmp_weight_threshold: Option<$crate::impls::Weight>,
644					amount_to_mint: u128,
645				) {
646					use $crate::impls::Chain;
647
648					// Force create asset
649					Self::force_create_asset_from_relay_as_root(
650						id,
651						min_balance,
652						is_sufficient,
653						asset_owner.clone(),
654						dmp_weight_threshold
655					);
656
657					// Mint asset for System Parachain's sender
658					let signed_origin = <Self as Chain>::RuntimeOrigin::signed(asset_owner.clone());
659					Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint);
660				}
661
662				/// Relay Chain sends `Transact` instruction with `force_create_asset` to Parachain with `Assets` instance of `pallet_assets` .
663				pub fn force_create_asset_from_relay_as_root(
664					id: u32,
665					min_balance: u128,
666					is_sufficient: bool,
667					asset_owner: $crate::impls::AccountId,
668					dmp_weight_threshold: Option<$crate::impls::Weight>,
669				) {
670					use $crate::impls::{Parachain, Inspect, TestExt};
671
672					<$relay_chain<N>>::send_unpaid_transact_to_parachain_as_root(
673						Self::para_id(),
674						Self::force_create_asset_call(id, asset_owner.clone(), is_sufficient, min_balance),
675					);
676
677					// Receive XCM message in Assets Parachain
678					Self::execute_with(|| {
679						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
680
681						Self::assert_dmp_queue_complete(dmp_weight_threshold);
682
683						$crate::impls::assert_expected_events!(
684							Self,
685							vec![
686								RuntimeEvent::<N>::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => {
687									asset_id: *asset_id == id,
688									owner: *owner == asset_owner,
689								},
690							]
691						);
692
693						assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone().into()));
694					});
695				}
696			}
697		}
698	};
699}
700
701#[macro_export]
702macro_rules! impl_assets_helpers_for_parachain {
703	($chain:ident) => {
704		$crate::impls::paste::paste! {
705			impl<N: $crate::impls::Network> $chain<N> {
706				/// Create assets using sudo `Assets::force_create()`
707				pub fn force_create_asset(
708					id: u32,
709					owner: $crate::impls::AccountId,
710					is_sufficient: bool,
711					min_balance: u128,
712					prefund_accounts: Vec<($crate::impls::AccountId, u128)>,
713				) {
714					use $crate::impls::Inspect;
715					let sudo_origin = <$chain<N> as $crate::impls::Chain>::RuntimeOrigin::root();
716					<Self as $crate::impls::TestExt>::execute_with(|| {
717						$crate::impls::assert_ok!(
718							<Self as [<$chain ParaPallet>]>::Assets::force_create(
719								sudo_origin,
720								id.clone().into(),
721								owner.clone().into(),
722								is_sufficient,
723								min_balance,
724							)
725						);
726						assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone()));
727						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
728						$crate::impls::assert_expected_events!(
729							Self,
730							vec![
731								RuntimeEvent::<N>::Assets(
732									$crate::impls::pallet_assets::Event::ForceCreated {
733										asset_id,
734										..
735									}
736								) => { asset_id: *asset_id == id, },
737							]
738						);
739					});
740					for (beneficiary, amount) in prefund_accounts.into_iter() {
741						let signed_origin =
742							<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
743						Self::mint_asset(signed_origin, id.clone(), beneficiary, amount);
744					}
745				}
746
747				/// Mint assets making use of the assets pallet
748				pub fn mint_asset(
749					signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
750					id: u32,
751					beneficiary: $crate::impls::AccountId,
752					amount_to_mint: u128,
753				) {
754					<Self as $crate::impls::TestExt>::execute_with(|| {
755						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
756							signed_origin,
757							id.clone().into(),
758							beneficiary.clone().into(),
759							amount_to_mint
760						));
761
762						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
763
764						$crate::impls::assert_expected_events!(
765							Self,
766							vec![
767								RuntimeEvent::<N>::Assets(
768									$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
769								) => {
770									asset_id: *asset_id == id,
771									owner: *owner == beneficiary.clone().into(),
772									amount: *amount == amount_to_mint,
773								},
774							]
775						);
776					});
777				}
778
779				/// Returns the encoded call for `create` from the assets pallet
780				pub fn create_asset_call(
781					asset_id: u32,
782					min_balance: $crate::impls::Balance,
783					admin: $crate::impls::AccountId,
784				) -> $crate::impls::DoubleEncoded<()> {
785					use $crate::impls::{Chain, Encode};
786
787					<Self as Chain>::RuntimeCall::Assets($crate::impls::pallet_assets::Call::<
788						<Self as Chain>::Runtime,
789						$crate::impls::pallet_assets::Instance1,
790					>::create {
791						id: asset_id.into(),
792						min_balance,
793						admin: admin.into(),
794					})
795					.encode()
796					.into()
797				}
798			}
799		}
800	};
801}
802
803#[macro_export]
804macro_rules! impl_foreign_assets_helpers_for_parachain {
805	($chain:ident, $asset_id_type:ty) => {
806		$crate::impls::paste::paste! {
807			impl<N: $crate::impls::Network> $chain<N> {
808				/// Create foreign assets using sudo `ForeignAssets::force_create()`
809				pub fn force_create_foreign_asset(
810					id: $asset_id_type,
811					owner: $crate::impls::AccountId,
812					is_sufficient: bool,
813					min_balance: u128,
814					prefund_accounts: Vec<($crate::impls::AccountId, u128)>,
815				) {
816					use $crate::impls::Inspect;
817					let sudo_origin = <$chain<N> as $crate::impls::Chain>::RuntimeOrigin::root();
818					<Self as $crate::impls::TestExt>::execute_with(|| {
819						$crate::impls::assert_ok!(
820							<Self as [<$chain ParaPallet>]>::ForeignAssets::force_create(
821								sudo_origin,
822								id.clone(),
823								owner.clone().into(),
824								is_sufficient,
825								min_balance,
826							)
827						);
828						assert!(<Self as [<$chain ParaPallet>]>::ForeignAssets::asset_exists(id.clone()));
829						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
830						$crate::impls::assert_expected_events!(
831							Self,
832							vec![
833								RuntimeEvent::<N>::ForeignAssets(
834									$crate::impls::pallet_assets::Event::ForceCreated {
835										asset_id,
836										..
837									}
838								) => { asset_id: *asset_id == id, },
839							]
840						);
841					});
842					for (beneficiary, amount) in prefund_accounts.into_iter() {
843						let signed_origin =
844							<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
845						Self::mint_foreign_asset(signed_origin, id.clone(), beneficiary, amount);
846					}
847				}
848
849				/// Mint assets making use of the ForeignAssets pallet-assets instance
850				pub fn mint_foreign_asset(
851					signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
852					id: $asset_id_type,
853					beneficiary: $crate::impls::AccountId,
854					amount_to_mint: u128,
855				) {
856					<Self as $crate::impls::TestExt>::execute_with(|| {
857						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::ForeignAssets::mint(
858							signed_origin,
859							id.clone().into(),
860							beneficiary.clone().into(),
861							amount_to_mint
862						));
863
864						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
865
866						$crate::impls::assert_expected_events!(
867							Self,
868							vec![
869								RuntimeEvent::<N>::ForeignAssets(
870									$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
871								) => {
872									asset_id: *asset_id == id,
873									owner: *owner == beneficiary.clone().into(),
874									amount: *amount == amount_to_mint,
875								},
876							]
877						);
878					});
879				}
880
881				/// Returns the encoded call for `create` from the foreign assets pallet
882				pub fn create_foreign_asset_call(
883					asset_id: $asset_id_type,
884					min_balance: $crate::impls::Balance,
885					admin: $crate::impls::AccountId,
886				) -> $crate::impls::DoubleEncoded<()> {
887					use $crate::impls::{Chain, Encode};
888
889					<Self as Chain>::RuntimeCall::ForeignAssets($crate::impls::pallet_assets::Call::<
890						<Self as Chain>::Runtime,
891						$crate::impls::pallet_assets::Instance2,
892					>::create {
893						id: asset_id.into(),
894						min_balance,
895						admin: admin.into(),
896					})
897					.encode()
898					.into()
899				}
900			}
901		}
902	};
903}
904
905#[macro_export]
906macro_rules! impl_xcm_helpers_for_parachain {
907	( $chain:ident ) => {
908		$crate::impls::paste::paste! {
909			impl<N: $crate::impls::Network> $chain<N> {
910				/// Set XCM version for destination.
911				pub fn force_xcm_version(dest: $crate::impls::Location, version: $crate::impls::XcmVersion) {
912					<Self as $crate::impls::TestExt>::execute_with(|| {
913						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::PolkadotXcm::force_xcm_version(
914							<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
915							$crate::impls::bx!(dest),
916							version,
917						));
918					});
919				}
920
921				/// Set default/safe XCM version for runtime.
922				pub fn force_default_xcm_version(version: Option<$crate::impls::XcmVersion>) {
923					<Self as $crate::impls::TestExt>::execute_with(|| {
924						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::PolkadotXcm::force_default_xcm_version(
925							<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
926							version,
927						));
928					});
929				}
930			}
931		}
932	}
933}
934
935#[macro_export]
936macro_rules! impl_bridge_helpers_for_chain {
937	( $chain:ident, $pallet:ident, $pallet_xcm:ident, $runtime_call_wrapper:path ) => {
938		$crate::impls::paste::paste! {
939			impl<N: $crate::impls::Network> $chain<N> {
940				/// Open bridge with `dest`.
941				pub fn open_bridge(
942					bridge_location: $crate::impls::Location,
943					bridge_destination_universal_location: $crate::impls::InteriorLocation,
944					maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)>
945				) {
946					<Self as $crate::impls::TestExt>::execute_with(|| {
947						use $crate::impls::{bx, Chain};
948						use $crate::impls::XcmBridgeHubCall;
949						use $crate::impls::Encode;
950
951						// important to use `root` and `OriginKind::Xcm`
952						let root_origin = <Self as Chain>::RuntimeOrigin::root();
953
954						// construct call
955						let call: $crate::impls::DoubleEncoded<()> = $runtime_call_wrapper(XcmBridgeHubCall::open_bridge {
956							bridge_destination_universal_location: bx!(
957								bridge_destination_universal_location.clone().into()
958							)
959						}).encode().into();
960
961						let xcm = if let Some((fee_asset, beneficiary)) = maybe_paid {
962							$crate::impls::xcm_transact_paid_execution(call, $crate::impls::OriginKind::Xcm, fee_asset, beneficiary)
963						} else {
964							$crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Xcm)
965						};
966
967						// Send XCM `Transact` with `open_bridge` call
968						$crate::impls::assert_ok!(<Self as [<$chain $pallet>]>::$pallet_xcm::send(
969							root_origin,
970							bx!(bridge_location.into()),
971							bx!(xcm),
972						));
973						Self::assert_xcm_pallet_sent();
974					});
975				}
976			}
977		}
978	}
979}