12345678910111213141516171819extern crate alloc;20use alloc::{format, string::ToString};21use core::char::{REPLACEMENT_CHARACTER, decode_utf16};22use core::convert::TryInto;23use evm_coder::{24 ToLog,25 execution::*,26 generate_stubgen, solidity_interface,27 types::*,28 weight,29 custom_signature::{FunctionName, FunctionSignature},30 make_signature,31};32use pallet_common::eth::convert_tuple_to_cross_account;33use up_data_structs::CollectionMode;34use pallet_common::erc::{CommonEvmHandler, PrecompileResult};35use sp_std::vec::Vec;36use pallet_evm::{account::CrossAccountId, PrecompileHandle};37use pallet_evm_coder_substrate::{call, dispatch_to_evm};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};39use pallet_common::{CollectionHandle, erc::CollectionCall};4041use crate::{42 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,43 weights::WeightInfo,44};4546#[derive(ToLog)]47pub enum ERC20Events {48 Transfer {49 #[indexed]50 from: address,51 #[indexed]52 to: address,53 value: uint256,54 },55 Approval {56 #[indexed]57 owner: address,58 #[indexed]59 spender: address,60 value: uint256,61 },62}6364#[solidity_interface(name = ERC20, events(ERC20Events))]65impl<T: Config> FungibleHandle<T> {66 fn name(&self) -> Result<string> {67 Ok(decode_utf16(self.name.iter().copied())68 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))69 .collect::<string>())70 }71 fn symbol(&self) -> Result<string> {72 Ok(string::from_utf8_lossy(&self.token_prefix).into())73 }74 fn total_supply(&self) -> Result<uint256> {75 self.consume_store_reads(1)?;76 Ok(<TotalSupply<T>>::get(self.id).into())77 }7879 fn decimals(&self) -> Result<uint8> {80 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {81 *decimals82 } else {83 unreachable!()84 })85 }86 fn balance_of(&self, owner: address) -> Result<uint256> {87 self.consume_store_reads(1)?;88 let owner = T::CrossAccountId::from_eth(owner);89 let balance = <Balance<T>>::get((self.id, owner));90 Ok(balance.into())91 }92 #[weight(<SelfWeightOf<T>>::transfer())]93 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {94 let caller = T::CrossAccountId::from_eth(caller);95 let to = T::CrossAccountId::from_eth(to);96 let amount = amount.try_into().map_err(|_| "amount overflow")?;97 let budget = self98 .recorder99 .weight_calls_budget(<StructureWeight<T>>::find_parent());100101 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;102 Ok(true)103 }104 #[weight(<SelfWeightOf<T>>::transfer_from())]105 fn transfer_from(106 &mut self,107 caller: caller,108 from: address,109 to: address,110 amount: uint256,111 ) -> Result<bool> {112 let caller = T::CrossAccountId::from_eth(caller);113 let from = T::CrossAccountId::from_eth(from);114 let to = T::CrossAccountId::from_eth(to);115 let amount = amount.try_into().map_err(|_| "amount overflow")?;116 let budget = self117 .recorder118 .weight_calls_budget(<StructureWeight<T>>::find_parent());119120 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)121 .map_err(dispatch_to_evm::<T>)?;122 Ok(true)123 }124 #[weight(<SelfWeightOf<T>>::approve())]125 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {126 let caller = T::CrossAccountId::from_eth(caller);127 let spender = T::CrossAccountId::from_eth(spender);128 let amount = amount.try_into().map_err(|_| "amount overflow")?;129130 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)131 .map_err(dispatch_to_evm::<T>)?;132 Ok(true)133 }134 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {135 self.consume_store_reads(1)?;136 let owner = T::CrossAccountId::from_eth(owner);137 let spender = T::CrossAccountId::from_eth(spender);138139 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())140 }141}142143#[solidity_interface(name = ERC20Mintable)]144impl<T: Config> FungibleHandle<T> {145 146 147 148 #[weight(<SelfWeightOf<T>>::create_item())]149 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {150 let caller = T::CrossAccountId::from_eth(caller);151 let to = T::CrossAccountId::from_eth(to);152 let amount = amount.try_into().map_err(|_| "amount overflow")?;153 let budget = self154 .recorder155 .weight_calls_budget(<StructureWeight<T>>::find_parent());156 <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)157 .map_err(dispatch_to_evm::<T>)?;158 Ok(true)159 }160}161162#[solidity_interface(name = ERC20UniqueExtensions)]163impl<T: Config> FungibleHandle<T>164where165 T::AccountId: From<[u8; 32]>,166{167 #[weight(<SelfWeightOf<T>>::approve())]168 fn approve_cross(169 &mut self,170 caller: caller,171 spender: (address, uint256),172 amount: uint256,173 ) -> Result<bool> {174 let caller = T::CrossAccountId::from_eth(caller);175 let spender = convert_tuple_to_cross_account::<T>(spender)?;176 let amount = amount.try_into().map_err(|_| "amount overflow")?;177178 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)179 .map_err(dispatch_to_evm::<T>)?;180 Ok(true)181 }182183 184 185 186 187 188 #[weight(<SelfWeightOf<T>>::burn_from())]189 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {190 let caller = T::CrossAccountId::from_eth(caller);191 let from = T::CrossAccountId::from_eth(from);192 let amount = amount.try_into().map_err(|_| "amount overflow")?;193 let budget = self194 .recorder195 .weight_calls_budget(<StructureWeight<T>>::find_parent());196197 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)198 .map_err(dispatch_to_evm::<T>)?;199 Ok(true)200 }201202 203 204 205 206 207 #[weight(<SelfWeightOf<T>>::burn_from())]208 fn burn_from_cross(209 &mut self,210 caller: caller,211 from: (address, uint256),212 amount: uint256,213 ) -> Result<bool> {214 let caller = T::CrossAccountId::from_eth(caller);215 let from = convert_tuple_to_cross_account::<T>(from)?;216 let amount = amount.try_into().map_err(|_| "amount overflow")?;217 let budget = self218 .recorder219 .weight_calls_budget(<StructureWeight<T>>::find_parent());220221 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)222 .map_err(dispatch_to_evm::<T>)?;223 Ok(true)224 }225226 227 228 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]229 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {230 let caller = T::CrossAccountId::from_eth(caller);231 let budget = self232 .recorder233 .weight_calls_budget(<StructureWeight<T>>::find_parent());234 let amounts = amounts235 .into_iter()236 .map(|(to, amount)| {237 Ok((238 T::CrossAccountId::from_eth(to),239 amount.try_into().map_err(|_| "amount overflow")?,240 ))241 })242 .collect::<Result<_>>()?;243244 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)245 .map_err(dispatch_to_evm::<T>)?;246 Ok(true)247 }248249 #[weight(<SelfWeightOf<T>>::transfer_from())]250 fn transfer_from_cross(251 &mut self,252 caller: caller,253 from: (address, uint256),254 to: (address, uint256),255 amount: uint256,256 ) -> Result<bool> {257 let caller = T::CrossAccountId::from_eth(caller);258 let from = convert_tuple_to_cross_account::<T>(from)?;259 let to = convert_tuple_to_cross_account::<T>(to)?;260 let amount = amount.try_into().map_err(|_| "amount overflow")?;261 let budget = self262 .recorder263 .weight_calls_budget(<StructureWeight<T>>::find_parent());264265 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)266 .map_err(dispatch_to_evm::<T>)?;267 Ok(true)268 }269}270271#[solidity_interface(272 name = UniqueFungible,273 is(274 ERC20,275 ERC20Mintable,276 ERC20UniqueExtensions,277 Collection(via(common_mut returns CollectionHandle<T>)),278 )279)]280impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}281282generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);283generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);284285impl<T: Config> CommonEvmHandler for FungibleHandle<T>286where287 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,288{289 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");290291 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {292 call::<T, UniqueFungibleCall<T>, _, _>(handle, self)293 }294}