mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
XCM docs and tests (#2948)
* WIP * add tests and docs for DoubleEncoded * reformat parent_count * add test for match_and_split * fix append_with docs and add tests * move Parachain enum variant to tuple * Fix stuff * add to append test * simplify match * formatting * format and extend doc comments (including examples) * fix typo * add some doc comments * add test for location inverter * Add more tests/docs * Fix build * matches fungibles * currency adapter. * add more tests for location inverter * extract max length magic number into constant * adapters. * Apply suggestions from code review * Final touches. * Repot and fixes * Remove last todo * Apply suggestions from code review Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/barriers.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/barriers.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/currency_adapter.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/filter_asset_location.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-builder/src/matches_fungible.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-executor/src/traits/conversion.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-executor/src/traits/conversion.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-executor/src/traits/transact_asset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update xcm/xcm-executor/src/traits/should_execute.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> Co-authored-by: kianenigma <kian@parity.io> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -14,12 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Various implementations for `ShouldExecute`.
|
||||
|
||||
use sp_std::{result::Result, marker::PhantomData};
|
||||
use xcm::v0::{Xcm, Order, MultiLocation, Junction};
|
||||
use frame_support::{ensure, traits::Contains, weights::Weight};
|
||||
use xcm_executor::traits::{OnResponse, ShouldExecute};
|
||||
use polkadot_parachain::primitives::IsSystem;
|
||||
|
||||
/// Execution barrier that just takes `shallow_weight` from `weight_credit`.
|
||||
pub struct TakeWeightCredit;
|
||||
impl ShouldExecute for TakeWeightCredit {
|
||||
fn should_execute<Call>(
|
||||
@@ -34,6 +37,8 @@ impl ShouldExecute for TakeWeightCredit {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking payments into
|
||||
/// account.
|
||||
pub struct AllowTopLevelPaidExecutionFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFrom<T> {
|
||||
fn should_execute<Call>(
|
||||
@@ -59,6 +64,8 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows execution from any origin that is contained in `T` (i.e. `T::Contains(origin)`) without any payments.
|
||||
/// Use only for executions from trusted origin groups.
|
||||
pub struct AllowUnpaidExecutionFrom<T>(PhantomData<T>);
|
||||
impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
|
||||
fn should_execute<Call>(
|
||||
@@ -73,6 +80,7 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows a message only if it is from a system-level child parachain.
|
||||
pub struct IsChildSystemParachain<ParaId>(PhantomData<ParaId>);
|
||||
impl<
|
||||
ParaId: IsSystem + From<u32>,
|
||||
@@ -82,6 +90,7 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows only messages if the generic `ResponseHandler` expects them via `expecting_response`.
|
||||
pub struct AllowKnownQueryResponses<ResponseHandler>(PhantomData<ResponseHandler>);
|
||||
impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<ResponseHandler> {
|
||||
fn should_execute<Call>(
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Adapters to work with `frame_support::traits::Currency` through XCM.
|
||||
|
||||
use sp_std::{result, convert::TryInto, marker::PhantomData};
|
||||
use xcm::v0::{Error as XcmError, Result, MultiAsset, MultiLocation};
|
||||
use sp_runtime::traits::{SaturatedConversion, CheckedSub};
|
||||
@@ -33,16 +35,51 @@ enum Error {
|
||||
|
||||
impl From<Error> for XcmError {
|
||||
fn from(e: Error) -> Self {
|
||||
use XcmError::FailedToTransactAsset;
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::FailedToTransactAsset("AssetNotFound"),
|
||||
Error::AccountIdConversionFailed =>
|
||||
XcmError::FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
XcmError::FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AssetNotFound => FailedToTransactAsset("AssetNotFound"),
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed => FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple adapter to use a currency as asset transactor. This type can be used as `type AssetTransactor` in
|
||||
/// `xcm::Config`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use frame_support::parameter_types;
|
||||
/// use xcm::v0::{MultiLocation, Junction};
|
||||
/// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete};
|
||||
///
|
||||
/// /// Our chain's account id.
|
||||
/// type AccountId = sp_runtime::AccountId32;
|
||||
///
|
||||
/// /// Our relay chain's location.
|
||||
/// parameter_types! {
|
||||
/// RelayChain: MultiLocation = MultiLocation::X1(Junction::Parent);
|
||||
/// CheckingAccount: AccountId = Default::default();
|
||||
/// }
|
||||
///
|
||||
/// /// Some items that implement `Convert<MultiLocation, AccountId>`. Can be more, but for now we just assume we accept
|
||||
/// /// messages from the parent (relay chain).
|
||||
/// pub type LocationConvertor = (ParentIsDefault<RelayChain>);
|
||||
///
|
||||
/// /// Final currency adapter. This can be used in `xcm::Config` to specify how asset related transactions happen.
|
||||
/// pub type AssetTransactor = CurrencyAdapter<
|
||||
/// // Use this balance type:
|
||||
/// u128,
|
||||
/// // The matcher: use the currency when the asset is a concrete asset in our relay chain.
|
||||
/// IsConcrete<RelayChain>,
|
||||
/// // The local convertor: default account of the parent relay chain.
|
||||
/// LocationConvertor,
|
||||
/// // Our chain's account ID type.
|
||||
/// AccountId,
|
||||
/// // The checking account. Can be any deterministic inaccessible account.
|
||||
/// CheckingAccount,
|
||||
/// >;
|
||||
/// ```
|
||||
pub struct CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>(
|
||||
PhantomData<(Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount)>
|
||||
);
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Various implementations of `FilterAssetLocation`.
|
||||
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::v0::{MultiAsset, MultiLocation};
|
||||
use frame_support::traits::Get;
|
||||
use xcm_executor::traits::FilterAssetLocation;
|
||||
|
||||
/// Accepts an asset IFF it is a native asset.
|
||||
pub struct NativeAsset;
|
||||
impl FilterAssetLocation for NativeAsset {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
@@ -26,6 +29,7 @@ impl FilterAssetLocation for NativeAsset {
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts an asset if it is contained in the given `T`'s `Get` impl.
|
||||
pub struct Case<T>(PhantomData<T>);
|
||||
impl<T: Get<(MultiAsset, MultiLocation)>> FilterAssetLocation for Case<T> {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
|
||||
@@ -14,40 +14,16 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM.
|
||||
|
||||
use sp_std::{prelude::*, result, marker::PhantomData, borrow::Borrow};
|
||||
use xcm::v0::{Error as XcmError, Result, MultiAsset, MultiLocation, Junction};
|
||||
use frame_support::traits::{Get, tokens::fungibles, Contains};
|
||||
use xcm_executor::traits::{TransactAsset, Convert};
|
||||
use xcm_executor::traits::{TransactAsset, Convert, MatchesFungibles, Error as MatchError};
|
||||
|
||||
/// Asset transaction errors.
|
||||
pub enum Error {
|
||||
/// Asset not found.
|
||||
AssetNotFound,
|
||||
/// `MultiLocation` to `AccountId` conversion failed.
|
||||
AccountIdConversionFailed,
|
||||
/// `u128` amount to currency `Balance` conversion failed.
|
||||
AmountToBalanceConversionFailed,
|
||||
/// `MultiLocation` to `AssetId` conversion failed.
|
||||
AssetIdConversionFailed,
|
||||
}
|
||||
|
||||
impl From<Error> for XcmError {
|
||||
fn from(e: Error) -> Self {
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::FailedToTransactAsset("AssetNotFound"),
|
||||
Error::AccountIdConversionFailed =>
|
||||
XcmError::FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
XcmError::FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AssetIdConversionFailed =>
|
||||
XcmError::FailedToTransactAsset("AssetIdConversionFailed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be TryFrom/TryInto<u128>)
|
||||
/// into a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will
|
||||
/// typically be a `PalletInstance` junction.
|
||||
/// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be TryFrom/TryInto<u128>) into
|
||||
/// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a
|
||||
/// `PalletInstance` junction.
|
||||
pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>(PhantomData<(Prefix, AssetId, ConvertAssetId)>);
|
||||
impl<
|
||||
Prefix: Get<MultiLocation>,
|
||||
@@ -73,23 +49,6 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MatchesFungibles<AssetId, Balance> {
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error>;
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
> MatchesFungibles<AssetId, Balance> for Tuple {
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error> {
|
||||
for_tuples!( #(
|
||||
match Tuple::matches_fungibles(a) { o @ Ok(_) => return o, _ => () }
|
||||
)* );
|
||||
Err(Error::AssetNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>
|
||||
);
|
||||
@@ -101,13 +60,13 @@ impl<
|
||||
> MatchesFungibles<AssetId, Balance> for
|
||||
ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error> {
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (id, amount) = match a {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (id, amount),
|
||||
_ => return Err(Error::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| Error::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
@@ -123,13 +82,13 @@ impl<
|
||||
> MatchesFungibles<AssetId, Balance> for
|
||||
ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error> {
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (id, amount) = match a {
|
||||
MultiAsset::AbstractFungible { id, amount } => (id, amount),
|
||||
_ => return Err(Error::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| Error::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
@@ -151,9 +110,9 @@ impl<
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
let source = AccountIdConverter::convert_ref(from)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
.map_err(|()| MatchError::AccountIdConversionFailed)?;
|
||||
let dest = AccountIdConverter::convert_ref(to)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
.map_err(|()| MatchError::AccountIdConversionFailed)?;
|
||||
Assets::transfer(asset_id, &source, &dest, amount, true)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
|
||||
Ok(what.clone().into())
|
||||
@@ -208,7 +167,7 @@ impl<
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
let who = AccountIdConverter::convert_ref(who)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
.map_err(|()| MatchError::AccountIdConversionFailed)?;
|
||||
Assets::mint_into(asset_id, &who, amount)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))
|
||||
}
|
||||
@@ -220,7 +179,7 @@ impl<
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
let who = AccountIdConverter::convert_ref(who)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
.map_err(|()| MatchError::AccountIdConversionFailed)?;
|
||||
Assets::burn_from(asset_id, &who, amount)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
|
||||
Ok(what.clone().into())
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! # XCM-Builder
|
||||
//!
|
||||
//! Types and helpers for *building* XCM configuration.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -23,7 +23,6 @@ use xcm::v0::{MultiLocation, NetworkId, Junction};
|
||||
use xcm_executor::traits::{InvertLocation, Convert};
|
||||
|
||||
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone,
|
||||
@@ -37,6 +36,8 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`MultiLocation`] consisting of a single `Parent` [`Junction`] will be converted to the
|
||||
/// default value of `AccountId` (e.g. all zeros for `AccountId32`).
|
||||
pub struct ParentIsDefault<AccountId>(PhantomData<AccountId>);
|
||||
impl<
|
||||
AccountId: Default + Eq + Clone,
|
||||
@@ -81,7 +82,6 @@ impl<
|
||||
}
|
||||
|
||||
pub struct SiblingParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
|
||||
|
||||
impl<
|
||||
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
|
||||
AccountId: Clone,
|
||||
@@ -103,6 +103,7 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the `AccountId32` from the passed `location` if the network matches.
|
||||
pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
@@ -142,7 +143,40 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple location inverter; give it this location's ancestry and it'll figure out the inverted location.
|
||||
/// Simple location inverter; give it this location's ancestry and it'll figure out the inverted
|
||||
/// location.
|
||||
///
|
||||
/// # Example
|
||||
/// ## Network Topology
|
||||
/// ```txt
|
||||
/// v Source
|
||||
/// Relay -> Para 1 -> Account20
|
||||
/// -> Para 2 -> Account32
|
||||
/// ^ Target
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// # use frame_support::parameter_types;
|
||||
/// # use xcm::v0::{MultiLocation::{self, *}, Junction::*, NetworkId::Any};
|
||||
/// # use xcm_builder::LocationInverter;
|
||||
/// # use xcm_executor::traits::InvertLocation;
|
||||
/// # fn main() {
|
||||
/// parameter_types!{
|
||||
/// pub Ancestry: MultiLocation = X2(
|
||||
/// Parachain(1),
|
||||
/// AccountKey20 { network: Any, key: Default::default() },
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// let input = X4(Parent, Parent, Parachain(2), AccountId32 { network: Any, id: Default::default() });
|
||||
/// let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
/// assert_eq!(inverted, X4(
|
||||
/// Parent,
|
||||
/// Parent,
|
||||
/// Parachain(1),
|
||||
/// AccountKey20 { network: Any, key: Default::default() },
|
||||
/// ));
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
|
||||
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
|
||||
fn invert_location(location: &MultiLocation) -> MultiLocation {
|
||||
@@ -160,3 +194,72 @@ impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry>
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use frame_support::parameter_types;
|
||||
use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any};
|
||||
|
||||
fn account20() -> Junction {
|
||||
AccountKey20 { network: Any, key: Default::default() }
|
||||
}
|
||||
|
||||
fn account32() -> Junction {
|
||||
AccountId32 { network: Any, id: Default::default() }
|
||||
}
|
||||
|
||||
// Network Topology
|
||||
// v Source
|
||||
// Relay -> Para 1 -> SmartContract -> Account
|
||||
// -> Para 2 -> Account
|
||||
// ^ Target
|
||||
//
|
||||
// Inputs and outputs written as file paths:
|
||||
//
|
||||
// input location (source to target): ../../../para_2/account32_default
|
||||
// ancestry (root to source): para_1/account20_default/account20_default
|
||||
// =>
|
||||
// output (target to source): ../../para_1/account20_default/account20_default
|
||||
#[test]
|
||||
fn inverter_works_in_tree() {
|
||||
parameter_types!{
|
||||
pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20());
|
||||
}
|
||||
|
||||
let input = X5(Parent, Parent, Parent, Parachain(2), account32());
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
assert_eq!(inverted, X5(Parent, Parent, Parachain(1), account20(), account20()));
|
||||
}
|
||||
|
||||
// Network Topology
|
||||
// v Source
|
||||
// Relay -> Para 1 -> SmartContract -> Account
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_ancestry_as_inverted_location() {
|
||||
parameter_types!{
|
||||
pub Ancestry: MultiLocation = X2(account20(), account20());
|
||||
}
|
||||
|
||||
let input = X2(Parent, Parent);
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
assert_eq!(inverted, X2(account20(), account20()));
|
||||
}
|
||||
|
||||
// Network Topology
|
||||
// v Source
|
||||
// Relay -> Para 1 -> CollectivePallet -> Plurality
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_only_child_on_missing_ancestry() {
|
||||
parameter_types!{
|
||||
pub Ancestry: MultiLocation = X1(PalletInstance(5));
|
||||
}
|
||||
|
||||
let input = X2(Parent, Parent);
|
||||
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
|
||||
assert_eq!(inverted, X2(PalletInstance(5), OnlyChild));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,35 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Various implementations for the `MatchesFungible` trait.
|
||||
|
||||
use sp_std::{marker::PhantomData, convert::TryFrom};
|
||||
use sp_runtime::traits::CheckedConversion;
|
||||
use xcm::v0::{MultiAsset, MultiLocation};
|
||||
use frame_support::traits::Get;
|
||||
use xcm_executor::traits::MatchesFungible;
|
||||
|
||||
/// Converts a `MultiAsset` into balance `B` if it is a concrete fungible with an id equal to that
|
||||
/// given by `T`'s `Get`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use xcm::v0::{MultiAsset, MultiLocation, Junction};
|
||||
/// use xcm_builder::IsConcrete;
|
||||
/// use xcm_executor::traits::MatchesFungible;
|
||||
///
|
||||
/// frame_support::parameter_types! {
|
||||
/// pub TargetLocation: MultiLocation = MultiLocation::X1(Junction::Parent);
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let id = MultiLocation::X1(Junction::Parent);
|
||||
/// let asset = MultiAsset::ConcreteFungible { id, amount: 999u128 };
|
||||
/// // match `asset` if it is a concrete asset in `TargetLocation`.
|
||||
/// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999));
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct IsConcrete<T>(PhantomData<T>);
|
||||
impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete<T> {
|
||||
fn matches_fungible(a: &MultiAsset) -> Option<B> {
|
||||
@@ -30,6 +53,26 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`IsConcrete`] but for a fungible with abstract location.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use xcm::v0::{MultiAsset};
|
||||
/// use xcm_builder::IsAbstract;
|
||||
/// use xcm_executor::traits::MatchesFungible;
|
||||
///
|
||||
/// frame_support::parameter_types! {
|
||||
/// pub TargetLocation: &'static [u8] = &[7u8];
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let asset = MultiAsset::AbstractFungible { id: vec![7u8], amount: 999u128 };
|
||||
/// // match `asset` if it is a concrete asset in `TargetLocation`.
|
||||
/// assert_eq!(<IsAbstract<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999));
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct IsAbstract<T>(PhantomData<T>);
|
||||
impl<T: Get<&'static [u8]>, B: TryFrom<u128>> MatchesFungible<B> for IsAbstract<T> {
|
||||
fn matches_fungible(a: &MultiAsset) -> Option<B> {
|
||||
|
||||
@@ -36,8 +36,17 @@ pub use crate::{
|
||||
FixedRateOfConcreteFungible, AllowKnownQueryResponses, LocationInverter,
|
||||
};
|
||||
|
||||
pub enum TestOrigin { Root, Relay, Signed(u64), Parachain(u32) }
|
||||
pub enum TestOrigin {
|
||||
Root,
|
||||
Relay,
|
||||
Signed(u64),
|
||||
Parachain(u32),
|
||||
}
|
||||
|
||||
/// A dummy call.
|
||||
///
|
||||
/// Each item contains the amount of weight that it *wants* to consume as the first item, and the actual amount (if
|
||||
/// different from the former) in the second option.
|
||||
#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone, Copy)]
|
||||
pub enum TestCall {
|
||||
OnlyRoot(Weight, Option<Weight>),
|
||||
@@ -60,17 +69,13 @@ impl Dispatchable for TestCall {
|
||||
=> maybe_actual,
|
||||
};
|
||||
if match (&origin, &self) {
|
||||
(TestOrigin::Parachain(i), TestCall::OnlyParachain(_, _, Some(j)))
|
||||
=> i == j,
|
||||
(TestOrigin::Signed(i), TestCall::OnlySigned(_, _, Some(j)))
|
||||
=> i == j,
|
||||
|
||||
(TestOrigin::Parachain(i), TestCall::OnlyParachain(_, _, Some(j))) => i == j,
|
||||
(TestOrigin::Signed(i), TestCall::OnlySigned(_, _, Some(j))) => i == j,
|
||||
(TestOrigin::Root, TestCall::OnlyRoot(..))
|
||||
| (TestOrigin::Parachain(_), TestCall::OnlyParachain(_, _, None))
|
||||
| (TestOrigin::Signed(_), TestCall::OnlySigned(_, _, None))
|
||||
| (_, TestCall::Any(..))
|
||||
=> true,
|
||||
|
||||
_ => false,
|
||||
} {
|
||||
Ok(post_info)
|
||||
@@ -151,7 +156,7 @@ pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> {
|
||||
X1(Parachain(id)) => 1000 + id as u64,
|
||||
// Self at 3000
|
||||
Null => 3000,
|
||||
// Parent at 3000
|
||||
// Parent at 3001
|
||||
X1(Parent) => 3001,
|
||||
l => return Err(l),
|
||||
})
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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};
|
||||
@@ -21,8 +23,7 @@ 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`.
|
||||
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`.
|
||||
pub struct SovereignSignedViaLocation<LocationConverter, Origin>(
|
||||
PhantomData<(LocationConverter, Origin)>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user