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:
Shawn Tabrizi
2021-08-02 12:47:33 +02:00
committed by GitHub
parent 30e3012270
commit ff5d56fb76
350 changed files with 20617 additions and 21266 deletions
+58 -48
View File
@@ -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()),
+22 -19
View File
@@ -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.
+3 -3
View File
@@ -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.
+45 -18
View File
@@ -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
View File
@@ -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()) },
}
}
}
+103 -87
View File
@@ -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 }
}));
}
}
+68 -38
View File
@@ -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)));
}
}
+33 -19
View File
@@ -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 }
+1 -1
View File
@@ -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};
+13 -14
View File
@@ -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.
+129 -68
View File
@@ -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,
)
}
}
+10 -9
View File
@@ -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
+59 -61
View File
@@ -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),
})
}
+85 -66
View File
@@ -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...
+68 -52
View File
@@ -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));
}
+153 -101
View File
@@ -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 {
+8 -6
View File
@@ -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;
+74 -41
View File
@@ -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, _ => () }
+4 -4
View File
@@ -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)
}
+1
View File
@@ -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 {