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.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//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language2324#[cfg(not(feature = "std"))]25use alloc::{string::String, vec::Vec, collections::BTreeMap, format};26#[cfg(feature = "std")]27use std::collections::BTreeMap;28use core::{29 fmt::{self, Write},30 marker::PhantomData,31 cell::{Cell, RefCell},32 cmp::Reverse,33};34use impl_trait_for_tuples::impl_for_tuples;35use crate::{types::*, custom_signature::SignatureUnit};3637#[derive(Default)]38pub struct TypeCollector {39 /// Code => id40 /// id ordering is required to perform topo-sort on the resulting data41 structs: RefCell<BTreeMap<string, usize>>,42 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,43 id: Cell<usize>,44}45impl TypeCollector {46 pub fn new() -> Self {47 Self::default()48 }49 pub fn collect(&self, item: string) {50 let id = self.next_id();51 self.structs.borrow_mut().insert(item, id);52 }53 pub fn next_id(&self) -> usize {54 let v = self.id.get();55 self.id.set(v + 1);56 v57 }58 pub fn collect_tuple<T: SolidityTupleType>(&self) -> String {59 let names = T::names(self);60 if let Some(id) = self.anonymous.borrow().get(&names).cloned() {61 return format!("Tuple{}", id);62 }63 let id = self.next_id();64 let mut str = String::new();65 writeln!(str, "/// @dev anonymous struct").unwrap();66 writeln!(str, "struct Tuple{} {{", id).unwrap();67 for (i, name) in names.iter().enumerate() {68 writeln!(str, "\t{} field_{};", name, i).unwrap();69 }70 writeln!(str, "}}").unwrap();71 self.collect(str);72 self.anonymous.borrow_mut().insert(names, id);73 format!("Tuple{}", id)74 }75 pub fn collect_struct<T: StructCollect>(&self) -> String {76 self.collect(<T as StructCollect>::declaration());77 <T as StructCollect>::name()78 }79 pub fn finish(self) -> Vec<string> {80 let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();81 data.sort_by_key(|(_, id)| Reverse(*id));82 data.into_iter().map(|(code, _)| code).collect()83 }84}8586pub trait StructCollect: 'static {87 /// Structure name.88 fn name() -> String;89 /// Structure declaration.90 fn declaration() -> String;91}9293pub trait SolidityTypeName: 'static {94 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;95 /// "simple" types are stored inline, no `memory` modifier should be used in solidity96 fn is_simple() -> bool;97 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;98 /// Specialization99 fn is_void() -> bool {100 false101 }102}103macro_rules! solidity_type_name {104 ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {105 $(106 impl SolidityTypeName for $ty {107 fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {108 write!(writer, $name)109 }110 fn is_simple() -> bool {111 $simple112 }113 fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {114 write!(writer, $default)115 }116 }117 )*118 };119}120121solidity_type_name! {122 uint8 => "uint8" true = "0",123 uint32 => "uint32" true = "0",124 uint64 => "uint64" true = "0",125 uint128 => "uint128" true = "0",126 uint256 => "uint256" true = "0",127 bytes4 => "bytes4" true = "bytes4(0)",128 address => "address" true = "0x0000000000000000000000000000000000000000",129 string => "string" false = "\"\"",130 bytes => "bytes" false = "hex\"\"",131 bool => "bool" true = "false",132}133impl SolidityTypeName for void {134 fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {135 Ok(())136 }137 fn is_simple() -> bool {138 true139 }140 fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {141 Ok(())142 }143 fn is_void() -> bool {144 true145 }146}147148mod sealed {149 /// Not every type should be directly placed in vec.150 /// Vec encoding is not memory efficient, as every item will be padded151 /// to 32 bytes.152 /// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)153 pub trait CanBePlacedInVec {}154}155156impl sealed::CanBePlacedInVec for uint256 {}157impl sealed::CanBePlacedInVec for string {}158impl sealed::CanBePlacedInVec for address {}159impl sealed::CanBePlacedInVec for EthCrossAccount {}160impl sealed::CanBePlacedInVec for Property {}161162impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {163 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {164 T::solidity_name(writer, tc)?;165 write!(writer, "[]")166 }167 fn is_simple() -> bool {168 false169 }170 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {171 write!(writer, "new ")?;172 T::solidity_name(writer, tc)?;173 write!(writer, "[](0)")174 }175}176177impl SolidityTupleType for EthCrossAccount {178 fn names(tc: &TypeCollector) -> Vec<string> {179 let mut collected = Vec::with_capacity(Self::len());180 {181 let mut out = string::new();182 address::solidity_name(&mut out, tc).expect("no fmt error");183 collected.push(out);184 }185 {186 let mut out = string::new();187 uint256::solidity_name(&mut out, tc).expect("no fmt error");188 collected.push(out);189 }190 collected191 }192193 fn len() -> usize {194 2195 }196}197198impl SolidityTypeName for EthCrossAccount {199 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {200 write!(writer, "{}", tc.collect_struct::<Self>())201 }202203 fn is_simple() -> bool {204 false205 }206207 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {208 write!(writer, "{}(", tc.collect_struct::<Self>())?;209 address::solidity_default(writer, tc)?;210 write!(writer, ",")?;211 uint256::solidity_default(writer, tc)?;212 write!(writer, ")")213 }214}215216impl StructCollect for EthCrossAccount {217 fn name() -> String {218 "EthCrossAccount".into()219 }220221 fn declaration() -> String {222 let mut str = String::new();223 writeln!(str, "/// @dev Cross account struct").unwrap();224 writeln!(str, "struct {} {{", Self::name()).unwrap();225 writeln!(str, "\taddress eth;").unwrap();226 writeln!(str, "\tuint256 sub;").unwrap();227 writeln!(str, "}}").unwrap();228 str229 }230}231232impl StructCollect for Property {233 fn name() -> String {234 "Property".into()235 }236237 fn declaration() -> String {238 let mut str = String::new();239 writeln!(str, "/// @dev Property struct").unwrap();240 writeln!(str, "struct {} {{", Self::name()).unwrap();241 writeln!(str, "\tstring key;").unwrap();242 writeln!(str, "\tbytes value;").unwrap();243 writeln!(str, "}}").unwrap();244 str245 }246}247248impl SolidityTypeName for Property {249 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {250 write!(writer, "{}", tc.collect_struct::<Self>())251 }252253 fn is_simple() -> bool {254 false255 }256257 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {258 write!(writer, "{}(", tc.collect_struct::<Self>())?;259 address::solidity_default(writer, tc)?;260 write!(writer, ",")?;261 uint256::solidity_default(writer, tc)?;262 write!(writer, ")")263 }264}265266impl SolidityTupleType for Property {267 fn names(tc: &TypeCollector) -> Vec<string> {268 let mut collected = Vec::with_capacity(Self::len());269 {270 let mut out = string::new();271 string::solidity_name(&mut out, tc).expect("no fmt error");272 collected.push(out);273 }274 {275 let mut out = string::new();276 bytes::solidity_name(&mut out, tc).expect("no fmt error");277 collected.push(out);278 }279 collected280 }281282 fn len() -> usize {283 2284 }285}286287pub trait SolidityTupleType {288 fn names(tc: &TypeCollector) -> Vec<String>;289 fn len() -> usize;290}291292macro_rules! count {293 () => (0usize);294 ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));295}296297macro_rules! impl_tuples {298 ($($ident:ident)+) => {299 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}300 impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) {301 fn names(tc: &TypeCollector) -> Vec<string> {302 let mut collected = Vec::with_capacity(Self::len());303 $({304 let mut out = string::new();305 $ident::solidity_name(&mut out, tc).expect("no fmt error");306 collected.push(out);307 })*;308 collected309 }310311 fn len() -> usize {312 count!($($ident)*)313 }314 }315 impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {316 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {317 write!(writer, "{}", tc.collect_tuple::<Self>())318 }319 fn is_simple() -> bool {320 false321 }322 #[allow(unused_assignments)]323 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {324 write!(writer, "{}(", tc.collect_tuple::<Self>())?;325 let mut first = true;326 $(327 if !first {328 write!(writer, ",")?;329 } else {330 first = false;331 }332 <$ident>::solidity_default(writer, tc)?;333 )*334 write!(writer, ")")335 }336 }337 };338}339340impl_tuples! {A}341impl_tuples! {A B}342impl_tuples! {A B C}343impl_tuples! {A B C D}344impl_tuples! {A B C D E}345impl_tuples! {A B C D E F}346impl_tuples! {A B C D E F G}347impl_tuples! {A B C D E F G H}348impl_tuples! {A B C D E F G H I}349impl_tuples! {A B C D E F G H I J}350351pub trait SolidityArguments {352 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;353 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result;354 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;355 fn is_empty(&self) -> bool {356 self.len() == 0357 }358 fn len(&self) -> usize;359}360361#[derive(Default)]362pub struct UnnamedArgument<T>(PhantomData<*const T>);363364impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {365 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {366 if !T::is_void() {367 T::solidity_name(writer, tc)?;368 if !T::is_simple() {369 write!(writer, " memory")?;370 }371 Ok(())372 } else {373 Ok(())374 }375 }376 fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {377 Ok(())378 }379 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {380 T::solidity_default(writer, tc)381 }382 fn len(&self) -> usize {383 if T::is_void() {384 0385 } else {386 1387 }388 }389}390391pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);392393impl<T> NamedArgument<T> {394 pub fn new(name: &'static str) -> Self {395 Self(name, Default::default())396 }397}398399impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {400 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {401 if !T::is_void() {402 T::solidity_name(writer, tc)?;403 if !T::is_simple() {404 write!(writer, " memory")?;405 }406 write!(writer, " {}", self.0)407 } else {408 Ok(())409 }410 }411 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {412 writeln!(writer, "\t{prefix}\t{};", self.0)413 }414 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {415 T::solidity_default(writer, tc)416 }417 fn len(&self) -> usize {418 if T::is_void() {419 0420 } else {421 1422 }423 }424}425426pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);427428impl<T> SolidityEventArgument<T> {429 pub fn new(indexed: bool, name: &'static str) -> Self {430 Self(indexed, name, Default::default())431 }432}433434impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {435 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {436 if !T::is_void() {437 T::solidity_name(writer, tc)?;438 if self.0 {439 write!(writer, " indexed")?;440 }441 write!(writer, " {}", self.1)442 } else {443 Ok(())444 }445 }446 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {447 writeln!(writer, "\t{prefix}\t{};", self.1)448 }449 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {450 T::solidity_default(writer, tc)451 }452 fn len(&self) -> usize {453 if T::is_void() {454 0455 } else {456 1457 }458 }459}460461impl SolidityArguments for () {462 fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {463 Ok(())464 }465 fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {466 Ok(())467 }468 fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {469 Ok(())470 }471 fn len(&self) -> usize {472 0473 }474}475476#[impl_for_tuples(1, 12)]477impl SolidityArguments for Tuple {478 for_tuples!( where #( Tuple: SolidityArguments ),* );479480 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {481 let mut first = true;482 for_tuples!( #(483 if !Tuple.is_empty() {484 if !first {485 write!(writer, ", ")?;486 }487 first = false;488 Tuple.solidity_name(writer, tc)?;489 }490 )* );491 Ok(())492 }493 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {494 for_tuples!( #(495 Tuple.solidity_get(prefix, writer)?;496 )* );497 Ok(())498 }499 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {500 if self.is_empty() {501 Ok(())502 } else if self.len() == 1 {503 for_tuples!( #(504 Tuple.solidity_default(writer, tc)?;505 )* );506 Ok(())507 } else {508 write!(writer, "(")?;509 let mut first = true;510 for_tuples!( #(511 if !Tuple.is_empty() {512 if !first {513 write!(writer, ", ")?;514 }515 first = false;516 Tuple.solidity_default(writer, tc)?;517 }518 )* );519 write!(writer, ")")?;520 Ok(())521 }522 }523 fn len(&self) -> usize {524 for_tuples!( #( Tuple.len() )+* )525 }526}527528pub trait SolidityFunctions {529 fn solidity_name(530 &self,531 is_impl: bool,532 writer: &mut impl fmt::Write,533 tc: &TypeCollector,534 ) -> fmt::Result;535}536537pub enum SolidityMutability {538 Pure,539 View,540 Mutable,541}542pub struct SolidityFunction<A, R> {543 pub docs: &'static [&'static str],544 pub selector: u32,545 pub hide: bool,546 pub custom_signature: SignatureUnit,547 pub name: &'static str,548 pub args: A,549 pub result: R,550 pub mutability: SolidityMutability,551 pub is_payable: bool,552}553impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {554 fn solidity_name(555 &self,556 is_impl: bool,557 writer: &mut impl fmt::Write,558 tc: &TypeCollector,559 ) -> fmt::Result {560 let hide_comment = self.hide.then(|| "// ").unwrap_or("");561 for doc in self.docs {562 writeln!(writer, "\t{hide_comment}///{}", doc)?;563 }564 writeln!(565 writer,566 "\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",567 self.selector568 )?;569 writeln!(570 writer,571 "\t{hide_comment}/// or in textual repr: {}",572 self.custom_signature.as_str().expect("bad utf-8")573 )?;574 write!(writer, "\t{hide_comment}function {}(", self.name)?;575 self.args.solidity_name(writer, tc)?;576 write!(writer, ")")?;577 if is_impl {578 write!(writer, " public")?;579 } else {580 write!(writer, " external")?;581 }582 match &self.mutability {583 SolidityMutability::Pure => write!(writer, " pure")?,584 SolidityMutability::View => write!(writer, " view")?,585 SolidityMutability::Mutable => {}586 }587 if self.is_payable {588 write!(writer, " payable")?;589 }590 if !self.result.is_empty() {591 write!(writer, " returns (")?;592 self.result.solidity_name(writer, tc)?;593 write!(writer, ")")?;594 }595 if is_impl {596 writeln!(writer, " {{")?;597 writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;598 self.args.solidity_get(hide_comment, writer)?;599 match &self.mutability {600 SolidityMutability::Pure => {}601 SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,602 SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,603 }604 if !self.result.is_empty() {605 write!(writer, "\t{hide_comment}\treturn ")?;606 self.result.solidity_default(writer, tc)?;607 writeln!(writer, ";")?;608 }609 writeln!(writer, "\t{hide_comment}}}")?;610 } else {611 writeln!(writer, ";")?;612 }613 if self.hide {614 writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;615 }616 Ok(())617 }618}619620#[impl_for_tuples(0, 48)]621impl SolidityFunctions for Tuple {622 for_tuples!( where #( Tuple: SolidityFunctions ),* );623624 fn solidity_name(625 &self,626 is_impl: bool,627 writer: &mut impl fmt::Write,628 tc: &TypeCollector,629 ) -> fmt::Result {630 let mut first = false;631 for_tuples!( #(632 Tuple.solidity_name(is_impl, writer, tc)?;633 )* );634 Ok(())635 }636}637638pub struct SolidityInterface<F: SolidityFunctions> {639 pub docs: &'static [&'static str],640 pub selector: bytes4,641 pub name: &'static str,642 pub is: &'static [&'static str],643 pub functions: F,644}645646impl<F: SolidityFunctions> SolidityInterface<F> {647 pub fn format(648 &self,649 is_impl: bool,650 out: &mut impl fmt::Write,651 tc: &TypeCollector,652 ) -> fmt::Result {653 const ZERO_BYTES: [u8; 4] = [0; 4];654 for doc in self.docs {655 writeln!(out, "///{}", doc)?;656 }657 if self.selector != ZERO_BYTES {658 writeln!(659 out,660 "/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",661 u32::from_be_bytes(self.selector)662 )?;663 }664 if is_impl {665 write!(out, "contract ")?;666 } else {667 write!(out, "interface ")?;668 }669 write!(out, "{}", self.name)?;670 if !self.is.is_empty() {671 write!(out, " is")?;672 for (i, n) in self.is.iter().enumerate() {673 if i != 0 {674 write!(out, ",")?;675 }676 write!(out, " {}", n)?;677 }678 }679 writeln!(out, " {{")?;680 self.functions.solidity_name(is_impl, out, tc)?;681 writeln!(out, "}}")?;682 Ok(())683 }684}685686pub struct SolidityEvent<A> {687 pub name: &'static str,688 pub args: A,689}690691impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {692 fn solidity_name(693 &self,694 _is_impl: bool,695 writer: &mut impl fmt::Write,696 tc: &TypeCollector,697 ) -> fmt::Result {698 write!(writer, "\tevent {}(", self.name)?;699 self.args.solidity_name(writer, tc)?;700 writeln!(writer, ");")701 }702}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//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language2324#[cfg(not(feature = "std"))]25use alloc::{string::String, vec::Vec, collections::BTreeMap, format};26#[cfg(feature = "std")]27use std::collections::BTreeMap;28use core::{29 fmt::{self, Write},30 marker::PhantomData,31 cell::{Cell, RefCell},32 cmp::Reverse,33};34use impl_trait_for_tuples::impl_for_tuples;35use crate::{types::*, custom_signature::SignatureUnit};3637#[derive(Default)]38pub struct TypeCollector {39 /// Code => id40 /// id ordering is required to perform topo-sort on the resulting data41 structs: RefCell<BTreeMap<string, usize>>,42 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,43 id: Cell<usize>,44}45impl TypeCollector {46 pub fn new() -> Self {47 Self::default()48 }49 pub fn collect(&self, item: string) {50 let id = self.next_id();51 self.structs.borrow_mut().insert(item, id);52 }53 pub fn next_id(&self) -> usize {54 let v = self.id.get();55 self.id.set(v + 1);56 v57 }58 pub fn collect_tuple<T: SolidityTupleType>(&self) -> String {59 let names = T::names(self);60 if let Some(id) = self.anonymous.borrow().get(&names).cloned() {61 return format!("Tuple{}", id);62 }63 let id = self.next_id();64 let mut str = String::new();65 writeln!(str, "/// @dev anonymous struct").unwrap();66 writeln!(str, "struct Tuple{} {{", id).unwrap();67 for (i, name) in names.iter().enumerate() {68 writeln!(str, "\t{} field_{};", name, i).unwrap();69 }70 writeln!(str, "}}").unwrap();71 self.collect(str);72 self.anonymous.borrow_mut().insert(names, id);73 format!("Tuple{}", id)74 }75 pub fn collect_struct<T: StructCollect>(&self) -> String {76 self.collect(<T as StructCollect>::declaration());77 <T as StructCollect>::name()78 }79 pub fn finish(self) -> Vec<string> {80 let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();81 data.sort_by_key(|(_, id)| Reverse(*id));82 data.into_iter().map(|(code, _)| code).collect()83 }84}8586pub trait StructCollect: 'static {87 /// Structure name.88 fn name() -> String;89 /// Structure declaration.90 fn declaration() -> String;91}9293pub trait SolidityTypeName: 'static {94 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;95 /// "simple" types are stored inline, no `memory` modifier should be used in solidity96 fn is_simple() -> bool;97 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;98 /// Specialization99 fn is_void() -> bool {100 false101 }102}103macro_rules! solidity_type_name {104 ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {105 $(106 impl SolidityTypeName for $ty {107 fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {108 write!(writer, $name)109 }110 fn is_simple() -> bool {111 $simple112 }113 fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {114 write!(writer, $default)115 }116 }117 )*118 };119}120121solidity_type_name! {122 uint8 => "uint8" true = "0",123 uint32 => "uint32" true = "0",124 uint64 => "uint64" true = "0",125 uint128 => "uint128" true = "0",126 uint256 => "uint256" true = "0",127 bytes4 => "bytes4" true = "bytes4(0)",128 address => "address" true = "0x0000000000000000000000000000000000000000",129 string => "string" false = "\"\"",130 bytes => "bytes" false = "hex\"\"",131 bool => "bool" true = "false",132}133impl SolidityTypeName for void {134 fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {135 Ok(())136 }137 fn is_simple() -> bool {138 true139 }140 fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {141 Ok(())142 }143 fn is_void() -> bool {144 true145 }146}147148pub mod sealed {149 /// Not every type should be directly placed in vec.150 /// Vec encoding is not memory efficient, as every item will be padded151 /// to 32 bytes.152 /// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)153 pub trait CanBePlacedInVec {}154}155156impl sealed::CanBePlacedInVec for uint256 {}157impl sealed::CanBePlacedInVec for string {}158impl sealed::CanBePlacedInVec for address {}159impl sealed::CanBePlacedInVec for Property {}160161impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {162 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {163 T::solidity_name(writer, tc)?;164 write!(writer, "[]")165 }166 fn is_simple() -> bool {167 false168 }169 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {170 write!(writer, "new ")?;171 T::solidity_name(writer, tc)?;172 write!(writer, "[](0)")173 }174}175176impl StructCollect for Property {177 fn name() -> String {178 "Property".into()179 }180181 fn declaration() -> String {182 let mut str = String::new();183 writeln!(str, "/// @dev Property struct").unwrap();184 writeln!(str, "struct {} {{", Self::name()).unwrap();185 writeln!(str, "\tstring key;").unwrap();186 writeln!(str, "\tbytes value;").unwrap();187 writeln!(str, "}}").unwrap();188 str189 }190}191192impl SolidityTypeName for Property {193 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {194 write!(writer, "{}", tc.collect_struct::<Self>())195 }196197 fn is_simple() -> bool {198 false199 }200201 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {202 write!(writer, "{}(", tc.collect_struct::<Self>())?;203 address::solidity_default(writer, tc)?;204 write!(writer, ",")?;205 uint256::solidity_default(writer, tc)?;206 write!(writer, ")")207 }208}209210impl SolidityTupleType for Property {211 fn names(tc: &TypeCollector) -> Vec<string> {212 let mut collected = Vec::with_capacity(Self::len());213 {214 let mut out = string::new();215 string::solidity_name(&mut out, tc).expect("no fmt error");216 collected.push(out);217 }218 {219 let mut out = string::new();220 bytes::solidity_name(&mut out, tc).expect("no fmt error");221 collected.push(out);222 }223 collected224 }225226 fn len() -> usize {227 2228 }229}230231pub trait SolidityTupleType {232 fn names(tc: &TypeCollector) -> Vec<String>;233 fn len() -> usize;234}235236macro_rules! count {237 () => (0usize);238 ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));239}240241macro_rules! impl_tuples {242 ($($ident:ident)+) => {243 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}244 impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) {245 fn names(tc: &TypeCollector) -> Vec<string> {246 let mut collected = Vec::with_capacity(Self::len());247 $({248 let mut out = string::new();249 $ident::solidity_name(&mut out, tc).expect("no fmt error");250 collected.push(out);251 })*;252 collected253 }254255 fn len() -> usize {256 count!($($ident)*)257 }258 }259 impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {260 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {261 write!(writer, "{}", tc.collect_tuple::<Self>())262 }263 fn is_simple() -> bool {264 false265 }266 #[allow(unused_assignments)]267 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {268 write!(writer, "{}(", tc.collect_tuple::<Self>())?;269 let mut first = true;270 $(271 if !first {272 write!(writer, ",")?;273 } else {274 first = false;275 }276 <$ident>::solidity_default(writer, tc)?;277 )*278 write!(writer, ")")279 }280 }281 };282}283284impl_tuples! {A}285impl_tuples! {A B}286impl_tuples! {A B C}287impl_tuples! {A B C D}288impl_tuples! {A B C D E}289impl_tuples! {A B C D E F}290impl_tuples! {A B C D E F G}291impl_tuples! {A B C D E F G H}292impl_tuples! {A B C D E F G H I}293impl_tuples! {A B C D E F G H I J}294295pub trait SolidityArguments {296 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;297 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result;298 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;299 fn is_empty(&self) -> bool {300 self.len() == 0301 }302 fn len(&self) -> usize;303}304305#[derive(Default)]306pub struct UnnamedArgument<T>(PhantomData<*const T>);307308impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {309 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {310 if !T::is_void() {311 T::solidity_name(writer, tc)?;312 if !T::is_simple() {313 write!(writer, " memory")?;314 }315 Ok(())316 } else {317 Ok(())318 }319 }320 fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {321 Ok(())322 }323 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {324 T::solidity_default(writer, tc)325 }326 fn len(&self) -> usize {327 if T::is_void() {328 0329 } else {330 1331 }332 }333}334335pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);336337impl<T> NamedArgument<T> {338 pub fn new(name: &'static str) -> Self {339 Self(name, Default::default())340 }341}342343impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {344 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {345 if !T::is_void() {346 T::solidity_name(writer, tc)?;347 if !T::is_simple() {348 write!(writer, " memory")?;349 }350 write!(writer, " {}", self.0)351 } else {352 Ok(())353 }354 }355 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {356 writeln!(writer, "\t{prefix}\t{};", self.0)357 }358 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {359 T::solidity_default(writer, tc)360 }361 fn len(&self) -> usize {362 if T::is_void() {363 0364 } else {365 1366 }367 }368}369370pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);371372impl<T> SolidityEventArgument<T> {373 pub fn new(indexed: bool, name: &'static str) -> Self {374 Self(indexed, name, Default::default())375 }376}377378impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {379 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {380 if !T::is_void() {381 T::solidity_name(writer, tc)?;382 if self.0 {383 write!(writer, " indexed")?;384 }385 write!(writer, " {}", self.1)386 } else {387 Ok(())388 }389 }390 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {391 writeln!(writer, "\t{prefix}\t{};", self.1)392 }393 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {394 T::solidity_default(writer, tc)395 }396 fn len(&self) -> usize {397 if T::is_void() {398 0399 } else {400 1401 }402 }403}404405impl SolidityArguments for () {406 fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {407 Ok(())408 }409 fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {410 Ok(())411 }412 fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {413 Ok(())414 }415 fn len(&self) -> usize {416 0417 }418}419420#[impl_for_tuples(1, 12)]421impl SolidityArguments for Tuple {422 for_tuples!( where #( Tuple: SolidityArguments ),* );423424 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {425 let mut first = true;426 for_tuples!( #(427 if !Tuple.is_empty() {428 if !first {429 write!(writer, ", ")?;430 }431 first = false;432 Tuple.solidity_name(writer, tc)?;433 }434 )* );435 Ok(())436 }437 fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {438 for_tuples!( #(439 Tuple.solidity_get(prefix, writer)?;440 )* );441 Ok(())442 }443 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {444 if self.is_empty() {445 Ok(())446 } else if self.len() == 1 {447 for_tuples!( #(448 Tuple.solidity_default(writer, tc)?;449 )* );450 Ok(())451 } else {452 write!(writer, "(")?;453 let mut first = true;454 for_tuples!( #(455 if !Tuple.is_empty() {456 if !first {457 write!(writer, ", ")?;458 }459 first = false;460 Tuple.solidity_default(writer, tc)?;461 }462 )* );463 write!(writer, ")")?;464 Ok(())465 }466 }467 fn len(&self) -> usize {468 for_tuples!( #( Tuple.len() )+* )469 }470}471472pub trait SolidityFunctions {473 fn solidity_name(474 &self,475 is_impl: bool,476 writer: &mut impl fmt::Write,477 tc: &TypeCollector,478 ) -> fmt::Result;479}480481pub enum SolidityMutability {482 Pure,483 View,484 Mutable,485}486pub struct SolidityFunction<A, R> {487 pub docs: &'static [&'static str],488 pub selector: u32,489 pub hide: bool,490 pub custom_signature: SignatureUnit,491 pub name: &'static str,492 pub args: A,493 pub result: R,494 pub mutability: SolidityMutability,495 pub is_payable: bool,496}497impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {498 fn solidity_name(499 &self,500 is_impl: bool,501 writer: &mut impl fmt::Write,502 tc: &TypeCollector,503 ) -> fmt::Result {504 let hide_comment = self.hide.then(|| "// ").unwrap_or("");505 for doc in self.docs {506 writeln!(writer, "\t{hide_comment}///{}", doc)?;507 }508 writeln!(509 writer,510 "\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",511 self.selector512 )?;513 writeln!(514 writer,515 "\t{hide_comment}/// or in textual repr: {}",516 self.custom_signature.as_str().expect("bad utf-8")517 )?;518 write!(writer, "\t{hide_comment}function {}(", self.name)?;519 self.args.solidity_name(writer, tc)?;520 write!(writer, ")")?;521 if is_impl {522 write!(writer, " public")?;523 } else {524 write!(writer, " external")?;525 }526 match &self.mutability {527 SolidityMutability::Pure => write!(writer, " pure")?,528 SolidityMutability::View => write!(writer, " view")?,529 SolidityMutability::Mutable => {}530 }531 if self.is_payable {532 write!(writer, " payable")?;533 }534 if !self.result.is_empty() {535 write!(writer, " returns (")?;536 self.result.solidity_name(writer, tc)?;537 write!(writer, ")")?;538 }539 if is_impl {540 writeln!(writer, " {{")?;541 writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;542 self.args.solidity_get(hide_comment, writer)?;543 match &self.mutability {544 SolidityMutability::Pure => {}545 SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,546 SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,547 }548 if !self.result.is_empty() {549 write!(writer, "\t{hide_comment}\treturn ")?;550 self.result.solidity_default(writer, tc)?;551 writeln!(writer, ";")?;552 }553 writeln!(writer, "\t{hide_comment}}}")?;554 } else {555 writeln!(writer, ";")?;556 }557 if self.hide {558 writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;559 }560 Ok(())561 }562}563564#[impl_for_tuples(0, 48)]565impl SolidityFunctions for Tuple {566 for_tuples!( where #( Tuple: SolidityFunctions ),* );567568 fn solidity_name(569 &self,570 is_impl: bool,571 writer: &mut impl fmt::Write,572 tc: &TypeCollector,573 ) -> fmt::Result {574 let mut first = false;575 for_tuples!( #(576 Tuple.solidity_name(is_impl, writer, tc)?;577 )* );578 Ok(())579 }580}581582pub struct SolidityInterface<F: SolidityFunctions> {583 pub docs: &'static [&'static str],584 pub selector: bytes4,585 pub name: &'static str,586 pub is: &'static [&'static str],587 pub functions: F,588}589590impl<F: SolidityFunctions> SolidityInterface<F> {591 pub fn format(592 &self,593 is_impl: bool,594 out: &mut impl fmt::Write,595 tc: &TypeCollector,596 ) -> fmt::Result {597 const ZERO_BYTES: [u8; 4] = [0; 4];598 for doc in self.docs {599 writeln!(out, "///{}", doc)?;600 }601 if self.selector != ZERO_BYTES {602 writeln!(603 out,604 "/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",605 u32::from_be_bytes(self.selector)606 )?;607 }608 if is_impl {609 write!(out, "contract ")?;610 } else {611 write!(out, "interface ")?;612 }613 write!(out, "{}", self.name)?;614 if !self.is.is_empty() {615 write!(out, " is")?;616 for (i, n) in self.is.iter().enumerate() {617 if i != 0 {618 write!(out, ",")?;619 }620 write!(out, " {}", n)?;621 }622 }623 writeln!(out, " {{")?;624 self.functions.solidity_name(is_impl, out, tc)?;625 writeln!(out, "}}")?;626 Ok(())627 }628}629630pub struct SolidityEvent<A> {631 pub name: &'static str,632 pub args: A,633}634635impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {636 fn solidity_name(637 &self,638 _is_impl: bool,639 writer: &mut impl fmt::Write,640 tc: &TypeCollector,641 ) -> fmt::Result {642 write!(writer, "\tevent {}(", self.name)?;643 self.args.solidity_name(writer, tc)?;644 writeln!(writer, ");")645 }646}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.rsdiffbeforeafterboth--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -24,12 +24,15 @@
weight,
};
use up_data_structs::CollectionMode;
-use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
+use pallet_common::{
+ CollectionHandle,
+ erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
+ eth::EthCrossAccount,
+};
use sp_std::vec::Vec;
use pallet_evm::{account::CrossAccountId, PrecompileHandle};
use pallet_evm_coder_substrate::{call, dispatch_to_evm};
use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use pallet_common::{CollectionHandle, erc::CollectionCall};
use sp_core::Get;
use crate::{
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};