difftreelog
refactor Make implementations of Abi* for EthCrossAccount via AbiCoder macro
in: master
9 files changed
.maintain/scripts/generate_abi.shdiffbeforeafterboth--- a/.maintain/scripts/generate_abi.sh
+++ b/.maintain/scripts/generate_abi.sh
@@ -4,6 +4,7 @@
dir=$PWD
tmp=$(mktemp -d)
+echo "Tmp file: $tmp/input.sol"
cd $tmp
cp $dir/$INPUT input.sol
solcjs --abi -p input.sol
crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -120,42 +120,6 @@
}
}
-impl sealed::CanBePlacedInVec for EthCrossAccount {}
-
-impl AbiType for EthCrossAccount {
- const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
-
- fn is_dynamic() -> bool {
- address::is_dynamic() || uint256::is_dynamic()
- }
-
- fn size() -> usize {
- <address as AbiType>::size() + <uint256 as AbiType>::size()
- }
-}
-
-impl AbiRead for EthCrossAccount {
- fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {
- let size = if !EthCrossAccount::is_dynamic() {
- Some(<EthCrossAccount as AbiType>::size())
- } else {
- None
- };
- let mut subresult = reader.subresult(size)?;
- let eth = <address>::abi_read(&mut subresult)?;
- let sub = <uint256>::abi_read(&mut subresult)?;
-
- Ok(EthCrossAccount { eth, sub })
- }
-}
-
-impl AbiWrite for EthCrossAccount {
- fn abi_write(&self, writer: &mut AbiWriter) {
- self.eth.abi_write(writer);
- self.sub.abi_write(writer);
- }
-}
-
impl sealed::CanBePlacedInVec for Property {}
impl AbiType for Property {
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -93,6 +93,7 @@
pub use evm_coder_procedural::solidity;
/// See [`solidity_interface`]
pub use evm_coder_procedural::weight;
+pub use evm_coder_procedural::AbiCoder;
pub use sha3_const;
/// Derives [`ToLog`] for enum
@@ -119,7 +120,6 @@
#[cfg(not(feature = "std"))]
use alloc::{vec::Vec};
- use pallet_evm::account::CrossAccountId;
use primitive_types::{U256, H160, H256};
pub type address = H160;
@@ -185,73 +185,7 @@
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
- }
- }
-
- #[derive(Debug, Default)]
- pub struct EthCrossAccount {
- pub(crate) eth: address,
- pub(crate) sub: uint256,
- }
-
- impl EthCrossAccount {
- pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self
- where
- T: pallet_evm::Config,
- T::AccountId: AsRef<[u8; 32]>,
- {
- if cross_account_id.is_canonical_substrate() {
- Self {
- eth: Default::default(),
- sub: convert_cross_account_to_uint256::<T>(cross_account_id),
- }
- } else {
- Self {
- eth: *cross_account_id.as_eth(),
- sub: Default::default(),
- }
- }
- }
-
- pub fn into_sub_cross_account<T>(&self) -> crate::execution::Result<T::CrossAccountId>
- where
- T: pallet_evm::Config,
- T::AccountId: From<[u8; 32]>,
- {
- if self.eth == Default::default() && self.sub == Default::default() {
- Err("All fields of cross account is zeroed".into())
- } else if self.eth == Default::default() {
- Ok(convert_uint256_to_cross_account::<T>(self.sub))
- } else if self.sub == Default::default() {
- Ok(T::CrossAccountId::from_eth(self.eth))
- } else {
- Err("All fields of cross account is non zeroed".into())
- }
}
- }
-
- /// Convert `CrossAccountId` to `uint256`.
- pub fn convert_cross_account_to_uint256<T: pallet_evm::Config>(
- from: &T::CrossAccountId,
- ) -> uint256
- where
- T::AccountId: AsRef<[u8; 32]>,
- {
- let slice = from.as_sub().as_ref();
- uint256::from_big_endian(slice)
- }
-
- /// Convert `uint256` to `CrossAccountId`.
- pub fn convert_uint256_to_cross_account<T: pallet_evm::Config>(
- from: uint256,
- ) -> T::CrossAccountId
- where
- T::AccountId: From<[u8; 32]>,
- {
- let mut new_admin_arr = [0_u8; 32];
- from.to_big_endian(&mut new_admin_arr);
- let account_id = T::AccountId::from(new_admin_arr);
- T::CrossAccountId::from_sub(account_id)
}
#[derive(Debug, Default)]
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -145,7 +145,7 @@
}
}
-mod sealed {
+pub mod sealed {
/// Not every type should be directly placed in vec.
/// Vec encoding is not memory efficient, as every item will be padded
/// to 32 bytes.
@@ -156,7 +156,6 @@
impl sealed::CanBePlacedInVec for uint256 {}
impl sealed::CanBePlacedInVec for string {}
impl sealed::CanBePlacedInVec for address {}
-impl sealed::CanBePlacedInVec for EthCrossAccount {}
impl sealed::CanBePlacedInVec for Property {}
impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {
@@ -171,61 +170,6 @@
write!(writer, "new ")?;
T::solidity_name(writer, tc)?;
write!(writer, "[](0)")
- }
-}
-
-impl SolidityTupleType for EthCrossAccount {
- fn names(tc: &TypeCollector) -> Vec<string> {
- let mut collected = Vec::with_capacity(Self::len());
- {
- let mut out = string::new();
- address::solidity_name(&mut out, tc).expect("no fmt error");
- collected.push(out);
- }
- {
- let mut out = string::new();
- uint256::solidity_name(&mut out, tc).expect("no fmt error");
- collected.push(out);
- }
- collected
- }
-
- fn len() -> usize {
- 2
- }
-}
-
-impl SolidityTypeName for EthCrossAccount {
- fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}", tc.collect_struct::<Self>())
- }
-
- fn is_simple() -> bool {
- false
- }
-
- fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
- write!(writer, "{}(", tc.collect_struct::<Self>())?;
- address::solidity_default(writer, tc)?;
- write!(writer, ",")?;
- uint256::solidity_default(writer, tc)?;
- write!(writer, ")")
- }
-}
-
-impl StructCollect for EthCrossAccount {
- fn name() -> String {
- "EthCrossAccount".into()
- }
-
- fn declaration() -> String {
- let mut str = String::new();
- writeln!(str, "/// @dev Cross account struct").unwrap();
- writeln!(str, "struct {} {{", Self::name()).unwrap();
- writeln!(str, "\taddress eth;").unwrap();
- writeln!(str, "\tuint256 sub;").unwrap();
- writeln!(str, "}}").unwrap();
- str
}
}
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -16,6 +16,7 @@
//! This module contains the implementation of pallet methods for evm.
+pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
use evm_coder::{
abi::AbiType,
solidity_interface, solidity, ToLog,
@@ -24,7 +25,6 @@
execution::{Result, Error},
weight,
};
-pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_std::vec::Vec;
use up_data_structs::{
@@ -35,7 +35,8 @@
use crate::{
Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,
- eth::convert_cross_account_to_uint256, weights::WeightInfo,
+ eth::{EthCrossAccount, convert_cross_account_to_uint256},
+ weights::WeightInfo,
};
/// Events for ethereum collection helper.
pallets/common/src/eth.rsdiffbeforeafterboth--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -16,7 +16,10 @@
//! The module contains a number of functions for converting and checking ethereum identifiers.
-use evm_coder::types::{uint256, address};
+use evm_coder::{
+ AbiCoder,
+ types::{uint256, address},
+};
pub use pallet_evm::{Config, account::CrossAccountId};
use sp_core::H160;
use up_data_structs::CollectionId;
@@ -109,3 +112,111 @@
Err("All fields of cross account is non zeroed".into())
}
}
+
+#[derive(Debug, Default, AbiCoder)]
+pub struct EthCrossAccount {
+ pub(crate) eth: address,
+ pub(crate) sub: uint256,
+}
+
+impl EthCrossAccount {
+ pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self
+ where
+ T: pallet_evm::account::Config,
+ T::AccountId: AsRef<[u8; 32]>,
+ {
+ if cross_account_id.is_canonical_substrate() {
+ Self {
+ eth: Default::default(),
+ sub: convert_cross_account_to_uint256::<T>(cross_account_id),
+ }
+ } else {
+ Self {
+ eth: *cross_account_id.as_eth(),
+ sub: Default::default(),
+ }
+ }
+ }
+
+ pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>
+ where
+ T: pallet_evm::account::Config,
+ T::AccountId: From<[u8; 32]>,
+ {
+ if self.eth == Default::default() && self.sub == Default::default() {
+ Err("All fields of cross account is zeroed".into())
+ } else if self.eth == Default::default() {
+ Ok(convert_uint256_to_cross_account::<T>(self.sub))
+ } else if self.sub == Default::default() {
+ Ok(T::CrossAccountId::from_eth(self.eth))
+ } else {
+ Err("All fields of cross account is non zeroed".into())
+ }
+ }
+}
+
+impl ::evm_coder::solidity::sealed::CanBePlacedInVec for EthCrossAccount {}
+impl ::evm_coder::solidity::SolidityTupleType for EthCrossAccount {
+ fn names(tc: &::evm_coder::solidity::TypeCollector) -> Vec<String> {
+ let mut collected =
+ Vec::with_capacity(<Self as ::evm_coder::solidity::SolidityTupleType>::len());
+ {
+ let mut out = String::new();
+ <address as ::evm_coder::solidity::SolidityTypeName>::solidity_name(&mut out, tc)
+ .expect("no fmt error");
+ collected.push(out);
+ }
+ {
+ let mut out = String::new();
+ <uint256 as ::evm_coder::solidity::SolidityTypeName>::solidity_name(&mut out, tc)
+ .expect("no fmt error");
+ collected.push(out);
+ }
+ collected
+ }
+
+ fn len() -> usize {
+ 2
+ }
+}
+impl ::evm_coder::solidity::SolidityTypeName for EthCrossAccount {
+ fn solidity_name(
+ writer: &mut impl ::core::fmt::Write,
+ tc: &::evm_coder::solidity::TypeCollector,
+ ) -> ::core::fmt::Result {
+ write!(writer, "{}", tc.collect_struct::<Self>())
+ }
+
+ fn is_simple() -> bool {
+ false
+ }
+
+ fn solidity_default(
+ writer: &mut impl ::core::fmt::Write,
+ tc: &::evm_coder::solidity::TypeCollector,
+ ) -> ::core::fmt::Result {
+ write!(writer, "{}(", tc.collect_struct::<Self>())?;
+ address::solidity_default(writer, tc)?;
+ write!(writer, ",")?;
+ uint256::solidity_default(writer, tc)?;
+ write!(writer, ")")
+ }
+}
+
+impl ::evm_coder::solidity::StructCollect for EthCrossAccount {
+ fn name() -> String {
+ "EthCrossAccount".into()
+ }
+
+ fn declaration() -> String {
+ use std::fmt::Write;
+
+ let mut str = String::new();
+ writeln!(str, "/// @dev Cross account struct").unwrap();
+ writeln!(str, "struct {} {{", Self::name()).unwrap();
+ writeln!(str, "\taddress eth;").unwrap();
+ writeln!(str, "\tuint256 sub;").unwrap();
+ writeln!(str, "}}").unwrap();
+ str
+ }
+}
pallets/fungible/src/erc.rsdiffbeforeafterboth1// 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, solidity_interface, types::*,24 weight,25};26use up_data_structs::CollectionMode;27use pallet_common::erc::{CommonEvmHandler, PrecompileResult};28use sp_std::vec::Vec;29use pallet_evm::{account::CrossAccountId, PrecompileHandle};30use pallet_evm_coder_substrate::{call, dispatch_to_evm};31use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};32use pallet_common::{CollectionHandle, erc::CollectionCall};33use sp_core::Get;3435use crate::{36 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,37 weights::WeightInfo,38};3940#[derive(ToLog)]41pub enum ERC20Events {42 Transfer {43 #[indexed]44 from: address,45 #[indexed]46 to: address,47 value: uint256,48 },49 Approval {50 #[indexed]51 owner: address,52 #[indexed]53 spender: address,54 value: uint256,55 },56}5758#[solidity_interface(name = ERC20, events(ERC20Events))]59impl<T: Config> FungibleHandle<T> {60 fn name(&self) -> Result<string> {61 Ok(decode_utf16(self.name.iter().copied())62 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))63 .collect::<string>())64 }65 fn symbol(&self) -> Result<string> {66 Ok(string::from_utf8_lossy(&self.token_prefix).into())67 }68 fn total_supply(&self) -> Result<uint256> {69 self.consume_store_reads(1)?;70 Ok(<TotalSupply<T>>::get(self.id).into())71 }7273 fn decimals(&self) -> Result<uint8> {74 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {75 *decimals76 } else {77 unreachable!()78 })79 }80 fn balance_of(&self, owner: address) -> Result<uint256> {81 self.consume_store_reads(1)?;82 let owner = T::CrossAccountId::from_eth(owner);83 let balance = <Balance<T>>::get((self.id, owner));84 Ok(balance.into())85 }86 #[weight(<SelfWeightOf<T>>::transfer())]87 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {88 let caller = T::CrossAccountId::from_eth(caller);89 let to = T::CrossAccountId::from_eth(to);90 let amount = amount.try_into().map_err(|_| "amount overflow")?;91 let budget = self92 .recorder93 .weight_calls_budget(<StructureWeight<T>>::find_parent());9495 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;96 Ok(true)97 }9899 #[weight(<SelfWeightOf<T>>::transfer_from())]100 fn transfer_from(101 &mut self,102 caller: caller,103 from: address,104 to: address,105 amount: uint256,106 ) -> Result<bool> {107 let caller = T::CrossAccountId::from_eth(caller);108 let from = T::CrossAccountId::from_eth(from);109 let to = T::CrossAccountId::from_eth(to);110 let amount = amount.try_into().map_err(|_| "amount overflow")?;111 let budget = self112 .recorder113 .weight_calls_budget(<StructureWeight<T>>::find_parent());114115 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)116 .map_err(dispatch_to_evm::<T>)?;117 Ok(true)118 }119 #[weight(<SelfWeightOf<T>>::approve())]120 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {121 let caller = T::CrossAccountId::from_eth(caller);122 let spender = T::CrossAccountId::from_eth(spender);123 let amount = amount.try_into().map_err(|_| "amount overflow")?;124125 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)126 .map_err(dispatch_to_evm::<T>)?;127 Ok(true)128 }129 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {130 self.consume_store_reads(1)?;131 let owner = T::CrossAccountId::from_eth(owner);132 let spender = T::CrossAccountId::from_eth(spender);133134 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())135 }136137 /// @notice Returns collection helper contract address138 fn collection_helper_address(&self) -> Result<address> {139 Ok(T::ContractAddress::get())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 /// @notice A description for the collection.168 fn description(&self) -> Result<string> {169 Ok(decode_utf16(self.description.iter().copied())170 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))171 .collect::<string>())172 }173174 #[weight(<SelfWeightOf<T>>::approve())]175 fn approve_cross(176 &mut self,177 caller: caller,178 spender: EthCrossAccount,179 amount: uint256,180 ) -> Result<bool> {181 let caller = T::CrossAccountId::from_eth(caller);182 let spender = spender.into_sub_cross_account::<T>()?;183 let amount = amount.try_into().map_err(|_| "amount overflow")?;184185 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)186 .map_err(dispatch_to_evm::<T>)?;187 Ok(true)188 }189190 /// Burn tokens from account191 /// @dev Function that burns an `amount` of the tokens of a given account,192 /// deducting from the sender's allowance for said account.193 /// @param from The account whose tokens will be burnt.194 /// @param amount The amount that will be burnt.195 #[solidity(hide)]196 #[weight(<SelfWeightOf<T>>::burn_from())]197 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {198 let caller = T::CrossAccountId::from_eth(caller);199 let from = T::CrossAccountId::from_eth(from);200 let amount = amount.try_into().map_err(|_| "amount overflow")?;201 let budget = self202 .recorder203 .weight_calls_budget(<StructureWeight<T>>::find_parent());204205 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)206 .map_err(dispatch_to_evm::<T>)?;207 Ok(true)208 }209210 /// Burn tokens from account211 /// @dev Function that burns an `amount` of the tokens of a given account,212 /// deducting from the sender's allowance for said account.213 /// @param from The account whose tokens will be burnt.214 /// @param amount The amount that will be burnt.215 #[weight(<SelfWeightOf<T>>::burn_from())]216 fn burn_from_cross(217 &mut self,218 caller: caller,219 from: EthCrossAccount,220 amount: uint256,221 ) -> Result<bool> {222 let caller = T::CrossAccountId::from_eth(caller);223 let from = from.into_sub_cross_account::<T>()?;224 let amount = amount.try_into().map_err(|_| "amount overflow")?;225 let budget = self226 .recorder227 .weight_calls_budget(<StructureWeight<T>>::find_parent());228229 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)230 .map_err(dispatch_to_evm::<T>)?;231 Ok(true)232 }233234 /// Mint tokens for multiple accounts.235 /// @param amounts array of pairs of account address and amount236 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]237 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {238 let caller = T::CrossAccountId::from_eth(caller);239 let budget = self240 .recorder241 .weight_calls_budget(<StructureWeight<T>>::find_parent());242 let amounts = amounts243 .into_iter()244 .map(|(to, amount)| {245 Ok((246 T::CrossAccountId::from_eth(to),247 amount.try_into().map_err(|_| "amount overflow")?,248 ))249 })250 .collect::<Result<_>>()?;251252 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)253 .map_err(dispatch_to_evm::<T>)?;254 Ok(true)255 }256257 #[weight(<SelfWeightOf<T>>::transfer())]258 fn transfer_cross(259 &mut self,260 caller: caller,261 to: EthCrossAccount,262 amount: uint256,263 ) -> Result<bool> {264 let caller = T::CrossAccountId::from_eth(caller);265 let to = to.into_sub_cross_account::<T>()?;266 let amount = amount.try_into().map_err(|_| "amount overflow")?;267 let budget = self268 .recorder269 .weight_calls_budget(<StructureWeight<T>>::find_parent());270271 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;272 Ok(true)273 }274275 #[weight(<SelfWeightOf<T>>::transfer_from())]276 fn transfer_from_cross(277 &mut self,278 caller: caller,279 from: EthCrossAccount,280 to: EthCrossAccount,281 amount: uint256,282 ) -> Result<bool> {283 let caller = T::CrossAccountId::from_eth(caller);284 let from = from.into_sub_cross_account::<T>()?;285 let to = to.into_sub_cross_account::<T>()?;286 let amount = amount.try_into().map_err(|_| "amount overflow")?;287 let budget = self288 .recorder289 .weight_calls_budget(<StructureWeight<T>>::find_parent());290291 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)292 .map_err(dispatch_to_evm::<T>)?;293 Ok(true)294 }295}296297#[solidity_interface(298 name = UniqueFungible,299 is(300 ERC20,301 ERC20Mintable,302 ERC20UniqueExtensions,303 Collection(via(common_mut returns CollectionHandle<T>)),304 )305)]306impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}307308generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);309generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);310311impl<T: Config> CommonEvmHandler for FungibleHandle<T>312where313 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,314{315 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");316317 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {318 call::<T, UniqueFungibleCall<T>, _, _>(handle, self)319 }320}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, solidity_interface, types::*,24 weight,25};26use up_data_structs::CollectionMode;27use pallet_common::{28 CollectionHandle,29 erc::{CommonEvmHandler, PrecompileResult, CollectionCall},30 eth::EthCrossAccount,31};32use sp_std::vec::Vec;33use pallet_evm::{account::CrossAccountId, PrecompileHandle};34use pallet_evm_coder_substrate::{call, dispatch_to_evm};35use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};36use sp_core::Get;3738use crate::{39 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,40 weights::WeightInfo,41};4243#[derive(ToLog)]44pub enum ERC20Events {45 Transfer {46 #[indexed]47 from: address,48 #[indexed]49 to: address,50 value: uint256,51 },52 Approval {53 #[indexed]54 owner: address,55 #[indexed]56 spender: address,57 value: uint256,58 },59}6061#[solidity_interface(name = ERC20, events(ERC20Events))]62impl<T: Config> FungibleHandle<T> {63 fn name(&self) -> Result<string> {64 Ok(decode_utf16(self.name.iter().copied())65 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))66 .collect::<string>())67 }68 fn symbol(&self) -> Result<string> {69 Ok(string::from_utf8_lossy(&self.token_prefix).into())70 }71 fn total_supply(&self) -> Result<uint256> {72 self.consume_store_reads(1)?;73 Ok(<TotalSupply<T>>::get(self.id).into())74 }7576 fn decimals(&self) -> Result<uint8> {77 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {78 *decimals79 } else {80 unreachable!()81 })82 }83 fn balance_of(&self, owner: address) -> Result<uint256> {84 self.consume_store_reads(1)?;85 let owner = T::CrossAccountId::from_eth(owner);86 let balance = <Balance<T>>::get((self.id, owner));87 Ok(balance.into())88 }89 #[weight(<SelfWeightOf<T>>::transfer())]90 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {91 let caller = T::CrossAccountId::from_eth(caller);92 let to = T::CrossAccountId::from_eth(to);93 let amount = amount.try_into().map_err(|_| "amount overflow")?;94 let budget = self95 .recorder96 .weight_calls_budget(<StructureWeight<T>>::find_parent());9798 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;99 Ok(true)100 }101102 #[weight(<SelfWeightOf<T>>::transfer_from())]103 fn transfer_from(104 &mut self,105 caller: caller,106 from: address,107 to: address,108 amount: uint256,109 ) -> Result<bool> {110 let caller = T::CrossAccountId::from_eth(caller);111 let from = T::CrossAccountId::from_eth(from);112 let to = T::CrossAccountId::from_eth(to);113 let amount = amount.try_into().map_err(|_| "amount overflow")?;114 let budget = self115 .recorder116 .weight_calls_budget(<StructureWeight<T>>::find_parent());117118 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)119 .map_err(dispatch_to_evm::<T>)?;120 Ok(true)121 }122 #[weight(<SelfWeightOf<T>>::approve())]123 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {124 let caller = T::CrossAccountId::from_eth(caller);125 let spender = T::CrossAccountId::from_eth(spender);126 let amount = amount.try_into().map_err(|_| "amount overflow")?;127128 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)129 .map_err(dispatch_to_evm::<T>)?;130 Ok(true)131 }132 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {133 self.consume_store_reads(1)?;134 let owner = T::CrossAccountId::from_eth(owner);135 let spender = T::CrossAccountId::from_eth(spender);136137 Ok(<Allowance<T>>::get((self.id, owner, spender)).into())138 }139140 /// @notice Returns collection helper contract address141 fn collection_helper_address(&self) -> Result<address> {142 Ok(T::ContractAddress::get())143 }144}145146#[solidity_interface(name = ERC20Mintable)]147impl<T: Config> FungibleHandle<T> {148 /// Mint tokens for `to` account.149 /// @param to account that will receive minted tokens150 /// @param amount amount of tokens to mint151 #[weight(<SelfWeightOf<T>>::create_item())]152 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {153 let caller = T::CrossAccountId::from_eth(caller);154 let to = T::CrossAccountId::from_eth(to);155 let amount = amount.try_into().map_err(|_| "amount overflow")?;156 let budget = self157 .recorder158 .weight_calls_budget(<StructureWeight<T>>::find_parent());159 <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)160 .map_err(dispatch_to_evm::<T>)?;161 Ok(true)162 }163}164165#[solidity_interface(name = ERC20UniqueExtensions)]166impl<T: Config> FungibleHandle<T>167where168 T::AccountId: From<[u8; 32]>,169{170 /// @notice A description for the collection.171 fn description(&self) -> Result<string> {172 Ok(decode_utf16(self.description.iter().copied())173 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))174 .collect::<string>())175 }176177 #[weight(<SelfWeightOf<T>>::approve())]178 fn approve_cross(179 &mut self,180 caller: caller,181 spender: EthCrossAccount,182 amount: uint256,183 ) -> Result<bool> {184 let caller = T::CrossAccountId::from_eth(caller);185 let spender = spender.into_sub_cross_account::<T>()?;186 let amount = amount.try_into().map_err(|_| "amount overflow")?;187188 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)189 .map_err(dispatch_to_evm::<T>)?;190 Ok(true)191 }192193 /// Burn tokens from account194 /// @dev Function that burns an `amount` of the tokens of a given account,195 /// deducting from the sender's allowance for said account.196 /// @param from The account whose tokens will be burnt.197 /// @param amount The amount that will be burnt.198 #[solidity(hide)]199 #[weight(<SelfWeightOf<T>>::burn_from())]200 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {201 let caller = T::CrossAccountId::from_eth(caller);202 let from = T::CrossAccountId::from_eth(from);203 let amount = amount.try_into().map_err(|_| "amount overflow")?;204 let budget = self205 .recorder206 .weight_calls_budget(<StructureWeight<T>>::find_parent());207208 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)209 .map_err(dispatch_to_evm::<T>)?;210 Ok(true)211 }212213 /// Burn tokens from account214 /// @dev Function that burns an `amount` of the tokens of a given account,215 /// deducting from the sender's allowance for said account.216 /// @param from The account whose tokens will be burnt.217 /// @param amount The amount that will be burnt.218 #[weight(<SelfWeightOf<T>>::burn_from())]219 fn burn_from_cross(220 &mut self,221 caller: caller,222 from: EthCrossAccount,223 amount: uint256,224 ) -> Result<bool> {225 let caller = T::CrossAccountId::from_eth(caller);226 let from = from.into_sub_cross_account::<T>()?;227 let amount = amount.try_into().map_err(|_| "amount overflow")?;228 let budget = self229 .recorder230 .weight_calls_budget(<StructureWeight<T>>::find_parent());231232 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)233 .map_err(dispatch_to_evm::<T>)?;234 Ok(true)235 }236237 /// Mint tokens for multiple accounts.238 /// @param amounts array of pairs of account address and amount239 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]240 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {241 let caller = T::CrossAccountId::from_eth(caller);242 let budget = self243 .recorder244 .weight_calls_budget(<StructureWeight<T>>::find_parent());245 let amounts = amounts246 .into_iter()247 .map(|(to, amount)| {248 Ok((249 T::CrossAccountId::from_eth(to),250 amount.try_into().map_err(|_| "amount overflow")?,251 ))252 })253 .collect::<Result<_>>()?;254255 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)256 .map_err(dispatch_to_evm::<T>)?;257 Ok(true)258 }259260 #[weight(<SelfWeightOf<T>>::transfer())]261 fn transfer_cross(262 &mut self,263 caller: caller,264 to: EthCrossAccount,265 amount: uint256,266 ) -> Result<bool> {267 let caller = T::CrossAccountId::from_eth(caller);268 let to = to.into_sub_cross_account::<T>()?;269 let amount = amount.try_into().map_err(|_| "amount overflow")?;270 let budget = self271 .recorder272 .weight_calls_budget(<StructureWeight<T>>::find_parent());273274 <Pallet<T>>::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?;275 Ok(true)276 }277278 #[weight(<SelfWeightOf<T>>::transfer_from())]279 fn transfer_from_cross(280 &mut self,281 caller: caller,282 from: EthCrossAccount,283 to: EthCrossAccount,284 amount: uint256,285 ) -> Result<bool> {286 let caller = T::CrossAccountId::from_eth(caller);287 let from = from.into_sub_cross_account::<T>()?;288 let to = to.into_sub_cross_account::<T>()?;289 let amount = amount.try_into().map_err(|_| "amount overflow")?;290 let budget = self291 .recorder292 .weight_calls_budget(<StructureWeight<T>>::find_parent());293294 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)295 .map_err(dispatch_to_evm::<T>)?;296 Ok(true)297 }298}299300#[solidity_interface(301 name = UniqueFungible,302 is(303 ERC20,304 ERC20Mintable,305 ERC20UniqueExtensions,306 Collection(via(common_mut returns CollectionHandle<T>)),307 )308)]309impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}310311generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);312generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);313314impl<T: Config> CommonEvmHandler for FungibleHandle<T>315where316 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,317{318 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");319320 fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {321 call::<T, UniqueFungibleCall<T>, _, _>(handle, self)322 }323}pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -36,8 +36,9 @@
use pallet_evm_coder_substrate::dispatch_to_evm;
use sp_std::vec::Vec;
use pallet_common::{
+ CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},
- CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
+ eth::EthCrossAccount,
};
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
use pallet_evm_coder_substrate::call;
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -33,6 +33,7 @@
use pallet_common::{
CollectionHandle, CollectionPropertyPermissions,
erc::{CommonEvmHandler, CollectionCall, static_property::key},
+ eth::EthCrossAccount,
CommonCollectionOperations,
};
use pallet_evm::{account::CrossAccountId, PrecompileHandle};