# 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
@@ -76,21 +76,25 @@ use sp_std::prelude::*;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use xcm::opaque::v3::MultiLocation;
use xcm_config::{
ForeignAssetsConvertedConcreteId, PoolAssetsConvertedConcreteId,
TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, WestendLocation,
XcmOriginToTransactDispatchOrigin,
TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocationV3, WestendLocation,
WestendLocationV3, XcmOriginToTransactDispatchOrigin,
};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
use assets_common::{
foreign_creators::ForeignCreators, matching::FromSiblingParachain, MultiLocationForAssetId,
};
use assets_common::{foreign_creators::ForeignCreators, matching::FromSiblingParachain};
use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate};
use xcm::latest::prelude::*;
// We exclude `Assets` since it's the name of a pallet
use xcm::latest::prelude::AssetId;
#[cfg(feature = "runtime-benchmarks")]
use xcm::latest::prelude::{
Asset, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, NetworkId,
NonFungible, Parent, ParentThen, Response, XCM_VERSION,
};
use crate::xcm_config::ForeignCreatorsSovereignAccountOf;
use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight};
@@ -300,10 +304,11 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
Assets,
ForeignAssets,
LocalFromLeft<
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation>,
AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocationV3>,
AssetIdForTrustBackedAssets,
xcm::v3::Location,
>,
MultiLocation,
xcm::v3::Location,
AccountId,
>;
@@ -311,8 +316,8 @@ pub type LocalAndForeignAssets = fungibles::UnionOf<
pub type NativeAndAssets = fungible::UnionOf<
Balances,
LocalAndForeignAssets,
TargetFromLeft<WestendLocation>,
MultiLocation,
TargetFromLeft<WestendLocationV3, xcm::v3::Location>,
xcm::v3::Location,
AccountId,
>;
@@ -320,15 +325,15 @@ impl pallet_asset_conversion::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Balance = Balance;
type HigherPrecisionBalance = sp_core::U256;
type AssetKind = MultiLocation;
type AssetKind = xcm::v3::Location;
type Assets = NativeAndAssets;
type PoolId = (Self::AssetKind, Self::AssetKind);
type PoolLocator =
pallet_asset_conversion::WithFirstAsset<WestendLocation, AccountId, Self::AssetKind>;
pallet_asset_conversion::WithFirstAsset<WestendLocationV3, AccountId, Self::AssetKind>;
type PoolAssetId = u32;
type PoolAssets = PoolAssets;
type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam
type PoolSetupFeeAsset = WestendLocation;
type PoolSetupFeeAsset = WestendLocationV3;
type PoolSetupFeeTarget = ResolveAssetTo<AssetConversionOrigin, Self::Assets>;
type LiquidityWithdrawalFee = LiquidityWithdrawalFee;
type LPFee = ConstU32<3>;
@@ -338,9 +343,10 @@ impl pallet_asset_conversion::Config for Runtime {
type WeightInfo = weights::pallet_asset_conversion::WeightInfo<Runtime>;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory<
WestendLocation,
WestendLocationV3,
parachain_info::Pallet<Runtime>,
xcm_config::AssetsPalletIndex,
xcm_config::TrustBackedAssetsPalletIndex,
xcm::v3::Location,
>;
}
@@ -362,13 +368,14 @@ pub type ForeignAssetsInstance = pallet_assets::Instance2;
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type Balance = Balance;
type AssetId = MultiLocationForAssetId;
type AssetIdParameter = MultiLocationForAssetId;
type AssetId = xcm::v3::Location;
type AssetIdParameter = xcm::v3::Location;
type Currency = Balances;
type CreateOrigin = ForeignCreators<
(FromSiblingParachain<parachain_info::Pallet<Runtime>>,),
FromSiblingParachain<parachain_info::Pallet<Runtime>, xcm::v3::Location>,
ForeignCreatorsSovereignAccountOf,
AccountId,
xcm::v3::Location,
>;
type ForceOrigin = AssetsForceOrigin;
type AssetDeposit = ForeignAssetsAssetDeposit;
@@ -644,7 +651,7 @@ impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = Concrete(xcm_config::WestendLocation::get());
pub FeeAssetId: AssetId = AssetId(xcm_config::WestendLocation::get());
/// The base fee for the message delivery fees.
pub const BaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
@@ -728,7 +735,7 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Fungibles = LocalAndForeignAssets;
type OnChargeAssetTransaction =
AssetConversionAdapter<Balances, AssetConversion, WestendLocation>;
AssetConversionAdapter<Balances, AssetConversion, WestendLocationV3>;
}
parameter_types! {
@@ -1229,18 +1236,18 @@ impl_runtime_apis! {
impl pallet_asset_conversion::AssetConversionApi<
Block,
Balance,
MultiLocation,
xcm::v3::Location,
> for Runtime
{
fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option<Balance> {
fn quote_price_exact_tokens_for_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee)
}
fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option<Balance> {
fn quote_price_tokens_for_exact_tokens(asset1: xcm::v3::Location, asset2: xcm::v3::Location, amount: Balance, include_fee: bool) -> Option<Balance> {
AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee)
}
fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> {
fn get_reserves(asset1: xcm::v3::Location, asset2: xcm::v3::Location) -> Option<(Balance, Balance)> {
AssetConversion::get_reserves(asset1, asset2).ok()
}
}
@@ -1294,7 +1301,7 @@ impl_runtime_apis! {
AccountId,
> for Runtime
{
fn query_account_balances(account: AccountId) -> Result<xcm::VersionedMultiAssets, assets_common::runtime_api::FungiblesAccessError> {
fn query_account_balances(account: AccountId) -> Result<xcm::VersionedAssets, assets_common::runtime_api::FungiblesAccessError> {
use assets_common::fungible_conversion::{convert, convert_balance};
Ok([
// collect pallet_balance
@@ -1413,45 +1420,45 @@ impl_runtime_apis! {
use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
impl pallet_xcm::benchmarking::Config for Runtime {
fn reachable_dest() -> Option<MultiLocation> {
fn reachable_dest() -> Option<Location> {
Some(Parent.into())
}
fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
// Relay/native token can be teleported between AH and Relay.
Some((
MultiAsset {
Asset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
id: AssetId(Parent.into())
},
Parent.into(),
))
}
fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> {
fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
// AH can reserve transfer native token to some random parachain.
let random_para_id = 43211234;
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
random_para_id.into()
);
Some((
MultiAsset {
Asset {
fun: Fungible(EXISTENTIAL_DEPOSIT),
id: Concrete(Parent.into())
id: AssetId(Parent.into())
},
ParentThen(Parachain(random_para_id).into()).into(),
))
}
fn set_up_complex_asset_transfer(
) -> Option<(MultiAssets, u32, MultiLocation, Box<dyn FnOnce()>)> {
) -> Option<(xcm::v4::Assets, u32, Location, Box<dyn FnOnce()>)> {
// Transfer to Relay some local AH asset (local-reserve-transfer) while paying
// fees using teleported native token.
// (We don't care that Relay doesn't accept incoming unknown AH local asset)
let dest = Parent.into();
let fee_amount = EXISTENTIAL_DEPOSIT;
let fee_asset: MultiAsset = (MultiLocation::parent(), fee_amount).into();
let fee_asset: Asset = (Location::parent(), fee_amount).into();
let who = frame_benchmarking::whitelisted_caller();
// Give some multiple of the existential deposit
@@ -1469,13 +1476,13 @@ impl_runtime_apis! {
Runtime,
pallet_assets::Instance1
>(true, initial_asset_amount);
let asset_location = MultiLocation::new(
let asset_location = Location::new(
0,
X2(PalletInstance(50), GeneralIndex(u32::from(asset_id).into()))
[PalletInstance(50), GeneralIndex(u32::from(asset_id).into())]
);
let transfer_asset: MultiAsset = (asset_location, asset_amount).into();
let transfer_asset: Asset = (asset_location, asset_amount).into();
let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset].into();
let assets: xcm::v4::Assets = vec![fee_asset.clone(), transfer_asset].into();
let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 };
// verify transferred successfully
@@ -1504,14 +1511,14 @@ impl_runtime_apis! {
xcm_config::bridging::SiblingBridgeHubParaId::get().into()
);
}
fn ensure_bridged_target_destination() -> Result<MultiLocation, BenchmarkError> {
fn ensure_bridged_target_destination() -> Result<Location, BenchmarkError> {
ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
xcm_config::bridging::SiblingBridgeHubParaId::get().into()
);
let bridged_asset_hub = xcm_config::bridging::to_rococo::AssetHubRococo::get();
let _ = PolkadotXcm::force_xcm_version(
RuntimeOrigin::root(),
Box::new(bridged_asset_hub),
Box::new(bridged_asset_hub.clone()),
XCM_VERSION,
).map_err(|e| {
log::error!(
@@ -1527,12 +1534,11 @@ impl_runtime_apis! {
}
}
use xcm::latest::prelude::*;
use xcm_config::{MaxAssetsIntoHolding, WestendLocation};
use pallet_xcm_benchmarks::asset_instance_from;
parameter_types! {
pub ExistentialDepositMultiAsset: Option<MultiAsset> = Some((
pub ExistentialDepositAsset: Option<Asset> = Some((
WestendLocation::get(),
ExistentialDeposit::get()
).into());
@@ -1543,33 +1549,33 @@ impl_runtime_apis! {
type AccountIdConverter = xcm_config::LocationToAccountId;
type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
xcm_config::XcmConfig,
ExistentialDepositMultiAsset,
ExistentialDepositAsset,
xcm_config::PriceForParentDelivery,
>;
fn valid_destination() -> Result<MultiLocation, BenchmarkError> {
fn valid_destination() -> Result<Location, BenchmarkError> {
Ok(WestendLocation::get())
}
fn worst_case_holding(depositable_count: u32) -> MultiAssets {
fn worst_case_holding(depositable_count: u32) -> xcm::v4::Assets {
// A mix of fungible, non-fungible, and concrete assets.
let holding_non_fungibles = MaxAssetsIntoHolding::get() / 2 - depositable_count;
let holding_fungibles = holding_non_fungibles - 1;
let fungibles_amount: u128 = 100;
let mut assets = (0..holding_fungibles)
.map(|i| {
MultiAsset {
id: Concrete(GeneralIndex(i as u128).into()),
Asset {
id: AssetId(GeneralIndex(i as u128).into()),
fun: Fungible(fungibles_amount * i as u128),
}
})
.chain(core::iter::once(MultiAsset { id: Concrete(Here.into()), fun: Fungible(u128::MAX) }))
.chain((0..holding_non_fungibles).map(|i| MultiAsset {
id: Concrete(GeneralIndex(i as u128).into()),
.chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) }))
.chain((0..holding_non_fungibles).map(|i| Asset {
id: AssetId(GeneralIndex(i as u128).into()),
fun: NonFungible(asset_instance_from(i)),
}))
.collect::<Vec<_>>();
assets.push(MultiAsset {
id: Concrete(WestendLocation::get()),
assets.push(Asset {
id: AssetId(WestendLocation::get()),
fun: Fungible(1_000_000 * UNITS),
});
assets.into()
@@ -1577,16 +1583,16 @@ impl_runtime_apis! {
}
parameter_types! {
pub const TrustedTeleporter: Option<(MultiLocation, MultiAsset)> = Some((
pub const TrustedTeleporter: Option<(Location, Asset)> = Some((
WestendLocation::get(),
MultiAsset { fun: Fungible(UNITS), id: Concrete(WestendLocation::get()) },
Asset { fun: Fungible(UNITS), id: AssetId(WestendLocation::get()) },
));
pub const CheckedAccount: Option<(AccountId, xcm_builder::MintLocation)> = None;
// AssetHubWestend trusts AssetHubRococo as reserve for ROCs
pub TrustedReserve: Option<(MultiLocation, MultiAsset)> = Some(
pub TrustedReserve: Option<(Location, Asset)> = Some(
(
xcm_config::bridging::to_rococo::AssetHubRococo::get(),
MultiAsset::from((xcm_config::bridging::to_rococo::RocLocation::get(), 1000000000000 as u128))
Asset::from((xcm_config::bridging::to_rococo::RocLocation::get(), 1000000000000 as u128))
)
);
}
@@ -1598,9 +1604,9 @@ impl_runtime_apis! {
type TrustedTeleporter = TrustedTeleporter;
type TrustedReserve = TrustedReserve;
fn get_multi_asset() -> MultiAsset {
MultiAsset {
id: Concrete(WestendLocation::get()),
fn get_asset() -> Asset {
Asset {
id: AssetId(WestendLocation::get()),
fun: Fungible(UNITS),
}
}
@@ -1614,42 +1620,42 @@ impl_runtime_apis! {
(0u64, Response::Version(Default::default()))
}
fn worst_case_asset_exchange() -> Result<(MultiAssets, MultiAssets), BenchmarkError> {
fn worst_case_asset_exchange() -> Result<(xcm::v4::Assets, xcm::v4::Assets), BenchmarkError> {
Err(BenchmarkError::Skip)
}
fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> {
fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
match xcm_config::bridging::BridgingBenchmarksHelper::prepare_universal_alias() {
Some(alias) => Ok(alias),
None => Err(BenchmarkError::Skip)
}
}
fn transact_origin_and_runtime_call() -> Result<(MultiLocation, RuntimeCall), BenchmarkError> {
fn transact_origin_and_runtime_call() -> Result<(Location, RuntimeCall), BenchmarkError> {
Ok((WestendLocation::get(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
}
fn subscribe_origin() -> Result<MultiLocation, BenchmarkError> {
fn subscribe_origin() -> Result<Location, BenchmarkError> {
Ok(WestendLocation::get())
}
fn claimable_asset() -> Result<(MultiLocation, MultiLocation, MultiAssets), BenchmarkError> {
fn claimable_asset() -> Result<(Location, Location, xcm::v4::Assets), BenchmarkError> {
let origin = WestendLocation::get();
let assets: MultiAssets = (Concrete(WestendLocation::get()), 1_000 * UNITS).into();
let ticket = MultiLocation { parents: 0, interior: Here };
let assets: xcm::v4::Assets = (AssetId(WestendLocation::get()), 1_000 * UNITS).into();
let ticket = Location { parents: 0, interior: Here };
Ok((origin, ticket, assets))
}
fn unlockable_asset() -> Result<(MultiLocation, MultiLocation, MultiAsset), BenchmarkError> {
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
fn export_message_origin_and_destination(
) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> {
) -> Result<(Location, NetworkId, InteriorLocation), BenchmarkError> {
Err(BenchmarkError::Skip)
}
fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> {
fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
Err(BenchmarkError::Skip)
}
}