Skip to content

Commit a3724dc

Browse files
authored
Use CurrencyId convert. (#437)
* Use CurrencyId convert. * Apply review suggestions.
1 parent e4091cd commit a3724dc

File tree

5 files changed

+99
-68
lines changed

5 files changed

+99
-68
lines changed

xcm-support/src/currency_adapter.rs

+30-15
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use codec::FullCodec;
2-
use sp_runtime::traits::{MaybeSerializeDeserialize, SaturatedConversion};
2+
use sp_runtime::traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion};
33
use sp_std::{
44
cmp::{Eq, PartialEq},
5-
convert::{TryFrom, TryInto},
65
fmt::Debug,
76
marker::PhantomData,
87
prelude::*,
@@ -38,35 +37,53 @@ impl From<Error> for XcmError {
3837
///
3938
/// If the asset is known, deposit/withdraw will be handled by `MultiCurrency`,
4039
/// else by `UnknownAsset` if unknown.
41-
pub struct MultiCurrencyAdapter<MultiCurrency, UnknownAsset, Matcher, AccountIdConverter, AccountId, CurrencyId>(
40+
pub struct MultiCurrencyAdapter<
41+
MultiCurrency,
42+
UnknownAsset,
43+
Matcher,
44+
AccountId,
45+
AccountIdConvert,
46+
CurrencyId,
47+
CurrencyIdConvert,
48+
>(
4249
PhantomData<(
4350
MultiCurrency,
4451
UnknownAsset,
4552
Matcher,
46-
AccountIdConverter,
4753
AccountId,
54+
AccountIdConvert,
4855
CurrencyId,
56+
CurrencyIdConvert,
4957
)>,
5058
);
5159

5260
impl<
5361
MultiCurrency: orml_traits::MultiCurrency<AccountId, CurrencyId = CurrencyId>,
5462
UnknownAsset: UnknownAssetT,
5563
Matcher: MatchesFungible<MultiCurrency::Balance>,
56-
AccountIdConverter: LocationConversion<AccountId>,
5764
AccountId: sp_std::fmt::Debug,
58-
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug + TryFrom<MultiAsset>,
65+
AccountIdConvert: LocationConversion<AccountId>,
66+
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug,
67+
CurrencyIdConvert: Convert<MultiAsset, Option<CurrencyId>>,
5968
> TransactAsset
60-
for MultiCurrencyAdapter<MultiCurrency, UnknownAsset, Matcher, AccountIdConverter, AccountId, CurrencyId>
69+
for MultiCurrencyAdapter<
70+
MultiCurrency,
71+
UnknownAsset,
72+
Matcher,
73+
AccountId,
74+
AccountIdConvert,
75+
CurrencyId,
76+
CurrencyIdConvert,
77+
>
6178
{
6279
fn deposit_asset(asset: &MultiAsset, location: &MultiLocation) -> Result {
6380
match (
64-
AccountIdConverter::from_location(location),
65-
asset.clone().try_into(),
81+
AccountIdConvert::from_location(location),
82+
CurrencyIdConvert::convert(asset.clone()),
6683
Matcher::matches_fungible(&asset),
6784
) {
6885
// known asset
69-
(Some(who), Ok(currency_id), Some(amount)) => {
86+
(Some(who), Some(currency_id), Some(amount)) => {
7087
MultiCurrency::deposit(currency_id, &who, amount).map_err(|e| XcmError::FailedToTransactAsset(e.into()))
7188
}
7289
// unknown asset
@@ -76,12 +93,10 @@ impl<
7693

7794
fn withdraw_asset(asset: &MultiAsset, location: &MultiLocation) -> result::Result<MultiAsset, XcmError> {
7895
UnknownAsset::withdraw(asset, location).or_else(|_| {
79-
let who = AccountIdConverter::from_location(location)
96+
let who = AccountIdConvert::from_location(location)
8097
.ok_or_else(|| XcmError::from(Error::AccountIdConversionFailed))?;
81-
let currency_id = asset
82-
.clone()
83-
.try_into()
84-
.map_err(|_| XcmError::from(Error::CurrencyIdConversionFailed))?;
98+
let currency_id = CurrencyIdConvert::convert(asset.clone())
99+
.ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?;
85100
let amount: MultiCurrency::Balance = Matcher::matches_fungible(&asset)
86101
.ok_or_else(|| XcmError::from(Error::FailedToMatchFungible))?
87102
.saturated_into();

xcm-support/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#![allow(clippy::unused_unit)]
1111

1212
use frame_support::dispatch::{DispatchError, DispatchResult};
13-
use sp_runtime::traits::CheckedConversion;
13+
use sp_runtime::traits::{CheckedConversion, Convert};
1414
use sp_std::{convert::TryFrom, marker::PhantomData, prelude::*};
1515

1616
use xcm::v0::{MultiAsset, MultiLocation, Xcm};
@@ -31,15 +31,15 @@ pub trait XcmHandler<AccountId> {
3131

3232
/// A `MatchesFungible` implementation. It matches concrete fungible assets
3333
/// whose `id` could be converted into `CurrencyId`.
34-
pub struct IsNativeConcrete<CurrencyId>(PhantomData<CurrencyId>);
35-
impl<CurrencyId, Amount> MatchesFungible<Amount> for IsNativeConcrete<CurrencyId>
34+
pub struct IsNativeConcrete<CurrencyId, CurrencyIdConvert>(PhantomData<(CurrencyId, CurrencyIdConvert)>);
35+
impl<CurrencyId, CurrencyIdConvert, Amount> MatchesFungible<Amount> for IsNativeConcrete<CurrencyId, CurrencyIdConvert>
3636
where
37-
CurrencyId: TryFrom<MultiLocation>,
37+
CurrencyIdConvert: Convert<MultiLocation, Option<CurrencyId>>,
3838
Amount: TryFrom<u128>,
3939
{
4040
fn matches_fungible(a: &MultiAsset) -> Option<Amount> {
4141
if let MultiAsset::ConcreteFungible { id, amount } = a {
42-
if CurrencyId::try_from(id.clone()).is_ok() {
42+
if CurrencyIdConvert::convert(id.clone()).is_some() {
4343
return CheckedConversion::checked_from(*amount);
4444
}
4545
}

xcm-support/src/tests.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use super::*;
66

7-
use xcm::v0::{Junction::*, MultiAsset::*, MultiLocation::*};
7+
use xcm::v0::{Junction::*, MultiAsset::ConcreteFungible, MultiLocation::*};
88

99
#[derive(Debug, PartialEq, Eq)]
1010
pub enum TestCurrencyId {
@@ -13,22 +13,22 @@ pub enum TestCurrencyId {
1313
RelayChainToken,
1414
}
1515

16-
impl TryFrom<MultiLocation> for TestCurrencyId {
17-
type Error = ();
18-
fn try_from(l: MultiLocation) -> Result<TestCurrencyId, ()> {
16+
pub struct CurrencyIdConvert;
17+
impl Convert<MultiLocation, Option<TestCurrencyId>> for CurrencyIdConvert {
18+
fn convert(l: MultiLocation) -> Option<TestCurrencyId> {
1919
use TestCurrencyId::*;
2020
let token_a: Vec<u8> = "TokenA".into();
2121
let token_b: Vec<u8> = "TokenB".into();
2222
match l {
23-
X1(Parent) => Ok(RelayChainToken),
24-
X3(Parent, Parachain { id: 1 }, GeneralKey(k)) if k == token_a => Ok(TokenA),
25-
X3(Parent, Parachain { id: 2 }, GeneralKey(k)) if k == token_b => Ok(TokenB),
26-
_ => Err(()),
23+
X1(Parent) => Some(RelayChainToken),
24+
X3(Parent, Parachain { id: 1 }, GeneralKey(k)) if k == token_a => Some(TokenA),
25+
X3(Parent, Parachain { id: 2 }, GeneralKey(k)) if k == token_b => Some(TokenB),
26+
_ => None,
2727
}
2828
}
2929
}
3030

31-
type MatchesCurrencyId = IsNativeConcrete<TestCurrencyId>;
31+
type MatchesCurrencyId = IsNativeConcrete<TestCurrencyId, CurrencyIdConvert>;
3232

3333
#[test]
3434
fn is_native_concrete_matches_native_currencies() {

xtokens/src/lib.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ pub mod module {
6363
+ Into<u128>;
6464

6565
/// Currency Id.
66-
type CurrencyId: Parameter + Member + Clone + Into<MultiLocation>;
66+
type CurrencyId: Parameter + Member + Clone;
67+
68+
/// Convert `T::CurrencyIn` to `MultiLocation`.
69+
type CurrencyIdConvert: Convert<Self::CurrencyId, Option<MultiLocation>>;
6770

6871
/// Convert `Self::Account` to `AccountId32`
6972
type AccountId32Convert: Convert<Self::AccountId, [u8; 32]>;
@@ -94,6 +97,8 @@ pub mod module {
9497
NotCrossChainTransfer,
9598
/// Invalid transfer destination.
9699
InvalidDest,
100+
/// Currency is not cross-chain transferable.
101+
NotCrossChainTransferableCurrency,
97102
}
98103

99104
#[pallet::hooks]
@@ -119,8 +124,10 @@ pub mod module {
119124
return Ok(().into());
120125
}
121126

127+
let id: MultiLocation = T::CurrencyIdConvert::convert(currency_id.clone())
128+
.ok_or(Error::<T>::NotCrossChainTransferableCurrency)?;
122129
let asset = MultiAsset::ConcreteFungible {
123-
id: currency_id.clone().into(),
130+
id,
124131
amount: amount.into(),
125132
};
126133
Self::do_transfer_multiasset(who.clone(), asset, dest.clone())?;

xtokens/src/mock.rs

+46-37
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use polkadot_parachain::primitives::Sibling;
1010
use serde::{Deserialize, Serialize};
1111
use sp_io::TestExternalities;
1212
use sp_runtime::AccountId32;
13-
use sp_std::convert::TryFrom;
1413
use xcm::v0::{Junction, MultiLocation::*, NetworkId};
1514
use xcm_builder::{
1615
AccountId32Aliases, LocationInverter, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,
@@ -33,48 +32,52 @@ pub enum CurrencyId {
3332
B,
3433
}
3534

36-
impl From<CurrencyId> for MultiLocation {
37-
fn from(id: CurrencyId) -> Self {
35+
pub struct CurrencyIdConvert;
36+
impl Convert<CurrencyId, Option<MultiLocation>> for CurrencyIdConvert {
37+
fn convert(id: CurrencyId) -> Option<MultiLocation> {
3838
match id {
39-
CurrencyId::R => Junction::Parent.into(),
40-
CurrencyId::A => (
41-
Junction::Parent,
42-
Junction::Parachain { id: 1 },
43-
Junction::GeneralKey("A".into()),
44-
)
45-
.into(),
46-
CurrencyId::B => (
47-
Junction::Parent,
48-
Junction::Parachain { id: 2 },
49-
Junction::GeneralKey("B".into()),
50-
)
51-
.into(),
39+
CurrencyId::R => Some(Junction::Parent.into()),
40+
CurrencyId::A => Some(
41+
(
42+
Junction::Parent,
43+
Junction::Parachain { id: 1 },
44+
Junction::GeneralKey("A".into()),
45+
)
46+
.into(),
47+
),
48+
CurrencyId::B => Some(
49+
(
50+
Junction::Parent,
51+
Junction::Parachain { id: 2 },
52+
Junction::GeneralKey("B".into()),
53+
)
54+
.into(),
55+
),
5256
}
5357
}
5458
}
55-
56-
impl TryFrom<MultiLocation> for CurrencyId {
57-
type Error = ();
58-
fn try_from(l: MultiLocation) -> Result<Self, Self::Error> {
59+
impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
60+
fn convert(l: MultiLocation) -> Option<CurrencyId> {
5961
let a: Vec<u8> = "A".into();
6062
let b: Vec<u8> = "B".into();
6163
match l {
62-
X1(Parent) => Ok(CurrencyId::R),
63-
X3(Junction::Parent, Junction::Parachain { id: 1 }, Junction::GeneralKey(k)) if k == a => Ok(CurrencyId::A),
64-
X3(Junction::Parent, Junction::Parachain { id: 2 }, Junction::GeneralKey(k)) if k == b => Ok(CurrencyId::B),
65-
66-
_ => Err(()),
64+
X1(Parent) => Some(CurrencyId::R),
65+
X3(Junction::Parent, Junction::Parachain { id: 1 }, Junction::GeneralKey(k)) if k == a => {
66+
Some(CurrencyId::A)
67+
}
68+
X3(Junction::Parent, Junction::Parachain { id: 2 }, Junction::GeneralKey(k)) if k == b => {
69+
Some(CurrencyId::B)
70+
}
71+
_ => None,
6772
}
6873
}
6974
}
70-
71-
impl TryFrom<MultiAsset> for CurrencyId {
72-
type Error = ();
73-
fn try_from(a: MultiAsset) -> Result<Self, Self::Error> {
75+
impl Convert<MultiAsset, Option<CurrencyId>> for CurrencyIdConvert {
76+
fn convert(a: MultiAsset) -> Option<CurrencyId> {
7477
if let MultiAsset::ConcreteFungible { id, amount: _ } = a {
75-
Self::try_from(id)
78+
Self::convert(id)
7679
} else {
77-
Err(())
80+
None
7881
}
7982
}
8083
}
@@ -110,10 +113,11 @@ decl_test_parachain! {
110113
pub type LocalAssetTransactor = MultiCurrencyAdapter<
111114
Tokens,
112115
(),
113-
IsNativeConcrete<CurrencyId>,
114-
LocationConverter,
116+
IsNativeConcrete<CurrencyId, CurrencyIdConvert>,
115117
AccountId,
118+
LocationConverter,
116119
CurrencyId,
120+
CurrencyIdConvert,
117121
>;
118122

119123
pub type LocalOriginConverter = (
@@ -173,6 +177,7 @@ decl_test_parachain! {
173177
type Event = Event;
174178
type Balance = Balance;
175179
type CurrencyId = CurrencyId;
180+
type CurrencyIdConvert = CurrencyIdConvert;
176181
type AccountId32Convert = AccountId32Convert;
177182
type SelfLocation = SelfLocation;
178183
type XcmHandler = HandleXcm;
@@ -213,10 +218,11 @@ decl_test_parachain! {
213218
pub type LocalAssetTransactor = MultiCurrencyAdapter<
214219
Tokens,
215220
(),
216-
IsNativeConcrete<CurrencyId>,
217-
LocationConverter,
221+
IsNativeConcrete<CurrencyId, CurrencyIdConvert>,
218222
AccountId,
223+
LocationConverter,
219224
CurrencyId,
225+
CurrencyIdConvert,
220226
>;
221227

222228
pub type LocalOriginConverter = (
@@ -276,6 +282,7 @@ decl_test_parachain! {
276282
type Event = Event;
277283
type Balance = Balance;
278284
type CurrencyId = CurrencyId;
285+
type CurrencyIdConvert = CurrencyIdConvert;
279286
type AccountId32Convert = AccountId32Convert;
280287
type SelfLocation = SelfLocation;
281288
type XcmHandler = HandleXcm;
@@ -316,10 +323,11 @@ decl_test_parachain! {
316323
pub type LocalAssetTransactor = MultiCurrencyAdapter<
317324
Tokens,
318325
(),
319-
IsNativeConcrete<CurrencyId>,
320-
LocationConverter,
326+
IsNativeConcrete<CurrencyId, CurrencyIdConvert>,
321327
AccountId,
328+
LocationConverter,
322329
CurrencyId,
330+
CurrencyIdConvert,
323331
>;
324332

325333
pub type LocalOriginConverter = (
@@ -379,6 +387,7 @@ decl_test_parachain! {
379387
type Event = Event;
380388
type Balance = Balance;
381389
type CurrencyId = CurrencyId;
390+
type CurrencyIdConvert = CurrencyIdConvert;
382391
type AccountId32Convert = AccountId32Convert;
383392
type SelfLocation = SelfLocation;
384393
type XcmHandler = HandleXcm;

0 commit comments

Comments
 (0)