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						// Send XCM `Transact`
374						$crate::impls::assert_ok!(<Self as [<$chain RelayPallet>]>::XcmPallet::send(
375							root_origin,
376							bx!(destination.into()),
377							bx!(xcm),
378						));
379						Self::assert_xcm_pallet_sent();
380					});
381				}
382			}
383		}
384	};
385}
386
387#[macro_export]
388macro_rules! impl_accounts_helpers_for_parachain {
389	( $chain:ident ) => {
390		$crate::impls::paste::paste! {
391			impl<N: $crate::impls::Network> $chain<N> {
392				/// Fund a set of accounts with a balance
393				pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) {
394					<Self as $crate::impls::TestExt>::execute_with(|| {
395						for account in accounts {
396							let who = account.0;
397							let actual = <Self as [<$chain ParaPallet>]>::Balances::free_balance(&who);
398							let actual = actual.saturating_add(<Self as [<$chain ParaPallet>]>::Balances::reserved_balance(&who));
399
400							$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Balances::force_set_balance(
401								<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
402								who.into(),
403								actual.saturating_add(account.1),
404							));
405						}
406					});
407				}
408
409				/// Fund a sovereign account of sibling para.
410				pub fn fund_para_sovereign(sibling_para_id: $crate::impls::ParaId, balance: $crate::impls::Balance) {
411					let sibling_location = Self::sibling_location_of(sibling_para_id);
412					let sovereign_account = Self::sovereign_account_id_of(sibling_location);
413					Self::fund_accounts(vec![(sovereign_account.into(), balance)])
414				}
415
416				/// Return local sovereign account of `para_id` on other `network_id`
417				pub fn sovereign_account_of_parachain_on_other_global_consensus(
418					network_id: $crate::impls::NetworkId,
419					para_id: $crate::impls::ParaId,
420				) -> $crate::impls::AccountId {
421					let remote_location = $crate::impls::Location::new(
422						2,
423						[
424							$crate::impls::Junction::GlobalConsensus(network_id),
425							$crate::impls::Junction::Parachain(para_id.into()),
426						],
427					);
428					<Self as $crate::impls::TestExt>::execute_with(|| {
429						Self::sovereign_account_id_of(remote_location)
430					})
431				}
432			}
433		}
434	};
435}
436
437#[macro_export]
438macro_rules! impl_assert_events_helpers_for_parachain {
439	( $chain:ident ) => {
440		$crate::impls::paste::paste! {
441			type [<$chain RuntimeEvent>]<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
442
443			impl<N: $crate::impls::Network> $chain<N> {
444				/// Asserts a dispatchable is completely executed and XCM sent
445				pub fn assert_xcm_pallet_attempted_complete(expected_weight: Option<$crate::impls::Weight>) {
446					$crate::impls::assert_expected_events!(
447						Self,
448						vec![
449							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
450								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete { used: weight } }
451							) => {
452								weight: $crate::impls::weight_within_threshold(
453									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
454									expected_weight.unwrap_or(*weight),
455									*weight
456								),
457							},
458						]
459					);
460				}
461
462				/// Asserts a dispatchable is incompletely executed and XCM sent
463				pub fn assert_xcm_pallet_attempted_incomplete(
464					expected_weight: Option<$crate::impls::Weight>,
465					expected_error: Option<$crate::impls::XcmError>,
466				) {
467					$crate::impls::assert_expected_events!(
468						Self,
469						vec![
470							// Dispatchable is properly executed and XCM message sent
471							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
472								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete { used: weight, error } }
473							) => {
474								weight: $crate::impls::weight_within_threshold(
475									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
476									expected_weight.unwrap_or(*weight),
477									*weight
478								),
479								error: *error == expected_error.unwrap_or((*error).into()).into(),
480							},
481						]
482					);
483				}
484
485				/// Asserts a dispatchable throws and error when trying to be sent
486				pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::XcmError>) {
487					$crate::impls::assert_expected_events!(
488						Self,
489						vec![
490							// Execution fails in the origin with `Barrier`
491							[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
492								$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error { error } }
493							) => {
494								error: *error == expected_error.unwrap_or((*error).into()).into(),
495							},
496						]
497					);
498				}
499
500				/// Asserts a XCM message is sent
501				pub fn assert_xcm_pallet_sent() {
502					$crate::impls::assert_expected_events!(
503						Self,
504						vec![
505							[<$chain RuntimeEvent>]::<N>::PolkadotXcm($crate::impls::pallet_xcm::Event::Sent { .. }) => {},
506						]
507					);
508				}
509
510				/// Asserts a XCM message is sent to Relay Chain
511				pub fn assert_parachain_system_ump_sent() {
512					$crate::impls::assert_expected_events!(
513						Self,
514						vec![
515							[<$chain RuntimeEvent>]::<N>::ParachainSystem(
516								$crate::impls::cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
517							) => {},
518						]
519					);
520				}
521
522				/// Asserts a XCM from Relay Chain is completely executed
523				pub fn assert_dmp_queue_complete(expected_weight: Option<$crate::impls::Weight>) {
524					$crate::impls::assert_expected_events!(
525						Self,
526						vec![
527							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
528								success: true, weight_used: weight, ..
529							}) => {
530								weight: $crate::impls::weight_within_threshold(
531									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
532									expected_weight.unwrap_or(*weight),
533									*weight
534								),
535							},
536						]
537					);
538				}
539
540				/// Asserts a XCM from Relay Chain is incompletely executed
541				pub fn assert_dmp_queue_incomplete(
542					expected_weight: Option<$crate::impls::Weight>,
543				) {
544					$crate::impls::assert_expected_events!(
545						Self,
546						vec![
547							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed {
548								success: false, weight_used: weight, ..
549							}) => {
550								weight: $crate::impls::weight_within_threshold(
551									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
552									expected_weight.unwrap_or(*weight),
553									*weight
554								),
555							},
556						]
557					);
558				}
559
560				/// Asserts a XCM from Relay Chain is executed with error
561				pub fn assert_dmp_queue_error() {
562					$crate::impls::assert_expected_events!(
563						Self,
564						vec![
565							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::ProcessingFailed {
566								..
567							}) => {
568
569							},
570						]
571					);
572				}
573
574				/// Asserts a XCM from another Parachain is completely executed
575				pub fn assert_xcmp_queue_success(expected_weight: Option<$crate::impls::Weight>) {
576					$crate::impls::assert_expected_events!(
577						Self,
578						vec![
579							[<$chain RuntimeEvent>]::<N>::MessageQueue($crate::impls::pallet_message_queue::Event::Processed { success: true, weight_used: weight, .. }
580							) => {
581								weight: $crate::impls::weight_within_threshold(
582									($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
583									expected_weight.unwrap_or(*weight),
584									*weight
585								),
586							},
587						]
588					);
589				}
590			}
591		}
592	};
593}
594
595#[macro_export]
596macro_rules! impl_assets_helpers_for_system_parachain {
597	( $chain:ident, $relay_chain:ident ) => {
598		$crate::impls::paste::paste! {
599			impl<N: $crate::impls::Network> $chain<N> {
600				/// Returns the encoded call for `force_create` from the assets pallet
601				pub fn force_create_asset_call(
602					asset_id: u32,
603					owner: $crate::impls::AccountId,
604					is_sufficient: bool,
605					min_balance: $crate::impls::Balance,
606				) -> $crate::impls::DoubleEncoded<()> {
607					use $crate::impls::{Chain, Encode};
608
609					<Self as Chain>::RuntimeCall::Assets($crate::impls::pallet_assets::Call::<
610						<Self as Chain>::Runtime,
611						$crate::impls::pallet_assets::Instance1,
612					>::force_create {
613						id: asset_id.into(),
614						owner: owner.into(),
615						is_sufficient,
616						min_balance,
617					})
618					.encode()
619					.into()
620				}
621
622				/// Returns a `VersionedXcm` for `force_create` from the assets pallet
623				pub fn force_create_asset_xcm(
624					origin_kind: $crate::impls::OriginKind,
625					asset_id: u32,
626					owner: $crate::impls::AccountId,
627					is_sufficient: bool,
628					min_balance: $crate::impls::Balance,
629				) -> $crate::impls::VersionedXcm<()> {
630					let call = Self::force_create_asset_call(asset_id, owner, is_sufficient, min_balance);
631					$crate::impls::xcm_transact_unpaid_execution(call, origin_kind)
632				}
633
634				/// Force create and mint assets making use of the assets pallet
635				pub fn force_create_and_mint_asset(
636					id: u32,
637					min_balance: u128,
638					is_sufficient: bool,
639					asset_owner: $crate::impls::AccountId,
640					dmp_weight_threshold: Option<$crate::impls::Weight>,
641					amount_to_mint: u128,
642				) {
643					use $crate::impls::Chain;
644
645					// Force create asset
646					Self::force_create_asset_from_relay_as_root(
647						id,
648						min_balance,
649						is_sufficient,
650						asset_owner.clone(),
651						dmp_weight_threshold
652					);
653
654					// Mint asset for System Parachain's sender
655					let signed_origin = <Self as Chain>::RuntimeOrigin::signed(asset_owner.clone());
656					Self::mint_asset(signed_origin, id, asset_owner, amount_to_mint);
657				}
658
659				/// Relay Chain sends `Transact` instruction with `force_create_asset` to Parachain with `Assets` instance of `pallet_assets` .
660				pub fn force_create_asset_from_relay_as_root(
661					id: u32,
662					min_balance: u128,
663					is_sufficient: bool,
664					asset_owner: $crate::impls::AccountId,
665					dmp_weight_threshold: Option<$crate::impls::Weight>,
666				) {
667					use $crate::impls::{Parachain, Inspect, TestExt};
668
669					<$relay_chain<N>>::send_unpaid_transact_to_parachain_as_root(
670						Self::para_id(),
671						Self::force_create_asset_call(id, asset_owner.clone(), is_sufficient, min_balance),
672					);
673
674					// Receive XCM message in Assets Parachain
675					Self::execute_with(|| {
676						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
677
678						Self::assert_dmp_queue_complete(dmp_weight_threshold);
679
680						$crate::impls::assert_expected_events!(
681							Self,
682							vec![
683								RuntimeEvent::<N>::Assets($crate::impls::pallet_assets::Event::ForceCreated { asset_id, owner }) => {
684									asset_id: *asset_id == id,
685									owner: *owner == asset_owner,
686								},
687							]
688						);
689
690						assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone().into()));
691					});
692				}
693			}
694		}
695	};
696}
697
698#[macro_export]
699macro_rules! impl_assets_helpers_for_parachain {
700	($chain:ident) => {
701		$crate::impls::paste::paste! {
702			impl<N: $crate::impls::Network> $chain<N> {
703				/// Create assets using sudo `Assets::force_create()`
704				pub fn force_create_asset(
705					id: u32,
706					owner: $crate::impls::AccountId,
707					is_sufficient: bool,
708					min_balance: u128,
709					prefund_accounts: Vec<($crate::impls::AccountId, u128)>,
710				) {
711					use $crate::impls::Inspect;
712					let sudo_origin = <$chain<N> as $crate::impls::Chain>::RuntimeOrigin::root();
713					<Self as $crate::impls::TestExt>::execute_with(|| {
714						$crate::impls::assert_ok!(
715							<Self as [<$chain ParaPallet>]>::Assets::force_create(
716								sudo_origin,
717								id.clone().into(),
718								owner.clone().into(),
719								is_sufficient,
720								min_balance,
721							)
722						);
723						assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone()));
724						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
725						$crate::impls::assert_expected_events!(
726							Self,
727							vec![
728								RuntimeEvent::<N>::Assets(
729									$crate::impls::pallet_assets::Event::ForceCreated {
730										asset_id,
731										..
732									}
733								) => { asset_id: *asset_id == id, },
734							]
735						);
736					});
737					for (beneficiary, amount) in prefund_accounts.into_iter() {
738						let signed_origin =
739							<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
740						Self::mint_asset(signed_origin, id.clone(), beneficiary, amount);
741					}
742				}
743
744				/// Mint assets making use of the assets pallet
745				pub fn mint_asset(
746					signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
747					id: u32,
748					beneficiary: $crate::impls::AccountId,
749					amount_to_mint: u128,
750				) {
751					<Self as $crate::impls::TestExt>::execute_with(|| {
752						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
753							signed_origin,
754							id.clone().into(),
755							beneficiary.clone().into(),
756							amount_to_mint
757						));
758
759						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
760
761						$crate::impls::assert_expected_events!(
762							Self,
763							vec![
764								RuntimeEvent::<N>::Assets(
765									$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
766								) => {
767									asset_id: *asset_id == id,
768									owner: *owner == beneficiary.clone().into(),
769									amount: *amount == amount_to_mint,
770								},
771							]
772						);
773					});
774				}
775
776				/// Returns the encoded call for `create` from the assets pallet
777				pub fn create_asset_call(
778					asset_id: u32,
779					min_balance: $crate::impls::Balance,
780					admin: $crate::impls::AccountId,
781				) -> $crate::impls::DoubleEncoded<()> {
782					use $crate::impls::{Chain, Encode};
783
784					<Self as Chain>::RuntimeCall::Assets($crate::impls::pallet_assets::Call::<
785						<Self as Chain>::Runtime,
786						$crate::impls::pallet_assets::Instance1,
787					>::create {
788						id: asset_id.into(),
789						min_balance,
790						admin: admin.into(),
791					})
792					.encode()
793					.into()
794				}
795			}
796		}
797	};
798}
799
800#[macro_export]
801macro_rules! impl_foreign_assets_helpers_for_parachain {
802	($chain:ident, $asset_id_type:ty) => {
803		$crate::impls::paste::paste! {
804			impl<N: $crate::impls::Network> $chain<N> {
805				/// Create foreign assets using sudo `ForeignAssets::force_create()`
806				pub fn force_create_foreign_asset(
807					id: $asset_id_type,
808					owner: $crate::impls::AccountId,
809					is_sufficient: bool,
810					min_balance: u128,
811					prefund_accounts: Vec<($crate::impls::AccountId, u128)>,
812				) {
813					use $crate::impls::Inspect;
814					let sudo_origin = <$chain<N> as $crate::impls::Chain>::RuntimeOrigin::root();
815					<Self as $crate::impls::TestExt>::execute_with(|| {
816						$crate::impls::assert_ok!(
817							<Self as [<$chain ParaPallet>]>::ForeignAssets::force_create(
818								sudo_origin,
819								id.clone(),
820								owner.clone().into(),
821								is_sufficient,
822								min_balance,
823							)
824						);
825						assert!(<Self as [<$chain ParaPallet>]>::ForeignAssets::asset_exists(id.clone()));
826						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
827						$crate::impls::assert_expected_events!(
828							Self,
829							vec![
830								RuntimeEvent::<N>::ForeignAssets(
831									$crate::impls::pallet_assets::Event::ForceCreated {
832										asset_id,
833										..
834									}
835								) => { asset_id: *asset_id == id, },
836							]
837						);
838					});
839					for (beneficiary, amount) in prefund_accounts.into_iter() {
840						let signed_origin =
841							<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
842						Self::mint_foreign_asset(signed_origin, id.clone(), beneficiary, amount);
843					}
844				}
845
846				/// Mint assets making use of the ForeignAssets pallet-assets instance
847				pub fn mint_foreign_asset(
848					signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
849					id: $asset_id_type,
850					beneficiary: $crate::impls::AccountId,
851					amount_to_mint: u128,
852				) {
853					<Self as $crate::impls::TestExt>::execute_with(|| {
854						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::ForeignAssets::mint(
855							signed_origin,
856							id.clone().into(),
857							beneficiary.clone().into(),
858							amount_to_mint
859						));
860
861						type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
862
863						$crate::impls::assert_expected_events!(
864							Self,
865							vec![
866								RuntimeEvent::<N>::ForeignAssets(
867									$crate::impls::pallet_assets::Event::Issued { asset_id, owner, amount }
868								) => {
869									asset_id: *asset_id == id,
870									owner: *owner == beneficiary.clone().into(),
871									amount: *amount == amount_to_mint,
872								},
873							]
874						);
875					});
876				}
877
878				/// Returns the encoded call for `create` from the foreign assets pallet
879				pub fn create_foreign_asset_call(
880					asset_id: $asset_id_type,
881					min_balance: $crate::impls::Balance,
882					admin: $crate::impls::AccountId,
883				) -> $crate::impls::DoubleEncoded<()> {
884					use $crate::impls::{Chain, Encode};
885
886					<Self as Chain>::RuntimeCall::ForeignAssets($crate::impls::pallet_assets::Call::<
887						<Self as Chain>::Runtime,
888						$crate::impls::pallet_assets::Instance2,
889					>::create {
890						id: asset_id.into(),
891						min_balance,
892						admin: admin.into(),
893					})
894					.encode()
895					.into()
896				}
897			}
898		}
899	};
900}
901
902#[macro_export]
903macro_rules! impl_xcm_helpers_for_parachain {
904	( $chain:ident ) => {
905		$crate::impls::paste::paste! {
906			impl<N: $crate::impls::Network> $chain<N> {
907				/// Set XCM version for destination.
908				pub fn force_xcm_version(dest: $crate::impls::Location, version: $crate::impls::XcmVersion) {
909					<Self as $crate::impls::TestExt>::execute_with(|| {
910						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::PolkadotXcm::force_xcm_version(
911							<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
912							$crate::impls::bx!(dest),
913							version,
914						));
915					});
916				}
917
918				/// Set default/safe XCM version for runtime.
919				pub fn force_default_xcm_version(version: Option<$crate::impls::XcmVersion>) {
920					<Self as $crate::impls::TestExt>::execute_with(|| {
921						$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::PolkadotXcm::force_default_xcm_version(
922							<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
923							version,
924						));
925					});
926				}
927			}
928		}
929	}
930}
931
932#[macro_export]
933macro_rules! impl_bridge_helpers_for_chain {
934	( $chain:ident, $pallet:ident, $pallet_xcm:ident, $runtime_call_wrapper:path ) => {
935		$crate::impls::paste::paste! {
936			impl<N: $crate::impls::Network> $chain<N> {
937				/// Open bridge with `dest`.
938				pub fn open_bridge(
939					bridge_location: $crate::impls::Location,
940					bridge_destination_universal_location: $crate::impls::InteriorLocation,
941					maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)>
942				) {
943					<Self as $crate::impls::TestExt>::execute_with(|| {
944						use $crate::impls::{bx, Chain};
945						use $crate::impls::XcmBridgeHubCall;
946						use $crate::impls::Encode;
947
948						// important to use `root` and `OriginKind::Xcm`
949						let root_origin = <Self as Chain>::RuntimeOrigin::root();
950
951						// construct call
952						let call: $crate::impls::DoubleEncoded<()> = $runtime_call_wrapper(XcmBridgeHubCall::open_bridge {
953							bridge_destination_universal_location: bx!(
954								bridge_destination_universal_location.clone().into()
955							)
956						}).encode().into();
957
958						let xcm = if let Some((fee_asset, beneficiary)) = maybe_paid {
959							$crate::impls::xcm_transact_paid_execution(call, $crate::impls::OriginKind::Xcm, fee_asset, beneficiary)
960						} else {
961							$crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Xcm)
962						};
963
964						// Send XCM `Transact` with `open_bridge` call
965						$crate::impls::assert_ok!(<Self as [<$chain $pallet>]>::$pallet_xcm::send(
966							root_origin,
967							bx!(bridge_location.into()),
968							bx!(xcm),
969						));
970						Self::assert_xcm_pallet_sent();
971					});
972				}
973			}
974		}
975	}
976}