# 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
@@ -38,8 +38,9 @@ pub use polkadot_runtime_parachains::{
inclusion::{AggregateMessageOrigin, UmpQueueId},
};
pub use xcm::{
prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm, XcmVersion},
v3::Error,
prelude::{Location, OriginKind, Outcome, VersionedXcm, XcmVersion},
v3,
v4::Error as XcmError,
DoubleEncoded,
};
@@ -209,7 +210,7 @@ macro_rules! impl_assert_events_helpers_for_relay_chain {
Self,
vec![
[<$chain RuntimeEvent>]::<N>::XcmPallet(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete { used: weight } }
) => {
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
@@ -224,21 +225,21 @@ macro_rules! impl_assert_events_helpers_for_relay_chain {
/// Asserts a dispatchable is incompletely executed and XCM sent
pub fn assert_xcm_pallet_attempted_incomplete(
expected_weight: Option<$crate::impls::Weight>,
expected_error: Option<$crate::impls::Error>,
expected_error: Option<$crate::impls::XcmError>,
) {
$crate::impls::assert_expected_events!(
Self,
vec![
// Dispatchable is properly executed and XCM message sent
[<$chain RuntimeEvent>]::<N>::XcmPallet(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete { used: weight, error } }
) => {
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
error: *error == expected_error.unwrap_or(*error),
error: *error == expected_error.unwrap_or((*error).into()).into(),
},
]
);
@@ -365,7 +366,7 @@ macro_rules! impl_send_transact_helpers_for_relay_chain {
<Self as $crate::impls::TestExt>::execute_with(|| {
let root_origin = <Self as Chain>::RuntimeOrigin::root();
let destination: $crate::impls::MultiLocation = <Self as RelayChain>::child_location_of(recipient);
let destination: $crate::impls::Location = <Self as RelayChain>::child_location_of(recipient);
let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser);
// Send XCM `Transact`
@@ -416,13 +417,13 @@ macro_rules! impl_accounts_helpers_for_parachain {
network_id: $crate::impls::NetworkId,
para_id: $crate::impls::ParaId,
) -> $crate::impls::AccountId {
let remote_location = $crate::impls::MultiLocation {
parents: 2,
interior: $crate::impls::Junctions::X2(
let remote_location = $crate::impls::Location::new(
2,
[
$crate::impls::Junction::GlobalConsensus(network_id),
$crate::impls::Junction::Parachain(para_id.into()),
),
};
],
);
<Self as $crate::impls::TestExt>::execute_with(|| {
Self::sovereign_account_id_of(remote_location)
})
@@ -445,7 +446,7 @@ macro_rules! impl_assert_events_helpers_for_parachain {
Self,
vec![
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete(weight) }
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Complete { used: weight } }
) => {
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
@@ -460,36 +461,36 @@ macro_rules! impl_assert_events_helpers_for_parachain {
/// Asserts a dispatchable is incompletely executed and XCM sent
pub fn assert_xcm_pallet_attempted_incomplete(
expected_weight: Option<$crate::impls::Weight>,
expected_error: Option<$crate::impls::Error>,
expected_error: Option<$crate::impls::XcmError>,
) {
$crate::impls::assert_expected_events!(
Self,
vec![
// Dispatchable is properly executed and XCM message sent
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete(weight, error) }
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Incomplete { used: weight, error } }
) => {
weight: $crate::impls::weight_within_threshold(
($crate::impls::REF_TIME_THRESHOLD, $crate::impls::PROOF_SIZE_THRESHOLD),
expected_weight.unwrap_or(*weight),
*weight
),
error: *error == expected_error.unwrap_or(*error),
error: *error == expected_error.unwrap_or((*error).into()).into(),
},
]
);
}
/// Asserts a dispatchable throws and error when trying to be sent
pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::Error>) {
pub fn assert_xcm_pallet_attempted_error(expected_error: Option<$crate::impls::XcmError>) {
$crate::impls::assert_expected_events!(
Self,
vec![
// Execution fails in the origin with `Barrier`
[<$chain RuntimeEvent>]::<N>::PolkadotXcm(
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error(error) }
$crate::impls::pallet_xcm::Event::Attempted { outcome: $crate::impls::Outcome::Error { error } }
) => {
error: *error == expected_error.unwrap_or(*error),
error: *error == expected_error.unwrap_or((*error).into()).into(),
},
]
);
@@ -639,7 +640,7 @@ macro_rules! impl_assets_helpers_for_parachain {
<Self as $crate::impls::TestExt>::execute_with(|| {
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::Assets::mint(
signed_origin,
id.into(),
id.clone().into(),
beneficiary.clone().into(),
amount_to_mint
));
@@ -717,7 +718,7 @@ macro_rules! impl_assets_helpers_for_parachain {
]
);
assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.into()));
assert!(<Self as [<$chain ParaPallet>]>::Assets::asset_exists(id.clone().into()));
});
}
}
@@ -732,7 +733,7 @@ macro_rules! impl_foreign_assets_helpers_for_parachain {
impl<N: $crate::impls::Network> $chain<N> {
/// Create foreign assets using sudo `ForeignAssets::force_create()`
pub fn force_create_foreign_asset(
id: $crate::impls::MultiLocation,
id: $crate::impls::v3::Location,
owner: $crate::impls::AccountId,
is_sufficient: bool,
min_balance: u128,
@@ -744,13 +745,13 @@ macro_rules! impl_foreign_assets_helpers_for_parachain {
$crate::impls::assert_ok!(
<Self as [<$chain ParaPallet>]>::ForeignAssets::force_create(
sudo_origin,
id,
id.clone(),
owner.clone().into(),
is_sufficient,
min_balance,
)
);
assert!(<Self as [<$chain ParaPallet>]>::ForeignAssets::asset_exists(id));
assert!(<Self as [<$chain ParaPallet>]>::ForeignAssets::asset_exists(id.clone()));
type RuntimeEvent<N> = <$chain<N> as $crate::impls::Chain>::RuntimeEvent;
$crate::impls::assert_expected_events!(
Self,
@@ -767,21 +768,21 @@ macro_rules! impl_foreign_assets_helpers_for_parachain {
for (beneficiary, amount) in prefund_accounts.into_iter() {
let signed_origin =
<$chain<N> as $crate::impls::Chain>::RuntimeOrigin::signed(owner.clone());
Self::mint_foreign_asset(signed_origin, id, beneficiary, amount);
Self::mint_foreign_asset(signed_origin, id.clone(), beneficiary, amount);
}
}
/// Mint assets making use of the ForeignAssets pallet-assets instance
pub fn mint_foreign_asset(
signed_origin: <Self as $crate::impls::Chain>::RuntimeOrigin,
id: $crate::impls::MultiLocation,
id: $crate::impls::v3::Location,
beneficiary: $crate::impls::AccountId,
amount_to_mint: u128,
) {
<Self as $crate::impls::TestExt>::execute_with(|| {
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::ForeignAssets::mint(
signed_origin,
id.into(),
id.clone().into(),
beneficiary.clone().into(),
amount_to_mint
));
@@ -813,7 +814,7 @@ macro_rules! impl_xcm_helpers_for_parachain {
$crate::impls::paste::paste! {
impl<N: $crate::impls::Network> $chain<N> {
/// Set XCM version for destination.
pub fn force_xcm_version(dest: $crate::impls::MultiLocation, version: $crate::impls::XcmVersion) {
pub fn force_xcm_version(dest: $crate::impls::Location, version: $crate::impls::XcmVersion) {
<Self as $crate::impls::TestExt>::execute_with(|| {
$crate::impls::assert_ok!(<Self as [<$chain ParaPallet>]>::PolkadotXcm::force_xcm_version(
<Self as $crate::impls::Chain>::RuntimeOrigin::root(),
@@ -40,6 +40,7 @@ use polkadot_service::chain_spec::get_authority_keys_from_seed_no_beefy;
pub const XCM_V2: u32 = 2;
pub const XCM_V3: u32 = 3;
pub const XCM_V4: u32 = 4;
pub const REF_TIME_THRESHOLD: u64 = 33;
pub const PROOF_SIZE_THRESHOLD: u64 = 33;
@@ -48,7 +48,7 @@ macro_rules! test_parachain_is_trusted_teleporter {
<$receiver_para as $crate::macros::Chain>::account_data_of(receiver.clone()).free;
let para_destination =
<$sender_para>::sibling_location_of(<$receiver_para>::para_id());
let beneficiary: MultiLocation =
let beneficiary: Location =
$crate::macros::AccountId32 { network: None, id: receiver.clone().into() }.into();
// Send XCM message from Origin Parachain
@@ -57,8 +57,8 @@ macro_rules! test_parachain_is_trusted_teleporter {
<$sender_para>::execute_with(|| {
assert_ok!(<$sender_para as [<$sender_para Pallet>]>::PolkadotXcm::limited_teleport_assets(
origin.clone(),
bx!(para_destination.into()),
bx!(beneficiary.into()),
bx!(para_destination.clone().into()),
bx!(beneficiary.clone().into()),
bx!($assets.clone().into()),
fee_asset_item,
weight_limit.clone(),
@@ -127,8 +127,8 @@ macro_rules! include_penpal_create_foreign_asset_on_asset_hub {
$crate::impls::paste::paste! {
pub fn penpal_create_foreign_asset_on_asset_hub(
asset_id_on_penpal: u32,
foreign_asset_at_asset_hub: MultiLocation,
ah_as_seen_by_penpal: MultiLocation,
foreign_asset_at_asset_hub: v3::Location,
ah_as_seen_by_penpal: Location,
is_sufficient: bool,
asset_owner: AccountId,
prefund_amount: u128,
@@ -144,14 +144,14 @@ macro_rules! include_penpal_create_foreign_asset_on_asset_hub {
// prefund SA of Penpal on AssetHub with enough native tokens to pay for creating
// new foreign asset, also prefund CheckingAccount with ED, because teleported asset
// itself might not be sufficient and CheckingAccount cannot be created otherwise
let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah);
let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah.clone());
$asset_hub::fund_accounts(vec![
(sov_penpal_on_ah.clone().into(), $relay_ed * 100_000_000_000),
(ah_check_account.clone().into(), $relay_ed * 1000),
]);
// prefund SA of AssetHub on Penpal with native asset
let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal);
let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal.clone());
$penpal::fund_accounts(vec![
(sov_ah_on_penpal.into(), $relay_ed * 1_000_000_000),
(penpal_check_account.clone().into(), $relay_ed * 1000),
@@ -183,8 +183,8 @@ macro_rules! include_penpal_create_foreign_asset_on_asset_hub {
let buy_execution_fee_amount = $weight_to_fee::weight_to_fee(
&Weight::from_parts(10_100_000_000_000, 300_000),
);
let buy_execution_fee = MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
let buy_execution_fee = Asset {
id: AssetId(Location { parents: 1, interior: Here }),
fun: Fungible(buy_execution_fee_amount),
};
let xcm = VersionedXcm::from(Xcm(vec![
@@ -23,12 +23,12 @@ use xcm::{prelude::*, DoubleEncoded};
pub fn xcm_transact_paid_execution(
call: DoubleEncoded<()>,
origin_kind: OriginKind,
native_asset: MultiAsset,
native_asset: Asset,
beneficiary: AccountId,
) -> VersionedXcm<()> {
let weight_limit = WeightLimit::Unlimited;
let require_weight_at_most = Weight::from_parts(1000000000, 200000);
let native_assets: MultiAssets = native_asset.clone().into();
let native_assets: Assets = native_asset.clone().into();
VersionedXcm::from(Xcm(vec![
WithdrawAsset(native_assets),
@@ -37,9 +37,9 @@ pub fn xcm_transact_paid_execution(
RefundSurplus,
DepositAsset {
assets: All.into(),
beneficiary: MultiLocation {
beneficiary: Location {
parents: 0,
interior: X1(AccountId32 { network: None, id: beneficiary.into() }),
interior: [AccountId32 { network: None, id: beneficiary.into() }].into(),
},
},
]))
@@ -61,15 +61,11 @@ pub fn xcm_transact_unpaid_execution(
}
/// Helper method to get the non-fee asset used in multiple assets transfer
pub fn non_fee_asset(assets: &MultiAssets, fee_idx: usize) -> Option<(MultiLocation, u128)> {
pub fn non_fee_asset(assets: &Assets, fee_idx: usize) -> Option<(Location, u128)> {
let asset = assets.inner().into_iter().enumerate().find(|a| a.0 != fee_idx)?.1.clone();
let asset_id = match asset.id {
Concrete(id) => id,
_ => return None,
};
let asset_amount = match asset.fun {
Fungible(amount) => amount,
_ => return None,
};
Some((asset_id, asset_amount))
Some((asset.id.0, asset_amount))
}