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::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 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 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 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 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 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 [<$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 pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::XcmError>) {
487 $crate::impls::assert_expected_events!(
488 Self,
489 vec![
490 [<$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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let root_origin = <Self as Chain>::RuntimeOrigin::root();
950
951 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 $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}