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

Commit

Permalink
Add a custom SovereignReceiveTeleportRemoteExporter
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Jul 30, 2024
1 parent 93f952e commit 88c31b1
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,6 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
use ahr_xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee;
let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id());
let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location);
let bridgehub_location = AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id());

AssetHubRococo::force_xcm_version(
Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]),
Expand All @@ -388,9 +387,8 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {

const WETH_AMOUNT: u128 = 1_000_000_000;
const FEE_AMOUNT: u128 = 2_750_872_500_000;
const TELEPORT_FEE_AMOUNT: u128 = 12_000_000;
// To cover the delivery cost on BH and
const LOCAL_FEE_AMOUNT: u128 = DefaultBridgeHubEthereumBaseFee::get() + TELEPORT_FEE_AMOUNT;
const LOCAL_FEE_AMOUNT: u128 = DefaultBridgeHubEthereumBaseFee::get();
// To cover the delivery cost on Ethereum
const REMOTE_FEE_AMOUNT: u128 = FEE_AMOUNT - LOCAL_FEE_AMOUNT;

Expand Down Expand Up @@ -450,23 +448,10 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
DepositAsset { assets: Wild(AllCounted(2)), beneficiary },
]);

let teleport_xcm_on_bh = Xcm(vec![
BuyExecution { fees: local_fee_asset.clone(), weight_limit: Unlimited },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary:
(AccountId32 { id: assethub_sovereign.clone().into(), network: None },).into(),
},
]);

