1use fp_evm::PrecompileHandle;
20use frame_support::{
21 dispatch::{GetDispatchInfo, PostDispatchInfo},
22 traits::ConstU32,
23};
24use pallet_evm::AddressMapping;
25use pallet_xcm_transactor::{
26 Currency, CurrencyPayment, RemoteTransactInfoWithMaxWeight, TransactWeights,
27};
28use precompile_utils::prelude::*;
29use sp_core::{MaxEncodedLen, H160, U256};
30use sp_runtime::traits::Dispatchable;
31use sp_std::{
32 boxed::Box,
33 convert::{TryFrom, TryInto},
34 marker::PhantomData,
35 vec::Vec,
36};
37use sp_weights::Weight;
38use xcm::latest::prelude::*;
39use xcm::latest::Location;
40use xcm_primitives::{
41 AccountIdToCurrencyId, UtilityAvailableCalls, UtilityEncodeCall, DEFAULT_PROOF_SIZE,
42};
43
44pub struct XcmTransactorWrapper<Runtime>(PhantomData<Runtime>);
46
47pub type TransactorOf<Runtime> = <Runtime as pallet_xcm_transactor::Config>::Transactor;
48pub type CurrencyIdOf<Runtime> = <Runtime as pallet_xcm_transactor::Config>::CurrencyId;
49
50pub const CALL_DATA_LIMIT: u32 = 2u32.pow(16);
51pub type GetDataLimit = ConstU32<CALL_DATA_LIMIT>;
52
53impl<Runtime> XcmTransactorWrapper<Runtime>
54where
55 Runtime: pallet_xcm_transactor::Config + pallet_evm::Config + frame_system::Config,
56 Runtime::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
57 Runtime::RuntimeCall: From<pallet_xcm_transactor::Call<Runtime>>,
58 TransactorOf<Runtime>: TryFrom<u8>,
59 Runtime::AccountId: Into<H160>,
60 Runtime: AccountIdToCurrencyId<Runtime::AccountId, CurrencyIdOf<Runtime>>,
61 <Runtime as pallet_evm::Config>::AddressMapping: AddressMapping<Runtime::AccountId>,
62{
63 pub(crate) fn account_index(
64 handle: &mut impl PrecompileHandle,
65 index: u16,
66 ) -> EvmResult<Address> {
67 handle.record_db_read::<Runtime>(38)?;
69
70 let account: H160 = pallet_xcm_transactor::Pallet::<Runtime>::index_to_account(index)
72 .ok_or(revert("No index assigned"))?
73 .into();
74
75 Ok(account.into())
76 }
77
78 pub(crate) fn transact_info(
79 handle: &mut impl PrecompileHandle,
80 multilocation: Location,
81 ) -> EvmResult<(u64, U256, u64)> {
82 handle.record_db_read::<Runtime>(
86 16 + Location::max_encoded_len() + RemoteTransactInfoWithMaxWeight::max_encoded_len(),
87 )?;
88 let remote_transact_info: RemoteTransactInfoWithMaxWeight =
89 pallet_xcm_transactor::Pallet::<Runtime>::transact_info(&multilocation)
90 .ok_or(revert("Transact Info not set"))?;
91
92 handle.record_db_read::<Runtime>(32 + Location::max_encoded_len())?;
95 let fee_per_second: u128 =
96 pallet_xcm_transactor::Pallet::<Runtime>::dest_asset_fee_per_second(&multilocation)
97 .ok_or(revert("Fee Per Second not set"))?;
98
99 Ok((
100 remote_transact_info.transact_extra_weight.ref_time(),
101 fee_per_second.into(),
102 remote_transact_info.max_weight.ref_time(),
103 ))
104 }
105
106 pub(crate) fn transact_info_with_signed(
107 handle: &mut impl PrecompileHandle,
108 multilocation: Location,
109 ) -> EvmResult<(u64, u64, u64)> {
110 handle.record_db_read::<Runtime>(
114 16 + Location::max_encoded_len() + RemoteTransactInfoWithMaxWeight::max_encoded_len(),
115 )?;
116 let remote_transact_info: RemoteTransactInfoWithMaxWeight =
117 pallet_xcm_transactor::Pallet::<Runtime>::transact_info(multilocation)
118 .ok_or(revert("Transact Info not set"))?;
119
120 let transact_extra_weight_signed = remote_transact_info
121 .transact_extra_weight_signed
122 .unwrap_or(Weight::zero());
123
124 Ok((
125 remote_transact_info.transact_extra_weight.ref_time(),
126 transact_extra_weight_signed.ref_time(),
127 remote_transact_info.max_weight.ref_time(),
128 ))
129 }
130
131 pub(crate) fn fee_per_second(
132 handle: &mut impl PrecompileHandle,
133 location: Location,
134 ) -> EvmResult<U256> {
135 handle.record_db_read::<Runtime>(32 + Location::max_encoded_len())?;
138 let fee_per_second: u128 =
139 pallet_xcm_transactor::Pallet::<Runtime>::dest_asset_fee_per_second(location)
140 .ok_or(revert("Fee Per Second not set"))?;
141
142 Ok(fee_per_second.into())
143 }
144
145 pub(crate) fn transact_through_derivative_multilocation(
146 handle: &mut impl PrecompileHandle,
147 transactor: u8,
148 index: u16,
149 fee_asset: Location,
150 weight: u64,
151 inner_call: BoundedBytes<GetDataLimit>,
152 ) -> EvmResult {
153 let transactor = transactor
154 .try_into()
155 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
156 let inner_call: Vec<_> = inner_call.into();
157
158 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
161 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
162 dest: transactor,
163 index,
164 fee: CurrencyPayment {
165 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
166 fee_asset,
167 ))),
168 fee_amount: None,
169 },
170 inner_call,
171 weight_info: TransactWeights {
172 transact_required_weight_at_most: Weight::from_parts(
177 weight,
178 DEFAULT_PROOF_SIZE.saturating_div(2),
179 ),
180 overall_weight: None,
181 },
182 refund: false,
183 };
184
185 RuntimeHelper::<Runtime>::try_dispatch(
186 handle,
187 frame_system::RawOrigin::Signed(origin).into(),
188 call,
189 0,
190 )?;
191
192 Ok(())
193 }
194
195 pub(crate) fn transact_through_derivative_multilocation_fee_weight(
196 handle: &mut impl PrecompileHandle,
197 transactor: u8,
198 index: u16,
199 fee_asset: Location,
200 weight: u64,
201 inner_call: BoundedBytes<GetDataLimit>,
202 fee_amount: u128,
203 overall_weight: u64,
204 ) -> EvmResult {
205 let transactor = transactor
206 .try_into()
207 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
208
209 let inner_call: Vec<_> = inner_call.into();
210
211 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
214 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
215 dest: transactor,
216 index,
217 fee: CurrencyPayment {
218 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
219 fee_asset,
220 ))),
221 fee_amount: Some(fee_amount),
222 },
223 inner_call,
224 weight_info: TransactWeights {
225 transact_required_weight_at_most: Weight::from_parts(
226 weight,
227 DEFAULT_PROOF_SIZE.saturating_div(2),
228 ),
229 overall_weight: Some(Limited(Weight::from_parts(
230 overall_weight,
231 DEFAULT_PROOF_SIZE,
232 ))),
233 },
234 refund: false,
235 };
236
237 RuntimeHelper::<Runtime>::try_dispatch(
238 handle,
239 frame_system::RawOrigin::Signed(origin).into(),
240 call,
241 0,
242 )?;
243
244 Ok(())
245 }
246
247 pub(crate) fn transact_through_derivative(
248 handle: &mut impl PrecompileHandle,
249 transactor: u8,
250 index: u16,
251 currency_id: Address,
252 weight: u64,
253 inner_call: BoundedBytes<GetDataLimit>,
254 ) -> EvmResult {
255 handle.record_cost(1000)?;
258
259 let transactor = transactor
260 .try_into()
261 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
262 let inner_call: Vec<_> = inner_call.into();
263
264 let to_account = Runtime::AddressMapping::into_account_id(currency_id.0);
265
266 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
268 Runtime::account_to_currency_id(to_account)
269 .ok_or(revert("cannot convert into currency id"))?;
270
271 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
274 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
275 dest: transactor,
276 index,
277 fee: CurrencyPayment {
278 currency: Currency::AsCurrencyId(currency_id),
279 fee_amount: None,
280 },
281 weight_info: TransactWeights {
282 transact_required_weight_at_most: Weight::from_parts(
283 weight,
284 DEFAULT_PROOF_SIZE.saturating_div(2),
285 ),
286 overall_weight: None,
287 },
288 inner_call,
289 refund: false,
290 };
291
292 RuntimeHelper::<Runtime>::try_dispatch(
293 handle,
294 frame_system::RawOrigin::Signed(origin).into(),
295 call,
296 0,
297 )?;
298
299 Ok(())
300 }
301
302 pub(crate) fn transact_through_derivative_fee_weight(
303 handle: &mut impl PrecompileHandle,
304 transactor: u8,
305 index: u16,
306 fee_asset: Address,
307 weight: u64,
308 inner_call: BoundedBytes<GetDataLimit>,
309 fee_amount: u128,
310 overall_weight: u64,
311 ) -> EvmResult {
312 handle.record_cost(1000)?;
315
316 let transactor = transactor
317 .try_into()
318 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
319 let inner_call: Vec<_> = inner_call.into();
320
321 let to_address: H160 = fee_asset.into();
322 let to_account = Runtime::AddressMapping::into_account_id(to_address);
323
324 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
326 Runtime::account_to_currency_id(to_account)
327 .ok_or(revert("cannot convert into currency id"))?;
328
329 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
332 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
333 dest: transactor,
334 index,
335 fee: CurrencyPayment {
336 currency: Currency::AsCurrencyId(currency_id),
337 fee_amount: Some(fee_amount),
338 },
339 weight_info: TransactWeights {
340 transact_required_weight_at_most: Weight::from_parts(
341 weight,
342 DEFAULT_PROOF_SIZE.saturating_div(2),
343 ),
344 overall_weight: Some(Limited(Weight::from_parts(
345 overall_weight,
346 DEFAULT_PROOF_SIZE,
347 ))),
348 },
349 inner_call,
350 refund: false,
351 };
352
353 RuntimeHelper::<Runtime>::try_dispatch(
354 handle,
355 frame_system::RawOrigin::Signed(origin).into(),
356 call,
357 0,
358 )?;
359
360 Ok(())
361 }
362
363 pub(crate) fn transact_through_signed_multilocation(
364 handle: &mut impl PrecompileHandle,
365 dest: Location,
366 fee_asset: Location,
367 weight: u64,
368 call: BoundedBytes<GetDataLimit>,
369 ) -> EvmResult {
370 let call: Vec<_> = call.into();
371
372 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
375 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
376 dest: Box::new(xcm::VersionedLocation::from(dest)),
377 fee: CurrencyPayment {
378 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
379 fee_asset,
380 ))),
381 fee_amount: None,
382 },
383 weight_info: TransactWeights {
384 transact_required_weight_at_most: Weight::from_parts(
385 weight,
386 DEFAULT_PROOF_SIZE.saturating_div(2),
387 ),
388 overall_weight: None,
389 },
390 refund: false,
391 call,
392 };
393
394 RuntimeHelper::<Runtime>::try_dispatch(
395 handle,
396 frame_system::RawOrigin::Signed(origin).into(),
397 call,
398 0,
399 )?;
400
401 Ok(())
402 }
403
404 pub(crate) fn transact_through_signed_multilocation_fee_weight(
405 handle: &mut impl PrecompileHandle,
406 dest: Location,
407 fee_asset: Location,
408 weight: u64,
409 call: BoundedBytes<GetDataLimit>,
410 fee_amount: u128,
411 overall_weight: u64,
412 ) -> EvmResult {
413 let call: Vec<_> = call.into();
414
415 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
418 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
419 dest: Box::new(xcm::VersionedLocation::from(dest)),
420 fee: CurrencyPayment {
421 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
422 fee_asset,
423 ))),
424 fee_amount: Some(fee_amount),
425 },
426 weight_info: TransactWeights {
427 transact_required_weight_at_most: Weight::from_parts(
428 weight,
429 DEFAULT_PROOF_SIZE.saturating_div(2),
430 ),
431 overall_weight: Some(Limited(Weight::from_parts(
432 overall_weight,
433 DEFAULT_PROOF_SIZE,
434 ))),
435 },
436 refund: false,
437 call,
438 };
439
440 RuntimeHelper::<Runtime>::try_dispatch(
441 handle,
442 frame_system::RawOrigin::Signed(origin).into(),
443 call,
444 0,
445 )?;
446
447 Ok(())
448 }
449
450 pub(crate) fn transact_through_signed(
451 handle: &mut impl PrecompileHandle,
452 dest: Location,
453 fee_asset: Address,
454 weight: u64,
455 call: BoundedBytes<GetDataLimit>,
456 ) -> EvmResult {
457 handle.record_cost(1000)?;
460
461 let to_address: H160 = fee_asset.into();
462 let to_account = Runtime::AddressMapping::into_account_id(to_address);
463
464 let call: Vec<_> = call.into();
465
466 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
468 Runtime::account_to_currency_id(to_account)
469 .ok_or(revert("cannot convert into currency id"))?;
470
471 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
474 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
475 dest: Box::new(xcm::VersionedLocation::from(dest)),
476 fee: CurrencyPayment {
477 currency: Currency::AsCurrencyId(currency_id),
478 fee_amount: None,
479 },
480 weight_info: TransactWeights {
481 transact_required_weight_at_most: Weight::from_parts(
482 weight,
483 DEFAULT_PROOF_SIZE.saturating_div(2),
484 ),
485 overall_weight: None,
486 },
487 refund: false,
488 call,
489 };
490
491 RuntimeHelper::<Runtime>::try_dispatch(
492 handle,
493 frame_system::RawOrigin::Signed(origin).into(),
494 call,
495 0,
496 )?;
497
498 Ok(())
499 }
500
501 pub(crate) fn transact_through_signed_fee_weight(
502 handle: &mut impl PrecompileHandle,
503 dest: Location,
504 fee_asset: Address,
505 weight: u64,
506 call: BoundedBytes<GetDataLimit>,
507 fee_amount: u128,
508 overall_weight: u64,
509 ) -> EvmResult {
510 handle.record_cost(1000)?;
513
514 let to_address: H160 = fee_asset.into();
515 let to_account = Runtime::AddressMapping::into_account_id(to_address);
516
517 let call: Vec<_> = call.into();
518
519 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
521 Runtime::account_to_currency_id(to_account)
522 .ok_or(revert("cannot convert into currency id"))?;
523
524 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
527 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
528 dest: Box::new(xcm::VersionedLocation::from(dest)),
529 fee: CurrencyPayment {
530 currency: Currency::AsCurrencyId(currency_id),
531 fee_amount: Some(fee_amount),
532 },
533 weight_info: TransactWeights {
534 transact_required_weight_at_most: Weight::from_parts(
535 weight,
536 DEFAULT_PROOF_SIZE.saturating_div(2),
537 ),
538 overall_weight: Some(Limited(Weight::from_parts(
539 overall_weight,
540 DEFAULT_PROOF_SIZE,
541 ))),
542 },
543 refund: false,
544 call,
545 };
546
547 RuntimeHelper::<Runtime>::try_dispatch(
548 handle,
549 frame_system::RawOrigin::Signed(origin).into(),
550 call,
551 0,
552 )?;
553
554 Ok(())
555 }
556
557 pub(crate) fn encode_utility_as_derivative(
558 handle: &mut impl PrecompileHandle,
559 transactor: u8,
560 index: u16,
561 inner_call: BoundedBytes<GetDataLimit>,
562 ) -> EvmResult<UnboundedBytes> {
563 handle.record_cost(1000)?;
567
568 let transactor: TransactorOf<Runtime> = transactor
569 .try_into()
570 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
571
572 let encoded = <pallet_xcm_transactor::Pallet<Runtime> as UtilityEncodeCall>::encode_call(
573 transactor,
574 UtilityAvailableCalls::AsDerivative(index, inner_call.into()),
575 )
576 .as_slice()
577 .into();
578 Ok(encoded)
579 }
580
581 pub(crate) fn transact_info_with_signed_v3(
582 handle: &mut impl PrecompileHandle,
583 multilocation: Location,
584 ) -> EvmResult<(Weight, Weight, Weight)> {
585 handle.record_db_read::<Runtime>(
589 16 + Location::max_encoded_len() + RemoteTransactInfoWithMaxWeight::max_encoded_len(),
590 )?;
591
592 let remote_transact_info: RemoteTransactInfoWithMaxWeight =
593 pallet_xcm_transactor::Pallet::<Runtime>::transact_info(multilocation)
594 .ok_or(revert("Transact Info not set"))?;
595
596 let transact_extra_weight_signed = remote_transact_info
597 .transact_extra_weight_signed
598 .unwrap_or(Weight::zero());
599
600 Ok((
601 remote_transact_info.transact_extra_weight,
602 transact_extra_weight_signed,
603 remote_transact_info.max_weight,
604 ))
605 }
606
607 pub(crate) fn transact_through_derivative_multilocation_v3(
608 handle: &mut impl PrecompileHandle,
609 transactor: u8,
610 index: u16,
611 fee_asset: Location,
612 weight: Weight,
613 inner_call: BoundedBytes<GetDataLimit>,
614 fee_amount: u128,
615 overall_weight: Weight,
616 refund: bool,
617 ) -> EvmResult {
618 let transactor = transactor
619 .try_into()
620 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
621
622 let inner_call: Vec<_> = inner_call.into();
623
624 let overall_weight_limit = match overall_weight.ref_time() {
625 u64::MAX => Unlimited,
626 _ => Limited(overall_weight),
627 };
628
629 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
632 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
633 dest: transactor,
634 index,
635 fee: CurrencyPayment {
636 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
637 fee_asset,
638 ))),
639 fee_amount: Some(fee_amount),
640 },
641 inner_call,
642 weight_info: TransactWeights {
643 transact_required_weight_at_most: weight,
644 overall_weight: Some(overall_weight_limit),
645 },
646 refund,
647 };
648
649 RuntimeHelper::<Runtime>::try_dispatch(
650 handle,
651 frame_system::RawOrigin::Signed(origin).into(),
652 call,
653 0,
654 )?;
655
656 Ok(())
657 }
658
659 pub(crate) fn transact_through_derivative_v3(
660 handle: &mut impl PrecompileHandle,
661 transactor: u8,
662 index: u16,
663 fee_asset: Address,
664 weight: Weight,
665 inner_call: BoundedBytes<GetDataLimit>,
666 fee_amount: u128,
667 overall_weight: Weight,
668 refund: bool,
669 ) -> EvmResult {
670 handle.record_cost(1000)?;
673
674 let transactor = transactor
675 .try_into()
676 .map_err(|_| RevertReason::custom("Non-existent transactor").in_field("transactor"))?;
677 let inner_call: Vec<_> = inner_call.into();
678
679 let to_address: H160 = fee_asset.into();
680 let to_account = Runtime::AddressMapping::into_account_id(to_address);
681
682 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
684 Runtime::account_to_currency_id(to_account)
685 .ok_or(revert("cannot convert into currency id"))?;
686
687 let overall_weight_limit = match overall_weight.ref_time() {
688 u64::MAX => Unlimited,
689 _ => Limited(overall_weight),
690 };
691
692 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
695 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_derivative {
696 dest: transactor,
697 index,
698 fee: CurrencyPayment {
699 currency: Currency::AsCurrencyId(currency_id),
700 fee_amount: Some(fee_amount),
701 },
702 weight_info: TransactWeights {
703 transact_required_weight_at_most: weight,
704 overall_weight: Some(overall_weight_limit),
705 },
706 inner_call,
707 refund,
708 };
709
710 RuntimeHelper::<Runtime>::try_dispatch(
711 handle,
712 frame_system::RawOrigin::Signed(origin).into(),
713 call,
714 0,
715 )?;
716
717 Ok(())
718 }
719
720 pub(crate) fn transact_through_signed_multilocation_v3(
721 handle: &mut impl PrecompileHandle,
722 dest: Location,
723 fee_asset: Location,
724 weight: Weight,
725 call: BoundedBytes<GetDataLimit>,
726 fee_amount: u128,
727 overall_weight: Weight,
728 refund: bool,
729 ) -> EvmResult {
730 let call: Vec<_> = call.into();
731
732 let overall_weight_limit = match overall_weight.ref_time() {
733 u64::MAX => Unlimited,
734 _ => Limited(overall_weight),
735 };
736
737 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
740 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
741 dest: Box::new(xcm::VersionedLocation::from(dest)),
742 fee: CurrencyPayment {
743 currency: Currency::AsMultiLocation(Box::new(xcm::VersionedLocation::from(
744 fee_asset,
745 ))),
746 fee_amount: Some(fee_amount),
747 },
748 weight_info: TransactWeights {
749 transact_required_weight_at_most: weight,
750 overall_weight: Some(overall_weight_limit),
751 },
752 refund,
753 call,
754 };
755
756 RuntimeHelper::<Runtime>::try_dispatch(
757 handle,
758 frame_system::RawOrigin::Signed(origin).into(),
759 call,
760 0,
761 )?;
762
763 Ok(())
764 }
765
766 pub(crate) fn transact_through_signed_v3(
767 handle: &mut impl PrecompileHandle,
768 dest: Location,
769 fee_asset: Address,
770 weight: Weight,
771 call: BoundedBytes<GetDataLimit>,
772 fee_amount: u128,
773 overall_weight: Weight,
774 refund: bool,
775 ) -> EvmResult {
776 handle.record_cost(1000)?;
779
780 let to_address: H160 = fee_asset.into();
781 let to_account = Runtime::AddressMapping::into_account_id(to_address);
782
783 let call: Vec<_> = call.into();
784
785 let currency_id: <Runtime as pallet_xcm_transactor::Config>::CurrencyId =
787 Runtime::account_to_currency_id(to_account)
788 .ok_or(revert("cannot convert into currency id"))?;
789
790 let overall_weight_limit = match overall_weight.ref_time() {
791 u64::MAX => Unlimited,
792 _ => Limited(overall_weight),
793 };
794
795 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
798 let call = pallet_xcm_transactor::Call::<Runtime>::transact_through_signed {
799 dest: Box::new(xcm::VersionedLocation::from(dest)),
800 fee: CurrencyPayment {
801 currency: Currency::AsCurrencyId(currency_id),
802 fee_amount: Some(fee_amount),
803 },
804 weight_info: TransactWeights {
805 transact_required_weight_at_most: weight,
806 overall_weight: Some(overall_weight_limit),
807 },
808 refund,
809 call,
810 };
811
812 RuntimeHelper::<Runtime>::try_dispatch(
813 handle,
814 frame_system::RawOrigin::Signed(origin).into(),
815 call,
816 0,
817 )?;
818
819 Ok(())
820 }
821}