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")?;8485 <Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;86 Ok(true)87 }88 #[weight(<SelfWeightOf<T>>::transfer_from())]89 fn transfer_from(90 &mut self,91 caller: caller,92 from: address,93 to: address,94 amount: uint256,95 ) -> Result<bool> {96 let caller = T::CrossAccountId::from_eth(caller);97 let from = T::CrossAccountId::from_eth(from);98 let to = T::CrossAccountId::from_eth(to);99 let amount = amount.try_into().map_err(|_| "amount overflow")?;100 let budget = self101 .recorder102 .weight_calls_budget(<StructureWeight<T>>::find_parent());103104 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)105 .map_err(dispatch_to_evm::<T>)?;106 Ok(true)107 }108 #[weight(<SelfWeightOf<T>>::approve())]109 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {110 let caller = T::CrossAccountId::from_eth(caller);111 let spender = T::CrossAccountId::from_eth(spender);112 let amount = amount.try_into().map_err(|_| "amount overflow")?;113114 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)115 .map_err(dispatch_to_evm::<T>)?;116 Ok(true)117 }118 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {119 self.consume_store_reads(1)?;120 let owner = T::CrossAccountId::from_eth(owner);121 let spender = T::CrossAccountId::from_eth(spender);122123 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())124 }125}126127#[solidity_interface(name = "ERC20UniqueExtensions")]128impl<T: Config> FungibleHandle<T> {129 #[weight(<SelfWeightOf<T>>::burn_from())]130 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {131 let caller = T::CrossAccountId::from_eth(caller);132 let from = T::CrossAccountId::from_eth(from);133 let amount = amount.try_into().map_err(|_| "amount overflow")?;134 let budget = self135 .recorder136 .weight_calls_budget(<StructureWeight<T>>::find_parent());137138 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)139 .map_err(dispatch_to_evm::<T>)?;140 Ok(true)141 }142}143144#[solidity_interface(name = "UniqueFungible", is(ERC20))]145impl<T: Config> FungibleHandle<T> {}146147generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);148generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);149150impl<T: Config> CommonEvmHandler for FungibleHandle<T> {151 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");152153 fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {154 call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)155 }156}