let xcms = VersionedXcm::from(Xcm(vec![
WithdrawAsset(assets.clone().into()),
BurnAsset(local_fee_asset.clone().into()),
SetFeesMode { jit_withdraw: true },
InitiateTeleport {
assets: Definite(vec![local_fee_asset.clone()].into()),
xcm: teleport_xcm_on_bh,
dest: bridgehub_location,
},
InitiateReserveWithdraw {
assets: Definite(vec![remote_fee_asset.clone(), weth_asset.clone()].into()),
// with reserve set to Ethereum destination, the ExportMessage will
Expand Down Expand Up @@ -511,7 +496,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, 3613334);
assert_eq!(free_balance_of_sovereign_on_bh_after, 15590000);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ sp-block-builder = { workspace = true }
sp-consensus-aura = { workspace = true }
sp-core = { workspace = true }
sp-inherents = { workspace = true }
sp-io = { workspace = true }
sp-genesis-builder = { workspace = true }
sp-offchain = { workspace = true }
sp-runtime = { workspace = true }
sp-session = { workspace = true }
sp-std = { workspace = true }
sp-storage = { workspace = true }
sp-transaction-pool = { workspace = true }
sp-version = { workspace = true }
Expand Down Expand Up @@ -237,9 +239,11 @@ std = [
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
"sp-io/std",
"sp-offchain/std",
"sp-runtime/std",
"sp-session/std",
"sp-std/std",
"sp-storage/std",
"sp-transaction-pool/std",
"sp-version/std",
Expand Down
125 changes: 111 additions & 14 deletions cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ use super::{
ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee,
XcmpQueue,
};
use crate::{vec, Vec};
use assets_common::{
matching::{FromNetwork, FromSiblingParachain, IsForeignConcreteAsset},
TrustBackedAssetsAsLocation,
};
use codec::Encode;
use frame_support::{
parameter_types,
traits::{
tokens::imbalance::{ResolveAssetTo, ResolveTo},
ConstU32, Contains, Equals, Everything, Nothing, PalletInfoAccess,
ConstU32, Contains, Equals, Everything, Get, Nothing, PalletInfoAccess,
},
};
use frame_system::EnsureRoot;
Expand All @@ -44,22 +46,27 @@ use polkadot_parachain_primitives::primitives::Sibling;
use polkadot_runtime_common::xcm_sender::ExponentialPrice;
use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor;
use sp_runtime::traits::{AccountIdConversion, ConvertInto};
use sp_std::marker::PhantomData;
use testnet_parachains_constants::rococo::snowbridge::{
EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX,
};
use xcm::latest::prelude::*;
use xcm::{
latest::prelude::*,
prelude::SendError::{MissingArgument, NotApplicable, Unroutable},
VersionedLocation, VersionedXcm,
};
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain,
AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily,
EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter,
GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint,
NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents,
ensure_is_remote, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom,
AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry,
DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, ExporterFor, FrameTransactionalProcessor,
FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription,
InspectMessageQueues, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking,
NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith,
StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
};
use xcm_executor::XcmExecutor;

Expand Down Expand Up @@ -443,6 +450,92 @@ type LocalXcmRouter = (
XcmpQueue,
);

pub struct SovereignReceiveTeleportRemoteExporter<Bridges, Router, UniversalLocation>(
PhantomData<(Bridges, Router, UniversalLocation)>,
);
impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
for SovereignReceiveTeleportRemoteExporter<Bridges, Router, UniversalLocation>
{
type Ticket = Router::Ticket;

fn validate(
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<Router::Ticket> {
let d = dest.as_ref().ok_or(MissingArgument)?;
let devolved =
ensure_is_remote(UniversalLocation::get(), d.clone()).map_err(|_| NotApplicable)?;
let (remote_network, remote_location) = devolved;
let xcm = msg.take().ok_or(MissingArgument)?;

// find exporter
let Some((bridge, maybe_payment)) =
Bridges::exporter_for(&remote_network, &remote_location, &xcm)
else {
// We need to make sure that msg is not consumed in case of `NotApplicable`.
*msg = Some(xcm);
return Err(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() {
Some(SetTopic(t)) =>
Some((b"forward_id_for", t).using_encoded(sp_io::hashing::blake2_256)),
_ => None,
};

let local_from_bridge =
UniversalLocation::get().invert_target(&bridge).map_err(|_| Unroutable)?;
let export_instruction =
ExportMessage { network: remote_network, destination: remote_location, xcm };

let mut message = Xcm(if let Some(ref payment) = maybe_payment {
let fees = payment
.clone()
.reanchored(&bridge, &UniversalLocation::get())
.map_err(|_| Unroutable)?;
vec![
ReceiveTeleportedAsset(fees.clone().into()),
BuyExecution { fees, weight_limit: Unlimited },
// `SetAppendix` ensures that `fees` are not trapped in any case, for example, when
// `ExportXcm::validate` encounters an error during the processing of
// `ExportMessage`.
SetAppendix(Xcm(vec![DepositAsset {
assets: AllCounted(1).into(),
beneficiary: local_from_bridge,
}])),
export_instruction,
]
} else {
vec![export_instruction]
});
if let Some(forward_id) = maybe_forward_id {
message.0.push(SetTopic(forward_id));
}

// 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)?;
if let Some(bridge_payment) = maybe_payment {
cost.push(bridge_payment);
}
Ok((v, cost))
}

fn deliver(ticket: Router::Ticket) -> Result<XcmHash, SendError> {
Router::deliver(ticket)
}
}

impl<Bridges, Router: InspectMessageQueues, UniversalLocation> InspectMessageQueues
for SovereignReceiveTeleportRemoteExporter<Bridges, Router, UniversalLocation>
{
fn get_messages() -> Vec<(VersionedLocation, Vec<VersionedXcm<()>>)> {
Router::get_messages()
}
}

/// The means for routing XCM messages which are not for local execution into the right message
/// queues.
pub type XcmRouter = WithUniqueTopic<(
Expand All @@ -452,7 +545,11 @@ pub type XcmRouter = WithUniqueTopic<(
ToWestendXcmRouter,
// Router which wraps and sends xcm to BridgeHub to be delivered to the Ethereum
// GlobalConsensus
SovereignPaidRemoteExporter<bridging::EthereumNetworkExportTable, XcmpQueue, UniversalLocation>,
SovereignReceiveTeleportRemoteExporter<
bridging::EthereumNetworkExportTable,
XcmpQueue,
UniversalLocation,
>,
)>;

impl pallet_xcm::Config for Runtime {
Expand Down

0 comments on commit 88c31b1

Please sign in to comment.