// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
//! Various implementations for `ConvertOrigin`.
use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait};
use frame_system::RawOrigin as SystemRawOrigin;
use polkadot_parachain_primitives::primitives::IsSystem;
use sp_runtime::traits::TryConvert;
use sp_std::marker::PhantomData;
use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, Location, NetworkId, OriginKind};
use xcm_executor::traits::{ConvertLocation, ConvertOrigin};
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the
/// `LocationConverter`.
pub struct SovereignSignedViaLocation(
PhantomData<(LocationConverter, RuntimeOrigin)>,
);
impl, RuntimeOrigin: OriginTrait>
ConvertOrigin for SovereignSignedViaLocation
where
RuntimeOrigin::AccountId: Clone,
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SovereignSignedViaLocation origin: {:?}, kind: {:?}",
origin, kind,
);
if let OriginKind::SovereignAccount = kind {
let location = LocationConverter::convert_location(&origin).ok_or(origin)?;
Ok(RuntimeOrigin::signed(location).into())
} else {
Err(origin)
}
}
}
pub struct ParentAsSuperuser(PhantomData);
impl ConvertOrigin for ParentAsSuperuser {
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ParentAsSuperuser origin: {:?}, kind: {:?}", origin, kind);
if kind == OriginKind::Superuser && origin.contains_parents_only(1) {
Ok(RuntimeOrigin::root())
} else {
Err(origin)
}
}
}
pub struct ChildSystemParachainAsSuperuser(
PhantomData<(ParaId, RuntimeOrigin)>,
);
impl, RuntimeOrigin: OriginTrait> ConvertOrigin
for ChildSystemParachainAsSuperuser
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ChildSystemParachainAsSuperuser origin: {:?}, kind: {:?}", origin, kind);
match (kind, origin.unpack()) {
(OriginKind::Superuser, (0, [Junction::Parachain(id)]))
if ParaId::from(*id).is_system() =>
Ok(RuntimeOrigin::root()),
_ => Err(origin),
}
}
}
pub struct SiblingSystemParachainAsSuperuser(
PhantomData<(ParaId, RuntimeOrigin)>,
);
impl, RuntimeOrigin: OriginTrait> ConvertOrigin
for SiblingSystemParachainAsSuperuser
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SiblingSystemParachainAsSuperuser origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin.unpack()) {
(OriginKind::Superuser, (1, [Junction::Parachain(id)]))
if ParaId::from(*id).is_system() =>
Ok(RuntimeOrigin::root()),
_ => Err(origin),
}
}
}
pub struct ChildParachainAsNative(
PhantomData<(ParachainOrigin, RuntimeOrigin)>,
);
impl, RuntimeOrigin: From> ConvertOrigin
for ChildParachainAsNative
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "ChildParachainAsNative origin: {:?}, kind: {:?}", origin, kind);
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::Parachain(id)])) =>
Ok(RuntimeOrigin::from(ParachainOrigin::from(*id))),
_ => Err(origin),
}
}
}
pub struct SiblingParachainAsNative(
PhantomData<(ParachainOrigin, RuntimeOrigin)>,
);
impl, RuntimeOrigin: From> ConvertOrigin
for SiblingParachainAsNative
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SiblingParachainAsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin.unpack()) {
(OriginKind::Native, (1, [Junction::Parachain(id)])) =>
Ok(RuntimeOrigin::from(ParachainOrigin::from(*id))),
_ => Err(origin),
}
}
}
// Our Relay-chain has a native origin given by the `Get`ter.
pub struct RelayChainAsNative(
PhantomData<(RelayOrigin, RuntimeOrigin)>,
);
impl, RuntimeOrigin> ConvertOrigin
for RelayChainAsNative
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(target: "xcm::origin_conversion", "RelayChainAsNative origin: {:?}, kind: {:?}", origin, kind);
if kind == OriginKind::Native && origin.contains_parents_only(1) {
Ok(RelayOrigin::get())
} else {
Err(origin)
}
}
}
pub struct SignedAccountId32AsNative(PhantomData<(Network, RuntimeOrigin)>);
impl>, RuntimeOrigin: OriginTrait> ConvertOrigin
for SignedAccountId32AsNative
where
RuntimeOrigin::AccountId: From<[u8; 32]>,
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SignedAccountId32AsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::AccountId32 { id, network }]))
if matches!(network, None) || *network == Network::get() =>
Ok(RuntimeOrigin::signed((*id).into())),
_ => Err(origin),
}
}
}
pub struct SignedAccountKey20AsNative(
PhantomData<(Network, RuntimeOrigin)>,
);
impl>, RuntimeOrigin: OriginTrait> ConvertOrigin
for SignedAccountKey20AsNative
where
RuntimeOrigin::AccountId: From<[u8; 20]>,
{
fn convert_origin(
origin: impl Into,
kind: OriginKind,
) -> Result {
let origin = origin.into();
log::trace!(
target: "xcm::origin_conversion",
"SignedAccountKey20AsNative origin: {:?}, kind: {:?}",
origin, kind,
);
match (kind, origin.unpack()) {
(OriginKind::Native, (0, [Junction::AccountKey20 { key, network }]))
if (matches!(network, None) || *network == Network::get()) =>
Ok(RuntimeOrigin::signed((*key).into())),
_ => Err(origin),
}
}
}
/// `EnsureOrigin` barrier to convert from dispatch origin to XCM origin, if one exists.
pub struct EnsureXcmOrigin(PhantomData<(RuntimeOrigin, Conversion)>);
impl>
EnsureOrigin for EnsureXcmOrigin
where
RuntimeOrigin::PalletsOrigin: PartialEq,
{
type Success = Location;
fn try_origin(o: RuntimeOrigin) -> Result {
let o = match Conversion::try_convert(o) {
Ok(location) => return Ok(location),
Err(o) => o,
};
// We institute a root fallback so root can always represent the context. This
// guarantees that `successful_origin` will work.
if o.caller() == RuntimeOrigin::root().caller() {
Ok(Here.into())
} else {
Err(o)
}
}
#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin() -> Result {
Ok(RuntimeOrigin::root())
}
}
/// `Convert` implementation to convert from some a `Signed` (system) `Origin` into an
/// `AccountId32`.
///
/// Typically used when configuring `pallet-xcm` for allowing normal accounts to dispatch an XCM
/// from an `AccountId32` origin.
pub struct SignedToAccountId32(
PhantomData<(RuntimeOrigin, AccountId, Network)>,
);
impl<
RuntimeOrigin: OriginTrait + Clone,
AccountId: Into<[u8; 32]>,
Network: Get