12345678910111213141516171819202122extern crate alloc;2324#[cfg(not(feature = "std"))]25use alloc::format;2627use core::{28 char::{REPLACEMENT_CHARACTER, decode_utf16},29 convert::TryInto,30 ops::Deref,31};32use evm_coder::{33 ToLog,34 execution::*,35 generate_stubgen, solidity_interface,36 types::*,37 weight,38 custom_signature::{SignatureUnit, FunctionSignature, SignaturePreferences},39 make_signature,40};41use pallet_common::{42 CommonWeightInfo,43 erc::{CommonEvmHandler, PrecompileResult},44 eth::collection_id_to_address,45};46use pallet_evm::{account::CrossAccountId, PrecompileHandle};47use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};48use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};49use sp_std::vec::Vec;50use up_data_structs::TokenId;5152use crate::{53 Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,54 TotalSupply, weights::WeightInfo,55};5657pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);5859#[solidity_interface(name = ERC1633)]60impl<T: Config> RefungibleTokenHandle<T> {61 fn parent_token(&self) -> Result<address> {62 Ok(collection_id_to_address(self.id))63 }6465 fn parent_token_id(&self) -> Result<uint256> {66 Ok(self.1.into())67 }68}6970#[derive(ToLog)]71pub enum ERC20Events {72 73 74 75 76 Transfer {77 #[indexed]78 from: address,79 #[indexed]80 to: address,81 value: uint256,82 },83 84 85 Approval {86 #[indexed]87 owner: address,88 #[indexed]89 spender: address,90 value: uint256,91 },92}939495969798#[solidity_interface(name = ERC20, events(ERC20Events))]99impl<T: Config> RefungibleTokenHandle<T> {100 101 fn name(&self) -> Result<string> {102 Ok(decode_utf16(self.name.iter().copied())103 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))104 .collect::<string>())105 }106107 108 fn symbol(&self) -> Result<string> {109 Ok(string::from_utf8_lossy(&self.token_prefix).into())110 }111112 113 fn total_supply(&self) -> Result<uint256> {114 self.consume_store_reads(1)?;115 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())116 }117118 119 fn decimals(&self) -> Result<uint8> {120 121 Ok(0)122 }123124 125 126 127 fn balance_of(&self, owner: address) -> Result<uint256> {128 self.consume_store_reads(1)?;129 let owner = T::CrossAccountId::from_eth(owner);130 let balance = <Balance<T>>::get((self.id, self.1, owner));131 Ok(balance.into())132 }133134 135 136 137 #[weight(<CommonWeights<T>>::transfer())]138 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {139 let caller = T::CrossAccountId::from_eth(caller);140 let to = T::CrossAccountId::from_eth(to);141 let amount = amount.try_into().map_err(|_| "amount overflow")?;142 let budget = self143 .recorder144 .weight_calls_budget(<StructureWeight<T>>::find_parent());145146 <Pallet<T>>::transfer(self, &caller, &to, self.1, amount, &budget)147 .map_err(dispatch_to_evm::<T>)?;148 Ok(true)149 }150151 152 153 154 155 #[weight(<CommonWeights<T>>::transfer_from())]156 fn transfer_from(157 &mut self,158 caller: caller,159 from: address,160 to: address,161 amount: uint256,162 ) -> Result<bool> {163 let caller = T::CrossAccountId::from_eth(caller);164 let from = T::CrossAccountId::from_eth(from);165 let to = T::CrossAccountId::from_eth(to);166 let amount = amount.try_into().map_err(|_| "amount overflow")?;167 let budget = self168 .recorder169 .weight_calls_budget(<StructureWeight<T>>::find_parent());170171 <Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)172 .map_err(dispatch_to_evm::<T>)?;173 Ok(true)174 }175176 177 178 179 180 181 182 183 #[weight(<SelfWeightOf<T>>::approve())]184 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {185 let caller = T::CrossAccountId::from_eth(caller);186 let spender = T::CrossAccountId::from_eth(spender);187 let amount = amount.try_into().map_err(|_| "amount overflow")?;188189 <Pallet<T>>::set_allowance(self, &caller, &spender, self.1, amount)190 .map_err(dispatch_to_evm::<T>)?;191 Ok(true)192 }193194 195 196 197 198 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {199 self.consume_store_reads(1)?;200 let owner = T::CrossAccountId::from_eth(owner);201 let spender = T::CrossAccountId::from_eth(spender);202203 Ok(<Allowance<T>>::get((self.id, self.1, owner, spender)).into())204 }205}206207#[solidity_interface(name = ERC20UniqueExtensions)]208impl<T: Config> RefungibleTokenHandle<T> {209 210 211 212 213 #[weight(<SelfWeightOf<T>>::burn_from())]214 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {215 let caller = T::CrossAccountId::from_eth(caller);216 let from = T::CrossAccountId::from_eth(from);217 let amount = amount.try_into().map_err(|_| "amount overflow")?;218 let budget = self219 .recorder220 .weight_calls_budget(<StructureWeight<T>>::find_parent());221222 <Pallet<T>>::burn_from(self, &caller, &from, self.1, amount, &budget)223 .map_err(dispatch_to_evm::<T>)?;224 Ok(true)225 }226227 228 229 230 #[weight(<SelfWeightOf<T>>::repartition_item())]231 fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {232 let caller = T::CrossAccountId::from_eth(caller);233 let amount = amount.try_into().map_err(|_| "amount overflow")?;234235 <Pallet<T>>::repartition(self, &caller, self.1, amount).map_err(dispatch_to_evm::<T>)?;236 Ok(true)237 }238}239240impl<T: Config> RefungibleTokenHandle<T> {241 pub fn into_inner(self) -> RefungibleHandle<T> {242 self.0243 }244 pub fn common_mut(&mut self) -> &mut RefungibleHandle<T> {245 &mut self.0246 }247}248249impl<T: Config> WithRecorder<T> for RefungibleTokenHandle<T> {250 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {251 self.0.recorder()252 }253 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {254 self.0.into_recorder()255 }256}257258impl<T: Config> Deref for RefungibleTokenHandle<T> {259 type Target = RefungibleHandle<T>;260261 fn deref(&self) -> &Self::Target {262 &self.0263 }264}265266#[solidity_interface(267 name = UniqueRefungibleToken,268 is(ERC20, ERC20UniqueExtensions, ERC1633)269)]270impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}271272generate_stubgen!(gen_impl, UniqueRefungibleTokenCall<()>, true);273generate_stubgen!(gen_iface, UniqueRefungibleTokenCall<()>, false);274275impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T>276where277 T::AccountId: From<[u8; 32]>,278{279 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");280281 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {282 call::<T, UniqueRefungibleTokenCall<T>, _, _>(handle, self)283 }284}