git.delta.rocks / unique-network / refs/commits / 424362fb52a4

difftreelog

source

pallets/fungible/src/erc.rs9.2 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.1819use core::char::{REPLACEMENT_CHARACTER, decode_utf16};20use core::convert::TryInto;21use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};22use pallet_common::eth::convert_tuple_to_cross_account;23use up_data_structs::CollectionMode;24use pallet_common::erc::{CommonEvmHandler, PrecompileResult};25use sp_std::vec::Vec;26use pallet_evm::{account::CrossAccountId, PrecompileHandle};27use pallet_evm_coder_substrate::{call, dispatch_to_evm};28use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};29use pallet_common::{CollectionHandle, erc::CollectionCall};3031use crate::{32	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,33	weights::WeightInfo,34};3536#[derive(ToLog)]37pub enum ERC20Events {38	Transfer {39		#[indexed]40		from: address,41		#[indexed]42		to: address,43		value: uint256,44	},45	Approval {46		#[indexed]47		owner: address,48		#[indexed]49		spender: address,50		value: uint256,51	},52}5354#[solidity_interface(name = ERC20, events(ERC20Events))]55impl<T: Config> FungibleHandle<T> {56	fn name(&self) -> Result<string> {57		Ok(decode_utf16(self.name.iter().copied())58			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))59			.collect::<string>())60	}61	fn symbol(&self) -> Result<string> {62		Ok(string::from_utf8_lossy(&self.token_prefix).into())63	}64	fn total_supply(&self) -> Result<uint256> {65		self.consume_store_reads(1)?;66		Ok(<TotalSupply<T>>::get(self.id).into())67	}6869	fn decimals(&self) -> Result<uint8> {70		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {71			*decimals72		} else {73			unreachable!()74		})75	}76	fn balance_of(&self, owner: address) -> Result<uint256> {77		self.consume_store_reads(1)?;78		let owner = T::CrossAccountId::from_eth(owner);79		let balance = <Balance<T>>::get((self.id, owner));80		Ok(balance.into())81	}82	#[weight(<SelfWeightOf<T>>::transfer())]83	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {84		let caller = T::CrossAccountId::from_eth(caller);85		let to = T::CrossAccountId::from_eth(to);86		let amount = amount.try_into().map_err(|_| "amount overflow")?;87		let budget = self88			.recorder89			.weight_calls_budget(<StructureWeight<T>>::find_parent());9091		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;92		Ok(true)93	}94	#[weight(<SelfWeightOf<T>>::transfer_from())]95	fn transfer_from(96		&mut self,97		caller: caller,98		from: address,99		to: address,100		amount: uint256,101	) -> Result<bool> {102		let caller = T::CrossAccountId::from_eth(caller);103		let from = T::CrossAccountId::from_eth(from);104		let to = T::CrossAccountId::from_eth(to);105		let amount = amount.try_into().map_err(|_| "amount overflow")?;106		let budget = self107			.recorder108			.weight_calls_budget(<StructureWeight<T>>::find_parent());109110		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)111			.map_err(dispatch_to_evm::<T>)?;112		Ok(true)113	}114	#[weight(<SelfWeightOf<T>>::approve())]115	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {116		let caller = T::CrossAccountId::from_eth(caller);117		let spender = T::CrossAccountId::from_eth(spender);118		let amount = amount.try_into().map_err(|_| "amount overflow")?;119120		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)121			.map_err(dispatch_to_evm::<T>)?;122		Ok(true)123	}124	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {125		self.consume_store_reads(1)?;126		let owner = T::CrossAccountId::from_eth(owner);127		let spender = T::CrossAccountId::from_eth(spender);128129		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())130	}131}132133#[solidity_interface(name = ERC20Mintable)]134impl<T: Config> FungibleHandle<T> {135	/// Mint tokens for `to` account.136	/// @param to account that will receive minted tokens137	/// @param amount amount of tokens to mint138	#[weight(<SelfWeightOf<T>>::create_item())]139	fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {140		let caller = T::CrossAccountId::from_eth(caller);141		let to = T::CrossAccountId::from_eth(to);142		let amount = amount.try_into().map_err(|_| "amount overflow")?;143		let budget = self144			.recorder145			.weight_calls_budget(<StructureWeight<T>>::find_parent());146		<Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)147			.map_err(dispatch_to_evm::<T>)?;148		Ok(true)149	}150}151152#[solidity_interface(name = ERC20UniqueExtensions)]153impl<T: Config> FungibleHandle<T>154where155	T::AccountId: From<[u8; 32]>,156{157	#[weight(<SelfWeightOf<T>>::approve())]158	fn approve_cross(159		&mut self,160		caller: caller,161		spender: (address, uint256),162		amount: uint256,163	) -> Result<bool> {164		let caller = T::CrossAccountId::from_eth(caller);165		let spender = convert_tuple_to_cross_account::<T>(spender)?;166		let amount = amount.try_into().map_err(|_| "amount overflow")?;167168		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)169			.map_err(dispatch_to_evm::<T>)?;170		Ok(true)171	}172173	/// Burn tokens from account174	/// @dev Function that burns an `amount` of the tokens of a given account,175	/// deducting from the sender's allowance for said account.176	/// @param from The account whose tokens will be burnt.177	/// @param amount The amount that will be burnt.178	#[weight(<SelfWeightOf<T>>::burn_from())]179	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {180		let caller = T::CrossAccountId::from_eth(caller);181		let from = T::CrossAccountId::from_eth(from);182		let amount = amount.try_into().map_err(|_| "amount overflow")?;183		let budget = self184			.recorder185			.weight_calls_budget(<StructureWeight<T>>::find_parent());186187		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)188			.map_err(dispatch_to_evm::<T>)?;189		Ok(true)190	}191192	/// Burn tokens from account193	/// @dev Function that burns an `amount` of the tokens of a given account,194	/// deducting from the sender's allowance for said account.195	/// @param from The account whose tokens will be burnt.196	/// @param amount The amount that will be burnt.197	#[weight(<SelfWeightOf<T>>::burn_from())]198	fn burn_from_cross(199		&mut self,200		caller: caller,201		from: (address, uint256),202		amount: uint256,203	) -> Result<bool> {204		let caller = T::CrossAccountId::from_eth(caller);205		let from = convert_tuple_to_cross_account::<T>(from)?;206		let amount = amount.try_into().map_err(|_| "amount overflow")?;207		let budget = self208			.recorder209			.weight_calls_budget(<StructureWeight<T>>::find_parent());210211		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)212			.map_err(dispatch_to_evm::<T>)?;213		Ok(true)214	}215216	/// Mint tokens for multiple accounts.217	/// @param amounts array of pairs of account address and amount218	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]219	fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {220		let caller = T::CrossAccountId::from_eth(caller);221		let budget = self222			.recorder223			.weight_calls_budget(<StructureWeight<T>>::find_parent());224		let amounts = amounts225			.into_iter()226			.map(|(to, amount)| {227				Ok((228					T::CrossAccountId::from_eth(to),229					amount.try_into().map_err(|_| "amount overflow")?,230				))231			})232			.collect::<Result<_>>()?;233234		<Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)235			.map_err(dispatch_to_evm::<T>)?;236		Ok(true)237	}238239	#[weight(<SelfWeightOf<T>>::transfer_from())]240	fn transfer_from_cross(241		&mut self,242		caller: caller,243		from: (address, uint256),244		to: (address, uint256),245		amount: uint256,246	) -> Result<bool> {247		let caller = T::CrossAccountId::from_eth(caller);248		let from = convert_tuple_to_cross_account::<T>(from)?;249		let to = convert_tuple_to_cross_account::<T>(to)?;250		let amount = amount.try_into().map_err(|_| "amount overflow")?;251		let budget = self252			.recorder253			.weight_calls_budget(<StructureWeight<T>>::find_parent());254255		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)256			.map_err(dispatch_to_evm::<T>)?;257		Ok(true)258	}259}260261#[solidity_interface(262	name = UniqueFungible,263	is(264		ERC20,265		ERC20Mintable,266		ERC20UniqueExtensions,267		Collection(via(common_mut returns CollectionHandle<T>)),268	)269)]270impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}271272generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);273generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);274275impl<T: Config> CommonEvmHandler for FungibleHandle<T>276where277	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,278{279	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");280281	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {282		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)283	}284}