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::*;
27
28/// Implementation of the `frame_support::traits::tokens::Pay` trait, to allow
29/// for XCM-based payments of a given `Balance` of some asset ID existing on some chain under
30/// ownership of some `Interior` location of the local chain to a particular `Beneficiary`. The
31/// `AssetKind` value is not itself bounded (to avoid the issue of needing to wrap some preexisting
32/// datatype), however a converter type `AssetKindToLocatableAsset` must be provided in order to
33/// translate it into a `LocatableAsset`, which comprises both an XCM `Location` describing
34/// the XCM endpoint on which the asset to be paid resides and an XCM `AssetId` to identify the
35/// specific asset at that endpoint.
36///
37/// This relies on the XCM `TransferAsset` instruction. A trait `BeneficiaryRefToLocation` must be
38/// provided in order to convert the `Beneficiary` reference into a location usable by
39/// `TransferAsset`.
40///
41/// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in
42/// `check_payment` to check the status of the XCM transaction.
43///
44/// See also `PayAccountId32OverXcm` which is similar to this except that `BeneficiaryRefToLocation`
45/// need not be supplied and `Beneficiary` must implement `Into<[u8; 32]>`.
46///
47/// The implementation of this type assumes:
48///
49/// - The sending account on the remote chain is fixed (derived from the `Interior` location),
50/// rather than being fully configurable.
51/// - The remote chain waives the XCM execution fee (`PaysRemoteFee::No`).
52///
53/// See also [super::transfer::TransferOverXcm] for a more generic implementation with a flexible
54/// sender account on the remote chain, and not making the assumption that the remote XCM execution
55/// fee is waived.
56pub type PayOverXcm<
57 Interior,
58 XcmConfig,
59 Querier,
60 Timeout,
61 Beneficiary,
62 AssetKind,
63 AssetKindToLocatableAsset,
64 BeneficiaryRefToLocation,
65> = PayOverXcmWithHelper<
66 Interior,
67 TransferOverXcmHelper<
68 XcmConfig,
69 Querier,
70 Timeout,
71 Beneficiary,
72 AssetKind,
73 AssetKindToLocatableAsset,
74 BeneficiaryRefToLocation,
75 >,
76>;
77
78/// Simpler than [`PayOverXcm`] the low-level XCM configuration is extracted to the
79/// `TransferOverXcmHelper` type.
80pub struct PayOverXcmWithHelper<Interior, TransferOverXcmHelper>(
81 PhantomData<(Interior, TransferOverXcmHelper)>,
82);
83impl<Interior, TransferOverXcmHelper> Pay for PayOverXcmWithHelper<Interior, TransferOverXcmHelper>
84where
85 Interior: Get<InteriorLocation>,
86 TransferOverXcmHelper: TransferOverXcmHelperT<Balance = u128, QueryId = QueryId>,
87{
88 type Balance = u128;
89 type Beneficiary = TransferOverXcmHelper::Beneficiary;
90 type AssetKind = TransferOverXcmHelper::AssetKind;
91 type Id = TransferOverXcmHelper::QueryId;
92 type Error = xcm::latest::Error;
93
94 fn pay(
95 who: &Self::Beneficiary,
96 asset_kind: Self::AssetKind,
97 amount: Self::Balance,
98 ) -> Result<Self::Id, Self::Error> {
99 TransferOverXcmHelper::send_remote_transfer_xcm(
100 Interior::get().into(),
101 who,
102 asset_kind,
103 amount,
104 None,
105 )
106 }
107
108 fn check_payment(id: Self::Id) -> PaymentStatus {
109 TransferOverXcmHelper::check_transfer(id)
110 }
111
112 #[cfg(feature = "runtime-benchmarks")]
113 fn ensure_successful(
114 beneficiary: &Self::Beneficiary,
115 asset_kind: Self::AssetKind,
116 balance: Self::Balance,
117 ) {
118 TransferOverXcmHelper::ensure_successful(beneficiary, asset_kind, balance);
119 }
120
121 #[cfg(feature = "runtime-benchmarks")]
122 fn ensure_concluded(id: Self::Id) {
123 TransferOverXcmHelper::ensure_concluded(id);
124 }
125}
126
127/// Specialization of the [`PayOverXcm`] trait to allow `[u8; 32]`-based `AccountId` values to be
128/// paid on a remote chain.
129///
130/// Implementation of the [`frame_support::traits::tokens::Pay`] trait, to allow
131/// for XCM payments of a given `Balance` of `AssetKind` existing on a `DestinationChain` under
132/// ownership of some `Interior` location of the local chain to a particular `Beneficiary`.
133///
134/// This relies on the XCM `TransferAsset` instruction. `Beneficiary` must implement
135/// `Into<[u8; 32]>` (as 32-byte `AccountId`s generally do), and the actual XCM beneficiary will be
136/// the location consisting of a single `AccountId32` junction with an appropriate account and no
137/// specific network.
138///
139/// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in
140/// `check_payment` to check the status of the XCM transaction.
141pub type PayAccountId32OnChainOverXcm<
142 DestinationChain,
143 Interior,
144 XcmConfig,
145 Querier,
146 Timeout,
147 Beneficiary,
148 AssetKind,
149> = PayOverXcm<
150 Interior,
151 XcmConfig,
152 Querier,
153 Timeout,
154 Beneficiary,
155 AssetKind,
156 crate::AliasesIntoAccountId32<(), Beneficiary>,
157 FixedLocation<DestinationChain>,
158>;
159
160/// Simple struct which contains both an XCM `location` and `asset_id` to identify an asset which
161/// exists on some chain.
162pub struct LocatableAssetId {
163 /// The asset's ID.
164 pub asset_id: AssetId,
165 /// The (relative) location in which the asset ID is meaningful.
166 pub location: Location,
167}
168
169/// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`]
170/// value using a fixed `Location` for the `location` field.
171pub struct FixedLocation<FixedLocationValue>(core::marker::PhantomData<FixedLocationValue>);
172impl<FixedLocationValue: Get<Location>, AssetKind: Into<AssetId>>
173 TryConvert<AssetKind, LocatableAssetId> for FixedLocation<FixedLocationValue>
174{
175 fn try_convert(value: AssetKind) -> Result<LocatableAssetId, AssetKind> {
176 Ok(LocatableAssetId { asset_id: value.into(), location: FixedLocationValue::get() })
177 }
178}