1#![cfg_attr(not(feature = "std"), no_std)]23extern crate alloc;4use core::ops::Deref;56use frame_support::sp_runtime::DispatchResult;7use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};8pub use pallet::*;910pub mod common;11pub mod erc;1213pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;141516pub struct NativeFungibleHandle<T: Config>(SubstrateRecorder<T>);17impl<T: Config> NativeFungibleHandle<T> {18 19 pub fn new() -> NativeFungibleHandle<T> {20 Self(SubstrateRecorder::new(u64::MAX))21 }2223 24 pub fn new_with_gas_limit(gas_limit: u64) -> NativeFungibleHandle<T> {25 Self(SubstrateRecorder::new(gas_limit))26 }2728 29 pub fn check_is_internal(&self) -> DispatchResult {30 Ok(())31 }32}3334impl<T: Config> WithRecorder<T> for NativeFungibleHandle<T> {35 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {36 &self.037 }38 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {39 self.040 }41}4243impl<T: Config> Deref for NativeFungibleHandle<T> {44 type Target = SubstrateRecorder<T>;4546 fn deref(&self) -> &Self::Target {47 &self.048 }49}50#[frame_support::pallet]51pub mod pallet {52 use super::*;53 use alloc::string::String;54 use frame_support::{55 dispatch::PostDispatchInfo,56 ensure,57 pallet_prelude::{DispatchResultWithPostInfo, Pays},58 traits::{59 Get,60 fungible::{Inspect, Mutate},61 tokens::Preservation,62 },63 };64 use pallet_balances::WeightInfo;65 use pallet_common::{erc::CrossAccountId, Error as CommonError, Pallet as PalletCommon};66 use pallet_structure::Pallet as PalletStructure;67 use sp_core::U256;68 use sp_runtime::DispatchError;69 use up_data_structs::{budget::Budget, mapping::TokenAddressMapping};7071 #[pallet::config]72 pub trait Config:73 frame_system::Config74 + pallet_evm_coder_substrate::Config75 + pallet_common::Config76 + pallet_structure::Config77 {78 79 type Inspect: frame_support::traits::tokens::fungible::Inspect<80 Self::AccountId,81 Balance = Self::CurrencyBalance,82 >;8384 85 type Mutate: frame_support::traits::tokens::fungible::Mutate<86 Self::AccountId,87 Balance = Self::CurrencyBalance,88 >;8990 91 type CurrencyBalance: Into<U256> + TryFrom<U256> + TryFrom<u128> + Into<u128>;9293 94 type Decimals: Get<u8>;95 96 type Name: Get<String>;97 98 type Symbol: Get<String>;99100 101 type WeightInfo: WeightInfo;102 }103 #[pallet::pallet]104 pub struct Pallet<T>(_);105106 impl<T: Config> Pallet<T> {107 pub fn balance_of(account: &T::CrossAccountId) -> u128 {108 T::Inspect::balance(account.as_sub()).into()109 }110111 pub fn total_balance(account: &T::CrossAccountId) -> u128 {112 T::Inspect::total_balance(account.as_sub()).into()113 }114115 pub fn total_issuance() -> u128 {116 T::Inspect::total_issuance().into()117 }118119 120 121 122 123 124 125 fn check_allowed(126 spender: &T::CrossAccountId,127 from: &T::CrossAccountId,128 nesting_budget: &dyn Budget,129 ) -> Result<u128, DispatchError> {130 if let Some((collection_id, token_id)) =131 T::CrossTokenAddressMapping::address_to_token(from)132 {133 ensure!(134 <PalletStructure<T>>::check_indirectly_owned(135 spender.clone(),136 collection_id,137 token_id,138 None,139 nesting_budget140 )?,141 <CommonError<T>>::ApprovedValueTooLow,142 );143 } else if !spender.conv_eq(from) {144 return Ok(0);145 }146147 Ok(Self::balance_of(from))148 }149150 151 152 153 154 155 156 157 158 pub fn transfer(159 _collection: &NativeFungibleHandle<T>,160 from: &T::CrossAccountId,161 to: &T::CrossAccountId,162 amount: u128,163 _nesting_budget: &dyn Budget,164 ) -> DispatchResultWithPostInfo {165 <PalletCommon<T>>::ensure_correct_receiver(to)?;166167 if from != to && amount != 0 {168 let amount = amount169 .try_into()170 .map_err(|_| sp_runtime::ArithmeticError::Overflow)?;171 T::Mutate::transfer(from.as_sub(), to.as_sub(), amount, Preservation::Expendable)?;172 };173174 Ok(PostDispatchInfo {175 actual_weight: Some(<SelfWeightOf<T>>::transfer_allow_death()),176 pays_fee: Pays::Yes,177 })178 }179180 181 182 183 184 185 186 187 188 189 190 191 pub fn transfer_from(192 collection: &NativeFungibleHandle<T>,193 spender: &T::CrossAccountId,194 from: &T::CrossAccountId,195 to: &T::CrossAccountId,196 amount: u128,197 nesting_budget: &dyn Budget,198 ) -> DispatchResultWithPostInfo {199 let allowance = Self::check_allowed(spender, from, nesting_budget)?;200 if allowance < amount {201 return Err(<CommonError<T>>::ApprovedValueTooLow.into());202 }203 Self::transfer(collection, from, to, amount, nesting_budget)204 }205 }206}