mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 12:51:02 +00:00
cargo +nightly fmt (#3540)
* cargo +nightly fmt * add cargo-fmt check to ci * update ci * fmt * fmt * skip macro * ignore bridges
This commit is contained in:
@@ -18,23 +18,23 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::{prelude::*, marker::PhantomData, convert::TryInto, boxed::Box, vec};
|
||||
use codec::{Encode, Decode};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait};
|
||||
use sp_runtime::{traits::BadOrigin, RuntimeDebug};
|
||||
use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec};
|
||||
use xcm::v0::prelude::*;
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
use sp_runtime::{RuntimeDebug, traits::BadOrigin};
|
||||
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get, Contains};
|
||||
|
||||
pub use pallet::*;
|
||||
use frame_support::PalletId;
|
||||
pub use pallet::*;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use xcm_executor::traits::WeightBounds;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
use xcm_executor::traits::WeightBounds;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
@@ -48,7 +48,7 @@ pub mod pallet {
|
||||
|
||||
/// Required origin for sending XCM messages. If successful, the it resolves to `MultiLocation`
|
||||
/// which exists as an interior location within this chain's XCM context.
|
||||
type SendXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
|
||||
type SendXcmOrigin: EnsureOrigin<Self::Origin, Success = MultiLocation>;
|
||||
|
||||
/// The type used to actually dispatch an XCM to its destination.
|
||||
type XcmRouter: SendXcm;
|
||||
@@ -56,7 +56,7 @@ pub mod pallet {
|
||||
/// Required origin for executing XCM messages, including the teleport functionality. If successful,
|
||||
/// then it resolves to `MultiLocation` which exists as an interior location within this chain's XCM
|
||||
/// context.
|
||||
type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
|
||||
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>)>;
|
||||
@@ -99,11 +99,12 @@ pub mod pallet {
|
||||
#[pallet::weight(100_000_000)]
|
||||
pub fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult {
|
||||
let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
|
||||
Self::send_xcm(origin_location.clone(), dest.clone(), message.clone())
|
||||
.map_err(|e| match e {
|
||||
Self::send_xcm(origin_location.clone(), dest.clone(), message.clone()).map_err(
|
||||
|e| match e {
|
||||
XcmError::CannotReachDestination(..) => Error::<T>::Unreachable,
|
||||
_ => Error::<T>::SendFailure,
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
Self::deposit_event(Event::Sent(origin_location, dest, message));
|
||||
Ok(())
|
||||
}
|
||||
@@ -143,27 +144,26 @@ pub mod pallet {
|
||||
let (origin_location, assets) = value;
|
||||
let mut message = Xcm::WithdrawAsset {
|
||||
assets,
|
||||
effects: vec![
|
||||
InitiateTeleport {
|
||||
assets: vec![ All ],
|
||||
dest,
|
||||
effects: vec![
|
||||
BuyExecution {
|
||||
fees: All,
|
||||
// Zero weight for additional XCM (since there are none to execute)
|
||||
weight: 0,
|
||||
debt: dest_weight,
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![ All ], dest: beneficiary },
|
||||
],
|
||||
},
|
||||
],
|
||||
effects: vec![InitiateTeleport {
|
||||
assets: vec![All],
|
||||
dest,
|
||||
effects: vec![
|
||||
BuyExecution {
|
||||
fees: All,
|
||||
// Zero weight for additional XCM (since there are none to execute)
|
||||
weight: 0,
|
||||
debt: dest_weight,
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![All], dest: beneficiary },
|
||||
],
|
||||
}],
|
||||
};
|
||||
let weight = T::Weigher::weight(&mut message)
|
||||
.map_err(|()| Error::<T>::UnweighableMessage)?;
|
||||
let outcome = T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight);
|
||||
let weight =
|
||||
T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?;
|
||||
let outcome =
|
||||
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight);
|
||||
Self::deposit_event(Event::Attempted(outcome));
|
||||
Ok(())
|
||||
}
|
||||
@@ -211,12 +211,13 @@ pub mod pallet {
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![ All ], dest: beneficiary },
|
||||
DepositAsset { assets: vec![All], dest: beneficiary },
|
||||
],
|
||||
};
|
||||
let weight = T::Weigher::weight(&mut message)
|
||||
.map_err(|()| Error::<T>::UnweighableMessage)?;
|
||||
let outcome = T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight);
|
||||
let weight =
|
||||
T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?;
|
||||
let outcome =
|
||||
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight);
|
||||
Self::deposit_event(Event::Attempted(outcome));
|
||||
Ok(())
|
||||
}
|
||||
@@ -233,9 +234,11 @@ pub mod pallet {
|
||||
/// NOTE: A successful return to this does *not* imply that the `msg` was executed successfully
|
||||
/// to completion; only that *some* of it was executed.
|
||||
#[pallet::weight(max_weight.saturating_add(100_000_000u64))]
|
||||
pub fn execute(origin: OriginFor<T>, message: Box<Xcm<T::Call>>, max_weight: Weight)
|
||||
-> DispatchResult
|
||||
{
|
||||
pub fn execute(
|
||||
origin: OriginFor<T>,
|
||||
message: Box<Xcm<T::Call>>,
|
||||
max_weight: Weight,
|
||||
) -> DispatchResult {
|
||||
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
|
||||
let value = (origin_location, *message);
|
||||
ensure!(T::XcmExecuteFilter::contains(&value), Error::<T>::Filtered);
|
||||
@@ -249,7 +252,11 @@ pub mod pallet {
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
|
||||
/// location. A null `dest` is not handled.
|
||||
pub fn send_xcm(interior: MultiLocation, dest: MultiLocation, message: Xcm<()>) -> Result<(), XcmError> {
|
||||
pub fn send_xcm(
|
||||
interior: MultiLocation,
|
||||
dest: MultiLocation,
|
||||
message: Xcm<()>,
|
||||
) -> Result<(), XcmError> {
|
||||
let message = match interior {
|
||||
MultiLocation::Null => message,
|
||||
who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) },
|
||||
@@ -282,7 +289,8 @@ pub mod pallet {
|
||||
/// Ensure that the origin `o` represents a sibling parachain.
|
||||
/// Returns `Ok` with the parachain ID of the sibling or an `Err` otherwise.
|
||||
pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigin>
|
||||
where OuterOrigin: Into<Result<Origin, OuterOrigin>>
|
||||
where
|
||||
OuterOrigin: Into<Result<Origin, OuterOrigin>>,
|
||||
{
|
||||
match o.into() {
|
||||
Ok(Origin::Xcm(location)) => Ok(location),
|
||||
@@ -295,7 +303,9 @@ pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigi
|
||||
///
|
||||
/// May reasonably be used with `EnsureXcm`.
|
||||
pub struct IsMajorityOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>);
|
||||
impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> for IsMajorityOfBody<Prefix, Body> {
|
||||
impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation>
|
||||
for IsMajorityOfBody<Prefix, Body>
|
||||
{
|
||||
fn filter(l: &MultiLocation) -> bool {
|
||||
let maybe_suffix = l.match_and_split(&Prefix::get());
|
||||
matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part.is_majority())
|
||||
@@ -306,19 +316,21 @@ impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> for Is
|
||||
/// `Origin::Xcm` item.
|
||||
pub struct EnsureXcm<F>(PhantomData<F>);
|
||||
impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> for EnsureXcm<F>
|
||||
where O::PalletsOrigin: From<Origin> + TryInto<Origin, Error=O::PalletsOrigin>
|
||||
where
|
||||
O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>,
|
||||
{
|
||||
type Success = MultiLocation;
|
||||
|
||||
fn try_origin(outer: O) -> Result<Self::Success, O> {
|
||||
outer.try_with_caller(|caller| caller.try_into()
|
||||
.and_then(|Origin::Xcm(location)|
|
||||
outer.try_with_caller(|caller| {
|
||||
caller.try_into().and_then(|Origin::Xcm(location)| {
|
||||
if F::filter(&location) {
|
||||
Ok(location)
|
||||
} else {
|
||||
Err(Origin::Xcm(location).into())
|
||||
}
|
||||
))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
@@ -330,9 +342,7 @@ impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> fo
|
||||
/// A simple passthrough where we reuse the `MultiLocation`-typed XCM origin as the inner value of
|
||||
/// this crate's `Origin::Xcm` value.
|
||||
pub struct XcmPassthrough<Origin>(PhantomData<Origin>);
|
||||
impl<
|
||||
Origin: From<crate::Origin>,
|
||||
> ConvertOrigin<Origin> for XcmPassthrough<Origin> {
|
||||
impl<Origin: From<crate::Origin>> ConvertOrigin<Origin> for XcmPassthrough<Origin> {
|
||||
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
|
||||
match (kind, origin) {
|
||||
(OriginKind::Xcm, l) => Ok(crate::Origin::Xcm(l).into()),
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use parity_scale_codec::{Encode, Decode, DecodeLimit};
|
||||
use parity_scale_codec::{Decode, DecodeLimit, Encode};
|
||||
|
||||
/// Maximum nesting level for XCM decoding.
|
||||
pub const MAX_XCM_DECODE_DEPTH: u32 = 8;
|
||||
@@ -32,16 +32,22 @@ pub struct DoubleEncoded<T> {
|
||||
}
|
||||
|
||||
impl<T> Clone for DoubleEncoded<T> {
|
||||
fn clone(&self) -> Self { Self { encoded: self.encoded.clone(), decoded: None } }
|
||||
fn clone(&self) -> Self {
|
||||
Self { encoded: self.encoded.clone(), decoded: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for DoubleEncoded<T> {
|
||||
fn eq(&self, other: &Self) -> bool { self.encoded.eq(&other.encoded) }
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.encoded.eq(&other.encoded)
|
||||
}
|
||||
}
|
||||
impl<T> Eq for DoubleEncoded<T> {}
|
||||
|
||||
impl<T> core::fmt::Debug for DoubleEncoded<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.encoded.fmt(f) }
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.encoded.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<u8>> for DoubleEncoded<T> {
|
||||
@@ -51,13 +57,12 @@ impl<T> From<Vec<u8>> for DoubleEncoded<T> {
|
||||
}
|
||||
|
||||
impl<T> DoubleEncoded<T> {
|
||||
pub fn into<S>(self) -> DoubleEncoded<S> { DoubleEncoded::from(self) }
|
||||
pub fn into<S>(self) -> DoubleEncoded<S> {
|
||||
DoubleEncoded::from(self)
|
||||
}
|
||||
|
||||
pub fn from<S>(e: DoubleEncoded<S>) -> Self {
|
||||
Self {
|
||||
encoded: e.encoded,
|
||||
decoded: None,
|
||||
}
|
||||
Self { encoded: e.encoded, decoded: None }
|
||||
}
|
||||
|
||||
/// Provides an API similar to `AsRef` that provides access to the inner value.
|
||||
@@ -72,22 +77,20 @@ impl<T: Decode> DoubleEncoded<T> {
|
||||
/// Returns a reference to the value in case of success and `Err(())` in case the decoding fails.
|
||||
pub fn ensure_decoded(&mut self) -> Result<&T, ()> {
|
||||
if self.decoded.is_none() {
|
||||
self.decoded = T::decode_all_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut &self.encoded[..],
|
||||
).ok();
|
||||
self.decoded =
|
||||
T::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut &self.encoded[..]).ok();
|
||||
}
|
||||
self.decoded.as_ref().ok_or(())
|
||||
}
|
||||
|
||||
/// Move the decoded value out or (if not present) decode `encoded`.
|
||||
pub fn take_decoded(&mut self) -> Result<T, ()> {
|
||||
self.decoded.take().or_else(|| {
|
||||
T::decode_all_with_depth_limit(
|
||||
MAX_XCM_DECODE_DEPTH,
|
||||
&mut &self.encoded[..],
|
||||
).ok()
|
||||
}).ok_or(())
|
||||
self.decoded
|
||||
.take()
|
||||
.or_else(|| {
|
||||
T::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut &self.encoded[..]).ok()
|
||||
})
|
||||
.ok_or(())
|
||||
}
|
||||
|
||||
/// Provides an API similar to `TryInto` that allows fallible conversion to the inner value type.
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
pub mod v0;
|
||||
|
||||
@@ -33,7 +33,7 @@ pub use double_encoded::DoubleEncoded;
|
||||
|
||||
/// A single XCM message, together with its version code.
|
||||
#[derive(Derivative, Encode, Decode)]
|
||||
#[derivative(Clone(bound=""), Eq(bound=""), PartialEq(bound=""), Debug(bound=""))]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum VersionedXcm<Call> {
|
||||
@@ -45,7 +45,7 @@ pub mod opaque {
|
||||
// Everything from v0
|
||||
pub use crate::v0::*;
|
||||
// Then override with the opaque types in v0
|
||||
pub use crate::v0::opaque::{Xcm, Order};
|
||||
pub use crate::v0::opaque::{Order, Xcm};
|
||||
}
|
||||
|
||||
/// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Support data structures for `MultiLocation`, primarily the `Junction` datatype.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use parity_scale_codec::{self, Encode, Decode};
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// A global identifier of an account-bearing consensus system.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
|
||||
@@ -41,7 +41,10 @@ pub enum BodyId {
|
||||
Named(Vec<u8>),
|
||||
/// An indexed body.
|
||||
// TODO: parity-scale-codec#262: Change to be a tuple.
|
||||
Index { #[codec(compact)] id: u32 },
|
||||
Index {
|
||||
#[codec(compact)]
|
||||
id: u32,
|
||||
},
|
||||
/// The unambiguous executive body (for Polkadot, this would be the Polkadot council).
|
||||
Executive,
|
||||
/// The unambiguous technical body (for Polkadot, this would be the Technical Committee).
|
||||
@@ -60,13 +63,31 @@ pub enum BodyPart {
|
||||
/// The body's declaration, under whatever means it decides.
|
||||
Voice,
|
||||
/// A given number of members of the body.
|
||||
Members { #[codec(compact)] count: u32 },
|
||||
Members {
|
||||
#[codec(compact)]
|
||||
count: u32,
|
||||
},
|
||||
/// A given number of members of the body, out of some larger caucus.
|
||||
Fraction { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 },
|
||||
Fraction {
|
||||
#[codec(compact)]
|
||||
nom: u32,
|
||||
#[codec(compact)]
|
||||
denom: u32,
|
||||
},
|
||||
/// No less than the given proportion of members of the body.
|
||||
AtLeastProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 },
|
||||
AtLeastProportion {
|
||||
#[codec(compact)]
|
||||
nom: u32,
|
||||
#[codec(compact)]
|
||||
denom: u32,
|
||||
},
|
||||
/// More than than the given proportion of members of the body.
|
||||
MoreThanProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 },
|
||||
MoreThanProportion {
|
||||
#[codec(compact)]
|
||||
nom: u32,
|
||||
#[codec(compact)]
|
||||
denom: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl BodyPart {
|
||||
@@ -104,7 +125,11 @@ pub enum Junction {
|
||||
/// the context.
|
||||
///
|
||||
/// May be used when the context is a Frame-based chain and includes e.g. an indices pallet.
|
||||
AccountIndex64 { network: NetworkId, #[codec(compact)] index: u64 },
|
||||
AccountIndex64 {
|
||||
network: NetworkId,
|
||||
#[codec(compact)]
|
||||
index: u64,
|
||||
},
|
||||
/// A 20-byte identifier for an account of a specific network that is respected as a sovereign endpoint within
|
||||
/// the context.
|
||||
///
|
||||
@@ -119,7 +144,10 @@ pub enum Junction {
|
||||
/// Usage will vary widely owing to its generality.
|
||||
///
|
||||
/// NOTE: Try to avoid using this and instead use a more specific item.
|
||||
GeneralIndex { #[codec(compact)] id: u128 },
|
||||
GeneralIndex {
|
||||
#[codec(compact)]
|
||||
id: u128,
|
||||
},
|
||||
/// A nondescript datum acting as a key within the context location.
|
||||
///
|
||||
/// Usage will vary widely owing to its generality.
|
||||
@@ -152,16 +180,15 @@ impl Junction {
|
||||
match self {
|
||||
Junction::Parent => false,
|
||||
|
||||
Junction::Parachain(..)
|
||||
| Junction::AccountId32 { .. }
|
||||
| Junction::AccountIndex64 { .. }
|
||||
| Junction::AccountKey20 { .. }
|
||||
| Junction::PalletInstance { .. }
|
||||
| Junction::GeneralIndex { .. }
|
||||
| Junction::GeneralKey(..)
|
||||
| Junction::OnlyChild
|
||||
| Junction::Plurality { .. }
|
||||
=> true,
|
||||
Junction::Parachain(..) |
|
||||
Junction::AccountId32 { .. } |
|
||||
Junction::AccountIndex64 { .. } |
|
||||
Junction::AccountKey20 { .. } |
|
||||
Junction::PalletInstance { .. } |
|
||||
Junction::GeneralIndex { .. } |
|
||||
Junction::GeneralKey(..) |
|
||||
Junction::OnlyChild |
|
||||
Junction::Plurality { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-48
@@ -16,31 +16,37 @@
|
||||
|
||||
//! Version 0 of the Cross-Consensus Message format data structures.
|
||||
|
||||
use core::{result, convert::TryFrom, fmt::Debug};
|
||||
use derivative::Derivative;
|
||||
use crate::{DoubleEncoded, VersionedMultiAsset, VersionedXcm};
|
||||
use alloc::vec::Vec;
|
||||
use parity_scale_codec::{self, Encode, Decode};
|
||||
use crate::{VersionedMultiAsset, DoubleEncoded, VersionedXcm};
|
||||
use core::{convert::TryFrom, fmt::Debug, result};
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
mod junction;
|
||||
mod multi_asset;
|
||||
mod multi_location;
|
||||
mod order;
|
||||
mod traits;
|
||||
pub use junction::{Junction, NetworkId, BodyId, BodyPart};
|
||||
pub use multi_asset::{MultiAsset, AssetInstance};
|
||||
pub use junction::{BodyId, BodyPart, Junction, NetworkId};
|
||||
pub use multi_asset::{AssetInstance, MultiAsset};
|
||||
pub use multi_location::MultiLocation;
|
||||
pub use order::Order;
|
||||
pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome};
|
||||
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm};
|
||||
|
||||
/// A prelude for importing all types typically used when interacting with XCM messages.
|
||||
pub mod prelude {
|
||||
pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart};
|
||||
pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}};
|
||||
pub use super::multi_location::MultiLocation::{self, *};
|
||||
pub use super::order::Order::{self, *};
|
||||
pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome};
|
||||
pub use super::{Xcm::{self, *}, OriginKind};
|
||||
pub use super::{
|
||||
junction::{BodyId, BodyPart, Junction::*, NetworkId},
|
||||
multi_asset::{
|
||||
AssetInstance::{self, *},
|
||||
MultiAsset::{self, *},
|
||||
},
|
||||
multi_location::MultiLocation::{self, *},
|
||||
order::Order::{self, *},
|
||||
traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm},
|
||||
OriginKind,
|
||||
Xcm::{self, *},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode
|
||||
@@ -147,7 +153,11 @@ pub enum Xcm<Call> {
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 3)]
|
||||
QueryResponse { #[codec(compact)] query_id: u64, response: Response },
|
||||
QueryResponse {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
response: Response,
|
||||
},
|
||||
|
||||
/// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the
|
||||
/// ownership of `dest` within this consensus system.
|
||||
@@ -209,9 +219,12 @@ pub enum Xcm<Call> {
|
||||
/// Kind: *System Notification*
|
||||
#[codec(index = 7)]
|
||||
HrmpNewChannelOpenRequest {
|
||||
#[codec(compact)] sender: u32,
|
||||
#[codec(compact)] max_message_size: u32,
|
||||
#[codec(compact)] max_capacity: u32,
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
max_message_size: u32,
|
||||
#[codec(compact)]
|
||||
max_capacity: u32,
|
||||
},
|
||||
|
||||
/// A message to notify about that a previously sent open channel request has been accepted by
|
||||
@@ -225,7 +238,8 @@ pub enum Xcm<Call> {
|
||||
/// Errors:
|
||||
#[codec(index = 8)]
|
||||
HrmpChannelAccepted {
|
||||
#[codec(compact)] recipient: u32,
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to notify that the other party in an open channel decided to close it. In particular,
|
||||
@@ -240,9 +254,12 @@ pub enum Xcm<Call> {
|
||||
/// Errors:
|
||||
#[codec(index = 9)]
|
||||
HrmpChannelClosing {
|
||||
#[codec(compact)] initiator: u32,
|
||||
#[codec(compact)] sender: u32,
|
||||
#[codec(compact)] recipient: u32,
|
||||
#[codec(compact)]
|
||||
initiator: u32,
|
||||
#[codec(compact)]
|
||||
sender: u32,
|
||||
#[codec(compact)]
|
||||
recipient: u32,
|
||||
},
|
||||
|
||||
/// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus
|
||||
@@ -255,10 +272,7 @@ pub enum Xcm<Call> {
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 10)]
|
||||
RelayedFrom {
|
||||
who: MultiLocation,
|
||||
message: alloc::boxed::Box<Xcm<Call>>,
|
||||
},
|
||||
RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<Call>> },
|
||||
}
|
||||
|
||||
impl<Call> From<Xcm<Call>> for VersionedXcm<Call> {
|
||||
@@ -277,32 +291,33 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> {
|
||||
}
|
||||
|
||||
impl<Call> Xcm<Call> {
|
||||
pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) }
|
||||
pub fn into<C>(self) -> Xcm<C> {
|
||||
Xcm::from(self)
|
||||
}
|
||||
pub fn from<C>(xcm: Xcm<C>) -> Self {
|
||||
use Xcm::*;
|
||||
match xcm {
|
||||
WithdrawAsset { assets, effects }
|
||||
=> WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
ReserveAssetDeposit { assets, effects }
|
||||
=> ReserveAssetDeposit { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
TeleportAsset { assets, effects }
|
||||
=> TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
QueryResponse { query_id: u64, response }
|
||||
=> QueryResponse { query_id: u64, response },
|
||||
TransferAsset { assets, dest }
|
||||
=> TransferAsset { assets, dest },
|
||||
TransferReserveAsset { assets, dest, effects }
|
||||
=> TransferReserveAsset { assets, dest, effects },
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity}
|
||||
=> HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity},
|
||||
HrmpChannelAccepted { recipient}
|
||||
=> HrmpChannelAccepted { recipient},
|
||||
HrmpChannelClosing { initiator, sender, recipient}
|
||||
=> HrmpChannelClosing { initiator, sender, recipient},
|
||||
Transact { origin_type, require_weight_at_most, call}
|
||||
=> Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
RelayedFrom { who, message }
|
||||
=> RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) },
|
||||
WithdrawAsset { assets, effects } =>
|
||||
WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
ReserveAssetDeposit { assets, effects } => ReserveAssetDeposit {
|
||||
assets,
|
||||
effects: effects.into_iter().map(Order::into).collect(),
|
||||
},
|
||||
TeleportAsset { assets, effects } =>
|
||||
TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() },
|
||||
QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response },
|
||||
TransferAsset { assets, dest } => TransferAsset { assets, dest },
|
||||
TransferReserveAsset { assets, dest, effects } =>
|
||||
TransferReserveAsset { assets, dest, effects },
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } =>
|
||||
HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity },
|
||||
HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
|
||||
HrmpChannelClosing { initiator, sender, recipient } =>
|
||||
HrmpChannelClosing { initiator, sender, recipient },
|
||||
Transact { origin_type, require_weight_at_most, call } =>
|
||||
Transact { origin_type, require_weight_at_most, call: call.into() },
|
||||
RelayedFrom { who, message } =>
|
||||
RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use core::{result, convert::TryFrom};
|
||||
use alloc::vec::Vec;
|
||||
use core::{convert::TryFrom, result};
|
||||
|
||||
use parity_scale_codec::{self, Encode, Decode};
|
||||
use super::{MultiLocation, VersionedMultiAsset};
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// A general identifier for an instance of a non-fungible asset class.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)]
|
||||
@@ -30,7 +30,10 @@ pub enum AssetInstance {
|
||||
|
||||
/// A compact index. Technically this could be greater than `u128`, but this implementation supports only
|
||||
/// values up to `2**128 - 1`.
|
||||
Index { #[codec(compact)] id: u128 },
|
||||
Index {
|
||||
#[codec(compact)]
|
||||
id: u128,
|
||||
},
|
||||
|
||||
/// A 4-byte fixed-length datum.
|
||||
Array4([u8; 4]),
|
||||
@@ -133,13 +136,21 @@ pub enum MultiAsset {
|
||||
AllConcreteNonFungible { class: MultiLocation },
|
||||
|
||||
/// Some specific `amount` of the fungible asset identified by an abstract `id`.
|
||||
AbstractFungible { id: Vec<u8>, #[codec(compact)] amount: u128 },
|
||||
AbstractFungible {
|
||||
id: Vec<u8>,
|
||||
#[codec(compact)]
|
||||
amount: u128,
|
||||
},
|
||||
|
||||
/// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly.
|
||||
AbstractNonFungible { class: Vec<u8>, instance: AssetInstance },
|
||||
|
||||
/// Some specific `amount` of the fungible asset identified by an concrete `id`.
|
||||
ConcreteFungible { id: MultiLocation, #[codec(compact)] amount: u128 },
|
||||
ConcreteFungible {
|
||||
id: MultiLocation,
|
||||
#[codec(compact)]
|
||||
amount: u128,
|
||||
},
|
||||
|
||||
/// Some specific `instance` of the non-fungible asset whose `class` is identified concretely.
|
||||
ConcreteNonFungible { class: MultiLocation, instance: AssetInstance },
|
||||
@@ -151,30 +162,27 @@ impl MultiAsset {
|
||||
/// Typically can also be inferred by the name starting with `All`.
|
||||
pub fn is_wildcard(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::None
|
||||
| MultiAsset::AbstractFungible {..}
|
||||
| MultiAsset::AbstractNonFungible {..}
|
||||
| MultiAsset::ConcreteFungible {..}
|
||||
| MultiAsset::ConcreteNonFungible {..}
|
||||
=> false,
|
||||
MultiAsset::None |
|
||||
MultiAsset::AbstractFungible { .. } |
|
||||
MultiAsset::AbstractNonFungible { .. } |
|
||||
MultiAsset::ConcreteFungible { .. } |
|
||||
MultiAsset::ConcreteNonFungible { .. } => false,
|
||||
|
||||
MultiAsset::All
|
||||
| MultiAsset::AllFungible
|
||||
| MultiAsset::AllNonFungible
|
||||
| MultiAsset::AllAbstractFungible {..}
|
||||
| MultiAsset::AllConcreteFungible {..}
|
||||
| MultiAsset::AllAbstractNonFungible {..}
|
||||
| MultiAsset::AllConcreteNonFungible {..}
|
||||
=> true,
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllFungible |
|
||||
MultiAsset::AllNonFungible |
|
||||
MultiAsset::AllAbstractFungible { .. } |
|
||||
MultiAsset::AllConcreteFungible { .. } |
|
||||
MultiAsset::AllAbstractNonFungible { .. } |
|
||||
MultiAsset::AllConcreteNonFungible { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_none(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::None
|
||||
| MultiAsset::AbstractFungible { amount: 0, .. }
|
||||
| MultiAsset::ConcreteFungible { amount: 0, .. }
|
||||
=> true,
|
||||
MultiAsset::None |
|
||||
MultiAsset::AbstractFungible { amount: 0, .. } |
|
||||
MultiAsset::ConcreteFungible { amount: 0, .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
@@ -182,13 +190,12 @@ impl MultiAsset {
|
||||
|
||||
fn is_fungible(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::All
|
||||
| MultiAsset::AllFungible
|
||||
| MultiAsset::AllAbstractFungible {..}
|
||||
| MultiAsset::AllConcreteFungible {..}
|
||||
| MultiAsset::AbstractFungible {..}
|
||||
| MultiAsset::ConcreteFungible {..}
|
||||
=> true,
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllFungible |
|
||||
MultiAsset::AllAbstractFungible { .. } |
|
||||
MultiAsset::AllConcreteFungible { .. } |
|
||||
MultiAsset::AbstractFungible { .. } |
|
||||
MultiAsset::ConcreteFungible { .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
@@ -196,13 +203,12 @@ impl MultiAsset {
|
||||
|
||||
fn is_non_fungible(&self) -> bool {
|
||||
match self {
|
||||
MultiAsset::All
|
||||
| MultiAsset::AllNonFungible
|
||||
| MultiAsset::AllAbstractNonFungible {..}
|
||||
| MultiAsset::AllConcreteNonFungible {..}
|
||||
| MultiAsset::AbstractNonFungible {..}
|
||||
| MultiAsset::ConcreteNonFungible {..}
|
||||
=> true,
|
||||
MultiAsset::All |
|
||||
MultiAsset::AllNonFungible |
|
||||
MultiAsset::AllAbstractNonFungible { .. } |
|
||||
MultiAsset::AllConcreteNonFungible { .. } |
|
||||
MultiAsset::AbstractNonFungible { .. } |
|
||||
MultiAsset::ConcreteNonFungible { .. } => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
@@ -211,9 +217,8 @@ impl MultiAsset {
|
||||
fn is_concrete_fungible(&self, id: &MultiLocation) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllFungible => true,
|
||||
MultiAsset::AllConcreteFungible { id: i }
|
||||
| MultiAsset::ConcreteFungible { id: i, .. }
|
||||
=> i == id,
|
||||
MultiAsset::AllConcreteFungible { id: i } |
|
||||
MultiAsset::ConcreteFungible { id: i, .. } => i == id,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
@@ -222,9 +227,8 @@ impl MultiAsset {
|
||||
fn is_abstract_fungible(&self, id: &[u8]) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllFungible => true,
|
||||
MultiAsset::AllAbstractFungible { id: i }
|
||||
| MultiAsset::AbstractFungible { id: i, .. }
|
||||
=> i == id,
|
||||
MultiAsset::AllAbstractFungible { id: i } |
|
||||
MultiAsset::AbstractFungible { id: i, .. } => i == id,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -232,9 +236,8 @@ impl MultiAsset {
|
||||
fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllNonFungible => true,
|
||||
MultiAsset::AllConcreteNonFungible { class: i }
|
||||
| MultiAsset::ConcreteNonFungible { class: i, .. }
|
||||
=> i == class,
|
||||
MultiAsset::AllConcreteNonFungible { class: i } |
|
||||
MultiAsset::ConcreteNonFungible { class: i, .. } => i == class,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -242,14 +245,15 @@ impl MultiAsset {
|
||||
fn is_abstract_non_fungible(&self, class: &[u8]) -> bool {
|
||||
match self {
|
||||
MultiAsset::AllNonFungible => true,
|
||||
MultiAsset::AllAbstractNonFungible { class: i }
|
||||
| MultiAsset::AbstractNonFungible { class: i, .. }
|
||||
=> i == class,
|
||||
MultiAsset::AllAbstractNonFungible { class: i } |
|
||||
MultiAsset::AbstractNonFungible { class: i, .. } => i == class,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_all(&self) -> bool { matches!(self, MultiAsset::All) }
|
||||
fn is_all(&self) -> bool {
|
||||
matches!(self, MultiAsset::All)
|
||||
}
|
||||
|
||||
/// Returns true if `self` is a super-set of the given `inner`.
|
||||
///
|
||||
@@ -259,14 +263,22 @@ impl MultiAsset {
|
||||
use MultiAsset::*;
|
||||
|
||||
// Inner cannot be wild
|
||||
if inner.is_wildcard() { return false }
|
||||
if inner.is_wildcard() {
|
||||
return false
|
||||
}
|
||||
// Everything contains nothing.
|
||||
if inner.is_none() { return true }
|
||||
if inner.is_none() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Everything contains anything.
|
||||
if self.is_all() { return true }
|
||||
if self.is_all() {
|
||||
return true
|
||||
}
|
||||
// Nothing contains nothing.
|
||||
if self.is_none() { return false }
|
||||
if self.is_none() {
|
||||
return false
|
||||
}
|
||||
|
||||
match self {
|
||||
// Anything fungible contains "all fungibles"
|
||||
@@ -296,11 +308,11 @@ impl MultiAsset {
|
||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||
use MultiAsset::*;
|
||||
match self {
|
||||
AllConcreteFungible { ref mut id }
|
||||
| AllConcreteNonFungible { class: ref mut id }
|
||||
| ConcreteFungible { ref mut id, .. }
|
||||
| ConcreteNonFungible { class: ref mut id, .. }
|
||||
=> id.prepend_with(prepend.clone()).map_err(|_| ()),
|
||||
AllConcreteFungible { ref mut id } |
|
||||
AllConcreteNonFungible { class: ref mut id } |
|
||||
ConcreteFungible { ref mut id, .. } |
|
||||
ConcreteNonFungible { class: ref mut id, .. } =>
|
||||
id.prepend_with(prepend.clone()).map_err(|_| ()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
@@ -345,35 +357,39 @@ mod tests {
|
||||
assert!(!AllNonFungible.contains(&AllNonFungible));
|
||||
|
||||
// For fungibles, containing is basically equality, or equal id with higher amount.
|
||||
assert!(
|
||||
!AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![1u8], amount: 99 })
|
||||
);
|
||||
assert!(
|
||||
AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 99 })
|
||||
);
|
||||
assert!(
|
||||
AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 9 })
|
||||
);
|
||||
assert!(
|
||||
!AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 100 })
|
||||
);
|
||||
assert!(!AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![1u8], amount: 99 }));
|
||||
assert!(AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 99 }));
|
||||
assert!(AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 9 }));
|
||||
assert!(!AbstractFungible { id: vec![99u8], amount: 99 }
|
||||
.contains(&AbstractFungible { id: vec![99u8], amount: 100 }));
|
||||
|
||||
// For non-fungibles, containing is equality.
|
||||
assert!(
|
||||
!AbstractNonFungible {class: vec![99u8], instance: AssetInstance::Index { id: 9 } }
|
||||
.contains(&AbstractNonFungible { class: vec![98u8], instance: AssetInstance::Index { id: 9 } })
|
||||
);
|
||||
assert!(
|
||||
!AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 8 } }
|
||||
.contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } })
|
||||
);
|
||||
assert!(
|
||||
AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }
|
||||
.contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } })
|
||||
);
|
||||
assert!(!AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index { id: 9 }
|
||||
}
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![98u8],
|
||||
instance: AssetInstance::Index { id: 9 }
|
||||
}));
|
||||
assert!(!AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index { id: 8 }
|
||||
}
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index { id: 9 }
|
||||
}));
|
||||
assert!(AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index { id: 9 }
|
||||
}
|
||||
.contains(&AbstractNonFungible {
|
||||
class: vec![99u8],
|
||||
instance: AssetInstance::Index { id: 9 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use core::{result, mem, convert::TryFrom};
|
||||
use core::{convert::TryFrom, mem, result};
|
||||
|
||||
use parity_scale_codec::{self, Encode, Decode};
|
||||
use super::Junction;
|
||||
use crate::VersionedMultiLocation;
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// A relative path between state-bearing consensus systems.
|
||||
///
|
||||
@@ -110,13 +110,19 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction)> for Mult
|
||||
MultiLocation::X6(x.0, x.1, x.2, x.3, x.4, x.5)
|
||||
}
|
||||
}
|
||||
impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
|
||||
impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
|
||||
for MultiLocation
|
||||
{
|
||||
fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
|
||||
MultiLocation::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6)
|
||||
}
|
||||
}
|
||||
impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
|
||||
fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
|
||||
impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
|
||||
for MultiLocation
|
||||
{
|
||||
fn from(
|
||||
x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
|
||||
) -> Self {
|
||||
MultiLocation::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7)
|
||||
}
|
||||
}
|
||||
@@ -249,11 +255,13 @@ impl MultiLocation {
|
||||
MultiLocation::X1(a) => (MultiLocation::Null, Some(a)),
|
||||
MultiLocation::X2(a, b) => (MultiLocation::X1(b), Some(a)),
|
||||
MultiLocation::X3(a, b, c) => (MultiLocation::X2(b, c), Some(a)),
|
||||
MultiLocation::X4(a, b, c ,d) => (MultiLocation::X3(b, c, d), Some(a)),
|
||||
MultiLocation::X5(a, b, c ,d, e) => (MultiLocation::X4(b, c, d, e), Some(a)),
|
||||
MultiLocation::X6(a, b, c ,d, e, f) => (MultiLocation::X5(b, c, d, e, f), Some(a)),
|
||||
MultiLocation::X7(a, b, c ,d, e, f, g) => (MultiLocation::X6(b, c, d, e, f, g), Some(a)),
|
||||
MultiLocation::X8(a, b, c ,d, e, f, g, h) => (MultiLocation::X7(b, c, d, e, f, g, h), Some(a)),
|
||||
MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(b, c, d), Some(a)),
|
||||
MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(b, c, d, e), Some(a)),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(b, c, d, e, f), Some(a)),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) =>
|
||||
(MultiLocation::X6(b, c, d, e, f, g), Some(a)),
|
||||
MultiLocation::X8(a, b, c, d, e, f, g, h) =>
|
||||
(MultiLocation::X7(b, c, d, e, f, g, h), Some(a)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,11 +273,13 @@ impl MultiLocation {
|
||||
MultiLocation::X1(a) => (MultiLocation::Null, Some(a)),
|
||||
MultiLocation::X2(a, b) => (MultiLocation::X1(a), Some(b)),
|
||||
MultiLocation::X3(a, b, c) => (MultiLocation::X2(a, b), Some(c)),
|
||||
MultiLocation::X4(a, b, c ,d) => (MultiLocation::X3(a, b, c), Some(d)),
|
||||
MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(a, b, c), Some(d)),
|
||||
MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(a, b, c, d), Some(e)),
|
||||
MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(a, b, c, d, e), Some(f)),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) => (MultiLocation::X6(a, b, c, d, e, f), Some(g)),
|
||||
MultiLocation::X8(a, b, c, d, e, f, g, h) => (MultiLocation::X7(a, b, c, d, e, f, g), Some(h)),
|
||||
MultiLocation::X7(a, b, c, d, e, f, g) =>
|
||||
(MultiLocation::X6(a, b, c, d, e, f), Some(g)),
|
||||
MultiLocation::X8(a, b, c, d, e, f, g, h) =>
|
||||
(MultiLocation::X7(a, b, c, d, e, f, g), Some(h)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,19 +484,30 @@ impl MultiLocation {
|
||||
let mut n = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut n);
|
||||
match n.pushed_with(new) {
|
||||
Ok(result) => { *self = result; Ok(()) }
|
||||
Err(old) => { *self = old; Err(()) }
|
||||
Ok(result) => {
|
||||
*self = result;
|
||||
Ok(())
|
||||
},
|
||||
Err(old) => {
|
||||
*self = old;
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Mutates `self`, prefixing it with `new`. Returns `Err` in case of overflow.
|
||||
pub fn push_front(&mut self, new: Junction) -> result::Result<(), ()> {
|
||||
let mut n = MultiLocation::Null;
|
||||
mem::swap(&mut *self, &mut n);
|
||||
match n.pushed_front_with(new) {
|
||||
Ok(result) => { *self = result; Ok(()) }
|
||||
Err(old) => { *self = old; Err(()) }
|
||||
Ok(result) => {
|
||||
*self = result;
|
||||
Ok(())
|
||||
},
|
||||
Err(old) => {
|
||||
*self = old;
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,10 +579,10 @@ impl MultiLocation {
|
||||
while let Some(j) = iter.next() {
|
||||
if j == &Junction::Parent {
|
||||
match normalized.last() {
|
||||
None | Some(Junction::Parent) => {}
|
||||
None | Some(Junction::Parent) => {},
|
||||
Some(_) => {
|
||||
normalized.take_last();
|
||||
continue;
|
||||
continue
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -572,7 +593,6 @@ impl MultiLocation {
|
||||
core::mem::swap(self, &mut normalized);
|
||||
}
|
||||
|
||||
|
||||
/// Mutate `self` so that it is suffixed with `suffix`. The correct normalized form is returned,
|
||||
/// removing any internal `[Non-Parent, Parent]` combinations.
|
||||
///
|
||||
@@ -596,7 +616,7 @@ impl MultiLocation {
|
||||
let mut suffix = prefix;
|
||||
core::mem::swap(self, &mut suffix);
|
||||
Err(suffix)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,7 +650,7 @@ impl MultiLocation {
|
||||
|
||||
// Pre-pending this prefix would create a multi-location with too many junctions.
|
||||
if self.len() + prefix.len() - 2 * skipped > MAX_MULTILOCATION_LENGTH {
|
||||
return Err(prefix);
|
||||
return Err(prefix)
|
||||
}
|
||||
|
||||
// Here we cancel out `[Non-Parent, Parent]` items (normalization), where
|
||||
@@ -638,21 +658,22 @@ impl MultiLocation {
|
||||
// comes from the front of the original location.
|
||||
//
|
||||
// We calculated already how many of these there should be above.
|
||||
for _ in 0 .. skipped {
|
||||
let _non_parent = prefix.take_last();
|
||||
let _parent = self.take_first();
|
||||
debug_assert!(
|
||||
_non_parent.is_some() && _non_parent != Some(Junction::Parent),
|
||||
"prepend_with should always remove a non-parent from the end of the prefix",
|
||||
);
|
||||
debug_assert!(
|
||||
_parent == Some(Junction::Parent),
|
||||
"prepend_with should always remove a parent from the front of the location",
|
||||
);
|
||||
for _ in 0..skipped {
|
||||
let _non_parent = prefix.take_last();
|
||||
let _parent = self.take_first();
|
||||
debug_assert!(
|
||||
_non_parent.is_some() && _non_parent != Some(Junction::Parent),
|
||||
"prepend_with should always remove a non-parent from the end of the prefix",
|
||||
);
|
||||
debug_assert!(
|
||||
_parent == Some(Junction::Parent),
|
||||
"prepend_with should always remove a parent from the front of the location",
|
||||
);
|
||||
}
|
||||
|
||||
for j in prefix.into_iter_rev() {
|
||||
self.push_front(j).expect("len + prefix minus 2*skipped is less than max length; qed");
|
||||
self.push_front(j)
|
||||
.expect("len + prefix minus 2*skipped is less than max length; qed");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -734,7 +755,16 @@ mod tests {
|
||||
|
||||
// Can handle shared prefix and resizing correctly.
|
||||
let mut m = X1(Parent);
|
||||
let prefix = X8(Parachain(100), OnlyChild, OnlyChild, OnlyChild, OnlyChild, OnlyChild, OnlyChild, Parent);
|
||||
let prefix = X8(
|
||||
Parachain(100),
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
OnlyChild,
|
||||
Parent,
|
||||
);
|
||||
assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
|
||||
assert_eq!(m, X5(Parachain(100), OnlyChild, OnlyChild, OnlyChild, OnlyChild));
|
||||
|
||||
@@ -783,8 +813,8 @@ mod tests {
|
||||
m.canonicalize();
|
||||
assert_eq!(m, Null);
|
||||
|
||||
let mut m = X4( Parent, Parent, Parachain(1), Parachain(2));
|
||||
let mut m = X4(Parent, Parent, Parachain(1), Parachain(2));
|
||||
m.canonicalize();
|
||||
assert_eq!(m, X4( Parent, Parent, Parachain(1), Parachain(2)));
|
||||
assert_eq!(m, X4(Parent, Parent, Parachain(1), Parachain(2)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
//! Version 0 of the Cross-Consensus Message format data structures.
|
||||
|
||||
use super::{MultiAsset, MultiLocation, Xcm};
|
||||
use alloc::vec::Vec;
|
||||
use derivative::Derivative;
|
||||
use parity_scale_codec::{self, Encode, Decode};
|
||||
use super::{MultiAsset, MultiLocation, Xcm};
|
||||
use parity_scale_codec::{self, Decode, Encode};
|
||||
|
||||
/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages.
|
||||
#[derive(Derivative, Encode, Decode)]
|
||||
#[derivative(Clone(bound=""), Eq(bound=""), PartialEq(bound=""), Debug(bound=""))]
|
||||
#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
pub enum Order<Call> {
|
||||
@@ -77,7 +77,11 @@ pub enum Order<Call> {
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 4)]
|
||||
InitiateReserveWithdraw { assets: Vec<MultiAsset>, reserve: MultiLocation, effects: Vec<Order<()>> },
|
||||
InitiateReserveWithdraw {
|
||||
assets: Vec<MultiAsset>,
|
||||
reserve: MultiLocation,
|
||||
effects: Vec<Order<()>>,
|
||||
},
|
||||
|
||||
/// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location.
|
||||
///
|
||||
@@ -99,14 +103,25 @@ pub enum Order<Call> {
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 6)]
|
||||
QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: Vec<MultiAsset> },
|
||||
QueryHolding {
|
||||
#[codec(compact)]
|
||||
query_id: u64,
|
||||
dest: MultiLocation,
|
||||
assets: Vec<MultiAsset>,
|
||||
},
|
||||
|
||||
/// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with
|
||||
/// up to `fees` from the holding account.
|
||||
///
|
||||
/// Errors:
|
||||
#[codec(index = 7)]
|
||||
BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> },
|
||||
BuyExecution {
|
||||
fees: MultiAsset,
|
||||
weight: u64,
|
||||
debt: u64,
|
||||
halt_on_error: bool,
|
||||
xcm: Vec<Xcm<Call>>,
|
||||
},
|
||||
}
|
||||
|
||||
pub mod opaque {
|
||||
@@ -114,23 +129,22 @@ pub mod opaque {
|
||||
}
|
||||
|
||||
impl<Call> Order<Call> {
|
||||
pub fn into<C>(self) -> Order<C> { Order::from(self) }
|
||||
pub fn into<C>(self) -> Order<C> {
|
||||
Order::from(self)
|
||||
}
|
||||
pub fn from<C>(order: Order<C>) -> Self {
|
||||
use Order::*;
|
||||
match order {
|
||||
Null => Null,
|
||||
DepositAsset { assets, dest }
|
||||
=> DepositAsset { assets, dest },
|
||||
DepositReserveAsset { assets, dest, effects }
|
||||
=> DepositReserveAsset { assets, dest, effects },
|
||||
ExchangeAsset { give, receive }
|
||||
=> ExchangeAsset { give, receive },
|
||||
InitiateReserveWithdraw { assets, reserve, effects }
|
||||
=> InitiateReserveWithdraw { assets, reserve, effects },
|
||||
InitiateTeleport { assets, dest, effects }
|
||||
=> InitiateTeleport { assets, dest, effects },
|
||||
QueryHolding { query_id, dest, assets }
|
||||
=> QueryHolding { query_id, dest, assets },
|
||||
DepositAsset { assets, dest } => DepositAsset { assets, dest },
|
||||
DepositReserveAsset { assets, dest, effects } =>
|
||||
DepositReserveAsset { assets, dest, effects },
|
||||
ExchangeAsset { give, receive } => ExchangeAsset { give, receive },
|
||||
InitiateReserveWithdraw { assets, reserve, effects } =>
|
||||
InitiateReserveWithdraw { assets, reserve, effects },
|
||||
InitiateTeleport { assets, dest, effects } =>
|
||||
InitiateTeleport { assets, dest, effects },
|
||||
QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets },
|
||||
BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
let xcm = xcm.into_iter().map(Xcm::from).collect();
|
||||
BuyExecution { fees, weight, debt, halt_on_error, xcm }
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Cross-Consensus Message format data structures.
|
||||
|
||||
use core::result;
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
use super::{MultiLocation, Xcm};
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//! 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;
|
||||
use sp_std::{marker::PhantomData, result::Result};
|
||||
use xcm::v0::{Junction, MultiLocation, Order, Xcm};
|
||||
use xcm_executor::traits::{OnResponse, ShouldExecute};
|
||||
|
||||
/// Execution barrier that just takes `shallow_weight` from `weight_credit`.
|
||||
pub struct TakeWeightCredit;
|
||||
@@ -51,14 +51,14 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
|
||||
ensure!(T::contains(origin), ());
|
||||
ensure!(top_level, ());
|
||||
match message {
|
||||
Xcm::TeleportAsset { effects, .. }
|
||||
| Xcm::WithdrawAsset { effects, ..}
|
||||
| Xcm::ReserveAssetDeposit { effects, ..}
|
||||
if matches!(
|
||||
Xcm::TeleportAsset { effects, .. } |
|
||||
Xcm::WithdrawAsset { effects, .. } |
|
||||
Xcm::ReserveAssetDeposit { effects, .. }
|
||||
if matches!(
|
||||
effects.first(),
|
||||
Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight
|
||||
)
|
||||
=> Ok(()),
|
||||
) =>
|
||||
Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -82,9 +82,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>,
|
||||
> Contains<MultiLocation> for IsChildSystemParachain<ParaId> {
|
||||
impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemParachain<ParaId> {
|
||||
fn contains(l: &MultiLocation) -> bool {
|
||||
matches!(l, MultiLocation::X1(Junction::Parachain(id)) if ParaId::from(*id).is_system())
|
||||
}
|
||||
@@ -101,8 +99,9 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res
|
||||
_weight_credit: &mut Weight,
|
||||
) -> Result<(), ()> {
|
||||
match message {
|
||||
Xcm::QueryResponse { query_id, .. } if ResponseHandler::expecting_response(origin, *query_id)
|
||||
=> Ok(()),
|
||||
Xcm::QueryResponse { query_id, .. }
|
||||
if ResponseHandler::expecting_response(origin, *query_id) =>
|
||||
Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
//! 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};
|
||||
use frame_support::traits::{ExistenceRequirement::AllowDeath, WithdrawReasons, Get};
|
||||
use xcm_executor::traits::{MatchesFungible, Convert, TransactAsset};
|
||||
use xcm_executor::Assets;
|
||||
use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons};
|
||||
use sp_runtime::traits::{CheckedSub, SaturatedConversion};
|
||||
use sp_std::{convert::TryInto, marker::PhantomData, result};
|
||||
use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result};
|
||||
use xcm_executor::{
|
||||
traits::{Convert, MatchesFungible, TransactAsset},
|
||||
Assets,
|
||||
};
|
||||
|
||||
/// Asset transaction errors.
|
||||
enum Error {
|
||||
@@ -39,7 +41,8 @@ impl From<Error> for XcmError {
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::AssetNotFound,
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed => FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,26 +84,33 @@ impl From<Error> for XcmError {
|
||||
/// >;
|
||||
/// ```
|
||||
pub struct CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>(
|
||||
PhantomData<(Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount)>
|
||||
PhantomData<(Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount)>,
|
||||
);
|
||||
|
||||
impl<
|
||||
Matcher: MatchesFungible<Currency::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
Currency: frame_support::traits::Currency<AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckedAccount: Get<Option<AccountId>>,
|
||||
> TransactAsset for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount> {
|
||||
Matcher: MatchesFungible<Currency::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
Currency: frame_support::traits::Currency<AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckedAccount: Get<Option<AccountId>>,
|
||||
> TransactAsset
|
||||
for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId, CheckedAccount>
|
||||
{
|
||||
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
// Check we handle this asset.
|
||||
let amount: Currency::Balance = Matcher::matches_fungible(what)
|
||||
.ok_or(Error::AssetNotFound)?;
|
||||
let amount: Currency::Balance =
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
if let Some(checked_account) = CheckedAccount::get() {
|
||||
let new_balance = Currency::free_balance(&checked_account)
|
||||
.checked_sub(&amount)
|
||||
.ok_or(XcmError::NotWithdrawable)?;
|
||||
Currency::ensure_can_withdraw(&checked_account, amount, WithdrawReasons::TRANSFER, new_balance)
|
||||
.map_err(|_| XcmError::NotWithdrawable)?;
|
||||
Currency::ensure_can_withdraw(
|
||||
&checked_account,
|
||||
amount,
|
||||
WithdrawReasons::TRANSFER,
|
||||
new_balance,
|
||||
)
|
||||
.map_err(|_| XcmError::NotWithdrawable)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -108,8 +118,17 @@ impl<
|
||||
fn check_in(_origin: &MultiLocation, what: &MultiAsset) {
|
||||
if let Some(amount) = Matcher::matches_fungible(what) {
|
||||
if let Some(checked_account) = CheckedAccount::get() {
|
||||
let ok = Currency::withdraw(&checked_account, amount, WithdrawReasons::TRANSFER, AllowDeath).is_ok();
|
||||
debug_assert!(ok, "`can_check_in` must have returned `true` immediately prior; qed");
|
||||
let ok = Currency::withdraw(
|
||||
&checked_account,
|
||||
amount,
|
||||
WithdrawReasons::TRANSFER,
|
||||
AllowDeath,
|
||||
)
|
||||
.is_ok();
|
||||
debug_assert!(
|
||||
ok,
|
||||
"`can_check_in` must have returned `true` immediately prior; qed"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,31 +143,24 @@ impl<
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
// Check we handle this asset.
|
||||
let amount: u128 = Matcher::matches_fungible(&what)
|
||||
.ok_or(Error::AssetNotFound)?
|
||||
.saturated_into();
|
||||
let who = AccountIdConverter::convert_ref(who)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount = amount
|
||||
.try_into()
|
||||
.map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let amount: u128 =
|
||||
Matcher::matches_fungible(&what).ok_or(Error::AssetNotFound)?.saturated_into();
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount =
|
||||
amount.try_into().map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let _imbalance = Currency::deposit_creating(&who, balance_amount);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> result::Result<Assets, XcmError> {
|
||||
// Check we handle this asset.
|
||||
let amount: u128 = Matcher::matches_fungible(what)
|
||||
.ok_or(Error::AssetNotFound)?
|
||||
.saturated_into();
|
||||
let who = AccountIdConverter::convert_ref(who)
|
||||
.map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount = amount
|
||||
.try_into()
|
||||
.map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
let amount: u128 =
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?.saturated_into();
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let balance_amount =
|
||||
amount.try_into().map_err(|_| Error::AmountToBalanceConversionFailed)?;
|
||||
Currency::withdraw(&who, balance_amount, WithdrawReasons::TRANSFER, AllowDeath)
|
||||
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
|
||||
Ok(what.clone().into())
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
//! Various implementations of `FilterAssetLocation`.
|
||||
|
||||
use frame_support::traits::Get;
|
||||
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.
|
||||
|
||||
@@ -16,20 +16,20 @@
|
||||
|
||||
//! 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, MatchesFungibles, Error as MatchError};
|
||||
use frame_support::traits::{tokens::fungibles, Contains, Get};
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result};
|
||||
use xcm::v0::{Error as XcmError, Junction, MultiAsset, MultiLocation, Result};
|
||||
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, TransactAsset};
|
||||
|
||||
/// 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>,
|
||||
AssetId: Clone,
|
||||
ConvertAssetId: Convert<u128, AssetId>,
|
||||
> Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId> {
|
||||
pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>(
|
||||
PhantomData<(Prefix, AssetId, ConvertAssetId)>,
|
||||
);
|
||||
impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, AssetId>>
|
||||
Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>
|
||||
{
|
||||
fn convert_ref(id: impl Borrow<MultiLocation>) -> result::Result<AssetId, ()> {
|
||||
let prefix = Prefix::get();
|
||||
let id = id.borrow();
|
||||
@@ -50,58 +50,63 @@ impl<
|
||||
}
|
||||
|
||||
pub struct ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance> for
|
||||
ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (id, amount) = match a {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (id, amount),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>(
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>
|
||||
PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<Vec<u8>, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance> for
|
||||
ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
ConvertAssetId: Convert<Vec<u8>, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (id, amount) = match a {
|
||||
MultiAsset::AbstractFungible { id, amount } => (id, amount),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
};
|
||||
let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>(
|
||||
PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>
|
||||
PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>,
|
||||
);
|
||||
impl<
|
||||
Assets: fungibles::Transfer<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
> TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId> {
|
||||
Assets: fungibles::Transfer<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
> TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>
|
||||
{
|
||||
fn transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
@@ -119,17 +124,31 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FungiblesMutateAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>(
|
||||
PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>
|
||||
);
|
||||
pub struct FungiblesMutateAdapter<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>);
|
||||
impl<
|
||||
Assets: fungibles::Mutate<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset for FungiblesMutateAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> {
|
||||
Assets: fungibles::Mutate<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset
|
||||
for FungiblesMutateAdapter<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>
|
||||
{
|
||||
fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
@@ -148,7 +167,10 @@ impl<
|
||||
if CheckAsset::contains(&asset_id) {
|
||||
let checking_account = CheckingAccount::get();
|
||||
let ok = Assets::burn_from(asset_id, &checking_account, amount).is_ok();
|
||||
debug_assert!(ok, "`can_check_in` must have returned `true` immediately prior; qed");
|
||||
debug_assert!(
|
||||
ok,
|
||||
"`can_check_in` must have returned `true` immediately prior; qed"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +196,7 @@ impl<
|
||||
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation
|
||||
who: &MultiLocation,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
// Check we handle this asset.
|
||||
let (asset_id, amount) = Matcher::matches_fungibles(what)?;
|
||||
@@ -186,43 +208,80 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>(
|
||||
PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>
|
||||
);
|
||||
pub struct FungiblesAdapter<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>);
|
||||
impl<
|
||||
Assets: fungibles::Mutate<AccountId> + fungibles::Transfer<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> {
|
||||
Assets: fungibles::Mutate<AccountId> + fungibles::Transfer<AccountId>,
|
||||
Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>,
|
||||
AccountIdConverter: Convert<MultiLocation, AccountId>,
|
||||
AccountId: Clone, // can't get away without it since Currency is generic over it.
|
||||
CheckAsset: Contains<Assets::AssetId>,
|
||||
CheckingAccount: Get<AccountId>,
|
||||
> TransactAsset
|
||||
for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
{
|
||||
fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> Result {
|
||||
FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
::can_check_in(origin, what)
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::can_check_in(origin, what)
|
||||
}
|
||||
|
||||
fn check_in(origin: &MultiLocation, what: &MultiAsset) {
|
||||
FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
::check_in(origin, what)
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::check_in(origin, what)
|
||||
}
|
||||
|
||||
fn check_out(dest: &MultiLocation, what: &MultiAsset) {
|
||||
FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
::check_out(dest, what)
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::check_out(dest, what)
|
||||
}
|
||||
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
|
||||
FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
::deposit_asset(what, who)
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::deposit_asset(what, who)
|
||||
}
|
||||
|
||||
fn withdraw_asset(
|
||||
what: &MultiAsset,
|
||||
who: &MultiLocation
|
||||
who: &MultiLocation,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>
|
||||
::withdraw_asset(what, who)
|
||||
FungiblesMutateAdapter::<
|
||||
Assets,
|
||||
Matcher,
|
||||
AccountIdConverter,
|
||||
AccountId,
|
||||
CheckAsset,
|
||||
CheckingAccount,
|
||||
>::withdraw_asset(what, who)
|
||||
}
|
||||
|
||||
fn transfer_asset(
|
||||
@@ -230,6 +289,8 @@ impl<
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> result::Result<xcm_executor::Assets, XcmError> {
|
||||
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset(what, from, to)
|
||||
FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset(
|
||||
what, from, to,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,21 +27,22 @@ mod tests;
|
||||
|
||||
mod location_conversion;
|
||||
pub use location_conversion::{
|
||||
Account32Hash, ParentIsDefault, ChildParachainConvertsVia, SiblingParachainConvertsVia, AccountId32Aliases,
|
||||
AccountKey20Aliases, LocationInverter,
|
||||
Account32Hash, AccountId32Aliases, AccountKey20Aliases, ChildParachainConvertsVia,
|
||||
LocationInverter, ParentIsDefault, SiblingParachainConvertsVia,
|
||||
};
|
||||
|
||||
mod origin_conversion;
|
||||
pub use origin_conversion::{
|
||||
SovereignSignedViaLocation, ParentAsSuperuser, ChildSystemParachainAsSuperuser, SiblingSystemParachainAsSuperuser,
|
||||
ChildParachainAsNative, SiblingParachainAsNative, RelayChainAsNative, SignedAccountId32AsNative,
|
||||
SignedAccountKey20AsNative, EnsureXcmOrigin, SignedToAccountId32, BackingToPlurality,
|
||||
BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin,
|
||||
ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
|
||||
SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative,
|
||||
SignedToAccountId32, SovereignSignedViaLocation,
|
||||
};
|
||||
|
||||
mod barriers;
|
||||
pub use barriers::{
|
||||
TakeWeightCredit, AllowUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, AllowKnownQueryResponses,
|
||||
IsChildSystemParachain,
|
||||
AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
|
||||
IsChildSystemParachain, TakeWeightCredit,
|
||||
};
|
||||
|
||||
mod currency_adapter;
|
||||
@@ -50,11 +51,11 @@ pub use currency_adapter::CurrencyAdapter;
|
||||
mod fungibles_adapter;
|
||||
pub use fungibles_adapter::{
|
||||
AsPrefixedGeneralIndex, ConvertedAbstractAssetId, ConvertedConcreteAssetId, FungiblesAdapter,
|
||||
FungiblesMutateAdapter, FungiblesTransferAdapter
|
||||
FungiblesMutateAdapter, FungiblesTransferAdapter,
|
||||
};
|
||||
|
||||
mod weight;
|
||||
pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds, UsingComponents, TakeRevenue};
|
||||
pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds, TakeRevenue, UsingComponents};
|
||||
|
||||
mod matches_fungible;
|
||||
pub use matches_fungible::{IsAbstract, IsConcrete};
|
||||
|
||||
@@ -14,19 +14,18 @@
|
||||
// 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, borrow::Borrow};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
use frame_support::traits::Get;
|
||||
use parity_scale_codec::Encode;
|
||||
use xcm::v0::{MultiLocation, NetworkId, Junction};
|
||||
use xcm_executor::traits::{InvertLocation, Convert};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData};
|
||||
use xcm::v0::{Junction, MultiLocation, NetworkId};
|
||||
use xcm_executor::traits::{Convert, InvertLocation};
|
||||
|
||||
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone,
|
||||
> Convert<MultiLocation, AccountId> for Account32Hash<Network, AccountId> {
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for Account32Hash<Network, AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
Ok(("multiloc", location.borrow()).using_encoded(blake2_256).into())
|
||||
}
|
||||
@@ -39,9 +38,9 @@ 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,
|
||||
> Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> {
|
||||
impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId>
|
||||
for ParentIsDefault<AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
if let &MultiLocation::X1(Junction::Parent) = location.borrow() {
|
||||
Ok(AccountId::default())
|
||||
@@ -60,10 +59,9 @@ impl<
|
||||
}
|
||||
|
||||
pub struct ChildParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
|
||||
impl<
|
||||
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
|
||||
AccountId: Clone,
|
||||
> Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId> {
|
||||
impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
|
||||
Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
if let &MultiLocation::X1(Junction::Parachain(id)) = location.borrow() {
|
||||
Ok(ParaId::from(id).into_account())
|
||||
@@ -82,10 +80,9 @@ impl<
|
||||
}
|
||||
|
||||
pub struct SiblingParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
|
||||
impl<
|
||||
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
|
||||
AccountId: Clone,
|
||||
> Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> {
|
||||
impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Clone>
|
||||
Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId>
|
||||
{
|
||||
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
|
||||
if let &MultiLocation::X2(Junction::Parent, Junction::Parachain(id)) = location.borrow() {
|
||||
Ok(ParaId::from(id).into_account())
|
||||
@@ -105,14 +102,15 @@ impl<
|
||||
|
||||
/// Extracts the `AccountId32` from the passed `location` if the network matches.
|
||||
pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone,
|
||||
> Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> {
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId>
|
||||
{
|
||||
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
|
||||
let id = match location {
|
||||
MultiLocation::X1(Junction::AccountId32 { id, network: NetworkId::Any }) => id,
|
||||
MultiLocation::X1(Junction::AccountId32 { id, network }) if &network == &Network::get() => id,
|
||||
MultiLocation::X1(Junction::AccountId32 { id, network })
|
||||
if &network == &Network::get() =>
|
||||
id,
|
||||
l => return Err(l),
|
||||
};
|
||||
Ok(id.into())
|
||||
@@ -124,14 +122,15 @@ impl<
|
||||
}
|
||||
|
||||
pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone,
|
||||
> Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> {
|
||||
impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
|
||||
Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId>
|
||||
{
|
||||
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
|
||||
let key = match location {
|
||||
MultiLocation::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) => key,
|
||||
MultiLocation::X1(Junction::AccountKey20 { key, network }) if &network == &Network::get() => key,
|
||||
MultiLocation::X1(Junction::AccountKey20 { key, network })
|
||||
if &network == &Network::get() =>
|
||||
key,
|
||||
l => return Err(l),
|
||||
};
|
||||
Ok(key.into())
|
||||
@@ -182,7 +181,8 @@ 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()
|
||||
for (i, j) in location
|
||||
.iter_rev()
|
||||
.map(|j| match j {
|
||||
Junction::Parent => ancestry.take_first().unwrap_or(Junction::OnlyChild),
|
||||
_ => Junction::Parent,
|
||||
@@ -200,7 +200,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
use frame_support::parameter_types;
|
||||
use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any};
|
||||
use xcm::v0::{Junction::*, MultiLocation::*, NetworkId::Any};
|
||||
|
||||
fn account20() -> Junction {
|
||||
AccountKey20 { network: Any, key: Default::default() }
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
// output (target to source): ../../para_1/account20_default/account20_default
|
||||
#[test]
|
||||
fn inverter_works_in_tree() {
|
||||
parameter_types!{
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20());
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ mod tests {
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_ancestry_as_inverted_location() {
|
||||
parameter_types!{
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X2(account20(), account20());
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ mod tests {
|
||||
// ^ Target
|
||||
#[test]
|
||||
fn inverter_uses_only_child_on_missing_ancestry() {
|
||||
parameter_types!{
|
||||
parameter_types! {
|
||||
pub Ancestry: MultiLocation = X1(PalletInstance(5));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
//! 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 sp_runtime::traits::CheckedConversion;
|
||||
use sp_std::{convert::TryFrom, marker::PhantomData};
|
||||
use xcm::v0::{MultiAsset, MultiLocation};
|
||||
use xcm_executor::traits::MatchesFungible;
|
||||
|
||||
/// Converts a `MultiAsset` into balance `B` if it is a concrete fungible with an id equal to that
|
||||
|
||||
@@ -14,26 +14,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
pub use sp_std::{fmt::Debug, marker::PhantomData, cell::RefCell};
|
||||
pub use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
|
||||
pub use parity_scale_codec::{Encode, Decode};
|
||||
pub use xcm::v0::{
|
||||
SendXcm, MultiLocation::*, Junction::*, MultiAsset, Xcm, Order, Result as XcmResult, Error as XcmError,
|
||||
OriginKind, MultiLocation, Junction, opaque,
|
||||
pub use crate::{
|
||||
AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
|
||||
FixedRateOfConcreteFungible, FixedWeightBounds, LocationInverter, TakeWeightCredit,
|
||||
};
|
||||
pub use frame_support::{
|
||||
dispatch::{
|
||||
DispatchError, DispatchInfo, DispatchResultWithPostInfo, Dispatchable, Parameter, Weight,
|
||||
},
|
||||
ensure, parameter_types,
|
||||
dispatch::{Dispatchable, Parameter, Weight, DispatchError, DispatchResultWithPostInfo, DispatchInfo},
|
||||
weights::{PostDispatchInfo, GetDispatchInfo},
|
||||
sp_runtime::DispatchErrorWithPostInfo,
|
||||
traits::{Get, Contains, IsInVec},
|
||||
traits::{Contains, Get, IsInVec},
|
||||
weights::{GetDispatchInfo, PostDispatchInfo},
|
||||
};
|
||||
pub use parity_scale_codec::{Decode, Encode};
|
||||
pub use sp_std::{
|
||||
cell::RefCell,
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
};
|
||||
pub use xcm::v0::{
|
||||
opaque, Error as XcmError, Junction, Junction::*, MultiAsset, MultiLocation, MultiLocation::*,
|
||||
Order, OriginKind, Result as XcmResult, SendXcm, Xcm,
|
||||
};
|
||||
pub use xcm_executor::{
|
||||
Assets, Config, traits::{TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse}
|
||||
};
|
||||
pub use crate::{
|
||||
TakeWeightCredit, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedWeightBounds,
|
||||
FixedRateOfConcreteFungible, AllowKnownQueryResponses, LocationInverter,
|
||||
traits::{ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, TransactAsset},
|
||||
Assets, Config,
|
||||
};
|
||||
|
||||
pub enum TestOrigin {
|
||||
@@ -62,20 +69,18 @@ impl Dispatchable for TestCall {
|
||||
fn dispatch(self, origin: Self::Origin) -> DispatchResultWithPostInfo {
|
||||
let mut post_info = PostDispatchInfo::default();
|
||||
post_info.actual_weight = match self {
|
||||
TestCall::OnlyRoot(_, maybe_actual)
|
||||
| TestCall::OnlySigned(_, maybe_actual, _)
|
||||
| TestCall::OnlyParachain(_, maybe_actual, _)
|
||||
| TestCall::Any(_, maybe_actual)
|
||||
=> maybe_actual,
|
||||
TestCall::OnlyRoot(_, maybe_actual) |
|
||||
TestCall::OnlySigned(_, maybe_actual, _) |
|
||||
TestCall::OnlyParachain(_, maybe_actual, _) |
|
||||
TestCall::Any(_, maybe_actual) => 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::Root, TestCall::OnlyRoot(..))
|
||||
| (TestOrigin::Parachain(_), TestCall::OnlyParachain(_, _, None))
|
||||
| (TestOrigin::Signed(_), TestCall::OnlySigned(_, _, None))
|
||||
| (_, TestCall::Any(..))
|
||||
=> true,
|
||||
(TestOrigin::Root, TestCall::OnlyRoot(..)) |
|
||||
(TestOrigin::Parachain(_), TestCall::OnlyParachain(_, _, None)) |
|
||||
(TestOrigin::Signed(_), TestCall::OnlySigned(_, _, None)) |
|
||||
(_, TestCall::Any(..)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
Ok(post_info)
|
||||
@@ -88,13 +93,12 @@ impl Dispatchable for TestCall {
|
||||
impl GetDispatchInfo for TestCall {
|
||||
fn get_dispatch_info(&self) -> DispatchInfo {
|
||||
let weight = *match self {
|
||||
TestCall::OnlyRoot(estimate, ..)
|
||||
| TestCall::OnlyParachain(estimate, ..)
|
||||
| TestCall::OnlySigned(estimate, ..)
|
||||
| TestCall::Any(estimate, ..)
|
||||
=> estimate,
|
||||
TestCall::OnlyRoot(estimate, ..) |
|
||||
TestCall::OnlyParachain(estimate, ..) |
|
||||
TestCall::OnlySigned(estimate, ..) |
|
||||
TestCall::Any(estimate, ..) => estimate,
|
||||
};
|
||||
DispatchInfo { weight, .. Default::default() }
|
||||
DispatchInfo { weight, ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,11 +123,7 @@ pub fn assets(who: u64) -> Vec<MultiAsset> {
|
||||
ASSETS.with(|a| a.borrow().get(&who).map_or(vec![], |a| a.clone().into()))
|
||||
}
|
||||
pub fn add_asset(who: u64, what: MultiAsset) {
|
||||
ASSETS.with(|a| a.borrow_mut()
|
||||
.entry(who)
|
||||
.or_insert(Assets::new())
|
||||
.saturating_subsume(what)
|
||||
);
|
||||
ASSETS.with(|a| a.borrow_mut().entry(who).or_insert(Assets::new()).saturating_subsume(what));
|
||||
}
|
||||
|
||||
pub struct TestAssetTransactor;
|
||||
@@ -136,16 +136,16 @@ impl TransactAsset for TestAssetTransactor {
|
||||
|
||||
fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
let who = to_account(who.clone()).map_err(|_| XcmError::LocationCannotHold)?;
|
||||
ASSETS.with(|a| a.borrow_mut()
|
||||
.get_mut(&who)
|
||||
.ok_or(XcmError::NotWithdrawable)?
|
||||
.try_take(what.clone())
|
||||
.map_err(|()| XcmError::NotWithdrawable)
|
||||
)
|
||||
ASSETS.with(|a| {
|
||||
a.borrow_mut()
|
||||
.get_mut(&who)
|
||||
.ok_or(XcmError::NotWithdrawable)?
|
||||
.try_take(what.clone())
|
||||
.map_err(|()| XcmError::NotWithdrawable)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> {
|
||||
Ok(match l {
|
||||
// Siblings at 2000+id
|
||||
@@ -164,14 +164,17 @@ pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> {
|
||||
|
||||
pub struct TestOriginConverter;
|
||||
impl ConvertOrigin<TestOrigin> for TestOriginConverter {
|
||||
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<TestOrigin, MultiLocation> {
|
||||
fn convert_origin(
|
||||
origin: MultiLocation,
|
||||
kind: OriginKind,
|
||||
) -> Result<TestOrigin, MultiLocation> {
|
||||
use OriginKind::*;
|
||||
match (kind, origin) {
|
||||
(Superuser, _) => Ok(TestOrigin::Root),
|
||||
(SovereignAccount, l) => Ok(TestOrigin::Signed(to_account(l)?)),
|
||||
(Native, X1(Parachain(id))) => Ok(TestOrigin::Parachain(id)),
|
||||
(Native, X1(Parent)) => Ok(TestOrigin::Relay),
|
||||
(Native, X1(AccountIndex64 {index, ..})) => Ok(TestOrigin::Signed(index)),
|
||||
(Native, X1(AccountIndex64 { index, .. })) => Ok(TestOrigin::Signed(index)),
|
||||
(_, origin) => Err(origin),
|
||||
}
|
||||
}
|
||||
@@ -191,17 +194,15 @@ pub fn add_teleporter(from: MultiLocation, asset: MultiAsset) {
|
||||
pub struct TestIsReserve;
|
||||
impl FilterAssetLocation for TestIsReserve {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
IS_RESERVE.with(|r| r.borrow().get(origin)
|
||||
.map_or(false, |v| v.iter().any(|a| a.contains(asset)))
|
||||
)
|
||||
IS_RESERVE
|
||||
.with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.contains(asset))))
|
||||
}
|
||||
}
|
||||
pub struct TestIsTeleporter;
|
||||
impl FilterAssetLocation for TestIsTeleporter {
|
||||
fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool {
|
||||
IS_TELEPORTER.with(|r| r.borrow().get(origin)
|
||||
.map_or(false, |v| v.iter().any(|a| a.contains(asset)))
|
||||
)
|
||||
IS_TELEPORTER
|
||||
.with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.contains(asset))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,28 +224,25 @@ impl OnResponse for TestResponseHandler {
|
||||
}
|
||||
fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::v0::Response) -> Weight {
|
||||
QUERIES.with(|q| {
|
||||
q.borrow_mut()
|
||||
.entry(query_id)
|
||||
.and_modify(|v| if matches!(*v, ResponseSlot::Expecting(..)) {
|
||||
q.borrow_mut().entry(query_id).and_modify(|v| {
|
||||
if matches!(*v, ResponseSlot::Expecting(..)) {
|
||||
*v = ResponseSlot::Received(response);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
10
|
||||
}
|
||||
}
|
||||
pub fn expect_response(query_id: u64, from: MultiLocation) {
|
||||
QUERIES.with(|q| q.borrow_mut()
|
||||
.insert(query_id, ResponseSlot::Expecting(from))
|
||||
);
|
||||
QUERIES.with(|q| q.borrow_mut().insert(query_id, ResponseSlot::Expecting(from)));
|
||||
}
|
||||
pub fn response(query_id: u64) -> Option<Response> {
|
||||
QUERIES.with(|q| q.borrow()
|
||||
.get(&query_id)
|
||||
.and_then(|v| match v {
|
||||
QUERIES.with(|q| {
|
||||
q.borrow().get(&query_id).and_then(|v| match v {
|
||||
ResponseSlot::Received(r) => Some(r.clone()),
|
||||
_ => None,
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
|
||||
@@ -16,21 +16,22 @@
|
||||
|
||||
//! 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_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait};
|
||||
use frame_system::RawOrigin as SystemRawOrigin;
|
||||
use polkadot_parachain::primitives::IsSystem;
|
||||
use sp_std::{convert::TryInto, marker::PhantomData};
|
||||
use xcm::v0::{BodyId, BodyPart, Junction, MultiLocation, NetworkId, OriginKind};
|
||||
use xcm_executor::traits::{Convert, ConvertOrigin};
|
||||
|
||||
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`.
|
||||
pub struct SovereignSignedViaLocation<LocationConverter, Origin>(
|
||||
PhantomData<(LocationConverter, Origin)>
|
||||
PhantomData<(LocationConverter, Origin)>,
|
||||
);
|
||||
impl<
|
||||
LocationConverter: Convert<MultiLocation, Origin::AccountId>,
|
||||
Origin: OriginTrait,
|
||||
> ConvertOrigin<Origin> for SovereignSignedViaLocation<LocationConverter, Origin> where Origin::AccountId: Clone {
|
||||
impl<LocationConverter: Convert<MultiLocation, Origin::AccountId>, Origin: OriginTrait>
|
||||
ConvertOrigin<Origin> for SovereignSignedViaLocation<LocationConverter, Origin>
|
||||
where
|
||||
Origin::AccountId: Clone,
|
||||
{
|
||||
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
|
||||
if let OriginKind::SovereignAccount = kind {
|
||||
let location = LocationConverter::convert(origin)?;
|
||||
@@ -42,27 +43,23 @@ impl<
|
||||
}
|
||||
|
||||
pub struct ParentAsSuperuser<Origin>(PhantomData<Origin>);
|
||||
impl<
|
||||
Origin: OriginTrait,
|
||||
> ConvertOrigin<Origin> for ParentAsSuperuser<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()),
|
||||
(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> {
|
||||
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() =>
|
||||
if ParaId::from(id).is_system() =>
|
||||
Ok(Origin::root()),
|
||||
(_, origin) => Err(origin),
|
||||
}
|
||||
@@ -70,60 +67,53 @@ impl<
|
||||
}
|
||||
|
||||
pub struct SiblingSystemParachainAsSuperuser<ParaId, Origin>(PhantomData<(ParaId, Origin)>);
|
||||
impl<
|
||||
ParaId: IsSystem + From<u32>,
|
||||
Origin: OriginTrait
|
||||
> ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<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()),
|
||||
(
|
||||
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> {
|
||||
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))),
|
||||
(OriginKind::Native, MultiLocation::X1(Junction::Parachain(id))) =>
|
||||
Ok(Origin::from(ParachainOrigin::from(id))),
|
||||
(_, origin) => Err(origin),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SiblingParachainAsNative<ParachainOrigin, Origin>(
|
||||
PhantomData<(ParachainOrigin, Origin)>
|
||||
PhantomData<(ParachainOrigin, Origin)>,
|
||||
);
|
||||
impl<
|
||||
ParachainOrigin: From<u32>,
|
||||
Origin: From<ParachainOrigin>,
|
||||
> ConvertOrigin<Origin> for SiblingParachainAsNative<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))),
|
||||
(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> {
|
||||
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()),
|
||||
@@ -132,41 +122,33 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SignedAccountId32AsNative<Network, Origin>(
|
||||
PhantomData<(Network, Origin)>
|
||||
);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
Origin: OriginTrait,
|
||||
> ConvertOrigin<Origin> for SignedAccountId32AsNative<Network, Origin> where
|
||||
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())),
|
||||
if matches!(network, NetworkId::Any) || network == Network::get() =>
|
||||
Ok(Origin::signed(id.into())),
|
||||
(_, origin) => Err(origin),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SignedAccountKey20AsNative<Network, Origin>(
|
||||
PhantomData<(Network, Origin)>
|
||||
);
|
||||
impl<
|
||||
Network: Get<NetworkId>,
|
||||
Origin: OriginTrait
|
||||
> ConvertOrigin<Origin> for SignedAccountKey20AsNative<Network, Origin> where
|
||||
pub struct SignedAccountKey20AsNative<Network, Origin>(PhantomData<(Network, Origin)>);
|
||||
impl<Network: Get<NetworkId>, Origin: OriginTrait> ConvertOrigin<Origin>
|
||||
for SignedAccountKey20AsNative<Network, Origin>
|
||||
where
|
||||
Origin::AccountId: From<[u8; 20]>,
|
||||
{
|
||||
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
|
||||
match (kind, origin) {
|
||||
(OriginKind::Native, MultiLocation::X1(Junction::AccountKey20 { key, network }))
|
||||
if matches!(network, NetworkId::Any) || network == Network::get() =>
|
||||
{
|
||||
Ok(Origin::signed(key.into()))
|
||||
}
|
||||
Ok(Origin::signed(key.into())),
|
||||
(_, origin) => Err(origin),
|
||||
}
|
||||
}
|
||||
@@ -174,10 +156,9 @@ impl<
|
||||
|
||||
/// `EnsureOrigin` barrier to convert from dispatch origin to XCM origin, if one exists.
|
||||
pub struct EnsureXcmOrigin<Origin, Conversion>(PhantomData<(Origin, Conversion)>);
|
||||
impl<
|
||||
Origin: OriginTrait + Clone,
|
||||
Conversion: Convert<Origin, MultiLocation>,
|
||||
> EnsureOrigin<Origin> for EnsureXcmOrigin<Origin, Conversion> where
|
||||
impl<Origin: OriginTrait + Clone, Conversion: Convert<Origin, MultiLocation>> EnsureOrigin<Origin>
|
||||
for EnsureXcmOrigin<Origin, Conversion>
|
||||
where
|
||||
Origin::PalletsOrigin: PartialEq,
|
||||
{
|
||||
type Success = MultiLocation;
|
||||
@@ -206,15 +187,13 @@ impl<
|
||||
/// Typically used when configuring `pallet-xcm` for allowing normal accounts to dispatch an XCM from an `AccountId32`
|
||||
/// origin.
|
||||
pub struct SignedToAccountId32<Origin, AccountId, Network>(
|
||||
PhantomData<(Origin, AccountId, Network)>
|
||||
PhantomData<(Origin, AccountId, Network)>,
|
||||
);
|
||||
impl<
|
||||
Origin: OriginTrait + Clone,
|
||||
AccountId: Into<[u8; 32]>,
|
||||
Network: Get<NetworkId>,
|
||||
> Convert<Origin, MultiLocation> for SignedToAccountId32<Origin, AccountId, Network> where
|
||||
Origin::PalletsOrigin: From<SystemRawOrigin<AccountId>> +
|
||||
TryInto<SystemRawOrigin<AccountId>, Error=Origin::PalletsOrigin>
|
||||
impl<Origin: OriginTrait + Clone, AccountId: Into<[u8; 32]>, Network: Get<NetworkId>>
|
||||
Convert<Origin, MultiLocation> for SignedToAccountId32<Origin, AccountId, Network>
|
||||
where
|
||||
Origin::PalletsOrigin: From<SystemRawOrigin<AccountId>>
|
||||
+ TryInto<SystemRawOrigin<AccountId>, Error = Origin::PalletsOrigin>,
|
||||
{
|
||||
fn convert(o: Origin) -> Result<MultiLocation, Origin> {
|
||||
o.try_with_caller(|caller| match caller.try_into() {
|
||||
@@ -231,16 +210,11 @@ impl<
|
||||
///
|
||||
/// Typically used when configuring `pallet-xcm` for allowing a collective's Origin to dispatch an XCM from a
|
||||
/// `Plurality` origin.
|
||||
pub struct BackingToPlurality<Origin, COrigin, Body>(
|
||||
PhantomData<(Origin, COrigin, Body)>
|
||||
);
|
||||
impl<
|
||||
Origin: OriginTrait + Clone,
|
||||
COrigin: GetBacking,
|
||||
Body: Get<BodyId>,
|
||||
> Convert<Origin, MultiLocation> for BackingToPlurality<Origin, COrigin, Body> where
|
||||
Origin::PalletsOrigin: From<COrigin> +
|
||||
TryInto<COrigin, Error=Origin::PalletsOrigin>
|
||||
pub struct BackingToPlurality<Origin, COrigin, Body>(PhantomData<(Origin, COrigin, Body)>);
|
||||
impl<Origin: OriginTrait + Clone, COrigin: GetBacking, Body: Get<BodyId>>
|
||||
Convert<Origin, MultiLocation> for BackingToPlurality<Origin, COrigin, Body>
|
||||
where
|
||||
Origin::PalletsOrigin: From<COrigin> + TryInto<COrigin, Error = Origin::PalletsOrigin>,
|
||||
{
|
||||
fn convert(o: Origin) -> Result<MultiLocation, Origin> {
|
||||
o.try_with_caller(|caller| match caller.try_into() {
|
||||
@@ -248,9 +222,10 @@ impl<
|
||||
Some(backing) => Ok(Junction::Plurality {
|
||||
id: Body::get(),
|
||||
part: BodyPart::Fraction { nom: backing.approvals, denom: backing.eligible },
|
||||
}.into()),
|
||||
}
|
||||
.into()),
|
||||
None => Err(co.into()),
|
||||
}
|
||||
},
|
||||
Err(other) => Err(other),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use super::mock::*;
|
||||
use {MultiAsset::*, Option::None};
|
||||
use xcm::v0::{Order, NetworkId::Any, Outcome, Response, ExecuteXcm};
|
||||
use xcm_executor::{XcmExecutor, Config, traits::*};
|
||||
use super::{mock::*, *};
|
||||
use xcm::v0::{ExecuteXcm, NetworkId::Any, Order, Outcome, Response};
|
||||
use xcm_executor::{traits::*, Config, XcmExecutor};
|
||||
use MultiAsset::*;
|
||||
use Option::None;
|
||||
|
||||
#[test]
|
||||
fn basic_setup_works() {
|
||||
@@ -32,8 +32,8 @@ fn basic_setup_works() {
|
||||
assert_eq!(to_account(X1(Parachain(50))), Ok(1050));
|
||||
assert_eq!(to_account(X2(Parent, Parachain(1))), Ok(2001));
|
||||
assert_eq!(to_account(X2(Parent, Parachain(50))), Ok(2050));
|
||||
assert_eq!(to_account(X1(AccountIndex64{index:1, network:Any})), Ok(1));
|
||||
assert_eq!(to_account(X1(AccountIndex64{index:42, network:Any})), Ok(42));
|
||||
assert_eq!(to_account(X1(AccountIndex64 { index: 1, network: Any })), Ok(1));
|
||||
assert_eq!(to_account(X1(AccountIndex64 { index: 42, network: Any })), Ok(42));
|
||||
assert_eq!(to_account(Null), Ok(3000));
|
||||
}
|
||||
|
||||
@@ -42,10 +42,17 @@ fn weigher_should_work() {
|
||||
let mut message = opaque::Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
effects: vec![
|
||||
Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] },
|
||||
Order::BuyExecution {
|
||||
fees: All,
|
||||
weight: 0,
|
||||
debt: 30,
|
||||
halt_on_error: true,
|
||||
xcm: vec![],
|
||||
},
|
||||
Order::DepositAsset { assets: vec![All], dest: Null },
|
||||
],
|
||||
}.into();
|
||||
}
|
||||
.into();
|
||||
assert_eq!(<TestConfig as Config>::Weigher::shallow(&mut message), Ok(30));
|
||||
}
|
||||
|
||||
@@ -57,23 +64,13 @@ fn take_weight_credit_barrier_should_work() {
|
||||
};
|
||||
|
||||
let mut weight_credit = 10;
|
||||
let r = TakeWeightCredit::should_execute(
|
||||
&X1(Parent),
|
||||
true,
|
||||
&mut message,
|
||||
10,
|
||||
&mut weight_credit,
|
||||
);
|
||||
let r =
|
||||
TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit);
|
||||
assert_eq!(r, Ok(()));
|
||||
assert_eq!(weight_credit, 0);
|
||||
|
||||
let r = TakeWeightCredit::should_execute(
|
||||
&X1(Parent),
|
||||
true,
|
||||
&mut message,
|
||||
10,
|
||||
&mut weight_credit,
|
||||
);
|
||||
let r =
|
||||
TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit);
|
||||
assert_eq!(r, Err(()));
|
||||
assert_eq!(weight_credit, 0);
|
||||
}
|
||||
@@ -85,7 +82,7 @@ fn allow_unpaid_should_work() {
|
||||
dest: Null,
|
||||
};
|
||||
|
||||
AllowUnpaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parent)]);
|
||||
|
||||
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
|
||||
&X1(Parachain(1)),
|
||||
@@ -108,7 +105,7 @@ fn allow_unpaid_should_work() {
|
||||
|
||||
#[test]
|
||||
fn allow_paid_should_work() {
|
||||
AllowPaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowPaidFrom::set(vec![X1(Parent)]);
|
||||
|
||||
let mut message = opaque::Xcm::TransferAsset {
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
@@ -127,7 +124,13 @@ fn allow_paid_should_work() {
|
||||
let mut underpaying_message = opaque::Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
effects: vec![
|
||||
Order::BuyExecution { fees: All, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] },
|
||||
Order::BuyExecution {
|
||||
fees: All,
|
||||
weight: 0,
|
||||
debt: 20,
|
||||
halt_on_error: true,
|
||||
xcm: vec![],
|
||||
},
|
||||
Order::DepositAsset { assets: vec![All], dest: Null },
|
||||
],
|
||||
};
|
||||
@@ -144,7 +147,13 @@ fn allow_paid_should_work() {
|
||||
let mut paying_message = opaque::Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
effects: vec![
|
||||
Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] },
|
||||
Order::BuyExecution {
|
||||
fees: All,
|
||||
weight: 0,
|
||||
debt: 30,
|
||||
halt_on_error: true,
|
||||
xcm: vec![],
|
||||
},
|
||||
Order::DepositAsset { assets: vec![All], dest: Null },
|
||||
],
|
||||
};
|
||||
@@ -170,79 +179,88 @@ fn allow_paid_should_work() {
|
||||
|
||||
#[test]
|
||||
fn paying_reserve_deposit_should_work() {
|
||||
AllowPaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowPaidFrom::set(vec![X1(Parent)]);
|
||||
add_reserve(X1(Parent), AllConcreteFungible { id: X1(Parent) });
|
||||
WeightPrice::set((X1(Parent), 1_000_000_000_000));
|
||||
|
||||
let origin = X1(Parent);
|
||||
let message = Xcm::<TestCall>::ReserveAssetDeposit {
|
||||
assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ],
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
effects: vec![
|
||||
Order::<TestCall>::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] },
|
||||
Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: Null },
|
||||
Order::<TestCall>::BuyExecution {
|
||||
fees: All,
|
||||
weight: 0,
|
||||
debt: 30,
|
||||
halt_on_error: true,
|
||||
xcm: vec![],
|
||||
},
|
||||
Order::<TestCall>::DepositAsset { assets: vec![All], dest: Null },
|
||||
],
|
||||
};
|
||||
let weight_limit = 50;
|
||||
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
|
||||
assert_eq!(r, Outcome::Complete(30));
|
||||
assert_eq!(assets(3000), vec![ ConcreteFungible { id: X1(Parent), amount: 70 } ]);
|
||||
assert_eq!(assets(3000), vec![ConcreteFungible { id: X1(Parent), amount: 70 }]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_should_work() {
|
||||
// we'll let them have message execution for free.
|
||||
AllowUnpaidFrom::set(vec![ X1(Parachain(1)) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parachain(1))]);
|
||||
// Child parachain #1 owns 1000 tokens held by us in reserve.
|
||||
add_asset(1001, ConcreteFungible { id: Null, amount: 1000 });
|
||||
// They want to transfer 100 of them to their sibling parachain #2
|
||||
let r = XcmExecutor::<TestConfig>::execute_xcm(
|
||||
X1(Parachain(1)),
|
||||
Xcm::TransferAsset {
|
||||
assets: vec![ ConcreteFungible { id: Null, amount: 100 } ],
|
||||
dest: X1(AccountIndex64{index:3, network:Any}),
|
||||
assets: vec![ConcreteFungible { id: Null, amount: 100 }],
|
||||
dest: X1(AccountIndex64 { index: 3, network: Any }),
|
||||
},
|
||||
50,
|
||||
);
|
||||
assert_eq!(r, Outcome::Complete(10));
|
||||
assert_eq!(assets(3), vec![ ConcreteFungible { id: Null, amount: 100 } ]);
|
||||
assert_eq!(assets(1001), vec![ ConcreteFungible { id: Null, amount: 900 } ]);
|
||||
assert_eq!(assets(3), vec![ConcreteFungible { id: Null, amount: 100 }]);
|
||||
assert_eq!(assets(1001), vec![ConcreteFungible { id: Null, amount: 900 }]);
|
||||
assert_eq!(sent_xcm(), vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserve_transfer_should_work() {
|
||||
AllowUnpaidFrom::set(vec![ X1(Parachain(1)) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parachain(1))]);
|
||||
// Child parachain #1 owns 1000 tokens held by us in reserve.
|
||||
add_asset(1001, ConcreteFungible { id: Null, amount: 1000 });
|
||||
// The remote account owned by gav.
|
||||
let three = X1(AccountIndex64{index:3, network:Any});
|
||||
let three = X1(AccountIndex64 { index: 3, network: Any });
|
||||
|
||||
// They want to transfer 100 of our native asset from sovereign account of parachain #1 into #2
|
||||
// and let them know to hand it to account #3.
|
||||
let r = XcmExecutor::<TestConfig>::execute_xcm(
|
||||
X1(Parachain(1)),
|
||||
Xcm::TransferReserveAsset {
|
||||
assets: vec![ ConcreteFungible { id: Null, amount: 100 } ],
|
||||
assets: vec![ConcreteFungible { id: Null, amount: 100 }],
|
||||
dest: X1(Parachain(2)),
|
||||
effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three.clone() } ],
|
||||
effects: vec![Order::DepositAsset { assets: vec![All], dest: three.clone() }],
|
||||
},
|
||||
50,
|
||||
);
|
||||
assert_eq!(r, Outcome::Complete(10));
|
||||
|
||||
assert_eq!(assets(1002), vec![ ConcreteFungible { id: Null, amount: 100 } ]);
|
||||
assert_eq!(sent_xcm(), vec![(
|
||||
X1(Parachain(2)),
|
||||
Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ],
|
||||
effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three } ],
|
||||
})
|
||||
]);
|
||||
assert_eq!(assets(1002), vec![ConcreteFungible { id: Null, amount: 100 }]);
|
||||
assert_eq!(
|
||||
sent_xcm(),
|
||||
vec![(
|
||||
X1(Parachain(2)),
|
||||
Xcm::ReserveAssetDeposit {
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }],
|
||||
effects: vec![Order::DepositAsset { assets: vec![All], dest: three }],
|
||||
}
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transacting_should_work() {
|
||||
AllowUnpaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parent)]);
|
||||
|
||||
let origin = X1(Parent);
|
||||
let message = Xcm::<TestCall>::Transact {
|
||||
@@ -257,7 +275,7 @@ fn transacting_should_work() {
|
||||
|
||||
#[test]
|
||||
fn transacting_should_respect_max_weight_requirement() {
|
||||
AllowUnpaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parent)]);
|
||||
|
||||
let origin = X1(Parent);
|
||||
let message = Xcm::<TestCall>::Transact {
|
||||
@@ -272,7 +290,7 @@ fn transacting_should_respect_max_weight_requirement() {
|
||||
|
||||
#[test]
|
||||
fn transacting_should_refund_weight() {
|
||||
AllowUnpaidFrom::set(vec![ X1(Parent) ]);
|
||||
AllowUnpaidFrom::set(vec![X1(Parent)]);
|
||||
|
||||
let origin = X1(Parent);
|
||||
let message = Xcm::<TestCall>::Transact {
|
||||
@@ -287,30 +305,34 @@ fn transacting_should_refund_weight() {
|
||||
|
||||
#[test]
|
||||
fn paid_transacting_should_refund_payment_for_unused_weight() {
|
||||
let one = X1(AccountIndex64{index:1, network:Any});
|
||||
AllowPaidFrom::set(vec![ one.clone() ]);
|
||||
let one = X1(AccountIndex64 { index: 1, network: Any });
|
||||
AllowPaidFrom::set(vec![one.clone()]);
|
||||
add_asset(1, ConcreteFungible { id: X1(Parent), amount: 100 });
|
||||
WeightPrice::set((X1(Parent), 1_000_000_000_000));
|
||||
|
||||
let origin = one.clone();
|
||||
let message = Xcm::<TestCall>::WithdrawAsset {
|
||||
assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], // enough for 100 units of weight.
|
||||
assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], // enough for 100 units of weight.
|
||||
effects: vec![
|
||||
Order::<TestCall>::BuyExecution { fees: All, weight: 70, debt: 30, halt_on_error: true, xcm: vec![
|
||||
Xcm::<TestCall>::Transact {
|
||||
Order::<TestCall>::BuyExecution {
|
||||
fees: All,
|
||||
weight: 70,
|
||||
debt: 30,
|
||||
halt_on_error: true,
|
||||
xcm: vec![Xcm::<TestCall>::Transact {
|
||||
origin_type: OriginKind::Native,
|
||||
require_weight_at_most: 60,
|
||||
// call estimated at 70 but only takes 10.
|
||||
call: TestCall::Any(60, Some(10)).encode().into(),
|
||||
}
|
||||
] },
|
||||
Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: one.clone() },
|
||||
}],
|
||||
},
|
||||
Order::<TestCall>::DepositAsset { assets: vec![All], dest: one.clone() },
|
||||
],
|
||||
};
|
||||
let weight_limit = 100;
|
||||
let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit);
|
||||
assert_eq!(r, Outcome::Complete(50));
|
||||
assert_eq!(assets(1), vec![ ConcreteFungible { id: X1(Parent), amount: 50 } ]);
|
||||
assert_eq!(assets(1), vec![ConcreteFungible { id: X1(Parent), amount: 50 }]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -320,11 +342,8 @@ fn prepaid_result_of_query_should_get_free_execution() {
|
||||
// We put this in manually here, but normally this would be done at the point of crafting the message.
|
||||
expect_response(query_id, origin.clone());
|
||||
|
||||
let the_response = Response::Assets(vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ]);
|
||||
let message = Xcm::<TestCall>::QueryResponse {
|
||||
query_id,
|
||||
response: the_response.clone(),
|
||||
};
|
||||
let the_response = Response::Assets(vec![ConcreteFungible { id: X1(Parent), amount: 100 }]);
|
||||
let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() };
|
||||
let weight_limit = 10;
|
||||
|
||||
// First time the response gets through since we're expecting it...
|
||||
|
||||
@@ -14,27 +14,32 @@
|
||||
// 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::Result, marker::PhantomData, convert::TryInto};
|
||||
use frame_support::{
|
||||
traits::{tokens::currency::Currency as CurrencyT, Get, OnUnbalanced as OnUnbalancedT},
|
||||
weights::{GetDispatchInfo, Weight, WeightToFeePolynomial},
|
||||
};
|
||||
use parity_scale_codec::Decode;
|
||||
use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error};
|
||||
use sp_runtime::traits::{Zero, Saturating, SaturatedConversion};
|
||||
use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT};
|
||||
use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial};
|
||||
use xcm_executor::{Assets, traits::{WeightBounds, WeightTrader}};
|
||||
use sp_runtime::traits::{SaturatedConversion, Saturating, Zero};
|
||||
use sp_std::{convert::TryInto, marker::PhantomData, result::Result};
|
||||
use xcm::v0::{Error, MultiAsset, MultiLocation, Order, Xcm};
|
||||
use xcm_executor::{
|
||||
traits::{WeightBounds, WeightTrader},
|
||||
Assets,
|
||||
};
|
||||
|
||||
pub struct FixedWeightBounds<T, C>(PhantomData<(T, C)>);
|
||||
impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeightBounds<T, C> {
|
||||
fn shallow(message: &mut Xcm<C>) -> Result<Weight, ()> {
|
||||
Ok(match message {
|
||||
Xcm::Transact { call, .. } => {
|
||||
call.ensure_decoded()?.get_dispatch_info().weight.saturating_add(T::get())
|
||||
}
|
||||
Xcm::RelayedFrom { ref mut message, .. } => T::get().saturating_add(Self::shallow(message.as_mut())?),
|
||||
Xcm::WithdrawAsset { effects, .. }
|
||||
| Xcm::ReserveAssetDeposit { effects, .. }
|
||||
| Xcm::TeleportAsset { effects, .. }
|
||||
=> {
|
||||
let inner: Weight = effects.iter_mut()
|
||||
Xcm::Transact { call, .. } =>
|
||||
call.ensure_decoded()?.get_dispatch_info().weight.saturating_add(T::get()),
|
||||
Xcm::RelayedFrom { ref mut message, .. } =>
|
||||
T::get().saturating_add(Self::shallow(message.as_mut())?),
|
||||
Xcm::WithdrawAsset { effects, .. } |
|
||||
Xcm::ReserveAssetDeposit { effects, .. } |
|
||||
Xcm::TeleportAsset { effects, .. } => {
|
||||
let inner: Weight = effects
|
||||
.iter_mut()
|
||||
.map(|effect| match effect {
|
||||
Order::BuyExecution { .. } => {
|
||||
// On success, execution of this will result in more weight being consumed but
|
||||
@@ -45,28 +50,29 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
|
||||
T::get()
|
||||
},
|
||||
_ => T::get(),
|
||||
}).sum();
|
||||
})
|
||||
.sum();
|
||||
T::get().saturating_add(inner)
|
||||
}
|
||||
},
|
||||
_ => T::get(),
|
||||
})
|
||||
}
|
||||
fn deep(message: &mut Xcm<C>) -> Result<Weight, ()> {
|
||||
Ok(match message {
|
||||
Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?,
|
||||
Xcm::WithdrawAsset { effects, .. }
|
||||
| Xcm::ReserveAssetDeposit { effects, .. }
|
||||
| Xcm::TeleportAsset { effects, .. }
|
||||
=> {
|
||||
Xcm::WithdrawAsset { effects, .. } |
|
||||
Xcm::ReserveAssetDeposit { effects, .. } |
|
||||
Xcm::TeleportAsset { effects, .. } => {
|
||||
let mut extra = 0;
|
||||
for effect in effects.iter_mut() {
|
||||
match effect {
|
||||
Order::BuyExecution { xcm, .. } => {
|
||||
Order::BuyExecution { xcm, .. } =>
|
||||
for message in xcm.iter_mut() {
|
||||
extra.saturating_accrue(Self::shallow(message)?.saturating_add(Self::deep(message)?));
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
extra.saturating_accrue(
|
||||
Self::shallow(message)?.saturating_add(Self::deep(message)?),
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
extra
|
||||
@@ -92,12 +98,17 @@ impl TakeRevenue for () {
|
||||
///
|
||||
/// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for
|
||||
/// one second of weight.
|
||||
pub struct FixedRateOfConcreteFungible<
|
||||
T: Get<(MultiLocation, u128)>,
|
||||
R: TakeRevenue,
|
||||
>(Weight, u128, PhantomData<(T, R)>);
|
||||
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfConcreteFungible<T, R> {
|
||||
fn new() -> Self { Self(0, 0, PhantomData) }
|
||||
pub struct FixedRateOfConcreteFungible<T: Get<(MultiLocation, u128)>, R: TakeRevenue>(
|
||||
Weight,
|
||||
u128,
|
||||
PhantomData<(T, R)>,
|
||||
);
|
||||
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader
|
||||
for FixedRateOfConcreteFungible<T, R>
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self(0, 0, PhantomData)
|
||||
}
|
||||
|
||||
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
|
||||
let (id, units_per_second) = T::get();
|
||||
@@ -131,20 +142,27 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcrete
|
||||
/// Weight trader which uses the `TransactionPayment` pallet to set the right price for weight and then
|
||||
/// places any weight bought into the right account.
|
||||
pub struct UsingComponents<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
>(Weight, Currency::Balance, PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>);
|
||||
>(
|
||||
Weight,
|
||||
Currency::Balance,
|
||||
PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
|
||||
);
|
||||
impl<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
|
||||
fn new() -> Self { Self(0, Zero::zero(), PhantomData) }
|
||||
WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self(0, Zero::zero(), PhantomData)
|
||||
}
|
||||
|
||||
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
|
||||
let amount = WeightToFee::calc(&weight);
|
||||
@@ -163,21 +181,19 @@ impl<
|
||||
let amount = WeightToFee::calc(&weight);
|
||||
self.0 -= weight;
|
||||
self.1 = self.1.saturating_sub(amount);
|
||||
let result = MultiAsset::ConcreteFungible {
|
||||
amount: amount.saturated_into(),
|
||||
id: AssetId::get(),
|
||||
};
|
||||
let result =
|
||||
MultiAsset::ConcreteFungible { amount: amount.saturated_into(), id: AssetId::get() };
|
||||
result
|
||||
}
|
||||
|
||||
}
|
||||
impl<
|
||||
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
|
||||
WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
|
||||
AssetId: Get<MultiLocation>,
|
||||
AccountId,
|
||||
Currency: CurrencyT<AccountId>,
|
||||
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
|
||||
> Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
OnUnbalanced::on_unbalanced(Currency::issue(self.1));
|
||||
}
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
// 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::{prelude::*, mem, collections::{btree_map::BTreeMap, btree_set::BTreeSet}};
|
||||
use xcm::v0::{MultiAsset, MultiLocation, AssetInstance};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::{
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
mem,
|
||||
prelude::*,
|
||||
};
|
||||
use xcm::v0::{AssetInstance, MultiAsset, MultiLocation};
|
||||
|
||||
/// Classification of an asset being concrete or abstract.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug)]
|
||||
@@ -91,43 +95,43 @@ impl From<MultiAsset> for Assets {
|
||||
|
||||
impl Assets {
|
||||
/// New value, containing no assets.
|
||||
pub fn new() -> Self { Self::default() }
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// An iterator over the fungible assets.
|
||||
pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
self.fungible.iter()
|
||||
.map(|(id, &amount)| match id.clone() {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
})
|
||||
pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
self.fungible.iter().map(|(id, &amount)| match id.clone() {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
})
|
||||
}
|
||||
|
||||
/// An iterator over the non-fungible assets.
|
||||
pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
self.non_fungible.iter()
|
||||
.map(|&(ref class, ref instance)| match class.clone() {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance: instance.clone() },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance: instance.clone() },
|
||||
})
|
||||
pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
self.non_fungible.iter().map(|&(ref class, ref instance)| match class.clone() {
|
||||
AssetId::Concrete(class) =>
|
||||
MultiAsset::ConcreteNonFungible { class, instance: instance.clone() },
|
||||
AssetId::Abstract(class) =>
|
||||
MultiAsset::AbstractNonFungible { class, instance: instance.clone() },
|
||||
})
|
||||
}
|
||||
|
||||
/// An iterator over all assets.
|
||||
pub fn into_assets_iter(self) -> impl Iterator<Item=MultiAsset> {
|
||||
let fungible = self.fungible.into_iter()
|
||||
.map(|(id, amount)| match id {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
});
|
||||
let non_fungible = self.non_fungible.into_iter()
|
||||
.map(|(id, instance)| match id {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance },
|
||||
});
|
||||
pub fn into_assets_iter(self) -> impl Iterator<Item = MultiAsset> {
|
||||
let fungible = self.fungible.into_iter().map(|(id, amount)| match id {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
});
|
||||
let non_fungible = self.non_fungible.into_iter().map(|(id, instance)| match id {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance },
|
||||
});
|
||||
fungible.chain(non_fungible)
|
||||
}
|
||||
|
||||
/// An iterator over all assets.
|
||||
pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
let fungible = self.fungible_assets_iter();
|
||||
let non_fungible = self.non_fungible_assets_iter();
|
||||
fungible.chain(non_fungible)
|
||||
@@ -151,16 +155,16 @@ impl Assets {
|
||||
match asset {
|
||||
MultiAsset::ConcreteFungible { id, amount } => {
|
||||
self.saturating_subsume_fungible(AssetId::Concrete(id), amount);
|
||||
}
|
||||
},
|
||||
MultiAsset::AbstractFungible { id, amount } => {
|
||||
self.saturating_subsume_fungible(AssetId::Abstract(id), amount);
|
||||
}
|
||||
MultiAsset::ConcreteNonFungible { class, instance} => {
|
||||
},
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => {
|
||||
self.saturating_subsume_non_fungible(AssetId::Concrete(class), instance);
|
||||
}
|
||||
MultiAsset::AbstractNonFungible { class, instance} => {
|
||||
},
|
||||
MultiAsset::AbstractNonFungible { class, instance } => {
|
||||
self.saturating_subsume_non_fungible(AssetId::Abstract(class), instance);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -191,14 +195,22 @@ impl Assets {
|
||||
pub fn try_take(&mut self, asset: MultiAsset) -> Result<Assets, ()> {
|
||||
match asset {
|
||||
MultiAsset::None => Ok(Assets::new()),
|
||||
MultiAsset::ConcreteFungible { id, amount } => self.try_take_fungible(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => self.try_take_fungible(AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Abstract(class), instance),
|
||||
MultiAsset::AllAbstractFungible { id } => Ok(self.take_fungible(&AssetId::Abstract(id))),
|
||||
MultiAsset::AllConcreteFungible { id } => Ok(self.take_fungible(&AssetId::Concrete(id))),
|
||||
MultiAsset::AllAbstractNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Abstract(class))),
|
||||
MultiAsset::AllConcreteNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Concrete(class))),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
self.try_take_fungible(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
self.try_take_fungible(AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
self.try_take_non_fungible(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
self.try_take_non_fungible(AssetId::Abstract(class), instance),
|
||||
MultiAsset::AllAbstractFungible { id } =>
|
||||
Ok(self.take_fungible(&AssetId::Abstract(id))),
|
||||
MultiAsset::AllConcreteFungible { id } =>
|
||||
Ok(self.take_fungible(&AssetId::Concrete(id))),
|
||||
MultiAsset::AllAbstractNonFungible { class } =>
|
||||
Ok(self.take_non_fungible(&AssetId::Abstract(class))),
|
||||
MultiAsset::AllConcreteNonFungible { class } =>
|
||||
Ok(self.take_non_fungible(&AssetId::Concrete(class))),
|
||||
MultiAsset::AllFungible => {
|
||||
let mut taken = Assets::new();
|
||||
mem::swap(&mut self.fungible, &mut taken.fungible);
|
||||
@@ -218,7 +230,11 @@ impl Assets {
|
||||
Ok(id.into_fungible_multiasset(amount).into())
|
||||
}
|
||||
|
||||
pub fn try_take_non_fungible(&mut self, id: AssetId, instance: AssetInstance) -> Result<Assets, ()> {
|
||||
pub fn try_take_non_fungible(
|
||||
&mut self,
|
||||
id: AssetId,
|
||||
instance: AssetInstance,
|
||||
) -> Result<Assets, ()> {
|
||||
let asset_id_instance = (id, instance);
|
||||
self.try_remove_non_fungible(&asset_id_instance)?;
|
||||
let (asset_id, instance) = asset_id_instance;
|
||||
@@ -252,7 +268,10 @@ impl Assets {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn try_remove_non_fungible(&mut self, class_instance: &(AssetId, AssetInstance)) -> Result<(), ()> {
|
||||
pub fn try_remove_non_fungible(
|
||||
&mut self,
|
||||
class_instance: &(AssetId, AssetInstance),
|
||||
) -> Result<(), ()> {
|
||||
match self.non_fungible.remove(class_instance) {
|
||||
true => Ok(()),
|
||||
false => Err(()),
|
||||
@@ -280,13 +299,21 @@ impl Assets {
|
||||
pub fn prepend_location(&mut self, prepend: &MultiLocation) {
|
||||
let mut fungible = Default::default();
|
||||
mem::swap(&mut self.fungible, &mut fungible);
|
||||
self.fungible = fungible.into_iter()
|
||||
.map(|(mut id, amount)| { let _ = id.prepend_location(prepend); (id, amount) })
|
||||
self.fungible = fungible
|
||||
.into_iter()
|
||||
.map(|(mut id, amount)| {
|
||||
let _ = id.prepend_location(prepend);
|
||||
(id, amount)
|
||||
})
|
||||
.collect();
|
||||
let mut non_fungible = Default::default();
|
||||
mem::swap(&mut self.non_fungible, &mut non_fungible);
|
||||
self.non_fungible = non_fungible.into_iter()
|
||||
.map(|(mut class, inst)| { let _ = class.prepend_location(prepend); (class, inst) })
|
||||
self.non_fungible = non_fungible
|
||||
.into_iter()
|
||||
.map(|(mut class, inst)| {
|
||||
let _ = class.prepend_location(prepend);
|
||||
(class, inst)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
@@ -340,67 +367,77 @@ impl Assets {
|
||||
non_fungible: self.non_fungible.clone(),
|
||||
}
|
||||
},
|
||||
MultiAsset::AllAbstractFungible { id } => {
|
||||
MultiAsset::AllAbstractFungible { id } =>
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::AbstractFungible { id: identifier, .. } => {
|
||||
if id == identifier { result.saturating_subsume(asset) }
|
||||
if id == identifier {
|
||||
result.saturating_subsume(asset)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
MultiAsset::AllAbstractNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::AbstractNonFungible { class: c, .. } => {
|
||||
if class == c { result.saturating_subsume(asset) }
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
MultiAsset::AllConcreteFungible { id } => {
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteFungible { id: identifier, .. } => {
|
||||
if id == identifier { result.saturating_subsume(asset) }
|
||||
},
|
||||
MultiAsset::AbstractNonFungible { class: c, .. } =>
|
||||
if class == c {
|
||||
result.saturating_subsume(asset)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
MultiAsset::AllConcreteNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
MultiAsset::AllConcreteFungible { id } =>
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteNonFungible { class: c, .. } => {
|
||||
if class == c { result.saturating_subsume(asset) }
|
||||
MultiAsset::ConcreteFungible { id: identifier, .. } => {
|
||||
if id == identifier {
|
||||
result.saturating_subsume(asset)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
MultiAsset::AllConcreteNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteNonFungible { class: c, .. } =>
|
||||
if class == c {
|
||||
result.saturating_subsume(asset)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
x @ MultiAsset::ConcreteFungible { .. } | x @ MultiAsset::AbstractFungible { .. } => {
|
||||
},
|
||||
x @ MultiAsset::ConcreteFungible { .. } |
|
||||
x @ MultiAsset::AbstractFungible { .. } => {
|
||||
let (id, amount) = match x {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id.clone()), *amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id.clone()), *amount),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
(AssetId::Concrete(id.clone()), *amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
(AssetId::Abstract(id.clone()), *amount),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if let Some(v) = self.fungible.get(&id) {
|
||||
result.saturating_subsume_fungible(id, amount.min(*v));
|
||||
}
|
||||
},
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } | x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } |
|
||||
x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
let (class, instance) = match x {
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class.clone()), instance.clone()),
|
||||
MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class.clone()), instance.clone()),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
(AssetId::Concrete(class.clone()), instance.clone()),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
(AssetId::Abstract(class.clone()), instance.clone()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let item = (class, instance);
|
||||
if self.non_fungible.contains(&item) {
|
||||
result.non_fungible.insert(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
result
|
||||
@@ -455,7 +492,8 @@ impl Assets {
|
||||
result.saturating_subsume_non_fungible(class, instance);
|
||||
});
|
||||
},
|
||||
x @ MultiAsset::AllAbstractFungible { .. } | x @ MultiAsset::AllConcreteFungible { .. } => {
|
||||
x @ MultiAsset::AllAbstractFungible { .. } |
|
||||
x @ MultiAsset::AllConcreteFungible { .. } => {
|
||||
let id = match x {
|
||||
MultiAsset::AllConcreteFungible { id } => AssetId::Concrete(id),
|
||||
MultiAsset::AllAbstractFungible { id } => AssetId::Abstract(id),
|
||||
@@ -465,36 +503,41 @@ impl Assets {
|
||||
let mut non_matching_fungibles = BTreeMap::<AssetId, u128>::new();
|
||||
let fungible = mem::replace(&mut self.fungible, Default::default());
|
||||
fungible.into_iter().for_each(|(iden, amount)| {
|
||||
if iden == id {
|
||||
result.saturating_subsume_fungible(iden, amount);
|
||||
} else {
|
||||
non_matching_fungibles.insert(iden, amount);
|
||||
}
|
||||
});
|
||||
if iden == id {
|
||||
result.saturating_subsume_fungible(iden, amount);
|
||||
} else {
|
||||
non_matching_fungibles.insert(iden, amount);
|
||||
}
|
||||
});
|
||||
self.fungible = non_matching_fungibles;
|
||||
},
|
||||
x @ MultiAsset::AllAbstractNonFungible { .. } | x @ MultiAsset::AllConcreteNonFungible { .. } => {
|
||||
x @ MultiAsset::AllAbstractNonFungible { .. } |
|
||||
x @ MultiAsset::AllConcreteNonFungible { .. } => {
|
||||
let class = match x {
|
||||
MultiAsset::AllConcreteNonFungible { class } => AssetId::Concrete(class),
|
||||
MultiAsset::AllAbstractNonFungible { class } => AssetId::Abstract(class),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// At the end of this block, we will be left with only the non-matching non-fungibles.
|
||||
let mut non_matching_non_fungibles = BTreeSet::<(AssetId, AssetInstance)>::new();
|
||||
let mut non_matching_non_fungibles =
|
||||
BTreeSet::<(AssetId, AssetInstance)>::new();
|
||||
let non_fungible = mem::replace(&mut self.non_fungible, Default::default());
|
||||
non_fungible.into_iter().for_each(|(c, instance)| {
|
||||
if class == c {
|
||||
result.saturating_subsume_non_fungible(c, instance);
|
||||
} else {
|
||||
non_matching_non_fungibles.insert((c, instance));
|
||||
}
|
||||
});
|
||||
if class == c {
|
||||
result.saturating_subsume_non_fungible(c, instance);
|
||||
} else {
|
||||
non_matching_non_fungibles.insert((c, instance));
|
||||
}
|
||||
});
|
||||
self.non_fungible = non_matching_non_fungibles;
|
||||
},
|
||||
x @ MultiAsset::ConcreteFungible {..} | x @ MultiAsset::AbstractFungible {..} => {
|
||||
x @ MultiAsset::ConcreteFungible { .. } |
|
||||
x @ MultiAsset::AbstractFungible { .. } => {
|
||||
let (id, amount) = match x {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
(AssetId::Abstract(id), amount),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// remove the maxmimum possible up to id/amount from self, add the removed onto
|
||||
@@ -509,11 +552,14 @@ impl Assets {
|
||||
result.saturating_subsume_fungible(id, e.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
x @ MultiAsset::ConcreteNonFungible {..} | x @ MultiAsset::AbstractNonFungible {..} => {
|
||||
},
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } |
|
||||
x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
let (class, instance) = match x {
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class), instance),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
(AssetId::Abstract(class), instance),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// remove the maxmimum possible up to id/amount from self, add the removed onto
|
||||
@@ -521,7 +567,7 @@ impl Assets {
|
||||
if let Some(entry) = self.non_fungible.take(&(class, instance)) {
|
||||
result.non_fungible.insert(entry);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
result
|
||||
@@ -543,7 +589,10 @@ mod tests {
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn ANF(class: u8, instance_id: u128) -> MultiAsset {
|
||||
MultiAsset::AbstractNonFungible { class: vec![class], instance: AssetInstance::Index { id: instance_id } }
|
||||
MultiAsset::AbstractNonFungible {
|
||||
class: vec![class],
|
||||
instance: AssetInstance::Index { id: instance_id },
|
||||
}
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn CF(amount: u128) -> MultiAsset {
|
||||
@@ -551,7 +600,10 @@ mod tests {
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn CNF(instance_id: u128) -> MultiAsset {
|
||||
MultiAsset::ConcreteNonFungible { class: MultiLocation::Null, instance: AssetInstance::Index { id: instance_id } }
|
||||
MultiAsset::ConcreteNonFungible {
|
||||
class: MultiLocation::Null,
|
||||
instance: AssetInstance::Index { id: instance_id },
|
||||
}
|
||||
}
|
||||
|
||||
fn test_assets() -> Assets {
|
||||
|
||||
@@ -14,18 +14,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::SendXcm;
|
||||
use frame_support::dispatch::{Dispatchable, Parameter};
|
||||
use frame_support::weights::{PostDispatchInfo, GetDispatchInfo};
|
||||
use crate::traits::{
|
||||
TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, ShouldExecute, WeightTrader, WeightBounds,
|
||||
OnResponse,
|
||||
ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, ShouldExecute, TransactAsset,
|
||||
WeightBounds, WeightTrader,
|
||||
};
|
||||
use frame_support::{
|
||||
dispatch::{Dispatchable, Parameter},
|
||||
weights::{GetDispatchInfo, PostDispatchInfo},
|
||||
};
|
||||
use xcm::v0::SendXcm;
|
||||
|
||||
/// The trait to parameterize the `XcmExecutor`.
|
||||
pub trait Config {
|
||||
/// The outer call dispatch type.
|
||||
type Call: Parameter + Dispatchable<PostInfo=PostDispatchInfo> + GetDispatchInfo;
|
||||
type Call: Parameter + Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo;
|
||||
|
||||
/// How to send an onward XCM message.
|
||||
type XcmSender: SendXcm;
|
||||
|
||||
@@ -16,24 +16,25 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::{prelude::*, marker::PhantomData};
|
||||
use frame_support::{
|
||||
ensure, weights::GetDispatchInfo,
|
||||
dispatch::{Weight, Dispatchable}
|
||||
dispatch::{Dispatchable, Weight},
|
||||
ensure,
|
||||
weights::GetDispatchInfo,
|
||||
};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
use xcm::v0::{
|
||||
ExecuteXcm, SendXcm, Error as XcmError, Outcome,
|
||||
MultiLocation, MultiAsset, Xcm, Order, Response,
|
||||
Error as XcmError, ExecuteXcm, MultiAsset, MultiLocation, Order, Outcome, Response, SendXcm,
|
||||
Xcm,
|
||||
};
|
||||
|
||||
pub mod traits;
|
||||
use traits::{
|
||||
TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, WeightBounds, WeightTrader,
|
||||
ShouldExecute, OnResponse
|
||||
ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, ShouldExecute, TransactAsset,
|
||||
WeightBounds, WeightTrader,
|
||||
};
|
||||
|
||||
mod assets;
|
||||
pub use assets::{Assets, AssetId};
|
||||
pub use assets::{AssetId, Assets};
|
||||
mod config;
|
||||
pub use config::Config;
|
||||
|
||||
@@ -70,10 +71,17 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
|
||||
None => return Outcome::Error(XcmError::Overflow),
|
||||
};
|
||||
if maximum_weight > weight_limit {
|
||||
return Outcome::Error(XcmError::WeightLimitReached(maximum_weight));
|
||||
return Outcome::Error(XcmError::WeightLimitReached(maximum_weight))
|
||||
}
|
||||
let mut trader = Config::Trader::new();
|
||||
let result = Self::do_execute_xcm(origin, true, message, &mut weight_credit, Some(shallow_weight), &mut trader);
|
||||
let result = Self::do_execute_xcm(
|
||||
origin,
|
||||
true,
|
||||
message,
|
||||
&mut weight_credit,
|
||||
Some(shallow_weight),
|
||||
&mut trader,
|
||||
);
|
||||
drop(trader);
|
||||
log::trace!(target: "xcm::execute_xcm", "result: {:?}", &result);
|
||||
match result {
|
||||
@@ -106,10 +114,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
log::trace!(
|
||||
target: "xcm::do_execute_xcm",
|
||||
"origin: {:?}, top_level: {:?}, message: {:?}, weight_credit: {:?}, maybe_shallow_weight: {:?}",
|
||||
origin,
|
||||
top_level,
|
||||
message,
|
||||
weight_credit,
|
||||
origin,
|
||||
top_level,
|
||||
message,
|
||||
weight_credit,
|
||||
maybe_shallow_weight,
|
||||
);
|
||||
// This is the weight of everything that cannot be paid for. This basically means all computation
|
||||
@@ -118,8 +126,14 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
.or_else(|| Config::Weigher::shallow(&mut message).ok())
|
||||
.ok_or(XcmError::WeightNotComputable)?;
|
||||
|
||||
Config::Barrier::should_execute(&origin, top_level, &message, shallow_weight, weight_credit)
|
||||
.map_err(|()| XcmError::Barrier)?;
|
||||
Config::Barrier::should_execute(
|
||||
&origin,
|
||||
top_level,
|
||||
&message,
|
||||
shallow_weight,
|
||||
weight_credit,
|
||||
)
|
||||
.map_err(|()| XcmError::Barrier)?;
|
||||
|
||||
// The surplus weight, defined as the amount by which `shallow_weight` plus all nested
|
||||
// `shallow_weight` values (ensuring no double-counting and also known as `deep_weight`) is an
|
||||
@@ -136,17 +150,20 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
holding.saturating_subsume_all(withdrawn);
|
||||
}
|
||||
Some((holding, effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::ReserveAssetDeposit { assets, effects }) => {
|
||||
// check whether we trust origin to be our reserve location for this asset.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(Config::IsReserve::filter_asset_location(asset, &origin), XcmError::UntrustedReserveLocation);
|
||||
ensure!(
|
||||
Config::IsReserve::filter_asset_location(asset, &origin),
|
||||
XcmError::UntrustedReserveLocation
|
||||
);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TransferAsset { assets, dest }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
for asset in assets {
|
||||
@@ -154,7 +171,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?;
|
||||
}
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TransferReserveAsset { mut assets, dest, effects }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
let inv_dest = Config::LocationInverter::invert_location(&dest);
|
||||
@@ -165,14 +182,17 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
}
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TeleportAsset { assets, effects }) => {
|
||||
// check whether we trust origin to teleport this asset to us via config trait.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(Config::IsTeleporter::filter_asset_location(asset, &origin), XcmError::UntrustedTeleportLocation);
|
||||
ensure!(
|
||||
Config::IsTeleporter::filter_asset_location(asset, &origin),
|
||||
XcmError::UntrustedTeleportLocation
|
||||
);
|
||||
// We should check that the asset can actually be teleported in (for this to be in error, there
|
||||
// would need to be an accounting violation by one of the trusted chains, so it's unlikely, but we
|
||||
// don't want to punish a possibly innocent chain/user).
|
||||
@@ -182,7 +202,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Config::AssetTransactor::check_in(&origin, asset);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::Transact { origin_type, require_weight_at_most, mut call }) => {
|
||||
// We assume that the Relay-chain is allowed to use transact on this parachain.
|
||||
|
||||
@@ -198,8 +218,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
||||
// message makes sense.
|
||||
error_and_info.post_info.actual_weight
|
||||
}
|
||||
}.unwrap_or(weight);
|
||||
},
|
||||
}
|
||||
.unwrap_or(weight);
|
||||
let surplus = weight.saturating_sub(actual_weight);
|
||||
// Credit any surplus weight that we bought. This should be safe since it's work we
|
||||
// didn't realise that we didn't have to do.
|
||||
@@ -212,20 +233,21 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
// Return the overestimated amount so we can adjust our expectations on how much this entire
|
||||
// execution has taken.
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::QueryResponse { query_id, response }) => {
|
||||
Config::ResponseHandler::on_response(origin, query_id, response);
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::RelayedFrom { who, message }) => {
|
||||
ensure!(who.is_interior(), XcmError::EscalationOfPrivilege);
|
||||
let mut origin = origin;
|
||||
origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?;
|
||||
let surplus = Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?;
|
||||
let surplus =
|
||||
Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?;
|
||||
total_surplus = total_surplus.saturating_add(surplus);
|
||||
None
|
||||
}
|
||||
_ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message.
|
||||
},
|
||||
_ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message.
|
||||
};
|
||||
|
||||
if let Some((mut holding, effects)) = maybe_holding_effects {
|
||||
@@ -266,11 +288,11 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
let assets = Self::reanchored(deposited, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
},
|
||||
Order::InitiateReserveWithdraw { assets, reserve, effects} => {
|
||||
Order::InitiateReserveWithdraw { assets, reserve, effects } => {
|
||||
let assets = Self::reanchored(holding.saturating_take(assets), &reserve);
|
||||
Config::XcmSender::send_xcm(reserve, Xcm::WithdrawAsset { assets, effects })?;
|
||||
}
|
||||
Order::InitiateTeleport { assets, dest, effects} => {
|
||||
},
|
||||
Order::InitiateTeleport { assets, dest, effects } => {
|
||||
// We must do this first in order to resolve wildcards.
|
||||
let assets = holding.saturating_take(assets);
|
||||
for asset in assets.assets_iter() {
|
||||
@@ -278,28 +300,39 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
}
|
||||
let assets = Self::reanchored(assets, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?;
|
||||
}
|
||||
},
|
||||
Order::QueryHolding { query_id, dest, assets } => {
|
||||
let assets = Self::reanchored(holding.min(assets.iter()), &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::QueryResponse { query_id, response: Response::Assets(assets) })?;
|
||||
}
|
||||
Config::XcmSender::send_xcm(
|
||||
dest,
|
||||
Xcm::QueryResponse { query_id, response: Response::Assets(assets) },
|
||||
)?;
|
||||
},
|
||||
Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
// pay for `weight` using up to `fees` of the holding account.
|
||||
let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?);
|
||||
let purchasing_weight =
|
||||
Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?);
|
||||
let max_fee = holding.try_take(fees).map_err(|()| XcmError::NotHoldingFees)?;
|
||||
let unspent = trader.buy_weight(purchasing_weight, max_fee)?;
|
||||
holding.saturating_subsume_all(unspent);
|
||||
|
||||
let mut remaining_weight = weight;
|
||||
for message in xcm.into_iter() {
|
||||
match Self::do_execute_xcm(origin.clone(), false, message, &mut remaining_weight, None, trader) {
|
||||
match Self::do_execute_xcm(
|
||||
origin.clone(),
|
||||
false,
|
||||
message,
|
||||
&mut remaining_weight,
|
||||
None,
|
||||
trader,
|
||||
) {
|
||||
Err(e) if halt_on_error => return Err(e),
|
||||
Err(_) => {}
|
||||
Ok(surplus) => { total_surplus += surplus }
|
||||
Err(_) => {},
|
||||
Ok(surplus) => total_surplus += surplus,
|
||||
}
|
||||
}
|
||||
holding.saturating_subsume(trader.refund_weight(remaining_weight));
|
||||
}
|
||||
},
|
||||
_ => return Err(XcmError::UnhandledEffect)?,
|
||||
}
|
||||
Ok(total_surplus)
|
||||
|
||||
@@ -14,8 +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/>.
|
||||
|
||||
use sp_std::{prelude::*, result::Result, borrow::Borrow, convert::TryFrom};
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_std::{borrow::Borrow, convert::TryFrom, prelude::*, result::Result};
|
||||
use xcm::v0::{MultiLocation, OriginKind};
|
||||
|
||||
/// Generic third-party conversion trait. Use this when you don't want to force the user to use default
|
||||
@@ -29,12 +29,16 @@ use xcm::v0::{MultiLocation, OriginKind};
|
||||
/// the `Err(_)` of the last failing conversion (or `Err(())` for ref conversions).
|
||||
pub trait Convert<A: Clone, B: Clone> {
|
||||
/// Convert from `value` (of type `A`) into an equivalent value of type `B`, `Err` if not possible.
|
||||
fn convert(value: A) -> Result<B, A> { Self::convert_ref(&value).map_err(|_| value) }
|
||||
fn convert(value: A) -> Result<B, A> {
|
||||
Self::convert_ref(&value).map_err(|_| value)
|
||||
}
|
||||
fn convert_ref(value: impl Borrow<A>) -> Result<B, ()> {
|
||||
Self::convert(value.borrow().clone()).map_err(|_| ())
|
||||
}
|
||||
/// Convert from `value` (of type `B`) into an equivalent value of type `A`, `Err` if not possible.
|
||||
fn reverse(value: B) -> Result<A, B> { Self::reverse_ref(&value).map_err(|_| value) }
|
||||
fn reverse(value: B) -> Result<A, B> {
|
||||
Self::reverse_ref(&value).map_err(|_| value)
|
||||
}
|
||||
fn reverse_ref(value: impl Borrow<B>) -> Result<A, ()> {
|
||||
Self::reverse(value.borrow().clone()).map_err(|_| ())
|
||||
}
|
||||
@@ -85,13 +89,19 @@ impl<A: Clone, B: Clone> Convert<A, B> for Tuple {
|
||||
/// Simple pass-through which implements `BytesConversion` while not doing any conversion.
|
||||
pub struct Identity;
|
||||
impl<T: Clone> Convert<T, T> for Identity {
|
||||
fn convert(value: T) -> Result<T, T> { Ok(value) }
|
||||
fn reverse(value: T) -> Result<T, T> { Ok(value) }
|
||||
fn convert(value: T) -> Result<T, T> {
|
||||
Ok(value)
|
||||
}
|
||||
fn reverse(value: T) -> Result<T, T> {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `Convert` trait using `TryFrom`.
|
||||
pub struct JustTry;
|
||||
impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Source, Dest> for JustTry {
|
||||
impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Source, Dest>
|
||||
for JustTry
|
||||
{
|
||||
fn convert(value: Source) -> Result<Dest, Source> {
|
||||
Dest::try_from(value.clone()).map_err(|_| value)
|
||||
}
|
||||
@@ -103,7 +113,9 @@ impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Sourc
|
||||
/// Implementation of `Convert<_, Vec<u8>>` using the parity scale codec.
|
||||
pub struct Encoded;
|
||||
impl<T: Clone + Encode + Decode> Convert<T, Vec<u8>> for Encoded {
|
||||
fn convert_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> { Ok(value.borrow().encode()) }
|
||||
fn convert_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> {
|
||||
Ok(value.borrow().encode())
|
||||
}
|
||||
fn reverse_ref(bytes: impl Borrow<Vec<u8>>) -> Result<T, ()> {
|
||||
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
|
||||
}
|
||||
@@ -115,7 +127,9 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded {
|
||||
fn convert_ref(bytes: impl Borrow<Vec<u8>>) -> Result<T, ()> {
|
||||
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
|
||||
}
|
||||
fn reverse_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> { Ok(value.borrow().encode()) }
|
||||
fn reverse_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> {
|
||||
Ok(value.borrow().encode())
|
||||
}
|
||||
}
|
||||
|
||||
/// A converter `trait` for origin types.
|
||||
|
||||
@@ -14,8 +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/>.
|
||||
|
||||
use xcm::v0::{MultiAsset, Error as XcmError};
|
||||
use sp_std::result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset};
|
||||
|
||||
/// Errors associated with [`MatchesFungibles`] operation.
|
||||
pub enum Error {
|
||||
@@ -35,7 +35,8 @@ impl From<Error> for XcmError {
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::AssetNotFound,
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed => FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AssetIdConversionFailed => FailedToTransactAsset("AssetIdConversionFailed"),
|
||||
}
|
||||
}
|
||||
@@ -46,10 +47,7 @@ pub trait MatchesFungibles<AssetId, Balance> {
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
> MatchesFungibles<AssetId, Balance> for Tuple {
|
||||
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, _ => () }
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
//! Various traits used in configuring the executor.
|
||||
|
||||
mod conversion;
|
||||
pub use conversion::{InvertLocation, ConvertOrigin, Convert, JustTry, Identity, Encoded, Decoded};
|
||||
pub use conversion::{Convert, ConvertOrigin, Decoded, Encoded, Identity, InvertLocation, JustTry};
|
||||
mod filter_asset_location;
|
||||
pub use filter_asset_location::{FilterAssetLocation};
|
||||
pub use filter_asset_location::FilterAssetLocation;
|
||||
mod matches_fungible;
|
||||
pub use matches_fungible::{MatchesFungible};
|
||||
pub use matches_fungible::MatchesFungible;
|
||||
mod matches_fungibles;
|
||||
pub use matches_fungibles::{MatchesFungibles, Error};
|
||||
pub use matches_fungibles::{Error, MatchesFungibles};
|
||||
mod on_response;
|
||||
pub use on_response::OnResponse;
|
||||
mod should_execute;
|
||||
|
||||
@@ -14,8 +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/>.
|
||||
|
||||
use xcm::v0::{Response, MultiLocation};
|
||||
use frame_support::weights::Weight;
|
||||
use xcm::v0::{MultiLocation, Response};
|
||||
|
||||
/// Define what needs to be done upon receiving a query response.
|
||||
pub trait OnResponse {
|
||||
@@ -25,6 +25,10 @@ pub trait OnResponse {
|
||||
fn on_response(origin: MultiLocation, query_id: u64, response: Response) -> Weight;
|
||||
}
|
||||
impl OnResponse for () {
|
||||
fn expecting_response(_origin: &MultiLocation, _query_id: u64) -> bool { false }
|
||||
fn on_response(_origin: MultiLocation, _query_id: u64, _response: Response) -> Weight { 0 }
|
||||
fn expecting_response(_origin: &MultiLocation, _query_id: u64) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_response(_origin: MultiLocation, _query_id: u64, _response: Response) -> Weight {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// 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::Result;
|
||||
use xcm::v0::{Xcm, MultiLocation};
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{MultiLocation, Xcm};
|
||||
|
||||
/// Trait to determine whether the execution engine should actually execute a given XCM.
|
||||
///
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// 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::Result;
|
||||
use xcm::v0::{Error as XcmError, Result as XcmResult, MultiAsset, MultiLocation};
|
||||
use crate::Assets;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult};
|
||||
|
||||
/// Facility for asset transacting.
|
||||
///
|
||||
@@ -78,22 +78,30 @@ pub trait TransactAsset {
|
||||
/// Move an `asset` `from` one location in `to` another location.
|
||||
///
|
||||
/// Returns `XcmError::FailedToTransactAsset` if transfer failed.
|
||||
fn transfer_asset(_asset: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_asset: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::Unimplemented)
|
||||
}
|
||||
|
||||
/// Move an `asset` `from` one location in `to` another location.
|
||||
///
|
||||
/// Attempts to use `transfer_asset` and if not available then falls back to using a two-part withdraw/deposit.
|
||||
fn teleport_asset(asset: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn teleport_asset(
|
||||
asset: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
match Self::transfer_asset(asset, from, to) {
|
||||
Err(XcmError::Unimplemented) => {
|
||||
let assets = Self::withdraw_asset(asset, from)?;
|
||||
// Not a very forgiving attitude; once we implement roll-backs then it'll be nicer.
|
||||
Self::deposit_asset(asset, to)?;
|
||||
Ok(assets)
|
||||
}
|
||||
result => result
|
||||
},
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +168,11 @@ impl TransactAsset for Tuple {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
|
||||
fn transfer_asset(what: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
for_tuples!( #(
|
||||
match Tuple::transfer_asset(what, from, to) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
@@ -199,7 +211,11 @@ mod tests {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
}
|
||||
@@ -218,7 +234,11 @@ mod tests {
|
||||
Err(XcmError::Overflow)
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::Overflow)
|
||||
}
|
||||
}
|
||||
@@ -237,16 +257,24 @@ mod tests {
|
||||
Ok(Assets::default())
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Ok(Assets::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_to_asset_not_found() {
|
||||
type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
|
||||
type MultiTransactor =
|
||||
(UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::AssetNotFound));
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
Err(XcmError::AssetNotFound)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -260,7 +288,10 @@ mod tests {
|
||||
fn unexpected_error_stops_iteration() {
|
||||
type MultiTransactor = (OverflowTransactor, SuccessfulTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::Overflow));
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
Err(XcmError::Overflow)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,10 +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/>.
|
||||
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Xcm, MultiAsset, MultiLocation, Error};
|
||||
use frame_support::weights::Weight;
|
||||
use crate::Assets;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error, MultiAsset, MultiLocation, Xcm};
|
||||
|
||||
/// Determine the weight of an XCM message.
|
||||
pub trait WeightBounds<Call> {
|
||||
@@ -71,11 +71,15 @@ pub trait WeightTrader: Sized {
|
||||
/// purchased using `buy_weight`.
|
||||
///
|
||||
/// Default implementation refunds nothing.
|
||||
fn refund_weight(&mut self, _weight: Weight) -> MultiAsset { MultiAsset::None }
|
||||
fn refund_weight(&mut self, _weight: Weight) -> MultiAsset {
|
||||
MultiAsset::None
|
||||
}
|
||||
}
|
||||
|
||||
impl WeightTrader for () {
|
||||
fn new() -> Self { () }
|
||||
fn new() -> Self {
|
||||
()
|
||||
}
|
||||
fn buy_weight(&mut self, _: Weight, _: Assets) -> Result<Assets, Error> {
|
||||
Err(Error::Unimplemented)
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ pub fn encode_xcm(message: Xcm<()>, message_kind: MessageKind) -> Vec<u8> {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[rustfmt::skip]
|
||||
macro_rules! decl_test_relay_chain {
|
||||
(
|
||||
pub struct $name:ident {
|
||||
|
||||
Reference in New Issue
Block a user