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