difftreelog
feat calculate signature in compile time
in: master
11 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1096,6 +1096,26 @@
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
[[package]]
+name = "const_format"
+version = "0.2.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "939dc9e2eb9077e0679d2ce32de1ded8531779360b003b4a972a7a39ec263495"
+dependencies = [
+ "const_format_proc_macros",
+]
+
+[[package]]
+name = "const_format_proc_macros"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2353,6 +2373,7 @@
version = "0.1.3"
dependencies = [
"concat-idents",
+ "const_format",
"ethereum",
"evm-coder-procedural",
"evm-core 0.35.0 (git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.30)",
@@ -2362,6 +2383,7 @@
"impl-trait-for-tuples",
"pallet-evm 6.0.0-dev (git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27-fee-limit)",
"primitive-types",
+ "sha3-const",
"similar-asserts",
"sp-std 4.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30)",
]
@@ -11085,6 +11107,12 @@
]
[[package]]
+name = "sha3-const"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af9625d558d174dbdc711248b479271c0fdca39e9d3d67f6e890b3d4251fbf8e"
+
+[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
crates/evm-coder/Cargo.tomldiffbeforeafterboth--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -5,6 +5,10 @@
edition = "2021"
[dependencies]
+const_format = { version = "0.2.26", default-features = false }
+sha3-const = { version = "0.1.0", default-features = false }
+# Ethereum uses keccak (=sha3) for selectors
+# sha3 = "0.10.1"
# evm-coder reexports those proc-macro
evm-coder-procedural = { path = "./procedural" }
# Evm uses primitive-types for H160, H256 and others
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -20,6 +20,7 @@
// about Procedural Macros in Rust book:
// https://doc.rust-lang.org/reference/procedural-macros.html
+use proc_macro2::{TokenStream, Group};
use quote::{quote, ToTokens};
use inflector::cases;
use std::fmt::Write;
@@ -328,6 +329,7 @@
}
}
+#[derive(Debug)]
enum AbiType {
// type
Plain(Ident),
@@ -473,6 +475,7 @@
}
}
+#[derive(Debug)]
struct MethodArg {
name: Ident,
camel_name: String,
@@ -722,13 +725,25 @@
}
}
+ fn expand_selector(&self) -> proc_macro2::TokenStream {
+ let custom_signature = self.expand_custom_signature();
+ quote! {
+ {
+ let a = ::evm_coder::sha3_const::Keccak256::new()
+ .update(#custom_signature.as_bytes())
+ .finalize();
+ [a[0], a[1], a[2], a[3]]
+ }
+ }
+ }
+
fn expand_const(&self) -> proc_macro2::TokenStream {
let screaming_name = &self.screaming_name;
- let selector = u32::to_be_bytes(self.selector);
let selector_str = &self.selector_str;
+ let selector = &self.expand_selector();
quote! {
#[doc = #selector_str]
- const #screaming_name: ::evm_coder::types::bytes4 = [#(#selector,)*];
+ const #screaming_name: ::evm_coder::types::bytes4 = #selector;
}
}
@@ -831,6 +846,59 @@
}
}
+ fn expand_custom_signature(&self) -> proc_macro2::TokenStream {
+ let mut first_comma = true;
+ let mut custom_signature = TokenStream::new();
+ let mut template = self.camel_name.clone() + "(";
+ self.args
+ .iter()
+ .filter_map(|a| {
+ if a.is_special() {
+ return None;
+ };
+
+ match a.ty {
+ AbiType::Plain(ref ident) => Some(ident),
+ _ => None,
+ }
+ })
+ .for_each(|ident| {
+ if !first_comma {
+ custom_signature.extend(quote!(,));
+ template.push(',');
+ } else {
+ first_comma = false;
+ };
+ template.push_str("{}");
+ let ident_str = ident.to_string();
+ match ident_str.as_str() {
+ "address" | "uint8" | "uint16" | "uint32" | "uint64" | "uint128"
+ | "uint256" | "bytes4" | "topic" | "string" | "bytes" | "void" | "caller"
+ | "bool" | "" => {
+ custom_signature.extend(quote!(#ident_str));
+ }
+ _ => {
+ custom_signature.extend(quote! {
+ #ident::SIGNATURE_STRING
+ });
+ }
+ }
+ });
+
+ template.push(')');
+ let mut template = quote!(#template);
+ template.extend(quote!(,));
+ template.extend(custom_signature);
+ let custom_signature_group = Group::new(proc_macro2::Delimiter::Parenthesis, template);
+ let mut custom_signature = quote! {
+ ::evm_coder::const_format::formatcp!
+ };
+ custom_signature.extend(custom_signature_group.to_token_stream());
+
+ // println!("!!!!! {}", custom_signature);
+ custom_signature
+ }
+
fn expand_solidity_function(&self) -> proc_macro2::TokenStream {
let camel_name = &self.camel_name;
let mutability = match self.mutability {
@@ -847,15 +915,17 @@
.map(MethodArg::expand_solidity_argument);
let docs = &self.docs;
let selector_str = &self.selector_str;
- let selector = self.selector;
+ let selector = &self.expand_selector();
let hide = self.hide;
+ let custom_signature = self.expand_custom_signature();
let is_payable = self.has_value_args;
quote! {
SolidityFunction {
docs: &[#(#docs),*],
selector_str: #selector_str,
- selector: #selector,
hide: #hide,
+ selector: u32::from_be_bytes(#selector),
+ custom_signature: #custom_signature,
name: #camel_name,
mutability: #mutability,
is_payable: #is_payable,
crates/evm-coder/src/lib.rsdiffbeforeafterboth--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -90,6 +90,8 @@
pub use evm_coder_procedural::solidity;
/// See [`solidity_interface`]
pub use evm_coder_procedural::weight;
+pub use const_format;
+pub use sha3_const;
/// Derives [`ToLog`] for enum
///
@@ -227,6 +229,14 @@
}
}
+ impl SignatureString for EthCrossAccount {
+ const SIGNATURE_STRING: &'static str = "(address,uint256)";
+ }
+
+ pub trait SignatureString {
+ const SIGNATURE_STRING: &'static str;
+ }
+
/// Convert `CrossAccountId` to `uint256`.
pub fn convert_cross_account_to_uint256<T: pallet_evm::account::Config>(
from: &T::CrossAccountId,
@@ -348,6 +358,18 @@
assert_eq!(fn_selector!(transfer(address, uint256)), 0xa9059cbb);
}
+ // #[test]
+ // fn function_selector_generation_1() {
+ // assert_eq!(
+ // fn_selector!(transferFromCrossAccountToCrossAccount(
+ // EthCrossAccount,
+ // EthCrossAccount,
+ // uint256
+ // )),
+ // 2543295963
+ // );
+ // }
+
#[test]
fn event_topic_generation() {
assert_eq!(
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -35,6 +35,12 @@
use crate::types::*;
#[derive(Default)]
+pub struct FunctionSelectorMaker {
+ pub name: string,
+ pub args: Vec<fn() -> string>,
+}
+
+#[derive(Default)]
pub struct TypeCollector {
/// Code => id
/// id ordering is required to perform topo-sort on the resulting data
@@ -482,11 +488,25 @@
View,
Mutable,
}
+
+// fn fn_selector_str(input: &str) -> u32 {
+// use sha3::Digest;
+// let mut hasher = sha3::Keccak256::new();
+// hasher.update(input.as_bytes());
+// let result = hasher.finalize();
+
+// let mut selector_bytes = [0; 4];
+// selector_bytes.copy_from_slice(&result[0..4]);
+
+// u32::from_be_bytes(selector_bytes)
+// }
+
pub struct SolidityFunction<A, R> {
pub docs: &'static [&'static str],
pub selector_str: &'static str,
pub selector: u32,
pub hide: bool,
+ pub custom_signature: &'static str,
pub name: &'static str,
pub args: A,
pub result: R,
@@ -512,7 +532,7 @@
writeln!(
writer,
"\t{hide_comment}/// or in textual repr: {}",
- self.selector_str
+ self.custom_signature
)?;
write!(writer, "\t{hide_comment}function {}(", self.name)?;
self.args.solidity_name(writer, tc)?;
pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -27,7 +27,7 @@
evm-coder = { default-features = false, path = '../../crates/evm-coder' }
pallet-common = { default-features = false, path = '../../pallets/common' }
pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
-pallet-evm-transaction-payment = { default-features = false, path = '../../pallets/evm-transaction-payment' }
+pallet-evm-transaction-payment = { default-features = false, path = '../../pallets/evm-transaction-payment' }
up-data-structs = { default-features = false, path = '../../primitives/data-structs', features = [
'serde1',
] }
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -16,6 +16,8 @@
//! Implementation of magic contract
+extern crate alloc;
+use alloc::{format, string::ToString};
use core::marker::PhantomData;
use evm_coder::{
abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog,
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.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}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::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};24use pallet_common::eth::convert_tuple_to_cross_account;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: (address, uint256),164 amount: uint256,165 ) -> Result<bool> {166 let caller = T::CrossAccountId::from_eth(caller);167 let spender = convert_tuple_to_cross_account::<T>(spender)?;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: (address, uint256),204 amount: uint256,205 ) -> Result<bool> {206 let caller = T::CrossAccountId::from_eth(caller);207 let from = convert_tuple_to_cross_account::<T>(from)?;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: (address, uint256),246 to: (address, uint256),247 amount: uint256,248 ) -> Result<bool> {249 let caller = T::CrossAccountId::from_eth(caller);250 let from = convert_tuple_to_cross_account::<T>(from)?;251 let to = convert_tuple_to_cross_account::<T>(to)?;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}pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -20,6 +20,7 @@
//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.
extern crate alloc;
+use alloc::{format, string::ToString};
use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,
pallets/refungible/Cargo.tomldiffbeforeafterboth--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -26,7 +26,9 @@
struct-versioning = { path = "../../crates/struct-versioning" }
up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
ethereum = { version = "0.12.0", default-features = false }
-scale-info = { version = "2.0.1", default-features = false, features = ["derive",] }
+scale-info = { version = "2.0.1", default-features = false, features = [
+ "derive",
+] }
derivative = { version = "2.2.0", features = ["use_core"] }
[features]
pallets/refungible/src/erc.rsdiffbeforeafterboth--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -21,6 +21,7 @@
extern crate alloc;
+use alloc::{format, string::ToString};
use core::{
char::{REPLACEMENT_CHARACTER, decode_utf16},
convert::TryInto,