# 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
@@ -46,43 +46,38 @@ impl<Balance, AccountId, FeeAssetLocation, EthereumNetwork, AssetTransactor, Fee
> where
Balance: BaseArithmetic + Unsigned + Copy + From<u128> + Into<u128>,
AccountId: Clone + Into<[u8; 32]> + From<[u8; 32]>,
FeeAssetLocation: Get<MultiLocation>,
FeeAssetLocation: Get<Location>,
EthereumNetwork: Get<NetworkId>,
AssetTransactor: TransactAsset,
FeeProvider: SendMessageFeeProvider<Balance = Balance>,
{
fn handle_fee(
fees: MultiAssets,
context: Option<&XcmContext>,
reason: FeeReason,
) -> MultiAssets {
fn handle_fee(fees: Assets, context: Option<&XcmContext>, reason: FeeReason) -> Assets {
let token_location = FeeAssetLocation::get();
// Check the reason to see if this export is for snowbridge.
if !matches!(
reason,
FeeReason::Export { network: bridged_network, destination }
if bridged_network == EthereumNetwork::get() && destination == Here
FeeReason::Export { network: bridged_network, ref destination }
if bridged_network == EthereumNetwork::get() && destination == &Here
) {
return fees
}
// Get the parachain sovereign from the `context`.
let para_sovereign = if let Some(XcmContext {
origin: Some(MultiLocation { parents: 1, interior }),
..
}) = context
{
if let Some(Parachain(sibling_para_id)) = interior.first() {
let account: AccountId =
sibling_sovereign_account_raw((*sibling_para_id).into()).into();
account
let para_sovereign =
if let Some(XcmContext { origin: Some(Location { parents: 1, interior }), .. }) =
context
{
if let Some(Parachain(sibling_para_id)) = interior.first() {
let account: AccountId =
sibling_sovereign_account_raw((*sibling_para_id).into()).into();
account
} else {
return fees
}
} else {
return fees
}
} else {
return fees
};
};
// Get the total fee offered by export message.
let maybe_total_supplied_fee: Option<(usize, Balance)> = fees
@@ -90,8 +85,8 @@ impl<Balance, AccountId, FeeAssetLocation, EthereumNetwork, AssetTransactor, Fee
.iter()
.enumerate()
.filter_map(|(index, asset)| {
if let MultiAsset { id: Concrete(location), fun: Fungible(amount) } = asset {
if *location == token_location {
if let Asset { id: location, fun: Fungible(amount) } = asset {
if location.0 == token_location {
return Some((index, (*amount).into()))
}
}
@@ -104,7 +99,7 @@ impl<Balance, AccountId, FeeAssetLocation, EthereumNetwork, AssetTransactor, Fee
if remote_fee > (0u128).into() {
// Refund remote component of fee to physical origin
deposit_or_burn_fee::<AssetTransactor, _>(
MultiAsset { id: Concrete(token_location), fun: Fungible(remote_fee.into()) }
Asset { id: AssetId(token_location.clone()), fun: Fungible(remote_fee.into()) }
.into(),
context,
para_sovereign,
@@ -112,8 +107,8 @@ impl<Balance, AccountId, FeeAssetLocation, EthereumNetwork, AssetTransactor, Fee
// Return remaining fee to the next fee handler in the chain.
let mut modified_fees = fees.inner().clone();
modified_fees.remove(fee_index);
modified_fees.push(MultiAsset {
id: Concrete(token_location),
modified_fees.push(Asset {
id: AssetId(token_location),
fun: Fungible((total_fee - remote_fee).into()),
});
return modified_fees.into()
@@ -49,38 +49,36 @@ where
+ snowbridge_pallet_outbound_queue::Config,
XcmConfig: xcm_executor::Config,
{
let assethub_parachain_location = MultiLocation::new(1, Parachain(assethub_parachain_id));
let asset = MultiAsset {
id: Concrete(MultiLocation {
parents: 0,
interior: X1(AccountKey20 { network: None, key: weth_contract_address.into() }),
}),
let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id));
let asset = Asset {
id: AssetId(Location::new(
0,
[AccountKey20 { network: None, key: weth_contract_address.into() }],
)),
fun: Fungible(1000000000),
};
let assets = vec![asset.clone()];
let inner_xcm = Xcm(vec![
WithdrawAsset(MultiAssets::from(assets.clone())),
WithdrawAsset(Assets::from(assets.clone())),
ClearOrigin,
BuyExecution { fees: asset, weight_limit: Unlimited },
DepositAsset {
assets: Wild(All),
beneficiary: MultiLocation {
parents: 0,
interior: X1(AccountKey20 { network: None, key: destination_address.into() }),
},
beneficiary: Location::new(
0,
[AccountKey20 { network: None, key: destination_address.into() }],
),
},
SetTopic([0; 32]),
]);
let fee = MultiAsset {
id: Concrete(MultiLocation { parents: 1, interior: Here }),
fun: Fungible(fee_amount),
};
let fee =
Asset { id: AssetId(Location { parents: 1, interior: Here }), fun: Fungible(fee_amount) };
// prepare transfer token message
let xcm = Xcm(vec![
WithdrawAsset(MultiAssets::from(vec![fee.clone()])),
WithdrawAsset(Assets::from(vec![fee.clone()])),
BuyExecution { fees: fee, weight_limit: Unlimited },
ExportMessage {
network: Ethereum { chain_id: 11155111 },
@@ -90,12 +88,13 @@ where
]);
// execute XCM
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
XcmExecutor::<XcmConfig>::execute_xcm(
let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
XcmExecutor::<XcmConfig>::prepare_and_execute(
assethub_parachain_location,
xcm,
hash,
&mut hash,
RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
Weight::zero(),
)
}
@@ -176,7 +175,7 @@ pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
XcmConfig: xcm_executor::Config,
ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
{
let assethub_parachain_location = MultiLocation::new(1, Parachain(assethub_parachain_id));
let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id));
ExtBuilder::<Runtime>::default()
.with_collators(collator_session_key.collators())
@@ -194,28 +193,25 @@ pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
)
.unwrap();
let asset = MultiAsset {
id: Concrete(MultiLocation {
parents: 0,
interior: X1(AccountKey20 { network: None, key: weth_contract_address.into() }),
}),
let asset = Asset {
id: AssetId(Location::new(
0,
[AccountKey20 { network: None, key: weth_contract_address.into() }],
)),
fun: Fungible(1000000000),
};
let assets = vec![asset.clone()];
let inner_xcm = Xcm(vec![
WithdrawAsset(MultiAssets::from(assets.clone())),
WithdrawAsset(Assets::from(assets.clone())),
ClearOrigin,
BuyExecution { fees: asset, weight_limit: Unlimited },
DepositAsset {
assets: Wild(AllCounted(1)),
beneficiary: MultiLocation {
parents: 0,
interior: X1(AccountKey20 {
network: None,
key: destination_contract.into(),
}),
},
beneficiary: Location::new(
0,
[AccountKey20 { network: None, key: destination_contract.into() }],
),
},
SetTopic([0; 32]),
]);
@@ -231,12 +227,13 @@ pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
]);
// execute XCM
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
let outcome = XcmExecutor::<XcmConfig>::execute_xcm(
let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256);
let outcome = XcmExecutor::<XcmConfig>::prepare_and_execute(
assethub_parachain_location,
xcm,
hash,
&mut hash,
RuntimeHelper::<Runtime>::xcm_max_weight(XcmReceivedFrom::Sibling),
Weight::zero(),
);
// check error is barrier
assert_err!(outcome.ensure_complete(), Barrier);