1use crate::{Config, NativeFungibleHandle, 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 erc::{CommonEvmHandler, CrossAccountId, PrecompileHandle, PrecompileResult},7 eth::CrossAddress,8};9use pallet_evm_coder_substrate::{10 call, dispatch_to_evm,11 execution::{PreDispatch, Result},12 frontier_contract, WithRecorder, SubstrateRecorder,13};14use sp_core::{U256, Get};15use sp_std::vec::Vec;1617frontier_contract! {18 macro_rules! NativeFungibleHandle_result {...}19 impl<T: Config> Contract for NativeFungibleHandle<T> {...}20}2122#[derive(ToLog)]23pub enum ERC20Events {24 Transfer {25 #[indexed]26 from: Address,27 #[indexed]28 to: Address,29 value: U256,30 },31 Approval {32 #[indexed]33 owner: Address,34 #[indexed]35 spender: Address,36 value: U256,37 },38}3940#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]41impl<T: Config> NativeFungibleHandle<T> {42 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {43 Ok(U256::zero())44 }4546 47 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {48 49 Err("Approve not supported".into())50 }5152 fn balance_of(&self, owner: Address) -> Result<U256> {53 54 let owner = T::CrossAccountId::from_eth(owner);55 let balance = <T as Config>::Currency::free_balance(owner.as_sub());56 Ok(balance.into())57 }5859 fn decimals(&self) -> Result<u8> {60 Ok(T::Decimals::get())61 }6263 fn name(&self) -> Result<String> {64 Ok(T::Name::get())65 }6667 fn symbol(&self) -> Result<String> {68 Ok(T::Symbol::get())69 }7071 fn total_supply(&self) -> Result<U256> {72 73 let total = <T as Config>::Currency::total_issuance();74 Ok(total.into())75 }7677 #[weight(<SelfWeightOf<T>>::transfer())]78 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {79 let caller = T::CrossAccountId::from_eth(caller);80 let to = T::CrossAccountId::from_eth(to);81 let amount = amount.try_into().map_err(|_| "amount overflow")?;82 83 84 8586 87 <T as Config>::Currency::transfer(88 caller.as_sub(),89 to.as_sub(),90 amount,91 ExistenceRequirement::KeepAlive,92 )93 .map_err(dispatch_to_evm::<T>)?;94 Ok(true)95 }9697 #[weight(<SelfWeightOf<T>>::transfer())]98 fn transfer_from(99 &mut self,100 caller: Caller,101 from: Address,102 to: Address,103 amount: U256,104 ) -> Result<bool> {105 let caller = T::CrossAccountId::from_eth(caller);106 let from = T::CrossAccountId::from_eth(from);107 let to = T::CrossAccountId::from_eth(to);108 let amount = amount.try_into().map_err(|_| "amount overflow")?;109110 if from != caller {111 return Err("no permission".into());112 }113 114 115 116117 118 119 <T as Config>::Currency::transfer(120 caller.as_sub(),121 to.as_sub(),122 amount,123 ExistenceRequirement::KeepAlive,124 )125 .map_err(dispatch_to_evm::<T>)?;126 Ok(true)127 }128}129130#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]131impl<T: Config> NativeFungibleHandle<T>132where133 T::AccountId: From<[u8; 32]>,134{135 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {136 137 let owner = owner.into_sub_cross_account::<T>()?;138 let balance = <T as Config>::Currency::free_balance(owner.as_sub());139 Ok(balance.into())140 }141142 #[weight(<SelfWeightOf<T>>::transfer())]143 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {144 let caller = T::CrossAccountId::from_eth(caller);145 let to = to.into_sub_cross_account::<T>()?;146 let amount = amount.try_into().map_err(|_| "amount overflow")?;147 148 149 150151 152 <T as Config>::Currency::transfer(153 caller.as_sub(),154 to.as_sub(),155 amount,156 ExistenceRequirement::KeepAlive,157 )158 .map_err(dispatch_to_evm::<T>)?;159 Ok(true)160 }161162 #[weight(<SelfWeightOf<T>>::transfer())]163 fn transfer_from_cross(164 &mut self,165 caller: Caller,166 from: CrossAddress,167 to: CrossAddress,168 amount: U256,169 ) -> Result<bool> {170 let caller = T::CrossAccountId::from_eth(caller);171 let from = from.into_sub_cross_account::<T>()?;172 let to = to.into_sub_cross_account::<T>()?;173 let amount = amount.try_into().map_err(|_| "amount overflow")?;174175 if from != caller {176 return Err("no permission".into());177 }178179 180 181 182183 184 185 <T as Config>::Currency::transfer(186 caller.as_sub(),187 to.as_sub(),188 amount,189 ExistenceRequirement::KeepAlive,190 )191 .map_err(dispatch_to_evm::<T>)?;192 Ok(true)193 }194}195196#[solidity_interface(197 name = UniqueNativeFungible,198 is(ERC20, ERC20UniqueExtensions),199 enum(derive(PreDispatch))200)]201impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}202203generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);204generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);205206impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>207where208 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,209{210 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");211212 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {213 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)214 }215}