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

difftreelog

source

pallets/fungible/src/erc.rs9.6 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::{23	abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,24};25use up_data_structs::CollectionMode;26use pallet_common::erc::{CommonEvmHandler, PrecompileResult};27use sp_std::vec::Vec;28use pallet_evm::{account::CrossAccountId, PrecompileHandle};29use pallet_evm_coder_substrate::{call, dispatch_to_evm};30use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};31use pallet_common::{CollectionHandle, erc::CollectionCall};3233use crate::{34	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,35	weights::WeightInfo,36};3738#[derive(ToLog)]39pub enum ERC20Events {40	Transfer {41		#[indexed]42		from: address,43		#[indexed]44		to: address,45		value: uint256,46	},47	Approval {48		#[indexed]49		owner: address,50		#[indexed]51		spender: address,52		value: uint256,53	},54}5556#[solidity_interface(name = ERC20, events(ERC20Events))]57impl<T: Config> FungibleHandle<T> {58	fn name(&self) -> Result<string> {59		Ok(decode_utf16(self.name.iter().copied())60			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))61			.collect::<string>())62	}63	fn symbol(&self) -> Result<string> {64		Ok(string::from_utf8_lossy(&self.token_prefix).into())65	}66	fn total_supply(&self) -> Result<uint256> {67		self.consume_store_reads(1)?;68		Ok(<TotalSupply<T>>::get(self.id).into())69	}7071	fn decimals(&self) -> Result<uint8> {72		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {73			*decimals74		} else {75			unreachable!()76		})77	}78	fn balance_of(&self, owner: address) -> Result<uint256> {79		self.consume_store_reads(1)?;80		let owner = T::CrossAccountId::from_eth(owner);81		let balance = <Balance<T>>::get((self.id, owner));82		Ok(balance.into())83	}84	#[weight(<SelfWeightOf<T>>::transfer())]85	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {86		let caller = T::CrossAccountId::from_eth(caller);87		let to = T::CrossAccountId::from_eth(to);88		let amount = amount.try_into().map_err(|_| "amount overflow")?;89		let budget = self90			.recorder91			.weight_calls_budget(<StructureWeight<T>>::find_parent());9293		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;94		Ok(true)95	}9697	#[weight(<SelfWeightOf<T>>::transfer_from())]98	fn transfer_from(99		&mut self,100		caller: caller,101		from: address,102		to: address,103		amount: uint256,104	) -> Result<bool> {105		let caller = T::CrossAccountId::from_eth(caller);106		let from = T::CrossAccountId::from_eth(from);107		let to = T::CrossAccountId::from_eth(to);108		let amount = amount.try_into().map_err(|_| "amount overflow")?;109		let budget = self110			.recorder111			.weight_calls_budget(<StructureWeight<T>>::find_parent());112113		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)114			.map_err(dispatch_to_evm::<T>)?;115		Ok(true)116	}117	#[weight(<SelfWeightOf<T>>::approve())]118	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {119		let caller = T::CrossAccountId::from_eth(caller);120		let spender = T::CrossAccountId::from_eth(spender);121		let amount = amount.try_into().map_err(|_| "amount overflow")?;122123		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)124			.map_err(dispatch_to_evm::<T>)?;125		Ok(true)126	}127	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {128		self.consume_store_reads(1)?;129		let owner = T::CrossAccountId::from_eth(owner);130		let spender = T::CrossAccountId::from_eth(spender);131132		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())133	}134}135136#[solidity_interface(name = ERC20Mintable)]137impl<T: Config> FungibleHandle<T> {138	/// Mint tokens for `to` account.139	/// @param to account that will receive minted tokens140	/// @param amount amount of tokens to mint141	#[weight(<SelfWeightOf<T>>::create_item())]142	fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {143		let caller = T::CrossAccountId::from_eth(caller);144		let to = T::CrossAccountId::from_eth(to);145		let amount = amount.try_into().map_err(|_| "amount overflow")?;146		let budget = self147			.recorder148			.weight_calls_budget(<StructureWeight<T>>::find_parent());149		<Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)150			.map_err(dispatch_to_evm::<T>)?;151		Ok(true)152	}153}154155#[solidity_interface(name = ERC20UniqueExtensions)]156impl<T: Config> FungibleHandle<T>157where158	T::AccountId: From<[u8; 32]>,159{160	#[weight(<SelfWeightOf<T>>::approve())]161	fn approve_cross(162		&mut self,163		caller: caller,164		spender: EthCrossAccount,165		amount: uint256,166	) -> Result<bool> {167		let caller = T::CrossAccountId::from_eth(caller);168		let spender = spender.into_sub_cross_account::<T>()?;169		let amount = amount.try_into().map_err(|_| "amount overflow")?;170171		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)172			.map_err(dispatch_to_evm::<T>)?;173		Ok(true)174	}175176	/// Burn tokens from account177	/// @dev Function that burns an `amount` of the tokens of a given account,178	/// deducting from the sender's allowance for said account.179	/// @param from The account whose tokens will be burnt.180	/// @param amount The amount that will be burnt.181	#[weight(<SelfWeightOf<T>>::burn_from())]182	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {183		let caller = T::CrossAccountId::from_eth(caller);184		let from = T::CrossAccountId::from_eth(from);185		let amount = amount.try_into().map_err(|_| "amount overflow")?;186		let budget = self187			.recorder188			.weight_calls_budget(<StructureWeight<T>>::find_parent());189190		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)191			.map_err(dispatch_to_evm::<T>)?;192		Ok(true)193	}194195	/// Burn tokens from account196	/// @dev Function that burns an `amount` of the tokens of a given account,197	/// deducting from the sender's allowance for said account.198	/// @param from The account whose tokens will be burnt.199	/// @param amount The amount that will be burnt.200	#[weight(<SelfWeightOf<T>>::burn_from())]201	fn burn_from_cross(202		&mut self,203		caller: caller,204		from: EthCrossAccount,205		amount: uint256,206	) -> Result<bool> {207		let caller = T::CrossAccountId::from_eth(caller);208		let from = from.into_sub_cross_account::<T>()?;209		let amount = amount.try_into().map_err(|_| "amount overflow")?;210		let budget = self211			.recorder212			.weight_calls_budget(<StructureWeight<T>>::find_parent());213214		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)215			.map_err(dispatch_to_evm::<T>)?;216		Ok(true)217	}218219	/// Mint tokens for multiple accounts.220	/// @param amounts array of pairs of account address and amount221	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]222	fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {223		let caller = T::CrossAccountId::from_eth(caller);224		let budget = self225			.recorder226			.weight_calls_budget(<StructureWeight<T>>::find_parent());227		let amounts = amounts228			.into_iter()229			.map(|(to, amount)| {230				Ok((231					T::CrossAccountId::from_eth(to),232					amount.try_into().map_err(|_| "amount overflow")?,233				))234			})235			.collect::<Result<_>>()?;236237		<Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)238			.map_err(dispatch_to_evm::<T>)?;239		Ok(true)240	}241242	#[weight(<SelfWeightOf<T>>::transfer())]243	fn transfer_cross(244		&mut self,245		caller: caller,246		to: EthCrossAccount,247		amount: uint256,248	) -> Result<bool> {249		let caller = T::CrossAccountId::from_eth(caller);250		let to = to.into_sub_cross_account::<T>()?;251		let amount = amount.try_into().map_err(|_| "amount overflow")?;252		let budget = self253			.recorder254			.weight_calls_budget(<StructureWeight<T>>::find_parent());255256		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;257		Ok(true)258	}259260	#[weight(<SelfWeightOf<T>>::transfer_from())]261	fn transfer_from_cross(262		&mut self,263		caller: caller,264		from: EthCrossAccount,265		to: EthCrossAccount,266		amount: uint256,267	) -> Result<bool> {268		let caller = T::CrossAccountId::from_eth(caller);269		let from = from.into_sub_cross_account::<T>()?;270		let to = to.into_sub_cross_account::<T>()?;271		let amount = amount.try_into().map_err(|_| "amount overflow")?;272		let budget = self273			.recorder274			.weight_calls_budget(<StructureWeight<T>>::find_parent());275276		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)277			.map_err(dispatch_to_evm::<T>)?;278		Ok(true)279	}280}281282#[solidity_interface(283	name = UniqueFungible,284	is(285		ERC20,286		ERC20Mintable,287		ERC20UniqueExtensions,288		Collection(via(common_mut returns CollectionHandle<T>)),289	)290)]291impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}292293generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);294generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);295296impl<T: Config> CommonEvmHandler for FungibleHandle<T>297where298	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,299{300	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");301302	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {303		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)304	}305}