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