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};26use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};2728use crate::{29 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,30 weights::WeightInfo,31};3233#[derive(ToLog)]34pub enum ERC20Events {35 Transfer {36 #[indexed]37 from: address,38 #[indexed]39 to: address,40 value: uint256,41 },42 Approval {43 #[indexed]44 owner: address,45 #[indexed]46 spender: address,47 value: uint256,48 },49}5051#[solidity_interface(name = "ERC20", events(ERC20Events))]52impl<T: Config> FungibleHandle<T> {53 fn name(&self) -> Result<string> {54 Ok(decode_utf16(self.name.iter().copied())55 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))56 .collect::<string>())57 }58 fn symbol(&self) -> Result<string> {59 Ok(string::from_utf8_lossy(&self.token_prefix).into())60 }61 fn total_supply(&self) -> Result<uint256> {62 self.consume_store_reads(1)?;63 Ok(<TotalSupply<T>>::get(self.id).into())64 }6566 fn decimals(&self) -> Result<uint8> {67 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {68 *decimals69 } else {70 unreachable!()71 })72 }73 fn balance_of(&self, owner: address) -> Result<uint256> {74 self.consume_store_reads(1)?;75 let owner = T::CrossAccountId::from_eth(owner);76 let balance = <Balance<T>>::get((self.id, owner));77 Ok(balance.into())78 }79 #[weight(<SelfWeightOf<T>>::transfer())]80 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {81 let caller = T::CrossAccountId::from_eth(caller);82 let to = T::CrossAccountId::from_eth(to);83 let amount = amount.try_into().map_err(|_| "amount overflow")?;84 let budget = self85 .recorder86 .weight_calls_budget(<StructureWeight<T>>::find_parent());8788 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;89 Ok(true)90 }91 #[weight(<SelfWeightOf<T>>::transfer_from())]92 fn transfer_from(93 &mut self,94 caller: caller,95 from: address,96 to: address,97 amount: uint256,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")?;103 let budget = self104 .recorder105 .weight_calls_budget(<StructureWeight<T>>::find_parent());106107 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)108 .map_err(dispatch_to_evm::<T>)?;109 Ok(true)110 }111 #[weight(<SelfWeightOf<T>>::approve())]112 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {113 let caller = T::CrossAccountId::from_eth(caller);114 let spender = T::CrossAccountId::from_eth(spender);115 let amount = amount.try_into().map_err(|_| "amount overflow")?;116117 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)118 .map_err(dispatch_to_evm::<T>)?;119 Ok(true)120 }121 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {122 self.consume_store_reads(1)?;123 let owner = T::CrossAccountId::from_eth(owner);124 let spender = T::CrossAccountId::from_eth(spender);125126 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())127 }128}129130#[solidity_interface(name = "ERC20UniqueExtensions")]131impl<T: Config> FungibleHandle<T> {132 #[weight(<SelfWeightOf<T>>::burn_from())]133 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {134 let caller = T::CrossAccountId::from_eth(caller);135 let from = T::CrossAccountId::from_eth(from);136 let amount = amount.try_into().map_err(|_| "amount overflow")?;137 let budget = self138 .recorder139 .weight_calls_budget(<StructureWeight<T>>::find_parent());140141 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)142 .map_err(dispatch_to_evm::<T>)?;143 Ok(true)144 }145}146147#[solidity_interface(name = "UniqueFungible", is(ERC20))]148impl<T: Config> FungibleHandle<T> {}149150generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);151generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);152153impl<T: Config> CommonEvmHandler for FungibleHandle<T> {154 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");155156 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {157 call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)158 }159}