Unverified Commit 6cbf3cc3 authored by Gavin Wood's avatar Gavin Wood Committed by GitHub
Browse files

Allow normal accounts to execute XCM for withdraw+teleport (#2953)

* Allow normal accounts to execute XCM for withdraw+teleport

* Bump Substrate
parent 6663dee8
Pipeline #136181 passed with stages
in 38 minutes
This diff is collapsed.
......@@ -86,7 +86,7 @@ pub use pallet_balances::Call as BalancesCall;
use polkadot_parachain::primitives::Id as ParaId;
use xcm::v0::{MultiLocation, NetworkId, BodyId};
use xcm::v0::{Xcm, MultiLocation, NetworkId, BodyId};
use xcm_executor::XcmExecutor;
use xcm_builder::{
AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation,
......@@ -619,7 +619,7 @@ pub type TrustedTeleporters = (
);
parameter_types! {
pub AllowUnpaidFrom: Vec<MultiLocation> =
pub AllowUnpaidFrom: Vec<MultiLocation> =
vec![
X1(Parachain(100)),
X1(Parachain(110)),
......@@ -664,12 +664,61 @@ 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::{
Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset},
MultiAsset::{All, ConcreteFungible}, Junction::AccountId32,
};
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;
// Right now nobody but root is allowed to dispatch local XCM messages.
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, ()>;
// 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;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
......
......@@ -23,7 +23,7 @@ use codec::{Encode, Decode};
use xcm::v0::{BodyId, OriginKind, MultiLocation, Junction::Plurality};
use xcm_executor::traits::ConvertOrigin;
use sp_runtime::{RuntimeDebug, traits::BadOrigin};
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get};
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get, Contains};
pub use pallet::*;
......@@ -55,6 +55,9 @@ pub mod pallet {
/// which exists as an interior location within this chain's XCM context.
type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
/// Our XCM filter which messages to be executed using `XcmExecutor` must pass.
type XcmExecuteFilter: Contains<(MultiLocation, Xcm<Self::Call>)>;
/// Something to execute an XCM message.
type XcmExecutor: ExecuteXcm<Self::Call>;
}
......@@ -70,6 +73,8 @@ pub mod pallet {
pub enum Error<T> {
Unreachable,
SendFailure,
/// The message execution fails the filter.
Filtered,
}
#[pallet::hooks]
......@@ -105,7 +110,10 @@ pub mod pallet {
-> DispatchResult
{
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
let outcome = T::XcmExecutor::execute_xcm(origin_location, *message, max_weight);
let value = (origin_location, *message);
ensure!(T::XcmExecuteFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, message) = value;
let outcome = T::XcmExecutor::execute_xcm(origin_location, message, max_weight);
Self::deposit_event(Event::Attempted(outcome));
Ok(())
}
......
......@@ -238,7 +238,8 @@ pub enum Xcm<Call> {
/// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus
/// location within the origin.
///
/// Safety: No concerns.
/// Safety: `who` must be an interior location of the context. This basically means that no `Parent`
/// junctions are allowed in it. This should be verified at the time of XCM execution.
///
/// Kind: *Instruction*
///
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment