Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

feat(abigen): include ethevent proc macro in abigen code gen workflow #232

Merged
25 changes: 14 additions & 11 deletions ethers-contract/ethers-contract-abigen/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
mod common;
mod events;
mod methods;
mod structs;
mod types;

use super::util;
use super::Abigen;
use anyhow::{anyhow, Context as _, Result};
use ethers_core::abi::AbiParser;
use ethers_core::{
abi::{parse_abi, Abi},
types::Address,
Expand All @@ -25,6 +27,9 @@ pub(crate) struct Context {
/// The parsed ABI.
abi: Abi,

/// The parser used for human readable format
abi_parser: AbiParser,

/// Was the ABI in human readable format?
human_readable: bool,

Expand Down Expand Up @@ -59,11 +64,14 @@ impl Context {
let events_decl = cx.events_declaration()?;

// 3. impl block for the event functions
let contract_events = cx.events()?;
let contract_events = cx.event_methods()?;

// 4. impl block for the contract methods
let contract_methods = cx.methods()?;

// 5. Declare the structs parsed from the human readable abi
let abi_structs_decl = cx.abi_structs()?;

Ok(quote! {
// export all the created data types
pub use #name_mod::*;
Expand Down Expand Up @@ -91,6 +99,8 @@ impl Context {
}

#events_decl

#abi_structs_decl
}
})
}
Expand All @@ -99,22 +109,14 @@ impl Context {
fn from_abigen(args: Abigen) -> Result<Self> {
// get the actual ABI string
let abi_str = args.abi_source.get().context("failed to get ABI JSON")?;
let mut abi_parser = AbiParser::default();
// parse it
let (abi, human_readable): (Abi, _) = if let Ok(abi) = serde_json::from_str(&abi_str) {
// normal abi format
(abi, false)
} else {
// heuristic for parsing the human readable format

// replace bad chars
let abi_str = abi_str.replace('[', "").replace(']', "");
// split lines and get only the non-empty things
let split: Vec<&str> = abi_str
.split('\n')
.map(|x| x.trim())
.filter(|x| !x.is_empty())
.collect();
(parse_abi(&split)?, true)
(abi_parser.parse_str(&abi_str)?, true)
};

let contract_name = util::ident(&args.contract_name);
Expand Down Expand Up @@ -144,6 +146,7 @@ impl Context {
abi,
human_readable,
abi_str: Literal::string(&abi_str),
abi_parser,
contract_name,
method_aliases,
event_derives,
Expand Down
15 changes: 4 additions & 11 deletions ethers-contract/ethers-contract-abigen/src/contract/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) fn imports(name: &str) -> TokenStream {
use std::sync::Arc;
use ethers::{
core::{
abi::{Abi, Token, Detokenize, InvalidOutputType, Tokenizable, parse_abi},
abi::{Abi, Token, Detokenize, InvalidOutputType, Tokenizable},
types::*, // import all the types so that we can codegen for everything
},
contract::{Contract, builders::{ContractCall, Event}, Lazy},
Expand All @@ -24,6 +24,7 @@ pub(crate) fn imports(name: &str) -> TokenStream {
}
}

/// Generates the static `Abi` constants and the contract struct
pub(crate) fn struct_declaration(cx: &Context, abi_name: &proc_macro2::Ident) -> TokenStream {
let name = &cx.contract_name;
let abi = &cx.abi_str;
Expand All @@ -35,16 +36,8 @@ pub(crate) fn struct_declaration(cx: &Context, abi_name: &proc_macro2::Ident) ->
}
} else {
quote! {
pub static #abi_name: Lazy<Abi> = Lazy::new(|| {
let abi_str = #abi.replace('[', "").replace(']', "");
// split lines and get only the non-empty things
let split: Vec<&str> = abi_str
.split("\n")
.map(|x| x.trim())
.filter(|x| !x.is_empty())
.collect();
parse_abi(&split).expect("invalid abi")
});
pub static #abi_name: Lazy<Abi> = Lazy::new(|| ethers::core::abi::parse_abi_str(#abi)
.expect("invalid abi"));
}
};

Expand Down
Loading