1use super::xcm_helpers;
19use crate::{assert_matches_reserve_asset_deposited_instructions, get_fungible_delivery_fees};
20use codec::Encode;
21use cumulus_primitives_core::XcmpMessageSource;
22use frame_support::{
23 assert_noop, assert_ok,
24 traits::{
25 fungible::Mutate, fungibles::InspectEnumerable, Currency, Get, OnFinalize, OnInitialize,
26 OriginTrait,
27 },
28 weights::Weight,
29};
30use frame_system::pallet_prelude::BlockNumberFor;
31use parachains_common::{AccountId, Balance};
32use parachains_runtimes_test_utils::{
33 assert_metadata, assert_total, mock_open_hrmp_channel, AccountIdOf, BalanceOf,
34 CollatorSessionKeys, ExtBuilder, SlotDurations, ValidatorIdOf, XcmReceivedFrom,
35};
36use sp_runtime::{
37 traits::{Block as BlockT, MaybeEquivalence, StaticLookup, Zero},
38 DispatchError, Saturating,
39};
40use xcm::{latest::prelude::*, VersionedAssetId, VersionedAssets, VersionedXcm};
41use xcm_executor::{
42 traits::{ConvertLocation, TransferType},
43 XcmExecutor,
44};
45use xcm_runtime_apis::fees::{
46 runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, Error as XcmPaymentApiError,
47};
48
49type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
50 parachains_runtimes_test_utils::RuntimeHelper<Runtime, AllPalletsWithoutSystem>;
51
52pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;
54
55pub fn teleports_for_native_asset_works<
58 Runtime,
59 AllPalletsWithoutSystem,
60 XcmConfig,
61 CheckingAccount,
62 WeightToFee,
63 HrmpChannelOpener,
64>(
65 collator_session_keys: CollatorSessionKeys<Runtime>,
66 slot_durations: SlotDurations,
67 existential_deposit: BalanceOf<Runtime>,
68 target_account: AccountIdOf<Runtime>,
69 unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
70 runtime_para_id: u32,
71) where
72 Runtime: frame_system::Config
73 + pallet_balances::Config
74 + pallet_session::Config
75 + pallet_xcm::Config
76 + parachain_info::Config
77 + pallet_collator_selection::Config
78 + cumulus_pallet_parachain_system::Config
79 + cumulus_pallet_xcmp_queue::Config
80 + pallet_timestamp::Config,
81 AllPalletsWithoutSystem:
82 OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
83 AccountIdOf<Runtime>: Into<[u8; 32]>,
84 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
85 BalanceOf<Runtime>: From<Balance> + Into<u128>,
86 WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
87 <WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
88 <Runtime as frame_system::Config>::AccountId:
89 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
90 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
91 From<<Runtime as frame_system::Config>::AccountId>,
92 <Runtime as frame_system::Config>::AccountId: From<AccountId>,
93 XcmConfig: xcm_executor::Config,
94 CheckingAccount: Get<AccountIdOf<Runtime>>,
95 HrmpChannelOpener: frame_support::inherent::ProvideInherent<
96 Call = cumulus_pallet_parachain_system::Call<Runtime>,
97 >,
98{
99 ExtBuilder::<Runtime>::default()
100 .with_collators(collator_session_keys.collators())
101 .with_session_keys(collator_session_keys.session_keys())
102 .with_safe_xcm_version(XCM_VERSION)
103 .with_para_id(runtime_para_id.into())
104 .with_tracing()
105 .build()
106 .execute_with(|| {
107 let mut alice = [0u8; 32];
108 alice[0] = 1;
109
110 let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
111 2,
112 AccountId::from(alice).into(),
113 );
114 assert_eq!(<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), 0.into());
116 assert_eq!(
117 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
118 0.into()
119 );
120
121 let native_asset_id = Location::parent();
122 let buy_execution_fee_amount_eta =
123 WeightToFee::weight_to_fee(&Weight::from_parts(90_000_000_000, 1024));
124 let native_asset_amount_unit = existential_deposit;
125 let native_asset_amount_received =
126 native_asset_amount_unit * 10.into() + buy_execution_fee_amount_eta.into();
127
128 let xcm = Xcm(vec![
130 ReceiveTeleportedAsset(Assets::from(vec![Asset {
131 id: AssetId(native_asset_id.clone()),
132 fun: Fungible(native_asset_amount_received.into()),
133 }])),
134 ClearOrigin,
135 BuyExecution {
136 fees: Asset {
137 id: AssetId(native_asset_id.clone()),
138 fun: Fungible(buy_execution_fee_amount_eta),
139 },
140 weight_limit: Limited(Weight::from_parts(3035310000, 65536)),
141 },
142 DepositAsset {
143 assets: Wild(AllCounted(1)),
144 beneficiary: Location {
145 parents: 0,
146 interior: [AccountId32 {
147 network: None,
148 id: target_account.clone().into(),
149 }]
150 .into(),
151 },
152 },
153 ExpectTransactStatus(MaybeErrorCode::Success),
154 ]);
155
156 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
157
158 let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
159 Parent,
160 xcm,
161 &mut hash,
162 RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Parent),
163 Weight::zero(),
164 );
165 assert_ok!(outcome.ensure_complete());
166
167 assert_ne!(<pallet_balances::Pallet<Runtime>>::free_balance(&target_account), 0.into());
169 assert_eq!(
170 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
171 0.into()
172 );
173
174 {
176 let dest = Location::parent();
177 let mut dest_beneficiary = Location::parent()
178 .appended_with(AccountId32 {
179 network: None,
180 id: sp_runtime::AccountId32::new([3; 32]).into(),
181 })
182 .unwrap();
183 dest_beneficiary.reanchor(&dest, &XcmConfig::UniversalLocation::get()).unwrap();
184
185 let target_account_balance_before_teleport =
186 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account);
187 let native_asset_to_teleport_away = native_asset_amount_unit * 3.into();
188 assert!(
189 native_asset_to_teleport_away <
190 target_account_balance_before_teleport - existential_deposit
191 );
192
193 let delivery_fees =
195 xcm_helpers::teleport_assets_delivery_fees::<XcmConfig::XcmSender>(
196 (native_asset_id.clone(), native_asset_to_teleport_away.into()).into(),
197 0,
198 Unlimited,
199 dest_beneficiary.clone(),
200 dest.clone(),
201 );
202 <pallet_balances::Pallet<Runtime>>::mint_into(
203 &target_account,
204 delivery_fees.into(),
205 )
206 .unwrap();
207
208 assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
209 RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
210 dest,
211 dest_beneficiary,
212 (native_asset_id.clone(), native_asset_to_teleport_away.into()),
213 None,
214 included_head.clone(),
215 &alice,
216 &slot_durations,
217 ));
218
219 assert_eq!(
221 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
222 target_account_balance_before_teleport - native_asset_to_teleport_away
223 );
224 assert_eq!(
225 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
226 0.into()
227 );
228
229 RuntimeHelper::<Runtime>::assert_pallet_xcm_event_outcome(
231 &unwrap_pallet_xcm_event,
232 |outcome| {
233 assert_ok!(outcome.ensure_complete());
234 },
235 );
236 }
237
238 {
241 let other_para_id = 2345;
242 let dest = Location::new(1, [Parachain(other_para_id)]);
243 let mut dest_beneficiary = Location::new(1, [Parachain(other_para_id)])
244 .appended_with(AccountId32 {
245 network: None,
246 id: sp_runtime::AccountId32::new([3; 32]).into(),
247 })
248 .unwrap();
249 dest_beneficiary.reanchor(&dest, &XcmConfig::UniversalLocation::get()).unwrap();
250
251 let target_account_balance_before_teleport =
252 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account);
253
254 let native_asset_to_teleport_away = native_asset_amount_unit * 3.into();
255 assert!(
256 native_asset_to_teleport_away <
257 target_account_balance_before_teleport - existential_deposit
258 );
259
260 assert_eq!(
261 RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
262 RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
263 dest,
264 dest_beneficiary,
265 (native_asset_id, native_asset_to_teleport_away.into()),
266 Some((runtime_para_id, other_para_id)),
267 included_head,
268 &alice,
269 &slot_durations,
270 ),
271 Err(DispatchError::Module(sp_runtime::ModuleError {
272 index: 31,
273 error: [2, 0, 0, 0,],
274 message: Some("Filtered",),
275 },),)
276 );
277
278 assert_eq!(
280 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
281 target_account_balance_before_teleport
282 );
283 assert_eq!(
284 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
285 0.into()
286 );
287 }
288 })
289}
290
291#[macro_export]
292macro_rules! include_teleports_for_native_asset_works(
293 (
294 $runtime:path,
295 $all_pallets_without_system:path,
296 $xcm_config:path,
297 $checking_account:path,
298 $weight_to_fee:path,
299 $hrmp_channel_opener:path,
300 $collator_session_key:expr,
301 $slot_durations:expr,
302 $existential_deposit:expr,
303 $unwrap_pallet_xcm_event:expr,
304 $runtime_para_id:expr
305 ) => {
306 #[test]
307 fn teleports_for_native_asset_works() {
308 const BOB: [u8; 32] = [2u8; 32];
309 let target_account = parachains_common::AccountId::from(BOB);
310
311 $crate::test_cases::teleports_for_native_asset_works::<
312 $runtime,
313 $all_pallets_without_system,
314 $xcm_config,
315 $checking_account,
316 $weight_to_fee,
317 $hrmp_channel_opener
318 >(
319 $collator_session_key,
320 $slot_durations,
321 $existential_deposit,
322 target_account,
323 $unwrap_pallet_xcm_event,
324 $runtime_para_id
325 )
326 }
327 }
328);
329
330pub fn teleports_for_foreign_assets_works<
333 Runtime,
334 AllPalletsWithoutSystem,
335 XcmConfig,
336 CheckingAccount,
337 WeightToFee,
338 HrmpChannelOpener,
339 SovereignAccountOf,
340 ForeignAssetsPalletInstance,
341>(
342 collator_session_keys: CollatorSessionKeys<Runtime>,
343 slot_durations: SlotDurations,
344 target_account: AccountIdOf<Runtime>,
345 existential_deposit: BalanceOf<Runtime>,
346 asset_owner: AccountIdOf<Runtime>,
347 unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
348 unwrap_xcmp_queue_event: Box<
349 dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
350 >,
351) where
352 Runtime: frame_system::Config
353 + pallet_balances::Config
354 + pallet_session::Config
355 + pallet_xcm::Config
356 + parachain_info::Config
357 + pallet_collator_selection::Config
358 + cumulus_pallet_parachain_system::Config
359 + cumulus_pallet_xcmp_queue::Config
360 + pallet_assets::Config<ForeignAssetsPalletInstance>
361 + pallet_timestamp::Config,
362 AllPalletsWithoutSystem:
363 OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
364 AccountIdOf<Runtime>: Into<[u8; 32]>,
365 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
366 BalanceOf<Runtime>: From<Balance>,
367 XcmConfig: xcm_executor::Config,
368 CheckingAccount: Get<AccountIdOf<Runtime>>,
369 HrmpChannelOpener: frame_support::inherent::ProvideInherent<
370 Call = cumulus_pallet_parachain_system::Call<Runtime>,
371 >,
372 WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
373 <WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
374 SovereignAccountOf: ConvertLocation<AccountIdOf<Runtime>>,
375 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetId:
376 From<xcm::v5::Location> + Into<xcm::v5::Location>,
377 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetIdParameter:
378 From<xcm::v5::Location> + Into<xcm::v5::Location>,
379 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::Balance:
380 From<Balance> + Into<u128>,
381 <Runtime as frame_system::Config>::AccountId:
382 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
383 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
384 From<<Runtime as frame_system::Config>::AccountId>,
385 <Runtime as frame_system::Config>::AccountId: From<AccountId>,
386 ForeignAssetsPalletInstance: 'static,
387{
388 let foreign_para_id = 2222;
390 let foreign_asset_id_location = xcm::v5::Location {
391 parents: 1,
392 interior: [
393 xcm::v5::Junction::Parachain(foreign_para_id),
394 xcm::v5::Junction::GeneralIndex(1234567),
395 ]
396 .into(),
397 };
398
399 let foreign_creator = Location { parents: 1, interior: [Parachain(foreign_para_id)].into() };
401 let foreign_creator_as_account_id =
402 SovereignAccountOf::convert_location(&foreign_creator).expect("");
403
404 let buy_execution_fee_amount =
406 WeightToFee::weight_to_fee(&Weight::from_parts(90_000_000_000, 0));
407 let buy_execution_fee =
408 Asset { id: AssetId(Location::parent()), fun: Fungible(buy_execution_fee_amount) };
409
410 let teleported_foreign_asset_amount = 10_000_000_000_000;
411 let runtime_para_id = 1000;
412 ExtBuilder::<Runtime>::default()
413 .with_collators(collator_session_keys.collators())
414 .with_session_keys(collator_session_keys.session_keys())
415 .with_balances(vec![
416 (
417 foreign_creator_as_account_id,
418 existential_deposit + (buy_execution_fee_amount * 2).into(),
419 ),
420 (target_account.clone(), existential_deposit),
421 (CheckingAccount::get(), existential_deposit),
422 ])
423 .with_safe_xcm_version(XCM_VERSION)
424 .with_para_id(runtime_para_id.into())
425 .with_tracing()
426 .build()
427 .execute_with(|| {
428 let mut alice = [0u8; 32];
429 alice[0] = 1;
430
431 let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
432 2,
433 AccountId::from(alice).into(),
434 );
435 assert_eq!(
437 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
438 existential_deposit
439 );
440 assert_eq!(
442 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
443 existential_deposit
444 );
445 assert_eq!(
446 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
447 foreign_asset_id_location.clone().into(),
448 &target_account
449 ),
450 0.into()
451 );
452 assert_eq!(
453 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
454 foreign_asset_id_location.clone().into(),
455 &CheckingAccount::get()
456 ),
457 0.into()
458 );
459 assert_total::<
461 pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>,
462 AccountIdOf<Runtime>,
463 >(foreign_asset_id_location.clone(), 0, 0);
464
465 let asset_minimum_asset_balance = 3333333_u128;
467 assert_ok!(
468 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::force_create(
469 RuntimeHelper::<Runtime>::root_origin(),
470 foreign_asset_id_location.clone().into(),
471 asset_owner.into(),
472 false,
473 asset_minimum_asset_balance.into()
474 )
475 );
476 assert_total::<
477 pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>,
478 AccountIdOf<Runtime>,
479 >(foreign_asset_id_location.clone(), 0, 0);
480 assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance);
481
482 let xcm = Xcm(vec![
484 WithdrawAsset(buy_execution_fee.clone().into()),
486 BuyExecution {
487 fees: Asset {
488 id: AssetId(Location::parent()),
489 fun: Fungible(buy_execution_fee_amount),
490 },
491 weight_limit: Unlimited,
492 },
493 ReceiveTeleportedAsset(Assets::from(vec![Asset {
495 id: AssetId(foreign_asset_id_location.clone()),
496 fun: Fungible(teleported_foreign_asset_amount),
497 }])),
498 DepositAsset {
499 assets: Wild(AllOf {
500 id: AssetId(foreign_asset_id_location.clone()),
501 fun: WildFungibility::Fungible,
502 }),
503 beneficiary: Location {
504 parents: 0,
505 interior: [AccountId32 {
506 network: None,
507 id: target_account.clone().into(),
508 }]
509 .into(),
510 },
511 },
512 ExpectTransactStatus(MaybeErrorCode::Success),
513 ]);
514 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
515
516 let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
517 foreign_creator,
518 xcm,
519 &mut hash,
520 RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
521 Weight::zero(),
522 );
523 assert_ok!(outcome.ensure_complete());
524
525 assert_eq!(
527 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
528 existential_deposit
529 );
530 assert_eq!(
531 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
532 foreign_asset_id_location.clone().into(),
533 &target_account
534 ),
535 teleported_foreign_asset_amount.into()
536 );
537 assert_eq!(
539 <pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
540 existential_deposit
541 );
542 assert_eq!(
543 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
544 foreign_asset_id_location.clone().into(),
545 &CheckingAccount::get()
546 ),
547 0.into()
548 );
549 assert_total::<
551 pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>,
552 AccountIdOf<Runtime>,
553 >(
554 foreign_asset_id_location.clone(),
555 teleported_foreign_asset_amount,
556 teleported_foreign_asset_amount,
557 );
558
559 {
561 let dest = Location::new(1, [Parachain(foreign_para_id)]);
562 let mut dest_beneficiary = Location::new(1, [Parachain(foreign_para_id)])
563 .appended_with(AccountId32 {
564 network: None,
565 id: sp_runtime::AccountId32::new([3; 32]).into(),
566 })
567 .unwrap();
568 dest_beneficiary.reanchor(&dest, &XcmConfig::UniversalLocation::get()).unwrap();
569
570 let target_account_balance_before_teleport =
571 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
572 foreign_asset_id_location.clone().into(),
573 &target_account,
574 );
575 let asset_to_teleport_away = asset_minimum_asset_balance * 3;
576 assert!(
577 asset_to_teleport_away <
578 (target_account_balance_before_teleport -
579 asset_minimum_asset_balance.into())
580 .into()
581 );
582
583 let delivery_fees =
585 xcm_helpers::teleport_assets_delivery_fees::<XcmConfig::XcmSender>(
586 (foreign_asset_id_location.clone(), asset_to_teleport_away).into(),
587 0,
588 Unlimited,
589 dest_beneficiary.clone(),
590 dest.clone(),
591 );
592 <pallet_balances::Pallet<Runtime>>::mint_into(
593 &target_account,
594 delivery_fees.into(),
595 )
596 .unwrap();
597
598 assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
599 RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
600 dest,
601 dest_beneficiary,
602 (foreign_asset_id_location.clone(), asset_to_teleport_away),
603 Some((runtime_para_id, foreign_para_id)),
604 included_head,
605 &alice,
606 &slot_durations,
607 ));
608
609 assert_eq!(
611 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
612 foreign_asset_id_location.clone().into(),
613 &target_account
614 ),
615 (target_account_balance_before_teleport - asset_to_teleport_away.into())
616 );
617 assert_eq!(
618 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::balance(
619 foreign_asset_id_location.clone().into(),
620 &CheckingAccount::get()
621 ),
622 0.into()
623 );
624 assert_total::<
626 pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>,
627 AccountIdOf<Runtime>,
628 >(
629 foreign_asset_id_location.clone(),
630 teleported_foreign_asset_amount - asset_to_teleport_away,
631 teleported_foreign_asset_amount - asset_to_teleport_away,
632 );
633
634 RuntimeHelper::<Runtime>::assert_pallet_xcm_event_outcome(
636 &unwrap_pallet_xcm_event,
637 |outcome| {
638 assert_ok!(outcome.ensure_complete());
639 },
640 );
641 assert!(RuntimeHelper::<Runtime>::xcmp_queue_message_sent(unwrap_xcmp_queue_event)
642 .is_some());
643 }
644 })
645}
646
647#[macro_export]
648macro_rules! include_teleports_for_foreign_assets_works(
649 (
650 $runtime:path,
651 $all_pallets_without_system:path,
652 $xcm_config:path,
653 $checking_account:path,
654 $weight_to_fee:path,
655 $hrmp_channel_opener:path,
656 $sovereign_account_of:path,
657 $assets_pallet_instance:path,
658 $collator_session_key:expr,
659 $slot_durations:expr,
660 $existential_deposit:expr,
661 $unwrap_pallet_xcm_event:expr,
662 $unwrap_xcmp_queue_event:expr
663 ) => {
664 #[test]
665 fn teleports_for_foreign_assets_works() {
666 const BOB: [u8; 32] = [2u8; 32];
667 let target_account = parachains_common::AccountId::from(BOB);
668 const SOME_ASSET_OWNER: [u8; 32] = [5u8; 32];
669 let asset_owner = parachains_common::AccountId::from(SOME_ASSET_OWNER);
670
671 $crate::test_cases::teleports_for_foreign_assets_works::<
672 $runtime,
673 $all_pallets_without_system,
674 $xcm_config,
675 $checking_account,
676 $weight_to_fee,
677 $hrmp_channel_opener,
678 $sovereign_account_of,
679 $assets_pallet_instance
680 >(
681 $collator_session_key,
682 $slot_durations,
683 target_account,
684 $existential_deposit,
685 asset_owner,
686 $unwrap_pallet_xcm_event,
687 $unwrap_xcmp_queue_event
688 )
689 }
690 }
691);
692
693pub fn asset_transactor_transfer_with_local_consensus_currency_works<Runtime, XcmConfig>(
696 collator_session_keys: CollatorSessionKeys<Runtime>,
697 source_account: AccountIdOf<Runtime>,
698 target_account: AccountIdOf<Runtime>,
699 existential_deposit: BalanceOf<Runtime>,
700 additional_checks_before: Box<dyn Fn()>,
701 additional_checks_after: Box<dyn Fn()>,
702) where
703 Runtime: frame_system::Config
704 + pallet_balances::Config
705 + pallet_session::Config
706 + pallet_xcm::Config
707 + parachain_info::Config
708 + pallet_collator_selection::Config
709 + cumulus_pallet_parachain_system::Config
710 + pallet_timestamp::Config,
711 AccountIdOf<Runtime>: Into<[u8; 32]>,
712 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
713 BalanceOf<Runtime>: From<Balance>,
714 XcmConfig: xcm_executor::Config,
715 <Runtime as pallet_balances::Config>::Balance: From<Balance> + Into<u128>,
716 <Runtime as frame_system::Config>::AccountId:
717 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
718 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
719 From<<Runtime as frame_system::Config>::AccountId>,
720{
721 let unit = existential_deposit;
722
723 ExtBuilder::<Runtime>::default()
724 .with_collators(collator_session_keys.collators())
725 .with_session_keys(collator_session_keys.session_keys())
726 .with_balances(vec![(source_account.clone(), (BalanceOf::<Runtime>::from(10_u128) * unit))])
727 .with_tracing()
728 .build()
729 .execute_with(|| {
730 assert_eq!(
732 <pallet_balances::Pallet<Runtime>>::free_balance(&source_account),
733 (BalanceOf::<Runtime>::from(10_u128) * unit)
734 );
735 assert_eq!(
736 <pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
737 (BalanceOf::<Runtime>::zero() * unit)
738 );
739
740 additional_checks_before();
742
743 let _ = RuntimeHelper::<XcmConfig>::do_transfer(
745 Location {
746 parents: 0,
747 interior: [AccountId32 { network: None, id: source_account.clone().into() }]
748 .into(),
749 },
750 Location {
751 parents: 0,
752 interior: [AccountId32 { network: None, id: target_account.clone().into() }]
753 .into(),
754 },
755 (
757 Location { parents: 1, interior: Here },
758 (BalanceOf::<Runtime>::from(1_u128) * unit).into(),
759 ),
760 )
761 .expect("no error");
762
763 assert_eq!(
765 <pallet_balances::Pallet<Runtime>>::free_balance(source_account),
766 (BalanceOf::<Runtime>::from(9_u128) * unit)
767 );
768 assert_eq!(
769 <pallet_balances::Pallet<Runtime>>::free_balance(target_account),
770 (BalanceOf::<Runtime>::from(1_u128) * unit)
771 );
772
773 additional_checks_after();
774 })
775}
776
777#[macro_export]
778macro_rules! include_asset_transactor_transfer_with_local_consensus_currency_works(
779 (
780 $runtime:path,
781 $xcm_config:path,
782 $collator_session_key:expr,
783 $existential_deposit:expr,
784 $additional_checks_before:expr,
785 $additional_checks_after:expr
786 ) => {
787 #[test]
788 fn asset_transactor_transfer_with_local_consensus_currency_works() {
789 const ALICE: [u8; 32] = [1u8; 32];
790 let source_account = parachains_common::AccountId::from(ALICE);
791 const BOB: [u8; 32] = [2u8; 32];
792 let target_account = parachains_common::AccountId::from(BOB);
793
794 $crate::test_cases::asset_transactor_transfer_with_local_consensus_currency_works::<
795 $runtime,
796 $xcm_config
797 >(
798 $collator_session_key,
799 source_account,
800 target_account,
801 $existential_deposit,
802 $additional_checks_before,
803 $additional_checks_after
804 )
805 }
806 }
807);
808
809pub fn asset_transactor_transfer_with_pallet_assets_instance_works<
812 Runtime,
813 XcmConfig,
814 AssetsPalletInstance,
815 AssetId,
816 AssetIdConverter,
817>(
818 collator_session_keys: CollatorSessionKeys<Runtime>,
819 existential_deposit: BalanceOf<Runtime>,
820 asset_id: AssetId,
821 asset_owner: AccountIdOf<Runtime>,
822 alice_account: AccountIdOf<Runtime>,
823 bob_account: AccountIdOf<Runtime>,
824 charlie_account: AccountIdOf<Runtime>,
825 additional_checks_before: Box<dyn Fn()>,
826 additional_checks_after: Box<dyn Fn()>,
827) where
828 Runtime: frame_system::Config
829 + pallet_balances::Config
830 + pallet_session::Config
831 + pallet_xcm::Config
832 + parachain_info::Config
833 + pallet_collator_selection::Config
834 + cumulus_pallet_parachain_system::Config
835 + pallet_assets::Config<AssetsPalletInstance>
836 + pallet_timestamp::Config,
837 AccountIdOf<Runtime>: Into<[u8; 32]>,
838 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
839 BalanceOf<Runtime>: From<Balance>,
840 XcmConfig: xcm_executor::Config,
841 <Runtime as pallet_assets::Config<AssetsPalletInstance>>::AssetId:
842 From<AssetId> + Into<AssetId>,
843 <Runtime as pallet_assets::Config<AssetsPalletInstance>>::AssetIdParameter:
844 From<AssetId> + Into<AssetId>,
845 <Runtime as pallet_assets::Config<AssetsPalletInstance>>::Balance: From<Balance> + Into<u128>,
846 <Runtime as frame_system::Config>::AccountId:
847 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
848 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
849 From<<Runtime as frame_system::Config>::AccountId>,
850 AssetsPalletInstance: 'static,
851 AssetId: Clone,
852 AssetIdConverter: MaybeEquivalence<Location, AssetId>,
853{
854 ExtBuilder::<Runtime>::default()
855 .with_collators(collator_session_keys.collators())
856 .with_session_keys(collator_session_keys.session_keys())
857 .with_balances(vec![
858 (asset_owner.clone(), existential_deposit),
859 (alice_account.clone(), existential_deposit),
860 (bob_account.clone(), existential_deposit),
861 ])
862 .with_tracing()
863 .build()
864 .execute_with(|| {
865 let asset_minimum_asset_balance = 3333333_u128;
867 let asset_id_as_location = AssetIdConverter::convert_back(&asset_id).unwrap();
868 assert_ok!(<pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::force_create(
869 RuntimeHelper::<Runtime>::root_origin(),
870 asset_id.clone().into(),
871 asset_owner.clone().into(),
872 false,
873 asset_minimum_asset_balance.into()
874 ));
875
876 assert_ok!(<pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::mint(
878 RuntimeHelper::<Runtime>::origin_of(asset_owner.clone()),
879 asset_id.clone().into(),
880 alice_account.clone().into(),
881 (6 * asset_minimum_asset_balance).into()
882 ));
883
884 assert_eq!(
886 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
887 asset_id.clone().into(),
888 &alice_account
889 ),
890 (6 * asset_minimum_asset_balance).into()
891 );
892 assert_eq!(
893 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
894 asset_id.clone().into(),
895 &bob_account
896 ),
897 0.into()
898 );
899 assert_eq!(
900 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
901 asset_id.clone().into(),
902 &charlie_account
903 ),
904 0.into()
905 );
906 assert_eq!(
907 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
908 asset_id.clone().into(),
909 &asset_owner
910 ),
911 0.into()
912 );
913 assert_eq!(
914 <pallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
915 existential_deposit
916 );
917 assert_eq!(
918 <pallet_balances::Pallet<Runtime>>::free_balance(&bob_account),
919 existential_deposit
920 );
921 assert_eq!(
922 <pallet_balances::Pallet<Runtime>>::free_balance(&charlie_account),
923 0.into()
924 );
925 assert_eq!(
926 <pallet_balances::Pallet<Runtime>>::free_balance(&asset_owner),
927 existential_deposit
928 );
929 additional_checks_before();
930
931 assert_noop!(
934 RuntimeHelper::<XcmConfig>::do_transfer(
935 Location {
936 parents: 0,
937 interior: [AccountId32 { network: None, id: alice_account.clone().into() }]
938 .into(),
939 },
940 Location {
941 parents: 0,
942 interior: [AccountId32 {
943 network: None,
944 id: charlie_account.clone().into()
945 }]
946 .into(),
947 },
948 (asset_id_as_location.clone(), asset_minimum_asset_balance),
949 ),
950 XcmError::FailedToTransactAsset(Into::<&str>::into(
951 sp_runtime::TokenError::CannotCreate
952 ))
953 );
954
955 assert!(matches!(
957 RuntimeHelper::<XcmConfig>::do_transfer(
958 Location {
959 parents: 0,
960 interior: [AccountId32 { network: None, id: alice_account.clone().into() }]
961 .into(),
962 },
963 Location {
964 parents: 0,
965 interior: [AccountId32 { network: None, id: bob_account.clone().into() }]
966 .into(),
967 },
968 (asset_id_as_location, asset_minimum_asset_balance),
969 ),
970 Ok(_)
971 ));
972
973 assert_eq!(
975 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
976 asset_id.clone().into(),
977 &alice_account
978 ),
979 (5 * asset_minimum_asset_balance).into()
980 );
981 assert_eq!(
982 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
983 asset_id.clone().into(),
984 &bob_account
985 ),
986 asset_minimum_asset_balance.into()
987 );
988 assert_eq!(
989 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
990 asset_id.clone().into(),
991 &charlie_account
992 ),
993 0.into()
994 );
995 assert_eq!(
996 <pallet_assets::Pallet<Runtime, AssetsPalletInstance>>::balance(
997 asset_id.into(),
998 &asset_owner
999 ),
1000 0.into()
1001 );
1002 assert_eq!(
1003 <pallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
1004 existential_deposit
1005 );
1006 assert_eq!(
1007 <pallet_balances::Pallet<Runtime>>::free_balance(&bob_account),
1008 existential_deposit
1009 );
1010 assert_eq!(
1011 <pallet_balances::Pallet<Runtime>>::free_balance(&charlie_account),
1012 0.into()
1013 );
1014 assert_eq!(
1015 <pallet_balances::Pallet<Runtime>>::free_balance(&asset_owner),
1016 existential_deposit
1017 );
1018
1019 additional_checks_after();
1020 })
1021}
1022
1023#[macro_export]
1024macro_rules! include_asset_transactor_transfer_with_pallet_assets_instance_works(
1025 (
1026 $test_name:tt,
1027 $runtime:path,
1028 $xcm_config:path,
1029 $assets_pallet_instance:path,
1030 $asset_id:path,
1031 $asset_id_converter:path,
1032 $collator_session_key:expr,
1033 $existential_deposit:expr,
1034 $tested_asset_id:expr,
1035 $additional_checks_before:expr,
1036 $additional_checks_after:expr
1037 ) => {
1038 #[test]
1039 fn $test_name() {
1040 const SOME_ASSET_OWNER: [u8; 32] = [5u8; 32];
1041 let asset_owner = parachains_common::AccountId::from(SOME_ASSET_OWNER);
1042 const ALICE: [u8; 32] = [1u8; 32];
1043 let alice_account = parachains_common::AccountId::from(ALICE);
1044 const BOB: [u8; 32] = [2u8; 32];
1045 let bob_account = parachains_common::AccountId::from(BOB);
1046 const CHARLIE: [u8; 32] = [3u8; 32];
1047 let charlie_account = parachains_common::AccountId::from(CHARLIE);
1048
1049 $crate::test_cases::asset_transactor_transfer_with_pallet_assets_instance_works::<
1050 $runtime,
1051 $xcm_config,
1052 $assets_pallet_instance,
1053 $asset_id,
1054 $asset_id_converter
1055 >(
1056 $collator_session_key,
1057 $existential_deposit,
1058 $tested_asset_id,
1059 asset_owner,
1060 alice_account,
1061 bob_account,
1062 charlie_account,
1063 $additional_checks_before,
1064 $additional_checks_after
1065 )
1066 }
1067 }
1068);
1069
1070pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works<
1072 Runtime,
1073 XcmConfig,
1074 WeightToFee,
1075 SovereignAccountOf,
1076 ForeignAssetsPalletInstance,
1077 AssetId,
1078 AssetIdConverter,
1079>(
1080 collator_session_keys: CollatorSessionKeys<Runtime>,
1081 existential_deposit: BalanceOf<Runtime>,
1082 asset_deposit: BalanceOf<Runtime>,
1083 metadata_deposit_base: BalanceOf<Runtime>,
1084 metadata_deposit_per_byte: BalanceOf<Runtime>,
1085 alice_account: AccountIdOf<Runtime>,
1086 bob_account: AccountIdOf<Runtime>,
1087 runtime_call_encode: Box<
1088 dyn Fn(pallet_assets::Call<Runtime, ForeignAssetsPalletInstance>) -> Vec<u8>,
1089 >,
1090 unwrap_pallet_assets_event: Box<
1091 dyn Fn(Vec<u8>) -> Option<pallet_assets::Event<Runtime, ForeignAssetsPalletInstance>>,
1092 >,
1093 additional_checks_before: Box<dyn Fn()>,
1094 additional_checks_after: Box<dyn Fn()>,
1095) where
1096 Runtime: frame_system::Config
1097 + pallet_balances::Config
1098 + pallet_session::Config
1099 + pallet_xcm::Config
1100 + parachain_info::Config
1101 + pallet_collator_selection::Config
1102 + cumulus_pallet_parachain_system::Config
1103 + pallet_assets::Config<ForeignAssetsPalletInstance>
1104 + pallet_timestamp::Config,
1105 AccountIdOf<Runtime>: Into<[u8; 32]>,
1106 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
1107 BalanceOf<Runtime>: From<Balance>,
1108 XcmConfig: xcm_executor::Config,
1109 WeightToFee: frame_support::weights::WeightToFee<Balance = Balance>,
1110 <WeightToFee as frame_support::weights::WeightToFee>::Balance: From<u128> + Into<u128>,
1111 SovereignAccountOf: ConvertLocation<AccountIdOf<Runtime>>,
1112 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetId:
1113 From<AssetId> + Into<AssetId>,
1114 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::AssetIdParameter:
1115 From<AssetId> + Into<AssetId>,
1116 <Runtime as pallet_assets::Config<ForeignAssetsPalletInstance>>::Balance:
1117 From<Balance> + Into<u128>,
1118 <Runtime as frame_system::Config>::AccountId:
1119 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
1120 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
1121 From<<Runtime as frame_system::Config>::AccountId>,
1122 ForeignAssetsPalletInstance: 'static,
1123 AssetId: Clone,
1124 AssetIdConverter: MaybeEquivalence<Location, AssetId>,
1125{
1126 let foreign_asset_id_location = Location::new(1, [Parachain(2222), GeneralIndex(1234567)]);
1128 let asset_id = AssetIdConverter::convert(&foreign_asset_id_location).unwrap();
1129
1130 let foreign_creator = Location { parents: 1, interior: [Parachain(2222)].into() };
1132 let foreign_creator_as_account_id =
1133 SovereignAccountOf::convert_location(&foreign_creator).expect("");
1134
1135 let buy_execution_fee_amount =
1137 WeightToFee::weight_to_fee(&Weight::from_parts(90_000_000_000, 0));
1138 let buy_execution_fee =
1139 Asset { id: AssetId(Location::parent()), fun: Fungible(buy_execution_fee_amount) };
1140
1141 const ASSET_NAME: &str = "My super coin";
1142 const ASSET_SYMBOL: &str = "MY_S_COIN";
1143 let metadata_deposit_per_byte_eta = metadata_deposit_per_byte
1144 .saturating_mul(((ASSET_NAME.len() + ASSET_SYMBOL.len()) as u128).into());
1145
1146 ExtBuilder::<Runtime>::default()
1147 .with_collators(collator_session_keys.collators())
1148 .with_session_keys(collator_session_keys.session_keys())
1149 .with_balances(vec![(
1150 foreign_creator_as_account_id.clone(),
1151 existential_deposit +
1152 asset_deposit +
1153 metadata_deposit_base +
1154 metadata_deposit_per_byte_eta +
1155 buy_execution_fee_amount.into() +
1156 buy_execution_fee_amount.into(),
1157 )])
1158 .with_tracing()
1159 .build()
1160 .execute_with(|| {
1161 assert!(<pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::asset_ids()
1162 .collect::<Vec<_>>()
1163 .is_empty());
1164 assert_eq!(
1165 <pallet_balances::Pallet<Runtime>>::free_balance(&foreign_creator_as_account_id),
1166 existential_deposit +
1167 asset_deposit + metadata_deposit_base +
1168 metadata_deposit_per_byte_eta +
1169 buy_execution_fee_amount.into() +
1170 buy_execution_fee_amount.into()
1171 );
1172 additional_checks_before();
1173
1174 let foreign_asset_create = runtime_call_encode(pallet_assets::Call::<
1177 Runtime,
1178 ForeignAssetsPalletInstance,
1179 >::create {
1180 id: asset_id.clone().into(),
1181 admin: foreign_creator_as_account_id.clone().into(),
1183 min_balance: 1.into(),
1184 });
1185 let foreign_asset_set_metadata = runtime_call_encode(pallet_assets::Call::<
1187 Runtime,
1188 ForeignAssetsPalletInstance,
1189 >::set_metadata {
1190 id: asset_id.clone().into(),
1191 name: Vec::from(ASSET_NAME),
1192 symbol: Vec::from(ASSET_SYMBOL),
1193 decimals: 12,
1194 });
1195 let foreign_asset_set_team = runtime_call_encode(pallet_assets::Call::<
1197 Runtime,
1198 ForeignAssetsPalletInstance,
1199 >::set_team {
1200 id: asset_id.clone().into(),
1201 issuer: foreign_creator_as_account_id.clone().into(),
1202 admin: foreign_creator_as_account_id.clone().into(),
1203 freezer: bob_account.clone().into(),
1204 });
1205
1206 let xcm = Xcm(vec![
1209 WithdrawAsset(buy_execution_fee.clone().into()),
1210 BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
1211 Transact {
1212 origin_kind: OriginKind::Xcm,
1213 call: foreign_asset_create.into(),
1214 fallback_max_weight: None,
1215 },
1216 Transact {
1217 origin_kind: OriginKind::SovereignAccount,
1218 call: foreign_asset_set_metadata.into(),
1219 fallback_max_weight: None,
1220 },
1221 Transact {
1222 origin_kind: OriginKind::SovereignAccount,
1223 call: foreign_asset_set_team.into(),
1224 fallback_max_weight: None,
1225 },
1226 ExpectTransactStatus(MaybeErrorCode::Success),
1227 ]);
1228
1229 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
1231
1232 let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
1234 foreign_creator.clone(),
1235 xcm,
1236 &mut hash,
1237 RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
1238 Weight::zero(),
1239 );
1240 assert_ok!(outcome.ensure_complete());
1241
1242 let mut events = <frame_system::Pallet<Runtime>>::events()
1244 .into_iter()
1245 .filter_map(|e| unwrap_pallet_assets_event(e.event.encode()));
1246 assert!(events.any(|e| matches!(e, pallet_assets::Event::Created { .. })));
1247 assert!(events.any(|e| matches!(e, pallet_assets::Event::MetadataSet { .. })));
1248 assert!(events.any(|e| matches!(e, pallet_assets::Event::TeamChanged { .. })));
1249
1250 assert!(!<pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::asset_ids()
1252 .collect::<Vec<_>>()
1253 .is_empty());
1254
1255 use frame_support::traits::fungibles::roles::Inspect as InspectRoles;
1257 assert_eq!(
1258 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::owner(
1259 asset_id.clone().into()
1260 ),
1261 Some(foreign_creator_as_account_id.clone())
1262 );
1263 assert_eq!(
1264 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::admin(
1265 asset_id.clone().into()
1266 ),
1267 Some(foreign_creator_as_account_id.clone())
1268 );
1269 assert_eq!(
1270 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::issuer(
1271 asset_id.clone().into()
1272 ),
1273 Some(foreign_creator_as_account_id.clone())
1274 );
1275 assert_eq!(
1276 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::freezer(
1277 asset_id.clone().into()
1278 ),
1279 Some(bob_account.clone())
1280 );
1281 assert!(
1282 <pallet_balances::Pallet<Runtime>>::free_balance(&foreign_creator_as_account_id) >=
1283 existential_deposit + buy_execution_fee_amount.into(),
1284 "Free balance: {:?} should be ge {:?}",
1285 <pallet_balances::Pallet<Runtime>>::free_balance(&foreign_creator_as_account_id),
1286 existential_deposit + buy_execution_fee_amount.into()
1287 );
1288 assert_metadata::<
1289 pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>,
1290 AccountIdOf<Runtime>,
1291 >(asset_id.clone(), ASSET_NAME, ASSET_SYMBOL, 12);
1292
1293 assert_noop!(
1295 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::freeze(
1296 RuntimeHelper::<Runtime>::origin_of(bob_account),
1297 asset_id.clone().into(),
1298 alice_account.clone().into()
1299 ),
1300 pallet_assets::Error::<Runtime, ForeignAssetsPalletInstance>::NoAccount
1301 );
1302 assert_noop!(
1303 <pallet_assets::Pallet<Runtime, ForeignAssetsPalletInstance>>::freeze(
1304 RuntimeHelper::<Runtime>::origin_of(foreign_creator_as_account_id.clone()),
1305 asset_id.into(),
1306 alice_account.into()
1307 ),
1308 pallet_assets::Error::<Runtime, ForeignAssetsPalletInstance>::NoPermission
1309 );
1310
1311 let foreign_asset_id_location =
1314 Location { parents: 1, interior: [Parachain(3333), GeneralIndex(1234567)].into() };
1315 let asset_id = AssetIdConverter::convert(&foreign_asset_id_location).unwrap();
1316
1317 let foreign_asset_create = runtime_call_encode(pallet_assets::Call::<
1319 Runtime,
1320 ForeignAssetsPalletInstance,
1321 >::create {
1322 id: asset_id.into(),
1323 admin: foreign_creator_as_account_id.clone().into(),
1325 min_balance: 1.into(),
1326 });
1327 let xcm = Xcm(vec![
1328 WithdrawAsset(buy_execution_fee.clone().into()),
1329 BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited },
1330 Transact {
1331 origin_kind: OriginKind::Xcm,
1332 call: foreign_asset_create.into(),
1333 fallback_max_weight: None,
1334 },
1335 ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())),
1336 ]);
1337
1338 let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
1340
1341 let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
1343 foreign_creator,
1344 xcm,
1345 &mut hash,
1346 RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
1347 Weight::zero(),
1348 );
1349 assert_ok!(outcome.ensure_complete());
1350
1351 additional_checks_after();
1352 })
1353}
1354
1355#[macro_export]
1356macro_rules! include_create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works(
1357 (
1358 $runtime:path,
1359 $xcm_config:path,
1360 $weight_to_fee:path,
1361 $sovereign_account_of:path,
1362 $assets_pallet_instance:path,
1363 $asset_id:path,
1364 $asset_id_converter:path,
1365 $collator_session_key:expr,
1366 $existential_deposit:expr,
1367 $asset_deposit:expr,
1368 $metadata_deposit_base:expr,
1369 $metadata_deposit_per_byte:expr,
1370 $runtime_call_encode:expr,
1371 $unwrap_pallet_assets_event:expr,
1372 $additional_checks_before:expr,
1373 $additional_checks_after:expr
1374 ) => {
1375 #[test]
1376 fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works() {
1377 const ALICE: [u8; 32] = [1u8; 32];
1378 let alice_account = parachains_common::AccountId::from(ALICE);
1379 const BOB: [u8; 32] = [2u8; 32];
1380 let bob_account = parachains_common::AccountId::from(BOB);
1381
1382 $crate::test_cases::create_and_manage_foreign_assets_for_local_consensus_parachain_assets_works::<
1383 $runtime,
1384 $xcm_config,
1385 $weight_to_fee,
1386 $sovereign_account_of,
1387 $assets_pallet_instance,
1388 $asset_id,
1389 $asset_id_converter
1390 >(
1391 $collator_session_key,
1392 $existential_deposit,
1393 $asset_deposit,
1394 $metadata_deposit_base,
1395 $metadata_deposit_per_byte,
1396 alice_account,
1397 bob_account,
1398 $runtime_call_encode,
1399 $unwrap_pallet_assets_event,
1400 $additional_checks_before,
1401 $additional_checks_after
1402 )
1403 }
1404 }
1405);
1406
1407pub fn reserve_transfer_native_asset_to_non_teleport_para_works<
1410 Runtime,
1411 AllPalletsWithoutSystem,
1412 XcmConfig,
1413 HrmpChannelOpener,
1414 HrmpChannelSource,
1415 LocationToAccountId,
1416>(
1417 collator_session_keys: CollatorSessionKeys<Runtime>,
1418 slot_durations: SlotDurations,
1419 existential_deposit: BalanceOf<Runtime>,
1420 alice_account: AccountIdOf<Runtime>,
1421 unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
1422 unwrap_xcmp_queue_event: Box<
1423 dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
1424 >,
1425 weight_limit: WeightLimit,
1426) where
1427 Runtime: frame_system::Config
1428 + pallet_balances::Config
1429 + pallet_session::Config
1430 + pallet_xcm::Config
1431 + parachain_info::Config
1432 + pallet_collator_selection::Config
1433 + cumulus_pallet_parachain_system::Config
1434 + cumulus_pallet_xcmp_queue::Config
1435 + pallet_timestamp::Config,
1436 AllPalletsWithoutSystem:
1437 OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
1438 AccountIdOf<Runtime>: Into<[u8; 32]>,
1439 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
1440 BalanceOf<Runtime>: From<Balance>,
1441 <Runtime as pallet_balances::Config>::Balance: From<Balance> + Into<u128>,
1442 XcmConfig: xcm_executor::Config,
1443 LocationToAccountId: ConvertLocation<AccountIdOf<Runtime>>,
1444 <Runtime as frame_system::Config>::AccountId:
1445 Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
1446 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
1447 From<<Runtime as frame_system::Config>::AccountId>,
1448 <Runtime as frame_system::Config>::AccountId: From<AccountId>,
1449 HrmpChannelOpener: frame_support::inherent::ProvideInherent<
1450 Call = cumulus_pallet_parachain_system::Call<Runtime>,
1451 >,
1452 HrmpChannelSource: XcmpMessageSource,
1453{
1454 let runtime_para_id = 1000;
1455 ExtBuilder::<Runtime>::default()
1456 .with_collators(collator_session_keys.collators())
1457 .with_session_keys(collator_session_keys.session_keys())
1458 .with_tracing()
1459 .with_safe_xcm_version(3)
1460 .with_para_id(runtime_para_id.into())
1461 .build()
1462 .execute_with(|| {
1463 let mut alice = [0u8; 32];
1464 alice[0] = 1;
1465 let included_head = RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block(
1466 2,
1467 AccountId::from(alice).into(),
1468 );
1469
1470 let other_para_id = 2345;
1473 let native_asset = Location::parent();
1474 let dest = Location::new(1, [Parachain(other_para_id)]);
1475 let mut dest_beneficiary = Location::new(1, [Parachain(other_para_id)])
1476 .appended_with(AccountId32 {
1477 network: None,
1478 id: sp_runtime::AccountId32::new([3; 32]).into(),
1479 })
1480 .unwrap();
1481 dest_beneficiary.reanchor(&dest, &XcmConfig::UniversalLocation::get()).unwrap();
1482
1483 let reserve_account = LocationToAccountId::convert_location(&dest)
1484 .expect("Sovereign account for reserves");
1485 let balance_to_transfer = 1_000_000_000_000_u128;
1486
1487 mock_open_hrmp_channel::<Runtime, HrmpChannelOpener>(
1489 runtime_para_id.into(),
1490 other_para_id.into(),
1491 included_head,
1492 &alice,
1493 &slot_durations,
1494 );
1495
1496 let delivery_fees_buffer = 40_000_000_000u128;
1500 let alice_account_init_balance = existential_deposit.saturating_mul(2.into()) +
1502 balance_to_transfer.into() +
1503 delivery_fees_buffer.into();
1504 let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating(
1505 &alice_account,
1506 alice_account_init_balance,
1507 );
1508 let _ = <pallet_balances::Pallet<Runtime>>::deposit_creating(
1510 &reserve_account,
1511 existential_deposit,
1512 );
1513
1514 assert!(
1517 (<pallet_balances::Pallet<Runtime>>::free_balance(&alice_account) -
1518 balance_to_transfer.into()) >=
1519 existential_deposit
1520 );
1521 assert_eq!(
1523 <pallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
1524 existential_deposit
1525 );
1526
1527 let asset_to_transfer =
1529 Asset { fun: Fungible(balance_to_transfer.into()), id: AssetId(native_asset) };
1530
1531 assert_ok!(<pallet_xcm::Pallet<Runtime>>::transfer_assets_using_type_and_then(
1533 RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::origin_of(alice_account.clone()),
1534 Box::new(dest.clone().into_versioned()),
1535 Box::new(VersionedAssets::from(Assets::from(asset_to_transfer))),
1536 Box::new(TransferType::LocalReserve),
1537 Box::new(VersionedAssetId::from(AssetId(Location::parent()))),
1538 Box::new(TransferType::LocalReserve),
1539 Box::new(VersionedXcm::from(
1540 Xcm::<()>::builder_unsafe()
1541 .deposit_asset(AllCounted(1), dest_beneficiary.clone())
1542 .build()
1543 )),
1544 weight_limit,
1545 ));
1546
1547 RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::assert_pallet_xcm_event_outcome(
1550 &unwrap_pallet_xcm_event,
1551 |outcome| {
1552 assert_ok!(outcome.ensure_complete());
1553 },
1554 );
1555
1556 let xcm_sent_message_hash = <frame_system::Pallet<Runtime>>::events()
1558 .into_iter()
1559 .filter_map(|e| unwrap_xcmp_queue_event(e.event.encode()))
1560 .find_map(|e| match e {
1561 cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { message_hash } =>
1562 Some(message_hash),
1563 _ => None,
1564 });
1565
1566 let xcm_sent = RuntimeHelper::<HrmpChannelSource, AllPalletsWithoutSystem>::take_xcm(
1568 other_para_id.into(),
1569 )
1570 .unwrap();
1571
1572 let delivery_fees = get_fungible_delivery_fees::<
1573 <XcmConfig as xcm_executor::Config>::XcmSender,
1574 >(dest.clone(), Xcm::try_from(xcm_sent.clone()).unwrap());
1575
1576 assert_eq!(
1577 xcm_sent_message_hash,
1578 Some(xcm_sent.using_encoded(sp_io::hashing::blake2_256))
1579 );
1580 let mut xcm_sent: Xcm<()> = xcm_sent.try_into().expect("versioned xcm");
1581
1582 println!("reserve_transfer_native_asset_works sent xcm: {:?}", xcm_sent);
1584 let reserve_assets_deposited = Assets::from(vec![Asset {
1585 id: AssetId(Location { parents: 1, interior: Here }),
1586 fun: Fungible(1000000000000),
1587 }]);
1588
1589 assert_matches_reserve_asset_deposited_instructions(
1590 &mut xcm_sent,
1591 &reserve_assets_deposited,
1592 &dest_beneficiary,
1593 );
1594
1595 assert_eq!(
1597 <pallet_balances::Pallet<Runtime>>::free_balance(&alice_account),
1598 alice_account_init_balance - balance_to_transfer.into() - delivery_fees.into()
1599 );
1600
1601 assert_eq!(
1604 <pallet_balances::Pallet<Runtime>>::free_balance(&reserve_account),
1605 existential_deposit + balance_to_transfer.into()
1606 );
1607 })
1608}
1609
1610pub fn xcm_payment_api_with_pools_works<Runtime, RuntimeCall, RuntimeOrigin, Block>()
1611where
1612 Runtime: XcmPaymentApiV1<Block>
1613 + frame_system::Config<RuntimeOrigin = RuntimeOrigin, AccountId = AccountId>
1614 + pallet_balances::Config<Balance = u128>
1615 + pallet_session::Config
1616 + pallet_xcm::Config
1617 + parachain_info::Config
1618 + pallet_collator_selection::Config
1619 + cumulus_pallet_parachain_system::Config
1620 + cumulus_pallet_xcmp_queue::Config
1621 + pallet_timestamp::Config
1622 + pallet_assets::Config<
1623 pallet_assets::Instance1,
1624 AssetId = u32,
1625 Balance = <Runtime as pallet_balances::Config>::Balance,
1626 > + pallet_asset_conversion::Config<
1627 AssetKind = xcm::v5::Location,
1628 Balance = <Runtime as pallet_balances::Config>::Balance,
1629 >,
1630 ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
1631 RuntimeOrigin: OriginTrait<AccountId = <Runtime as frame_system::Config>::AccountId>,
1632 <<Runtime as frame_system::Config>::Lookup as StaticLookup>::Source:
1633 From<<Runtime as frame_system::Config>::AccountId>,
1634 Block: BlockT,
1635{
1636 use xcm::prelude::*;
1637
1638 ExtBuilder::<Runtime>::default().build().execute_with(|| {
1639 let test_account = AccountId::from([0u8; 32]);
1640 let transfer_amount = 100u128;
1641 let xcm_to_weigh = Xcm::<RuntimeCall>::builder_unsafe()
1642 .withdraw_asset((Here, transfer_amount))
1643 .buy_execution((Here, transfer_amount), Unlimited)
1644 .deposit_asset(AllCounted(1), [1u8; 32])
1645 .build();
1646 let versioned_xcm_to_weigh = VersionedXcm::from(xcm_to_weigh.clone().into());
1647
1648 let xcm_weight = Runtime::query_xcm_weight(versioned_xcm_to_weigh);
1649 assert!(xcm_weight.is_ok());
1650 let native_token: Location = Parent.into();
1651 let native_token_versioned = VersionedAssetId::from(AssetId(native_token.clone()));
1652 let execution_fees =
1653 Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), native_token_versioned);
1654 assert!(execution_fees.is_ok());
1655
1656 assert_ok!(
1658 pallet_balances::Pallet::<Runtime>::mint_into(&test_account, 3_000_000_000_000,)
1659 );
1660
1661 let asset_id = 1984u32; let asset_not_in_pool: Location =
1664 (PalletInstance(50), GeneralIndex(asset_id.into())).into();
1665 assert_ok!(pallet_assets::Pallet::<Runtime, pallet_assets::Instance1>::create(
1666 RuntimeOrigin::signed(test_account.clone()),
1667 asset_id.into(),
1668 test_account.clone().into(),
1669 1000
1670 ));
1671 let execution_fees = Runtime::query_weight_to_asset_fee(
1672 xcm_weight.unwrap(),
1673 asset_not_in_pool.clone().into(),
1674 );
1675 assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound));
1676
1677 assert_ok!(pallet_asset_conversion::Pallet::<Runtime>::create_pool(
1679 RuntimeOrigin::signed(test_account.clone()),
1680 native_token.clone().try_into().unwrap(),
1681 asset_not_in_pool.clone().try_into().unwrap()
1682 ));
1683 let execution_fees = Runtime::query_weight_to_asset_fee(
1684 xcm_weight.unwrap(),
1685 asset_not_in_pool.clone().into(),
1686 );
1687 assert_eq!(execution_fees, Err(XcmPaymentApiError::AssetNotFound));
1689
1690 assert_ok!(pallet_assets::Pallet::<Runtime, pallet_assets::Instance1>::mint(
1692 RuntimeOrigin::signed(test_account.clone()),
1693 asset_id.into(),
1694 test_account.clone().into(),
1695 3_000_000_000_000,
1696 ));
1697 assert_ok!(pallet_asset_conversion::Pallet::<Runtime>::add_liquidity(
1699 RuntimeOrigin::signed(test_account.clone()),
1700 native_token.try_into().unwrap(),
1701 asset_not_in_pool.clone().try_into().unwrap(),
1702 1_000_000_000_000,
1703 2_000_000_000_000,
1704 0,
1705 0,
1706 test_account
1707 ));
1708 let execution_fees =
1709 Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), asset_not_in_pool.into());
1710 assert_ok!(execution_fees);
1712 });
1713}