1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use codec::FullCodec;
use sp_runtime::traits::{Convert, MaybeSerializeDeserialize, SaturatedConversion};
use sp_std::{
cmp::{Eq, PartialEq},
fmt::Debug,
marker::PhantomData,
prelude::*,
result,
};
use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result};
use xcm_executor::{
traits::{Convert as MoreConvert, MatchesFungible, TransactAsset},
Assets,
};
use crate::UnknownAsset as UnknownAssetT;
enum Error {
FailedToMatchFungible,
AccountIdConversionFailed,
CurrencyIdConversionFailed,
}
impl From<Error> for XcmError {
fn from(e: Error) -> Self {
match e {
Error::FailedToMatchFungible => XcmError::FailedToTransactAsset("FailedToMatchFungible"),
Error::AccountIdConversionFailed => XcmError::FailedToTransactAsset("AccountIdConversionFailed"),
Error::CurrencyIdConversionFailed => XcmError::FailedToTransactAsset("CurrencyIdConversionFailed"),
}
}
}
pub struct MultiCurrencyAdapter<
MultiCurrency,
UnknownAsset,
Match,
AccountId,
AccountIdConvert,
CurrencyId,
CurrencyIdConvert,
>(
PhantomData<(
MultiCurrency,
UnknownAsset,
Match,
AccountId,
AccountIdConvert,
CurrencyId,
CurrencyIdConvert,
)>,
);
impl<
MultiCurrency: orml_traits::MultiCurrency<AccountId, CurrencyId = CurrencyId>,
UnknownAsset: UnknownAssetT,
Match: MatchesFungible<MultiCurrency::Balance>,
AccountId: sp_std::fmt::Debug + Clone,
AccountIdConvert: MoreConvert<MultiLocation, AccountId>,
CurrencyId: FullCodec + Eq + PartialEq + Copy + MaybeSerializeDeserialize + Debug,
CurrencyIdConvert: Convert<MultiAsset, Option<CurrencyId>>,
> TransactAsset
for MultiCurrencyAdapter<MultiCurrency, UnknownAsset, Match, AccountId, AccountIdConvert, CurrencyId, CurrencyIdConvert>
{
fn deposit_asset(asset: &MultiAsset, location: &MultiLocation) -> Result {
match (
AccountIdConvert::convert_ref(location),
CurrencyIdConvert::convert(asset.clone()),
Match::matches_fungible(asset),
) {
(Ok(who), Some(currency_id), Some(amount)) => {
MultiCurrency::deposit(currency_id, &who, amount).map_err(|e| XcmError::FailedToTransactAsset(e.into()))
}
_ => UnknownAsset::deposit(asset, location).map_err(|e| XcmError::FailedToTransactAsset(e.into())),
}
}
fn withdraw_asset(asset: &MultiAsset, location: &MultiLocation) -> result::Result<Assets, XcmError> {
UnknownAsset::withdraw(asset, location).or_else(|_| {
let who = AccountIdConvert::convert_ref(location)
.map_err(|_| XcmError::from(Error::AccountIdConversionFailed))?;
let currency_id = CurrencyIdConvert::convert(asset.clone())
.ok_or_else(|| XcmError::from(Error::CurrencyIdConversionFailed))?;
let amount: MultiCurrency::Balance = Match::matches_fungible(asset)
.ok_or_else(|| XcmError::from(Error::FailedToMatchFungible))?
.saturated_into();
MultiCurrency::withdraw(currency_id, &who, amount).map_err(|e| XcmError::FailedToTransactAsset(e.into()))
})?;
Ok(asset.clone().into())
}
}