Skip to content

Commit 61e7e27

Browse files
authored
XCM: add deposit error handler for multi-currency adapter. (#675)
* XCM: add deposit error handler for multi-currency adapter. * Deposit to alternative account. * Make clippy happy.
1 parent 8d07637 commit 61e7e27

File tree

3 files changed

+81
-7
lines changed

3 files changed

+81
-7
lines changed

xcm-support/src/currency_adapter.rs

+79-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use codec::FullCodec;
2-
use sp_runtime::traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion};
2+
use frame_support::traits::Get;
3+
use sp_runtime::{
4+
traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion},
5+
DispatchError,
6+
};
37
use sp_std::{
48
cmp::{Eq, PartialEq},
59
fmt::Debug,
@@ -36,11 +40,68 @@ impl From<Error> for XcmError {
3640
}
3741
}
3842

43+
/// Deposit errors handler for `TransactAsset` implementations. Default impl for
44+
/// `()` returns an `XcmError::FailedToTransactAsset` error.
45+
pub trait OnDepositFail<CurrencyId, AccountId, Balance> {
46+
/// Called on deposit errors with a specific `currency_id`.
47+
fn on_deposit_currency_fail(
48+
err: DispatchError,
49+
currency_id: CurrencyId,
50+
who: &AccountId,
51+
amount: Balance,
52+
) -> Result;
53+
54+
/// Called on unknown asset deposit errors.
55+
fn on_deposit_unknown_asset_fail(err: DispatchError, _asset: &MultiAsset, _location: &MultiLocation) -> Result {
56+
Err(XcmError::FailedToTransactAsset(err.into()))
57+
}
58+
}
59+
60+
impl<CurrencyId, AccountId, Balance> OnDepositFail<CurrencyId, AccountId, Balance> for () {
61+
fn on_deposit_currency_fail(
62+
err: DispatchError,
63+
_currency_id: CurrencyId,
64+
_who: &AccountId,
65+
_amount: Balance,
66+
) -> Result {
67+
Err(XcmError::FailedToTransactAsset(err.into()))
68+
}
69+
}
70+
71+
/// `OnDepositFail` impl, will deposit known currencies to an alternative
72+
/// account.
73+
pub struct DepositToAlternative<Alternative, MultiCurrency, CurrencyId, AccountId, Balance>(
74+
PhantomData<(Alternative, MultiCurrency, CurrencyId, AccountId, Balance)>,
75+
);
76+
impl<
77+
Alternative: Get<AccountId>,
78+
MultiCurrency: orml_traits::MultiCurrency<AccountId, CurrencyId = CurrencyId, Balance = Balance>,
79+
AccountId: sp_std::fmt::Debug + Clone,
80+
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug,
81+
Balance,
82+
> OnDepositFail<CurrencyId, AccountId, Balance>
83+
for DepositToAlternative<Alternative, MultiCurrency, CurrencyId, AccountId, Balance>
84+
{
85+
fn on_deposit_currency_fail(
86+
_err: DispatchError,
87+
currency_id: CurrencyId,
88+
_who: &AccountId,
89+
amount: Balance,
90+
) -> Result {
91+
MultiCurrency::deposit(currency_id, &Alternative::get(), amount)
92+
.map_err(|e| XcmError::FailedToTransactAsset(e.into()))
93+
}
94+
}
95+
3996
/// The `TransactAsset` implementation, to handle `MultiAsset` deposit/withdraw.
4097
/// Note that teleport related functions are unimplemented.
4198
///
99+
/// Methods of `DepositFailureHandler` would be called on multi-currency deposit
100+
/// errors.
101+
///
42102
/// If the asset is known, deposit/withdraw will be handled by `MultiCurrency`,
43103
/// else by `UnknownAsset` if unknown.
104+
#[allow(clippy::type_complexity)]
44105
pub struct MultiCurrencyAdapter<
45106
MultiCurrency,
46107
UnknownAsset,
@@ -49,6 +110,7 @@ pub struct MultiCurrencyAdapter<
49110
AccountIdConvert,
50111
CurrencyId,
51112
CurrencyIdConvert,
113+
DepositFailureHandler,
52114
>(
53115
PhantomData<(
54116
MultiCurrency,
@@ -58,6 +120,7 @@ pub struct MultiCurrencyAdapter<
58120
AccountIdConvert,
59121
CurrencyId,
60122
CurrencyIdConvert,
123+
DepositFailureHandler,
61124
)>,
62125
);
63126

@@ -69,8 +132,18 @@ impl<
69132
AccountIdConvert: MoreConvert<MultiLocation, AccountId>,
70133
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug,
71134
CurrencyIdConvert: Convert<MultiAsset, Option<CurrencyId>>,
135+
DepositFailureHandler: OnDepositFail<CurrencyId, AccountId, MultiCurrency::Balance>,
72136
> TransactAsset
73-
for MultiCurrencyAdapter<MultiCurrency, UnknownAsset, Match, AccountId, AccountIdConvert, CurrencyId, CurrencyIdConvert>
137+
for MultiCurrencyAdapter<
138+
MultiCurrency,
139+
UnknownAsset,
140+
Match,
141+
AccountId,
142+
AccountIdConvert,
143+
CurrencyId,
144+
CurrencyIdConvert,
145+
DepositFailureHandler,
146+
>
74147
{
75148
fn deposit_asset(asset: &MultiAsset, location: &MultiLocation) -> Result {
76149
match (
@@ -79,11 +152,11 @@ impl<
79152
Match::matches_fungible(asset),
80153
) {
81154
// known asset
82-
(Ok(who), Some(currency_id), Some(amount)) => {
83-
MultiCurrency::deposit(currency_id, &who, amount).map_err(|e| XcmError::FailedToTransactAsset(e.into()))
84-
}
155+
(Ok(who), Some(currency_id), Some(amount)) => MultiCurrency::deposit(currency_id, &who, amount)
156+
.or_else(|err| DepositFailureHandler::on_deposit_currency_fail(err, currency_id, &who, amount)),
85157
// unknown asset
86-
_ => UnknownAsset::deposit(asset, location).map_err(|e| XcmError::FailedToTransactAsset(e.into())),
158+
_ => UnknownAsset::deposit(asset, location)
159+
.or_else(|err| DepositFailureHandler::on_deposit_unknown_asset_fail(err, asset, location)),
87160
}
88161
}
89162

xcm-support/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use xcm_executor::traits::{FilterAssetLocation, MatchesFungible};
1818

1919
use orml_traits::location::Reserve;
2020

21-
pub use currency_adapter::MultiCurrencyAdapter;
21+
pub use currency_adapter::{DepositToAlternative, MultiCurrencyAdapter, OnDepositFail};
2222

2323
mod currency_adapter;
2424

xtokens/src/mock/para.rs

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub type LocalAssetTransactor = MultiCurrencyAdapter<
137137
LocationToAccountId,
138138
CurrencyId,
139139
CurrencyIdConvert,
140+
(),
140141
>;
141142

142143
pub type XcmRouter = ParachainXcmRouter<ParachainInfo>;

0 commit comments

Comments
 (0)