referrerpolicy=no-referrer-when-downgrade

emulated_integration_tests_common/
macros.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 paste;
17
18// Substrate
19pub use frame_support::{pallet_prelude::Weight, weights::WeightToFee};
20pub use pallet_asset_conversion;
21pub use pallet_assets;
22pub use pallet_balances;
23pub use pallet_message_queue;
24pub use pallet_whitelist;
25pub use pallet_xcm;
26
27pub use frame_support::assert_ok;
28
29// Polkadot
30pub use polkadot_runtime_parachains::dmp::Pallet as Dmp;
31pub use xcm::{
32	latest::AssetTransferFilter,
33	prelude::{
34		AliasOrigin, All, AllCounted, Asset, AssetId, Assets, BuyExecution, DepositAsset,
35		ExpectTransactStatus, Fungible, GeneralIndex, Here, InitiateTransfer, Junction, Location,
36		MaybeErrorCode, OriginKind, Outcome, PalletInstance, Parachain, Parent, PayFees,
37		RefundSurplus, Transact, Unlimited, VersionedAssetId, VersionedAssets, VersionedLocation,
38		VersionedXcm, WeightLimit, Wild, WithdrawAsset, Xcm, XcmContext, XCM_VERSION,
39	},
40};
41
42pub use xcm_executor::traits::{DropAssets, TransferType};
43
44// Cumulus
45pub use asset_test_utils;
46pub use cumulus_pallet_xcmp_queue;
47pub use parachains_common::AccountId;
48pub use xcm_emulator::{
49	assert_expected_events, Chain, Parachain as Para, RelayChain, TestArgs, TestContext, TestExt,
50};
51
52pub use frame_support::{
53	dispatch::{GetDispatchInfo, RawOrigin},
54	BoundedVec,
55};
56pub use xcm_runtime_apis::{
57	dry_run::runtime_decl_for_dry_run_api::DryRunApiV2,
58	fees::{runtime_decl_for_xcm_payment_api::XcmPaymentApiV2, Error as XcmPaymentApiError},
59};
60
61pub use frame_support::traits::{fungible::Mutate, fungibles::Inspect, Currency};
62pub use sp_runtime::{traits::Dispatchable, AccountId32};
63
64pub use crate::{ASSETS_PALLET_ID, USDT_ID};
65
66#[macro_export]
67macro_rules! test_parachain_is_trusted_teleporter {
68	( $sender_para:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr), $xcm_call:ident ) => {
69		$crate::macros::paste::paste! {
70			// init Origin variables
71			let sender = [<$sender_para Sender>]::get();
72			let mut para_sender_balance_before =
73				<$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
74			let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
75			let fee_asset_item = 0;
76			let weight_limit = $crate::macros::WeightLimit::Unlimited;
77
78			$(
79				{
80					// init Destination variables
81					let receiver = [<$receiver_para Receiver>]::get();
82					let para_receiver_balance_before =
83						<$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
84					let para_destination =
85						<$sender_para as $crate::macros::Para>::sibling_location_of(
86							<$receiver_para as $crate::macros::Para>::para_id());
87					let beneficiary: $crate::macros::Location =
88						$crate::macros::Junction::AccountId32 { network: None, id: receiver.clone().into() }.into();
89
90					// Dry-run first.
91					let call = <$sender_para as $crate::macros::Chain>::RuntimeCall::PolkadotXcm(
92						$crate::macros::pallet_xcm::Call::$xcm_call {
93						dest: Box::new(para_destination.clone().into()),
94						beneficiary: Box::new(beneficiary.clone().into()),
95						assets: Box::new($assets.clone().into()),
96						fee_asset_item: fee_asset_item,
97						weight_limit: weight_limit.clone(),
98					});
99
100					// assume up to 90% of max weight
101					let max_weight_with_margin_for_error = ($crate::macros::Weight::MAX.ref_time() / 100) * 90;
102					assert!(<_ as $crate::macros::GetDispatchInfo>::get_dispatch_info(&call)
103						.call_weight.ref_time() < max_weight_with_margin_for_error);
104
105					let mut delivery_fees_amount = 0;
106					let mut remote_message = $crate::macros::VersionedXcm::from($crate::macros::Xcm(Vec::new()));
107					<$sender_para as $crate::macros::TestExt>::execute_with(|| {
108						type Runtime = <$sender_para as $crate::macros::Chain>::Runtime;
109						type OriginCaller = <$sender_para as $crate::macros::Chain>::OriginCaller;
110
111						let origin = OriginCaller::system($crate::macros::RawOrigin::Signed(sender.clone()));
112						let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_call(origin, call.clone(),
113							$crate::macros::XCM_VERSION).unwrap();
114
115
116						// We filter the result to get only the messages we are interested in.
117						let (destination_to_query, messages_to_query) = &result
118							.forwarded_xcms
119							.iter()
120							.find(|(destination, _)| {
121								*destination == $crate::macros::VersionedLocation::from($crate::macros::Location::new(1,
122									[$crate::macros::Parachain(<$receiver_para as $crate::macros::Para>::para_id().into())]))
123							})
124							.unwrap();
125						assert_eq!(messages_to_query.len(), 1);
126						remote_message = messages_to_query[0].clone();
127						// The native asset of every system chain.
128						// We want to get the delivery fees in this asset.
129						let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(1, []));
130						let delivery_fees =
131							<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_delivery_fees(
132								destination_to_query.clone(),
133								remote_message.clone(),
134								asset_id_for_delivery_fees
135							).unwrap();
136						let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap();
137						let $crate::macros::Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else {
138							unreachable!("asset is non-fungible");
139						};
140						delivery_fees_amount = inner_delivery_fees_amount;
141					});
142
143					// Reset to send actual message.
144					<$sender_para as $crate::macros::TestExt>::reset_ext();
145					<$receiver_para as $crate::macros::TestExt>::reset_ext();
146
147					// TODO: The test fails without the line below, seems like no horizontal message passing is being done
148					//       when also using dry_run_call above (it works if there is no dry_run_call)
149					//       So this is just workaround, must be investigated
150					<$sender_para as $crate::macros::TestExt>::execute_with(|| { });
151
152					// Send XCM message from Origin Parachain
153					<$sender_para as $crate::macros::TestExt>::execute_with(|| {
154						let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
155						$crate::macros::assert_ok!(<_ as $crate::macros::Dispatchable>::dispatch(call, origin));
156
157						type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent;
158
159						$crate::macros::assert_expected_events!(
160							$sender_para,
161							vec![
162								RuntimeEvent::PolkadotXcm(
163									$crate::macros::pallet_xcm::Event::Attempted { outcome: $crate::macros::Outcome::Complete { .. } }
164								) => {},
165								RuntimeEvent::XcmpQueue(
166									$crate::macros::cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }
167								) => {},
168								RuntimeEvent::Balances(
169									$crate::macros::pallet_balances::Event::Burned { who: sender, amount }
170								) => {},
171							]
172						);
173					});
174
175					// Receive XCM message in Destination Parachain
176					<$receiver_para as $crate::macros::TestExt>::execute_with(|| {
177						type RuntimeEvent = <$receiver_para as $crate::macros::Chain>::RuntimeEvent;
178
179						$crate::macros::assert_expected_events!(
180							$receiver_para,
181							vec![
182								RuntimeEvent::Balances(
183									$crate::macros::pallet_balances::Event::Minted { who: receiver, .. }
184								) => {},
185								RuntimeEvent::MessageQueue(
186									$crate::macros::pallet_message_queue::Event::Processed { success: true, .. }
187								) => {},
188							]
189						);
190					});
191
192					// Check if balances are updated accordingly in Origin and Destination Parachains
193					let para_sender_balance_after =
194						<$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
195					let para_receiver_balance_after =
196						<$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
197
198					assert_eq!(para_sender_balance_before - $amount - delivery_fees_amount, para_sender_balance_after);
199					assert!(para_receiver_balance_after > para_receiver_balance_before);
200
201					// Update sender balance
202					para_sender_balance_before = <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
203				}
204			)+
205		}
206	};
207}
208
209#[macro_export]
210macro_rules! test_relay_is_trusted_teleporter {
211	( $sender_relay:ty, vec![$( $receiver_para:ty ),+], ($assets:expr, $amount:expr), $xcm_call:ident ) => {
212		$crate::macros::paste::paste! {
213			// init Origin variables
214			let sender = [<$sender_relay Sender>]::get();
215			let mut relay_sender_balance_before =
216				<$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free;
217			let fee_asset_item = 0;
218			let weight_limit = $crate::macros::WeightLimit::Unlimited;
219
220			$(
221				{
222					// init Destination variables
223					let receiver = [<$receiver_para Receiver>]::get();
224					let para_receiver_balance_before =
225						<$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
226					let para_destination =
227						<$sender_relay as $crate::macros::RelayChain>::child_location_of(
228							<$receiver_para as $crate::macros::Para>::para_id());
229					let beneficiary: $crate::macros::Location =
230						$crate::macros::Junction::AccountId32 { network: None, id: receiver.clone().into() }.into();
231
232					// Dry-run first.
233					let call = <$sender_relay as $crate::macros::Chain>::RuntimeCall::XcmPallet(
234						$crate::macros::pallet_xcm::Call::$xcm_call {
235						dest: Box::new(para_destination.clone().into()),
236						beneficiary: Box::new(beneficiary.clone().into()),
237						assets: Box::new($assets.clone().into()),
238						fee_asset_item: fee_asset_item,
239						weight_limit: weight_limit.clone(),
240					});
241
242					// verify sane weight for a call
243					// assume up to 90% of max weight
244					let max_weight_with_margin_for_error = ($crate::macros::Weight::MAX.ref_time() / 100) * 90;
245					assert!(<_ as $crate::macros::GetDispatchInfo>::get_dispatch_info(&call)
246						.call_weight.ref_time() < max_weight_with_margin_for_error);
247
248					let mut delivery_fees_amount = 0;
249					let mut remote_message = $crate::macros::VersionedXcm::from($crate::macros::Xcm(Vec::new()));
250					<$sender_relay as $crate::macros::TestExt>::execute_with(|| {
251						$crate::macros::Dmp::<<$sender_relay as $crate::macros::Chain>::Runtime>::make_parachain_reachable(
252							<$receiver_para as $crate::macros::Para>::para_id());
253						type Runtime = <$sender_relay as $crate::macros::Chain>::Runtime;
254						type OriginCaller = <$sender_relay as $crate::macros::Chain>::OriginCaller;
255
256						let origin = OriginCaller::system($crate::macros::RawOrigin::Signed(sender.clone()));
257						let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_call(origin, call.clone(),
258							$crate::macros::XCM_VERSION).unwrap();
259						// We filter the result to get only the messages we are interested in.
260						let (destination_to_query, messages_to_query) = &result
261							.forwarded_xcms
262							.iter()
263							.find(|(destination, _)| {
264								*destination == $crate::macros::VersionedLocation::from($crate::macros::Location::new(0,
265									[$crate::macros::Parachain(<$receiver_para as $crate::macros::Para>::para_id().into())]))
266							})
267							.unwrap();
268						assert_eq!(messages_to_query.len(), 1);
269						remote_message = messages_to_query[0].clone();
270						// The native asset of every system chain.
271						// We want to get the delivery fees in this asset.
272						let asset_id_for_delivery_fees = VersionedAssetId::from(Location::new(0, []));
273						let delivery_fees =
274							<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_delivery_fees(
275								destination_to_query.clone(),
276								remote_message.clone(),
277								asset_id_for_delivery_fees
278							).unwrap();
279						let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap();
280						let $crate::macros::Fungible(inner_delivery_fees_amount) = latest_delivery_fees.inner()[0].fun else {
281							unreachable!("asset is non-fungible");
282						};
283						delivery_fees_amount = inner_delivery_fees_amount;
284					});
285
286					// Reset to send actual message.
287					<$sender_relay as $crate::macros::TestExt>::reset_ext();
288					<$receiver_para as $crate::macros::TestExt>::reset_ext();
289
290					// Send XCM message from Relay.
291					<$sender_relay as $crate::macros::TestExt>::execute_with(|| {
292						$crate::macros::Dmp::<<$sender_relay as $crate::macros::Chain>::Runtime>::make_parachain_reachable(
293							<$receiver_para as $crate::macros::Para>::para_id());
294						let origin = <$sender_relay as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
295						$crate::macros::assert_ok!(<_ as $crate::macros::Dispatchable>::dispatch(call, origin));
296
297						type RuntimeEvent = <$sender_relay as $crate::macros::Chain>::RuntimeEvent;
298
299						$crate::macros::assert_expected_events!(
300							$sender_relay,
301							vec![
302								RuntimeEvent::XcmPallet(
303									$crate::macros::pallet_xcm::Event::Attempted { outcome: $crate::macros::Outcome::Complete { .. } }
304								) => {},
305								RuntimeEvent::Balances(
306									$crate::macros::pallet_balances::Event::Burned { who: sender, amount }
307								) => {},
308								RuntimeEvent::XcmPallet(
309									$crate::macros::pallet_xcm::Event::Sent { .. }
310								) => {},
311							]
312						);
313					});
314
315					// Receive XCM message in Destination Parachain
316					<$receiver_para as $crate::macros::TestExt>::execute_with(|| {
317						type RuntimeEvent = <$receiver_para as $crate::macros::Chain>::RuntimeEvent;
318
319						$crate::macros::assert_expected_events!(
320							$receiver_para,
321							vec![
322								RuntimeEvent::Balances(
323									$crate::macros::pallet_balances::Event::Minted { who: receiver, .. }
324								) => {},
325								RuntimeEvent::MessageQueue(
326									$crate::macros::pallet_message_queue::Event::Processed { success: true, .. }
327								) => {},
328							]
329						);
330					});
331
332					// Check if balances are updated accordingly in Origin and Parachain
333					let relay_sender_balance_after =
334						<$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free;
335					let para_receiver_balance_after =
336						<$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
337
338					assert_eq!(relay_sender_balance_before - $amount - delivery_fees_amount, relay_sender_balance_after);
339					assert!(para_receiver_balance_after > para_receiver_balance_before);
340
341					// Update sender balance
342					relay_sender_balance_before = <$sender_relay as $crate::macros::Chain>::account_data_of(sender.clone()).free;
343				}
344			)+
345		}
346	};
347}
348
349#[macro_export]
350macro_rules! test_parachain_is_trusted_teleporter_for_relay {
351	( $sender_para:ty, $receiver_relay:ty, $amount:expr, $xcm_call:ident ) => {
352		$crate::macros::paste::paste! {
353			// init Origin variables
354			let sender = [<$sender_para Sender>]::get();
355			// Mint assets to `$sender_para` to succeed with teleport.
356			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
357				$crate::macros::assert_ok!(<<$sender_para as [<$sender_para Pallet>]>::Balances
358					as $crate::macros::Mutate<_>>::mint_into(&sender, $amount + 10_000_000_000));
359
360			});
361			let mut para_sender_balance_before =
362				<$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
363			let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
364			let assets: $crate::macros::Assets = ($crate::macros::Parent, $amount).into();
365			let fee_asset_item = 0;
366			let weight_limit = $crate::macros::WeightLimit::Unlimited;
367
368			// We need to mint funds into the checking account of `$receiver_relay`
369			// for it to accept a teleport from `$sender_para`.
370			// Else we'd get a `NotWithdrawable` error since it tries to reduce the check account balance, which
371			// would be 0.
372			<$receiver_relay as $crate::macros::TestExt>::execute_with(|| {
373				let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account();
374				$crate::macros::assert_ok!(<<$receiver_relay as [<$receiver_relay Pallet>]>::Balances
375					as $crate::macros::Mutate<_>>::mint_into(&check_account, $amount));
376			});
377
378			// Init destination variables.
379			let receiver = [<$receiver_relay Receiver>]::get();
380			let relay_receiver_balance_before =
381				<$receiver_relay as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
382			let relay_destination: $crate::macros::Location = $crate::macros::Parent.into();
383			let beneficiary: $crate::macros::Location =
384				$crate::macros::Junction::AccountId32 { network: None, id: receiver.clone().into() }.into();
385
386			// Dry-run first.
387			let call = <$sender_para as $crate::macros::Chain>::RuntimeCall::PolkadotXcm($crate::macros::pallet_xcm::Call::$xcm_call {
388				dest: Box::new(relay_destination.clone().into()),
389				beneficiary: Box::new(beneficiary.clone().into()),
390				assets: Box::new(assets.clone().into()),
391				fee_asset_item: fee_asset_item,
392				weight_limit: weight_limit.clone(),
393			});
394
395			// verify sane weight for a call
396			// assume up to 90% of max weight
397			let max_weight_with_margin_for_error = ($crate::macros::Weight::MAX.ref_time() / 100) * 90;
398			assert!(<_ as $crate::macros::GetDispatchInfo>::get_dispatch_info(&call)
399				.call_weight.ref_time() < max_weight_with_margin_for_error);
400
401			// These will be filled in the closure.
402			let mut delivery_fees_amount = 0;
403			let mut remote_message = $crate::macros::VersionedXcm::from($crate::macros::Xcm(Vec::new()));
404			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
405				type Runtime = <$sender_para as $crate::macros::Chain>::Runtime;
406				type OriginCaller = <$sender_para as $crate::macros::Chain>::OriginCaller;
407
408				let origin = OriginCaller::system($crate::macros::RawOrigin::Signed(sender.clone()));
409				let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_call(origin, call.clone(),
410					$crate::macros::XCM_VERSION).unwrap();
411				// We filter the result to get only the messages we are interested in.
412				let (destination_to_query, messages_to_query) = &result
413					.forwarded_xcms
414					.iter()
415					.find(|(destination, _)| {
416						*destination == $crate::macros::VersionedLocation::from($crate::macros::Location::parent())
417					})
418					.unwrap();
419				assert_eq!(messages_to_query.len(), 1);
420				remote_message = messages_to_query[0].clone();
421				// The native asset of every system chain.
422				// We want to get the delivery fees in this asset.
423				let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent());
424				let delivery_fees =
425					<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_delivery_fees(
426						destination_to_query.clone(),
427						remote_message.clone(),
428						asset_id_for_delivery_fees
429					).unwrap();
430				let latest_delivery_fees: $crate::macros::Assets = delivery_fees.clone().try_into().unwrap();
431				delivery_fees_amount = if let Some(first_asset) = latest_delivery_fees.inner().first() {
432					let $crate::macros::Fungible(inner_delivery_fees_amount) = first_asset.fun else {
433						unreachable!("asset is non-fungible");
434					};
435					inner_delivery_fees_amount
436				} else {
437					0
438				}
439			});
440
441			// Reset to send actual message.
442			<$sender_para as $crate::macros::TestExt>::reset_ext();
443			<$receiver_relay as $crate::macros::TestExt>::reset_ext();
444			// Mint assets to `$sender_para` to succeed with teleport.
445			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
446				$crate::macros::assert_ok!(<<$sender_para as [<$sender_para Pallet>]>::Balances
447					as $crate::macros::Mutate<_>>::mint_into(&sender, $amount + 10_000_000_000));
448			});
449
450			// Since we reset everything, we need to mint funds into the checking account again.
451			<$receiver_relay as $crate::macros::TestExt>::execute_with(|| {
452				let check_account = <$receiver_relay as [<$receiver_relay Pallet>]>::XcmPallet::check_account();
453				$crate::macros::assert_ok!(<<$receiver_relay as [<$receiver_relay Pallet>]>::Balances
454					as $crate::macros::Mutate<_>>::mint_into(&check_account, $amount));
455			});
456
457			// Send XCM message from Parachain.
458			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
459				let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
460				$crate::macros::assert_ok!(<_ as $crate::macros::Dispatchable>::dispatch(call, origin));
461
462				type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent;
463
464				$crate::macros::assert_expected_events!(
465					$sender_para,
466					vec![
467						RuntimeEvent::PolkadotXcm(
468							$crate::macros::pallet_xcm::Event::Attempted { outcome: $crate::macros::Outcome::Complete { .. } }
469						) => {},
470						RuntimeEvent::Balances(
471							$crate::macros::pallet_balances::Event::Burned { who: sender, amount }
472						) => {},
473						RuntimeEvent::PolkadotXcm(
474							$crate::macros::pallet_xcm::Event::Sent { .. }
475						) => {},
476					]
477				);
478			});
479
480			// Receive XCM message in Destination Parachain
481			<$receiver_relay as $crate::macros::TestExt>::execute_with(|| {
482				type RuntimeEvent = <$receiver_relay as $crate::macros::Chain>::RuntimeEvent;
483
484				$crate::macros::assert_expected_events!(
485					$receiver_relay,
486					vec![
487						RuntimeEvent::Balances(
488							$crate::macros::pallet_balances::Event::Minted { who: receiver, .. }
489						) => {},
490						RuntimeEvent::MessageQueue(
491							$crate::macros::pallet_message_queue::Event::Processed { success: true, .. }
492						) => {},
493					]
494				);
495			});
496
497			// Check if balances are updated accordingly in Origin and Relay Chain
498			let para_sender_balance_after =
499				<$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
500			let relay_receiver_balance_after =
501				<$receiver_relay as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
502
503			assert_eq!(para_sender_balance_before - $amount - delivery_fees_amount, para_sender_balance_after);
504			assert!(relay_receiver_balance_after > relay_receiver_balance_before);
505
506			// Update sender balance
507			para_sender_balance_before = <$sender_para as $crate::macros::Chain>::account_data_of(sender.clone()).free;
508		}
509	};
510}
511
512#[macro_export]
513macro_rules! test_chain_can_claim_assets {
514	( $sender_para:ty, $runtime_call:ty, $network_id:expr, $assets:expr, $amount:expr ) => {
515		$crate::macros::paste::paste! {
516			let sender = [<$sender_para Sender>]::get();
517			let origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(sender.clone());
518			// Receiver is the same as sender
519			let beneficiary: $crate::macros::Location =
520				$crate::macros::Junction::AccountId32 { network: Some($network_id), id: sender.clone().into() }.into();
521			let versioned_assets: $crate::macros::VersionedAssets = $assets.clone().into();
522
523			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
524				// Assets are trapped for whatever reason.
525				// The possible reasons for this might differ from runtime to runtime, so here we just drop them directly.
526				<<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm as $crate::macros::DropAssets>::drop_assets(
527					&beneficiary,
528					$assets.clone().into(),
529					&$crate::macros::XcmContext { origin: None, message_id: [0u8; 32], topic: None },
530				);
531
532				type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent;
533				$crate::macros::assert_expected_events!(
534					$sender_para,
535					vec![
536						RuntimeEvent::PolkadotXcm(
537							$crate::macros::pallet_xcm::Event::AssetsTrapped { origin: beneficiary, assets: versioned_assets, .. }
538						) => {},
539					]
540				);
541
542				let balance_before = <<$sender_para as [<$sender_para Pallet>]>::Balances
543					as $crate::macros::Currency<_>>::free_balance(&sender);
544
545				// Different origin or different assets won't work.
546				let other_origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed([<$sender_para Receiver>]::get());
547				assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets(
548					other_origin,
549					Box::new(versioned_assets.clone().into()),
550					Box::new(beneficiary.clone().into()),
551				).is_err());
552				let other_versioned_assets: $crate::macros::VersionedAssets = $crate::macros::Assets::new().into();
553				assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets(
554					origin.clone(),
555					Box::new(other_versioned_assets.into()),
556					Box::new(beneficiary.clone().into()),
557				).is_err());
558
559				// Assets will be claimed to `beneficiary`, which is the same as `sender`.
560				$crate::macros::assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets(
561					origin.clone(),
562					Box::new(versioned_assets.clone().into()),
563					Box::new(beneficiary.clone().into()),
564				));
565
566				$crate::macros::assert_expected_events!(
567					$sender_para,
568					vec![
569						RuntimeEvent::PolkadotXcm(
570							$crate::macros::pallet_xcm::Event::AssetsClaimed { origin: beneficiary, assets: versioned_assets, .. }
571						) => {},
572					]
573				);
574
575				// After claiming the assets, the balance has increased.
576				let balance_after = <<$sender_para as [<$sender_para Pallet>]>::Balances
577					as $crate::macros::Currency<_>>::free_balance(&sender);
578				assert_eq!(balance_after, balance_before + $amount);
579
580				// Claiming the assets again doesn't work.
581				assert!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets(
582					origin.clone(),
583					Box::new(versioned_assets.clone().into()),
584					Box::new(beneficiary.clone().into()),
585				).is_err());
586
587				let balance = <<$sender_para as [<$sender_para Pallet>]>::Balances
588					as $crate::macros::Currency<_>>::free_balance(&sender);
589				assert_eq!(balance, balance_after);
590
591				// You can also claim assets and send them to a different account.
592				<<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm as $crate::macros::DropAssets>::drop_assets(
593					&beneficiary,
594					$assets.clone().into(),
595					&$crate::macros::XcmContext { origin: None, message_id: [0u8; 32], topic: None },
596				);
597				let receiver = [<$sender_para Receiver>]::get();
598				let other_beneficiary: $crate::macros::Location =
599					$crate::macros::Junction::AccountId32 { network: Some($network_id), id: receiver.clone().into() }.into();
600				let balance_before = <<$sender_para as [<$sender_para Pallet>]>::Balances
601					as $crate::macros::Currency<_>>::free_balance(&receiver);
602				$crate::macros::assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::claim_assets(
603					origin.clone(),
604					Box::new(versioned_assets.clone().into()),
605					Box::new(other_beneficiary.clone().into()),
606				));
607				let balance_after = <<$sender_para as [<$sender_para Pallet>]>::Balances
608					as $crate::macros::Currency<_>>::free_balance(&receiver);
609				assert_eq!(balance_after, balance_before + $amount);
610			});
611		}
612	};
613}
614
615#[macro_export]
616macro_rules! test_can_estimate_and_pay_exact_fees {
617	( $sender_para:ty, $asset_hub:ty, $receiver_para:ty, ($asset_id:expr, $amount:expr), $owner_prefix:ty ) => {
618		$crate::macros::paste::paste! {
619			// We first define the call we'll use throughout the test.
620			fn get_call(
621				estimated_local_fees: impl Into<$crate::macros::Asset>,
622				estimated_intermediate_fees: impl Into<$crate::macros::Asset>,
623				estimated_remote_fees: impl Into<$crate::macros::Asset>,
624			) -> <$sender_para as $crate::macros::Chain>::RuntimeCall {
625				type RuntimeCall = <$sender_para as $crate::macros::Chain>::RuntimeCall;
626
627				let beneficiary = [<$receiver_para Receiver>]::get();
628				let xcm_in_destination = $crate::macros::Xcm::<()>::builder_unsafe()
629					.pay_fees(estimated_remote_fees)
630					.deposit_asset($crate::macros::AllCounted(1), beneficiary)
631					.build();
632				let ah_to_receiver = <$asset_hub as $crate::macros::Para>::sibling_location_of(
633					<$receiver_para as $crate::macros::Para>::para_id());
634				let xcm_in_reserve = $crate::macros::Xcm::<()>::builder_unsafe()
635					.pay_fees(estimated_intermediate_fees)
636					.deposit_reserve_asset(
637						$crate::macros::AllCounted(1),
638						ah_to_receiver,
639						xcm_in_destination,
640					)
641					.build();
642				let sender_to_ah = <$sender_para as $crate::macros::Para>::sibling_location_of(
643					<$asset_hub as $crate::macros::Para>::para_id());
644				let local_xcm = $crate::macros::Xcm::<<$sender_para as $crate::macros::Chain>::RuntimeCall>::builder()
645					.withdraw_asset(($asset_id, $amount))
646					.pay_fees(estimated_local_fees)
647					.initiate_reserve_withdraw($crate::macros::AllCounted(1), sender_to_ah, xcm_in_reserve)
648					.build();
649
650				RuntimeCall::PolkadotXcm($crate::macros::pallet_xcm::Call::execute {
651					message: Box::new($crate::macros::VersionedXcm::from(local_xcm)),
652					max_weight: $crate::macros::Weight::from_parts(10_000_000_000, 500_000),
653				})
654			}
655
656			let destination = <$sender_para as $crate::macros::Para>::sibling_location_of(
657				<$receiver_para as $crate::macros::Para>::para_id());
658			let sender = [<$sender_para Sender>]::get();
659			let sender_as_seen_by_ah = <$asset_hub as $crate::macros::Para>::sibling_location_of(
660				<$sender_para as $crate::macros::Para>::para_id());
661			let sov_of_sender_on_ah = <$asset_hub as $crate::macros::Para>::sovereign_account_id_of(sender_as_seen_by_ah.clone());
662			let asset_owner = [<$owner_prefix AssetOwner>]::get();
663
664			// Fund parachain's sender account.
665			// TODO: consider mint_foreign_asset to be part of xcm_emulator::Chain trait
666			$sender_para::mint_foreign_asset(
667				<$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(asset_owner.clone()),
668				$asset_id.clone().into(),
669				sender.clone(),
670				$amount * 2,
671			);
672
673			// Fund the parachain origin's SA on Asset Hub with the native tokens.
674			// TODO: consider fund_accounts to be part of xcm_emulator::Chain trait
675			$asset_hub::fund_accounts(vec![(sov_of_sender_on_ah.clone(), $amount * 2)]);
676
677			let beneficiary_id = [<$receiver_para Receiver>]::get();
678
679			let test_args = $crate::macros::TestContext {
680				sender: sender.clone(),
681				receiver: beneficiary_id.clone(),
682				args: $crate::macros::TestArgs::new_para(
683					destination,
684					beneficiary_id.clone(),
685					$amount,
686					($asset_id, $amount).into(),
687					None,
688					0,
689				),
690			};
691			let mut test = ParaToParaThroughAHTest::new(test_args);
692
693			// We get these from the closure.
694			let mut local_execution_fees = 0;
695			let mut local_delivery_fees = 0;
696			let mut remote_message = $crate::macros::VersionedXcm::from($crate::macros::Xcm::<()>(Vec::new()));
697			<$sender_para as $crate::macros::TestExt>::execute_with(|| {
698				type Runtime = <$sender_para as $crate::macros::Chain>::Runtime;
699				type OriginCaller = <$sender_para as $crate::macros::Chain>::OriginCaller;
700
701				let call = get_call(
702					($crate::macros::Parent, 100_000_000_000u128),
703					($crate::macros::Parent, 100_000_000_000u128),
704					($crate::macros::Parent, 100_000_000_000u128),
705				);
706				let origin = OriginCaller::system($crate::macros::RawOrigin::Signed(sender.clone()));
707				let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_call(origin, call.clone(),
708					$crate::macros::XCM_VERSION).unwrap();
709				let local_xcm = result.local_xcm.unwrap().clone();
710				let local_xcm_weight = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_xcm_weight(local_xcm).unwrap();
711				local_execution_fees = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(
712					local_xcm_weight,
713					$crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::parent())),
714				)
715				.unwrap();
716				// We filter the result to get only the messages we are interested in.
717				let (destination_to_query, messages_to_query) = &result
718					.forwarded_xcms
719					.iter()
720					.find(|(destination, _)| {
721						*destination == $crate::macros::VersionedLocation::from(
722							$crate::macros::Location::new(1, [$crate::macros::Parachain(1000)]))
723					})
724					.unwrap();
725				assert_eq!(messages_to_query.len(), 1);
726				remote_message = messages_to_query[0].clone();
727				let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent());
728				let delivery_fees =
729					<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_delivery_fees(
730						destination_to_query.clone(),
731						remote_message.clone(),
732						asset_id_for_delivery_fees
733					).unwrap();
734				local_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees);
735			});
736
737			// These are set in the AssetHub closure.
738			let mut intermediate_execution_fees = 0;
739			let mut intermediate_delivery_fees = 0;
740			let mut intermediate_remote_message = $crate::macros::VersionedXcm::from($crate::macros::Xcm::<()>(Vec::new()));
741			<$asset_hub as $crate::macros::TestExt>::execute_with(|| {
742				type Runtime = <$asset_hub as $crate::macros::Chain>::Runtime;
743				type RuntimeCall = <$asset_hub as $crate::macros::Chain>::RuntimeCall;
744
745				// First we get the execution fees.
746				let weight = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_xcm_weight(remote_message.clone()).unwrap();
747				intermediate_execution_fees = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(
748					weight,
749					$crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::new(1, []))),
750				)
751				.unwrap();
752
753				// We have to do this to turn `VersionedXcm<()>` into `VersionedXcm<RuntimeCall>`.
754				let xcm_program =
755					$crate::macros::VersionedXcm::from($crate::macros::Xcm::<RuntimeCall>::from(
756						remote_message.clone().try_into().unwrap()));
757
758				// Now we get the delivery fees to the final destination.
759				let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_xcm(
760					sender_as_seen_by_ah.clone().into(), xcm_program).unwrap();
761				let (destination_to_query, messages_to_query) = &result
762					.forwarded_xcms
763					.iter()
764					.find(|(destination, _)| {
765						*destination == $crate::macros::VersionedLocation::from($crate::macros::Location::new(1,
766							[$crate::macros::Parachain(2001)]))
767					})
768					.unwrap();
769				// There's actually two messages here.
770				// One created when the message we sent from `$sender_para` arrived and was executed.
771				// The second one when we dry-run the xcm.
772				// We could've gotten the message from the queue without having to dry-run, but
773				// offchain applications would have to dry-run, so we do it here as well.
774				intermediate_remote_message = messages_to_query[0].clone();
775				let asset_id_for_delivery_fees = VersionedAssetId::from(Location::parent());
776				let delivery_fees = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_delivery_fees(
777					destination_to_query.clone(),
778					intermediate_remote_message.clone(),
779					asset_id_for_delivery_fees,
780				)
781				.unwrap();
782				intermediate_delivery_fees = $crate::xcm_helpers::get_amount_from_versioned_assets(delivery_fees);
783			});
784
785			// Get the final execution fees in the destination.
786			let mut final_execution_fees = 0;
787			<$receiver_para as $crate::macros::TestExt>::execute_with(|| {
788				type Runtime = <$sender_para as $crate::macros::Chain>::Runtime;
789
790				let weight = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_xcm_weight(
791					intermediate_remote_message.clone()).unwrap();
792				final_execution_fees =
793					<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(weight,
794						$crate::macros::VersionedAssetId::from($crate::macros::AssetId($crate::macros::Location::parent())))
795						.unwrap();
796			});
797
798			// Dry-running is done.
799			<$sender_para as $crate::macros::TestExt>::reset_ext();
800			<$asset_hub as $crate::macros::TestExt>::reset_ext();
801			<$receiver_para as $crate::macros::TestExt>::reset_ext();
802
803			// Fund accounts again.
804			$sender_para::mint_foreign_asset(
805				<$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(asset_owner),
806				$asset_id.clone().into(),
807				sender.clone(),
808				$amount * 2,
809			);
810			$asset_hub::fund_accounts(vec![(sov_of_sender_on_ah, $amount * 2)]);
811
812			// Actually run the extrinsic.
813			let sender_assets_before = <$sender_para as $crate::macros::TestExt>::execute_with(|| {
814				type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets;
815				<ForeignAssets as $crate::macros::Inspect<_>>::balance($asset_id.clone().into(), &sender)
816			});
817			let receiver_assets_before = <$receiver_para as $crate::macros::TestExt>::execute_with(|| {
818				type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets;
819				<ForeignAssets as $crate::macros::Inspect<_>>::balance($asset_id.clone().into(), &beneficiary_id)
820			});
821
822			test.set_assertion::<$sender_para>(sender_assertions);
823			test.set_assertion::<$asset_hub>(hop_assertions);
824			test.set_assertion::<$receiver_para>(receiver_assertions);
825			let call = get_call(
826				($crate::macros::Parent, local_execution_fees + local_delivery_fees),
827				($crate::macros::Parent, intermediate_execution_fees + intermediate_delivery_fees),
828				($crate::macros::Parent, final_execution_fees),
829			);
830			test.set_call(call);
831			test.assert();
832
833			let sender_assets_after = <$sender_para as $crate::macros::TestExt>::execute_with(|| {
834				type ForeignAssets = <$sender_para as [<$sender_para Pallet>]>::ForeignAssets;
835				<ForeignAssets as $crate::macros::Inspect<_>>::balance($asset_id.clone().into(), &sender)
836			});
837			let receiver_assets_after = <$receiver_para as $crate::macros::TestExt>::execute_with(|| {
838				type ForeignAssets = <$receiver_para as [<$receiver_para Pallet>]>::ForeignAssets;
839				<ForeignAssets as $crate::macros::Inspect<_>>::balance($asset_id.into(), &beneficiary_id)
840			});
841
842			// We know the exact fees on every hop.
843			assert_eq!(sender_assets_after, sender_assets_before - $amount);
844			assert_eq!(
845				receiver_assets_after,
846				receiver_assets_before + $amount -
847					local_execution_fees -
848					local_delivery_fees -
849					intermediate_execution_fees -
850					intermediate_delivery_fees -
851					final_execution_fees
852			);
853		}
854	};
855}
856
857#[macro_export]
858macro_rules! test_dry_run_transfer_across_pk_bridge {
859	( $sender_asset_hub:ty, $sender_bridge_hub:ty, $destination:expr ) => {
860		$crate::macros::paste::paste! {
861
862			let who = $crate::macros::AccountId32::new([1u8; 32]);
863			let transfer_amount = 10_000_000_000_000u128;
864			let initial_balance = transfer_amount * 10;
865
866			// AssetHub setup.
867			$sender_asset_hub::force_xcm_version($destination, $crate::macros::XCM_VERSION);
868
869			<$sender_asset_hub as $crate::macros::TestExt>::execute_with(|| {
870				type Runtime = <$sender_asset_hub as $crate::macros::Chain>::Runtime;
871				type RuntimeCall = <$sender_asset_hub as $crate::macros::Chain>::RuntimeCall;
872				type OriginCaller = <$sender_asset_hub as $crate::macros::Chain>::OriginCaller;
873				type Balances = <$sender_asset_hub as [<$sender_asset_hub Pallet>]>::Balances;
874
875				// Give some initial funds.
876				<Balances as $crate::macros::Mutate<_>>::set_balance(&who, initial_balance);
877
878				let beneficiary: $crate::macros::Location = $crate::macros::Junction::AccountId32 {
879						id: who.clone().into(),
880						network: None,
881					}.into();
882
883				let call = RuntimeCall::PolkadotXcm($crate::macros::pallet_xcm::Call::transfer_assets_using_type_and_then {
884					dest: Box::new($crate::macros::VersionedLocation::from($destination)),
885					assets: Box::new($crate::macros::VersionedAssets::from(vec![
886						($crate::macros::Parent, transfer_amount).into(),
887					])),
888					assets_transfer_type: Box::new($crate::macros::TransferType::LocalReserve),
889					remote_fees_id: Box::new($crate::macros::VersionedAssetId::from($crate::macros::Parent)),
890					fees_transfer_type: Box::new($crate::macros::TransferType::LocalReserve),
891					custom_xcm_on_dest: Box::new($crate::macros::VersionedXcm::<()>::from($crate::macros::Xcm::<()>::builder_unsafe().deposit_asset(AllCounted(1), beneficiary).build())),
892					weight_limit: $crate::macros::Unlimited,
893				});
894				let origin = OriginCaller::system($crate::macros::RawOrigin::Signed(who));
895				let result = <Runtime as $crate::macros::DryRunApiV2<_,_,_,_>>::dry_run_call(origin, call.clone(),
896					$crate::macros::XCM_VERSION).unwrap();
897
898				// We assert the dry run succeeds and sends only one message to the local bridge hub.
899				assert!(result.execution_result.is_ok());
900				assert_eq!(result.forwarded_xcms.len(), 1);
901				assert_eq!(result.forwarded_xcms[0].0, $crate::macros::VersionedLocation::from(
902					$crate::macros::Location::new(1, [$crate::macros::Parachain(
903						<$sender_bridge_hub as $crate::macros::Para>::para_id().into())])));
904			});
905		}
906	};
907}
908
909#[macro_export]
910macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub {
911	( $asset_hub:ty ) => {
912		$crate::macros::paste::paste! {
913
914			<$asset_hub as $crate::macros::TestExt>::execute_with(|| {
915				// Setup a pool between USDT and WND.
916				type RuntimeOrigin = <$asset_hub as $crate::macros::Chain>::RuntimeOrigin;
917				type Assets = <$asset_hub as [<$asset_hub Pallet>]>::Assets;
918				type AssetConversion = <$asset_hub as [<$asset_hub Pallet>]>::AssetConversion;
919				let wnd = $crate::macros::Location::new(1, []);
920				let usdt = $crate::macros::Location::new(0, [$crate::macros::PalletInstance($crate::macros::ASSETS_PALLET_ID),
921					$crate::macros::GeneralIndex($crate::macros::USDT_ID.into())]);
922				let sender = [<$asset_hub Sender>]::get();
923				$crate::macros::assert_ok!(AssetConversion::create_pool(
924					RuntimeOrigin::signed(sender.clone()),
925					Box::new(wnd.clone()),
926					Box::new(usdt.clone()),
927				));
928
929				type Runtime = <$asset_hub as $crate::macros::Chain>::Runtime;
930				let acceptable_payment_assets = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_acceptable_payment_assets(
931					$crate::macros::XCM_VERSION).unwrap();
932				assert_eq!(acceptable_payment_assets, vec![
933					$crate::macros::VersionedAssetId::from($crate::macros::AssetId(wnd.clone())),
934					$crate::macros::VersionedAssetId::from($crate::macros::AssetId(usdt.clone())),
935				]);
936
937				let program = $crate::macros::Xcm::<()>::builder()
938					.withdraw_asset(($crate::macros::Parent, 100u128))
939					.buy_execution(($crate::macros::Parent, 10u128), $crate::macros::Unlimited)
940					.deposit_asset($crate::macros::All, [0u8; 32])
941					.build();
942				let weight = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_xcm_weight(
943					$crate::macros::VersionedXcm::from(program)).unwrap();
944				let fee_in_wnd = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(weight,
945					$crate::macros::VersionedAssetId::from($crate::macros::AssetId(wnd.clone()))).unwrap();
946				// Assets not in a pool don't work.
947				assert!(<Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(weight,
948					$crate::macros::VersionedAssetId::from(
949						$crate::macros::AssetId($crate::macros::Location::new(0,
950							[$crate::macros::PalletInstance($crate::macros::ASSETS_PALLET_ID),
951								$crate::macros::GeneralIndex(1)]
952							)
953						)
954					)
955				).is_err());
956				let fee_in_usdt_fail = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(weight,
957					$crate::macros::VersionedAssetId::from($crate::macros::AssetId(usdt.clone())));
958				// Weight to asset fee fails because there's not enough asset in the pool.
959				// We just created it, there's none.
960				assert_eq!(fee_in_usdt_fail, Err($crate::macros::XcmPaymentApiError::AssetNotFound));
961				// We add some.
962				$crate::macros::assert_ok!(Assets::mint(
963					RuntimeOrigin::signed(sender.clone()),
964					$crate::macros::USDT_ID.into(),
965					sender.clone().into(),
966					5_000_000_000_000
967				));
968				// We make 1 WND = 4 USDT.
969				$crate::macros::assert_ok!(AssetConversion::add_liquidity(
970					RuntimeOrigin::signed(sender.clone()),
971					Box::new(wnd),
972					Box::new(usdt.clone()),
973					1_000_000_000_000,
974					4_000_000_000_000,
975					0,
976					0,
977					sender.into()
978				));
979				// Now it works.
980				let fee_in_usdt = <Runtime as $crate::macros::XcmPaymentApiV2<_>>::query_weight_to_asset_fee(weight,
981					$crate::macros::VersionedAssetId::from($crate::macros::AssetId(usdt))
982				);
983				$crate::macros::assert_ok!(fee_in_usdt);
984				assert!(fee_in_usdt.unwrap() > fee_in_wnd);
985			});
986		}
987	};
988}
989
990#[macro_export]
991macro_rules! test_cross_chain_alias {
992	( vec![$( ($sender_para:ty, $receiver_para:ty, $is_teleport:expr, $expected_success:expr) ),+], $origin:expr, $target:expr, $fees:expr ) => {
993		$crate::macros::paste::paste! {
994			$(
995				{
996					let para_destination = <$sender_para as $crate::macros::Para>::sibling_location_of(
997						<$receiver_para as $crate::macros::Para>::para_id());
998					let account: $crate::macros::AccountId = $origin.clone().into();
999					$sender_para::fund_accounts(vec![(account.clone(), $fees * 10)]);
1000					let total_fees: $crate::macros::Asset = ($crate::macros::Location::parent(), $fees).into();
1001					let fees: $crate::macros::Asset = ($crate::macros::Location::parent(), $fees / 2).into();
1002
1003					let remote_fees = if $is_teleport {
1004						Some($crate::macros::AssetTransferFilter::Teleport(fees.clone().into()))
1005					} else {
1006						let source_para_sa = <$receiver_para as $crate::macros::Para>::sovereign_account_id_of(
1007							<$receiver_para as $crate::macros::Para>::sibling_location_of(
1008								<$sender_para as $crate::macros::Para>::para_id()),
1009						);
1010						$receiver_para::fund_accounts(vec![(source_para_sa, $fees * 10)]);
1011						Some($crate::macros::AssetTransferFilter::ReserveWithdraw(fees.clone().into()))
1012					};
1013					<$sender_para as $crate::macros::TestExt>::execute_with(|| {
1014						type RuntimeEvent = <$sender_para as $crate::macros::Chain>::RuntimeEvent;
1015						let xcm_message = $crate::macros::Xcm::<()>(vec![
1016							$crate::macros::WithdrawAsset(total_fees.into()),
1017							$crate::macros::PayFees { asset: fees.clone() },
1018							$crate::macros::InitiateTransfer {
1019								destination: para_destination,
1020								remote_fees,
1021								preserve_origin: true,
1022								assets: $crate::macros::BoundedVec::new(),
1023								remote_xcm: $crate::macros::Xcm(vec![
1024									// try to alias into `account`
1025									$crate::macros::AliasOrigin($target.clone().into()),
1026									$crate::macros::RefundSurplus,
1027									$crate::macros::DepositAsset {
1028										assets: $crate::macros::Wild($crate::macros::AllCounted(1)),
1029										beneficiary: $target.clone().into(),
1030									},
1031								]),
1032							},
1033							$crate::macros::RefundSurplus,
1034							$crate::macros::DepositAsset { assets: $crate::macros::Wild($crate::macros::AllCounted(1)),
1035								beneficiary: account.clone().into() },
1036						]);
1037
1038						let signed_origin = <$sender_para as $crate::macros::Chain>::RuntimeOrigin::signed(account.into());
1039						$crate::macros::assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::execute(
1040							signed_origin,
1041							Box::new($crate::macros::VersionedXcm::from(xcm_message.into())),
1042							$crate::macros::Weight::MAX
1043						));
1044						$crate::macros::assert_expected_events!(
1045							$sender_para,
1046							vec![
1047								RuntimeEvent::PolkadotXcm($crate::macros::pallet_xcm::Event::Sent { .. }) => {},
1048							]
1049						);
1050					});
1051
1052					<$receiver_para as $crate::macros::TestExt>::execute_with(|| {
1053						type RuntimeEvent = <$receiver_para as $crate::macros::Chain>::RuntimeEvent;
1054						$crate::macros::assert_expected_events!(
1055							$receiver_para,
1056							vec![
1057								RuntimeEvent::MessageQueue($crate::macros::pallet_message_queue::Event::Processed {
1058									success, ..
1059								}) => { success: *success == $expected_success, },
1060							]
1061						);
1062					});
1063				}
1064			)+
1065		}
1066	};
1067}
1068
1069/// note: $asset needs to be prefunded outside this function
1070#[macro_export]
1071macro_rules! create_pool_with_native_on {
1072	( $chain:ident, $asset:expr, $is_foreign:expr, $asset_owner:expr ) => {
1073		$crate::create_pool_with_native_on!(
1074			$chain,
1075			$asset,
1076			$is_foreign,
1077			$asset_owner,
1078			1_000_000_000_000,
1079			2_000_000_000_000
1080		);
1081	};
1082
1083	( $chain:ident, $asset:expr, $is_foreign:expr, $asset_owner:expr, $native_amount:expr, $asset_amount:expr ) => {
1084		$crate::macros::paste::paste! {
1085			<$chain as $crate::macros::TestExt>::execute_with(|| {
1086				type RuntimeEvent = <$chain as $crate::macros::Chain>::RuntimeEvent;
1087				let owner = $asset_owner;
1088				let signed_owner = <$chain as $crate::macros::Chain>::RuntimeOrigin::signed(owner.clone());
1089				let native_asset: $crate::macros::Location = $crate::macros::Parent.into();
1090
1091				if $is_foreign {
1092					$crate::macros::assert_ok!(<$chain as [<$chain Pallet>]>::ForeignAssets::mint(
1093						signed_owner.clone(),
1094						$asset.clone().into(),
1095						owner.clone().into(),
1096						10_000_000_000_000, // For it to have more than enough.
1097					));
1098				} else {
1099					let asset_id = match $asset.interior.last() {
1100						Some($crate::macros::GeneralIndex(id)) => *id as u32,
1101						_ => unreachable!(),
1102					};
1103					$crate::macros::assert_ok!(<$chain as [<$chain Pallet>]>::Assets::mint(
1104						signed_owner.clone(),
1105						asset_id.into(),
1106						owner.clone().into(),
1107						10_000_000_000_000, // For it to have more than enough.
1108					));
1109				}
1110
1111				$crate::macros::assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::create_pool(
1112					signed_owner.clone(),
1113					Box::new(native_asset.clone()),
1114					Box::new($asset.clone()),
1115				));
1116
1117				$crate::macros::assert_expected_events!(
1118					$chain,
1119					vec![
1120						RuntimeEvent::AssetConversion($crate::macros::pallet_asset_conversion::Event::PoolCreated { .. }) => {},
1121					]
1122				);
1123
1124				$crate::macros::assert_ok!(<$chain as [<$chain Pallet>]>::AssetConversion::add_liquidity(
1125					signed_owner,
1126					Box::new(native_asset),
1127					Box::new($asset),
1128					$native_amount,
1129					$asset_amount,
1130					0,
1131					0,
1132					owner.into()
1133				));
1134
1135				$crate::macros::assert_expected_events!(
1136					$chain,
1137					vec![
1138						RuntimeEvent::AssetConversion($crate::macros::pallet_asset_conversion::Event::LiquidityAdded { .. }) => {},
1139					]
1140				);
1141			});
1142		}
1143	};
1144}
1145
1146#[macro_export]
1147macro_rules! assert_whitelisted {
1148    ($chain:ident, $expected_call_hash:expr) => {
1149		type RuntimeEvent = <$chain as $crate::macros::Chain>::RuntimeEvent;
1150		$crate::macros::assert_expected_events!(
1151			$chain,
1152			vec![
1153				RuntimeEvent::Whitelist($crate::macros::pallet_whitelist::Event::CallWhitelisted { call_hash }) => {
1154						call_hash: *call_hash == $expected_call_hash,
1155				},
1156			]
1157		);
1158    };
1159}