frame_support/traits/tokens/
misc.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//! Miscellaneous types.
19
20use crate::{traits::Contains, TypeInfo};
21use alloc::{vec, vec::Vec};
22use codec::{Decode, DecodeWithMemTracking, Encode, FullCodec, HasCompact, MaxEncodedLen};
23use core::fmt::Debug;
24use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero};
25use sp_core::RuntimeDebug;
26use sp_runtime::{
27	traits::{Convert, MaybeSerializeDeserialize},
28	ArithmeticError, DispatchError, TokenError,
29};
30
31/// The origin of funds to be used for a deposit operation.
32#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
33pub enum Provenance {
34	/// The funds will be minted into the system, increasing total issuance (and potentially
35	/// causing an overflow there).
36	Minted,
37	/// The funds already exist in the system, therefore will not affect total issuance.
38	Extant,
39}
40
41/// The mode under which usage of funds may be restricted.
42#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
43pub enum Restriction {
44	/// Funds are under the normal conditions.
45	Free,
46	/// Funds are on hold.
47	OnHold,
48}
49
50/// The mode by which we describe whether an operation should keep an account alive.
51#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
52pub enum Preservation {
53	/// We don't care if the account gets killed by this operation.
54	Expendable,
55	/// The account may not be killed, but we don't care if the balance gets dusted.
56	Protect,
57	/// The account may not be killed and our provider reference must remain (in the context of
58	/// tokens, this means that the account may not be dusted).
59	Preserve,
60}
61
62/// The privilege with which a withdraw operation is conducted.
63#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
64pub enum Fortitude {
65	/// The operation should execute with regular privilege.
66	Polite,
67	/// The operation should be forced to succeed if possible. This is usually employed for system-
68	/// level security-critical events such as slashing.
69	Force,
70}
71
72/// The precision required of an operation generally involving some aspect of quantitative fund
73/// withdrawal or transfer.
74#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
75pub enum Precision {
76	/// The operation should must either proceed either exactly according to the amounts involved
77	/// or not at all.
78	Exact,
79	/// The operation may be considered successful even if less than the specified amounts are
80	/// available to be used. In this case a best effort will be made.
81	BestEffort,
82}
83
84/// One of a number of consequences of withdrawing a fungible from an account.
85#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
86pub enum WithdrawConsequence<Balance> {
87	/// Withdraw could not happen since the amount to be withdrawn is less than the total funds in
88	/// the account.
89	BalanceLow,
90	/// The withdraw would mean the account dying when it needs to exist (usually because it is a
91	/// provider and there are consumer references on it).
92	WouldDie,
93	/// The asset is unknown. Usually because an `AssetId` has been presented which doesn't exist
94	/// on the system.
95	UnknownAsset,
96	/// There has been an underflow in the system. This is indicative of a corrupt state and
97	/// likely unrecoverable.
98	Underflow,
99	/// There has been an overflow in the system. This is indicative of a corrupt state and
100	/// likely unrecoverable.
101	Overflow,
102	/// Not enough of the funds in the account are available for withdrawal.
103	Frozen,
104	/// Account balance would reduce to zero, potentially destroying it. The parameter is the
105	/// amount of balance which is destroyed.
106	ReducedToZero(Balance),
107	/// Account continued in existence.
108	Success,
109}
110
111impl<Balance: Zero> WithdrawConsequence<Balance> {
112	/// Convert the type into a `Result` with `DispatchError` as the error or the additional
113	/// `Balance` by which the account will be reduced.
114	pub fn into_result(self, keep_nonzero: bool) -> Result<Balance, DispatchError> {
115		use WithdrawConsequence::*;
116		match self {
117			BalanceLow => Err(TokenError::FundsUnavailable.into()),
118			WouldDie => Err(TokenError::OnlyProvider.into()),
119			UnknownAsset => Err(TokenError::UnknownAsset.into()),
120			Underflow => Err(ArithmeticError::Underflow.into()),
121			Overflow => Err(ArithmeticError::Overflow.into()),
122			Frozen => Err(TokenError::Frozen.into()),
123			ReducedToZero(_) if keep_nonzero => Err(TokenError::NotExpendable.into()),
124			ReducedToZero(result) => Ok(result),
125			Success => Ok(Zero::zero()),
126		}
127	}
128}
129
130/// One of a number of consequences of withdrawing a fungible from an account.
131#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
132pub enum DepositConsequence {
133	/// Deposit couldn't happen due to the amount being too low. This is usually because the
134	/// account doesn't yet exist and the deposit wouldn't bring it to at least the minimum needed
135	/// for existence.
136	BelowMinimum,
137	/// Deposit cannot happen since the account cannot be created (usually because it's a consumer
138	/// and there exists no provider reference).
139	CannotCreate,
140	/// The asset is unknown. Usually because an `AssetId` has been presented which doesn't exist
141	/// on the system.
142	UnknownAsset,
143	/// An overflow would occur. This is practically unexpected, but could happen in test systems
144	/// with extremely small balance types or balances that approach the max value of the balance
145	/// type.
146	Overflow,
147	/// Account continued in existence.
148	Success,
149	/// Account cannot receive the assets.
150	Blocked,
151}
152
153impl DepositConsequence {
154	/// Convert the type into a `Result` with `TokenError` as the error.
155	pub fn into_result(self) -> Result<(), DispatchError> {
156		use DepositConsequence::*;
157		Err(match self {
158			BelowMinimum => TokenError::BelowMinimum.into(),
159			CannotCreate => TokenError::CannotCreate.into(),
160			UnknownAsset => TokenError::UnknownAsset.into(),
161			Overflow => ArithmeticError::Overflow.into(),
162			Blocked => TokenError::Blocked.into(),
163			Success => return Ok(()),
164		})
165	}
166}
167
168/// Simple boolean for whether an account needs to be kept in existence.
169#[derive(Copy, Clone, RuntimeDebug, Eq, PartialEq)]
170pub enum ExistenceRequirement {
171	/// Operation must not result in the account going out of existence.
172	///
173	/// Note this implies that if the account never existed in the first place, then the operation
174	/// may legitimately leave the account unchanged and still non-existent.
175	KeepAlive,
176	/// Operation may result in account going out of existence.
177	AllowDeath,
178}
179
180/// Status of funds.
181#[derive(
182	PartialEq,
183	Eq,
184	Clone,
185	Copy,
186	Encode,
187	Decode,
188	DecodeWithMemTracking,
189	RuntimeDebug,
190	scale_info::TypeInfo,
191	MaxEncodedLen,
192)]
193pub enum BalanceStatus {
194	/// Funds are free, as corresponding to `free` item in Balances.
195	Free,
196	/// Funds are reserved, as corresponding to `reserved` item in Balances.
197	Reserved,
198}
199
200bitflags::bitflags! {
201	/// Reasons for moving funds out of an account.
202	#[derive(Encode, Decode, MaxEncodedLen)]
203	pub struct WithdrawReasons: u8 {
204		/// In order to pay for (system) transaction costs.
205		const TRANSACTION_PAYMENT = 0b00000001;
206		/// In order to transfer ownership.
207		const TRANSFER = 0b00000010;
208		/// In order to reserve some funds for a later return or repatriation.
209		const RESERVE = 0b00000100;
210		/// In order to pay some other (higher-level) fees.
211		const FEE = 0b00001000;
212		/// In order to tip a validator for transaction inclusion.
213		const TIP = 0b00010000;
214	}
215}
216
217impl WithdrawReasons {
218	/// Choose all variants except for `one`.
219	///
220	/// ```rust
221	/// # use frame_support::traits::WithdrawReasons;
222	/// # fn main() {
223	/// assert_eq!(
224	/// 	WithdrawReasons::FEE | WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE | WithdrawReasons::TIP,
225	/// 	WithdrawReasons::except(WithdrawReasons::TRANSACTION_PAYMENT),
226	/// 	);
227	/// # }
228	/// ```
229	pub fn except(one: WithdrawReasons) -> WithdrawReasons {
230		let mut flags = Self::all();
231		flags.toggle(one);
232		flags
233	}
234}
235
236/// Simple amalgamation trait to collect together properties for an AssetId under one roof.
237pub trait AssetId:
238	FullCodec
239	+ DecodeWithMemTracking
240	+ Clone
241	+ Eq
242	+ PartialEq
243	+ Debug
244	+ scale_info::TypeInfo
245	+ MaxEncodedLen
246{
247}
248impl<
249		T: FullCodec
250			+ DecodeWithMemTracking
251			+ Clone
252			+ Eq
253			+ PartialEq
254			+ Debug
255			+ scale_info::TypeInfo
256			+ MaxEncodedLen,
257	> AssetId for T
258{
259}
260
261/// Simple amalgamation trait to collect together properties for a Balance under one roof.
262pub trait Balance:
263	AtLeast32BitUnsigned
264	+ FullCodec
265	+ DecodeWithMemTracking
266	+ HasCompact<Type: DecodeWithMemTracking>
267	+ Copy
268	+ Default
269	+ Debug
270	+ scale_info::TypeInfo
271	+ MaxEncodedLen
272	+ Send
273	+ Sync
274	+ MaybeSerializeDeserialize
275	+ 'static
276{
277}
278impl<
279		T: AtLeast32BitUnsigned
280			+ FullCodec
281			+ DecodeWithMemTracking
282			+ HasCompact<Type: DecodeWithMemTracking>
283			+ Copy
284			+ Default
285			+ Debug
286			+ scale_info::TypeInfo
287			+ MaxEncodedLen
288			+ Send
289			+ Sync
290			+ MaybeSerializeDeserialize
291			+ 'static,
292	> Balance for T
293{
294}
295
296/// Converts a balance value into an asset balance.
297pub trait ConversionToAssetBalance<InBalance, AssetId, AssetBalance> {
298	type Error;
299	fn to_asset_balance(balance: InBalance, asset_id: AssetId)
300		-> Result<AssetBalance, Self::Error>;
301}
302
303/// Converts an asset balance value into balance.
304pub trait ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> {
305	type Error;
306	fn from_asset_balance(
307		balance: AssetBalance,
308		asset_id: AssetId,
309	) -> Result<OutBalance, Self::Error>;
310	/// Ensures that a conversion for the `asset_id` will be successful if done immediately after
311	/// this call.
312	#[cfg(feature = "runtime-benchmarks")]
313	fn ensure_successful(asset_id: AssetId);
314}
315
316/// Implements [`ConversionFromAssetBalance`] and [`ConversionToAssetBalance`],
317/// enabling a 1:1 conversion between the asset balance and the native balance.
318pub struct UnityAssetBalanceConversion;
319impl<AssetBalance, AssetId, OutBalance>
320	ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> for UnityAssetBalanceConversion
321where
322	AssetBalance: Into<OutBalance>,
323{
324	type Error = ();
325	fn from_asset_balance(balance: AssetBalance, _: AssetId) -> Result<OutBalance, Self::Error> {
326		Ok(balance.into())
327	}
328	#[cfg(feature = "runtime-benchmarks")]
329	fn ensure_successful(_: AssetId) {}
330}
331impl<InBalance, AssetId, AssetBalance> ConversionToAssetBalance<InBalance, AssetId, AssetBalance>
332	for UnityAssetBalanceConversion
333where
334	InBalance: Into<AssetBalance>,
335{
336	type Error = ();
337	fn to_asset_balance(balance: InBalance, _: AssetId) -> Result<AssetBalance, Self::Error> {
338		Ok(balance.into())
339	}
340}
341
342/// Implements [`ConversionFromAssetBalance`], allowing for a 1:1 balance conversion of the asset
343/// when it meets the conditions specified by `C`. If the conditions are not met, the conversion is
344/// delegated to `O`.
345pub struct UnityOrOuterConversion<C, O>(core::marker::PhantomData<(C, O)>);
346impl<AssetBalance, AssetId, OutBalance, C, O>
347	ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance> for UnityOrOuterConversion<C, O>
348where
349	C: Contains<AssetId>,
350	O: ConversionFromAssetBalance<AssetBalance, AssetId, OutBalance>,
351	AssetBalance: Into<OutBalance>,
352{
353	type Error = O::Error;
354	fn from_asset_balance(
355		balance: AssetBalance,
356		asset_id: AssetId,
357	) -> Result<OutBalance, Self::Error> {
358		if C::contains(&asset_id) {
359			return Ok(balance.into());
360		}
361		O::from_asset_balance(balance, asset_id)
362	}
363	#[cfg(feature = "runtime-benchmarks")]
364	fn ensure_successful(asset_id: AssetId) {
365		O::ensure_successful(asset_id)
366	}
367}
368
369/// Provides asset trusted-reserves identifiers for an asset.
370pub trait ProvideAssetReserves<A, R> {
371	fn reserves(id: &A) -> Vec<R>;
372}
373impl<A, R> ProvideAssetReserves<A, R> for () {
374	fn reserves(_id: &A) -> Vec<R> {
375		vec![]
376	}
377}
378
379/// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented
380/// downstream to extend logic of Uniques/Nfts current functionality.
381pub trait Locker<CollectionId, ItemId> {
382	/// Check if the asset should be locked and prevent interactions with the asset from executing.
383	fn is_locked(collection: CollectionId, item: ItemId) -> bool;
384}
385
386impl<CollectionId, ItemId> Locker<CollectionId, ItemId> for () {
387	// Default will be false if not implemented downstream.
388	// Note: The logic check in this function must be constant time and consistent for benchmarks
389	// to work.
390	fn is_locked(_collection: CollectionId, _item: ItemId) -> bool {
391		false
392	}
393}
394
395/// Retrieve the salary for a member of a particular rank.
396pub trait GetSalary<Rank, AccountId, Balance> {
397	/// Retrieve the salary for a given rank. The account ID is also supplied in case this changes
398	/// things.
399	fn get_salary(rank: Rank, who: &AccountId) -> Balance;
400}
401
402/// Adapter for a rank-to-salary `Convert` implementation into a `GetSalary` implementation.
403pub struct ConvertRank<C>(core::marker::PhantomData<C>);
404impl<A, R, B, C: Convert<R, B>> GetSalary<R, A, B> for ConvertRank<C> {
405	fn get_salary(rank: R, _: &A) -> B {
406		C::convert(rank)
407	}
408}
409
410/// An identifier and balance.
411#[derive(
412	Encode,
413	Decode,
414	DecodeWithMemTracking,
415	Clone,
416	PartialEq,
417	Eq,
418	RuntimeDebug,
419	MaxEncodedLen,
420	TypeInfo,
421)]
422pub struct IdAmount<Id, Balance> {
423	/// An identifier for this item.
424	pub id: Id,
425	/// Some amount for this item.
426	pub amount: Balance,
427}