mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-19 16:55:43 +00:00
Introduce XcmFeesToAccount fee manager (#1234)
Combination of paritytech/polkadot#7005, its addon PR paritytech/polkadot#7585 and its companion paritytech/cumulus#2433. This PR introduces a new XcmFeesToAccount struct which implements the `FeeManager` trait, and assigns this struct as the `FeeManager` in the XCM config for all runtimes. The struct simply deposits all fees handled by the XCM executor to a specified account. In all runtimes, the specified account is configured as the treasury account. XCM __delivery__ fees are now being introduced (unless the root origin is sending a message to a system parachain on behalf of the originating chain). # Note for reviewers Most file changes are tests that had to be modified to account for the new fees. Main changes are in: - cumulus/pallets/xcmp-queue/src/lib.rs <- To make it track the delivery fees exponential factor - polkadot/xcm/xcm-builder/src/fee_handling.rs <- Added. Has the FeeManager implementation - All runtime xcm_config files <- To add the FeeManager to the XCM configuration # Important note After this change, instructions that create and send a new XCM (Query*, Report*, ExportMessage, InitiateReserveWithdraw, InitiateTeleport, DepositReserveAsset, TransferReserveAsset, LockAsset and RequestUnlock) will require the corresponding origin account in the origin register to pay for transport delivery fees, and the onward message will fail to be sent if the origin account does not have the required amount. This delivery fee is on top of what we already collect as tx fees in pallet-xcm and XCM BuyExecution fees! Wallet UIs that want to expose the new delivery fee can do so using the formula: ``` delivery_fee_factor * (base_fee + encoded_msg_len * per_byte_fee) ``` where the delivery fee factor can be obtained from the corresponding pallet based on which transport you are using (UMP, HRMP or bridges), the base fee is a constant, the encoded message length from the message itself and the per byte fee is the same as the configured per byte fee for txs (i.e. `TransactionByteFee`). --------- Co-authored-by: Branislav Kontur <bkontur@gmail.com> Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Giles Cope <gilescope@gmail.com> Co-authored-by: command-bot <> Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
@@ -248,7 +248,7 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
|
||||
for asset in fees.inner() {
|
||||
Config::AssetTransactor::withdraw_asset(&asset, &origin, None)?;
|
||||
}
|
||||
Config::FeeManager::handle_fee(fees);
|
||||
Config::FeeManager::handle_fee(fees, None);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -405,10 +405,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
reason: FeeReason,
|
||||
) -> Result<XcmHash, XcmError> {
|
||||
let (ticket, fee) = validate_send::<Config::XcmSender>(dest, msg)?;
|
||||
if !Config::FeeManager::is_waived(self.origin_ref(), reason) {
|
||||
let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?;
|
||||
Config::FeeManager::handle_fee(paid.into());
|
||||
}
|
||||
self.take_fee(fee, reason)?;
|
||||
Config::XcmSender::deliver(ticket).map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -618,14 +615,18 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
DepositAsset { assets, beneficiary } => {
|
||||
let deposited = self.holding.saturating_take(assets);
|
||||
for asset in deposited.into_assets_iter() {
|
||||
Config::AssetTransactor::deposit_asset(&asset, &beneficiary, &self.context)?;
|
||||
Config::AssetTransactor::deposit_asset(
|
||||
&asset,
|
||||
&beneficiary,
|
||||
Some(&self.context),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
DepositReserveAsset { assets, dest, xcm } => {
|
||||
let deposited = self.holding.saturating_take(assets);
|
||||
for asset in deposited.assets_iter() {
|
||||
Config::AssetTransactor::deposit_asset(&asset, &dest, &self.context)?;
|
||||
Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?;
|
||||
}
|
||||
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
|
||||
// be reanchored because we have already called `deposit_asset` on all assets.
|
||||
@@ -944,6 +945,14 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
if Config::FeeManager::is_waived(self.origin_ref(), reason) {
|
||||
return Ok(())
|
||||
}
|
||||
log::trace!(
|
||||
target: "xcm::fees",
|
||||
"taking fee: {:?} from origin_ref: {:?} in fees_mode: {:?} for a reason: {:?}",
|
||||
fee,
|
||||
self.origin_ref(),
|
||||
self.fees_mode,
|
||||
reason,
|
||||
);
|
||||
let paid = if self.fees_mode.jit_withdraw {
|
||||
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
|
||||
for asset in fee.inner() {
|
||||
@@ -953,7 +962,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
} else {
|
||||
self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into()
|
||||
};
|
||||
Config::FeeManager::handle_fee(paid);
|
||||
Config::FeeManager::handle_fee(paid, Some(&self.context));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -985,12 +994,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
let QueryResponseInfo { destination, query_id, max_weight } = info;
|
||||
let instruction = QueryResponse { query_id, response, max_weight, querier };
|
||||
let message = Xcm(vec![instruction]);
|
||||
let (ticket, fee) = validate_send::<Config::XcmSender>(destination, message)?;
|
||||
if !Config::FeeManager::is_waived(self.origin_ref(), fee_reason) {
|
||||
let paid = self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?;
|
||||
Config::FeeManager::handle_fee(paid.into());
|
||||
}
|
||||
Config::XcmSender::deliver(ticket).map_err(Into::into)
|
||||
self.send(destination, message, fee_reason)
|
||||
}
|
||||
|
||||
fn try_reanchor(
|
||||
|
||||
@@ -23,11 +23,11 @@ pub trait FeeManager {
|
||||
|
||||
/// Do something with the fee which has been paid. Doing nothing here silently burns the
|
||||
/// fees.
|
||||
fn handle_fee(fee: MultiAssets);
|
||||
fn handle_fee(fee: MultiAssets, context: Option<&XcmContext>);
|
||||
}
|
||||
|
||||
/// Context under which a fee is paid.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FeeReason {
|
||||
/// When a reporting instruction is called.
|
||||
Report,
|
||||
@@ -53,7 +53,7 @@ pub enum FeeReason {
|
||||
|
||||
impl FeeManager for () {
|
||||
fn is_waived(_: Option<&MultiLocation>, _: FeeReason) -> bool {
|
||||
true
|
||||
false
|
||||
}
|
||||
fn handle_fee(_: MultiAssets) {}
|
||||
fn handle_fee(_: MultiAssets, _: Option<&XcmContext>) {}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,11 @@ pub trait TransactAsset {
|
||||
/// Deposit the `what` asset into the account of `who`.
|
||||
///
|
||||
/// Implementations should return `XcmError::FailedToTransactAsset` if deposit failed.
|
||||
fn deposit_asset(_what: &MultiAsset, _who: &MultiLocation, _context: &XcmContext) -> XcmResult {
|
||||
fn deposit_asset(
|
||||
_what: &MultiAsset,
|
||||
_who: &MultiLocation,
|
||||
_context: Option<&XcmContext>,
|
||||
) -> XcmResult {
|
||||
Err(XcmError::Unimplemented)
|
||||
}
|
||||
|
||||
@@ -139,7 +143,7 @@ pub trait TransactAsset {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => {
|
||||
let assets = Self::withdraw_asset(asset, from, Some(context))?;
|
||||
// Not a very forgiving attitude; once we implement roll-backs then it'll be nicer.
|
||||
Self::deposit_asset(asset, to, context)?;
|
||||
Self::deposit_asset(asset, to, Some(context))?;
|
||||
Ok(assets)
|
||||
},
|
||||
result => result,
|
||||
@@ -195,7 +199,11 @@ impl TransactAsset for Tuple {
|
||||
)* );
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult {
|
||||
fn deposit_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation,
|
||||
context: Option<&XcmContext>,
|
||||
) -> XcmResult {
|
||||
for_tuples!( #(
|
||||
match Tuple::deposit_asset(what, who, context) {
|
||||
Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (),
|
||||
@@ -286,7 +294,7 @@ mod tests {
|
||||
fn deposit_asset(
|
||||
_what: &MultiAsset,
|
||||
_who: &MultiLocation,
|
||||
_context: &XcmContext,
|
||||
_context: Option<&XcmContext>,
|
||||
) -> XcmResult {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
@@ -330,7 +338,7 @@ mod tests {
|
||||
fn deposit_asset(
|
||||
_what: &MultiAsset,
|
||||
_who: &MultiLocation,
|
||||
_context: &XcmContext,
|
||||
_context: Option<&XcmContext>,
|
||||
) -> XcmResult {
|
||||
Err(XcmError::Overflow)
|
||||
}
|
||||
@@ -374,7 +382,7 @@ mod tests {
|
||||
fn deposit_asset(
|
||||
_what: &MultiAsset,
|
||||
_who: &MultiLocation,
|
||||
_context: &XcmContext,
|
||||
_context: Option<&XcmContext>,
|
||||
) -> XcmResult {
|
||||
Ok(())
|
||||
}
|
||||
@@ -406,7 +414,7 @@ mod tests {
|
||||
MultiTransactor::deposit_asset(
|
||||
&(Here, 1u128).into(),
|
||||
&Here.into(),
|
||||
&XcmContext::with_message_id([0; 32]),
|
||||
Some(&XcmContext::with_message_id([0; 32])),
|
||||
),
|
||||
Err(XcmError::AssetNotFound)
|
||||
);
|
||||
@@ -420,7 +428,7 @@ mod tests {
|
||||
MultiTransactor::deposit_asset(
|
||||
&(Here, 1u128).into(),
|
||||
&Here.into(),
|
||||
&XcmContext::with_message_id([0; 32]),
|
||||
Some(&XcmContext::with_message_id([0; 32])),
|
||||
),
|
||||
Ok(())
|
||||
);
|
||||
@@ -434,7 +442,7 @@ mod tests {
|
||||
MultiTransactor::deposit_asset(
|
||||
&(Here, 1u128).into(),
|
||||
&Here.into(),
|
||||
&XcmContext::with_message_id([0; 32]),
|
||||
Some(&XcmContext::with_message_id([0; 32])),
|
||||
),
|
||||
Err(XcmError::Overflow)
|
||||
);
|
||||
@@ -448,7 +456,7 @@ mod tests {
|
||||
MultiTransactor::deposit_asset(
|
||||
&(Here, 1u128).into(),
|
||||
&Here.into(),
|
||||
&XcmContext::with_message_id([0; 32]),
|
||||
Some(&XcmContext::with_message_id([0; 32])),
|
||||
),
|
||||
Ok(()),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user