1pub 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
24pub 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
35pub 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
47pub 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
61use 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 let active_outbound_lanes = OutboundLanes::<S, SI>::iter_keys();
103
104 let mut messages: Vec<BridgeMessage> = Default::default();
105
106 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 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 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 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 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 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 [<$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 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 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 [<$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 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 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 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 $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 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 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 $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 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 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 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 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 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 [<$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 pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::XcmError>) {
489 $crate::impls::assert_expected_events!(
490 Self,
491 vec![
492 [<$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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let root_origin = <Self as Chain>::RuntimeOrigin::root();
952
953 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 $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}