git.delta.rocks / unique-network / refs/commits / 008833a7ebae

difftreelog

source

pallets/fungible/src/erc.rs11.9 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).map_err(|_| "transfer error")?;113		Ok(true)114	}115116	#[weight(<CommonWeights<T>>::transfer_from())]117	fn transfer_from(118		&mut self,119		caller: Caller,120		from: Address,121		to: Address,122		amount: U256,123	) -> Result<bool> {124		let caller = T::CrossAccountId::from_eth(caller);125		let from = T::CrossAccountId::from_eth(from);126		let to = T::CrossAccountId::from_eth(to);127		let amount = amount.try_into().map_err(|_| "amount overflow")?;128		let budget = self129			.recorder130			.weight_calls_budget(<StructureWeight<T>>::find_parent());131132		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)133			.map_err(|e| dispatch_to_evm::<T>(e.error))?;134		Ok(true)135	}136	#[weight(<SelfWeightOf<T>>::approve())]137	fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {138		let caller = T::CrossAccountId::from_eth(caller);139		let spender = T::CrossAccountId::from_eth(spender);140		let amount = amount.try_into().map_err(|_| "amount overflow")?;141142		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)143			.map_err(dispatch_to_evm::<T>)?;144		Ok(true)145	}146	fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {147		self.consume_store_reads(1)?;148		let owner = T::CrossAccountId::from_eth(owner);149		let spender = T::CrossAccountId::from_eth(spender);150151		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())152	}153}154155#[solidity_interface(name = ERC20Mintable, enum(derive(PreDispatch)), enum_attr(weight))]156impl<T: Config> FungibleHandle<T> {157	/// Mint tokens for `to` account.158	/// @param to account that will receive minted tokens159	/// @param amount amount of tokens to mint160	#[weight(<SelfWeightOf<T>>::create_item())]161	fn mint(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {162		let caller = T::CrossAccountId::from_eth(caller);163		let to = T::CrossAccountId::from_eth(to);164		let amount = amount.try_into().map_err(|_| "amount overflow")?;165		let budget = self166			.recorder167			.weight_calls_budget(<StructureWeight<T>>::find_parent());168		<Pallet<T>>::create_item(self, &caller, (to, amount), &budget)169			.map_err(dispatch_to_evm::<T>)?;170		Ok(true)171	}172}173174#[solidity_interface(name = ERC20UniqueExtensions, enum(derive(PreDispatch)), enum_attr(weight))]175impl<T: Config> FungibleHandle<T>176where177	T::AccountId: From<[u8; 32]>,178{179	/// @dev Function to check the amount of tokens that an owner allowed to a spender.180	/// @param owner crossAddress The address which owns the funds.181	/// @param spender crossAddress The address which will spend the funds.182	/// @return A uint256 specifying the amount of tokens still available for the spender.183	fn allowance_cross(&self, owner: CrossAddress, spender: CrossAddress) -> Result<U256> {184		let owner = owner.into_sub_cross_account::<T>()?;185		let spender = spender.into_sub_cross_account::<T>()?;186187		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())188	}189190	/// @notice A description for the collection.191	fn description(&self) -> String {192		decode_utf16(self.description.iter().copied())193			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))194			.collect::<String>()195	}196197	#[weight(<SelfWeightOf<T>>::create_item())]198	fn mint_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {199		let caller = T::CrossAccountId::from_eth(caller);200		let to = to.into_sub_cross_account::<T>()?;201		let amount = amount.try_into().map_err(|_| "amount overflow")?;202		let budget = self203			.recorder204			.weight_calls_budget(<StructureWeight<T>>::find_parent());205		<Pallet<T>>::create_item(self, &caller, (to, amount), &budget)206			.map_err(dispatch_to_evm::<T>)?;207		Ok(true)208	}209210	#[weight(<SelfWeightOf<T>>::approve())]211	fn approve_cross(212		&mut self,213		caller: Caller,214		spender: CrossAddress,215		amount: U256,216	) -> Result<bool> {217		let caller = T::CrossAccountId::from_eth(caller);218		let spender = spender.into_sub_cross_account::<T>()?;219		let amount = amount.try_into().map_err(|_| "amount overflow")?;220221		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)222			.map_err(dispatch_to_evm::<T>)?;223		Ok(true)224	}225226	/// Burn tokens from account227	/// @dev Function that burns an `amount` of the tokens of a given account,228	/// deducting from the sender's allowance for said account.229	/// @param from The account whose tokens will be burnt.230	/// @param amount The amount that will be burnt.231	#[solidity(hide)]232	#[weight(<SelfWeightOf<T>>::burn_from())]233	fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {234		let caller = T::CrossAccountId::from_eth(caller);235		let from = T::CrossAccountId::from_eth(from);236		let amount = amount.try_into().map_err(|_| "amount overflow")?;237		let budget = self238			.recorder239			.weight_calls_budget(<StructureWeight<T>>::find_parent());240241		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)242			.map_err(dispatch_to_evm::<T>)?;243		Ok(true)244	}245246	/// Burn tokens from account247	/// @dev Function that burns an `amount` of the tokens of a given account,248	/// deducting from the sender's allowance for said account.249	/// @param from The account whose tokens will be burnt.250	/// @param amount The amount that will be burnt.251	#[weight(<SelfWeightOf<T>>::burn_from())]252	fn burn_from_cross(253		&mut self,254		caller: Caller,255		from: CrossAddress,256		amount: U256,257	) -> Result<bool> {258		let caller = T::CrossAccountId::from_eth(caller);259		let from = from.into_sub_cross_account::<T>()?;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>>::burn_from(self, &caller, &from, amount, &budget)266			.map_err(dispatch_to_evm::<T>)?;267		Ok(true)268	}269270	/// Mint tokens for multiple accounts.271	/// @param amounts array of pairs of account address and amount272	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]273	fn mint_bulk(&mut self, caller: Caller, amounts: Vec<AmountForAddress>) -> Result<bool> {274		let caller = T::CrossAccountId::from_eth(caller);275		let budget = self276			.recorder277			.weight_calls_budget(<StructureWeight<T>>::find_parent());278		let amounts = amounts279			.into_iter()280			.map(|AmountForAddress { to, amount }| {281				Ok((282					T::CrossAccountId::from_eth(to),283					amount.try_into().map_err(|_| "amount overflow")?,284				))285			})286			.collect::<Result<_>>()?;287288		<Pallet<T>>::create_multiple_items(self, &caller, amounts, &budget)289			.map_err(dispatch_to_evm::<T>)?;290		Ok(true)291	}292293	#[weight(<CommonWeights<T>>::transfer())]294	fn transfer_cross(&mut self, caller: Caller, to: CrossAddress, amount: U256) -> Result<bool> {295		let caller = T::CrossAccountId::from_eth(caller);296		let to = to.into_sub_cross_account::<T>()?;297		let amount = amount.try_into().map_err(|_| "amount overflow")?;298		let budget = self299			.recorder300			.weight_calls_budget(<StructureWeight<T>>::find_parent());301302		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;303		Ok(true)304	}305306	#[weight(<CommonWeights<T>>::transfer_from())]307	fn transfer_from_cross(308		&mut self,309		caller: Caller,310		from: CrossAddress,311		to: CrossAddress,312		amount: U256,313	) -> Result<bool> {314		let caller = T::CrossAccountId::from_eth(caller);315		let from = from.into_sub_cross_account::<T>()?;316		let to = to.into_sub_cross_account::<T>()?;317		let amount = amount.try_into().map_err(|_| "amount overflow")?;318		let budget = self319			.recorder320			.weight_calls_budget(<StructureWeight<T>>::find_parent());321322		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)323			.map_err(|e| dispatch_to_evm::<T>(e.error))?;324		Ok(true)325	}326327	/// @notice Returns collection helper contract address328	fn collection_helper_address(&self) -> Result<Address> {329		Ok(T::ContractAddress::get())330	}331332	/// @notice Balance of account333	/// @param owner An cross address for whom to query the balance334	/// @return The number of fingibles owned by `owner`, possibly zero335	fn balance_of_cross(&self, owner: CrossAddress) -> Result<U256> {336		self.consume_store_reads(1)?;337		let balance = <Balance<T>>::get((self.id, owner.into_sub_cross_account::<T>()?));338		Ok(balance.into())339	}340}341342#[solidity_interface(343	name = UniqueFungible,344	is(345		ERC20,346		ERC20Mintable,347		ERC20UniqueExtensions,348		Collection(via(common_mut returns CollectionHandle<T>)),349	),350	enum(derive(PreDispatch))351)]352impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}353354generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);355generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);356357impl<T: Config> CommonEvmHandler for FungibleHandle<T>358where359	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,360{361	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");362363	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {364		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)365	}366}