# Note for reviewer

Most changes are just syntax changes necessary for the new version.
Most important files should be the ones under the `xcm` folder.

# Description 

Added XCMv4.

## Removed `Multi` prefix
The following types have been renamed:
- MultiLocation -> Location
- MultiAsset -> Asset
- MultiAssets -> Assets
- InteriorMultiLocation -> InteriorLocation
- MultiAssetFilter -> AssetFilter
- VersionedMultiAsset -> VersionedAsset
- WildMultiAsset -> WildAsset
- VersionedMultiLocation -> VersionedLocation

In order to fix a name conflict, the `Assets` in `xcm-executor` were
renamed to `HoldingAssets`, as they represent assets in holding.

## Removed `Abstract` asset id

It was not being used anywhere and this simplifies the code.

Now assets are just constructed as follows:

```rust
let asset: Asset = (AssetId(Location::new(1, Here)), 100u128).into();
```

No need for specifying `Concrete` anymore.

## Outcome is now a named fields struct

Instead of

```rust
pub enum Outcome {
  Complete(Weight),
  Incomplete(Weight, Error),
  Error(Error),
}
```

we now have

```rust
pub enum Outcome {
  Complete { used: Weight },
  Incomplete { used: Weight, error: Error },
  Error { error: Error },
}
```

## Added Reanchorable trait

Now both locations and assets implement this trait, making it easier to
reanchor both.

## New syntax for building locations and junctions

Now junctions are built using the following methods:

```rust
let location = Location {
    parents: 1,
    interior: [Parachain(1000), PalletInstance(50), GeneralIndex(1984)].into()
};
```

or

```rust
let location = Location::new(1, [Parachain(1000), PalletInstance(50), GeneralIndex(1984)]);
```

And they are matched like so:

```rust
match location.unpack() {
  (1, [Parachain(id)]) => ...
  (0, Here) => ...,
  (1, [_]) => ...,
}
```

This syntax is mandatory in v4, and has been also implemented for v2 and
v3 for easier migration.

This was needed to make all sizes smaller.

# TODO
- [x] Scaffold v4
- [x] Port github.com/paritytech/polkadot/pull/7236
- [x] Remove `Multi` prefix
- [x] Remove `Abstract` asset id

---------

