1use evm_coder::{abi::AbiType, generate_stubgen, solidity_interface, types::*};2use pallet_balances::WeightInfo;3use pallet_common::{4 erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult},5 eth::CrossAddress,6};7use pallet_evm_coder_substrate::{8 call, dispatch_to_evm,9 execution::{PreDispatch, Result},10 frontier_contract, WithRecorder,11};12use pallet_structure::{weights::WeightInfo as _, SelfWeightOf as StructureWeight};13use sp_core::{Get, U256};1415use crate::{Config, NativeFungibleHandle, Pallet, SelfWeightOf};1617frontier_contract! {18 macro_rules! NativeFungibleHandle_result {...}19 impl<T: Config> Contract for NativeFungibleHandle<T> {...}20}2122#[solidity_interface(name = ERC20, enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]23impl<T: Config> NativeFungibleHandle<T> {24 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {25 Ok(U256::zero())26 }2728 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {29 Err("approve not supported".into())30 }3132 fn balance_of(&self, owner: Address) -> Result<U256> {33 self.consume_store_reads(1)?;34 let owner = T::CrossAccountId::from_eth(owner);35 let balance = <Pallet<T>>::balance_of(&owner);36 Ok(balance.into())37 }3839 fn decimals(&self) -> Result<u8> {40 Ok(T::Decimals::get())41 }4243 fn name(&self) -> Result<String> {44 Ok(T::Name::get())45 }4647 fn symbol(&self) -> Result<String> {48 Ok(T::Symbol::get())49 }5051 fn total_supply(&self) -> Result<U256> {52 self.consume_store_reads(1)?;53 Ok(<Pallet<T>>::total_issuance().into())54 }5556 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]57 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {58 let caller = T::CrossAccountId::from_eth(caller);59 let to = T::CrossAccountId::from_eth(to);60 let amount = amount.try_into().map_err(|_| "amount overflow")?;61 let budget = self62 .recorder()63 .weight_calls_budget(<StructureWeight<T>>::find_parent());6465 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)66 .map_err(|e| dispatch_to_evm::<T>(e.error))?;67 Ok(true)68 }6970 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]71 fn transfer_from(72 &mut self,73 caller: Caller,74 from: Address,75 to: Address,76 amount: U256,77 ) -> Result<bool> {78 let caller = T::CrossAccountId::from_eth(caller);79 let from = T::CrossAccountId::from_eth(from);80 let to = T::CrossAccountId::from_eth(to);81 let amount = amount.try_into().map_err(|_| "amount overflow")?;82 let budget = self83 .recorder()84 .weight_calls_budget(<StructureWeight<T>>::find_parent());8586 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)87 .map_err(|e| dispatch_to_evm::<T>(e.error))?;88 Ok(true)89 }90}9192#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]93impl<T: Config> NativeFungibleHandle<T>94where95 T::AccountId: From<[u8; 32]>,96{97 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {98 self.consume_store_reads(1)?;99 let owner = owner.into_sub_cross_account::<T>()?;100 let balance = <Pallet<T>>::balance_of(&owner);101 Ok(balance.into())102 }103104 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]105 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {106 let caller = T::CrossAccountId::from_eth(caller);107 let to = to.into_sub_cross_account::<T>()?;108 let amount = amount.try_into().map_err(|_| "amount overflow")?;109 let budget = self110 .recorder()111 .weight_calls_budget(<StructureWeight<T>>::find_parent());112113 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)114 .map_err(|e| dispatch_to_evm::<T>(e.error))?;115116 Ok(true)117 }118119 #[weight(<SelfWeightOf<T>>::transfer_allow_death())]120 fn transfer_from_cross(121 &mut self,122 caller: Caller,123 from: CrossAddress,124 to: CrossAddress,125 amount: U256,126 ) -> Result<bool> {127 let caller = T::CrossAccountId::from_eth(caller);128 let from = from.into_sub_cross_account::<T>()?;129 let to = to.into_sub_cross_account::<T>()?;130 let amount = amount.try_into().map_err(|_| "amount overflow")?;131132 if from != caller {133 return Err("no permission".into());134 }135136 let budget = self137 .recorder()138 .weight_calls_budget(<StructureWeight<T>>::find_parent());139140 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)141 .map_err(|e| dispatch_to_evm::<T>(e.error))?;142143 Ok(true)144 }145}146147#[solidity_interface(148 name = UniqueNativeFungible,149 is(ERC20, ERC20UniqueExtensions),150 enum(derive(PreDispatch))151)]152impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}153154generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);155generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);156157impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>158where159 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,160{161 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");162163 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {164 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)165 }166}