1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::{env, fs::read_to_string, path::PathBuf};
use ethbind_rust::{BindingBuilder, JsonRuntimeBinder, RustGenerator, ToTokenStream};
use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::quote;
use syn::{parse::Parse, parse_macro_input, LitStr, Token};
struct Contract {
pub contract_name: Option<String>,
pub type_mapping: String,
pub abi_data: String,
}
impl Parse for Contract {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let contract_name: Option<Ident> = input.parse()?;
if contract_name.is_some() {
input.parse::<Token!(,)>()?;
}
let type_mapping: LitStr = input.parse()?;
input.parse::<Token!(,)>()?;
let abi_data: LitStr = input.parse()?;
Ok(Self {
contract_name: contract_name.map(|c| c.to_string()),
type_mapping: type_mapping.value(),
abi_data: abi_data.value(),
})
}
}
mod contract {
syn::custom_keyword!(hardhat);
}
fn load_json_file(path: &str) -> String {
let dir = env::var("CARGO_MANIFEST_DIR").expect("Find CARGO_MANIFEST_DIR");
let path = PathBuf::from(dir).join(path);
read_to_string(path.clone()).expect(&format!("Read json file: {:?}", path))
}
#[proc_macro]
pub fn contract(item: TokenStream) -> TokenStream {
let contract = parse_macro_input!(item as Contract);
let type_mapping: JsonRuntimeBinder = load_json_file(&contract.type_mapping)
.parse()
.expect("Parse mapping data");
let abi_data = load_json_file(&contract.abi_data);
let generator = if let Some(contract_name) = contract.contract_name {
BindingBuilder::new((RustGenerator::default(), type_mapping))
.bind(&contract_name, abi_data)
.finalize()
.expect("Generate contract/abi binding code")
} else {
BindingBuilder::new((RustGenerator::default(), type_mapping))
.bind_hardhat(abi_data)
.finalize()
.expect("Generate contract/abi binding code")
};
let contracts = generator.to_token_streams().expect("To token streams");
quote!(#(#contracts)*).into()
}