1use crate::{Config, NativeFungibleHandle, Pallet, SelfWeightOf};2use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};3use frame_support::traits::{Currency, ExistenceRequirement};4use pallet_balances::WeightInfo;5use pallet_common::{6 consume_store_reads,7 erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult},8 eth::CrossAddress,9};10use pallet_evm_coder_substrate::{11 call, dispatch_to_evm,12 execution::{PreDispatch, Result},13 frontier_contract, WithRecorder,14};15use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};16use sp_core::{U256, Get};17use sp_std::vec::Vec;1819frontier_contract! {20 macro_rules! NativeFungibleHandle_result {...}21 impl<T: Config> Contract for NativeFungibleHandle<T> {...}22}2324#[derive(ToLog)]25pub enum ERC20Events {26 Transfer {27 #[indexed]28 from: Address,29 #[indexed]30 to: Address,31 value: U256,32 },33}3435#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]36impl<T: Config> NativeFungibleHandle<T> {37 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {38 Ok(U256::zero())39 }4041 42 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {43 44 Err("Approve not supported".into())45 }4647 fn balance_of(&self, owner: Address) -> Result<U256> {48 consume_store_reads(self, 1)?;49 let owner = T::CrossAccountId::from_eth(owner);50 let balance = <T as Config>::Currency::free_balance(owner.as_sub());51 Ok(balance.into())52 }5354 fn decimals(&self) -> Result<u8> {55 Ok(T::Decimals::get())56 }5758 fn name(&self) -> Result<String> {59 Ok(T::Name::get())60 }6162 fn symbol(&self) -> Result<String> {63 Ok(T::Symbol::get())64 }6566 fn total_supply(&self) -> Result<U256> {67 consume_store_reads(self, 1)?;68 let total = <T as Config>::Currency::total_issuance();69 Ok(total.into())70 }7172 #[weight(<SelfWeightOf<T>>::transfer())]73 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {74 let caller = T::CrossAccountId::from_eth(caller);75 let to = T::CrossAccountId::from_eth(to);76 let amount = amount.try_into().map_err(|_| "amount overflow")?;77 let budget = self78 .recorder()79 .weight_calls_budget(<StructureWeight<T>>::find_parent());8081 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget)82 .map_err(|e| dispatch_to_evm::<T>(e.error))?;83 Ok(true)84 }8586 #[weight(<SelfWeightOf<T>>::transfer())]87 fn transfer_from(88 &mut self,89 caller: Caller,90 from: Address,91 to: Address,92 amount: U256,93 ) -> Result<bool> {94 let caller = T::CrossAccountId::from_eth(caller);95 let from = T::CrossAccountId::from_eth(from);96 let to = T::CrossAccountId::from_eth(to);97 let amount = amount.try_into().map_err(|_| "amount overflow")?;98 let budget = self99 .recorder()100 .weight_calls_budget(<StructureWeight<T>>::find_parent());101102 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)103 .map_err(|e| dispatch_to_evm::<T>(e.error))?;104 Ok(true)105 }106}107108#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]109impl<T: Config> NativeFungibleHandle<T>110where111 T::AccountId: From<[u8; 32]>,112{113 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {114 consume_store_reads(self, 1)?;115 let owner = owner.into_sub_cross_account::<T>()?;116 let balance = <T as Config>::Currency::free_balance(owner.as_sub());117 Ok(balance.into())118 }119120 #[weight(<SelfWeightOf<T>>::transfer())]121 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {122 let caller = T::CrossAccountId::from_eth(caller);123 let to = to.into_sub_cross_account::<T>()?;124 let amount = amount.try_into().map_err(|_| "amount overflow")?;125 126 127 128129 130 <T as Config>::Currency::transfer(131 caller.as_sub(),132 to.as_sub(),133 amount,134 ExistenceRequirement::KeepAlive,135 )136 .map_err(dispatch_to_evm::<T>)?;137 Ok(true)138 }139140 #[weight(<SelfWeightOf<T>>::transfer())]141 fn transfer_from_cross(142 &mut self,143 caller: Caller,144 from: CrossAddress,145 to: CrossAddress,146 amount: U256,147 ) -> Result<bool> {148 let caller = T::CrossAccountId::from_eth(caller);149 let from = from.into_sub_cross_account::<T>()?;150 let to = to.into_sub_cross_account::<T>()?;151 let amount = amount.try_into().map_err(|_| "amount overflow")?;152153 if from != caller {154 return Err("no permission".into());155 }156157 158 159 160161 162 163 <T as Config>::Currency::transfer(164 caller.as_sub(),165 to.as_sub(),166 amount,167 ExistenceRequirement::KeepAlive,168 )169 .map_err(dispatch_to_evm::<T>)?;170 Ok(true)171 }172}173174#[solidity_interface(175 name = UniqueNativeFungible,176 is(ERC20, ERC20UniqueExtensions),177 enum(derive(PreDispatch))178)]179impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}180181generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);182generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);183184impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>185where186 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,187{188 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");189190 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {191 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)192 }193}