git.delta.rocks / unique-network / refs/commits / dc6f0e24d331

difftreelog

source

pallets/fungible/src/erc.rs12.0 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! ERC-20 standart support implementation.1819extern crate alloc;20use core::char::{REPLACEMENT_CHARACTER, decode_utf16};21use core::convert::TryInto;22use evm_coder::AbiCoder;23use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*};24use up_data_structs::CollectionMode;25use pallet_common::{26	CollectionHandle,27	erc::{CommonEvmHandler, PrecompileResult, CollectionCall},28	eth::CrossAddress,29	CommonWeightInfo as _,30};31use sp_std::vec::Vec;32use pallet_evm::{account::CrossAccountId, PrecompileHandle};33use pallet_evm_coder_substrate::{34	call, dispatch_to_evm,35	execution::{PreDispatch, Result},36	frontier_contract,37};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};39use sp_core::{U256, Get};4041use crate::{42	Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply, SelfWeightOf,43	weights::WeightInfo, common::CommonWeights,44};4546frontier_contract! {47	macro_rules! FungibleHandle_result {...}48	impl<T: Config> Contract for FungibleHandle<T> {...}49}5051#[derive(ToLog)]52pub enum ERC20Events {53	Transfer {54		#[indexed]55		from: Address,56		#[indexed]57		to: Address,58		value: U256,59	},60	Approval {61		#[indexed]62		owner: Address,63		#[indexed]64		spender: Address,65		value: U256,66	},67}6869#[derive(AbiCoder, Debug)]70pub struct AmountForAddress {71	to: Address,72	amount: U256,73}7475#[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)]76impl<T: Config> FungibleHandle<T> {77	fn name(&self) -> Result<String> {78		Ok(decode_utf16(self.name.iter().copied())79			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))80			.collect::<String>())81	}82	fn symbol(&self) -> Result<String> {83		Ok(String::from_utf8_lossy(&self.token_prefix).into())84	}85	fn total_supply(&self) -> Result<U256> {86		self.consume_store_reads(1)?;87		Ok(<TotalSupply<T>>::get(self.id).into())88	}8990	fn decimals(&self) -> Result<u8> {91		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {92			*decimals93		} else {94			unreachable!()95		})96	}97	fn balance_of(&self, owner: Address) -> Result<U256> {98		self.consume_store_reads(1)?;99		let owner = T::CrossAccountId::from_eth(owner);100		let balance = <Balance<T>>::get((self.id, owner));101		Ok(balance.into())102	}103	#[weight(<CommonWeights<T>>::transfer())]104	fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {105		let caller = T::CrossAccountId::from_eth(caller);106		let to = T::CrossAccountId::from_eth(to);107		let amount = amount.try_into().map_err(|_| "amount overflow")?;108		let budget = self109			.recorder110			.weight_calls_budget(<StructureWeight<T>>::find_parent());111112		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget)113			.map_err(|e| dispatch_to_evm::<T>(e.error))?;114		Ok(true)115	}116117	#[weight(<CommonWeights<T>>::transfer_from())]118	fn transfer_from(119		&mut self,120		caller: Caller,121		from: Address,122		to: Address,123		amount: U256,124	) -> Result<bool> {125		let caller = T::CrossAccountId::from_eth(caller);126		let from = T::CrossAccountId::from_eth(from);127		let to = T::CrossAccountId::from_eth(to);128		let amount = amount.try_into().map_err(|_| "amount overflow")?;129		let budget = self130			.recorder131			.weight_calls_budget(<StructureWeight<T>>::find_parent());132133		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)134			.map_err(|e| dispatch_to_evm::<T>(e.error))?;135		Ok(true)136	}137	#[weight(<SelfWeightOf<T>>::approve())]138	fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {139		let caller = T::CrossAccountId::from_eth(caller);140		let spender = T::CrossAccountId::from_eth(spender);141		let amount = amount.try_into().map_err(|_| "amount overflow")?;142143		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)144			.map_err(dispatch_to_evm::<T>)?;145		Ok(true)146	}147	fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {148		self.consume_store_reads(1)?;149		let owner = T::CrossAccountId::from_eth(owner);150		let spender = T::CrossAccountId::from_eth(spender);151152		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())153	}154}155156#[solidity_interface(name = ERC20Mintable, enum(derive(PreDispatch)), enum_attr(weight))]157impl<T: Config> FungibleHandle<T> {158	/// Mint tokens for `to` account.159	/// @param to account that will receive minted tokens160	/// @param amount amount of tokens to mint161	#[weight(<SelfWeightOf<T>>::create_item())]162	fn mint(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {163		let caller = T::CrossAccountId::from_eth(caller);164		let to = T::CrossAccountId::from_eth(to);165		let amount = amount.try_into().map_err(|_| "amount overflow")?;166		let budget = self167			.recorder168			.weight_calls_budget(<StructureWeight<T>>::find_parent());169		<Pallet<T>>::create_item(self, &caller, (to, amount), &budget)170			.map_err(dispatch_to_evm::<T>)?;171		Ok(true)172	}173}174175#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]176impl<T: Config> FungibleHandle<T>177where178	T::AccountId: From<[u8; 32]>,179{180	/// @dev Function to check the amount of tokens that an owner allowed to a spender.181	/// @param owner crossAddress The address which owns the funds.182	/// @param spender crossAddress The address which will spend the funds.183	/// @return A uint256 specifying the amount of tokens still available for the spender.184	fn allowance_cross(&self, owner: CrossAddress, spender: CrossAddress) -> Result<U256> {185		let owner = owner.into_sub_cross_account::<T>()?;186		let spender = spender.into_sub_cross_account::<T>()?;187188		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())189	}190191	/// @notice A description for the collection.192	fn description(&self) -> String {193		decode_utf16(self.description.iter().copied())194			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))195			.collect::<String>()196	}197198	#[weight(<SelfWeightOf<T>>::create_item())]199	fn mint_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {200		let caller = T::CrossAccountId::from_eth(caller);201		let to = to.into_sub_cross_account::<T>()?;202		let amount = amount.try_into().map_err(|_| "amount overflow")?;203		let budget = self204			.recorder205			.weight_calls_budget(<StructureWeight<T>>::find_parent());206		<Pallet<T>>::create_item(self, &caller, (to, amount), &budget)207			.map_err(dispatch_to_evm::<T>)?;208		Ok(true)209	}210211	#[weight(<SelfWeightOf<T>>::approve())]212	fn approve_cross(213		&mut self,214		caller: Caller,215		spender: CrossAddress,216		amount: U256,217	) -> Result<bool> {218		let caller = T::CrossAccountId::from_eth(caller);219		let spender = spender.into_sub_cross_account::<T>()?;220		let amount = amount.try_into().map_err(|_| "amount overflow")?;221222		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)223			.map_err(dispatch_to_evm::<T>)?;224		Ok(true)225	}226227	/// Burn tokens from account228	/// @dev Function that burns an `amount` of the tokens of a given account,229	/// deducting from the sender's allowance for said account.230	/// @param from The account whose tokens will be burnt.231	/// @param amount The amount that will be burnt.232	#[solidity(hide)]233	#[weight(<SelfWeightOf<T>>::burn_from())]234	fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {235		let caller = T::CrossAccountId::from_eth(caller);236		let from = T::CrossAccountId::from_eth(from);237		let amount = amount.try_into().map_err(|_| "amount overflow")?;238		let budget = self239			.recorder240			.weight_calls_budget(<StructureWeight<T>>::find_parent());241242		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)243			.map_err(dispatch_to_evm::<T>)?;244		Ok(true)245	}246247	/// Burn tokens from account248	/// @dev Function that burns an `amount` of the tokens of a given account,249	/// deducting from the sender's allowance for said account.250	/// @param from The account whose tokens will be burnt.251	/// @param amount The amount that will be burnt.252	#[weight(<SelfWeightOf<T>>::burn_from())]253	fn burn_from_cross(254		&mut self,255		caller: Caller,256		from: CrossAddress,257		amount: U256,258	) -> Result<bool> {259		let caller = T::CrossAccountId::from_eth(caller);260		let from = from.into_sub_cross_account::<T>()?;261		let amount = amount.try_into().map_err(|_| "amount overflow")?;262		let budget = self263			.recorder264			.weight_calls_budget(<StructureWeight<T>>::find_parent());265266		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)267			.map_err(dispatch_to_evm::<T>)?;268		Ok(true)269	}270271	/// Mint tokens for multiple accounts.272	/// @param amounts array of pairs of account address and amount273	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]274	fn mint_bulk(&mut self, caller: Caller, amounts: Vec<AmountForAddress>) -> Result<bool> {275		let caller = T::CrossAccountId::from_eth(caller);276		let budget = self277			.recorder278			.weight_calls_budget(<StructureWeight<T>>::find_parent());279		let amounts = amounts280			.into_iter()281			.map(|AmountForAddress { to, amount }| {282				Ok((283					T::CrossAccountId::from_eth(to),284					amount.try_into().map_err(|_| "amount overflow")?,285				))286			})287			.collect::<Result<_>>()?;288289		<Pallet<T>>::create_multiple_items(self, &caller, amounts, &budget)290			.map_err(dispatch_to_evm::<T>)?;291		Ok(true)292	}293294	#[weight(<CommonWeights<T>>::transfer())]295	fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {296		let caller = T::CrossAccountId::from_eth(caller);297		let to = to.into_sub_cross_account::<T>()?;298		let amount = amount.try_into().map_err(|_| "amount overflow")?;299		let budget = self300			.recorder301			.weight_calls_budget(<StructureWeight<T>>::find_parent());302303		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;304		Ok(true)305	}306307	#[weight(<CommonWeights<T>>::transfer_from())]308	fn transfer_from_cross(309		&mut self,310		caller: Caller,311		from: CrossAddress,312		to: CrossAddress,313		amount: U256,314	) -> Result<bool> {315		let caller = T::CrossAccountId::from_eth(caller);316		let from = from.into_sub_cross_account::<T>()?;317		let to = to.into_sub_cross_account::<T>()?;318		let amount = amount.try_into().map_err(|_| "amount overflow")?;319		let budget = self320			.recorder321			.weight_calls_budget(<StructureWeight<T>>::find_parent());322323		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)324			.map_err(|e| dispatch_to_evm::<T>(e.error))?;325		Ok(true)326	}327328	/// @notice Returns collection helper contract address329	fn collection_helper_address(&self) -> Result<Address> {330		Ok(T::ContractAddress::get())331	}332333	/// @notice Balance of account334	/// @param owner An cross address for whom to query the balance335	/// @return The number of fingibles owned by `owner`, possibly zero336	fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {337		self.consume_store_reads(1)?;338		let balance = <Balance<T>>::get((self.id, owner.into_sub_cross_account::<T>()?));339		Ok(balance.into())340	}341}342343#[solidity_interface(344	name = UniqueFungible,345	is(346		ERC20,347		ERC20Mintable,348		ERC20UniqueExtensions,349		Collection(via(common_mut returns CollectionHandle<T>)),350	),351	enum(derive(PreDispatch))352)]353impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}354355generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);356generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);357358impl<T: Config> CommonEvmHandler for FungibleHandle<T>359where360	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,361{362	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");363364	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {365		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)366	}367}