Skip to content

Refactor: simplify XCM weight trading#8202

Draft
mrshiposha wants to merge 7 commits intoparitytech:masterfrom
UniqueNetwork:refactor/simplify-weight-trading
Draft

Refactor: simplify XCM weight trading#8202
mrshiposha wants to merge 7 commits intoparitytech:masterfrom
UniqueNetwork:refactor/simplify-weight-trading

Conversation

@mrshiposha
Copy link
Copy Markdown
Contributor

Description

This is a draft of an XCM weight trading refactoring that simplifies its API and makes it re-usable in the XCM payment API for converting weight to a fee in a selected fungible currency.

A common implementation for XCM payment API's query_weight_to_asset_fee is added to pallet-xcm.

The relevant tests in the xcm-builder and asset-hub-westend runtime are updated.

CC @acatangiu @franciscoaguirre

Integration

The PR changes the existing WeightTraders and adds a new entry to the pallet-xcm's config.
It affects the Runtime builders.

Review Notes

This is a draft, so some things aren't polished out. It is intentional because it seems reasonable to show the general idea first and collect feedback before finalizing everything (like changing in-code documentation, addressing TODOs and FIXMEs such as renaming relevant tests, adding logs in some places, etc).

The relevant changes are in the xcm-executor, xcm-builder, cumulus-primitives-utility, pallet-xcm, and asset-hub-westend runtime.
The rest was made only to build the Westend Relay and Westend Asset Hub for basic local testing.

WeightTrader related

  1. The xcm-executor's WeightTrader trait has been modified to deal only with fungibles since no obvious mechanism for using NFTs as XCM fees exists:

    • It is unclear how NFTs can be used for delivery fees
    • The XCM payment API doesn't have methods where NFTs are considered fee assets
      Apparently, no one uses NFTs for XCM execution fees, so it seems reasonable to remove them from the general weight trading API. If a kind of "XCM execution ticket" is needed in the future, corresponding logic could be added separately based on known use cases.
  2. The WeightTrader trait now describes a stateless mechanism. The traders' common state is now moved to the xcm-executor itself, represented by a FeePayment struct containing the desired fee asset ID, the actually used fee asset ID (which could be a different one in case of a swap), and the fee paid amount. This allows for avoiding re-implementing the state-tracking logic in all the weight traders, allowing for focusing on the actual weight fee computation in them, making their code clearer.
    The corresponding logic for buying and refunding the weight has been altered in the xcm-executor.

  3. The xcm-executor already has the AssetExchanger capable of swapping the assets. The Weight Trader might request an asset swap if the desired fee asset ID can't (or shouldn't) be used directly as a weight fee. The Trader either tells the executor to use the provided desired fee asset ID and returns the corresponding required amount of it via WeightFee::Desired or it tells how much of the desired asset must be swapped and to what it should be swapped via WeightFee::Swap.
    This way, a weight trader's code that allows an asset swap can be kept simple, only quoting the exchange price without changing any state and providing all the relevant info about the weight fee.

  4. The WeightTrader trait now has a default implementation for computing the refund weight amount. Most implementations can use it. A special refund weight computation is needed when there is some constraint on the provided payment to be honored (e.g., ensuring that at least the asset's minimum balance will be paid for the weight).

@acatangiu
Copy link
Copy Markdown
Contributor

I like it high-level.

The WeightTrader trait now describes a stateless mechanism. The traders' common state is now moved to the xcm-executor itself, represented by a FeePayment struct containing the desired fee asset ID, the actually used fee asset ID (which could be a different one in case of a swap), and the fee paid amount. This allows for avoiding re-implementing the state-tracking logic in all the weight traders, allowing for focusing on the actual weight fee computation in them, making their code clearer.
The corresponding logic for buying and refunding the weight has been altered in the xcm-executor.

This part needs more review - this is really the big change proposed here, with new logic proposed that we need to carefully audit..

github-merge-queue bot pushed a commit that referenced this pull request May 6, 2025
# Description

Add a common implementation for
`XcmPaymentApi::query_weight_to_asset_fee` to `pallet-xcm`.

This PR is a simple alternative to #8202 (which could still be useful
for other reasons).
It uses a workaround instead of a big refactoring.

