mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 15:41:02 +00:00
[XCM] Multiple FungiblesAdapters support + WeightTrader::buy_weight more accurate error (#6739)
* Change ParaId->Sibling for `SiblingParachainConvertsVia` * [XCM] Multiple `FungiblesAdapter`s support + `WeightTrader::buy_weight` more accurate error * Added test for `ConvertedConcreteId` with `AsPrefixedGeneralIndex` * Solution 3. - new MatchedConvertedConcreteId with matching capabilities * Review fixes * Renamed `AssetNotFound` -> `AssetNotHandled` --------- Co-authored-by: parity-processbot <>
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM.
|
||||
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::traits::{Contains, Get};
|
||||
use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, MatchesNonFungibles};
|
||||
@@ -69,7 +69,7 @@ impl<
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Concrete(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
@@ -89,7 +89,7 @@ impl<
|
||||
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
|
||||
let (instance, class) = match (&a.fun, &a.id) {
|
||||
(NonFungible(ref instance), Concrete(ref class)) => (instance, class),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
@@ -113,7 +113,7 @@ impl<
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Abstract(ref id)) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
@@ -133,7 +133,7 @@ impl<
|
||||
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
|
||||
let (instance, class) = match (&a.fun, &a.id) {
|
||||
(NonFungible(ref instance), Abstract(ref class)) => (instance, class),
|
||||
_ => return Err(MatchError::AssetNotFound),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
@@ -147,3 +147,204 @@ impl<
|
||||
pub type ConvertedConcreteAssetId<A, B, C, O> = ConvertedConcreteId<A, B, C, O>;
|
||||
#[deprecated = "Use `ConvertedAbstractId` instead"]
|
||||
pub type ConvertedAbstractAssetId<A, B, C, O> = ConvertedAbstractId<A, B, C, O>;
|
||||
|
||||
pub struct MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertOther>(
|
||||
PhantomData<(AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertOther)>,
|
||||
);
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: Convert<MultiLocation, AssetId>,
|
||||
ConvertBalance: Convert<u128, Balance>,
|
||||
> MatchesFungibles<AssetId, Balance>
|
||||
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> {
|
||||
let (amount, id) = match (&a.fun, &a.id) {
|
||||
(Fungible(ref amount), Concrete(ref id)) if MatchAssetId::contains(id) => (amount, id),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let amount = ConvertBalance::convert_ref(amount)
|
||||
.map_err(|_| MatchError::AmountToBalanceConversionFailed)?;
|
||||
Ok((what, amount))
|
||||
}
|
||||
}
|
||||
impl<
|
||||
ClassId: Clone,
|
||||
InstanceId: Clone,
|
||||
MatchClassId: Contains<MultiLocation>,
|
||||
ConvertClassId: Convert<MultiLocation, ClassId>,
|
||||
ConvertInstanceId: Convert<AssetInstance, InstanceId>,
|
||||
> MatchesNonFungibles<ClassId, InstanceId>
|
||||
for MatchedConvertedConcreteId<ClassId, InstanceId, MatchClassId, ConvertClassId, ConvertInstanceId>
|
||||
{
|
||||
fn matches_nonfungibles(a: &MultiAsset) -> result::Result<(ClassId, InstanceId), MatchError> {
|
||||
let (instance, class) = match (&a.fun, &a.id) {
|
||||
(NonFungible(ref instance), Concrete(ref class)) if MatchClassId::contains(class) =>
|
||||
(instance, class),
|
||||
_ => return Err(MatchError::AssetNotHandled),
|
||||
};
|
||||
let what =
|
||||
ConvertClassId::convert_ref(class).map_err(|_| MatchError::AssetIdConversionFailed)?;
|
||||
let instance = ConvertInstanceId::convert_ref(instance)
|
||||
.map_err(|_| MatchError::InstanceConversionFailed)?;
|
||||
Ok((what, instance))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use xcm_executor::traits::JustTry;
|
||||
|
||||
struct OnlyParentZero;
|
||||
impl Contains<MultiLocation> for OnlyParentZero {
|
||||
fn contains(a: &MultiLocation) -> bool {
|
||||
match a {
|
||||
MultiLocation { parents: 0, .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matched_converted_concrete_id_for_fungibles_works() {
|
||||
type AssetIdForTrustBackedAssets = u32;
|
||||
type Balance = u128;
|
||||
frame_support::parameter_types! {
|
||||
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50).into();
|
||||
}
|
||||
|
||||
// ConvertedConcreteId cfg
|
||||
type Converter = MatchedConvertedConcreteId<
|
||||
AssetIdForTrustBackedAssets,
|
||||
Balance,
|
||||
OnlyParentZero,
|
||||
AsPrefixedGeneralIndex<
|
||||
TrustBackedAssetsPalletLocation,
|
||||
AssetIdForTrustBackedAssets,
|
||||
JustTry,
|
||||
>,
|
||||
JustTry,
|
||||
>;
|
||||
assert_eq!(
|
||||
TrustBackedAssetsPalletLocation::get(),
|
||||
MultiLocation { parents: 0, interior: X1(PalletInstance(50)) }
|
||||
);
|
||||
|
||||
// err - does not match
|
||||
assert_eq!(
|
||||
Converter::matches_fungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: Fungible(12345),
|
||||
}),
|
||||
Err(MatchError::AssetNotHandled)
|
||||
);
|
||||
|
||||
// err - matches, but convert fails
|
||||
assert_eq!(
|
||||
Converter::matches_fungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(
|
||||
0,
|
||||
X2(PalletInstance(50), GeneralKey { length: 1, data: [1; 32] })
|
||||
)),
|
||||
fun: Fungible(12345),
|
||||
}),
|
||||
Err(MatchError::AssetIdConversionFailed)
|
||||
);
|
||||
|
||||
// err - matches, but NonFungible
|
||||
assert_eq!(
|
||||
Converter::matches_fungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: NonFungible(Index(54321)),
|
||||
}),
|
||||
Err(MatchError::AssetNotHandled)
|
||||
);
|
||||
|
||||
// ok
|
||||
assert_eq!(
|
||||
Converter::matches_fungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: Fungible(12345),
|
||||
}),
|
||||
Ok((1, 12345))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matched_converted_concrete_id_for_nonfungibles_works() {
|
||||
type ClassId = u32;
|
||||
type ClassInstanceId = u64;
|
||||
frame_support::parameter_types! {
|
||||
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50).into();
|
||||
}
|
||||
|
||||
// ConvertedConcreteId cfg
|
||||
struct ClassInstanceIdConverter;
|
||||
impl Convert<AssetInstance, ClassInstanceId> for ClassInstanceIdConverter {
|
||||
fn convert_ref(value: impl Borrow<AssetInstance>) -> Result<ClassInstanceId, ()> {
|
||||
value.borrow().clone().try_into().map_err(|_| ())
|
||||
}
|
||||
|
||||
fn reverse_ref(value: impl Borrow<ClassInstanceId>) -> Result<AssetInstance, ()> {
|
||||
Ok(AssetInstance::from(value.borrow().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
type Converter = MatchedConvertedConcreteId<
|
||||
ClassId,
|
||||
ClassInstanceId,
|
||||
OnlyParentZero,
|
||||
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, ClassId, JustTry>,
|
||||
ClassInstanceIdConverter,
|
||||
>;
|
||||
assert_eq!(
|
||||
TrustBackedAssetsPalletLocation::get(),
|
||||
MultiLocation { parents: 0, interior: X1(PalletInstance(50)) }
|
||||
);
|
||||
|
||||
// err - does not match
|
||||
assert_eq!(
|
||||
Converter::matches_nonfungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: NonFungible(Index(54321)),
|
||||
}),
|
||||
Err(MatchError::AssetNotHandled)
|
||||
);
|
||||
|
||||
// err - matches, but convert fails
|
||||
assert_eq!(
|
||||
Converter::matches_nonfungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(
|
||||
0,
|
||||
X2(PalletInstance(50), GeneralKey { length: 1, data: [1; 32] })
|
||||
)),
|
||||
fun: NonFungible(Index(54321)),
|
||||
}),
|
||||
Err(MatchError::AssetIdConversionFailed)
|
||||
);
|
||||
|
||||
// err - matches, but Fungible vs NonFungible
|
||||
assert_eq!(
|
||||
Converter::matches_nonfungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: Fungible(12345),
|
||||
}),
|
||||
Err(MatchError::AssetNotHandled)
|
||||
);
|
||||
|
||||
// ok
|
||||
assert_eq!(
|
||||
Converter::matches_nonfungibles(&MultiAsset {
|
||||
id: Concrete(MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1)))),
|
||||
fun: NonFungible(Index(54321)),
|
||||
}),
|
||||
Ok((1, 54321))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ use xcm_executor::{
|
||||
|
||||
/// Asset transaction errors.
|
||||
enum Error {
|
||||
/// Asset not found.
|
||||
AssetNotFound,
|
||||
/// The given asset is not handled. (According to [`XcmError::AssetNotFound`])
|
||||
AssetNotHandled,
|
||||
/// `MultiLocation` to `AccountId` conversion failed.
|
||||
AccountIdConversionFailed,
|
||||
}
|
||||
@@ -38,7 +38,7 @@ impl From<Error> for XcmError {
|
||||
fn from(e: Error) -> Self {
|
||||
use XcmError::FailedToTransactAsset;
|
||||
match e {
|
||||
Error::AssetNotFound => XcmError::AssetNotFound,
|
||||
Error::AssetNotHandled => XcmError::AssetNotFound,
|
||||
Error::AccountIdConversionFailed => FailedToTransactAsset("AccountIdConversionFailed"),
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ impl<
|
||||
log::trace!(target: "xcm::currency_adapter", "can_check_in origin: {:?}, what: {:?}", _origin, what);
|
||||
// Check we handle this asset.
|
||||
let amount: Currency::Balance =
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?;
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::can_reduce_checked(checked_account, amount),
|
||||
@@ -168,7 +168,7 @@ impl<
|
||||
|
||||
fn can_check_out(_dest: &MultiLocation, what: &MultiAsset, _context: &XcmContext) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "check_out dest: {:?}, what: {:?}", _dest, what);
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?;
|
||||
match CheckedAccount::get() {
|
||||
Some((checked_account, MintLocation::Local)) =>
|
||||
Self::can_accrue_checked(checked_account, amount),
|
||||
@@ -194,7 +194,7 @@ impl<
|
||||
fn deposit_asset(what: &MultiAsset, who: &MultiLocation, _context: &XcmContext) -> Result {
|
||||
log::trace!(target: "xcm::currency_adapter", "deposit_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotFound)?;
|
||||
let amount = Matcher::matches_fungible(&what).ok_or(Error::AssetNotHandled)?;
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let _imbalance = Currency::deposit_creating(&who, amount);
|
||||
@@ -208,7 +208,7 @@ impl<
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "withdraw_asset what: {:?}, who: {:?}", what, who);
|
||||
// Check we handle this asset.
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotFound)?;
|
||||
let amount = Matcher::matches_fungible(what).ok_or(Error::AssetNotHandled)?;
|
||||
let who =
|
||||
AccountIdConverter::convert_ref(who).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
Currency::withdraw(&who, amount, WithdrawReasons::TRANSFER, AllowDeath)
|
||||
@@ -223,7 +223,7 @@ impl<
|
||||
_context: &XcmContext,
|
||||
) -> result::Result<Assets, XcmError> {
|
||||
log::trace!(target: "xcm::currency_adapter", "internal_transfer_asset asset: {:?}, from: {:?}, to: {:?}", asset, from, to);
|
||||
let amount = Matcher::matches_fungible(asset).ok_or(Error::AssetNotFound)?;
|
||||
let amount = Matcher::matches_fungible(asset).ok_or(Error::AssetNotHandled)?;
|
||||
let from =
|
||||
AccountIdConverter::convert_ref(from).map_err(|()| Error::AccountIdConversionFailed)?;
|
||||
let to =
|
||||
|
||||
Reference in New Issue
Block a user