1mod errors;
4mod events;
5mod methods;
6pub(crate) mod structs;
7mod types;
8
9use super::{util, Abigen};
10use crate::contract::{methods::MethodAlias, structs::InternalStructs};
11#[cfg(feature = "providers")]
12use ethers_core::macros::ethers_providers_crate;
13use ethers_core::{
14 abi::{Abi, AbiParser, ErrorExt, EventExt, JsonAbi},
15 macros::{ethers_contract_crate, ethers_core_crate},
16 types::Bytes,
17};
18use eyre::{eyre, Result};
19use proc_macro2::{Ident, Literal, TokenStream};
20use quote::{format_ident, quote};
21use serde::Deserialize;
22use std::collections::BTreeMap;
23use syn::Path;
24
25#[derive(Debug)]
27pub struct ExpandedContract {
28 pub module: Ident,
30 pub imports: TokenStream,
32 pub contract: TokenStream,
34 pub events: TokenStream,
36 pub errors: TokenStream,
38 pub call_structs: TokenStream,
40 pub abi_structs: TokenStream,
42}
43
44impl ExpandedContract {
45 pub fn into_tokens(self) -> TokenStream {
47 self.into_tokens_with_path(None)
48 }
49
50 pub fn into_tokens_with_path(self, path: Option<&std::path::Path>) -> TokenStream {
52 let ExpandedContract {
53 module,
54 imports,
55 contract,
56 events,
57 call_structs,
58 abi_structs,
59 errors,
60 } = self;
61
62 let include_tokens = path.and_then(|path| path.to_str()).map(|s| {
63 quote! {
64 const _: () = { ::core::include_bytes!(#s); };
65 }
66 });
67
68 quote! {
69 pub use #module::*;
70
71 #[allow(
74 clippy::enum_variant_names,
75 clippy::too_many_arguments,
76 clippy::upper_case_acronyms,
77 clippy::type_complexity,
78 dead_code,
79 non_camel_case_types,
80 )]
81 pub mod #module {
82 #imports
83 #include_tokens
84 #contract
85 #errors
86 #events
87 #call_structs
88 #abi_structs
89 }
90 }
91 }
92}
93
94pub struct Context {
96 abi: Abi,
98
99 abi_parser: AbiParser,
101
102 internal_structs: InternalStructs,
104
105 human_readable: bool,
107
108 contract_ident: Ident,
110
111 contract_name: String,
113
114 method_aliases: BTreeMap<String, MethodAlias>,
116
117 error_aliases: BTreeMap<String, Ident>,
119
120 extra_derives: Vec<Path>,
122
123 event_aliases: BTreeMap<String, Ident>,
125
126 contract_bytecode: Option<Bytes>,
128
129 contract_deployed_bytecode: Option<Bytes>,
131}
132
133impl Context {
134 pub fn expand(&self) -> Result<ExpandedContract> {
136 let name_mod = util::ident(&util::safe_module_name(&self.contract_name));
137
138 let struct_decl = self.struct_declaration();
140
141 let events_decl = self.events_declaration()?;
143
144 let (contract_methods, call_structs) = self.methods_and_call_structs()?;
146
147 let abi_structs_decl = self.abi_structs()?;
149
150 let errors_decl = self.errors()?;
152
153 let contract = quote! {
154 #struct_decl
155 };
156
157 #[cfg(feature = "providers")]
158 let contract = {
159 let name = &self.contract_ident;
160 let abi_name = self.inline_abi_ident();
161
162 let contract_events = self.event_methods()?;
164
165 let deployment_methods = self.deployment_methods();
167
168 let ethers_core = ethers_core_crate();
169 let ethers_contract = ethers_contract_crate();
170 let ethers_providers = ethers_providers_crate();
171
172 quote! {
173 #contract
174
175 impl<M: #ethers_providers::Middleware> #name<M> {
176 pub fn new<T: Into<#ethers_core::types::Address>>(address: T, client: ::std::sync::Arc<M>) -> Self {
179 Self(#ethers_contract::Contract::new(address.into(), #abi_name.clone(), client))
180 }
181
182 #deployment_methods
183
184 #contract_methods
185
186 #contract_events
187 }
188
189 impl<M: #ethers_providers::Middleware> From<#ethers_contract::Contract<M>> for #name<M> {
190 fn from(contract: #ethers_contract::Contract<M>) -> Self {
191 Self::new(contract.address(), contract.client())
192 }
193 }
194 }
195 };
196
197 #[cfg(not(feature = "providers"))]
199 let _ = contract_methods;
200
201 Ok(ExpandedContract {
202 module: name_mod,
203 imports: quote!(),
204 contract,
205 events: events_decl,
206 errors: errors_decl,
207 call_structs,
208 abi_structs: abi_structs_decl,
209 })
210 }
211
212 pub fn from_abigen(args: Abigen) -> Result<Self> {
214 let abi_str = args.abi_source.get().map_err(|e| eyre!("failed to get ABI JSON: {e}"))?;
216
217 let mut contract_bytecode = None;
219
220 let mut contract_deployed_bytecode = None;
222
223 let (abi, human_readable, abi_parser) = parse_abi(&abi_str).map_err(|e| {
224 eyre::eyre!("error parsing abi for contract '{}': {e}", args.contract_name)
225 })?;
226
227 let internal_structs = if human_readable {
232 let mut internal_structs = InternalStructs::default();
233 internal_structs
236 .rust_type_names
237 .extend(abi_parser.function_params.values().map(|ty| (ty.clone(), ty.clone())));
238 internal_structs.function_params = abi_parser.function_params.clone();
239 internal_structs.event_params = abi_parser.event_params.clone();
240 internal_structs.outputs = abi_parser.outputs.clone();
241
242 internal_structs
243 } else {
244 match serde_json::from_str::<JsonAbi>(&abi_str)? {
245 JsonAbi::Object(obj) => {
246 contract_bytecode = obj.bytecode;
247 contract_deployed_bytecode = obj.deployed_bytecode;
248 InternalStructs::new(obj.abi)
249 }
250 JsonAbi::Array(abi) => InternalStructs::new(abi),
251 }
252 };
253
254 let mut method_aliases = BTreeMap::new();
258 for (signature, alias) in args.method_aliases.into_iter() {
259 let alias = MethodAlias {
260 function_name: util::safe_ident(&alias),
261 struct_name: util::safe_pascal_case_ident(&alias),
262 };
263
264 if method_aliases.insert(signature.clone(), alias).is_some() {
265 eyre::bail!("duplicate method signature {signature:?} in method aliases")
266 }
267 }
268
269 let mut event_aliases = BTreeMap::new();
270 for (signature, alias) in args.event_aliases.into_iter() {
271 let alias = syn::parse_str(&alias)?;
272 event_aliases.insert(signature, alias);
273 }
274
275 for events in abi.events.values() {
278 insert_alias_names(
279 &mut event_aliases,
280 events.iter().map(|e| (e.abi_signature(), e.name.as_str())),
281 events::event_struct_alias,
282 );
283 }
284
285 let mut error_aliases = BTreeMap::new();
286 for (signature, alias) in args.error_aliases.into_iter() {
287 let alias = syn::parse_str(&alias)?;
288 error_aliases.insert(signature, alias);
289 }
290
291 for errors in abi.errors.values() {
294 insert_alias_names(
295 &mut error_aliases,
296 errors.iter().map(|e| (e.abi_signature(), e.name.as_str())),
297 errors::error_struct_alias,
298 );
299 }
300
301 Ok(Self {
302 abi,
303 human_readable,
304 abi_parser,
305 internal_structs,
306 contract_name: args.contract_name.to_string(),
307 contract_ident: args.contract_name,
308 contract_bytecode,
309 contract_deployed_bytecode,
310 method_aliases,
311 error_aliases: Default::default(),
312 event_aliases,
313 extra_derives: args.derives,
314 })
315 }
316
317 pub(crate) fn contract_name(&self) -> &str {
319 &self.contract_name
320 }
321
322 pub(crate) fn inline_abi_ident(&self) -> Ident {
324 format_ident!("{}_ABI", self.contract_name.to_uppercase())
325 }
326
327 pub(crate) fn inline_bytecode_ident(&self) -> Ident {
329 format_ident!("{}_BYTECODE", self.contract_name.to_uppercase())
330 }
331
332 pub(crate) fn inline_deployed_bytecode_ident(&self) -> Ident {
334 format_ident!("{}_DEPLOYED_BYTECODE", self.contract_name.to_uppercase())
335 }
336
337 pub fn internal_structs(&self) -> &InternalStructs {
339 &self.internal_structs
340 }
341
342 pub fn internal_structs_mut(&mut self) -> &mut InternalStructs {
344 &mut self.internal_structs
345 }
346
347 pub(crate) fn expand_extra_derives(&self) -> TokenStream {
350 let extra_derives = &self.extra_derives;
351 quote!(#( #extra_derives, )*)
352 }
353
354 pub(crate) fn struct_declaration(&self) -> TokenStream {
356 let ethers_core = ethers_core_crate();
357 let ethers_contract = ethers_contract_crate();
358
359 let abi = {
360 let doc_str = if self.human_readable {
361 "The parsed human-readable ABI of the contract."
362 } else {
363 "The parsed JSON ABI of the contract."
364 };
365 let abi_name = self.inline_abi_ident();
366 let abi = crate::verbatim::generate(&self.abi, ðers_core);
367 quote! {
368 #[allow(deprecated)]
369 fn __abi() -> #ethers_core::abi::Abi {
370 #abi
371 }
372
373 #[doc = #doc_str]
374 pub static #abi_name: #ethers_contract::Lazy<#ethers_core::abi::Abi> =
375 #ethers_contract::Lazy::new(__abi);
376 }
377 };
378
379 let bytecode = self.contract_bytecode.as_ref().map(|bytecode| {
380 let bytecode = Literal::byte_string(bytecode);
381 let bytecode_name = self.inline_bytecode_ident();
382 quote! {
383 #[rustfmt::skip]
384 const __BYTECODE: &[u8] = #bytecode;
385
386 pub static #bytecode_name: #ethers_core::types::Bytes =
388 #ethers_core::types::Bytes::from_static(__BYTECODE);
389 }
390 });
391
392 let deployed_bytecode = self.contract_deployed_bytecode.as_ref().map(|bytecode| {
393 let bytecode = Literal::byte_string(bytecode);
394 let bytecode_name = self.inline_deployed_bytecode_ident();
395 quote! {
396 #[rustfmt::skip]
397 const __DEPLOYED_BYTECODE: &[u8] = #bytecode;
398
399 pub static #bytecode_name: #ethers_core::types::Bytes =
401 #ethers_core::types::Bytes::from_static(__DEPLOYED_BYTECODE);
402 }
403 });
404
405 let code = quote! {
406 #abi
408
409 #bytecode
411
412 #deployed_bytecode
414 };
415
416 #[cfg(feature = "providers")]
417 let code = {
418 let name = &self.contract_ident;
419
420 quote! {
421 #code
422
423 pub struct #name<M>(#ethers_contract::Contract<M>);
425
426 impl<M> ::core::clone::Clone for #name<M> {
428 fn clone(&self) -> Self {
429 Self(::core::clone::Clone::clone(&self.0))
430 }
431 }
432
433 impl<M> ::core::ops::Deref for #name<M> {
435 type Target = #ethers_contract::Contract<M>;
436
437 fn deref(&self) -> &Self::Target {
438 &self.0
439 }
440 }
441
442 impl<M> ::core::ops::DerefMut for #name<M> {
443 fn deref_mut(&mut self) -> &mut Self::Target {
444 &mut self.0
445 }
446 }
447
448 impl<M> ::core::fmt::Debug for #name<M> {
450 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
451 f.debug_tuple(::core::stringify!(#name))
452 .field(&self.address())
453 .finish()
454 }
455 }
456 }
457 };
458
459 code
460 }
461}
462
463fn insert_alias_names<'a, I, F>(aliases: &mut BTreeMap<String, Ident>, elements: I, get_ident: F)
472where
473 I: IntoIterator<Item = (String, &'a str)>,
474 F: Fn(&str) -> Ident,
475{
476 let not_aliased =
477 elements.into_iter().filter(|(sig, _name)| !aliases.contains_key(sig)).collect::<Vec<_>>();
478 if not_aliased.len() > 1 {
479 let mut overloaded_aliases = Vec::new();
480 for (idx, (sig, name)) in not_aliased.into_iter().enumerate() {
481 let unique_name = format!("{name}{}", idx + 1);
482 overloaded_aliases.push((sig, get_ident(&unique_name)));
483 }
484 aliases.extend(overloaded_aliases);
485 }
486}
487
488fn parse_abi(abi_str: &str) -> Result<(Abi, bool, AbiParser)> {
490 let mut abi_parser = AbiParser::default();
491 match abi_parser.parse_str(abi_str) {
492 Ok(abi) => Ok((abi, true, abi_parser)),
493 Err(e) => match serde_json::from_str::<JsonContract>(abi_str) {
494 Ok(contract) => Ok((contract.into_abi(), false, abi_parser)),
495 Err(e2) => Err(eyre::eyre!(
496 "couldn't parse ABI string as either human readable (1) or JSON (2):\n1. {e}\n2. {e2}"
497 )),
498 },
499 }
500}
501
502#[derive(Deserialize)]
503struct ContractObject {
504 abi: Abi,
505}
506
507#[derive(Deserialize)]
508#[serde(untagged)]
509enum JsonContract {
510 Object(ContractObject),
512 Array(Abi),
514}
515
516impl JsonContract {
517 fn into_abi(self) -> Abi {
518 match self {
519 JsonContract::Object(o) => o.abi,
520 JsonContract::Array(abi) => abi,
521 }
522 }
523}