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 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,14};15use sp_core::{U256, Get};16use sp_std::vec::Vec;1718frontier_contract! {19 macro_rules! NativeFungibleHandle_result {...}20 impl<T: Config> Contract for NativeFungibleHandle<T> {...}21}2223#[derive(ToLog)]24pub enum ERC20Events {25 Transfer {26 #[indexed]27 from: Address,28 #[indexed]29 to: Address,30 value: U256,31 },32}3334#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]35impl<T: Config> NativeFungibleHandle<T> {36 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {37 Ok(U256::zero())38 }3940 41 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {42 43 Err("Approve not supported".into())44 }4546 fn balance_of(&self, owner: Address) -> Result<U256> {47 consume_store_reads(self, 1)?;48 let owner = T::CrossAccountId::from_eth(owner);49 let balance = <T as Config>::Currency::free_balance(owner.as_sub());50 Ok(balance.into())51 }5253 fn decimals(&self) -> Result<u8> {54 Ok(T::Decimals::get())55 }5657 fn name(&self) -> Result<String> {58 Ok(T::Name::get())59 }6061 fn symbol(&self) -> Result<String> {62 Ok(T::Symbol::get())63 }6465 fn total_supply(&self) -> Result<U256> {66 consume_store_reads(self, 1)?;67 let total = <T as Config>::Currency::total_issuance();68 Ok(total.into())69 }7071 #[weight(<SelfWeightOf<T>>::transfer())]72 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {73 let caller = T::CrossAccountId::from_eth(caller);74 let to = T::CrossAccountId::from_eth(to);75 let amount = amount.try_into().map_err(|_| "amount overflow")?;76 77 78 7980 81 <T as Config>::Currency::transfer(82 caller.as_sub(),83 to.as_sub(),84 amount,85 ExistenceRequirement::KeepAlive,86 )87 .map_err(dispatch_to_evm::<T>)?;88 Ok(true)89 }9091 #[weight(<SelfWeightOf<T>>::transfer())]92 fn transfer_from(93 &mut self,94 caller: Caller,95 from: Address,96 to: Address,97 amount: U256,98 ) -> Result<bool> {99 let caller = T::CrossAccountId::from_eth(caller);100 let from = T::CrossAccountId::from_eth(from);101 let to = T::CrossAccountId::from_eth(to);102 let amount = amount.try_into().map_err(|_| "amount overflow")?;103104 if from != caller {105 return Err("no permission".into());106 }107 108 109 110111 112 113 <T as Config>::Currency::transfer(114 caller.as_sub(),115 to.as_sub(),116 amount,117 ExistenceRequirement::KeepAlive,118 )119 .map_err(dispatch_to_evm::<T>)?;120 Ok(true)121 }122}123124#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]125impl<T: Config> NativeFungibleHandle<T>126where127 T::AccountId: From<[u8; 32]>,128{129 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {130 consume_store_reads(self, 1)?;131 let owner = owner.into_sub_cross_account::<T>()?;132 let balance = <T as Config>::Currency::free_balance(owner.as_sub());133 Ok(balance.into())134 }135136 #[weight(<SelfWeightOf<T>>::transfer())]137 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {138 let caller = T::CrossAccountId::from_eth(caller);139 let to = to.into_sub_cross_account::<T>()?;140 let amount = amount.try_into().map_err(|_| "amount overflow")?;141 142 143 144145 146 <T as Config>::Currency::transfer(147 caller.as_sub(),148 to.as_sub(),149 amount,150 ExistenceRequirement::KeepAlive,151 )152 .map_err(dispatch_to_evm::<T>)?;153 Ok(true)154 }155156 #[weight(<SelfWeightOf<T>>::transfer())]157 fn transfer_from_cross(158 &mut self,159 caller: Caller,160 from: CrossAddress,161 to: CrossAddress,162 amount: U256,163 ) -> Result<bool> {164 let caller = T::CrossAccountId::from_eth(caller);165 let from = from.into_sub_cross_account::<T>()?;166 let to = to.into_sub_cross_account::<T>()?;167 let amount = amount.try_into().map_err(|_| "amount overflow")?;168169 if from != caller {170 return Err("no permission".into());171 }172173 174 175 176177 178 179 <T as Config>::Currency::transfer(180 caller.as_sub(),181 to.as_sub(),182 amount,183 ExistenceRequirement::KeepAlive,184 )185 .map_err(dispatch_to_evm::<T>)?;186 Ok(true)187 }188}189190#[solidity_interface(191 name = UniqueNativeFungible,192 is(ERC20, ERC20UniqueExtensions),193 enum(derive(PreDispatch))194)]195impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}196197generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);198generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);199200impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>201where202 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,203{204 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");205206 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {207 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)208 }209}