Skip to content

Commit

Permalink
xcm-executor: DepositReserveAsset charges delivery fees from inner as…
Browse files Browse the repository at this point in the history
…sets

This fix aims to solve an issue in Kusama that resulted in failed
reserve asset transfers.

During multi-hop XCMs, like reserve asset transfers where the reserve
is not the sender nor the destination, but a third remote chain, the
origin is not available to pay for delivery fees out of their account
directly, so delivery fees should be paid out of transferred assets.

This commit also adds an xcm-emulator regression test that validates
this scenario is now working.

Signed-off-by: Adrian Catangiu <[email protected]>
  • Loading branch information
acatangiu committed Jan 30, 2024
1 parent e5bb11b commit 48ea3ce
Showing 1 changed file with 16 additions and 0 deletions.
16 changes: 16 additions & 0 deletions polkadot/xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,20 @@ impl<Config: config::Config> XcmExecutor<Config> {
DepositReserveAsset { assets, dest, xcm } => {
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
// we need to do this take/put cycle to solve wildcards and get exact assets to
// be weighed
let to_weigh = self.holding.saturating_take(assets.clone());
self.holding.subsume_assets(to_weigh.clone());

let mut message_to_weigh =
vec![ReserveAssetDeposited(to_weigh.into()), ClearOrigin];
message_to_weigh.extend(xcm.0.clone().into_iter());
let (_, fee) =
validate_send::<Config::XcmSender>(dest.clone(), Xcm(message_to_weigh))?;
// set aside fee to be charged by XcmSender
let transport_fee = self.holding.saturating_take(fee.into());

// now take assets to deposit (excluding transport_fee)
let deposited = self.holding.saturating_take(assets);
for asset in deposited.assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?;
Expand All @@ -832,6 +846,8 @@ impl<Config: config::Config> XcmExecutor<Config> {
let assets = Self::reanchored(deposited, &dest, None);
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
// put back transport_fee in holding register to be charged by XcmSender
self.holding.subsume_assets(transport_fee);
self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?;
Ok(())
});
Expand Down

0 comments on commit 48ea3ce

Please sign in to comment.