paritytech / polkadot-sdk

The Parity Polkadot Blockchain SDK
https://polkadot.com/
1.92k stars 708 forks source link

Estimate Fees for XCM #690

Closed xlc closed 1 month ago

xlc commented 1 year ago

https://github.com/paritytech/polkadot/blob/543462890784d6cd17b6c6f58b73c94d3b32a65d/xcm/xcm-executor/src/lib.rs#L242-L251

Right now it withdraw the fee from origin account directly. This is just bad.

UI will have hard time to estimate the actual fee. User have no way to limit the fee amount.

I don't think right now it is possible to estimate fee of a XCM. We can estimate weight and therefore there is no reason we can't estimate fee. We need some traits and runtime calls to allow frontend to do estimation.

Also I would like to see that fees should only be withdrawn from a fee register, which are prefilled with an instruction to withdraw assets into fee register. This way, user can specify the max fee to avoid unexpected charge.

noandrea commented 1 year ago

Hello, with the migration to the polkadot-sdk single project, are there any updates relative to the ability to estimate XCM fees?

noandrea commented 11 months ago

@xlc gentle nudge

xlc commented 11 months ago

Don’t nudge me, I am the one asking question and hoping someone else will answer me as well.

bkchr commented 11 months ago

CC @franciscoaguirre

aaron2048 commented 11 months ago

@bkchr - would be great if someone from Dev Fellowship could comment on this and let interested parties know if and when this might be addressed.

We see this as a limitation to the Dynamic fee mechanism on Moonbeam and should XCM continue to get traction, this will prove to be a problem for others.

If you are not the right person to ping on this, is there a better way to get someone from the fellowship to take a look and provide some guidance?

Thanks in advance

acatangiu commented 11 months ago

I’m also aware of this behaviour, but am unsure what the best solution would be. Can you elaborate on the desired/ideal UX, and we can work backwards from that to fix/improve fee handling?

xlc commented 11 months ago
  1. Fee register to easily cap max fee.
  2. Runtime API to dry run XCM and returns outcome and fees and weights. If all the fees are deducted from fee register, then it is simply calculate how much is deducted from it.
gavofyork commented 11 months ago

We can take a look at this in the next XCM retreat, but in the meantime if you have any specific proposal for improvement, perhaps you can put it in an RFC.

acatangiu commented 11 months ago

What about multi-hop XCMs? For example, going through a reserve chain C for transferring TokenC from A to B, or going over a bridge.

Runtime API to dry run XCM and returns outcome and fees and weights. If all the fees are deducted from fee register, then it is simply calculate how much is deducted from it.

Having this ^ would allow UIs to call into each runtime for every hop to query fees, but they'd be "guessing" what the intermediary XCMs look like. Probably we'd need to provide these intermediaries too as part of the dry-run. As in: Dry-run this XCM, you get back execution cost/weight, delivery cost to first hop, first hop location, and XCM to be sent to first hop, then you repeat dry-runs with new intermediary XCMs for each hop to destination.

But I'm secretly hoping there's a better/smarter way to do it..

xlc commented 11 months ago

Unfortunately, it is most likely that you will need to query multiple chains for a multi hop XCM execution. I just cannot see any way around it. But at least someone could build an SDK to abstract all those complex logics. and with light clients and the new polkadot-api (which I don't know what it is because there are zero docs exists), it should be possible to make the consumer side relatively easy.

muharem commented 9 months ago

There is BuyExecution { fees: Asset, weight_limit: WeightLimit }, user can set the asset id to be used from registry and the weight limit. But no separate fee registry. And there is a runtime api to query a weight and an estimated fee for for a call - link. It would be nice to hear what we need on top of it.

acatangiu commented 9 months ago

Part of https://github.com/paritytech/polkadot-sdk/issues/3434#issuecomment-1961353598:

Current proposal is to provide runtime apis (callable from on-chain or off-chain) to effectively "dry-run" an XCM program, providing info on things like:

  1. local side effects
  2. forwarded messages: forwarded XCM content and its destination
  3. locally spent fees

The same runtime API can then be called off-chain recursively on [intermediary, +] destination chains dry-running the XCMs got in 2. from previous hop.

This way a wallet/dapp can dry-run the e2e path and get fees for each step.

This runtime API can be later genericized/replaced with a new XCQ mechanism to get the same info (and more) using generic chain-agnostic queries (rather than chain-specific runtime api calls).

Further, ideas were also discussed for some mechanism to actively lock-in the fee-price, to avoid synchronization issues between querying and executing.

franciscoaguirre commented 8 months ago

Now that we have the XCM fee payment runtime API, we need a higher level runtime API UIs can use to estimate fees for the most common operations users do, starting with reserve asset transfers and teleports. These would need to fit well with pallet-xcm's transfer_assets and xtokens' transfer at a minimum.

I see two options, either we create a runtime API that returns the fees needed to be paid for each transfer type, or one that just returns the message that will be executed and the message that would be sent. I lean towards the second one. Given those messages, the UI could call the lower level API for getting the fees. This has the benefit we don't need to replicate the weight and valid assets thing on the higher level API. The downside is UIs would have to call two APIs instead of one, but they could cache the response of one of them for some time if that's a problem.

acatangiu commented 8 months ago

Ongoing conversation happening in https://github.com/paritytech/polkadot-sdk/pull/3872

Cross-posting here as well:

I was discussing something similar with @franciscoaguirre, exploring something similar:

pub struct XcmDryRunEffects {
    forwarded_xcms: Vec<(Location, Xcm<()>)>,
    fees_spent_locally: MultiAssets,
    // maybe more?
}

pub trait DryRunXcmApi {
    /// query side effects for executing extrinsic
    fn query_xcm_for_extrinsic(
        xt: <Block as BlockT>::Extrinsic,    // extrinsic to dry-run
        query_side_effects: FnMut(),         // optional closure to implement any custom logic
                                             // for custom querying dry-run side-effects
                                             // (balances changes, any particular storage changes)
    ) -> Result<XcmDryRunEffects, /* ErrT */>;

    /// query side effects for executing (incoming) XCM
    fn query_execute_xcm(
        xcm: Xcm<()>,
        using_origin: Location,
        query_side_effects: FnMut(),
    ) -> Result<XcmDryRunEffects, /* ErrT */>;
}

We want to:

Would this be enough to cover all needs?

acatangiu commented 8 months ago

(Changed title to clarify this issue is now specialized on the ability to estimate total fees across multiple chains for cross-chain messages)

The other side of the problem, namely how transport fees are actually charged in the executor is being tracked and discussed in https://github.com/paritytech/polkadot-sdk/issues/3434

franciscoaguirre commented 6 months ago

Now that the XcmDryRunApi was merged. There are still some next steps:

acatangiu commented 1 month ago

Completed in https://github.com/polkadot-fellows/runtimes/issues/479