1use core::char::{REPLACEMENT_CHARACTER, decode_utf16};2use core::convert::TryInto;3use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};4use up_data_structs::CollectionMode;5use pallet_common::erc::{CommonEvmHandler, PrecompileResult};6use sp_core::{H160, U256};7use sp_std::vec::Vec;8use pallet_common::account::CrossAccountId;9use pallet_evm_coder_substrate::{call, dispatch_to_evm};1011use crate::{12 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,13 weights::WeightInfo,14};1516#[derive(ToLog)]17pub enum ERC20Events {18 Transfer {19 #[indexed]20 from: address,21 #[indexed]22 to: address,23 value: uint256,24 },25 Approval {26 #[indexed]27 owner: address,28 #[indexed]29 spender: address,30 value: uint256,31 },32}3334#[solidity_interface(name = "ERC20", events(ERC20Events))]35impl<T: Config> FungibleHandle<T> {36 fn name(&self) -> Result<string> {37 Ok(decode_utf16(self.name.iter().copied())38 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))39 .collect::<string>())40 }41 fn symbol(&self) -> Result<string> {42 Ok(string::from_utf8_lossy(&self.token_prefix).into())43 }44 fn total_supply(&self) -> Result<uint256> {45 self.consume_store_reads(1)?;46 Ok(<TotalSupply<T>>::get(self.id).into())47 }4849 fn decimals(&self) -> Result<uint8> {50 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {51 *decimals52 } else {53 unreachable!()54 })55 }56 fn balance_of(&self, owner: address) -> Result<uint256> {57 self.consume_store_reads(1)?;58 let owner = T::CrossAccountId::from_eth(owner);59 let balance = <Balance<T>>::get((self.id, owner));60 Ok(balance.into())61 }62 #[weight(<SelfWeightOf<T>>::transfer())]63 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {64 let caller = T::CrossAccountId::from_eth(caller);65 let to = T::CrossAccountId::from_eth(to);66 let amount = amount.try_into().map_err(|_| "amount overflow")?;6768 <Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;69 Ok(true)70 }71 #[weight(<SelfWeightOf<T>>::transfer_from())]72 fn transfer_from(73 &mut self,74 caller: caller,75 from: address,76 to: address,77 amount: uint256,78 ) -> Result<bool> {79 let caller = T::CrossAccountId::from_eth(caller);80 let from = T::CrossAccountId::from_eth(from);81 let to = T::CrossAccountId::from_eth(to);82 let amount = amount.try_into().map_err(|_| "amount overflow")?;8384 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount)85 .map_err(dispatch_to_evm::<T>)?;86 Ok(true)87 }88 #[weight(<SelfWeightOf<T>>::approve())]89 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {90 let caller = T::CrossAccountId::from_eth(caller);91 let spender = T::CrossAccountId::from_eth(spender);92 let amount = amount.try_into().map_err(|_| "amount overflow")?;9394 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)95 .map_err(dispatch_to_evm::<T>)?;96 Ok(true)97 }98 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {99 self.consume_store_reads(1)?;100 let owner = T::CrossAccountId::from_eth(owner);101 let spender = T::CrossAccountId::from_eth(spender);102103 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())104 }105}106107#[solidity_interface(name = "ERC20UniqueExtensions")]108impl<T: Config> FungibleHandle<T> {109 #[weight(<SelfWeightOf<T>>::burn_from())]110 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {111 let caller = T::CrossAccountId::from_eth(caller);112 let from = T::CrossAccountId::from_eth(from);113 let amount = amount.try_into().map_err(|_| "amount overflow")?;114115 <Pallet<T>>::burn_from(self, &caller, &from, amount).map_err(dispatch_to_evm::<T>)?;116 Ok(true)117 }118}119120#[solidity_interface(name = "UniqueFungible", is(ERC20))]121impl<T: Config> FungibleHandle<T> {}122123generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);124generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);125126impl<T: Config> CommonEvmHandler for FungibleHandle<T> {127 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");128129 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {130 call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)131 }132}