currency_adapter.rs 3.2 KB
Newer Older
Shawn Tabrizi's avatar
Shawn Tabrizi committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

use sp_std::{result, convert::TryInto, marker::PhantomData};
18
use xcm::v0::{Error as XcmError, Result, MultiAsset, MultiLocation};
19
use sp_runtime::traits::SaturatedConversion;
20
use frame_support::traits::{ExistenceRequirement::AllowDeath, WithdrawReasons};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
21
22
use xcm_executor::traits::{MatchesFungible, LocationConversion, TransactAsset};

23
24
25
26
/// Asset transaction errors.
enum Error {
	/// Asset not found.
	AssetNotFound,
27
	/// `MultiLocation` to `AccountId` conversion failed.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
	AccountIdConversionFailed,
	/// `u128` amount to currency `Balance` conversion failed.
	AmountToBalanceConversionFailed,
}

impl From<Error> for XcmError {
	fn from(e: Error) -> Self {
		match e {
			Error::AssetNotFound => XcmError::FailedToTransactAsset("AssetNotFound"),
			Error::AccountIdConversionFailed =>
				XcmError::FailedToTransactAsset("AccountIdConversionFailed"),
			Error::AmountToBalanceConversionFailed =>
				XcmError::FailedToTransactAsset("AmountToBalanceConversionFailed"),
		}
	}
}

Shawn Tabrizi's avatar
Shawn Tabrizi committed
45
pub struct CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId>(
46
	PhantomData<(Currency, Matcher, AccountIdConverter, AccountId)>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
47
48
49
50
51
52
53
54
55
56
57
);

impl<
	Matcher: MatchesFungible<Currency::Balance>,
	AccountIdConverter: LocationConversion<AccountId>,
	Currency: frame_support::traits::Currency<AccountId>,
	AccountId,	// can't get away without it since Currency is generic over it.
> TransactAsset for CurrencyAdapter<Currency, Matcher, AccountIdConverter, AccountId> {

	fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result {
		// Check we handle this asset.
58
		let amount: u128 = Matcher::matches_fungible(&what)
59
			.ok_or(Error::AssetNotFound)?
60
61
			.saturated_into();
		let who = AccountIdConverter::from_location(who)
62
			.ok_or(Error::AccountIdConversionFailed)?;
63
64
		let balance_amount = amount
			.try_into()
65
			.map_err(|_| Error::AmountToBalanceConversionFailed)?;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
66
67
68
69
		let _imbalance = Currency::deposit_creating(&who, balance_amount);
		Ok(())
	}

70
71
72
73
	fn withdraw_asset(
		what: &MultiAsset,
		who: &MultiLocation
	) -> result::Result<MultiAsset, XcmError> {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
74
		// Check we handle this asset.
75
76
		let amount: u128 = Matcher::matches_fungible(what)
			.ok_or(Error::AssetNotFound)?
77
78
			.saturated_into();
		let who = AccountIdConverter::from_location(who)
79
			.ok_or(Error::AccountIdConversionFailed)?;
80
81
		let balance_amount = amount
			.try_into()
82
			.map_err(|_| Error::AmountToBalanceConversionFailed)?;
83
84
		Currency::withdraw(&who, balance_amount, WithdrawReasons::TRANSFER, AllowDeath)
			.map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
85
86
87
		Ok(what.clone())
	}
}