Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Descend to user origin & Burn fee from the user #168

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bridges/snowbridge/primitives/router/src/outbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ where
}

let para_id = match local_sub.as_slice() {
[Parachain(para_id)] => *para_id,
[Parachain(para_id), AccountId32 { .. }] => *para_id,
_ => {
log::error!(target: "xcm::ethereum_blob_exporter", "could not get parachain id from universal source '{local_sub:?}'.");
return Err(SendError::MissingArgument)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
// Assert there is still some fee left in sov account after the transfer
let free_balance_of_sovereign_on_bh_after =
<BridgeHubRococo as BridgeHubRococoPallet>::Balances::free_balance(assethub_sovereign);
assert_eq!(free_balance_of_sovereign_on_bh_after, 15590000);
assert_eq!(free_balance_of_sovereign_on_bh_after, 10686667);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocat
fn validate(
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
_source: Option<&Location>,
source: Option<&Location>,
Copy link
Author

@yrong yrong Aug 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the source location(optional) to SendXcm trait so that we can DescendOrigin to the souce location(i.e. user) later.

#169 as prerequisite which is a breaking change.

) -> SendResult<Router::Ticket> {
let d = dest.as_ref().ok_or(MissingArgument)?;
let devolved =
Expand All @@ -478,6 +478,11 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocat
return Err(NotApplicable)
};

// Ensure the export fee configured is not None.
let payments: xcm::prelude::Assets =
if let Some(ref payment) = maybe_payment { Some(payment.clone().into()) } else { None }
.ok_or(NotApplicable)?;

// `xcm` should already end with `SetTopic` - if it does, then extract and derive into
// an onward topic ID.
let maybe_forward_id = match xcm.last() {
Expand All @@ -491,12 +496,16 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocat
let export_instruction =
ExportMessage { network: remote_network, destination: remote_location, xcm };

let sender = if let Some(origin) = source { Some(origin.clone().interior) } else { None }
.ok_or(NotApplicable)?;

let mut message = Xcm(if let Some(ref payment) = maybe_payment {
let fees = payment
.clone()
.reanchored(&bridge, &UniversalLocation::get())
.map_err(|_| Unroutable)?;
vec![
DescendOrigin(sender),
ReceiveTeleportedAsset(fees.clone().into()),
BuyExecution { fees, weight_limit: Unlimited },
Comment on lines +499 to 510
Copy link
Author

@yrong yrong Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In custom exporter we add DescendOrigin into the outer Xcm of the export message.

// `SetAppendix` ensures that `fees` are not trapped in any case, for example, when
Expand All @@ -517,11 +526,8 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocat

// We then send a normal message to the bridge asking it to export the prepended
// message to the remote chain.
let (v, mut cost, _) = validate_send::<Router>(bridge, message, None)?;
if let Some(bridge_payment) = maybe_payment {
cost.push(bridge_payment);
}
Ok((v, cost, None))
let (v, cost, _) = validate_send::<Router>(bridge, message, None)?;
Ok((v, cost, Some(payments)))
}

fn deliver(ticket: Router::Ticket) -> Result<XcmHash, SendError> {
Expand Down Expand Up @@ -727,7 +733,7 @@ pub mod bridging {
parameter_types! {
/// User fee for delivery cost on bridge hub. Leave some buffer here for avoid spamming
/// should cover at least the BuyExecution on BH
pub const DefaultBridgeHubEthereumBaseFee: Balance = 48_000_000;
pub const DefaultBridgeHubEthereumBaseFee: Balance = 60_000_000;
pub storage BridgeHubEthereumBaseFee: Balance = DefaultBridgeHubEthereumBaseFee::get();
pub SiblingBridgeHubWithEthereumInboundQueueInstance: Location = Location::new(
1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,23 @@ use super::{
use bp_messages::LaneId;
use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams};
use bp_runtime::ChainId;
use cumulus_primitives_core::ParaId;
use frame_support::{
parameter_types,
traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing},
traits::{
tokens::imbalance::ResolveTo, ConstU32, Contains, ContainsPair, Equals, Everything, Nothing,
},
};
use frame_system::EnsureRoot;
use pallet_collator_selection::StakingPotAccountId;
use pallet_xcm::XcmPassthrough;
use parachains_common::{
xcm_config::{
AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains,
RelayOrOtherSystemParachains,
AllSiblingSystemParachains, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains,
},
TREASURY_PALLET_ID,
};
use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_parachain_primitives::primitives::{IsSystem, Sibling};
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use sp_core::Get;
use sp_runtime::traits::AccountIdConversion;
Expand Down Expand Up @@ -167,9 +169,29 @@ pub type WaivedLocations = (
Equals<RelayTreasuryLocation>,
);

pub struct ConcreteAssetFromUserOriginOfSystemChain<AssetLocation>(PhantomData<AssetLocation>);
impl<AssetLocation: Get<Location>> ContainsPair<Asset, Location>
for ConcreteAssetFromUserOriginOfSystemChain<AssetLocation>
{
fn contains(asset: &Asset, origin: &Location) -> bool {
log::trace!(target: "xcm::contains", "ConcreteAssetFromSystem asset: {:?}, origin: {:?}", asset, origin);
let is_system = match origin.unpack() {
// The Relay Chain
(1, []) => true,
// System parachain
(1, [Parachain(id)]) => ParaId::from(*id).is_system(),
// User from system chain
(1, [Parachain(id), AccountId32 { .. }]) => ParaId::from(*id).is_system(),
// Others
_ => false,
};
asset.id.0 == AssetLocation::get() && is_system
}
}

/// Cases where a remote origin is accepted as trusted Teleporter for a given asset:
/// - NativeToken with the parent Relay Chain and sibling parachains.
pub type TrustedTeleporters = ConcreteAssetFromSystem<TokenLocation>;
pub type TrustedTeleporters = ConcreteAssetFromUserOriginOfSystemChain<TokenLocation>;

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
Expand Down
6 changes: 3 additions & 3 deletions polkadot/xcm/xcm-builder/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<Inner: SendXcm> SendXcm for WithUniqueTopic<Inner> {
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
_source: Option<&Location>,
source: Option<&Location>,
) -> SendResult<Self::Ticket> {
let mut message = message.take().ok_or(SendError::MissingArgument)?;
let unique_id = if let Some(SetTopic(id)) = message.last() {
Expand All @@ -52,8 +52,8 @@ impl<Inner: SendXcm> SendXcm for WithUniqueTopic<Inner> {
message.0.push(SetTopic(unique_id));
unique_id
};
let (ticket, assets, _) = Inner::validate(destination, &mut Some(message), None)?;
Ok(((ticket, unique_id), assets, None))
let (ticket, assets, burnt) = Inner::validate(destination, &mut Some(message), source)?;
Ok(((ticket, unique_id), assets, burnt))
}

fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
Expand Down
32 changes: 30 additions & 2 deletions polkadot/xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,12 @@ impl<Config: config::Config> XcmExecutor<Config> {
reason = ?reason,
"Sending msg",
);
let (ticket, fee, _) = validate_send::<Config::XcmSender>(dest, msg, self.origin_ref())?;
self.take_fee(fee, reason)?;
let (ticket, fee, fee_to_burn) =
validate_send::<Config::XcmSender>(dest, msg, self.origin_ref())?;
self.take_fee(fee, reason.clone())?;
if let Some(fee_to_burn) = fee_to_burn {
self.burn_fee(fee_to_burn, reason)?;
}
Comment on lines +390 to +395
Copy link
Author

@yrong yrong Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make validate_send return an extra fees(optional) for burning.

Config::XcmSender::deliver(ticket).map_err(Into::into)
}

Expand Down Expand Up @@ -494,6 +498,30 @@ impl<Config: config::Config> XcmExecutor<Config> {
Ok(())
}

fn burn_fee(&mut self, fee: Assets, reason: FeeReason) -> XcmResult {
if Config::FeeManager::is_waived(self.origin_ref(), reason.clone()) {
return Ok(())
}
tracing::trace!(
target: "xcm::fees",
?fee,
origin_ref = ?self.origin_ref(),
fees_mode = ?self.fees_mode,
?reason,
"Burning fees",
);
if self.fees_mode.jit_withdraw {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
for asset in fee.inner() {
Config::AssetTransactor::withdraw_asset(&asset, origin, Some(&self.context))?;
}
fee
} else {
self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into()
};
Ok(())
}

/// Calculates what `local_querier` would be from the perspective of `destination`.
fn to_querier(
local_querier: Option<Location>,
Expand Down
Loading