Unverified Commit 8f0a57ab authored by Gavin Wood's avatar Gavin Wood Committed by GitHub
Browse files

XCM v1 (#2815)



* MultiAsset TWO

* Draft next MultiAsset API.

* XCM core builds

* XCM Executor builds

* XCM Builder builds

* API changes making their way throughout

* Some TODOs

* Further build fixes

* Basic compile builds

* First test fixed

* All executor tests fixed

* Typo

* Optimize subsume_assets and add test

* Optimize checked_sub

* XCM Builder first test fixed

* Fix builder tests

* Fix doc test

* fix some doc tests

* spelling

* named fields for AllOf

* Update xcm/src/v0/multiasset.rs
Co-authored-by: default avatarAlexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs
Co-authored-by: default avatarAlexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs
Co-authored-by: default avatarAlexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs
Co-authored-by: default avatarAlexander Popiak <alexander.popiak@parity.io>

* Reformat

* Move to XCM version 1

* Spelling

* warnings

* Replace some more v0->v1s

* warnings

* format

* Add max_assets param

* building

* test fixes

* tests

* another test

* final test

* tests

* Rename Null -> Here

* Introduce

* More ergonomics

* More ergonomics

* test fix

* test fixes

* docs

* BuyExecution includes

* Fix XCM extrinsics

* fmt

* Make Vec<MultiAsset>/MultiAssets conversions safe

* More MultiAssets conversion safety

* spelling

* fix doc test

* Apply suggestions from code review
Co-authored-by: default avatarAmar Singh <asinghchrony@protonmail.com>

* Apply suggestions from code review
Co-authored-by: default avatarAmar Singh <asinghchrony@protonmail.com>

* fmt

* Add v0, remove VersionedMultiAsset

* Remove VersionedMultiLocation

* Update xcm/src/v1/order.rs
Co-authored-by: default avatarAmar Singh <asinghchrony@protonmail.com>

* Update xcm/src/v1/mod.rs
Co-authored-by: default avatarAmar Singh <asinghchrony@protonmail.com>

* XCM v0 backwards compatibility

* Full compatibility

* fmt

* Update xcm/pallet-xcm/src/lib.rs

* Update xcm/src/v0/order.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Tweaks to versioning system

* Fixes

* fmt

* Update xcm/xcm-executor/src/assets.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Update xcm/xcm-executor/src/assets.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Grumbles

* Update xcm/src/v1/multiasset.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* fmt

* Update xcm/src/v1/multiasset.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Update xcm/src/v1/multiasset.rs
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>

* Fixes

* Formatting
Co-authored-by: default avatarAlexander Popiak <alexander.popiak@parity.io>
Co-authored-by: default avatarAmar Singh <asinghchrony@protonmail.com>
Co-authored-by: Shawn Tabrizi's avatarShawn Tabrizi <shawntabrizi@gmail.com>
parent 3ef9924a
Pipeline #151572 passed with stages
in 43 minutes and 22 seconds
......@@ -19,29 +19,30 @@
use parity_scale_codec::Encode;
use runtime_parachains::{configuration, dmp};
use sp_std::marker::PhantomData;
use xcm::opaque::{
v0::{Error, Junction, MultiLocation, Result, SendXcm, Xcm},
VersionedXcm,
};
use xcm::opaque::v1::{Error, Junction, MultiLocation, Result, SendXcm, Xcm};
/// XCM sender for relay chain. It only sends downward message.
pub struct ChildParachainRouter<T>(PhantomData<T>);
pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>);
impl<T: configuration::Config + dmp::Config> SendXcm for ChildParachainRouter<T> {
impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm
for ChildParachainRouter<T, W>
{
fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result {
match dest {
match &dest {
MultiLocation::X1(Junction::Parachain(id)) => {
// Downward message passing.
let versioned_xcm =
W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?;
let config = <configuration::Pallet<T>>::config();
<dmp::Pallet<T>>::queue_downward_message(
&config,
id.into(),
VersionedXcm::from(msg).encode(),
(*id).into(),
versioned_xcm.encode(),
)
.map_err(Into::<Error>::into)?;
Ok(())
},
d => Err(Error::CannotReachDestination(d, msg)),
_ => Err(Error::CannotReachDestination(dest, msg)),
}
}
}
......@@ -75,13 +75,7 @@ use sp_staking::SessionIndex;
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use static_assertions::const_assert;
use xcm::v0::{
BodyId,
Junction::Parachain,
MultiAsset::{self, AllConcreteFungible},
MultiLocation::{self, Null, X1},
NetworkId, Xcm,
};
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia,
......@@ -1205,14 +1199,14 @@ impl auctions::Config for Runtime {
parameter_types! {
/// The location of the KSM token, from the context of this chain. Since this token is native to this
/// chain, we make it synonymous with it and thus it is the `Null` location, which means "equivalent to
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
/// the context".
pub const KsmLocation: MultiLocation = MultiLocation::Null;
pub const KsmLocation: MultiLocation = MultiLocation::Here;
/// The Kusama network ID. This is named.
pub const KusamaNetwork: NetworkId = NetworkId::Kusama;
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
/// Kusama is a top-level relay-chain, there is no ancestry.
pub const Ancestry: MultiLocation = MultiLocation::Null;
pub const Ancestry: MultiLocation = MultiLocation::Here;
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
pub CheckAccount: AccountId = XcmPallet::check_account();
}
......@@ -1264,12 +1258,12 @@ parameter_types! {
/// individual routers.
pub type XcmRouter = (
// Only one router so far - use DMP to communicate with child parachains.
xcm_sender::ChildParachainRouter<Runtime>,
xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>,
);
parameter_types! {
pub const KusamaForStatemint: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(1000)));
pub const Kusama: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(KsmLocation::get()) });
pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), X1(Parachain(1000)));
}
pub type TrustedTeleporters = (xcm_builder::Case<KusamaForStatemint>,);
......@@ -1317,65 +1311,14 @@ pub type LocalOriginToLocation = (
SignedToAccountId32<Origin, AccountId, KusamaNetwork>,
);
pub struct OnlyWithdrawTeleportForAccounts;
impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)>
for OnlyWithdrawTeleportForAccounts
{
fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool {
use xcm::v0::{
Junction::{AccountId32, Plurality},
MultiAsset::{All, ConcreteFungible},
Order::{BuyExecution, DepositAsset, InitiateTeleport},
Xcm::WithdrawAsset,
};
match origin {
// Root and council are are allowed to execute anything.
Null | X1(Plurality { .. }) => true,
X1(AccountId32 { .. }) => {
// An account ID trying to send a message. We ensure that it's sensible.
// This checks that it's of the form:
// WithdrawAsset {
// assets: [ ConcreteFungible { id: Null } ],
// effects: [ BuyExecution, InitiateTeleport {
// assets: All,
// dest: Parachain,
// effects: [ BuyExecution, DepositAssets {
// assets: All,
// dest: AccountId32,
// } ]
// } ]
// }
matches!(msg, WithdrawAsset { ref assets, ref effects }
if assets.len() == 1
&& matches!(assets[0], ConcreteFungible { id: Null, .. })
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects }
if assets.len() == 1
&& matches!(assets[0], All)
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) }
if assets.len() == 1
&& matches!(assets[0], All)
)
)
)
},
// Nobody else is allowed to execute anything.
_ => false,
}
}
}
impl pallet_xcm::Config for Runtime {
type Event = Event;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
// Anyone can execute XCM messages locally...
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
// ...but they must match our filter, which rejects all.
type XcmExecuteFilter = ();
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>;
......
......@@ -22,7 +22,7 @@ use frame_support::pallet_prelude::*;
use primitives::v1::{DownwardMessage, Hash, Id as ParaId, InboundDownwardMessage};
use sp_runtime::traits::{BlakeTwo256, Hash as HashT, SaturatedConversion};
use sp_std::{fmt, prelude::*};
use xcm::v0::Error as XcmError;
use xcm::latest::Error as XcmError;
pub use pallet::*;
......
......@@ -1007,7 +1007,7 @@ impl<T: Config> Pallet<T> {
let notification_bytes = {
use parity_scale_codec::Encode as _;
use xcm::opaque::{v0::Xcm, VersionedXcm};
use xcm::opaque::{v1::Xcm, VersionedXcm};
VersionedXcm::from(Xcm::HrmpNewChannelOpenRequest {
sender: u32::from(origin),
......@@ -1066,7 +1066,7 @@ impl<T: Config> Pallet<T> {
let notification_bytes = {
use parity_scale_codec::Encode as _;
use xcm::opaque::{v0::Xcm, VersionedXcm};
use xcm::opaque::{v1::Xcm, VersionedXcm};
VersionedXcm::from(Xcm::HrmpChannelAccepted { recipient: u32::from(origin) }).encode()
};
......@@ -1106,7 +1106,7 @@ impl<T: Config> Pallet<T> {
let config = <configuration::Pallet<T>>::config();
let notification_bytes = {
use parity_scale_codec::Encode as _;
use xcm::opaque::{v0::Xcm, VersionedXcm};
use xcm::opaque::{v1::Xcm, VersionedXcm};
VersionedXcm::from(Xcm::HrmpChannelClosing {
initiator: u32::from(origin),
......
......@@ -27,7 +27,7 @@ use sp_std::{
marker::PhantomData,
prelude::*,
};
use xcm::v0::Outcome;
use xcm::latest::Outcome;
pub use pallet::*;
......@@ -78,14 +78,14 @@ pub type MessageId = [u8; 32];
/// and will be forwarded to the XCM Executor.
pub struct XcmSink<XcmExecutor, Config>(PhantomData<(XcmExecutor, Config)>);
impl<XcmExecutor: xcm::v0::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> {
impl<XcmExecutor: xcm::latest::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> {
fn process_upward_message(
origin: ParaId,
data: &[u8],
max_weight: Weight,
) -> Result<Weight, (MessageId, Weight)> {
use xcm::{
v0::{Error as XcmError, Junction, MultiLocation, Xcm},
latest::{Error as XcmError, Junction, MultiLocation, Xcm},
VersionedXcm,
};
......
......@@ -80,7 +80,7 @@ use polkadot_parachain::primitives::Id as ParaId;
use constants::{currency::*, fee::*, time::*};
use frame_support::traits::InstanceFilter;
use xcm::v0::{BodyId, MultiLocation, NetworkId, Xcm};
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds,
......@@ -583,9 +583,9 @@ impl parachains_paras::Config for Runtime {
}
parameter_types! {
pub const RocLocation: MultiLocation = MultiLocation::Null;
pub const RocLocation: MultiLocation = MultiLocation::Here;
pub const RococoNetwork: NetworkId = NetworkId::Polkadot;
pub const Ancestry: MultiLocation = MultiLocation::Null;
pub const Ancestry: MultiLocation = MultiLocation::Here;
pub CheckAccount: AccountId = XcmPallet::check_account();
}
......@@ -620,24 +620,15 @@ parameter_types! {
/// individual routers.
pub type XcmRouter = (
// Only one router so far - use DMP to communicate with child parachains.
xcm_sender::ChildParachainRouter<Runtime>,
xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>,
);
use xcm::v0::{
Junction::Parachain,
MultiAsset,
MultiAsset::AllConcreteFungible,
MultiLocation::{Null, X1},
};
parameter_types! {
pub const RococoForTick: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(100)));
pub const RococoForTrick: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(110)));
pub const RococoForTrack: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(120)));
pub const RococoForStatemint: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(1001)));
pub const Rococo: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(RocLocation::get()) });
pub const RococoForTick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(100)));
pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(110)));
pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(120)));
pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(1001)));
}
pub type TrustedTeleporters = (
xcm_builder::Case<RococoForTick>,
......@@ -692,65 +683,14 @@ pub type LocalOriginToLocation = (
SignedToAccountId32<Origin, AccountId, RococoNetwork>,
);
pub struct OnlyWithdrawTeleportForAccounts;
impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)>
for OnlyWithdrawTeleportForAccounts
{
fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool {
use xcm::v0::{
Junction::{AccountId32, Plurality},
MultiAsset::{All, ConcreteFungible},
Order::{BuyExecution, DepositAsset, InitiateTeleport},
Xcm::WithdrawAsset,
};
match origin {
// Root and collective are allowed to execute anything.
Null | X1(Plurality { .. }) => true,
X1(AccountId32 { .. }) => {
// An account ID trying to send a message. We ensure that it's sensible.
// This checks that it's of the form:
// WithdrawAsset {
// assets: [ ConcreteFungible { id: Null } ],
// effects: [ BuyExecution, InitiateTeleport {
// assets: All,
// dest: Parachain,
// effects: [ BuyExecution, DepositAssets {
// assets: All,
// dest: AccountId32,
// } ]
// } ]
// }
matches!(msg, WithdrawAsset { ref assets, ref effects }
if assets.len() == 1
&& matches!(assets[0], ConcreteFungible { id: Null, .. })
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects }
if assets.len() == 1
&& matches!(assets[0], All)
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) }
if assets.len() == 1
&& matches!(assets[0], All)
)
)
)
},
// Nobody else is allowed to execute anything.
_ => false,
}
}
}
impl pallet_xcm::Config for Runtime {
type Event = Event;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
// Anyone can execute XCM messages locally...
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
// ...but they must match our filter, which right now rejects everything.
type XcmExecuteFilter = ();
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>;
......
......@@ -49,7 +49,7 @@ pub mod fee {
use frame_support::weights::{
WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
};
use primitives::v0::Balance;
use primitives::v1::Balance;
use runtime_common::ExtrinsicBaseWeight;
use smallvec::smallvec;
pub use sp_runtime::Perbill;
......
......@@ -44,12 +44,7 @@ use runtime_parachains::{
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump,
};
use xcm::v0::{
Junction::Parachain,
MultiAsset::{self, AllConcreteFungible},
MultiLocation::{self, Null, X1},
NetworkId, Xcm,
};
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
......@@ -871,8 +866,8 @@ impl auctions::Config for Runtime {
}
parameter_types! {
pub const WndLocation: MultiLocation = MultiLocation::Null;
pub const Ancestry: MultiLocation = MultiLocation::Null;
pub const WndLocation: MultiLocation = MultiLocation::Here;
pub const Ancestry: MultiLocation = MultiLocation::Here;
pub WestendNetwork: NetworkId = NetworkId::Named(b"Westend".to_vec());
pub CheckAccount: AccountId = XcmPallet::check_account();
}
......@@ -908,12 +903,12 @@ parameter_types! {
/// individual routers.
pub type XcmRouter = (
// Only one router so far - use DMP to communicate with child parachains.
xcm_sender::ChildParachainRouter<Runtime>,
xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>,
);
parameter_types! {
pub const WestendForWestmint: (MultiAsset, MultiLocation) =
(AllConcreteFungible { id: Null }, X1(Parachain(1000)));
pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) =
(Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), X1(Parachain(1000)));
}
pub type TrustedTeleporters = (xcm_builder::Case<WestendForWestmint>,);
......@@ -949,65 +944,14 @@ pub type LocalOriginToLocation = (
SignedToAccountId32<Origin, AccountId, WestendNetwork>,
);
pub struct OnlyWithdrawTeleportForAccounts;
impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)>
for OnlyWithdrawTeleportForAccounts
{
fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool {
use xcm::v0::{
Junction::AccountId32,
MultiAsset::{All, ConcreteFungible},
Order::{BuyExecution, DepositAsset, InitiateTeleport},
Xcm::WithdrawAsset,
};
match origin {
// Root is allowed to execute anything.
Null => true,
X1(AccountId32 { .. }) => {
// An account ID trying to send a message. We ensure that it's sensible.
// This checks that it's of the form:
// WithdrawAsset {
// assets: [ ConcreteFungible { id: Null } ],
// effects: [ BuyExecution, InitiateTeleport {
// assets: All,
// dest: Parachain,
// effects: [ BuyExecution, DepositAssets {
// assets: All,
// dest: AccountId32,
// } ]
// } ]
// }
matches!(msg, WithdrawAsset { ref assets, ref effects }
if assets.len() == 1
&& matches!(assets[0], ConcreteFungible { id: Null, .. })
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects }
if assets.len() == 1
&& matches!(assets[0], All)
&& effects.len() == 2
&& matches!(effects[0], BuyExecution { .. })
&& matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) }
if assets.len() == 1
&& matches!(assets[0], All)
)
)
)
},
// Nobody else is allowed to execute anything.
_ => false,
}
}
}
impl pallet_xcm::Config for Runtime {
type Event = Event;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
// Anyone can execute XCM messages locally...
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
// ...but they must match our filter, which rejects everything.
type XcmExecuteFilter = ();
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>;
......
......@@ -74,6 +74,7 @@ fedora/M
finalize/B
FRAME/MS
FSMs
fungibility
gameable
getter/MS
GiB/S
......
......@@ -23,10 +23,11 @@ mod mock;
#[cfg(test)]
mod tests;
use codec::{Decode, Encode};
use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait};
use sp_runtime::{traits::BadOrigin, RuntimeDebug};
use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec};
use xcm::v0::prelude::*;
use xcm::latest::prelude::*;
use xcm_executor::traits::ConvertOrigin;
use frame_support::PalletId;
......@@ -87,7 +88,7 @@ pub mod pallet {
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
Attempted(xcm::v0::Outcome),
Attempted(xcm::latest::Outcome),
Sent(MultiLocation, MultiLocation, Xcm<()>),
}
......@@ -134,15 +135,15 @@ pub mod pallet {
/// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain.
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be
/// an `AccountId32` value.
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the
/// `dest` side.
/// - `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the
/// `dest` side. May not be empty.
/// - `dest_weight`: Equal to the total weight on `dest` of the XCM message
/// `Teleport { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
#[pallet::weight({
let mut message = Xcm::WithdrawAsset {
assets: assets.clone(),
effects: sp_std::vec![ InitiateTeleport {
assets: sp_std::vec![ All ],
assets: Wild(All),
dest: dest.clone(),
effects: sp_std::vec![],
} ]
......@@ -153,21 +154,28 @@ pub mod pallet {
origin: OriginFor<T>,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
assets: MultiAssets,
fee_asset_item: u32,
dest_weight: Weight,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let value = (origin_location, assets);
let value = (origin_location, assets.drain());
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
let inv_dest = T::LocationInverter::invert_location(&dest);
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
let fees = assets
.get(fee_asset_item as usize)
.ok_or(Error::<T>::Empty)?
.clone()
.reanchored(&inv_dest)
.map_err(|_| Error::<T>::CannotReanchor)?;
let max_assets = assets.len() as u32;
let assets = assets.into();
let mut message = Xcm::WithdrawAsset {
assets,
effects: vec![InitiateTeleport {
assets: vec![All],
assets: Wild(All),
dest,
effects: vec![
BuyExecution {
......@@ -176,9 +184,10 @@ pub mod pallet {
weight: 0,
debt: dest_weight,
halt_on_error: false,
xcm: vec![],
orders: vec![],
instructions: vec![],
},
DepositAsset { assets: vec![All], dest: beneficiary },
DepositAsset { assets: Wild(All), max_assets, beneficiary },
],
}],
};
......@@ -203,7 +212,7 @@ pub mod pallet {
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the
/// `dest` side.
/// - `dest_weight`: Equal to the total weight on `dest` of the XCM message
/// `ReserveAssetDeposit { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
/// `ReserveAssetDeposited { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
#[pallet::weight({
let mut message = Xcm::TransferReserveAsset {
assets: assets.clone(),
......@@ -216,30 +225,38 @@ pub mod pallet {
origin: OriginFor<T>,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
assets: MultiAssets,
fee_asset_item: u32,
dest_weight: Weight,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
let value = (origin_location, assets);
let value = (origin_location, assets.drain());
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
let inv_dest = T::LocationInverter::invert_location(&dest);
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
let fees = assets
.get(fee_asset_item as usize)
.ok_or(Error::<T>::Empty)?
.clone()
.reanchored(&inv_dest)
.map_err(|_| Error::<T>::CannotReanchor)?;