// Copyright 2020 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 sp_std::{marker::PhantomData, convert::TryInto}; use xcm::v0::{MultiLocation, OriginKind, NetworkId, Junction, BodyId, BodyPart}; use xcm_executor::traits::{Convert, ConvertOrigin}; use frame_support::traits::{EnsureOrigin, Get, OriginTrait, GetBacking}; use frame_system::RawOrigin as SystemRawOrigin; use polkadot_parachain::primitives::IsSystem; /// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`. pub struct SovereignSignedViaLocation( PhantomData<(LocationConverter, Origin)> ); impl< LocationConverter: Convert, Origin: OriginTrait, > ConvertOrigin for SovereignSignedViaLocation where Origin::AccountId: Clone { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { if let OriginKind::SovereignAccount = kind { let location = LocationConverter::convert(origin)?; Ok(Origin::signed(location).into()) } else { Err(origin) } } } pub struct ParentAsSuperuser(PhantomData); impl< Origin: OriginTrait, > ConvertOrigin for ParentAsSuperuser { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Superuser, MultiLocation::X1(Junction::Parent)) => Ok(Origin::root()), (_, origin) => Err(origin), } } } pub struct ChildSystemParachainAsSuperuser(PhantomData<(ParaId, Origin)>); impl< ParaId: IsSystem + From, Origin: OriginTrait, > ConvertOrigin for ChildSystemParachainAsSuperuser { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Superuser, MultiLocation::X1(Junction::Parachain(id))) if ParaId::from(id).is_system() => Ok(Origin::root()), (_, origin) => Err(origin), } } } pub struct SiblingSystemParachainAsSuperuser(PhantomData<(ParaId, Origin)>); impl< ParaId: IsSystem + From, Origin: OriginTrait > ConvertOrigin for SiblingSystemParachainAsSuperuser { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Superuser, MultiLocation::X2(Junction::Parent, Junction::Parachain(id))) if ParaId::from(id).is_system() => Ok(Origin::root()), (_, origin) => Err(origin), } } } pub struct ChildParachainAsNative( PhantomData<(ParachainOrigin, Origin)> ); impl< ParachainOrigin: From, Origin: From, > ConvertOrigin for ChildParachainAsNative { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Native, MultiLocation::X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(id))), (_, origin) => Err(origin), } } } pub struct SiblingParachainAsNative( PhantomData<(ParachainOrigin, Origin)> ); impl< ParachainOrigin: From, Origin: From, > ConvertOrigin for SiblingParachainAsNative { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Native, MultiLocation::X2(Junction::Parent, Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(id))), (_, origin) => Err(origin), } } } // Our Relay-chain has a native origin given by the `Get`ter. pub struct RelayChainAsNative( PhantomData<(RelayOrigin, Origin)> ); impl< RelayOrigin: Get, Origin, > ConvertOrigin for RelayChainAsNative { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Native, MultiLocation::X1(Junction::Parent)) => Ok(RelayOrigin::get()), (_, origin) => Err(origin), } } } pub struct SignedAccountId32AsNative( PhantomData<(Network, Origin)> ); impl< Network: Get, Origin: OriginTrait, > ConvertOrigin for SignedAccountId32AsNative where Origin::AccountId: From<[u8; 32]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Native, MultiLocation::X1(Junction::AccountId32 { id, network })) if matches!(network, NetworkId::Any) || network == Network::get() => Ok(Origin::signed(id.into())), (_, origin) => Err(origin), } } } pub struct SignedAccountKey20AsNative( PhantomData<(Network, Origin)> ); impl< Network: Get, Origin: OriginTrait > ConvertOrigin for SignedAccountKey20AsNative where Origin::AccountId: From<[u8; 20]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { (OriginKind::Native, MultiLocation::X1(Junction::AccountKey20 { key, network })) if matches!(network, NetworkId::Any) || network == Network::get() => { Ok(Origin::signed(key.into())) } (_, origin) => Err(origin), } } } /// EnsureOrigin barrier to convert from dispatch origin to XCM origin, if one exists. pub struct EnsureXcmOrigin(PhantomData<(Origin, Conversion)>); impl< Origin: OriginTrait + Clone, Conversion: Convert, > EnsureOrigin for EnsureXcmOrigin where Origin::PalletsOrigin: PartialEq, { type Success = MultiLocation; fn try_origin(o: Origin) -> Result { let o = match Conversion::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() == Origin::root().caller() { Ok(MultiLocation::Null) } else { Err(o) } } #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> Origin { Origin::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<(Origin, AccountId, Network)> ); impl< Origin: OriginTrait + Clone, AccountId: Into<[u8; 32]>, Network: Get, > Convert for SignedToAccountId32 where Origin::PalletsOrigin: From> + TryInto, Error=Origin::PalletsOrigin> { fn convert(o: Origin) -> Result { o.try_with_caller(|caller| match caller.try_into() { Ok(SystemRawOrigin::Signed(who)) => Ok(Junction::AccountId32 { network: Network::get(), id: who.into() }.into()), Ok(other) => Err(other.into()), Err(other) => Err(other), }) } } /// `Convert` implementation to convert from some an origin which implements `Backing` into a corresponding `Plurality` /// MultiLocation. /// /// Typically used when configuring `pallet-xcm` for allowing a collective's Origin to dispatch an XCM from a /// `Plurality` origin. pub struct BackingToPlurality( PhantomData<(Origin, COrigin, Body)> ); impl< Origin: OriginTrait + Clone, COrigin: GetBacking, Body: Get, > Convert for BackingToPlurality where Origin::PalletsOrigin: From + TryInto { fn convert(o: Origin) -> Result { o.try_with_caller(|caller| match caller.try_into() { Ok(co) => match co.get_backing() { Some(backing) => Ok(Junction::Plurality { id: Body::get(), part: BodyPart::Fraction { nom: backing.approvals, denom: backing.eligible }, }.into()), None => Err(co.into()), } Err(other) => Err(other), }) } }