// This file is part of Bizinikiwi. // Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // 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. //! Implementations for fungibles trait. use alloc::vec::Vec; use pezframe_support::{ defensive, traits::tokens::{ Fortitude, Precision::{self, BestEffort}, Preservation::{self, Expendable}, Provenance::{self, Minted}, }, }; use super::*; impl, I: 'static> fungibles::Inspect<::AccountId> for Pezpallet { type AssetId = T::AssetId; type Balance = T::Balance; fn total_issuance(asset: Self::AssetId) -> Self::Balance { Asset::::get(asset).map(|x| x.supply).unwrap_or_else(Zero::zero) } fn minimum_balance(asset: Self::AssetId) -> Self::Balance { Asset::::get(asset).map(|x| x.min_balance).unwrap_or_else(Zero::zero) } fn balance(asset: Self::AssetId, who: &::AccountId) -> Self::Balance { Pezpallet::::balance(asset, who) } fn total_balance(asset: Self::AssetId, who: &::AccountId) -> Self::Balance { Pezpallet::::balance(asset.clone(), who) .saturating_add(T::Holder::balance_on_hold(asset, who).unwrap_or_default()) } fn reducible_balance( asset: Self::AssetId, who: &::AccountId, preservation: Preservation, _: Fortitude, ) -> Self::Balance { Pezpallet::::reducible_balance(asset, who, !matches!(preservation, Expendable)) .unwrap_or(Zero::zero()) } fn can_deposit( asset: Self::AssetId, who: &::AccountId, amount: Self::Balance, provenance: Provenance, ) -> DepositConsequence { Pezpallet::::can_increase(asset, who, amount, provenance == Minted) } fn can_withdraw( asset: Self::AssetId, who: &::AccountId, amount: Self::Balance, ) -> WithdrawConsequence { Pezpallet::::can_decrease(asset, who, amount, false) } fn asset_exists(asset: Self::AssetId) -> bool { Asset::::contains_key(asset) } } impl, I: 'static> fungibles::Mutate<::AccountId> for Pezpallet { fn done_mint_into( asset_id: Self::AssetId, beneficiary: &::AccountId, amount: Self::Balance, ) { Self::deposit_event(Event::Issued { asset_id, owner: beneficiary.clone(), amount }) } fn done_burn_from( asset_id: Self::AssetId, target: &::AccountId, balance: Self::Balance, ) { Self::deposit_event(Event::Burned { asset_id, owner: target.clone(), balance }); } fn done_transfer( asset_id: Self::AssetId, source: &::AccountId, dest: &::AccountId, amount: Self::Balance, ) { Self::deposit_event(Event::Transferred { asset_id, from: source.clone(), to: dest.clone(), amount, }); } } impl, I: 'static> fungibles::Balanced<::AccountId> for Pezpallet { type OnDropCredit = fungibles::DecreaseIssuance; type OnDropDebt = fungibles::IncreaseIssuance; fn done_deposit( asset_id: Self::AssetId, who: &::AccountId, amount: Self::Balance, ) { Self::deposit_event(Event::Deposited { asset_id, who: who.clone(), amount }) } fn done_withdraw( asset_id: Self::AssetId, who: &::AccountId, amount: Self::Balance, ) { Self::deposit_event(Event::Withdrawn { asset_id, who: who.clone(), amount }) } } impl, I: 'static> fungibles::Unbalanced for Pezpallet { fn handle_raw_dust(_: Self::AssetId, _: Self::Balance) {} fn handle_dust(_: fungibles::Dust) { defensive!("`decrease_balance` and `increase_balance` have non-default impls; nothing else calls this; qed"); } fn write_balance( _: Self::AssetId, _: &T::AccountId, _: Self::Balance, ) -> Result, DispatchError> { defensive!("write_balance is not used if other functions are impl'd"); Err(DispatchError::Unavailable) } fn set_total_issuance(id: T::AssetId, amount: Self::Balance) { Asset::::mutate_exists(id, |maybe_asset| { if let Some(ref mut asset) = maybe_asset { asset.supply = amount } }); } fn decrease_balance( asset: T::AssetId, who: &T::AccountId, amount: Self::Balance, precision: Precision, preservation: Preservation, _: Fortitude, ) -> Result { let f = DebitFlags { keep_alive: preservation != Expendable, best_effort: precision == BestEffort, }; Self::decrease_balance(asset, who, amount, f, |_, _| Ok(())) } fn increase_balance( asset: T::AssetId, who: &T::AccountId, amount: Self::Balance, _: Precision, ) -> Result { Self::increase_balance(asset, who, amount, |_| Ok(()))?; Ok(amount) } // TODO: #13196 implement deactivate/reactivate once we have inactive balance tracking. } impl, I: 'static> fungibles::Create for Pezpallet { fn create( id: T::AssetId, admin: T::AccountId, is_sufficient: bool, min_balance: Self::Balance, ) -> DispatchResult { Self::do_force_create(id, admin, is_sufficient, min_balance) } } impl, I: 'static> fungibles::Destroy for Pezpallet { fn start_destroy(id: T::AssetId, maybe_check_owner: Option) -> DispatchResult { Self::do_start_destroy(id, maybe_check_owner) } fn destroy_accounts(id: T::AssetId, max_items: u32) -> Result { Self::do_destroy_accounts(id, max_items) } fn destroy_approvals(id: T::AssetId, max_items: u32) -> Result { Self::do_destroy_approvals(id, max_items) } fn finish_destroy(id: T::AssetId) -> DispatchResult { Self::do_finish_destroy(id) } } impl, I: 'static> fungibles::metadata::Inspect<::AccountId> for Pezpallet { fn name(asset: T::AssetId) -> Vec { Metadata::::get(asset).name.to_vec() } fn symbol(asset: T::AssetId) -> Vec { Metadata::::get(asset).symbol.to_vec() } fn decimals(asset: T::AssetId) -> u8 { Metadata::::get(asset).decimals } } impl, I: 'static> fungibles::metadata::Mutate<::AccountId> for Pezpallet { fn set( asset: T::AssetId, from: &::AccountId, name: Vec, symbol: Vec, decimals: u8, ) -> DispatchResult { Self::do_set_metadata(asset, from, name, symbol, decimals) } } impl, I: 'static> fungibles::metadata::MetadataDeposit< ::AccountId>>::Balance, > for Pezpallet { fn calc_metadata_deposit( name: &[u8], symbol: &[u8], ) -> ::AccountId>>::Balance { Self::calc_metadata_deposit(&name, &symbol) } } impl, I: 'static> fungibles::approvals::Inspect<::AccountId> for Pezpallet { // Check the amount approved to be spent by an owner to a delegate fn allowance( asset: T::AssetId, owner: &::AccountId, delegate: &::AccountId, ) -> T::Balance { Approvals::::get((asset, &owner, &delegate)) .map(|x| x.amount) .unwrap_or_else(Zero::zero) } } impl, I: 'static> fungibles::approvals::Mutate<::AccountId> for Pezpallet { // Approve spending tokens from a given account fn approve( asset: T::AssetId, owner: &::AccountId, delegate: &::AccountId, amount: T::Balance, ) -> DispatchResult { Self::do_approve_transfer(asset, owner, delegate, amount) } fn transfer_from( asset: T::AssetId, owner: &::AccountId, delegate: &::AccountId, dest: &::AccountId, amount: T::Balance, ) -> DispatchResult { Self::do_transfer_approved(asset, owner, delegate, dest, amount) } } impl, I: 'static> fungibles::roles::Inspect<::AccountId> for Pezpallet { fn owner(asset: T::AssetId) -> Option<::AccountId> { Asset::::get(asset).map(|x| x.owner) } fn issuer(asset: T::AssetId) -> Option<::AccountId> { Asset::::get(asset).map(|x| x.issuer) } fn admin(asset: T::AssetId) -> Option<::AccountId> { Asset::::get(asset).map(|x| x.admin) } fn freezer(asset: T::AssetId) -> Option<::AccountId> { Asset::::get(asset).map(|x| x.freezer) } } impl, I: 'static> fungibles::InspectEnumerable for Pezpallet { type AssetsIterator = KeyPrefixIterator<>::AssetId>; /// Returns an iterator of the assets in existence. /// /// NOTE: iterating this list invokes a storage read per item. fn asset_ids() -> Self::AssetsIterator { Asset::::iter_keys() } } impl, I: 'static> fungibles::roles::ResetTeam for Pezpallet { fn reset_team( id: T::AssetId, owner: T::AccountId, admin: T::AccountId, issuer: T::AccountId, freezer: T::AccountId, ) -> DispatchResult { Self::do_reset_team(id, owner, admin, issuer, freezer) } } impl, I: 'static> fungibles::Refund for Pezpallet { type AssetId = T::AssetId; type Balance = DepositBalanceOf; fn deposit_held(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { use ExistenceReason::*; match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { DepositHeld(b) => Some((who, b)), DepositFrom(d, b) => Some((d, b)), _ => None, } } fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { match Self::deposit_held(id.clone(), who.clone()) { Some((d, _)) if d == who => Self::do_refund(id, who, false), Some(..) => Self::do_refund_other(id, &who, None), None => Err(Error::::NoDeposit.into()), } } }