git.delta.rocks / unique-network / refs/commits / 15e4512df81d

difftreelog

source

pallets/fungible/src/erc.rs9.3 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 alloc::{format, string::ToString};21use core::char::{REPLACEMENT_CHARACTER, decode_utf16};22use core::convert::TryInto;23use evm_coder::{24	ToLog,25	execution::*,26	generate_stubgen, solidity_interface,27	types::*,28	weight,29	custom_signature::{FunctionName, FunctionSignature},30	make_signature,31};32use pallet_common::eth::convert_tuple_to_cross_account;33use up_data_structs::CollectionMode;34use pallet_common::erc::{CommonEvmHandler, PrecompileResult};35use sp_std::vec::Vec;36use pallet_evm::{account::CrossAccountId, PrecompileHandle};37use pallet_evm_coder_substrate::{call, dispatch_to_evm};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};39use pallet_common::{CollectionHandle, erc::CollectionCall};4041use crate::{42	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,43	weights::WeightInfo,44};4546#[derive(ToLog)]47pub enum ERC20Events {48	Transfer {49		#[indexed]50		from: address,51		#[indexed]52		to: address,53		value: uint256,54	},55	Approval {56		#[indexed]57		owner: address,58		#[indexed]59		spender: address,60		value: uint256,61	},62}6364#[solidity_interface(name = ERC20, events(ERC20Events))]65impl<T: Config> FungibleHandle<T> {66	fn name(&self) -> Result<string> {67		Ok(decode_utf16(self.name.iter().copied())68			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))69			.collect::<string>())70	}71	fn symbol(&self) -> Result<string> {72		Ok(string::from_utf8_lossy(&self.token_prefix).into())73	}74	fn total_supply(&self) -> Result<uint256> {75		self.consume_store_reads(1)?;76		Ok(<TotalSupply<T>>::get(self.id).into())77	}7879	fn decimals(&self) -> Result<uint8> {80		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {81			*decimals82		} else {83			unreachable!()84		})85	}86	fn balance_of(&self, owner: address) -> Result<uint256> {87		self.consume_store_reads(1)?;88		let owner = T::CrossAccountId::from_eth(owner);89		let balance = <Balance<T>>::get((self.id, owner));90		Ok(balance.into())91	}92	#[weight(<SelfWeightOf<T>>::transfer())]93	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {94		let caller = T::CrossAccountId::from_eth(caller);95		let to = T::CrossAccountId::from_eth(to);96		let amount = amount.try_into().map_err(|_| "amount overflow")?;97		let budget = self98			.recorder99			.weight_calls_budget(<StructureWeight<T>>::find_parent());100101		<Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;102		Ok(true)103	}104	#[weight(<SelfWeightOf<T>>::transfer_from())]105	fn transfer_from(106		&mut self,107		caller: caller,108		from: address,109		to: address,110		amount: uint256,111	) -> Result<bool> {112		let caller = T::CrossAccountId::from_eth(caller);113		let from = T::CrossAccountId::from_eth(from);114		let to = T::CrossAccountId::from_eth(to);115		let amount = amount.try_into().map_err(|_| "amount overflow")?;116		let budget = self117			.recorder118			.weight_calls_budget(<StructureWeight<T>>::find_parent());119120		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)121			.map_err(dispatch_to_evm::<T>)?;122		Ok(true)123	}124	#[weight(<SelfWeightOf<T>>::approve())]125	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {126		let caller = T::CrossAccountId::from_eth(caller);127		let spender = T::CrossAccountId::from_eth(spender);128		let amount = amount.try_into().map_err(|_| "amount overflow")?;129130		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)131			.map_err(dispatch_to_evm::<T>)?;132		Ok(true)133	}134	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {135		self.consume_store_reads(1)?;136		let owner = T::CrossAccountId::from_eth(owner);137		let spender = T::CrossAccountId::from_eth(spender);138139		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())140	}141}142143#[solidity_interface(name = ERC20Mintable)]144impl<T: Config> FungibleHandle<T> {145	/// Mint tokens for `to` account.146	/// @param to account that will receive minted tokens147	/// @param amount amount of tokens to mint148	#[weight(<SelfWeightOf<T>>::create_item())]149	fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {150		let caller = T::CrossAccountId::from_eth(caller);151		let to = T::CrossAccountId::from_eth(to);152		let amount = amount.try_into().map_err(|_| "amount overflow")?;153		let budget = self154			.recorder155			.weight_calls_budget(<StructureWeight<T>>::find_parent());156		<Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)157			.map_err(dispatch_to_evm::<T>)?;158		Ok(true)159	}160}161162#[solidity_interface(name = ERC20UniqueExtensions)]163impl<T: Config> FungibleHandle<T>164where165	T::AccountId: From<[u8; 32]>,166{167	#[weight(<SelfWeightOf<T>>::approve())]168	fn approve_cross(169		&mut self,170		caller: caller,171		spender: (address, uint256),172		amount: uint256,173	) -> Result<bool> {174		let caller = T::CrossAccountId::from_eth(caller);175		let spender = convert_tuple_to_cross_account::<T>(spender)?;176		let amount = amount.try_into().map_err(|_| "amount overflow")?;177178		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)179			.map_err(dispatch_to_evm::<T>)?;180		Ok(true)181	}182183	/// Burn tokens from account184	/// @dev Function that burns an `amount` of the tokens of a given account,185	/// deducting from the sender's allowance for said account.186	/// @param from The account whose tokens will be burnt.187	/// @param amount The amount that will be burnt.188	#[weight(<SelfWeightOf<T>>::burn_from())]189	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {190		let caller = T::CrossAccountId::from_eth(caller);191		let from = T::CrossAccountId::from_eth(from);192		let amount = amount.try_into().map_err(|_| "amount overflow")?;193		let budget = self194			.recorder195			.weight_calls_budget(<StructureWeight<T>>::find_parent());196197		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)198			.map_err(dispatch_to_evm::<T>)?;199		Ok(true)200	}201202	/// Burn tokens from account203	/// @dev Function that burns an `amount` of the tokens of a given account,204	/// deducting from the sender's allowance for said account.205	/// @param from The account whose tokens will be burnt.206	/// @param amount The amount that will be burnt.207	#[weight(<SelfWeightOf<T>>::burn_from())]208	fn burn_from_cross(209		&mut self,210		caller: caller,211		from: (address, uint256),212		amount: uint256,213	) -> Result<bool> {214		let caller = T::CrossAccountId::from_eth(caller);215		let from = convert_tuple_to_cross_account::<T>(from)?;216		let amount = amount.try_into().map_err(|_| "amount overflow")?;217		let budget = self218			.recorder219			.weight_calls_budget(<StructureWeight<T>>::find_parent());220221		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)222			.map_err(dispatch_to_evm::<T>)?;223		Ok(true)224	}225226	/// Mint tokens for multiple accounts.227	/// @param amounts array of pairs of account address and amount228	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]229	fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {230		let caller = T::CrossAccountId::from_eth(caller);231		let budget = self232			.recorder233			.weight_calls_budget(<StructureWeight<T>>::find_parent());234		let amounts = amounts235			.into_iter()236			.map(|(to, amount)| {237				Ok((238					T::CrossAccountId::from_eth(to),239					amount.try_into().map_err(|_| "amount overflow")?,240				))241			})242			.collect::<Result<_>>()?;243244		<Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)245			.map_err(dispatch_to_evm::<T>)?;246		Ok(true)247	}248249	#[weight(<SelfWeightOf<T>>::transfer_from())]250	fn transfer_from_cross(251		&mut self,252		caller: caller,253		from: (address, uint256),254		to: (address, uint256),255		amount: uint256,256	) -> Result<bool> {257		let caller = T::CrossAccountId::from_eth(caller);258		let from = convert_tuple_to_cross_account::<T>(from)?;259		let to = convert_tuple_to_cross_account::<T>(to)?;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>>::transfer_from(self, &caller, &from, &to, amount, &budget)266			.map_err(dispatch_to_evm::<T>)?;267		Ok(true)268	}269}270271#[solidity_interface(272	name = UniqueFungible,273	is(274		ERC20,275		ERC20Mintable,276		ERC20UniqueExtensions,277		Collection(via(common_mut returns CollectionHandle<T>)),278	)279)]280impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}281282generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);283generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);284285impl<T: Config> CommonEvmHandler for FungibleHandle<T>286where287	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,288{289	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");290291	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {292		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)293	}294}