// This file is part of Bizinikiwi. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! # Assets Holder Pezpallet //! //! A pezpallet capable of holding fungibles from `pezpallet-assets`. This is an extension of //! `pezpallet-assets`, wrapping //! [`fungibles::Inspect`](`pezframe_support::traits::fungibles::Inspect`). It implements both //! [`fungibles::hold::Inspect`](pezframe_support::traits::fungibles::hold::Inspect), //! [`fungibles::hold::Mutate`](pezframe_support::traits::fungibles::hold::Mutate), and especially //! [`fungibles::hold::Unbalanced`](pezframe_support::traits::fungibles::hold::Unbalanced). The //! complexity of the operations is `O(1)`. //! //! ## Pezpallet API //! //! See the [`pezpallet`] module for more information about the interfaces this pezpallet exposes, //! including its configuration trait, dispatchables, storage items, events and errors. //! //! ## Overview //! //! This pezpallet provides the following functionality: //! //! - Pezpallet hooks allowing [`pezpallet-assets`] to know the balance on hold for an account on a //! given asset (see [`pezpallet_assets::BalanceOnHold`]). //! - An implementation of //! [`fungibles::hold::Inspect`](pezframe_support::traits::fungibles::hold::Inspect), //! [`fungibles::hold::Mutate`](pezframe_support::traits::fungibles::hold::Mutate) and //! [`fungibles::hold::Unbalanced`](pezframe_support::traits::fungibles::hold::Unbalanced), //! allowing other pallets to manage holds for the `pezpallet-assets` assets. #![cfg_attr(not(feature = "std"), no_std)] use pezframe_support::{ pezpallet_prelude::*, traits::{tokens::IdAmount, VariantCount, VariantCountOf}, BoundedVec, }; use pezframe_system::pezpallet_prelude::BlockNumberFor; pub use pezpallet::*; #[cfg(test)] mod mock; #[cfg(test)] mod tests; mod impl_fungibles; #[pezframe_support::pezpallet] pub mod pezpallet { use super::*; #[pezpallet::config(with_default)] pub trait Config: pezframe_system::Config + pezpallet_assets::Config> { /// The overarching freeze reason. #[pezpallet::no_default_bounds] type RuntimeHoldReason: Parameter + Member + MaxEncodedLen + Copy + VariantCount; /// The overarching event type. #[pezpallet::no_default_bounds] #[allow(deprecated)] type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pezpallet::error] pub enum Error { /// Number of holds on an account would exceed the count of `RuntimeHoldReason`. TooManyHolds, } #[pezpallet::pezpallet] pub struct Pezpallet(_); #[pezpallet::event] #[pezpallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { /// `who`s balance on hold was increased by `amount`. Held { who: T::AccountId, asset_id: T::AssetId, reason: T::RuntimeHoldReason, amount: T::Balance, }, /// `who`s balance on hold was decreased by `amount`. Released { who: T::AccountId, asset_id: T::AssetId, reason: T::RuntimeHoldReason, amount: T::Balance, }, /// `who`s balance on hold was burned by `amount`. Burned { who: T::AccountId, asset_id: T::AssetId, reason: T::RuntimeHoldReason, amount: T::Balance, }, } /// A map that stores holds applied on an account for a given AssetId. #[pezpallet::storage] pub(super) type Holds, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AssetId, Blake2_128Concat, T::AccountId, BoundedVec< IdAmount, VariantCountOf, >, ValueQuery, >; /// A map that stores the current total balance on hold for every account on a given AssetId. #[pezpallet::storage] pub(super) type BalancesOnHold, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::AssetId, Blake2_128Concat, T::AccountId, T::Balance, >; #[pezpallet::hooks] impl, I: 'static> Hooks> for Pezpallet { #[cfg(feature = "try-runtime")] fn try_state(_: BlockNumberFor) -> Result<(), pezsp_runtime::TryRuntimeError> { Self::do_try_state() } } } impl, I: 'static> Pezpallet { #[cfg(any(test, feature = "try-runtime"))] fn do_try_state() -> Result<(), pezsp_runtime::TryRuntimeError> { use pezsp_runtime::{ traits::{CheckedAdd, Zero}, ArithmeticError, }; for (asset, who, balance_on_hold) in BalancesOnHold::::iter() { ensure!(balance_on_hold != Zero::zero(), "zero on hold must not be in state"); let mut amount_from_holds: T::Balance = Zero::zero(); for l in Holds::::get(asset.clone(), who.clone()).iter() { ensure!(l.amount != Zero::zero(), "zero amount is invalid"); amount_from_holds = amount_from_holds.checked_add(&l.amount).ok_or(ArithmeticError::Overflow)?; } pezframe_support::ensure!( balance_on_hold == amount_from_holds, "The `BalancesOnHold` amount is not equal to the sum of `Holds` for (`asset`, `who`)" ); } Ok(()) } }