Unverified Commit 0c151049 authored by Shawn Tabrizi's avatar Shawn Tabrizi Committed by GitHub
Browse files

XCM: Land XCM Builder (#1793)



* Land XCM Builder

* Clean up Cargo dependencies

Co-authored-by: default avatarGavin Wood <gavin@parity.io>
parent bc5d442e
Pipeline #109863 passed with stages
in 22 minutes and 44 seconds
This diff is collapsed.
......@@ -41,6 +41,7 @@ members = [
"service",
"validation",
"xcm",
"xcm/xcm-builder",
"xcm/xcm-executor",
"node/collation-generation",
"node/core/av-store",
......
......@@ -124,9 +124,21 @@ impl Id {
}
/// Returns `true` if this parachain runs with system-level privileges.
/// Use IsSystem instead.
#[deprecated]
pub fn is_system(&self) -> bool { self.0 < USER_INDEX_START }
}
pub trait IsSystem {
fn is_system(&self) -> bool;
}
impl IsSystem for Id {
fn is_system(&self) -> bool {
self.0 < USER_INDEX_START
}
}
impl sp_std::ops::Add<u32> for Id {
type Output = Self;
......
......@@ -7,3 +7,10 @@ edition = "2018"
[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.5", default-features = false, features = [ "derive" ] }
[features]
default = ["std"]
wasm-api = []
std = [
"codec/std",
]
[package]
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
name = "xcm-builder"
description = "Tools & types for building with XCM and its executor."
version = "0.8.22"
[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] }
xcm = { path = "..", default-features = false }
xcm-executor = { path = "../xcm-executor", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
# Polkadot dependencies
polkadot-parachain = { path = "../../parachain", default-features = false }
[features]
default = ["std"]
std = [
"codec/std",
"xcm/std",
"xcm-executor/std",
"sp-std/std",
"sp-arithmetic/std",
"sp-io/std",
"sp-runtime/std",
"frame-support/std",
"polkadot-parachain/std",
]
// 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 <http://www.gnu.org/licenses/>.
use sp_std::{result, convert::TryInto, marker::PhantomData};
use xcm::v0::{Error, Result, MultiAsset, MultiLocation};
use sp_arithmetic::traits::SaturatedConversion;
use frame_support::traits::{ExistenceRequirement::AllowDeath, WithdrawReason};
use xcm_executor::traits::{MatchesFungible, LocationConversion, TransactAsset};
pub struct CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId>(
PhantomData<Currency>,
PhantomData<Matcher>,
PhantomData<AccountIdConverter>,
PhantomData<AccountId>,
);
impl<
Matcher: MatchesFungible<Currency::Balance>,
AccountIdConverter: LocationConversion<AccountId>,
Currency: frame_support::traits::Currency<AccountId>,
AccountId, // can't get away without it since Currency is generic over it.
> TransactAsset for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId> {
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
// Check we handle this asset.
let amount = Matcher::matches_fungible(&what).ok_or(())?.saturated_into();
let who = AccountIdConverter::from_location(who).ok_or(())?;
let balance_amount = amount.try_into().map_err(|_| ())?;
let _imbalance = Currency::deposit_creating(&who, balance_amount);
Ok(())
}
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> result::Result<MultiAsset, Error> {
// Check we handle this asset.
let amount = Matcher::matches_fungible(&what).ok_or(())?.saturated_into();
let who = AccountIdConverter::from_location(who).ok_or(())?;
let balance_amount = amount.try_into().map_err(|_| ())?;
Currency::withdraw(&who, balance_amount, WithdrawReason::Transfer.into(), AllowDeath).map_err(|_| ())?;
Ok(what.clone())
}
}
// 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 <http://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
mod location_conversion;
pub use location_conversion::{
Account32Hash, ParentIsDefault, ChildParachainConvertsVia, SiblingParachainConvertsVia, AccountId32Aliases
};
mod origin_conversion;
pub use origin_conversion::{
SovereignSignedViaLocation, ParentAsSuperuser, ChildSystemParachainAsSuperuser, SiblingSystemParachainAsSuperuser,
ChildParachainAsNative, SiblingParachainAsNative, RelayChainAsNative, SignedAccountId32AsNative
};
mod currency_adapter;
pub use currency_adapter::CurrencyAdapter;
use sp_std::marker::PhantomData;
use xcm_executor::traits::InvertLocation;
use xcm::v0::{MultiLocation, Junction};
use frame_support::traits::Get;
/// Simple location inverter; give it this location's ancestry and it'll
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
fn invert_location(location: &MultiLocation) -> MultiLocation {
let mut ancestry = Ancestry::get();
let mut result = location.clone();
for (i, j) in location.iter_rev()
.map(|j| match j {
Junction::Parent => ancestry.take_first().unwrap_or(Junction::OnlyChild),
_ => Junction::Parent,
})
.enumerate()
{
*result.at_mut(i).expect("location and result begin equal; same size; qed") = j;
}
result
}
}
// 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 <http://www.gnu.org/licenses/>.
use sp_std::marker::PhantomData;
use sp_io::hashing::blake2_256;
use sp_runtime::traits::AccountIdConversion;
use frame_support::traits::Get;
use codec::Encode;
use xcm::v0::{MultiLocation, NetworkId, Junction};
use xcm_executor::traits::LocationConversion;
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<
Network: Get<NetworkId>,
AccountId: From<[u8; 32]> + Into<[u8; 32]>,
> LocationConversion<AccountId> for Account32Hash<Network, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
Some(("multiloc", location).using_encoded(blake2_256).into())
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
Err(who)
}
}
pub struct ParentIsDefault<AccountId>(PhantomData<AccountId>);
impl<
AccountId: Default + Eq,
> LocationConversion<AccountId> for ParentIsDefault<AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::Parent) = location {
Some(AccountId::default())
} else {
None
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if who == AccountId::default() {
Ok(Junction::Parent.into())
} else {
Err(who)
}
}
}
pub struct ChildParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
impl<
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
AccountId,
> LocationConversion<AccountId> for ChildParachainConvertsVia<ParaId, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::Parachain { id }) = location {
Some(ParaId::from(*id).into_account())
} else {
None
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if let Some(id) = ParaId::try_from_account(&who) {
Ok(Junction::Parachain { id: id.into() }.into())
} else {
Err(who)
}
}
}
pub struct SiblingParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
impl<
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
AccountId,
> LocationConversion<AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X2(Junction::Parent, Junction::Parachain { id }) = location {
Some(ParaId::from(*id).into_account())
} else {
None
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if let Some(id) = ParaId::try_from_account(&who) {
Ok([Junction::Parent, Junction::Parachain { id: id.into() }].into())
} else {
Err(who)
}
}
}
pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<
Network: Get<NetworkId>,
AccountId: From<[u8; 32]> + Into<[u8; 32]>,
> LocationConversion<AccountId> for AccountId32Aliases<Network, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::AccountId32 { id, network }) = location {
if matches!(network, NetworkId::Any) || network == &Network::get() {
return Some((*id).into())
}
}
None
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok(Junction::AccountId32 { id: who.into(), network: Network::get() }.into())
}
}
// 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 <http://www.gnu.org/licenses/>.
use sp_std::marker::PhantomData;
use frame_support::traits::{Get, OriginTrait};
use xcm::v0::{MultiLocation, OriginKind, NetworkId, Junction};
use xcm_executor::traits::{LocationConversion, ConvertOrigin};
use polkadot_parachain::primitives::IsSystem;
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the
/// `LocationConverter`.
pub struct SovereignSignedViaLocation<LocationConverter, Origin>(
PhantomData<(LocationConverter, Origin)>
);
impl<
LocationConverter: LocationConversion<Origin::AccountId>,
Origin: OriginTrait,
> ConvertOrigin<Origin> for SovereignSignedViaLocation<LocationConverter, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
if let OriginKind::SovereignAccount = kind {
let location = LocationConverter::from_location(&origin).ok_or(origin)?;
Ok(Origin::signed(location).into())
} else {
Err(origin)
}
}
}
pub struct ParentAsSuperuser<Origin>(PhantomData<Origin>);
impl<
Origin: OriginTrait,
> ConvertOrigin<Origin> for ParentAsSuperuser<Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
match (kind, origin) {
(OriginKind::Superuser, MultiLocation::X1(Junction::Parent)) =>
Ok(Origin::root()),
(_, origin) => Err(origin),
}
}
}
pub struct ChildSystemParachainAsSuperuser<ParaId, Origin>(PhantomData<(ParaId, Origin)>);
impl<
ParaId: IsSystem + From<u32>,
Origin: OriginTrait,
> ConvertOrigin<Origin> for ChildSystemParachainAsSuperuser<ParaId, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
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<ParaId, Origin>(PhantomData<(ParaId, Origin)>);
impl<
ParaId: IsSystem + From<u32>,
Origin: OriginTrait
> ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<ParaId, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
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<ParachainOrigin, Origin>(
PhantomData<(ParachainOrigin, Origin)>
);
impl<
ParachainOrigin: From<u32>,
Origin: From<ParachainOrigin>,
> ConvertOrigin<Origin> for ChildParachainAsNative<ParachainOrigin, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
match (kind, origin) {
(OriginKind::Native, MultiLocation::X1(Junction::Parachain { id }))
=> Ok(Origin::from(ParachainOrigin::from(id))),
(_, origin) => Err(origin),
}
}
}
pub struct SiblingParachainAsNative<ParachainOrigin, Origin>(
PhantomData<(ParachainOrigin, Origin)>
);
impl<
ParachainOrigin: From<u32>,
Origin: From<ParachainOrigin>,
> ConvertOrigin<Origin> for SiblingParachainAsNative<ParachainOrigin, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
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<RelayOrigin, Origin>(
PhantomData<(RelayOrigin, Origin)>
);
impl<
RelayOrigin: Get<Origin>,
Origin,
> ConvertOrigin<Origin> for RelayChainAsNative<RelayOrigin, Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
match (kind, origin) {
(OriginKind::Native, MultiLocation::X1(Junction::Parent)) => Ok(RelayOrigin::get()),
(_, origin) => Err(origin),
}
}
}
pub struct SignedAccountId32AsNative<Network, Origin>(
PhantomData<(Network, Origin)>
);
impl<
Network: Get<NetworkId>,
Origin: OriginTrait,
> ConvertOrigin<Origin> for SignedAccountId32AsNative<Network, Origin> where
Origin::AccountId: From<[u8; 32]>,
{
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
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),
}
}
}
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