staging_xcm_builder/
pay.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! `PayOverXcm` struct for paying through XCM and getting the status back.
18
19use crate::{transfer::TransferOverXcmHelperT, TransferOverXcmHelper};
20use core::marker::PhantomData;
21use frame_support::traits::{
22	tokens::{Pay, PaymentStatus},
23	Get,
24};
25use sp_runtime::traits::TryConvert;
26use xcm::prelude::*;
27use xcm_executor::traits::WaiveDeliveryFees;
28
29/// Implementation of the `frame_support::traits::tokens::Pay` trait, to allow
30/// for XCM-based payments of a given `Balance` of some asset ID existing on some chain under
31/// ownership of some `Interior` location of the local chain to a particular `Beneficiary`. The
32/// `AssetKind` value is not itself bounded (to avoid the issue of needing to wrap some preexisting
33/// datatype), however a converter type `AssetKindToLocatableAsset` must be provided in order to
34/// translate it into a `LocatableAsset`, which comprises both an XCM `Location` describing
35/// the XCM endpoint on which the asset to be paid resides and an XCM `AssetId` to identify the
36/// specific asset at that endpoint.
37///
38/// This relies on the XCM `TransferAsset` instruction. A trait `BeneficiaryRefToLocation` must be
39/// provided in order to convert the `Beneficiary` reference into a location usable by
40/// `TransferAsset`.
41///
42/// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in
43/// `check_payment` to check the status of the XCM transaction.
44///
45/// See also `PayAccountId32OverXcm` which is similar to this except that `BeneficiaryRefToLocation`
46/// need not be supplied and `Beneficiary` must implement `Into<[u8; 32]>`.
47///
48/// The implementation of this type assumes:
49///
50/// - The sending account on the remote chain is fixed (derived from the `Interior` location),
51///   rather than being fully configurable.
52/// - The remote chain waives the XCM execution fee (`PaysRemoteFee::No`).
53///
54/// See also [super::transfer::TransferOverXcm] for a more generic implementation with a flexible
55/// sender account on the remote chain, and not making the assumption that the remote XCM execution
56/// fee is waived.
57pub type PayOverXcm<
58	Interior,
59	Router,
60	Querier,
61	Timeout,
62	Beneficiary,
63	AssetKind,
64	AssetKindToLocatableAsset,
65	BeneficiaryRefToLocation,
66> = PayOverXcmWithHelper<
67	Interior,
68	TransferOverXcmHelper<
69		Router,
70		Querier,
71		WaiveDeliveryFees,
72		Timeout,
73		Beneficiary,
74		AssetKind,
75		AssetKindToLocatableAsset,
76		BeneficiaryRefToLocation,
77	>,
78>;
79
80/// Simpler than [`PayOverXcm`] the low-level XCM configuration is extracted to the
81/// `TransferOverXcmHelper` type.
82pub struct PayOverXcmWithHelper<Interior, TransferOverXcmHelper>(
83	PhantomData<(Interior, TransferOverXcmHelper)>,
84);
85impl<Interior, TransferOverXcmHelper> Pay for PayOverXcmWithHelper<Interior, TransferOverXcmHelper>
86where
87	Interior: Get<InteriorLocation>,
88	TransferOverXcmHelper: TransferOverXcmHelperT<Balance = u128, QueryId = QueryId>,
89{
90	type Balance = u128;
91	type Beneficiary = TransferOverXcmHelper::Beneficiary;
92	type AssetKind = TransferOverXcmHelper::AssetKind;
93	type Id = TransferOverXcmHelper::QueryId;
94	type Error = xcm::latest::Error;
95
96	fn pay(
97		who: &Self::Beneficiary,
98		asset_kind: Self::AssetKind,
99		amount: Self::Balance,
100	) -> Result<Self::Id, Self::Error> {
101		TransferOverXcmHelper::send_remote_transfer_xcm(
102			Interior::get().into(),
103			who,
104			asset_kind,
105			amount,
106			None,
107		)
108	}
109
110	fn check_payment(id: Self::Id) -> PaymentStatus {
111		TransferOverXcmHelper::check_transfer(id)
112	}
113
114	#[cfg(feature = "runtime-benchmarks")]
115	fn ensure_successful(
116		beneficiary: &Self::Beneficiary,
117		asset_kind: Self::AssetKind,
118		balance: Self::Balance,
119	) {
120		TransferOverXcmHelper::ensure_successful(beneficiary, asset_kind, balance);
121	}
122
123	#[cfg(feature = "runtime-benchmarks")]
124	fn ensure_concluded(id: Self::Id) {
125		TransferOverXcmHelper::ensure_concluded(id);
126	}
127}
128
129/// Specialization of the [`PayOverXcm`] trait to allow `[u8; 32]`-based `AccountId` values to be
130/// paid on a remote chain.
131///
132/// Implementation of the [`frame_support::traits::tokens::Pay`] trait, to allow
133/// for XCM payments of a given `Balance` of `AssetKind` existing on a `DestinationChain` under
134/// ownership of some `Interior` location of the local chain to a particular `Beneficiary`.
135///
136/// This relies on the XCM `TransferAsset` instruction. `Beneficiary` must implement
137/// `Into<[u8; 32]>` (as 32-byte `AccountId`s generally do), and the actual XCM beneficiary will be
138/// the location consisting of a single `AccountId32` junction with an appropriate account and no
139/// specific network.
140///
141/// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in
142/// `check_payment` to check the status of the XCM transaction.
143pub type PayAccountId32OnChainOverXcm<
144	DestinationChain,
145	Interior,
146	Router,
147	Querier,
148	Timeout,
149	Beneficiary,
150	AssetKind,
151> = PayOverXcm<
152	Interior,
153	Router,
154	Querier,
155	Timeout,
156	Beneficiary,
157	AssetKind,
158	crate::AliasesIntoAccountId32<(), Beneficiary>,
159	FixedLocation<DestinationChain>,
160>;
161
162/// Simple struct which contains both an XCM `location` and `asset_id` to identify an asset which
163/// exists on some chain.
164pub struct LocatableAssetId {
165	/// The asset's ID.
166	pub asset_id: AssetId,
167	/// The (relative) location in which the asset ID is meaningful.
168	pub location: Location,
169}
170
171/// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`]
172/// value using a fixed `Location` for the `location` field.
173pub struct FixedLocation<FixedLocationValue>(core::marker::PhantomData<FixedLocationValue>);
174impl<FixedLocationValue: Get<Location>, AssetKind: Into<AssetId>>
175	TryConvert<AssetKind, LocatableAssetId> for FixedLocation<FixedLocationValue>
176{
177	fn try_convert(value: AssetKind) -> Result<LocatableAssetId, AssetKind> {
178		Ok(LocatableAssetId { asset_id: value.into(), location: FixedLocationValue::get() })
179	}
180}