@@ -226,6 +226,13 @@ impl<C> WeighedMessage<C> {
226
226
}
227
227
}
228
228
229
+ #[ derive( Debug , Clone , Copy ) ]
230
+ enum FeesSource {
231
+ JitWithdraw ,
232
+ HoldingRegister ,
233
+ FeesRegister ,
234
+ }
235
+
229
236
impl < Config : config:: Config > ExecuteXcm < Config :: RuntimeCall > for XcmExecutor < Config > {
230
237
type Prepared = WeighedMessage < Config :: RuntimeCall > ;
231
238
fn prepare (
@@ -567,48 +574,22 @@ impl<Config: config::Config> XcmExecutor<Config> {
567
574
let asset_to_pay_for_fees =
568
575
self . calculate_asset_for_delivery_fees ( asset_needed_for_fees. clone ( ) ) ;
569
576
tracing:: trace!( target: "xcm::fees" , ?asset_to_pay_for_fees) ;
570
- // We withdraw or take from holding the asset the user wants to use for fee payment.
571
- let withdrawn_fee_asset: AssetsInHolding = if self . fees_mode . jit_withdraw {
572
- let origin = self . origin_ref ( ) . ok_or ( XcmError :: BadOrigin ) ?;
573
- Config :: AssetTransactor :: withdraw_asset (
574
- & asset_to_pay_for_fees,
575
- origin,
576
- Some ( & self . context ) ,
577
- ) ?;
578
- tracing:: trace!( target: "xcm::fees" , ?asset_needed_for_fees) ;
579
- asset_to_pay_for_fees. clone ( ) . into ( )
577
+
578
+ let fees_source = if self . fees_mode . jit_withdraw {
579
+ // We withdraw or take from holding the asset the user wants to use for fee payment.
580
+ FeesSource :: JitWithdraw
581
+ } else if self . fees . is_empty ( ) {
582
+ // Means `BuyExecution` was used, we'll find the fees in the `holding` register.
583
+ FeesSource :: HoldingRegister
580
584
} else {
581
- // This condition exists to support `BuyExecution` while the ecosystem
582
- // transitions to `PayFees`.
583
- let assets_to_pay_delivery_fees: AssetsInHolding = if self . fees . is_empty ( ) {
584
- // Means `BuyExecution` was used, we'll find the fees in the `holding` register.
585
- self . holding
586
- . try_take ( asset_to_pay_for_fees. clone ( ) . into ( ) )
587
- . map_err ( |e| {
588
- tracing:: error!( target: "xcm::fees" , ?e, ?asset_to_pay_for_fees,
589
- "Holding doesn't hold enough for fees" ) ;
590
- XcmError :: NotHoldingFees
591
- } ) ?
592
- . into ( )
593
- } else {
594
- // Means `PayFees` was used, we'll find the fees in the `fees` register.
595
- self . fees
596
- . try_take ( asset_to_pay_for_fees. clone ( ) . into ( ) )
597
- . map_err ( |e| {
598
- tracing:: error!( target: "xcm::fees" , ?e, ?asset_to_pay_for_fees,
599
- "Fees register doesn't hold enough for fees" ) ;
600
- XcmError :: NotHoldingFees
601
- } ) ?
602
- . into ( )
603
- } ;
604
- tracing:: trace!( target: "xcm::fees" , ?assets_to_pay_delivery_fees) ;
605
- let mut iter = assets_to_pay_delivery_fees. fungible_assets_iter ( ) ;
606
- let asset = iter. next ( ) . ok_or ( XcmError :: NotHoldingFees ) ?;
607
- asset. into ( )
585
+ // Means `PayFees` was used, we'll find the fees in the `fees` register.
586
+ FeesSource :: FeesRegister
608
587
} ;
588
+ let withdrawn_fee_asset = self . withdraw_fee_asset ( & asset_to_pay_for_fees, fees_source) ?;
589
+
609
590
// We perform the swap, if needed, to pay fees.
610
591
let paid = if asset_to_pay_for_fees. id != asset_needed_for_fees. id {
611
- let swapped_asset: Assets = Config :: AssetExchanger :: exchange_asset (
592
+ let swapped_asset = Config :: AssetExchanger :: exchange_asset (
612
593
self . origin_ref ( ) ,
613
594
withdrawn_fee_asset. clone ( ) . into ( ) ,
614
595
& asset_needed_for_fees. clone ( ) . into ( ) ,
@@ -620,9 +601,18 @@ impl<Config: config::Config> XcmExecutor<Config> {
620
601
?given_assets, "Swap was deemed necessary but couldn't be done for withdrawn_fee_asset: {:?} and asset_needed_for_fees: {:?}" , withdrawn_fee_asset. clone( ) , asset_needed_for_fees,
621
602
) ;
622
603
XcmError :: FeesNotMet
623
- } ) ?
624
- . into ( ) ;
625
- swapped_asset
604
+ } ) ?;
605
+
606
+ let ( needed, change) = Self :: get_fungible_needed_and_change (
607
+ swapped_asset,
608
+ & asset_needed_for_fees. id ,
609
+ & asset_to_pay_for_fees. id ,
610
+ )
611
+ . ok_or ( XcmError :: FeesNotMet ) ?;
612
+
613
+ self . deposit_fee_asset ( change, fees_source) ?;
614
+
615
+ needed. into ( )
626
616
} else {
627
617
// If the asset wanted to pay for fees is the one that was needed,
628
618
// we don't need to do any swap.
@@ -633,6 +623,69 @@ impl<Config: config::Config> XcmExecutor<Config> {
633
623
Ok ( ( ) )
634
624
}
635
625
626
+ fn withdraw_fee_asset (
627
+ & mut self ,
628
+ asset : & Asset ,
629
+ fees_source : FeesSource ,
630
+ ) -> Result < Asset , XcmError > {
631
+ tracing:: trace!( target: "xcm::withdraw_fee_asset" , ?asset, ?fees_source) ;
632
+
633
+ let fees = match fees_source {
634
+ FeesSource :: JitWithdraw => {
635
+ let origin = self . origin_ref ( ) . ok_or ( XcmError :: BadOrigin ) ?;
636
+ Config :: AssetTransactor :: withdraw_asset ( & asset, origin, Some ( & self . context ) ) ?
637
+ } ,
638
+ FeesSource :: HoldingRegister =>
639
+ self . holding . try_take ( asset. clone ( ) . into ( ) ) . map_err ( |e| {
640
+ tracing:: error!( target: "xcm::withdraw_fee_asset" , ?e, ?asset,
641
+ "Holding doesn't hold enough for fees" ) ;
642
+ XcmError :: NotHoldingFees
643
+ } ) ?,
644
+ FeesSource :: FeesRegister => self . fees . try_take ( asset. clone ( ) . into ( ) ) . map_err ( |e| {
645
+ tracing:: error!( target: "xcm::withdraw_fee_asset" , ?e, ?asset,
646
+ "Fees register doesn't hold enough for fees" ) ;
647
+ XcmError :: NotHoldingFees
648
+ } ) ?,
649
+ } ;
650
+
651
+ let asset = fees. fungible_assets_iter ( ) . next ( ) . ok_or ( XcmError :: NotHoldingFees ) ?;
652
+
653
+ Ok ( asset)
654
+ }
655
+
656
+ fn deposit_fee_asset ( & mut self , asset : Asset , fees_source : FeesSource ) -> XcmResult {
657
+ tracing:: trace!( target: "xcm::deposit_fee_asset" , ?asset, ?fees_source) ;
658
+
659
+ match fees_source {
660
+ FeesSource :: JitWithdraw => {
661
+ let origin = self . origin_ref ( ) . ok_or ( XcmError :: BadOrigin ) ?;
662
+ Config :: AssetTransactor :: deposit_asset ( & asset, origin, Some ( & self . context ) ) ?;
663
+ } ,
664
+ FeesSource :: HoldingRegister => {
665
+ self . holding . subsume_assets ( asset. clone ( ) . into ( ) ) ;
666
+ } ,
667
+ FeesSource :: FeesRegister => {
668
+ self . fees . subsume_assets ( asset. clone ( ) . into ( ) ) ;
669
+ } ,
670
+ }
671
+
672
+ Ok ( ( ) )
673
+ }
674
+
675
+ fn get_fungible_needed_and_change (
676
+ assets : AssetsInHolding ,
677
+ needed_asset_id : & AssetId ,
678
+ change_asset_id : & AssetId ,
679
+ ) -> Option < ( Asset , Asset ) > {
680
+ let needed_amount = assets. fungible . get ( needed_asset_id) . cloned ( ) ?;
681
+ let change_amount = assets. fungible . get ( change_asset_id) . cloned ( ) . unwrap_or_default ( ) ;
682
+
683
+ let needed: Asset = ( needed_asset_id. clone ( ) , needed_amount) . into ( ) ;
684
+ let change: Asset = ( change_asset_id. clone ( ) , change_amount) . into ( ) ;
685
+
686
+ Some ( ( needed, change) )
687
+ }
688
+
636
689
/// Calculates the amount of asset used in `PayFees` or `BuyExecution` that would be
637
690
/// charged for swapping to `asset_needed_for_fees`.
638
691
///
0 commit comments