frame_support/traits/tokens/
pay.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! The Pay trait and associated types.
19
20use codec::{FullCodec, MaxEncodedLen};
21use core::fmt::Debug;
22use scale_info::TypeInfo;
23use sp_core::TypedGet;
24use sp_runtime::DispatchError;
25
26use super::{fungible, fungibles, Balance, Preservation::Expendable};
27
28/// Can be implemented by `PayFromAccount` using a `fungible` impl, but can also be implemented with
29/// XCM/Asset and made generic over assets.
30pub trait Pay {
31	/// The type by which we measure units of the currency in which we make payments.
32	type Balance: Balance;
33	/// The type by which we identify the beneficiaries to whom a payment may be made.
34	type Beneficiary;
35	/// The type for the kinds of asset that are going to be paid.
36	///
37	/// The unit type can be used here to indicate there's only one kind of asset to do payments
38	/// with. When implementing, it should be clear from the context what that asset is.
39	type AssetKind;
40	/// An identifier given to an individual payment.
41	type Id: FullCodec + MaxEncodedLen + TypeInfo + Clone + Eq + PartialEq + Debug + Copy;
42	/// An error which could be returned by the Pay type
43	type Error: Debug;
44	/// Make a payment and return an identifier for later evaluation of success in some off-chain
45	/// mechanism (likely an event, but possibly not on this chain).
46	fn pay(
47		who: &Self::Beneficiary,
48		asset_kind: Self::AssetKind,
49		amount: Self::Balance,
50	) -> Result<Self::Id, Self::Error>;
51	/// Check how a payment has proceeded. `id` must have been previously returned by `pay` for
52	/// the result of this call to be meaningful.
53	fn check_payment(id: Self::Id) -> PaymentStatus;
54	/// Ensure that a call to pay with the given parameters will be successful if done immediately
55	/// after this call. Used in benchmarking code.
56	#[cfg(feature = "runtime-benchmarks")]
57	fn ensure_successful(
58		who: &Self::Beneficiary,
59		asset_kind: Self::AssetKind,
60		amount: Self::Balance,
61	);
62	/// Ensure that a call to `check_payment` with the given parameters will return either `Success`
63	/// or `Failure`.
64	#[cfg(feature = "runtime-benchmarks")]
65	fn ensure_concluded(id: Self::Id);
66}
67
68/// Status for making a payment via the `Pay::pay` trait function.
69pub type PaymentStatus = super::transfer::TransferStatus;
70
71/// Simple implementation of `Pay` which makes a payment from a "pot" - i.e. a single account.
72pub struct PayFromAccount<F, A>(core::marker::PhantomData<(F, A)>);
73impl<A, F> Pay for PayFromAccount<F, A>
74where
75	A: TypedGet,
76	F: fungible::Mutate<A::Type>,
77	A::Type: Eq,
78{
79	type Balance = F::Balance;
80	type Beneficiary = A::Type;
81	type AssetKind = ();
82	type Id = ();
83	type Error = DispatchError;
84	fn pay(
85		who: &Self::Beneficiary,
86		_: Self::AssetKind,
87		amount: Self::Balance,
88	) -> Result<Self::Id, Self::Error> {
89		<F as fungible::Mutate<_>>::transfer(&A::get(), who, amount, Expendable)?;
90		Ok(())
91	}
92	fn check_payment(_: ()) -> PaymentStatus {
93		PaymentStatus::Success
94	}
95	#[cfg(feature = "runtime-benchmarks")]
96	fn ensure_successful(_: &Self::Beneficiary, _: Self::AssetKind, amount: Self::Balance) {
97		<F as fungible::Mutate<_>>::mint_into(&A::get(), amount).unwrap();
98	}
99	#[cfg(feature = "runtime-benchmarks")]
100	fn ensure_concluded(_: Self::Id) {}
101}
102
103/// Simple implementation of `Pay` for assets which makes a payment from a "pot" - i.e. a single
104/// account.
105pub struct PayAssetFromAccount<F, A>(core::marker::PhantomData<(F, A)>);
106impl<A, F> frame_support::traits::tokens::Pay for PayAssetFromAccount<F, A>
107where
108	A: TypedGet,
109	F: fungibles::Mutate<A::Type> + fungibles::Create<A::Type>,
110	A::Type: Eq,
111{
112	type Balance = F::Balance;
113	type Beneficiary = A::Type;
114	type AssetKind = F::AssetId;
115	type Id = ();
116	type Error = DispatchError;
117	fn pay(
118		who: &Self::Beneficiary,
119		asset: Self::AssetKind,
120		amount: Self::Balance,
121	) -> Result<Self::Id, Self::Error> {
122		<F as fungibles::Mutate<_>>::transfer(asset, &A::get(), who, amount, Expendable)?;
123		Ok(())
124	}
125	fn check_payment(_: ()) -> PaymentStatus {
126		PaymentStatus::Success
127	}
128	#[cfg(feature = "runtime-benchmarks")]
129	fn ensure_successful(_: &Self::Beneficiary, asset: Self::AssetKind, amount: Self::Balance) {
130		<F as fungibles::Create<_>>::create(asset.clone(), A::get(), true, amount).unwrap();
131		<F as fungibles::Mutate<_>>::mint_into(asset, &A::get(), amount).unwrap();
132	}
133	#[cfg(feature = "runtime-benchmarks")]
134	fn ensure_concluded(_: Self::Id) {}
135}
136
137/// A variant of `Pay` that includes the payment `Source`.
138pub trait PayWithSource {
139	/// The type by which we measure units of the currency in which we make payments.
140	type Balance: Balance;
141	/// The type by which we identify the sources from whom a payment may be made.
142	type Source;
143	/// The type by which we identify the beneficiaries to whom a payment may be made.
144	type Beneficiary;
145	/// The type for the kinds of asset that are going to be paid.
146	///
147	/// The unit type can be used here to indicate there's only one kind of asset to do payments
148	/// with. When implementing, it should be clear from the context what that asset is.
149	type AssetKind;
150	/// An identifier given to an individual payment.
151	type Id: FullCodec + MaxEncodedLen + TypeInfo + Clone + Eq + PartialEq + Debug + Copy;
152	/// An error which could be returned by the Pay type
153	type Error: Debug;
154	/// Make a payment and return an identifier for later evaluation of success in some off-chain
155	/// mechanism (likely an event, but possibly not on this chain).
156	fn pay(
157		source: &Self::Source,
158		beneficiary: &Self::Beneficiary,
159		asset_kind: Self::AssetKind,
160		amount: Self::Balance,
161	) -> Result<Self::Id, Self::Error>;
162	/// Check how a payment has proceeded. `id` must have been previously returned by `pay` for
163	/// the result of this call to be meaningful. Once this returns anything other than
164	/// `InProgress` for some `id` it must return `Unknown` rather than the actual result
165	/// value.
166	fn check_payment(id: Self::Id) -> PaymentStatus;
167	/// Ensure that a call to pay with the given parameters will be successful if done immediately
168	/// after this call. Used in benchmarking code.
169	#[cfg(feature = "runtime-benchmarks")]
170	fn ensure_successful(
171		source: &Self::Source,
172		beneficiary: &Self::Beneficiary,
173		asset_kind: Self::AssetKind,
174		amount: Self::Balance,
175	);
176	/// Ensure that a call to `check_payment` with the given parameters will return either `Success`
177	/// or `Failure`.
178	#[cfg(feature = "runtime-benchmarks")]
179	fn ensure_concluded(id: Self::Id);
180}
181
182/// Implementation of the `PayWithSource` trait using multiple fungible asset classes (e.g.,
183/// `pallet_assets`)
184pub struct PayWithFungibles<F, A>(core::marker::PhantomData<(F, A)>);
185impl<A, F> frame_support::traits::tokens::PayWithSource for PayWithFungibles<F, A>
186where
187	A: Eq + Clone,
188	F: fungibles::Mutate<A> + fungibles::Create<A>,
189{
190	type Balance = F::Balance;
191	type Source = A;
192	type Beneficiary = A;
193	type AssetKind = F::AssetId;
194	type Id = ();
195	type Error = DispatchError;
196	fn pay(
197		source: &Self::Source,
198		beneficiary: &Self::Beneficiary,
199		asset: Self::AssetKind,
200		amount: Self::Balance,
201	) -> Result<Self::Id, Self::Error> {
202		<F as fungibles::Mutate<_>>::transfer(asset, source, beneficiary, amount, Expendable)?;
203		Ok(())
204	}
205	fn check_payment(_: ()) -> PaymentStatus {
206		PaymentStatus::Success
207	}
208	#[cfg(feature = "runtime-benchmarks")]
209	fn ensure_successful(
210		source: &Self::Source,
211		_: &Self::Beneficiary,
212		asset: Self::AssetKind,
213		amount: Self::Balance,
214	) {
215		use sp_runtime::traits::Zero;
216
217		if F::total_issuance(asset.clone()).is_zero() {
218			let _ = <F as fungibles::Create<_>>::create(
219				asset.clone(),
220				source.clone(),
221				true,
222				1u32.into(),
223			);
224		}
225		<F as fungibles::Mutate<_>>::mint_into(asset, &source, amount).unwrap();
226	}
227	#[cfg(feature = "runtime-benchmarks")]
228	fn ensure_concluded(_: Self::Id) {}
229}