Skip to content

Commit 7a20075

Browse files
committed
fix: deposit fee change
1 parent 5f44a77 commit 7a20075

File tree

1 file changed

+94
-41
lines changed
  • polkadot/xcm/xcm-executor/src

1 file changed

+94
-41
lines changed

polkadot/xcm/xcm-executor/src/lib.rs

+94-41
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ impl<C> WeighedMessage<C> {
226226
}
227227
}
228228

229+
#[derive(Debug, Clone, Copy)]
230+
enum FeesSource {
231+
JitWithdraw,
232+
HoldingRegister,
233+
FeesRegister,
234+
}
235+
229236
impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Config> {
230237
type Prepared = WeighedMessage<Config::RuntimeCall>;
231238
fn prepare(
@@ -567,48 +574,22 @@ impl<Config: config::Config> XcmExecutor<Config> {
567574
let asset_to_pay_for_fees =
568575
self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone());
569576
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
580584
} 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
608587
};
588+
let withdrawn_fee_asset = self.withdraw_fee_asset(&asset_to_pay_for_fees, fees_source)?;
589+
609590
// We perform the swap, if needed, to pay fees.
610591
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(
612593
self.origin_ref(),
613594
withdrawn_fee_asset.clone().into(),
614595
&asset_needed_for_fees.clone().into(),
@@ -620,9 +601,18 @@ impl<Config: config::Config> XcmExecutor<Config> {
620601
?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,
621602
);
622603
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()
626616
} else {
627617
// If the asset wanted to pay for fees is the one that was needed,
628618
// we don't need to do any swap.
@@ -633,6 +623,69 @@ impl<Config: config::Config> XcmExecutor<Config> {
633623
Ok(())
634624
}
635625

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+
636689
/// Calculates the amount of asset used in `PayFees` or `BuyExecution` that would be
637690
/// charged for swapping to `asset_needed_for_fees`.
638691
///

0 commit comments

Comments
 (0)