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}