The workaround is:
Computes the weight cost using the provided `WeightTrader`.
This function is supposed to be used ONLY in
`XcmPaymentApi::query_weight_to_asset_fee`
Runtime API implementation, as it can introduce a massive change to the
total issuance.
The provided `WeightTrader` must be the same as the one used in the
XcmExecutor to ensure
uniformity in the weight cost calculation.

NOTE: Currently this function uses a workaround that should be good
enough for all practical
uses: passes `u128::MAX / 2 == 2^127` of the specified asset to the
`WeightTrader` as
payment and computes the weight cost as the difference between this and
the unspent amount.
Some weight traders could add the provided payment to some account's
balance. However,
it should practically never result in overflow because even currencies
with a lot of decimal digits
(say 18) usually have the total issuance of billions (`x * 10^9`) or
trillions (`x * 10^12`) at max,
much less than `2^127 / 10^18 =~ 1.7 * 10^20` (170 billion billion).
Thus, any account's balance
most likely holds less than `2^127`, so adding `2^127` won't result in
`u128` overflow.


## Integration

The Runtime builders can use the `query_weight_to_asset_fee` provided by
`pallet-xcm` in
their XcmPaymentApi implementation.

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
castillax pushed a commit that referenced this pull request May 12, 2025
# Description

Add a common implementation for
`XcmPaymentApi::query_weight_to_asset_fee` to `pallet-xcm`.

This PR is a simple alternative to #8202 (which could still be useful
for other reasons).
It uses a workaround instead of a big refactoring.

The workaround is:
Computes the weight cost using the provided `WeightTrader`.
This function is supposed to be used ONLY in
`XcmPaymentApi::query_weight_to_asset_fee`
Runtime API implementation, as it can introduce a massive change to the
total issuance.
The provided `WeightTrader` must be the same as the one used in the
XcmExecutor to ensure
uniformity in the weight cost calculation.

NOTE: Currently this function uses a workaround that should be good
enough for all practical
uses: passes `u128::MAX / 2 == 2^127` of the specified asset to the
`WeightTrader` as
payment and computes the weight cost as the difference between this and
the unspent amount.
Some weight traders could add the provided payment to some account's
balance. However,
it should practically never result in overflow because even currencies
with a lot of decimal digits
(say 18) usually have the total issuance of billions (`x * 10^9`) or
trillions (`x * 10^12`) at max,
much less than `2^127 / 10^18 =~ 1.7 * 10^20` (170 billion billion).
Thus, any account's balance
most likely holds less than `2^127`, so adding `2^127` won't result in
`u128` overflow.


## Integration

The Runtime builders can use the `query_weight_to_asset_fee` provided by
`pallet-xcm` in
their XcmPaymentApi implementation.

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
alvicsam pushed a commit that referenced this pull request Oct 17, 2025
# Description

Add a common implementation for
`XcmPaymentApi::query_weight_to_asset_fee` to `pallet-xcm`.

This PR is a simple alternative to #8202 (which could still be useful
for other reasons).
It uses a workaround instead of a big refactoring.

The workaround is:
Computes the weight cost using the provided `WeightTrader`.
This function is supposed to be used ONLY in
`XcmPaymentApi::query_weight_to_asset_fee`
Runtime API implementation, as it can introduce a massive change to the
total issuance.
The provided `WeightTrader` must be the same as the one used in the
XcmExecutor to ensure
uniformity in the weight cost calculation.

NOTE: Currently this function uses a workaround that should be good
enough for all practical
uses: passes `u128::MAX / 2 == 2^127` of the specified asset to the
`WeightTrader` as
payment and computes the weight cost as the difference between this and
the unspent amount.
Some weight traders could add the provided payment to some account's
balance. However,
it should practically never result in overflow because even currencies
with a lot of decimal digits
(say 18) usually have the total issuance of billions (`x * 10^9`) or
trillions (`x * 10^12`) at max,
much less than `2^127 / 10^18 =~ 1.7 * 10^20` (170 billion billion).
Thus, any account's balance
most likely holds less than `2^127`, so adding `2^127` won't result in
`u128` overflow.


## Integration

The Runtime builders can use the `query_weight_to_asset_fee` provided by
`pallet-xcm` in
their XcmPaymentApi implementation.

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants