git.delta.rocks / unique-network / refs/commits / 7bd00bbda0e0

difftreelog

source

pallets/fungible/src/erc.rs9.1 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	}96	#[weight(<SelfWeightOf<T>>::transfer_from())]97	fn transfer_from(98		&mut self,99		caller: caller,100		from: address,101		to: address,102		amount: uint256,103	) -> Result<bool> {104		let caller = T::CrossAccountId::from_eth(caller);105		let from = T::CrossAccountId::from_eth(from);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_from(self, &caller, &from, &to, amount, &budget)113			.map_err(dispatch_to_evm::<T>)?;114		Ok(true)115	}116	#[weight(<SelfWeightOf<T>>::approve())]117	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {118		let caller = T::CrossAccountId::from_eth(caller);119		let spender = T::CrossAccountId::from_eth(spender);120		let amount = amount.try_into().map_err(|_| "amount overflow")?;121122		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)123			.map_err(dispatch_to_evm::<T>)?;124		Ok(true)125	}126	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {127		self.consume_store_reads(1)?;128		let owner = T::CrossAccountId::from_eth(owner);129		let spender = T::CrossAccountId::from_eth(spender);130131		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())132	}133}134135#[solidity_interface(name = ERC20Mintable)]136impl<T: Config> FungibleHandle<T> {137	/// Mint tokens for `to` account.138	/// @param to account that will receive minted tokens139	/// @param amount amount of tokens to mint140	#[weight(<SelfWeightOf<T>>::create_item())]141	fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {142		let caller = T::CrossAccountId::from_eth(caller);143		let to = T::CrossAccountId::from_eth(to);144		let amount = amount.try_into().map_err(|_| "amount overflow")?;145		let budget = self146			.recorder147			.weight_calls_budget(<StructureWeight<T>>::find_parent());148		<Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)149			.map_err(dispatch_to_evm::<T>)?;150		Ok(true)151	}152}153154#[solidity_interface(name = ERC20UniqueExtensions)]155impl<T: Config> FungibleHandle<T>156where157	T::AccountId: From<[u8; 32]>,158{159	#[weight(<SelfWeightOf<T>>::approve())]160	fn approve_cross(161		&mut self,162		caller: caller,163		spender: EthCrossAccount,164		amount: uint256,165	) -> Result<bool> {166		let caller = T::CrossAccountId::from_eth(caller);167		let spender = spender.into_sub_cross_account::<T>()?;168		let amount = amount.try_into().map_err(|_| "amount overflow")?;169170		<Pallet<T>>::set_allowance(self, &caller, &spender, amount)171			.map_err(dispatch_to_evm::<T>)?;172		Ok(true)173	}174175	/// Burn tokens from account176	/// @dev Function that burns an `amount` of the tokens of a given account,177	/// deducting from the sender's allowance for said account.178	/// @param from The account whose tokens will be burnt.179	/// @param amount The amount that will be burnt.180	#[weight(<SelfWeightOf<T>>::burn_from())]181	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {182		let caller = T::CrossAccountId::from_eth(caller);183		let from = T::CrossAccountId::from_eth(from);184		let amount = amount.try_into().map_err(|_| "amount overflow")?;185		let budget = self186			.recorder187			.weight_calls_budget(<StructureWeight<T>>::find_parent());188189		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)190			.map_err(dispatch_to_evm::<T>)?;191		Ok(true)192	}193194	/// Burn tokens from account195	/// @dev Function that burns an `amount` of the tokens of a given account,196	/// deducting from the sender's allowance for said account.197	/// @param from The account whose tokens will be burnt.198	/// @param amount The amount that will be burnt.199	#[weight(<SelfWeightOf<T>>::burn_from())]200	fn burn_from_cross(201		&mut self,202		caller: caller,203		from: EthCrossAccount,204		amount: uint256,205	) -> Result<bool> {206		let caller = T::CrossAccountId::from_eth(caller);207		let from = from.into_sub_cross_account::<T>()?;208		let amount = amount.try_into().map_err(|_| "amount overflow")?;209		let budget = self210			.recorder211			.weight_calls_budget(<StructureWeight<T>>::find_parent());212213		<Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)214			.map_err(dispatch_to_evm::<T>)?;215		Ok(true)216	}217218	/// Mint tokens for multiple accounts.219	/// @param amounts array of pairs of account address and amount220	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]221	fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {222		let caller = T::CrossAccountId::from_eth(caller);223		let budget = self224			.recorder225			.weight_calls_budget(<StructureWeight<T>>::find_parent());226		let amounts = amounts227			.into_iter()228			.map(|(to, amount)| {229				Ok((230					T::CrossAccountId::from_eth(to),231					amount.try_into().map_err(|_| "amount overflow")?,232				))233			})234			.collect::<Result<_>>()?;235236		<Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)237			.map_err(dispatch_to_evm::<T>)?;238		Ok(true)239	}240241	#[weight(<SelfWeightOf<T>>::transfer_from())]242	fn transfer_from_cross(243		&mut self,244		caller: caller,245		from: EthCrossAccount,246		to: EthCrossAccount,247		amount: uint256,248	) -> Result<bool> {249		let caller = T::CrossAccountId::from_eth(caller);250		let from = from.into_sub_cross_account::<T>()?;251		let to = to.into_sub_cross_account::<T>()?;252		let amount = amount.try_into().map_err(|_| "amount overflow")?;253		let budget = self254			.recorder255			.weight_calls_budget(<StructureWeight<T>>::find_parent());256257		<Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)258			.map_err(dispatch_to_evm::<T>)?;259		Ok(true)260	}261}262263#[solidity_interface(264	name = UniqueFungible,265	is(266		ERC20,267		ERC20Mintable,268		ERC20UniqueExtensions,269		Collection(via(common_mut returns CollectionHandle<T>)),270	)271)]272impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}273274generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);275generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);276277impl<T: Config> CommonEvmHandler for FungibleHandle<T>278where279	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,280{281	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");282283	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {284		call::<T, UniqueFungibleCall<T>, _, _>(handle, self)285	}286}