mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 15:57:55 +00:00
cargo +nightly fmt (#3540)
* cargo +nightly fmt * add cargo-fmt check to ci * update ci * fmt * fmt * skip macro * ignore bridges
This commit is contained in:
@@ -14,9 +14,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::{prelude::*, mem, collections::{btree_map::BTreeMap, btree_set::BTreeSet}};
|
||||
use xcm::v0::{MultiAsset, MultiLocation, AssetInstance};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::{
|
||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||
mem,
|
||||
prelude::*,
|
||||
};
|
||||
use xcm::v0::{AssetInstance, MultiAsset, MultiLocation};
|
||||
|
||||
/// Classification of an asset being concrete or abstract.
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug)]
|
||||
@@ -91,43 +95,43 @@ impl From<MultiAsset> for Assets {
|
||||
|
||||
impl Assets {
|
||||
/// New value, containing no assets.
|
||||
pub fn new() -> Self { Self::default() }
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// An iterator over the fungible assets.
|
||||
pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
self.fungible.iter()
|
||||
.map(|(id, &amount)| match id.clone() {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
})
|
||||
pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
self.fungible.iter().map(|(id, &amount)| match id.clone() {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
})
|
||||
}
|
||||
|
||||
/// An iterator over the non-fungible assets.
|
||||
pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
self.non_fungible.iter()
|
||||
.map(|&(ref class, ref instance)| match class.clone() {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance: instance.clone() },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance: instance.clone() },
|
||||
})
|
||||
pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
self.non_fungible.iter().map(|&(ref class, ref instance)| match class.clone() {
|
||||
AssetId::Concrete(class) =>
|
||||
MultiAsset::ConcreteNonFungible { class, instance: instance.clone() },
|
||||
AssetId::Abstract(class) =>
|
||||
MultiAsset::AbstractNonFungible { class, instance: instance.clone() },
|
||||
})
|
||||
}
|
||||
|
||||
/// An iterator over all assets.
|
||||
pub fn into_assets_iter(self) -> impl Iterator<Item=MultiAsset> {
|
||||
let fungible = self.fungible.into_iter()
|
||||
.map(|(id, amount)| match id {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
});
|
||||
let non_fungible = self.non_fungible.into_iter()
|
||||
.map(|(id, instance)| match id {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance },
|
||||
});
|
||||
pub fn into_assets_iter(self) -> impl Iterator<Item = MultiAsset> {
|
||||
let fungible = self.fungible.into_iter().map(|(id, amount)| match id {
|
||||
AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount },
|
||||
AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount },
|
||||
});
|
||||
let non_fungible = self.non_fungible.into_iter().map(|(id, instance)| match id {
|
||||
AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance },
|
||||
AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance },
|
||||
});
|
||||
fungible.chain(non_fungible)
|
||||
}
|
||||
|
||||
/// An iterator over all assets.
|
||||
pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a {
|
||||
pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a {
|
||||
let fungible = self.fungible_assets_iter();
|
||||
let non_fungible = self.non_fungible_assets_iter();
|
||||
fungible.chain(non_fungible)
|
||||
@@ -151,16 +155,16 @@ impl Assets {
|
||||
match asset {
|
||||
MultiAsset::ConcreteFungible { id, amount } => {
|
||||
self.saturating_subsume_fungible(AssetId::Concrete(id), amount);
|
||||
}
|
||||
},
|
||||
MultiAsset::AbstractFungible { id, amount } => {
|
||||
self.saturating_subsume_fungible(AssetId::Abstract(id), amount);
|
||||
}
|
||||
MultiAsset::ConcreteNonFungible { class, instance} => {
|
||||
},
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => {
|
||||
self.saturating_subsume_non_fungible(AssetId::Concrete(class), instance);
|
||||
}
|
||||
MultiAsset::AbstractNonFungible { class, instance} => {
|
||||
},
|
||||
MultiAsset::AbstractNonFungible { class, instance } => {
|
||||
self.saturating_subsume_non_fungible(AssetId::Abstract(class), instance);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -191,14 +195,22 @@ impl Assets {
|
||||
pub fn try_take(&mut self, asset: MultiAsset) -> Result<Assets, ()> {
|
||||
match asset {
|
||||
MultiAsset::None => Ok(Assets::new()),
|
||||
MultiAsset::ConcreteFungible { id, amount } => self.try_take_fungible(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => self.try_take_fungible(AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Abstract(class), instance),
|
||||
MultiAsset::AllAbstractFungible { id } => Ok(self.take_fungible(&AssetId::Abstract(id))),
|
||||
MultiAsset::AllConcreteFungible { id } => Ok(self.take_fungible(&AssetId::Concrete(id))),
|
||||
MultiAsset::AllAbstractNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Abstract(class))),
|
||||
MultiAsset::AllConcreteNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Concrete(class))),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
self.try_take_fungible(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
self.try_take_fungible(AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
self.try_take_non_fungible(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
self.try_take_non_fungible(AssetId::Abstract(class), instance),
|
||||
MultiAsset::AllAbstractFungible { id } =>
|
||||
Ok(self.take_fungible(&AssetId::Abstract(id))),
|
||||
MultiAsset::AllConcreteFungible { id } =>
|
||||
Ok(self.take_fungible(&AssetId::Concrete(id))),
|
||||
MultiAsset::AllAbstractNonFungible { class } =>
|
||||
Ok(self.take_non_fungible(&AssetId::Abstract(class))),
|
||||
MultiAsset::AllConcreteNonFungible { class } =>
|
||||
Ok(self.take_non_fungible(&AssetId::Concrete(class))),
|
||||
MultiAsset::AllFungible => {
|
||||
let mut taken = Assets::new();
|
||||
mem::swap(&mut self.fungible, &mut taken.fungible);
|
||||
@@ -218,7 +230,11 @@ impl Assets {
|
||||
Ok(id.into_fungible_multiasset(amount).into())
|
||||
}
|
||||
|
||||
pub fn try_take_non_fungible(&mut self, id: AssetId, instance: AssetInstance) -> Result<Assets, ()> {
|
||||
pub fn try_take_non_fungible(
|
||||
&mut self,
|
||||
id: AssetId,
|
||||
instance: AssetInstance,
|
||||
) -> Result<Assets, ()> {
|
||||
let asset_id_instance = (id, instance);
|
||||
self.try_remove_non_fungible(&asset_id_instance)?;
|
||||
let (asset_id, instance) = asset_id_instance;
|
||||
@@ -252,7 +268,10 @@ impl Assets {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn try_remove_non_fungible(&mut self, class_instance: &(AssetId, AssetInstance)) -> Result<(), ()> {
|
||||
pub fn try_remove_non_fungible(
|
||||
&mut self,
|
||||
class_instance: &(AssetId, AssetInstance),
|
||||
) -> Result<(), ()> {
|
||||
match self.non_fungible.remove(class_instance) {
|
||||
true => Ok(()),
|
||||
false => Err(()),
|
||||
@@ -280,13 +299,21 @@ impl Assets {
|
||||
pub fn prepend_location(&mut self, prepend: &MultiLocation) {
|
||||
let mut fungible = Default::default();
|
||||
mem::swap(&mut self.fungible, &mut fungible);
|
||||
self.fungible = fungible.into_iter()
|
||||
.map(|(mut id, amount)| { let _ = id.prepend_location(prepend); (id, amount) })
|
||||
self.fungible = fungible
|
||||
.into_iter()
|
||||
.map(|(mut id, amount)| {
|
||||
let _ = id.prepend_location(prepend);
|
||||
(id, amount)
|
||||
})
|
||||
.collect();
|
||||
let mut non_fungible = Default::default();
|
||||
mem::swap(&mut self.non_fungible, &mut non_fungible);
|
||||
self.non_fungible = non_fungible.into_iter()
|
||||
.map(|(mut class, inst)| { let _ = class.prepend_location(prepend); (class, inst) })
|
||||
self.non_fungible = non_fungible
|
||||
.into_iter()
|
||||
.map(|(mut class, inst)| {
|
||||
let _ = class.prepend_location(prepend);
|
||||
(class, inst)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
@@ -340,67 +367,77 @@ impl Assets {
|
||||
non_fungible: self.non_fungible.clone(),
|
||||
}
|
||||
},
|
||||
MultiAsset::AllAbstractFungible { id } => {
|
||||
MultiAsset::AllAbstractFungible { id } =>
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::AbstractFungible { id: identifier, .. } => {
|
||||
if id == identifier { result.saturating_subsume(asset) }
|
||||
if id == identifier {
|
||||
result.saturating_subsume(asset)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
MultiAsset::AllAbstractNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::AbstractNonFungible { class: c, .. } => {
|
||||
if class == c { result.saturating_subsume(asset) }
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
MultiAsset::AllConcreteFungible { id } => {
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteFungible { id: identifier, .. } => {
|
||||
if id == identifier { result.saturating_subsume(asset) }
|
||||
},
|
||||
MultiAsset::AbstractNonFungible { class: c, .. } =>
|
||||
if class == c {
|
||||
result.saturating_subsume(asset)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
},
|
||||
MultiAsset::AllConcreteNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
MultiAsset::AllConcreteFungible { id } =>
|
||||
for asset in self.fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteNonFungible { class: c, .. } => {
|
||||
if class == c { result.saturating_subsume(asset) }
|
||||
MultiAsset::ConcreteFungible { id: identifier, .. } => {
|
||||
if id == identifier {
|
||||
result.saturating_subsume(asset)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
MultiAsset::AllConcreteNonFungible { class } => {
|
||||
for asset in self.non_fungible_assets_iter() {
|
||||
match &asset {
|
||||
MultiAsset::ConcreteNonFungible { class: c, .. } =>
|
||||
if class == c {
|
||||
result.saturating_subsume(asset)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
x @ MultiAsset::ConcreteFungible { .. } | x @ MultiAsset::AbstractFungible { .. } => {
|
||||
},
|
||||
x @ MultiAsset::ConcreteFungible { .. } |
|
||||
x @ MultiAsset::AbstractFungible { .. } => {
|
||||
let (id, amount) = match x {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id.clone()), *amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id.clone()), *amount),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
(AssetId::Concrete(id.clone()), *amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
(AssetId::Abstract(id.clone()), *amount),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if let Some(v) = self.fungible.get(&id) {
|
||||
result.saturating_subsume_fungible(id, amount.min(*v));
|
||||
}
|
||||
},
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } | x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } |
|
||||
x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
let (class, instance) = match x {
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class.clone()), instance.clone()),
|
||||
MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class.clone()), instance.clone()),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
(AssetId::Concrete(class.clone()), instance.clone()),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
(AssetId::Abstract(class.clone()), instance.clone()),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let item = (class, instance);
|
||||
if self.non_fungible.contains(&item) {
|
||||
result.non_fungible.insert(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
result
|
||||
@@ -455,7 +492,8 @@ impl Assets {
|
||||
result.saturating_subsume_non_fungible(class, instance);
|
||||
});
|
||||
},
|
||||
x @ MultiAsset::AllAbstractFungible { .. } | x @ MultiAsset::AllConcreteFungible { .. } => {
|
||||
x @ MultiAsset::AllAbstractFungible { .. } |
|
||||
x @ MultiAsset::AllConcreteFungible { .. } => {
|
||||
let id = match x {
|
||||
MultiAsset::AllConcreteFungible { id } => AssetId::Concrete(id),
|
||||
MultiAsset::AllAbstractFungible { id } => AssetId::Abstract(id),
|
||||
@@ -465,36 +503,41 @@ impl Assets {
|
||||
let mut non_matching_fungibles = BTreeMap::<AssetId, u128>::new();
|
||||
let fungible = mem::replace(&mut self.fungible, Default::default());
|
||||
fungible.into_iter().for_each(|(iden, amount)| {
|
||||
if iden == id {
|
||||
result.saturating_subsume_fungible(iden, amount);
|
||||
} else {
|
||||
non_matching_fungibles.insert(iden, amount);
|
||||
}
|
||||
});
|
||||
if iden == id {
|
||||
result.saturating_subsume_fungible(iden, amount);
|
||||
} else {
|
||||
non_matching_fungibles.insert(iden, amount);
|
||||
}
|
||||
});
|
||||
self.fungible = non_matching_fungibles;
|
||||
},
|
||||
x @ MultiAsset::AllAbstractNonFungible { .. } | x @ MultiAsset::AllConcreteNonFungible { .. } => {
|
||||
x @ MultiAsset::AllAbstractNonFungible { .. } |
|
||||
x @ MultiAsset::AllConcreteNonFungible { .. } => {
|
||||
let class = match x {
|
||||
MultiAsset::AllConcreteNonFungible { class } => AssetId::Concrete(class),
|
||||
MultiAsset::AllAbstractNonFungible { class } => AssetId::Abstract(class),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// At the end of this block, we will be left with only the non-matching non-fungibles.
|
||||
let mut non_matching_non_fungibles = BTreeSet::<(AssetId, AssetInstance)>::new();
|
||||
let mut non_matching_non_fungibles =
|
||||
BTreeSet::<(AssetId, AssetInstance)>::new();
|
||||
let non_fungible = mem::replace(&mut self.non_fungible, Default::default());
|
||||
non_fungible.into_iter().for_each(|(c, instance)| {
|
||||
if class == c {
|
||||
result.saturating_subsume_non_fungible(c, instance);
|
||||
} else {
|
||||
non_matching_non_fungibles.insert((c, instance));
|
||||
}
|
||||
});
|
||||
if class == c {
|
||||
result.saturating_subsume_non_fungible(c, instance);
|
||||
} else {
|
||||
non_matching_non_fungibles.insert((c, instance));
|
||||
}
|
||||
});
|
||||
self.non_fungible = non_matching_non_fungibles;
|
||||
},
|
||||
x @ MultiAsset::ConcreteFungible {..} | x @ MultiAsset::AbstractFungible {..} => {
|
||||
x @ MultiAsset::ConcreteFungible { .. } |
|
||||
x @ MultiAsset::AbstractFungible { .. } => {
|
||||
let (id, amount) = match x {
|
||||
MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id), amount),
|
||||
MultiAsset::ConcreteFungible { id, amount } =>
|
||||
(AssetId::Concrete(id), amount),
|
||||
MultiAsset::AbstractFungible { id, amount } =>
|
||||
(AssetId::Abstract(id), amount),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// remove the maxmimum possible up to id/amount from self, add the removed onto
|
||||
@@ -509,11 +552,14 @@ impl Assets {
|
||||
result.saturating_subsume_fungible(id, e.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
x @ MultiAsset::ConcreteNonFungible {..} | x @ MultiAsset::AbstractNonFungible {..} => {
|
||||
},
|
||||
x @ MultiAsset::ConcreteNonFungible { .. } |
|
||||
x @ MultiAsset::AbstractNonFungible { .. } => {
|
||||
let (class, instance) = match x {
|
||||
MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class), instance),
|
||||
MultiAsset::ConcreteNonFungible { class, instance } =>
|
||||
(AssetId::Concrete(class), instance),
|
||||
MultiAsset::AbstractNonFungible { class, instance } =>
|
||||
(AssetId::Abstract(class), instance),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// remove the maxmimum possible up to id/amount from self, add the removed onto
|
||||
@@ -521,7 +567,7 @@ impl Assets {
|
||||
if let Some(entry) = self.non_fungible.take(&(class, instance)) {
|
||||
result.non_fungible.insert(entry);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
result
|
||||
@@ -543,7 +589,10 @@ mod tests {
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn ANF(class: u8, instance_id: u128) -> MultiAsset {
|
||||
MultiAsset::AbstractNonFungible { class: vec![class], instance: AssetInstance::Index { id: instance_id } }
|
||||
MultiAsset::AbstractNonFungible {
|
||||
class: vec![class],
|
||||
instance: AssetInstance::Index { id: instance_id },
|
||||
}
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn CF(amount: u128) -> MultiAsset {
|
||||
@@ -551,7 +600,10 @@ mod tests {
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn CNF(instance_id: u128) -> MultiAsset {
|
||||
MultiAsset::ConcreteNonFungible { class: MultiLocation::Null, instance: AssetInstance::Index { id: instance_id } }
|
||||
MultiAsset::ConcreteNonFungible {
|
||||
class: MultiLocation::Null,
|
||||
instance: AssetInstance::Index { id: instance_id },
|
||||
}
|
||||
}
|
||||
|
||||
fn test_assets() -> Assets {
|
||||
|
||||
@@ -14,18 +14,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::SendXcm;
|
||||
use frame_support::dispatch::{Dispatchable, Parameter};
|
||||
use frame_support::weights::{PostDispatchInfo, GetDispatchInfo};
|
||||
use crate::traits::{
|
||||
TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, ShouldExecute, WeightTrader, WeightBounds,
|
||||
OnResponse,
|
||||
ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, ShouldExecute, TransactAsset,
|
||||
WeightBounds, WeightTrader,
|
||||
};
|
||||
use frame_support::{
|
||||
dispatch::{Dispatchable, Parameter},
|
||||
weights::{GetDispatchInfo, PostDispatchInfo},
|
||||
};
|
||||
use xcm::v0::SendXcm;
|
||||
|
||||
/// The trait to parameterize the `XcmExecutor`.
|
||||
pub trait Config {
|
||||
/// The outer call dispatch type.
|
||||
type Call: Parameter + Dispatchable<PostInfo=PostDispatchInfo> + GetDispatchInfo;
|
||||
type Call: Parameter + Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo;
|
||||
|
||||
/// How to send an onward XCM message.
|
||||
type XcmSender: SendXcm;
|
||||
|
||||
@@ -16,24 +16,25 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::{prelude::*, marker::PhantomData};
|
||||
use frame_support::{
|
||||
ensure, weights::GetDispatchInfo,
|
||||
dispatch::{Weight, Dispatchable}
|
||||
dispatch::{Dispatchable, Weight},
|
||||
ensure,
|
||||
weights::GetDispatchInfo,
|
||||
};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
use xcm::v0::{
|
||||
ExecuteXcm, SendXcm, Error as XcmError, Outcome,
|
||||
MultiLocation, MultiAsset, Xcm, Order, Response,
|
||||
Error as XcmError, ExecuteXcm, MultiAsset, MultiLocation, Order, Outcome, Response, SendXcm,
|
||||
Xcm,
|
||||
};
|
||||
|
||||
pub mod traits;
|
||||
use traits::{
|
||||
TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, WeightBounds, WeightTrader,
|
||||
ShouldExecute, OnResponse
|
||||
ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, ShouldExecute, TransactAsset,
|
||||
WeightBounds, WeightTrader,
|
||||
};
|
||||
|
||||
mod assets;
|
||||
pub use assets::{Assets, AssetId};
|
||||
pub use assets::{AssetId, Assets};
|
||||
mod config;
|
||||
pub use config::Config;
|
||||
|
||||
@@ -70,10 +71,17 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
|
||||
None => return Outcome::Error(XcmError::Overflow),
|
||||
};
|
||||
if maximum_weight > weight_limit {
|
||||
return Outcome::Error(XcmError::WeightLimitReached(maximum_weight));
|
||||
return Outcome::Error(XcmError::WeightLimitReached(maximum_weight))
|
||||
}
|
||||
let mut trader = Config::Trader::new();
|
||||
let result = Self::do_execute_xcm(origin, true, message, &mut weight_credit, Some(shallow_weight), &mut trader);
|
||||
let result = Self::do_execute_xcm(
|
||||
origin,
|
||||
true,
|
||||
message,
|
||||
&mut weight_credit,
|
||||
Some(shallow_weight),
|
||||
&mut trader,
|
||||
);
|
||||
drop(trader);
|
||||
log::trace!(target: "xcm::execute_xcm", "result: {:?}", &result);
|
||||
match result {
|
||||
@@ -106,10 +114,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
log::trace!(
|
||||
target: "xcm::do_execute_xcm",
|
||||
"origin: {:?}, top_level: {:?}, message: {:?}, weight_credit: {:?}, maybe_shallow_weight: {:?}",
|
||||
origin,
|
||||
top_level,
|
||||
message,
|
||||
weight_credit,
|
||||
origin,
|
||||
top_level,
|
||||
message,
|
||||
weight_credit,
|
||||
maybe_shallow_weight,
|
||||
);
|
||||
// This is the weight of everything that cannot be paid for. This basically means all computation
|
||||
@@ -118,8 +126,14 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
.or_else(|| Config::Weigher::shallow(&mut message).ok())
|
||||
.ok_or(XcmError::WeightNotComputable)?;
|
||||
|
||||
Config::Barrier::should_execute(&origin, top_level, &message, shallow_weight, weight_credit)
|
||||
.map_err(|()| XcmError::Barrier)?;
|
||||
Config::Barrier::should_execute(
|
||||
&origin,
|
||||
top_level,
|
||||
&message,
|
||||
shallow_weight,
|
||||
weight_credit,
|
||||
)
|
||||
.map_err(|()| XcmError::Barrier)?;
|
||||
|
||||
// The surplus weight, defined as the amount by which `shallow_weight` plus all nested
|
||||
// `shallow_weight` values (ensuring no double-counting and also known as `deep_weight`) is an
|
||||
@@ -136,17 +150,20 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
holding.saturating_subsume_all(withdrawn);
|
||||
}
|
||||
Some((holding, effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::ReserveAssetDeposit { assets, effects }) => {
|
||||
// check whether we trust origin to be our reserve location for this asset.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(Config::IsReserve::filter_asset_location(asset, &origin), XcmError::UntrustedReserveLocation);
|
||||
ensure!(
|
||||
Config::IsReserve::filter_asset_location(asset, &origin),
|
||||
XcmError::UntrustedReserveLocation
|
||||
);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TransferAsset { assets, dest }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
for asset in assets {
|
||||
@@ -154,7 +171,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?;
|
||||
}
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TransferReserveAsset { mut assets, dest, effects }) => {
|
||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||
let inv_dest = Config::LocationInverter::invert_location(&dest);
|
||||
@@ -165,14 +182,17 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
}
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::TeleportAsset { assets, effects }) => {
|
||||
// check whether we trust origin to teleport this asset to us via config trait.
|
||||
for asset in assets.iter() {
|
||||
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
|
||||
// We only trust the origin to send us assets that they identify as their
|
||||
// sovereign assets.
|
||||
ensure!(Config::IsTeleporter::filter_asset_location(asset, &origin), XcmError::UntrustedTeleportLocation);
|
||||
ensure!(
|
||||
Config::IsTeleporter::filter_asset_location(asset, &origin),
|
||||
XcmError::UntrustedTeleportLocation
|
||||
);
|
||||
// We should check that the asset can actually be teleported in (for this to be in error, there
|
||||
// would need to be an accounting violation by one of the trusted chains, so it's unlikely, but we
|
||||
// don't want to punish a possibly innocent chain/user).
|
||||
@@ -182,7 +202,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
Config::AssetTransactor::check_in(&origin, asset);
|
||||
}
|
||||
Some((Assets::from(assets), effects))
|
||||
}
|
||||
},
|
||||
(origin, Xcm::Transact { origin_type, require_weight_at_most, mut call }) => {
|
||||
// We assume that the Relay-chain is allowed to use transact on this parachain.
|
||||
|
||||
@@ -198,8 +218,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
||||
// message makes sense.
|
||||
error_and_info.post_info.actual_weight
|
||||
}
|
||||
}.unwrap_or(weight);
|
||||
},
|
||||
}
|
||||
.unwrap_or(weight);
|
||||
let surplus = weight.saturating_sub(actual_weight);
|
||||
// Credit any surplus weight that we bought. This should be safe since it's work we
|
||||
// didn't realise that we didn't have to do.
|
||||
@@ -212,20 +233,21 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
// Return the overestimated amount so we can adjust our expectations on how much this entire
|
||||
// execution has taken.
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::QueryResponse { query_id, response }) => {
|
||||
Config::ResponseHandler::on_response(origin, query_id, response);
|
||||
None
|
||||
}
|
||||
},
|
||||
(origin, Xcm::RelayedFrom { who, message }) => {
|
||||
ensure!(who.is_interior(), XcmError::EscalationOfPrivilege);
|
||||
let mut origin = origin;
|
||||
origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?;
|
||||
let surplus = Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?;
|
||||
let surplus =
|
||||
Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?;
|
||||
total_surplus = total_surplus.saturating_add(surplus);
|
||||
None
|
||||
}
|
||||
_ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message.
|
||||
},
|
||||
_ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message.
|
||||
};
|
||||
|
||||
if let Some((mut holding, effects)) = maybe_holding_effects {
|
||||
@@ -266,11 +288,11 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
let assets = Self::reanchored(deposited, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
|
||||
},
|
||||
Order::InitiateReserveWithdraw { assets, reserve, effects} => {
|
||||
Order::InitiateReserveWithdraw { assets, reserve, effects } => {
|
||||
let assets = Self::reanchored(holding.saturating_take(assets), &reserve);
|
||||
Config::XcmSender::send_xcm(reserve, Xcm::WithdrawAsset { assets, effects })?;
|
||||
}
|
||||
Order::InitiateTeleport { assets, dest, effects} => {
|
||||
},
|
||||
Order::InitiateTeleport { assets, dest, effects } => {
|
||||
// We must do this first in order to resolve wildcards.
|
||||
let assets = holding.saturating_take(assets);
|
||||
for asset in assets.assets_iter() {
|
||||
@@ -278,28 +300,39 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
||||
}
|
||||
let assets = Self::reanchored(assets, &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?;
|
||||
}
|
||||
},
|
||||
Order::QueryHolding { query_id, dest, assets } => {
|
||||
let assets = Self::reanchored(holding.min(assets.iter()), &dest);
|
||||
Config::XcmSender::send_xcm(dest, Xcm::QueryResponse { query_id, response: Response::Assets(assets) })?;
|
||||
}
|
||||
Config::XcmSender::send_xcm(
|
||||
dest,
|
||||
Xcm::QueryResponse { query_id, response: Response::Assets(assets) },
|
||||
)?;
|
||||
},
|
||||
Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => {
|
||||
// pay for `weight` using up to `fees` of the holding account.
|
||||
let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?);
|
||||
let purchasing_weight =
|
||||
Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?);
|
||||
let max_fee = holding.try_take(fees).map_err(|()| XcmError::NotHoldingFees)?;
|
||||
let unspent = trader.buy_weight(purchasing_weight, max_fee)?;
|
||||
holding.saturating_subsume_all(unspent);
|
||||
|
||||
let mut remaining_weight = weight;
|
||||
for message in xcm.into_iter() {
|
||||
match Self::do_execute_xcm(origin.clone(), false, message, &mut remaining_weight, None, trader) {
|
||||
match Self::do_execute_xcm(
|
||||
origin.clone(),
|
||||
false,
|
||||
message,
|
||||
&mut remaining_weight,
|
||||
None,
|
||||
trader,
|
||||
) {
|
||||
Err(e) if halt_on_error => return Err(e),
|
||||
Err(_) => {}
|
||||
Ok(surplus) => { total_surplus += surplus }
|
||||
Err(_) => {},
|
||||
Ok(surplus) => total_surplus += surplus,
|
||||
}
|
||||
}
|
||||
holding.saturating_subsume(trader.refund_weight(remaining_weight));
|
||||
}
|
||||
},
|
||||
_ => return Err(XcmError::UnhandledEffect)?,
|
||||
}
|
||||
Ok(total_surplus)
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::{prelude::*, result::Result, borrow::Borrow, convert::TryFrom};
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use sp_std::{borrow::Borrow, convert::TryFrom, prelude::*, result::Result};
|
||||
use xcm::v0::{MultiLocation, OriginKind};
|
||||
|
||||
/// Generic third-party conversion trait. Use this when you don't want to force the user to use default
|
||||
@@ -29,12 +29,16 @@ use xcm::v0::{MultiLocation, OriginKind};
|
||||
/// the `Err(_)` of the last failing conversion (or `Err(())` for ref conversions).
|
||||
pub trait Convert<A: Clone, B: Clone> {
|
||||
/// Convert from `value` (of type `A`) into an equivalent value of type `B`, `Err` if not possible.
|
||||
fn convert(value: A) -> Result<B, A> { Self::convert_ref(&value).map_err(|_| value) }
|
||||
fn convert(value: A) -> Result<B, A> {
|
||||
Self::convert_ref(&value).map_err(|_| value)
|
||||
}
|
||||
fn convert_ref(value: impl Borrow<A>) -> Result<B, ()> {
|
||||
Self::convert(value.borrow().clone()).map_err(|_| ())
|
||||
}
|
||||
/// Convert from `value` (of type `B`) into an equivalent value of type `A`, `Err` if not possible.
|
||||
fn reverse(value: B) -> Result<A, B> { Self::reverse_ref(&value).map_err(|_| value) }
|
||||
fn reverse(value: B) -> Result<A, B> {
|
||||
Self::reverse_ref(&value).map_err(|_| value)
|
||||
}
|
||||
fn reverse_ref(value: impl Borrow<B>) -> Result<A, ()> {
|
||||
Self::reverse(value.borrow().clone()).map_err(|_| ())
|
||||
}
|
||||
@@ -85,13 +89,19 @@ impl<A: Clone, B: Clone> Convert<A, B> for Tuple {
|
||||
/// Simple pass-through which implements `BytesConversion` while not doing any conversion.
|
||||
pub struct Identity;
|
||||
impl<T: Clone> Convert<T, T> for Identity {
|
||||
fn convert(value: T) -> Result<T, T> { Ok(value) }
|
||||
fn reverse(value: T) -> Result<T, T> { Ok(value) }
|
||||
fn convert(value: T) -> Result<T, T> {
|
||||
Ok(value)
|
||||
}
|
||||
fn reverse(value: T) -> Result<T, T> {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of `Convert` trait using `TryFrom`.
|
||||
pub struct JustTry;
|
||||
impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Source, Dest> for JustTry {
|
||||
impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Source, Dest>
|
||||
for JustTry
|
||||
{
|
||||
fn convert(value: Source) -> Result<Dest, Source> {
|
||||
Dest::try_from(value.clone()).map_err(|_| value)
|
||||
}
|
||||
@@ -103,7 +113,9 @@ impl<Source: TryFrom<Dest> + Clone, Dest: TryFrom<Source> + Clone> Convert<Sourc
|
||||
/// Implementation of `Convert<_, Vec<u8>>` using the parity scale codec.
|
||||
pub struct Encoded;
|
||||
impl<T: Clone + Encode + Decode> Convert<T, Vec<u8>> for Encoded {
|
||||
fn convert_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> { Ok(value.borrow().encode()) }
|
||||
fn convert_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> {
|
||||
Ok(value.borrow().encode())
|
||||
}
|
||||
fn reverse_ref(bytes: impl Borrow<Vec<u8>>) -> Result<T, ()> {
|
||||
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
|
||||
}
|
||||
@@ -115,7 +127,9 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded {
|
||||
fn convert_ref(bytes: impl Borrow<Vec<u8>>) -> Result<T, ()> {
|
||||
T::decode(&mut &bytes.borrow()[..]).map_err(|_| ())
|
||||
}
|
||||
fn reverse_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> { Ok(value.borrow().encode()) }
|
||||
fn reverse_ref(value: impl Borrow<T>) -> Result<Vec<u8>, ()> {
|
||||
Ok(value.borrow().encode())
|
||||
}
|
||||
}
|
||||
|
||||
/// A converter `trait` for origin types.
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::{MultiAsset, Error as XcmError};
|
||||
use sp_std::result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset};
|
||||
|
||||
/// Errors associated with [`MatchesFungibles`] operation.
|
||||
pub enum Error {
|
||||
@@ -35,7 +35,8 @@ impl From<Error> for XcmError {
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::AssetNotFound,
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed => FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AmountToBalanceConversionFailed =>
|
||||
FailedToTransactAsset("AmountToBalanceConversionFailed"),
|
||||
Error::AssetIdConversionFailed => FailedToTransactAsset("AssetIdConversionFailed"),
|
||||
}
|
||||
}
|
||||
@@ -46,10 +47,7 @@ pub trait MatchesFungibles<AssetId, Balance> {
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
> MatchesFungibles<AssetId, Balance> for Tuple {
|
||||
impl<AssetId: Clone, Balance: Clone> MatchesFungibles<AssetId, Balance> for Tuple {
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), Error> {
|
||||
for_tuples!( #(
|
||||
match Tuple::matches_fungibles(a) { o @ Ok(_) => return o, _ => () }
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
//! Various traits used in configuring the executor.
|
||||
|
||||
mod conversion;
|
||||
pub use conversion::{InvertLocation, ConvertOrigin, Convert, JustTry, Identity, Encoded, Decoded};
|
||||
pub use conversion::{Convert, ConvertOrigin, Decoded, Encoded, Identity, InvertLocation, JustTry};
|
||||
mod filter_asset_location;
|
||||
pub use filter_asset_location::{FilterAssetLocation};
|
||||
pub use filter_asset_location::FilterAssetLocation;
|
||||
mod matches_fungible;
|
||||
pub use matches_fungible::{MatchesFungible};
|
||||
pub use matches_fungible::MatchesFungible;
|
||||
mod matches_fungibles;
|
||||
pub use matches_fungibles::{MatchesFungibles, Error};
|
||||
pub use matches_fungibles::{Error, MatchesFungibles};
|
||||
mod on_response;
|
||||
pub use on_response::OnResponse;
|
||||
mod should_execute;
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use xcm::v0::{Response, MultiLocation};
|
||||
use frame_support::weights::Weight;
|
||||
use xcm::v0::{MultiLocation, Response};
|
||||
|
||||
/// Define what needs to be done upon receiving a query response.
|
||||
pub trait OnResponse {
|
||||
@@ -25,6 +25,10 @@ pub trait OnResponse {
|
||||
fn on_response(origin: MultiLocation, query_id: u64, response: Response) -> Weight;
|
||||
}
|
||||
impl OnResponse for () {
|
||||
fn expecting_response(_origin: &MultiLocation, _query_id: u64) -> bool { false }
|
||||
fn on_response(_origin: MultiLocation, _query_id: u64, _response: Response) -> Weight { 0 }
|
||||
fn expecting_response(_origin: &MultiLocation, _query_id: u64) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_response(_origin: MultiLocation, _query_id: u64, _response: Response) -> Weight {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Xcm, MultiLocation};
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{MultiLocation, Xcm};
|
||||
|
||||
/// Trait to determine whether the execution engine should actually execute a given XCM.
|
||||
///
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error as XcmError, Result as XcmResult, MultiAsset, MultiLocation};
|
||||
use crate::Assets;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult};
|
||||
|
||||
/// Facility for asset transacting.
|
||||
///
|
||||
@@ -78,22 +78,30 @@ pub trait TransactAsset {
|
||||
/// Move an `asset` `from` one location in `to` another location.
|
||||
///
|
||||
/// Returns `XcmError::FailedToTransactAsset` if transfer failed.
|
||||
fn transfer_asset(_asset: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_asset: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::Unimplemented)
|
||||
}
|
||||
|
||||
/// Move an `asset` `from` one location in `to` another location.
|
||||
///
|
||||
/// Attempts to use `transfer_asset` and if not available then falls back to using a two-part withdraw/deposit.
|
||||
fn teleport_asset(asset: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn teleport_asset(
|
||||
asset: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
match Self::transfer_asset(asset, from, to) {
|
||||
Err(XcmError::Unimplemented) => {
|
||||
let assets = Self::withdraw_asset(asset, from)?;
|
||||
// Not a very forgiving attitude; once we implement roll-backs then it'll be nicer.
|
||||
Self::deposit_asset(asset, to)?;
|
||||
Ok(assets)
|
||||
}
|
||||
result => result
|
||||
},
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +168,11 @@ impl TransactAsset for Tuple {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
|
||||
fn transfer_asset(what: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
what: &MultiAsset,
|
||||
from: &MultiLocation,
|
||||
to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
for_tuples!( #(
|
||||
match Tuple::transfer_asset(what, from, to) {
|
||||
Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (),
|
||||
@@ -199,7 +211,11 @@ mod tests {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::AssetNotFound)
|
||||
}
|
||||
}
|
||||
@@ -218,7 +234,11 @@ mod tests {
|
||||
Err(XcmError::Overflow)
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Err(XcmError::Overflow)
|
||||
}
|
||||
}
|
||||
@@ -237,16 +257,24 @@ mod tests {
|
||||
Ok(Assets::default())
|
||||
}
|
||||
|
||||
fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> {
|
||||
fn transfer_asset(
|
||||
_what: &MultiAsset,
|
||||
_from: &MultiLocation,
|
||||
_to: &MultiLocation,
|
||||
) -> Result<Assets, XcmError> {
|
||||
Ok(Assets::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_to_asset_not_found() {
|
||||
type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
|
||||
type MultiTransactor =
|
||||
(UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::AssetNotFound));
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
Err(XcmError::AssetNotFound)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -260,7 +288,10 @@ mod tests {
|
||||
fn unexpected_error_stops_iteration() {
|
||||
type MultiTransactor = (OverflowTransactor, SuccessfulTransactor);
|
||||
|
||||
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::Overflow));
|
||||
assert_eq!(
|
||||
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
|
||||
Err(XcmError::Overflow)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Xcm, MultiAsset, MultiLocation, Error};
|
||||
use frame_support::weights::Weight;
|
||||
use crate::Assets;
|
||||
use frame_support::weights::Weight;
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Error, MultiAsset, MultiLocation, Xcm};
|
||||
|
||||
/// Determine the weight of an XCM message.
|
||||
pub trait WeightBounds<Call> {
|
||||
@@ -71,11 +71,15 @@ pub trait WeightTrader: Sized {
|
||||
/// purchased using `buy_weight`.
|
||||
///
|
||||
/// Default implementation refunds nothing.
|
||||
fn refund_weight(&mut self, _weight: Weight) -> MultiAsset { MultiAsset::None }
|
||||
fn refund_weight(&mut self, _weight: Weight) -> MultiAsset {
|
||||
MultiAsset::None
|
||||
}
|
||||
}
|
||||
|
||||
impl WeightTrader for () {
|
||||
fn new() -> Self { () }
|
||||
fn new() -> Self {
|
||||
()
|
||||
}
|
||||
fn buy_weight(&mut self, _: Weight, _: Assets) -> Result<Assets, Error> {
|
||||
Err(Error::Unimplemented)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user