Skip to content

Commit

Permalink
adjust implementation and documentation to work with PayFees
Browse files Browse the repository at this point in the history
  • Loading branch information
acatangiu committed Oct 3, 2024
1 parent 4e568d1 commit 60345e5
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -838,8 +838,13 @@ fn bidirectional_transfer_multiple_assets_between_penpal_and_asset_hub() {
fees.fun = Fungible(fees_amount / 2);
}
// xcm to be executed at dest
let xcm_on_dest =
Xcm(vec![DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary }]);
let xcm_on_dest = Xcm(vec![
// since this is the last hop, we don't need to further use any assets previously
// reserved for fees (there are no further hops to cover transport fees for); we
// RefundSurplus to get back any unspent fees
RefundSurplus,
DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary },
]);
let xcm = Xcm::<()>(vec![
WithdrawAsset(all_assets.into()),
PayFees { asset: fees.clone() },
Expand Down Expand Up @@ -867,8 +872,13 @@ fn bidirectional_transfer_multiple_assets_between_penpal_and_asset_hub() {
fees.fun = Fungible(fees_amount / 2);
}
// xcm to be executed at dest
let xcm_on_dest =
Xcm(vec![DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary }]);
let xcm_on_dest = Xcm(vec![
// since this is the last hop, we don't need to further use any assets previously
// reserved for fees (there are no further hops to cover transport fees for); we
// RefundSurplus to get back any unspent fees
RefundSurplus,
DepositAsset { assets: Wild(All), beneficiary: t.args.beneficiary },
]);
let xcm = Xcm::<()>(vec![
WithdrawAsset(all_assets.into()),
PayFees { asset: fees.clone() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,14 @@ fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
let ahw_fee_amount = 100_000_000_000;

// XCM to be executed at dest (Rococo Asset Hub)
let xcm_on_dest =
Xcm(vec![DepositAsset { assets: Wild(All), beneficiary: beneficiary.clone() }]);
let xcm_on_dest = Xcm(vec![
// since this is the last hop, we don't need to further use any assets previously
// reserved for fees (there are no further hops to cover transport fees for); we
// RefundSurplus to get back any unspent fees
RefundSurplus,
// deposit everything to final beneficiary
DepositAsset { assets: Wild(All), beneficiary: beneficiary.clone() },
]);

// XCM to be executed at (intermediary) Westend Asset Hub
let context = PenpalUniversalLocation::get();
Expand All @@ -611,6 +617,9 @@ fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
onward_wnds.fun = Fungible(wnds_amount - ahw_fee_amount - penpal_fees_amount);
let xcm_on_ahw = Xcm(vec![
// both WNDs and PENs are local-reserve transferred to Rococo Asset Hub
// initially, all WNDs are reserved for fees on destination, but at the end of the
// program we RefundSurplus to get back any unspent and deposit them to final
// beneficiary
InitiateTransfer {
destination: reanchored_dest,
remote_fees: Some(AssetTransferFilter::ReserveDeposit(onward_wnds.into())),
Expand All @@ -631,9 +640,9 @@ fn do_send_pens_and_wnds_from_penpal_westend_via_ahw_to_asset_hub_rococo(
// Execute the transfers while paying remote fees with WNDs
InitiateTransfer {
destination: local_asset_hub,
// WNDs are reserve-withdrawn at AHW
// WNDs for fees are reserve-withdrawn at AHW and reserved for fees
remote_fees: Some(AssetTransferFilter::ReserveWithdraw(ahw_fees.into())),
// PENs are teleported to AHW
// PENs are teleported to AHW, rest of non-fee WNDs are reserve-withdrawn at AHW
assets: vec![
AssetTransferFilter::Teleport(pens.into()),
AssetTransferFilter::ReserveWithdraw(ahw_non_fees_wnds.into()),
Expand Down
31 changes: 19 additions & 12 deletions polkadot/xcm/src/v5/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,33 +1052,40 @@ pub enum Instruction<Call> {
/// they are then transferred based on their specified transfer type:
///
/// - teleport: burn local assets and append a `ReceiveTeleportedAsset` XCM instruction to the
/// XCM program to be sent onward to the `dest` location,
/// XCM program to be sent onward to the `destination` location,
///
/// - reserve deposit: place assets under the ownership of `dest` within this consensus system
/// (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction to the
/// XCM program to be sent onward to the `dest` location,
/// - reserve deposit: place assets under the ownership of `destination` within this consensus
/// system (i.e. its sovereign account), and append a `ReserveAssetDeposited` XCM instruction
/// to the XCM program to be sent onward to the `destination` location,
///
/// - reserve withdraw: burn local assets and append a `WithdrawAsset` XCM instruction to the
/// XCM program to be sent onward to the `dest` location,
/// XCM program to be sent onward to the `destination` location,
///
/// The onward XCM is then appended a `ClearOrigin` to allow safe execution of any following
/// custom XCM instructions provided in `remote_xcm`.
///
/// The onward XCM also contains either a `BuyExecution` or `UnpaidExecution` instruction based
/// The onward XCM also contains either a `PayFees` or `UnpaidExecution` instruction based
/// on the presence of the `remote_fees` parameter (see below).
///
/// If an XCM program requires going through multiple hops, it can compose this instruction to
/// be used at every chain along the path, describing that specific leg of the flow.
///
/// Parameters:
/// - `dest`: The location of the program next hop.
/// - `destination`: The location of the program next hop.
/// - `remote_fees`: If set to `Some(asset_xfer_filter)`, the single asset matching
/// `asset_xfer_filter` in the holding register will be transferred first in the remote XCM
/// program, followed by a `BuyExecution(fee)`, then rest of transfers follow. This
/// guarantees `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom`
/// barrier. If set to `None`, a `UnpaidExecution` instruction is appended instead.
/// - `remote_xcm`: Custom instructions that will be executed on the `dest` chain. Note that
/// these instructions will be executed after a `ClearOrigin` so their origin will be `None`.
/// program, followed by a `PayFees(fee)`, then rest of transfers follow. This guarantees
/// `remote_xcm` will successfully pass a `AllowTopLevelPaidExecutionFrom` barrier. If set to
/// `None`, a `UnpaidExecution` instruction is appended instead. Please note that these
/// assets are **reserved** for fees, they are sent to the fees register rather than holding.
/// Best practice is to only add here enough to cover fees, and transfer the rest through the
/// `assets` parameter.
/// - `assets`: List of asset filters matched against existing assets in holding. These are
/// transferred over to `destination` using the specified transfer type, and deposited to
/// holding on `destination`.
/// - `remote_xcm`: Custom instructions that will be executed on the `destination` chain. Note
/// that these instructions will be executed after a `ClearOrigin` so their origin will be
/// `None`.
///
/// Safety: No concerns.
///
Expand Down
5 changes: 3 additions & 2 deletions polkadot/xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1208,8 +1208,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
ensure!(reanchored_fees.len() == 1, XcmError::TooManyAssets);
let fees =
reanchored_fees.into_inner().pop().ok_or(XcmError::NotHoldingFees)?;
// buy execution
message.push(BuyExecution { fees, weight_limit: Unlimited });
// move these assets to the fees register for covering execution and paying
// any subsequent fees
message.push(PayFees { asset: fees });
} else {
// unpaid execution
message
Expand Down

0 comments on commit 60345e5

Please sign in to comment.