--- a/crates/evm-coder-macros/src/lib.rs +++ b/crates/evm-coder-macros/src/lib.rs @@ -22,7 +22,7 @@ use sha3::{Digest, Keccak256}; use syn::{ DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments, - PathSegment, Type, parse_macro_input, spanned::Spanned, Attribute, parse::Parse, + PathSegment, Type, parse_macro_input, spanned::Spanned, }; mod solidity_interface; @@ -241,7 +241,7 @@ /// Event(#[indexed] uint32), /// } /// -/// #[solidity_interface(name = "MyContract", is(SuperContract), inline_is(InlineContract))] +/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))] /// impl Contract { /// /// Multiply two numbers /// #[weight(200 + a + b)] --- a/crates/evm-coder-macros/src/solidity_interface.rs +++ b/crates/evm-coder-macros/src/solidity_interface.rs @@ -989,26 +989,24 @@ #solidity_functions, )*), }; - if is_impl { - tc.collect("/// @dev common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into()); - } else { - tc.collect("/// @dev common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into()); - } - #( - #solidity_generators - )* - #( - #solidity_event_generators - )* let mut out = string::new(); - // In solidity interface usage (is) should be preceeded by interface definition - // HACK: this comment helps to sort it in a set if #solidity_name.starts_with("Inline") { out.push_str("/// @dev inlined interface\n"); } let _ = interface.format(is_impl, &mut out, tc); tc.collect(out); + #( + #solidity_event_generators + )* + #( + #solidity_generators + )* + if is_impl { + tc.collect("/// @dev common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n".into()); + } else { + tc.collect("/// @dev common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n".into()); + } } } impl #gen_ref ::evm_coder::Call for #call_name #gen_ref { --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity.rs @@ -14,26 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . +//! Implementation detail of [`evm_coder::solidity_interface`] macro code-generation + #[cfg(not(feature = "std"))] use alloc::{ string::String, vec::Vec, - collections::{BTreeSet, BTreeMap}, + collections::BTreeMap, format, }; #[cfg(feature = "std")] -use std::collections::{BTreeSet, BTreeMap}; +use std::collections::BTreeMap; use core::{ fmt::{self, Write}, marker::PhantomData, cell::{Cell, RefCell}, + cmp::Reverse, }; use impl_trait_for_tuples::impl_for_tuples; use crate::types::*; #[derive(Default)] pub struct TypeCollector { - structs: RefCell>, + /// Code => id + /// id ordering is required to perform topo-sort on the resulting data + structs: RefCell>, anonymous: RefCell, usize>>, id: Cell, } @@ -42,7 +47,8 @@ Self::default() } pub fn collect(&self, item: string) { - self.structs.borrow_mut().insert(item); + let id = self.next_id(); + self.structs.borrow_mut().insert(item, id); } pub fn next_id(&self) -> usize { let v = self.id.get(); @@ -66,8 +72,10 @@ self.anonymous.borrow_mut().insert(names, id); format!("Tuple{}", id) } - pub fn finish(self) -> BTreeSet { - self.structs.into_inner() + pub fn finish(self) -> Vec { + let mut data = self.structs.into_inner().into_iter().collect::>(); + data.sort_by_key(|(_, id)| Reverse(*id)); + data.into_iter().map(|(code, _)| code).collect() } }