// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Pezkuwi. // Pezkuwi 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. // Pezkuwi 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 Pezkuwi. If not, see . //! `PayOverXcm` struct for paying through XCM and getting the status back. use crate::{transfer::TransferOverXcmHelperT, TransferOverXcmHelper}; use core::marker::PhantomData; use pezframe_support::traits::{ tokens::{Pay, PaymentStatus}, Get, }; use pezsp_runtime::traits::TryConvert; use xcm::prelude::*; use xcm_executor::traits::WaiveDeliveryFees; /// Implementation of the `pezframe_support::traits::tokens::Pay` trait, to allow /// for XCM-based payments of a given `Balance` of some asset ID existing on some chain under /// ownership of some `Interior` location of the local chain to a particular `Beneficiary`. The /// `AssetKind` value is not itself bounded (to avoid the issue of needing to wrap some preexisting /// datatype), however a converter type `AssetKindToLocatableAsset` must be provided in order to /// translate it into a `LocatableAsset`, which comprises both an XCM `Location` describing /// the XCM endpoint on which the asset to be paid resides and an XCM `AssetId` to identify the /// specific asset at that endpoint. /// /// This relies on the XCM `TransferAsset` instruction. A trait `BeneficiaryRefToLocation` must be /// provided in order to convert the `Beneficiary` reference into a location usable by /// `TransferAsset`. /// /// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in /// `check_payment` to check the status of the XCM transaction. /// /// See also `PayAccountId32OverXcm` which is similar to this except that `BeneficiaryRefToLocation` /// need not be supplied and `Beneficiary` must implement `Into<[u8; 32]>`. /// /// The implementation of this type assumes: /// /// - The sending account on the remote chain is fixed (derived from the `Interior` location), /// rather than being fully configurable. /// - The remote chain waives the XCM execution fee (`PaysRemoteFee::No`). /// /// See also [super::transfer::TransferOverXcm] for a more generic implementation with a flexible /// sender account on the remote chain, and not making the assumption that the remote XCM execution /// fee is waived. pub type PayOverXcm< Interior, Router, Querier, Timeout, Beneficiary, AssetKind, AssetKindToLocatableAsset, BeneficiaryRefToLocation, > = PayOverXcmWithHelper< Interior, TransferOverXcmHelper< Router, Querier, WaiveDeliveryFees, Timeout, Beneficiary, AssetKind, AssetKindToLocatableAsset, BeneficiaryRefToLocation, >, >; /// Simpler than [`PayOverXcm`] the low-level XCM configuration is extracted to the /// `TransferOverXcmHelper` type. pub struct PayOverXcmWithHelper( PhantomData<(Interior, TransferOverXcmHelper)>, ); impl Pay for PayOverXcmWithHelper where Interior: Get, TransferOverXcmHelper: TransferOverXcmHelperT, { type Balance = u128; type Beneficiary = TransferOverXcmHelper::Beneficiary; type AssetKind = TransferOverXcmHelper::AssetKind; type Id = TransferOverXcmHelper::QueryId; type Error = xcm::latest::Error; fn pay( who: &Self::Beneficiary, asset_kind: Self::AssetKind, amount: Self::Balance, ) -> Result { TransferOverXcmHelper::send_remote_transfer_xcm( Interior::get().into(), who, asset_kind, amount, None, ) } fn check_payment(id: Self::Id) -> PaymentStatus { TransferOverXcmHelper::check_transfer(id) } #[cfg(feature = "runtime-benchmarks")] fn ensure_successful( beneficiary: &Self::Beneficiary, asset_kind: Self::AssetKind, balance: Self::Balance, ) { TransferOverXcmHelper::ensure_successful(beneficiary, asset_kind, balance); } #[cfg(feature = "runtime-benchmarks")] fn ensure_concluded(id: Self::Id) { TransferOverXcmHelper::ensure_concluded(id); } } /// Specialization of the [`PayOverXcm`] trait to allow `[u8; 32]`-based `AccountId` values to be /// paid on a remote chain. /// /// Implementation of the [`pezframe_support::traits::tokens::Pay`] trait, to allow /// for XCM payments of a given `Balance` of `AssetKind` existing on a `DestinationChain` under /// ownership of some `Interior` location of the local chain to a particular `Beneficiary`. /// /// This relies on the XCM `TransferAsset` instruction. `Beneficiary` must implement /// `Into<[u8; 32]>` (as 32-byte `AccountId`s generally do), and the actual XCM beneficiary will be /// the location consisting of a single `AccountId32` junction with an appropriate account and no /// specific network. /// /// `PayOverXcm::pay` is asynchronous, and returns a `QueryId` which can then be used in /// `check_payment` to check the status of the XCM transaction. pub type PayAccountId32OnChainOverXcm< DestinationChain, Interior, Router, Querier, Timeout, Beneficiary, AssetKind, > = PayOverXcm< Interior, Router, Querier, Timeout, Beneficiary, AssetKind, crate::AliasesIntoAccountId32<(), Beneficiary>, FixedLocation, >; /// Simple struct which contains both an XCM `location` and `asset_id` to identify an asset which /// exists on some chain. pub struct LocatableAssetId { /// The asset's ID. pub asset_id: AssetId, /// The (relative) location in which the asset ID is meaningful. pub location: Location, } /// Adapter `struct` which implements a conversion from any `AssetKind` into a [`LocatableAssetId`] /// value using a fixed `Location` for the `location` field. pub struct FixedLocation(core::marker::PhantomData); impl, AssetKind: Into> TryConvert for FixedLocation { fn try_convert(value: AssetKind) -> Result { Ok(LocatableAssetId { asset_id: value.into(), location: FixedLocationValue::get() }) } }