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,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}3233#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]34impl<T: Config> NativeFungibleHandle<T> {35 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {36 Ok(U256::zero())37 }3839 40 fn approve(&mut self, _caller: Caller, _spender: Address, _amount: U256) -> Result<bool> {41 42 Err("Approve not supported".into())43 }4445 fn balance_of(&self, owner: Address) -> Result<U256> {46 47 let owner = T::CrossAccountId::from_eth(owner);48 let balance = <T as Config>::Currency::free_balance(owner.as_sub());49 Ok(balance.into())50 }5152 fn decimals(&self) -> Result<u8> {53 Ok(T::Decimals::get())54 }5556 fn name(&self) -> Result<String> {57 Ok(T::Name::get())58 }5960 fn symbol(&self) -> Result<String> {61 Ok(T::Symbol::get())62 }6364 fn total_supply(&self) -> Result<U256> {65 66 let total = <T as Config>::Currency::total_issuance();67 Ok(total.into())68 }6970 #[weight(<SelfWeightOf<T>>::transfer())]71 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {72 let caller = T::CrossAccountId::from_eth(caller);73 let to = T::CrossAccountId::from_eth(to);74 let amount = amount.try_into().map_err(|_| "amount overflow")?;75 76 77 7879 80 <T as Config>::Currency::transfer(81 caller.as_sub(),82 to.as_sub(),83 amount,84 ExistenceRequirement::KeepAlive,85 )86 .map_err(dispatch_to_evm::<T>)?;87 Ok(true)88 }8990 #[weight(<SelfWeightOf<T>>::transfer())]91 fn transfer_from(92 &mut self,93 caller: Caller,94 from: Address,95 to: Address,96 amount: U256,97 ) -> Result<bool> {98 let caller = T::CrossAccountId::from_eth(caller);99 let from = T::CrossAccountId::from_eth(from);100 let to = T::CrossAccountId::from_eth(to);101 let amount = amount.try_into().map_err(|_| "amount overflow")?;102103 if from != caller {104 return Err("no permission".into());105 }106 107 108 109110 111 112 <T as Config>::Currency::transfer(113 caller.as_sub(),114 to.as_sub(),115 amount,116 ExistenceRequirement::KeepAlive,117 )118 .map_err(dispatch_to_evm::<T>)?;119 Ok(true)120 }121}122123#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]124impl<T: Config> NativeFungibleHandle<T>125where126 T::AccountId: From<[u8; 32]>,127{128 fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {129 130 let owner = owner.into_sub_cross_account::<T>()?;131 let balance = <T as Config>::Currency::free_balance(owner.as_sub());132 Ok(balance.into())133 }134135 #[weight(<SelfWeightOf<T>>::transfer())]136 fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {137 let caller = T::CrossAccountId::from_eth(caller);138 let to = to.into_sub_cross_account::<T>()?;139 let amount = amount.try_into().map_err(|_| "amount overflow")?;140 141 142 143144 145 <T as Config>::Currency::transfer(146 caller.as_sub(),147 to.as_sub(),148 amount,149 ExistenceRequirement::KeepAlive,150 )151 .map_err(dispatch_to_evm::<T>)?;152 Ok(true)153 }154155 #[weight(<SelfWeightOf<T>>::transfer())]156 fn transfer_from_cross(157 &mut self,158 caller: Caller,159 from: CrossAddress,160 to: CrossAddress,161 amount: U256,162 ) -> Result<bool> {163 let caller = T::CrossAccountId::from_eth(caller);164 let from = from.into_sub_cross_account::<T>()?;165 let to = to.into_sub_cross_account::<T>()?;166 let amount = amount.try_into().map_err(|_| "amount overflow")?;167168 if from != caller {169 return Err("no permission".into());170 }171172 173 174 175176 177 178 <T as Config>::Currency::transfer(179 caller.as_sub(),180 to.as_sub(),181 amount,182 ExistenceRequirement::KeepAlive,183 )184 .map_err(dispatch_to_evm::<T>)?;185 Ok(true)186 }187}188189#[solidity_interface(190 name = UniqueNativeFungible,191 is(ERC20, ERC20UniqueExtensions),192 enum(derive(PreDispatch))193)]194impl<T: Config> NativeFungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}195196generate_stubgen!(gen_impl, UniqueNativeFungibleCall<()>, true);197generate_stubgen!(gen_iface, UniqueNativeFungibleCall<()>, false);198199impl<T: Config> CommonEvmHandler for NativeFungibleHandle<T>200where201 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,202{203 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNativeFungible.raw");204205 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {206 call::<T, UniqueNativeFungibleCall<T>, _, _>(handle, self)207 }208}