1use crate::{Config, NativeFungibleHandle, Pallet, SelfWeightOf};2use evm_coder::{abi::AbiType, generate_stubgen, solidity_interface, types::*};3use pallet_balances::WeightInfo;4use pallet_common::{5 erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult},6 eth::CrossAddress,7};8use pallet_evm_coder_substrate::{9 call, dispatch_to_evm,10 execution::{PreDispatch, Result},11 frontier_contract, WithRecorder,12};13use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};14use sp_core::{U256, Get};1516frontier_contract! {17 macro_rules! NativeFungibleHandle_result {...}18 impl<T: Config> Contract for NativeFungibleHandle<T> {...}19}2021#[solidity_interface(name = ERC20, enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]22impl<T: Config> NativeFungibleHandle<T> {23 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {24 Ok(U256::zero())25 }2627 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {28 Err("approve not supported".into())29 }3031 fn balance_of(&self, owner: Address) -> Result<U256> {32 self.consume_store_reads(1)?;33 let owner = T::CrossAccountId::from_eth(owner);34 let balance = <Pallet<T>>::balance_of(&owner);35 Ok(balance.into())36 }3738 fn decimals(&self) -> Result<u8> {39 Ok(T::Decimals::get())40 }4142 fn name(&self) -> Result<String> {43 Ok(T::Name::get())44 }4546 fn symbol(&self) -> Result<String> {47 Ok(T::Symbol::get())48 }4950 fn total_supply(&self) -> Result<U256> {51 self.consume_store_reads(1)?;52 Ok(<Pallet<T>>::total_issuance().into())53 }5455 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]56 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {57 let caller = T::CrossAccountId::from_eth(caller);58 let to = T::CrossAccountId::from_eth(to);59 let amount = amount.try_into().map_err(|_| "amount overflow")?;60 let budget = self61 .recorder()62 .weight_calls_budget(<StructureWeight<T>>::find_parent());6364 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)65 .map_err(|e| dispatch_to_evm::<T>(e.error))?;66 Ok(true)67 }6869 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]70 fn transfer_from(71 &mut self,72 caller: Caller,73 from: Address,74 to: Address,75 amount: U256,76 ) -> Result<bool> {77 let caller = T::CrossAccountId::from_eth(caller);78 let from = T::CrossAccountId::from_eth(from);79 let to = T::CrossAccountId::from_eth(to);80 let amount = amount.try_into().map_err(|_| "amount overflow")?;81 let budget = self82 .recorder()83 .weight_calls_budget(<StructureWeight<T>>::find_parent());8485 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)86 .map_err(|e| dispatch_to_evm::<T>(e.error))?;87 Ok(true)88 }89}9091#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]92impl<T: Config> NativeFungibleHandle<T>93where94 T::AccountId: From<[u8; 32]>,95{96 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {97 self.consume_store_reads(1)?;98 let owner = owner.into_sub_cross_account::<T>()?;99 let balance = <Pallet<T>>::balance_of(&owner);100 Ok(balance.into())101 }102103 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]104 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {105 let caller = T::CrossAccountId::from_eth(caller);106 let to = to.into_sub_cross_account::<T>()?;107 let amount = amount.try_into().map_err(|_| "amount overflow")?;108 let budget = self109 .recorder()110 .weight_calls_budget(<StructureWeight<T>>::find_parent());111112 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)113 .map_err(|e| dispatch_to_evm::<T>(e.error))?;114115 Ok(true)116 }117118 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]119 fn transfer_from_cross(120 &mut self,121 caller: Caller,122 from: CrossAddress,123 to: CrossAddress,124 amount: U256,125 ) -> Result<bool> {126 let caller = T::CrossAccountId::from_eth(caller);127 let from = from.into_sub_cross_account::<T>()?;128 let to = to.into_sub_cross_account::<T>()?;129 let amount = amount.try_into().map_err(|_| "amount overflow")?;130131 if from != caller {132 return Err("no permission".into());133 }134135 let budget = self136 .recorder()137 .weight_calls_budget(<StructureWeight<T>>::find_parent());138139 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)140 .map_err(|e| dispatch_to_evm::<T>(e.error))?;141142 Ok(true)143 }144}145146#[solidity_interface(147 name = UniqueNativeFungible,148 is(ERC20, ERC20UniqueExtensions),149 enum(derive(PreDispatch))150)]151impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}152153generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);154generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);155156impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>157where158 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,159{160 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");161162 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {163 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)164 }165}