Co-authored-by: command-bot <>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Francisco Aguirre
2024-01-16 19:18:04 +01:00
committed by GitHub
parent ec7bfae00a
commit 8428f678fe
255 changed files with 12425 additions and 6726 deletions
@@ -22,7 +22,7 @@ pub use xcm::{
latest::ParentThen,
prelude::{AccountId32 as AccountId32Junction, *},
v3::{
Error,
self, Error,
NetworkId::{Rococo as RococoId, Westend as WestendId},
},
};
@@ -15,14 +15,14 @@
use crate::tests::*;
fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: MultiLocation, amount: u128) {
fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: Location, amount: u128) {
let destination = asset_hub_westend_location();
// fund the AHR's SA on BHR for paying bridge transport fees
BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128);
// set XCM versions
AssetHubRococo::force_xcm_version(destination, XCM_VERSION);
AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION);
BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION);
// send message over bridge
@@ -33,9 +33,9 @@ fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: MultiLocation, amou
#[test]
fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
let roc_at_asset_hub_rococo: MultiLocation = Parent.into();
let roc_at_asset_hub_rococo: v3::Location = v3::Parent.into();
let roc_at_asset_hub_westend =
MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Rococo)) };
v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Rococo)]);
let owner: AccountId = AssetHubWestend::account_id_of(ALICE);
AssetHubWestend::force_create_foreign_asset(
roc_at_asset_hub_westend,
@@ -62,7 +62,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::create_pool(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
Box::new(Parent.into()),
Box::new(xcm::v3::Parent.into()),
Box::new(roc_at_asset_hub_westend),
));
@@ -75,7 +75,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
assert_ok!(<AssetHubWestend as AssetHubWestendPallet>::AssetConversion::add_liquidity(
<AssetHubWestend as Chain>::RuntimeOrigin::signed(AssetHubWestendSender::get()),
Box::new(Parent.into()),
Box::new(xcm::v3::Parent.into()),
Box::new(roc_at_asset_hub_westend),
1_000_000_000_000,
2_000_000_000_000,
@@ -101,8 +101,9 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
<Assets as Inspect<_>>::balance(roc_at_asset_hub_westend, &AssetHubWestendReceiver::get())
});
let roc_at_asset_hub_rococo_latest: Location = roc_at_asset_hub_rococo.try_into().unwrap();
let amount = ASSET_HUB_ROCOCO_ED * 1_000_000;
send_asset_from_asset_hub_rococo_to_asset_hub_westend(roc_at_asset_hub_rococo, amount);
send_asset_from_asset_hub_rococo_to_asset_hub_westend(roc_at_asset_hub_rococo_latest, amount);
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
assert_expected_events!(
@@ -142,7 +143,7 @@ fn send_rocs_from_asset_hub_rococo_to_asset_hub_westend() {
fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() {
let prefund_amount = 10_000_000_000_000u128;
let wnd_at_asset_hub_rococo =
MultiLocation { parents: 2, interior: X1(GlobalConsensus(NetworkId::Westend)) };
v3::Location::new(2, [v3::Junction::GlobalConsensus(v3::NetworkId::Westend)]);
let owner: AccountId = AssetHubWestend::account_id_of(ALICE);
AssetHubRococo::force_create_foreign_asset(
wnd_at_asset_hub_rococo,
@@ -170,8 +171,12 @@ fn send_wnds_from_asset_hub_rococo_to_asset_hub_westend() {
let receiver_wnds_before =
<AssetHubWestend as Chain>::account_data_of(AssetHubWestendReceiver::get()).free;
let wnd_at_asset_hub_rococo_latest: Location = wnd_at_asset_hub_rococo.try_into().unwrap();
let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000;
send_asset_from_asset_hub_rococo_to_asset_hub_westend(wnd_at_asset_hub_rococo, amount_to_send);
send_asset_from_asset_hub_rococo_to_asset_hub_westend(
wnd_at_asset_hub_rococo_latest.clone(),
amount_to_send,
);
AssetHubWestend::execute_with(|| {
type RuntimeEvent = <AssetHubWestend as Chain>::RuntimeEvent;
assert_expected_events!(
@@ -20,37 +20,31 @@ mod send_xcm;
mod snowbridge;
mod teleport;
pub(crate) fn asset_hub_westend_location() -> MultiLocation {
MultiLocation {
parents: 2,
interior: X2(
GlobalConsensus(NetworkId::Westend),
Parachain(AssetHubWestend::para_id().into()),
),
}
pub(crate) fn asset_hub_westend_location() -> Location {
Location::new(
2,
[GlobalConsensus(NetworkId::Westend), Parachain(AssetHubWestend::para_id().into())],
)
}
pub(crate) fn bridge_hub_westend_location() -> MultiLocation {
MultiLocation {
parents: 2,
interior: X2(
GlobalConsensus(NetworkId::Westend),
Parachain(BridgeHubWestend::para_id().into()),
),
}
pub(crate) fn bridge_hub_westend_location() -> Location {
Location::new(
2,
[GlobalConsensus(NetworkId::Westend), Parachain(BridgeHubWestend::para_id().into())],
)
}
pub(crate) fn send_asset_from_asset_hub_rococo(
destination: MultiLocation,
(id, amount): (MultiLocation, u128),
destination: Location,
(id, amount): (Location, u128),
) -> DispatchResult {
let signed_origin =
<AssetHubRococo as Chain>::RuntimeOrigin::signed(AssetHubRococoSender::get().into());
let beneficiary: MultiLocation =
let beneficiary: Location =
AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into();
let assets: MultiAssets = (id, amount).into();
let assets: Assets = (id, amount).into();
let fee_asset_item = 0;
AssetHubRococo::execute_with(|| {
@@ -29,8 +29,8 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable
let xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit, check_origin },
ExportMessage {
network: WestendId,
destination: X1(Parachain(AssetHubWestend::para_id().into())),
network: WestendId.into(),
destination: [Parachain(AssetHubWestend::para_id().into())].into(),
xcm: remote_xcm,
},
]));
@@ -68,7 +68,7 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
// prepare data
let destination = asset_hub_westend_location();
let native_token = MultiLocation::parent();
let native_token = Location::parent();
let amount = ASSET_HUB_ROCOCO_ED * 1_000;
// fund the AHR's SA on BHR for paying bridge transport fees
@@ -78,7 +78,7 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
// send XCM from AssetHubRococo - fails - destination version not known
assert_err!(
send_asset_from_asset_hub_rococo(destination, (native_token, amount)),
send_asset_from_asset_hub_rococo(destination.clone(), (native_token.clone(), amount)),
DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [1, 0, 0, 0],
@@ -87,7 +87,7 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
);
// set destination version
AssetHubRococo::force_xcm_version(destination, xcm::v3::prelude::XCM_VERSION);
AssetHubRococo::force_xcm_version(destination.clone(), xcm::v3::prelude::XCM_VERSION);
// TODO: remove this block, when removing `xcm:v2`
{
@@ -95,7 +95,7 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
// version, which does not have the `ExportMessage` instruction. If the default `2` is
// changed to `3`, then this assert can go away"
assert_err!(
send_asset_from_asset_hub_rococo(destination, (native_token, amount)),
send_asset_from_asset_hub_rococo(destination.clone(), (native_token.clone(), amount)),
DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [1, 0, 0, 0],
@@ -110,7 +110,7 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
);
// send XCM from AssetHubRococo - fails - `ExportMessage` is not in `2`
assert_err!(
send_asset_from_asset_hub_rococo(destination, (native_token, amount)),
send_asset_from_asset_hub_rococo(destination.clone(), (native_token.clone(), amount)),
DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [1, 0, 0, 0],
@@ -125,7 +125,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
xcm::v3::prelude::XCM_VERSION,
);
// send XCM from AssetHubRococo - ok
assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount)));
assert_ok!(send_asset_from_asset_hub_rococo(
destination.clone(),
(native_token.clone(), amount)
));
// `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known
assert_bridge_hub_rococo_message_accepted(false);
@@ -142,7 +145,10 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() {
);
// send XCM from AssetHubRococo - ok
assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount)));
assert_ok!(send_asset_from_asset_hub_rococo(
destination.clone(),
(native_token.clone(), amount)
));
assert_bridge_hub_rococo_message_accepted(true);
assert_bridge_hub_westend_message_received();
// message delivered and processed at destination
@@ -61,7 +61,7 @@ fn create_agent() {
let remote_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(X1(Parachain(origin_para))),
DescendOrigin(Parachain(origin_para).into()),
Transact {
require_weight_at_most: 3000000000.into(),
origin_kind: OriginKind::Xcm,
@@ -109,14 +109,14 @@ fn create_channel() {
BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND);
let sudo_origin = <Rococo as Chain>::RuntimeOrigin::root();
let destination: VersionedMultiLocation =
let destination: VersionedLocation =
Rococo::child_location_of(BridgeHubRococo::para_id()).into();
let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {});
let create_agent_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(X1(Parachain(origin_para))),
DescendOrigin(Parachain(origin_para).into()),
Transact {
require_weight_at_most: 3000000000.into(),
origin_kind: OriginKind::Xcm,
@@ -129,7 +129,7 @@ fn create_channel() {
let create_channel_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(X1(Parachain(origin_para))),
DescendOrigin(Parachain(origin_para).into()),
Transact {
require_weight_at_most: 3000000000.into(),
origin_kind: OriginKind::Xcm,
@@ -218,10 +218,10 @@ fn register_weth_token_from_ethereum_to_asset_hub() {
#[test]
fn send_token_from_ethereum_to_penpal() {
let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(MultiLocation {
parents: 1,
interior: X1(Parachain(AssetHubRococo::para_id().into())),
});
let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new(
1,
[Parachain(AssetHubRococo::para_id().into())],
));
BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]);
PenpalA::fund_accounts(vec![
@@ -229,9 +229,9 @@ fn send_token_from_ethereum_to_penpal() {
(PenpalASender::get(), INITIAL_FUND),
]);
let weth_asset_location: MultiLocation =
let weth_asset_location: Location =
(Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }).into();
let weth_asset_id = weth_asset_location.into();
let weth_asset_id: v3::Location = weth_asset_location.try_into().unwrap();
let origin_location = (Parent, Parent, EthereumNetwork::get()).into();
@@ -375,18 +375,15 @@ fn send_token_from_ethereum_to_asset_hub() {
#[test]
fn send_weth_asset_from_asset_hub_to_ethereum() {
use asset_hub_rococo_runtime::xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee;
let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(MultiLocation {
parents: 1,
interior: X1(Parachain(AssetHubRococo::para_id().into())),
});
let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new(
1,
[Parachain(AssetHubRococo::para_id().into())],
));
AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION));
BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION));
AssetHubRococo::force_xcm_version(
MultiLocation {
parents: 2,
interior: X1(GlobalConsensus(Ethereum { chain_id: CHAIN_ID })),
},
Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]),
XCM_VERSION,
);
@@ -437,27 +434,27 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {},
]
);
let assets = vec![MultiAsset {
id: Concrete(MultiLocation {
parents: 2,
interior: X2(
let assets = vec![Asset {
id: AssetId(Location::new(
2,
[
GlobalConsensus(Ethereum { chain_id: CHAIN_ID }),
AccountKey20 { network: None, key: WETH },
),
}),
],
)),
fun: Fungible(WETH_AMOUNT),
}];
let multi_assets = VersionedMultiAssets::V3(MultiAssets::from(assets));
let multi_assets = VersionedAssets::V4(Assets::from(assets));
let destination = VersionedMultiLocation::V3(MultiLocation {
parents: 2,
interior: X1(GlobalConsensus(Ethereum { chain_id: CHAIN_ID })),
});
let destination = VersionedLocation::V4(Location::new(
2,
[GlobalConsensus(Ethereum { chain_id: CHAIN_ID })],
));
let beneficiary = VersionedMultiLocation::V3(MultiLocation {
parents: 0,
interior: X1(AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }),
});
let beneficiary = VersionedLocation::V4(Location::new(
0,
[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
));
let free_balance_before = <AssetHubRococo as AssetHubRococoPallet>::Balances::free_balance(
AssetHubRococoReceiver::get(),
@@ -19,7 +19,7 @@ use bridge_hub_rococo_runtime::xcm_config::XcmConfig;
#[test]
fn teleport_to_other_system_parachains_works() {
let amount = BRIDGE_HUB_ROCOCO_ED * 100;
let native_asset: MultiAssets = (Parent, amount).into();
let native_asset: Assets = (Parent, amount).into();
test_parachain_is_trusted_teleporter!(
BridgeHubRococo, // Origin