1234567891011121314151617use core::char::{REPLACEMENT_CHARACTER, decode_utf16};18use core::convert::TryInto;19use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};20use up_data_structs::CollectionMode;21use pallet_common::erc::{CommonEvmHandler, PrecompileResult};22use sp_core::{H160, U256};23use sp_std::vec::Vec;24use pallet_evm::account::CrossAccountId;25use pallet_evm_coder_substrate::{call, dispatch_to_evm};2627use crate::{28 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,29 weights::WeightInfo,30};3132#[derive(ToLog)]33pub enum ERC20Events {34 Transfer {35 #[indexed]36 from: address,37 #[indexed]38 to: address,39 value: uint256,40 },41 Approval {42 #[indexed]43 owner: address,44 #[indexed]45 spender: address,46 value: uint256,47 },48}4950#[solidity_interface(name = "ERC20", events(ERC20Events))]51impl<T: Config> FungibleHandle<T> {52 fn name(&self) -> Result<string> {53 Ok(decode_utf16(self.name.iter().copied())54 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))55 .collect::<string>())56 }57 fn symbol(&self) -> Result<string> {58 Ok(string::from_utf8_lossy(&self.token_prefix).into())59 }60 fn total_supply(&self) -> Result<uint256> {61 self.consume_store_reads(1)?;62 Ok(<TotalSupply<T>>::get(self.id).into())63 }6465 fn decimals(&self) -> Result<uint8> {66 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {67 *decimals68 } else {69 unreachable!()70 })71 }72 fn balance_of(&self, owner: address) -> Result<uint256> {73 self.consume_store_reads(1)?;74 let owner = T::CrossAccountId::from_eth(owner);75 let balance = <Balance<T>>::get((self.id, owner));76 Ok(balance.into())77 }78 #[weight(<SelfWeightOf<T>>::transfer())]79 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {80 let caller = T::CrossAccountId::from_eth(caller);81 let to = T::CrossAccountId::from_eth(to);82 let amount = amount.try_into().map_err(|_| "amount overflow")?;8384 <Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;85 Ok(true)86 }87 #[weight(<SelfWeightOf<T>>::transfer_from())]88 fn transfer_from(89 &mut self,90 caller: caller,91 from: address,92 to: address,93 amount: uint256,94 ) -> Result<bool> {95 let caller = T::CrossAccountId::from_eth(caller);96 let from = T::CrossAccountId::from_eth(from);97 let to = T::CrossAccountId::from_eth(to);98 let amount = amount.try_into().map_err(|_| "amount overflow")?;99100 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount)101 .map_err(dispatch_to_evm::<T>)?;102 Ok(true)103 }104 #[weight(<SelfWeightOf<T>>::approve())]105 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {106 let caller = T::CrossAccountId::from_eth(caller);107 let spender = T::CrossAccountId::from_eth(spender);108 let amount = amount.try_into().map_err(|_| "amount overflow")?;109110 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)111 .map_err(dispatch_to_evm::<T>)?;112 Ok(true)113 }114 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {115 self.consume_store_reads(1)?;116 let owner = T::CrossAccountId::from_eth(owner);117 let spender = T::CrossAccountId::from_eth(spender);118119 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())120 }121}122123#[solidity_interface(name = "ERC20UniqueExtensions")]124impl<T: Config> FungibleHandle<T> {125 #[weight(<SelfWeightOf<T>>::burn_from())]126 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {127 let caller = T::CrossAccountId::from_eth(caller);128 let from = T::CrossAccountId::from_eth(from);129 let amount = amount.try_into().map_err(|_| "amount overflow")?;130131 <Pallet<T>>::burn_from(self, &caller, &from, amount).map_err(dispatch_to_evm::<T>)?;132 Ok(true)133 }134}135136#[solidity_interface(name = "UniqueFungible", is(ERC20))]137impl<T: Config> FungibleHandle<T> {}138139generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);140generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);141142impl<T: Config> CommonEvmHandler for FungibleHandle<T> {143 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");144145 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {146 call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)147 }148}