mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-18 22:21:02 +00:00
Reanchor should return canonical location (#4470)
* Reanchor should return canonical * Formatting * Formatting * Update xcm/src/v1/multilocation.rs * Formatting * Fixes * Don't discard unreanchorable assets * Formatting * Docs * Fixes * Fixes * tidy
This commit is contained in:
@@ -71,6 +71,9 @@ impl InvertLocation for InvertNothing {
|
|||||||
fn invert_location(_: &MultiLocation) -> sp_std::result::Result<MultiLocation, ()> {
|
fn invert_location(_: &MultiLocation) -> sp_std::result::Result<MultiLocation, ()> {
|
||||||
Ok(Here.into())
|
Ok(Here.into())
|
||||||
}
|
}
|
||||||
|
fn ancestry() -> MultiLocation {
|
||||||
|
Here.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct XcmConfig;
|
pub struct XcmConfig;
|
||||||
|
|||||||
@@ -777,13 +777,12 @@ pub mod pallet {
|
|||||||
let value = (origin_location, assets.drain());
|
let value = (origin_location, assets.drain());
|
||||||
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
|
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
|
||||||
let (origin_location, assets) = value;
|
let (origin_location, assets) = value;
|
||||||
let inv_dest = T::LocationInverter::invert_location(&dest)
|
let ancestry = T::LocationInverter::ancestry();
|
||||||
.map_err(|()| Error::<T>::DestinationNotInvertible)?;
|
|
||||||
let fees = assets
|
let fees = assets
|
||||||
.get(fee_asset_item as usize)
|
.get(fee_asset_item as usize)
|
||||||
.ok_or(Error::<T>::Empty)?
|
.ok_or(Error::<T>::Empty)?
|
||||||
.clone()
|
.clone()
|
||||||
.reanchored(&inv_dest)
|
.reanchored(&dest, &ancestry)
|
||||||
.map_err(|_| Error::<T>::CannotReanchor)?;
|
.map_err(|_| Error::<T>::CannotReanchor)?;
|
||||||
let max_assets = assets.len() as u32;
|
let max_assets = assets.len() as u32;
|
||||||
let assets: MultiAssets = assets.into();
|
let assets: MultiAssets = assets.into();
|
||||||
@@ -835,13 +834,12 @@ pub mod pallet {
|
|||||||
let value = (origin_location, assets.drain());
|
let value = (origin_location, assets.drain());
|
||||||
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
|
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
|
||||||
let (origin_location, assets) = value;
|
let (origin_location, assets) = value;
|
||||||
let inv_dest = T::LocationInverter::invert_location(&dest)
|
let ancestry = T::LocationInverter::ancestry();
|
||||||
.map_err(|()| Error::<T>::DestinationNotInvertible)?;
|
|
||||||
let fees = assets
|
let fees = assets
|
||||||
.get(fee_asset_item as usize)
|
.get(fee_asset_item as usize)
|
||||||
.ok_or(Error::<T>::Empty)?
|
.ok_or(Error::<T>::Empty)?
|
||||||
.clone()
|
.clone()
|
||||||
.reanchored(&inv_dest)
|
.reanchored(&dest, &ancestry)
|
||||||
.map_err(|_| Error::<T>::CannotReanchor)?;
|
.map_err(|_| Error::<T>::CannotReanchor)?;
|
||||||
let max_assets = assets.len() as u32;
|
let max_assets = assets.len() as u32;
|
||||||
let assets: MultiAssets = assets.into();
|
let assets: MultiAssets = assets.into();
|
||||||
|
|||||||
@@ -116,13 +116,22 @@ impl From<Vec<u8>> for AssetId {
|
|||||||
|
|
||||||
impl AssetId {
|
impl AssetId {
|
||||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
||||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||||
if let AssetId::Concrete(ref mut l) = self {
|
if let AssetId::Concrete(ref mut l) = self {
|
||||||
l.prepend_with(prepend.clone()).map_err(|_| ())?;
|
l.prepend_with(prepend.clone()).map_err(|_| ())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutate the asset to represent the same value from the perspective of a new `target`
|
||||||
|
/// location. The local chain's location is provided in `ancestry`.
|
||||||
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
|
if let AssetId::Concrete(ref mut l) = self {
|
||||||
|
l.reanchor(target, ancestry)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value.
|
/// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value.
|
||||||
pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
|
pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset {
|
||||||
MultiAsset { fun, id: self }
|
MultiAsset { fun, id: self }
|
||||||
@@ -203,13 +212,24 @@ impl MultiAsset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
||||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
pub fn prepend_with(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
||||||
self.id.reanchor(prepend)
|
self.id.prepend_with(prepend)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a `MultiLocation` to a concrete asset, giving it a new root location.
|
/// Mutate the location of the asset identifier if concrete, giving it the same location
|
||||||
pub fn reanchored(mut self, prepend: &MultiLocation) -> Result<Self, ()> {
|
/// relative to a `target` context. The local context is provided as `ancestry`.
|
||||||
self.reanchor(prepend)?;
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
|
self.id.reanchor(target, ancestry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutate the location of the asset identifier if concrete, giving it the same location
|
||||||
|
/// relative to a `target` context. The local context is provided as `ancestry`.
|
||||||
|
pub fn reanchored(
|
||||||
|
mut self,
|
||||||
|
target: &MultiLocation,
|
||||||
|
ancestry: &MultiLocation,
|
||||||
|
) -> Result<Self, ()> {
|
||||||
|
self.id.reanchor(target, ancestry)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,8 +435,13 @@ impl MultiAssets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
||||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> {
|
||||||
self.0.iter_mut().try_for_each(|i| i.reanchor(prepend))
|
self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location.
|
||||||
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
|
self.0.iter_mut().try_for_each(|i| i.reanchor(target, ancestry))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference to an item at a specific index or `None` if it doesn't exist.
|
/// Return a reference to an item at a specific index or `None` if it doesn't exist.
|
||||||
@@ -485,10 +510,10 @@ impl WildMultiAsset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
use WildMultiAsset::*;
|
use WildMultiAsset::*;
|
||||||
match self {
|
match self {
|
||||||
AllOf { ref mut id, .. } => id.reanchor(prepend).map_err(|_| ()),
|
AllOf { ref mut id, .. } => id.reanchor(target, ancestry).map_err(|_| ()),
|
||||||
All => Ok(()),
|
All => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,10 +572,10 @@ impl MultiAssetFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
/// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location.
|
||||||
pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> {
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
match self {
|
match self {
|
||||||
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(prepend),
|
MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(target, ancestry),
|
||||||
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(prepend),
|
MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(target, ancestry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,60 @@ impl MultiLocation {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutate `self` so that it represents the same location from the point of view of `target`.
|
||||||
|
/// The context of `self` is provided as `ancestry`.
|
||||||
|
///
|
||||||
|
/// Does not modify `self` in case of overflow.
|
||||||
|
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
|
||||||
|
// TODO: https://github.com/paritytech/polkadot/issues/4489 Optimize this.
|
||||||
|
|
||||||
|
// 1. Use our `ancestry` to figure out how the `target` would address us.
|
||||||
|
let inverted_target = ancestry.inverted(target)?;
|
||||||
|
|
||||||
|
// 2. Prepend `inverted_target` to `self` to get self's location from the perspective of
|
||||||
|
// `target`.
|
||||||
|
self.prepend_with(inverted_target).map_err(|_| ())?;
|
||||||
|
|
||||||
|
// 3. Given that we know some of `target` ancestry, ensure that any parents in `self` are
|
||||||
|
// strictly needed.
|
||||||
|
self.simplify(target.interior());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Treating `self` as a context, determine how it would be referenced by a `target` location.
|
||||||
|
pub fn inverted(&self, target: &MultiLocation) -> Result<MultiLocation, ()> {
|
||||||
|
use Junction::OnlyChild;
|
||||||
|
let mut ancestry = self.clone();
|
||||||
|
let mut junctions = Junctions::Here;
|
||||||
|
for _ in 0..target.parent_count() {
|
||||||
|
junctions = junctions
|
||||||
|
.pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild))
|
||||||
|
.map_err(|_| ())?;
|
||||||
|
}
|
||||||
|
let parents = target.interior().len() as u8;
|
||||||
|
Ok(MultiLocation::new(parents, junctions))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove any unneeded parents/junctions in `self` based on the given context it will be
|
||||||
|
/// interpreted in.
|
||||||
|
pub fn simplify(&mut self, context: &Junctions) {
|
||||||
|
if context.len() < self.parents as usize {
|
||||||
|
// Not enough context
|
||||||
|
return
|
||||||
|
}
|
||||||
|
while self.parents > 0 {
|
||||||
|
let maybe = context.at(context.len() - (self.parents as usize));
|
||||||
|
match (self.interior.first(), maybe) {
|
||||||
|
(Some(i), Some(j)) if i == j => {
|
||||||
|
self.interior.take_first();
|
||||||
|
self.parents -= 1;
|
||||||
|
},
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
|
/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
|
||||||
@@ -773,9 +827,82 @@ impl TryFrom<MultiLocation> for Junctions {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
|
use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
|
||||||
use crate::opaque::v1::{Junction::*, NetworkId::Any};
|
use crate::opaque::v1::{Junction::*, NetworkId::*};
|
||||||
use parity_scale_codec::{Decode, Encode};
|
use parity_scale_codec::{Decode, Encode};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inverted_works() {
|
||||||
|
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into();
|
||||||
|
let target = (Parent, PalletInstance(69)).into();
|
||||||
|
let expected = (Parent, PalletInstance(42)).into();
|
||||||
|
let inverted = ancestry.inverted(&target).unwrap();
|
||||||
|
assert_eq!(inverted, expected);
|
||||||
|
|
||||||
|
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
|
||||||
|
let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
|
||||||
|
let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
|
||||||
|
let inverted = ancestry.inverted(&target).unwrap();
|
||||||
|
assert_eq!(inverted, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simplify_basic_works() {
|
||||||
|
let mut location: MultiLocation =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X2(Parachain(1000), PalletInstance(42));
|
||||||
|
let expected = GeneralIndex(69).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
|
||||||
|
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X1(PalletInstance(42));
|
||||||
|
let expected = GeneralIndex(69).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
|
||||||
|
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X2(Parachain(1000), PalletInstance(42));
|
||||||
|
let expected = GeneralIndex(69).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
|
||||||
|
let mut location: MultiLocation =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
|
||||||
|
let expected = GeneralIndex(69).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simplify_incompatible_location_fails() {
|
||||||
|
let mut location: MultiLocation =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
|
||||||
|
let expected =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
|
||||||
|
let mut location: MultiLocation =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
let context = X1(Parachain(1000));
|
||||||
|
let expected =
|
||||||
|
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
|
||||||
|
location.simplify(&context);
|
||||||
|
assert_eq!(location, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reanchor_works() {
|
||||||
|
let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
|
||||||
|
let ancestry = Parachain(2000).into();
|
||||||
|
let target = (Parent, Parachain(1000)).into();
|
||||||
|
let expected = GeneralIndex(42).into();
|
||||||
|
id.reanchor(&target, &ancestry).unwrap();
|
||||||
|
assert_eq!(id, expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_and_decode_works() {
|
fn encode_and_decode_works() {
|
||||||
let m = MultiLocation {
|
let m = MultiLocation {
|
||||||
|
|||||||
@@ -182,6 +182,9 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
|
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
|
||||||
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
|
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
|
||||||
|
fn ancestry() -> MultiLocation {
|
||||||
|
Ancestry::get()
|
||||||
|
}
|
||||||
fn invert_location(location: &MultiLocation) -> Result<MultiLocation, ()> {
|
fn invert_location(location: &MultiLocation) -> Result<MultiLocation, ()> {
|
||||||
let mut ancestry = Ancestry::get();
|
let mut ancestry = Ancestry::get();
|
||||||
let mut junctions = Here;
|
let mut junctions = Here;
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ impl Assets {
|
|||||||
self.fungible = fungible
|
self.fungible = fungible
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(mut id, amount)| {
|
.map(|(mut id, amount)| {
|
||||||
let _ = id.reanchor(prepend);
|
let _ = id.prepend_with(prepend);
|
||||||
(id, amount)
|
(id, amount)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -203,12 +203,48 @@ impl Assets {
|
|||||||
self.non_fungible = non_fungible
|
self.non_fungible = non_fungible
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(mut class, inst)| {
|
.map(|(mut class, inst)| {
|
||||||
let _ = class.reanchor(prepend);
|
let _ = class.prepend_with(prepend);
|
||||||
(class, inst)
|
(class, inst)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutate the assets to be interpreted as the same assets from the perspective of a `target`
|
||||||
|
/// chain. The local chain's `ancestry` is provided.
|
||||||
|
///
|
||||||
|
/// Any assets which were unable to be reanchored are introduced into `failed_bin`.
|
||||||
|
pub fn reanchor(
|
||||||
|
&mut self,
|
||||||
|
target: &MultiLocation,
|
||||||
|
ancestry: &MultiLocation,
|
||||||
|
mut maybe_failed_bin: Option<&mut Self>,
|
||||||
|
) {
|
||||||
|
let mut fungible = Default::default();
|
||||||
|
mem::swap(&mut self.fungible, &mut fungible);
|
||||||
|
self.fungible = fungible
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(mut id, amount)| match id.reanchor(target, ancestry) {
|
||||||
|
Ok(()) => Some((id, amount)),
|
||||||
|
Err(()) => {
|
||||||
|
maybe_failed_bin.as_mut().map(|f| f.fungible.insert(id, amount));
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut non_fungible = Default::default();
|
||||||
|
mem::swap(&mut self.non_fungible, &mut non_fungible);
|
||||||
|
self.non_fungible = non_fungible
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(mut class, inst)| match class.reanchor(target, ancestry) {
|
||||||
|
Ok(()) => Some((class, inst)),
|
||||||
|
Err(()) => {
|
||||||
|
maybe_failed_bin.as_mut().map(|f| f.non_fungible.insert((class, inst)));
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns an error unless all `assets` are contained in `self`. In the case of an error, the first asset in
|
/// Returns an error unless all `assets` are contained in `self`. In the case of an error, the first asset in
|
||||||
/// `assets` which is not wholly in `self` is returned.
|
/// `assets` which is not wholly in `self` is returned.
|
||||||
pub fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> {
|
pub fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> {
|
||||||
|
|||||||
@@ -304,12 +304,11 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
TransferReserveAsset { mut assets, dest, xcm } => {
|
TransferReserveAsset { mut assets, dest, xcm } => {
|
||||||
let origin = self.origin.as_ref().ok_or(XcmError::BadOrigin)?;
|
let origin = self.origin.as_ref().ok_or(XcmError::BadOrigin)?;
|
||||||
// Take `assets` from the origin account (on-chain) and place into dest account.
|
// Take `assets` from the origin account (on-chain) and place into dest account.
|
||||||
let inv_dest = Config::LocationInverter::invert_location(&dest)
|
|
||||||
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
|
|
||||||
for asset in assets.inner() {
|
for asset in assets.inner() {
|
||||||
Config::AssetTransactor::beam_asset(asset, origin, &dest)?;
|
Config::AssetTransactor::beam_asset(asset, origin, &dest)?;
|
||||||
}
|
}
|
||||||
assets.reanchor(&inv_dest).map_err(|()| XcmError::MultiLocationFull)?;
|
let ancestry = Config::LocationInverter::ancestry();
|
||||||
|
assets.reanchor(&dest, &ancestry).map_err(|()| XcmError::MultiLocationFull)?;
|
||||||
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
|
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
|
||||||
message.extend(xcm.0.into_iter());
|
message.extend(xcm.0.into_iter());
|
||||||
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
||||||
@@ -401,13 +400,21 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
for asset in deposited.assets_iter() {
|
for asset in deposited.assets_iter() {
|
||||||
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
|
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
|
||||||
}
|
}
|
||||||
let assets = Self::reanchored(deposited, &dest)?;
|
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
|
||||||
|
// be reanchored because we have already called `deposit_asset` on all assets.
|
||||||
|
let assets = Self::reanchored(deposited, &dest, None);
|
||||||
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
|
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
|
||||||
message.extend(xcm.0.into_iter());
|
message.extend(xcm.0.into_iter());
|
||||||
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
||||||
},
|
},
|
||||||
InitiateReserveWithdraw { assets, reserve, xcm } => {
|
InitiateReserveWithdraw { assets, reserve, xcm } => {
|
||||||
let assets = Self::reanchored(self.holding.saturating_take(assets), &reserve)?;
|
// Note that here we are able to place any assets which could not be reanchored
|
||||||
|
// back into Holding.
|
||||||
|
let assets = Self::reanchored(
|
||||||
|
self.holding.saturating_take(assets),
|
||||||
|
&reserve,
|
||||||
|
Some(&mut self.holding),
|
||||||
|
);
|
||||||
let mut message = vec![WithdrawAsset(assets), ClearOrigin];
|
let mut message = vec![WithdrawAsset(assets), ClearOrigin];
|
||||||
message.extend(xcm.0.into_iter());
|
message.extend(xcm.0.into_iter());
|
||||||
Config::XcmSender::send_xcm(reserve, Xcm(message)).map_err(Into::into)
|
Config::XcmSender::send_xcm(reserve, Xcm(message)).map_err(Into::into)
|
||||||
@@ -418,13 +425,17 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
for asset in assets.assets_iter() {
|
for asset in assets.assets_iter() {
|
||||||
Config::AssetTransactor::check_out(&dest, &asset);
|
Config::AssetTransactor::check_out(&dest, &asset);
|
||||||
}
|
}
|
||||||
let assets = Self::reanchored(assets, &dest)?;
|
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
|
||||||
|
// be reanchored because we have already checked all assets out.
|
||||||
|
let assets = Self::reanchored(assets, &dest, None);
|
||||||
let mut message = vec![ReceiveTeleportedAsset(assets), ClearOrigin];
|
let mut message = vec![ReceiveTeleportedAsset(assets), ClearOrigin];
|
||||||
message.extend(xcm.0.into_iter());
|
message.extend(xcm.0.into_iter());
|
||||||
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
|
||||||
},
|
},
|
||||||
QueryHolding { query_id, dest, assets, max_response_weight } => {
|
QueryHolding { query_id, dest, assets, max_response_weight } => {
|
||||||
let assets = Self::reanchored(self.holding.min(&assets), &dest)?;
|
// Note that we pass `None` as `maybe_failed_bin` since no assets were ever removed
|
||||||
|
// from Holding.
|
||||||
|
let assets = Self::reanchored(self.holding.min(&assets), &dest, None);
|
||||||
let max_weight = max_response_weight;
|
let max_weight = max_response_weight;
|
||||||
let response = Response::Assets(assets);
|
let response = Response::Assets(assets);
|
||||||
let instruction = QueryResponse { query_id, response, max_weight };
|
let instruction = QueryResponse { query_id, response, max_weight };
|
||||||
@@ -497,10 +508,13 @@ impl<Config: config::Config> XcmExecutor<Config> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reanchored(mut assets: Assets, dest: &MultiLocation) -> Result<MultiAssets, XcmError> {
|
/// NOTE: Any assets which were unable to be reanchored are introduced into `failed_bin`.
|
||||||
let inv_dest = Config::LocationInverter::invert_location(&dest)
|
fn reanchored(
|
||||||
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
|
mut assets: Assets,
|
||||||
assets.prepend_location(&inv_dest);
|
dest: &MultiLocation,
|
||||||
Ok(assets.into_assets_iter().collect::<Vec<_>>().into())
|
maybe_failed_bin: Option<&mut Assets>,
|
||||||
|
) -> MultiAssets {
|
||||||
|
assets.reanchor(dest, &Config::LocationInverter::ancestry(), maybe_failed_bin);
|
||||||
|
assets.into_assets_iter().collect::<Vec<_>>().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,5 +207,6 @@ impl<O> ConvertOrigin<O> for Tuple {
|
|||||||
/// Means of inverting a location: given a location which describes a `target` interpreted from the
|
/// Means of inverting a location: given a location which describes a `target` interpreted from the
|
||||||
/// `source`, this will provide the corresponding location which describes the `source`.
|
/// `source`, this will provide the corresponding location which describes the `source`.
|
||||||
pub trait InvertLocation {
|
pub trait InvertLocation {
|
||||||
|
fn ancestry() -> MultiLocation;
|
||||||
fn invert_location(l: &MultiLocation) -> Result<MultiLocation, ()>;
|
fn invert_location(l: &MultiLocation) -> Result<MultiLocation, ()>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user