mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-18 08:15:41 +00:00
9a04ebbfb0
Currently `transfer_assets` from pallet-xcm covers 4 main different transfer types: - `localReserve` - `DestinationReserve` - `Teleport` - `RemoteReserve` For the first three, the local execution and the remote message sending are separated, and fees are deducted in pallet-xcm itself: https://github.com/paritytech/polkadot-sdk/blob/3410dfb3929462da88be2da813f121d8b1cf46b3/polkadot/xcm/pallet-xcm/src/lib.rs#L1758. For the 4th case `RemoteReserve`, pallet-xcm is still relying on the xcm-executor itself to send the message (through the `initiateReserveWithdraw` instruction). In this case, if delivery fees need to be charged, it is not possible to do so because the `jit_withdraw` mode has not being set. This PR proposes to still use the `initiateReserveWithdraw` but prepending a `setFeesMode { jit_withdraw: true }` to make sure delivery fees can be paid. A test-case is also added to present the aforementioned case --------- Co-authored-by: Adrian Catangiu <adrian@parity.io>
112 lines
4.0 KiB
Rust
112 lines
4.0 KiB
Rust
// Copyright Parity Technologies (UK) Ltd.
|
|
// This file is part of Cumulus.
|
|
|
|
// Cumulus is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Cumulus is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
//! Helpers for calculating XCM delivery fees.
|
|
|
|
use xcm::latest::prelude::*;
|
|
|
|
/// Returns the delivery fees amount for pallet xcm's `teleport_assets` extrinsics.
|
|
/// Because it returns only a `u128`, it assumes delivery fees are only paid
|
|
/// in one asset and that asset is known.
|
|
pub fn teleport_assets_delivery_fees<S: SendXcm>(
|
|
assets: Assets,
|
|
fee_asset_item: u32,
|
|
weight_limit: WeightLimit,
|
|
beneficiary: Location,
|
|
destination: Location,
|
|
) -> u128 {
|
|
let message = teleport_assets_dummy_message(assets, fee_asset_item, weight_limit, beneficiary);
|
|
get_fungible_delivery_fees::<S>(destination, message)
|
|
}
|
|
|
|
/// Returns the delivery fees amount for a query response as a result of the execution
|
|
/// of a `ExpectError` instruction with no error.
|
|
pub fn query_response_delivery_fees<S: SendXcm>(querier: Location) -> u128 {
|
|
// Message to calculate delivery fees, it's encoded size is what's important.
|
|
// This message reports that there was no error, if an error is reported, the encoded size would
|
|
// be different.
|
|
let message = Xcm(vec![
|
|
SetFeesMode { jit_withdraw: true },
|
|
QueryResponse {
|
|
query_id: 0, // Dummy query id
|
|
response: Response::ExecutionResult(None),
|
|
max_weight: Weight::zero(),
|
|
querier: Some(querier.clone()),
|
|
},
|
|
SetTopic([0u8; 32]), // Dummy topic
|
|
]);
|
|
get_fungible_delivery_fees::<S>(querier, message)
|
|
}
|
|
|
|
/// Returns the delivery fees amount for the execution of `PayOverXcm`
|
|
pub fn pay_over_xcm_delivery_fees<S: SendXcm>(
|
|
interior: Junctions,
|
|
destination: Location,
|
|
beneficiary: Location,
|
|
asset: Asset,
|
|
) -> u128 {
|
|
// This is a dummy message.
|
|
// The encoded size is all that matters for delivery fees.
|
|
let message = Xcm(vec![
|
|
DescendOrigin(interior),
|
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
|
SetAppendix(Xcm(vec![
|
|
SetFeesMode { jit_withdraw: true },
|
|
ReportError(QueryResponseInfo {
|
|
destination: destination.clone(),
|
|
query_id: 0,
|
|
max_weight: Weight::zero(),
|
|
}),
|
|
])),
|
|
TransferAsset { beneficiary, assets: vec![asset].into() },
|
|
]);
|
|
get_fungible_delivery_fees::<S>(destination, message)
|
|
}
|
|
|
|
/// Approximates the actual message sent by the teleport extrinsic.
|
|
/// The assets are not reanchored and the topic is a dummy one.
|
|
/// However, it should have the same encoded size, which is what matters for delivery fees.
|
|
/// Also has same encoded size as the one created by the reserve transfer assets extrinsic.
|
|
fn teleport_assets_dummy_message(
|
|
assets: Assets,
|
|
fee_asset_item: u32,
|
|
weight_limit: WeightLimit,
|
|
beneficiary: Location,
|
|
) -> Xcm<()> {
|
|
Xcm(vec![
|
|
ReceiveTeleportedAsset(assets.clone()), // Same encoded size as `ReserveAssetDeposited`
|
|
ClearOrigin,
|
|
BuyExecution { fees: assets.get(fee_asset_item as usize).unwrap().clone(), weight_limit },
|
|
DepositAsset { assets: Wild(AllCounted(assets.len() as u32)), beneficiary },
|
|
SetTopic([0u8; 32]), // Dummy topic
|
|
])
|
|
}
|
|
|
|
/// Given a message, a sender, and a destination, it returns the delivery fees
|
|
fn get_fungible_delivery_fees<S: SendXcm>(destination: Location, message: Xcm<()>) -> u128 {
|
|
let Ok((_, delivery_fees)) = validate_send::<S>(destination, message) else {
|
|
unreachable!("message can be sent; qed")
|
|
};
|
|
if let Some(delivery_fee) = delivery_fees.inner().first() {
|
|
let Fungible(delivery_fee_amount) = delivery_fee.fun else {
|
|
unreachable!("asset is fungible; qed");
|
|
};
|
|
delivery_fee_amount
|
|
} else {
|
|
0
|
|
}
|
|
}
|