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::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};33use pallet_common::{34 CommonWeightInfo,35 erc::{CommonEvmHandler, PrecompileResult},36};37use pallet_evm::{account::CrossAccountId, PrecompileHandle};38use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};39use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};40use sp_std::vec::Vec;41use up_data_structs::{mapping::TokenAddressMapping, TokenId};4243use crate::{44 Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,45 TotalSupply, weights::WeightInfo,46};4748pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);4950#[solidity_interface(name = ERC1633)]51impl<T: Config> RefungibleTokenHandle<T> {52 fn parent_token(&self) -> Result<address> {53 self.consume_store_reads(2)?;54 Ok(*T::CrossTokenAddressMapping::token_to_address(self.id, self.1).as_eth())55 }5657 fn parent_token_id(&self) -> Result<uint256> {58 self.consume_store_reads(2)?;59 Ok(self.1.into())60 }61}6263#[derive(ToLog)]64pub enum ERC20Events {65 66 67 68 69 Transfer {70 #[indexed]71 from: address,72 #[indexed]73 to: address,74 value: uint256,75 },76 77 78 Approval {79 #[indexed]80 owner: address,81 #[indexed]82 spender: address,83 value: uint256,84 },85}868788899091#[solidity_interface(name = ERC20, events(ERC20Events))]92impl<T: Config> RefungibleTokenHandle<T> {93 94 fn name(&self) -> Result<string> {95 Ok(decode_utf16(self.name.iter().copied())96 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))97 .collect::<string>())98 }99100 101 fn symbol(&self) -> Result<string> {102 Ok(string::from_utf8_lossy(&self.token_prefix).into())103 }104105 106 fn total_supply(&self) -> Result<uint256> {107 self.consume_store_reads(1)?;108 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())109 }110111 112 fn decimals(&self) -> Result<uint8> {113 114 Ok(0)115 }116117 118 119 120 fn balance_of(&self, owner: address) -> Result<uint256> {121 self.consume_store_reads(1)?;122 let owner = T::CrossAccountId::from_eth(owner);123 let balance = <Balance<T>>::get((self.id, self.1, owner));124 Ok(balance.into())125 }126127 128 129 130 #[weight(<CommonWeights<T>>::transfer())]131 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {132 let caller = T::CrossAccountId::from_eth(caller);133 let to = T::CrossAccountId::from_eth(to);134 let amount = amount.try_into().map_err(|_| "amount overflow")?;135 let budget = self136 .recorder137 .weight_calls_budget(<StructureWeight<T>>::find_parent());138139 <Pallet<T>>::transfer(self, &caller, &to, self.1, amount, &budget)140 .map_err(dispatch_to_evm::<T>)?;141 Ok(true)142 }143144 145 146 147 148 #[weight(<CommonWeights<T>>::transfer_from())]149 fn transfer_from(150 &mut self,151 caller: caller,152 from: address,153 to: address,154 amount: uint256,155 ) -> Result<bool> {156 let caller = T::CrossAccountId::from_eth(caller);157 let from = T::CrossAccountId::from_eth(from);158 let to = T::CrossAccountId::from_eth(to);159 let amount = amount.try_into().map_err(|_| "amount overflow")?;160 let budget = self161 .recorder162 .weight_calls_budget(<StructureWeight<T>>::find_parent());163164 <Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)165 .map_err(dispatch_to_evm::<T>)?;166 Ok(true)167 }168169 170 171 172 173 174 175 176 #[weight(<SelfWeightOf<T>>::approve())]177 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {178 let caller = T::CrossAccountId::from_eth(caller);179 let spender = T::CrossAccountId::from_eth(spender);180 let amount = amount.try_into().map_err(|_| "amount overflow")?;181182 <Pallet<T>>::set_allowance(self, &caller, &spender, self.1, amount)183 .map_err(dispatch_to_evm::<T>)?;184 Ok(true)185 }186187 188 189 190 191 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {192 self.consume_store_reads(1)?;193 let owner = T::CrossAccountId::from_eth(owner);194 let spender = T::CrossAccountId::from_eth(spender);195196 Ok(<Allowance<T>>::get((self.id, self.1, owner, spender)).into())197 }198}199200#[solidity_interface(name = ERC20UniqueExtensions)]201impl<T: Config> RefungibleTokenHandle<T> {202 203 204 205 206 #[weight(<SelfWeightOf<T>>::burn_from())]207 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {208 let caller = T::CrossAccountId::from_eth(caller);209 let from = T::CrossAccountId::from_eth(from);210 let amount = amount.try_into().map_err(|_| "amount overflow")?;211 let budget = self212 .recorder213 .weight_calls_budget(<StructureWeight<T>>::find_parent());214215 <Pallet<T>>::burn_from(self, &caller, &from, self.1, amount, &budget)216 .map_err(dispatch_to_evm::<T>)?;217 Ok(true)218 }219220 221 222 223 #[weight(<SelfWeightOf<T>>::repartition_item())]224 fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {225 let caller = T::CrossAccountId::from_eth(caller);226 let amount = amount.try_into().map_err(|_| "amount overflow")?;227228 <Pallet<T>>::repartition(self, &caller, self.1, amount).map_err(dispatch_to_evm::<T>)?;229 Ok(true)230 }231}232233impl<T: Config> RefungibleTokenHandle<T> {234 pub fn into_inner(self) -> RefungibleHandle<T> {235 self.0236 }237 pub fn common_mut(&mut self) -> &mut RefungibleHandle<T> {238 &mut self.0239 }240}241242impl<T: Config> WithRecorder<T> for RefungibleTokenHandle<T> {243 fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {244 self.0.recorder()245 }246 fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {247 self.0.into_recorder()248 }249}250251impl<T: Config> Deref for RefungibleTokenHandle<T> {252 type Target = RefungibleHandle<T>;253254 fn deref(&self) -> &Self::Target {255 &self.0256 }257}258259#[solidity_interface(260 name = UniqueRefungibleToken,261 is(ERC20, ERC20UniqueExtensions, ERC1633)262)]263impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}264265generate_stubgen!(gen_impl, UniqueRefungibleTokenCall<()>, true);266generate_stubgen!(gen_iface, UniqueRefungibleTokenCall<()>, false);267268impl<T: Config> CommonEvmHandler for RefungibleTokenHandle<T>269where270 T::AccountId: From<[u8; 32]>,271{272 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungibleToken.raw");273274 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {275 call::<T, UniqueRefungibleTokenCall<T>, _, _>(handle, self)276 }277}