1use crate::{Config, NativeFungibleHandle};2use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};3use frame_support::traits::{Currency, ExistenceRequirement};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, SubstrateRecorder,12};13use sp_core::{U256, Get};14use sp_std::vec::Vec;1516frontier_contract! {17 macro_rules! NativeFungibleHandle_result {...}18 impl<T: Config> Contract for NativeFungibleHandle<T> {...}19}2021#[derive(ToLog)]22pub enum ERC20Events {23 Transfer {24 #[indexed]25 from: Address,26 #[indexed]27 to: Address,28 value: U256,29 },30 Approval {31 #[indexed]32 owner: Address,33 #[indexed]34 spender: Address,35 value: U256,36 },37}3839#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]40impl<T: Config> NativeFungibleHandle<T> {41 fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {42 Ok(U256::zero())43 }4445 46 fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {47 48 Err("Approve not supported now".into())49 }5051 fn balance_of(&self, owner: Address) -> Result<U256> {52 53 let owner = T::CrossAccountId::from_eth(owner);54 let balance = <T as Config>::Currency::free_balance(owner.as_sub());55 Ok(balance.into())56 }5758 fn decimals(&self) -> Result<u8> {59 Ok(T::Decimals::get())60 }6162 fn name(&self) -> Result<String> {63 Ok(T::Name::get())64 }6566 fn symbol(&self) -> Result<String> {67 Ok(T::Symbol::get())68 }6970 fn total_supply(&self) -> Result<U256> {71 72 let total = <T as Config>::Currency::total_issuance();73 Ok(total.into())74 }7576 77 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {78 let caller = T::CrossAccountId::from_eth(caller);79 let to = T::CrossAccountId::from_eth(to);80 let amount = amount.try_into().map_err(|_| "amount overflow")?;81 82 83 8485 86 <T as Config>::Currency::transfer(87 caller.as_sub(),88 to.as_sub(),89 amount,90 ExistenceRequirement::KeepAlive,91 )92 .map_err(dispatch_to_evm::<T>)?;93 Ok(true)94 }9596 97 fn transfer_from(98 &mut self,99 caller: Caller,100 from: Address,101 to: Address,102 amount: U256,103 ) -> Result<bool> {104 let caller = T::CrossAccountId::from_eth(caller);105 let from = T::CrossAccountId::from_eth(from);106 let to = T::CrossAccountId::from_eth(to);107 let amount = amount.try_into().map_err(|_| "amount overflow")?;108109 if from != to {110 return Err("no permission".into());111 }112 113 114 115116 117 118 <T as Config>::Currency::transfer(119 caller.as_sub(),120 to.as_sub(),121 amount,122 ExistenceRequirement::KeepAlive,123 )124 .map_err(dispatch_to_evm::<T>)?;125 Ok(true)126 }127}128129#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]130impl<T: Config> NativeFungibleHandle<T>131where132 T::AccountId: From<[u8; 32]>,133{134 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {135 136 let owner = owner.into_sub_cross_account::<T>()?;137 let balance = <T as Config>::Currency::free_balance(owner.as_sub());138 Ok(balance.into())139 }140141 142 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {143 let caller = T::CrossAccountId::from_eth(caller);144 let to = to.into_sub_cross_account::<T>()?;145 let amount = amount.try_into().map_err(|_| "amount overflow")?;146 147 148 149150 151 <T as Config>::Currency::transfer(152 caller.as_sub(),153 to.as_sub(),154 amount,155 ExistenceRequirement::KeepAlive,156 )157 .map_err(dispatch_to_evm::<T>)?;158 Ok(true)159 }160161 162 fn transfer_from_cross(163 &mut self,164 caller: Caller,165 from: CrossAddress,166 to: CrossAddress,167 amount: U256,168 ) -> Result<bool> {169 let caller = T::CrossAccountId::from_eth(caller);170 let from = from.into_sub_cross_account::<T>()?;171 let to = to.into_sub_cross_account::<T>()?;172 let amount = amount.try_into().map_err(|_| "amount overflow")?;173174 if from != to {175 return Err("no permission".into());176 }177178 179 180 181182 183 184 <T as Config>::Currency::transfer(185 caller.as_sub(),186 to.as_sub(),187 amount,188 ExistenceRequirement::KeepAlive,189 )190 .map_err(dispatch_to_evm::<T>)?;191 Ok(true)192 }193}194195#[solidity_interface(196 name = UniqueNativeFungible,197 is(ERC20, ERC20UniqueExtensions),198 enum(derive(PreDispatch))199)]200impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}201202generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);203generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);204205impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>206where207 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,208{209 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");210211 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {212 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)213 }214}