1use super::{structs::expand_struct, types, Context};
4use crate::util;
5use ethers_core::{
6 abi::{Function, FunctionExt, Param, ParamType},
7 macros::{ethers_contract_crate, ethers_core_crate},
8 types::Selector,
9};
10use eyre::{Context as _, Result};
11use inflector::Inflector;
12use proc_macro2::{Literal, TokenStream};
13use quote::quote;
14use std::collections::{btree_map::Entry, BTreeMap, HashMap, HashSet};
15use syn::Ident;
16
17const NAME_ALIASING_OVERLOADED_FUNCTIONS_CAP: usize = 3;
21
22impl Context {
25 pub(crate) fn methods_and_call_structs(&self) -> Result<(TokenStream, TokenStream)> {
27 let aliases = self.get_method_aliases()?;
28 let sorted_functions: BTreeMap<_, _> = self.abi.functions.iter().collect();
29 let functions = sorted_functions
30 .values()
31 .flat_map(std::ops::Deref::deref)
32 .map(|function| {
33 let signature = function.abi_signature();
34 self.expand_function(function, aliases.get(&signature).cloned())
35 .wrap_err_with(|| eyre::eyre!("error expanding function '{signature}'"))
36 })
37 .collect::<Result<Vec<_>>>()?;
38
39 let function_impls = quote! { #( #functions )* };
40 let call_structs = self.expand_call_structs(aliases.clone())?;
41 let return_structs = self.expand_return_structs(aliases)?;
42
43 let all_structs = quote! {
44 #call_structs
45 #return_structs
46 };
47
48 Ok((function_impls, all_structs))
49 }
50
51 #[cfg(feature = "providers")]
53 pub(crate) fn deployment_methods(&self) -> Option<TokenStream> {
54 self.contract_bytecode.as_ref()?;
56
57 let ethers_core = ethers_core_crate();
58 let ethers_contract = ethers_contract_crate();
59
60 let abi_name = self.inline_abi_ident();
61 let get_abi = quote! {
62 #abi_name.clone()
63 };
64
65 let bytecode_name = self.inline_bytecode_ident();
66 let get_bytecode = quote! {
67 #bytecode_name.clone().into()
68 };
69
70 Some(quote! {
71 pub fn deploy<T: #ethers_core::abi::Tokenize>(
95 client: ::std::sync::Arc<M>,
96 constructor_args: T,
97 ) -> ::core::result::Result<#ethers_contract::builders::ContractDeployer<M, Self>, #ethers_contract::ContractError<M>> {
98 let factory = #ethers_contract::ContractFactory::new(#get_abi, #get_bytecode, client);
99 let deployer = factory.deploy(constructor_args)?;
100 let deployer = #ethers_contract::ContractDeployer::new(deployer);
101 Ok(deployer)
102 }
103 })
104 }
105
106 fn expand_call_struct(
108 &self,
109 function: &Function,
110 alias: Option<&MethodAlias>,
111 ) -> Result<TokenStream> {
112 let struct_name = expand_call_struct_name(function, alias);
113
114 let fields = self.expand_input_params(function)?;
115 let all_anonymous_fields = function.inputs.iter().all(|input| input.name.is_empty());
117 let call_type_definition = expand_struct(&struct_name, &fields, all_anonymous_fields);
118
119 let function_name = &function.name;
120 let abi_signature = function.abi_signature();
121 let doc_str = format!(
122 "Container type for all input parameters for the `{function_name}` function with signature `{abi_signature}` and selector `0x{}`",
123 hex::encode(function.selector())
124 );
125
126 let mut derives = self.expand_extra_derives();
127 let params = function.inputs.iter().map(|param| ¶m.kind);
128 util::derive_builtin_traits(params, &mut derives, true, true);
129
130 let ethers_contract = ethers_contract_crate();
131
132 Ok(quote! {
133 #[doc = #doc_str]
134 #[derive(Clone, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)]
135 #[ethcall( name = #function_name, abi = #abi_signature )]
136 pub #call_type_definition
137 })
138 }
139
140 pub fn expand_return_struct(
142 &self,
143 function: &Function,
144 alias: Option<&MethodAlias>,
145 ) -> Result<Option<TokenStream>> {
146 if function.outputs.is_empty() {
148 return Ok(None)
149 }
150
151 let name = &function.name;
152
153 let struct_name = expand_return_struct_name(function, alias);
154 let fields = self.expand_output_params(function)?;
155 let all_anonymous_fields = function.outputs.iter().all(|output| output.name.is_empty());
157 let return_type_definition = expand_struct(&struct_name, &fields, all_anonymous_fields);
158
159 let abi_signature = function.abi_signature();
160 let doc_str = format!(
161 "Container type for all return fields from the `{name}` function with signature `{abi_signature}` and selector `0x{}`",
162 hex::encode(function.selector())
163 );
164
165 let mut derives = self.expand_extra_derives();
166 let params = function.outputs.iter().map(|param| ¶m.kind);
167 util::derive_builtin_traits(params, &mut derives, true, true);
168
169 let ethers_contract = ethers_contract_crate();
170
171 Ok(Some(quote! {
172 #[doc = #doc_str]
173 #[derive(Clone, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
174 pub #return_type_definition
175 }))
176 }
177
178 fn expand_call_structs(&self, aliases: BTreeMap<String, MethodAlias>) -> Result<TokenStream> {
180 let len = self.abi.functions.len();
181 let mut struct_defs = Vec::with_capacity(len);
182 let mut struct_names = Vec::with_capacity(len);
183 let mut variant_names = Vec::with_capacity(len);
184 for function in self.abi.functions.values().flatten() {
185 let signature = function.abi_signature();
186 let alias = aliases.get(&signature);
187 struct_defs.push(self.expand_call_struct(function, alias)?);
188 struct_names.push(expand_call_struct_name(function, alias));
189 variant_names.push(expand_call_struct_variant_name(function, alias));
190 }
191
192 let struct_def_tokens = quote!(#(#struct_defs)*);
193
194 if struct_defs.len() <= 1 {
195 return Ok(struct_def_tokens)
197 }
198
199 let mut derives = self.expand_extra_derives();
200 let params =
201 self.abi.functions.values().flatten().flat_map(|f| &f.inputs).map(|param| ¶m.kind);
202 util::derive_builtin_traits(params, &mut derives, false, true);
203
204 let enum_name = self.expand_calls_enum_name();
205
206 let ethers_core = ethers_core_crate();
207 let ethers_contract = ethers_contract_crate();
208
209 let tokens = quote! {
210 #struct_def_tokens
211
212 #[doc = "Container type for all of the contract's call "]
213 #[derive(Clone, #ethers_contract::EthAbiType, #derives)]
214 pub enum #enum_name {
215 #( #variant_names(#struct_names), )*
216 }
217
218 impl #ethers_core::abi::AbiDecode for #enum_name {
219 fn decode(data: impl AsRef<[u8]>) -> ::core::result::Result<Self, #ethers_core::abi::AbiError> {
220 let data = data.as_ref();
221 #(
222 if let Ok(decoded) = <#struct_names as #ethers_core::abi::AbiDecode>::decode(data) {
223 return Ok(Self::#variant_names(decoded))
224 }
225 )*
226 Err(#ethers_core::abi::Error::InvalidData.into())
227 }
228 }
229
230 impl #ethers_core::abi::AbiEncode for #enum_name {
231 fn encode(self) -> Vec<u8> {
232 match self {
233 #(
234 Self::#variant_names(element) => #ethers_core::abi::AbiEncode::encode(element),
235 )*
236 }
237 }
238 }
239
240 impl ::core::fmt::Display for #enum_name {
241 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
242 match self {
243 #(
244 Self::#variant_names(element) => ::core::fmt::Display::fmt(element, f),
245 )*
246 }
247 }
248 }
249
250 #(
251 impl ::core::convert::From<#struct_names> for #enum_name {
252 fn from(value: #struct_names) -> Self {
253 Self::#variant_names(value)
254 }
255 }
256 )*
257 };
258
259 Ok(tokens)
260 }
261
262 fn expand_return_structs(&self, aliases: BTreeMap<String, MethodAlias>) -> Result<TokenStream> {
264 let mut tokens = TokenStream::new();
265 for function in self.abi.functions.values().flatten() {
266 let signature = function.abi_signature();
267 let alias = aliases.get(&signature);
268 match self.expand_return_struct(function, alias) {
269 Ok(Some(def)) => tokens.extend(def),
270 Ok(None) => {}
271 Err(e) => return Err(e),
272 }
273 }
274 Ok(tokens)
275 }
276
277 fn expand_calls_enum_name(&self) -> Ident {
279 util::ident(&format!("{}Calls", self.contract_ident))
280 }
281
282 fn expand_input_params(&self, fun: &Function) -> Result<Vec<(TokenStream, TokenStream)>> {
284 types::expand_params(&fun.inputs, |p| {
285 self.internal_structs.get_function_input_struct_type(&fun.name, &p.name)
286 })
287 }
288
289 fn expand_output_params(&self, fun: &Function) -> Result<Vec<(TokenStream, TokenStream)>> {
291 types::expand_params(&fun.outputs, |p| {
292 p.internal_type
293 .as_deref()
294 .and_then(|s| self.internal_structs.get_function_output_struct_type(&fun.name, s))
295 })
296 }
297
298 fn expand_contract_call_args(&self, fun: &Function) -> TokenStream {
300 let mut call_args = fun.inputs.iter().enumerate().map(|(idx, param)| {
301 let name = util::expand_input_name(idx, ¶m.name);
302 match param.kind {
303 ParamType::Tuple(_) if fun.inputs.len() == 1 => {
311 quote!((#name,))
313 }
314 _ => name,
315 }
316 });
317
318 match fun.inputs.len() {
319 0 => quote!(()),
320 1 => call_args.next().unwrap(),
321 _ => quote!(( #( #call_args ),* )),
322 }
323 }
324
325 fn expand_function(
327 &self,
328 function: &Function,
329 alias: Option<MethodAlias>,
330 ) -> Result<TokenStream> {
331 let name = &function.name;
332 let function_name = expand_function_name(function, alias.as_ref());
333 let selector = function.selector();
334
335 let selector_tokens = expand_selector(selector);
336
337 let contract_args = self.expand_contract_call_args(function);
338 let function_params =
339 self.expand_input_params(function)?.into_iter().map(|(name, ty)| quote! { #name: #ty });
340 let function_params = quote! { #( , #function_params )* };
341
342 let outputs = {
343 let mut out = self.expand_output_params(function)?;
344 match out.len() {
345 0 => quote!(()),
346 1 => out.pop().unwrap().1,
347 _ => {
348 let iter = out.into_iter().map(|(_, ty)| ty);
349 quote!(( #( #iter ),* ))
350 }
351 }
352 };
353
354 let doc_str =
355 format!("Calls the contract's `{name}` (0x{}) function", hex::encode(selector));
356
357 let ethers_contract = ethers_contract_crate();
358
359 Ok(quote! {
360 #[doc = #doc_str]
361 pub fn #function_name(&self #function_params) -> #ethers_contract::builders::ContractCall<M, #outputs> {
362 self.0.method_hash(#selector_tokens, #contract_args)
363 .expect("method not found (this should never happen)")
364 }
365 })
366 }
367
368 fn get_method_aliases(&self) -> Result<BTreeMap<String, MethodAlias>> {
378 let mut aliases = self.method_aliases.clone();
379
380 let mut all_functions = HashMap::new();
383 for function in self.abi.functions() {
384 all_functions
385 .entry(util::safe_snake_case_ident(&function.name))
386 .or_insert_with(Vec::new)
387 .push(function);
388 }
389
390 for functions in all_functions.values() {
392 if functions.iter().filter(|f| !aliases.contains_key(&f.abi_signature())).count() <= 1 {
393 continue
395 }
396
397 let num_functions = functions.len();
398 let mut functions = functions.iter().enumerate().collect::<Vec<_>>();
400 functions.sort_by(|(_, f1), (_, f2)| f1.inputs.len().cmp(&f2.inputs.len()));
401
402 for (idx, (f_idx, _)) in functions.iter_mut().enumerate() {
405 *f_idx = idx;
406 }
407
408 let (first_fun_idx, first_fun) = functions[0];
411
412 let mut needs_alias_for_first_fun_using_idx = false;
416
417 let mut diffs = Vec::new();
419
420 fn name_conflicts(idx: usize, diffs: &[(usize, Vec<&Param>, &&Function)]) -> bool {
422 let diff = &diffs.iter().find(|(i, _, _)| *i == idx).expect("diff exists").1;
423
424 for (_, other, _) in diffs.iter().filter(|(i, _, _)| *i != idx) {
425 let (a, b) =
426 if other.len() > diff.len() { (other, diff) } else { (diff, other) };
427
428 if a.iter()
429 .all(|d| b.iter().any(|o| o.name.to_snake_case() == d.name.to_snake_case()))
430 {
431 return true
432 }
433 }
434 false
435 }
436 for (idx, overloaded_fun) in functions.into_iter().skip(1) {
438 let mut already_matched_param_diff = HashSet::new();
440 let mut diff = Vec::new();
442 let mut same_params = true;
443 for (idx, i1) in overloaded_fun.inputs.iter().enumerate() {
444 if let Some((pos, _)) = first_fun
446 .inputs
447 .iter()
448 .enumerate()
449 .filter(|(pos, _)| !already_matched_param_diff.contains(pos))
450 .find(|(_, i2)| i1 != *i2)
451 {
452 already_matched_param_diff.insert(pos);
453 diff.push(i1);
454 same_params = false;
455 } else {
456 if same_params && idx + 1 > first_fun.inputs.len() {
459 diff.push(i1);
460 }
461 }
462 }
463 diffs.push((idx, diff, overloaded_fun));
464 }
465
466 for (idx, diff, overloaded_fun) in &diffs {
467 let alias = match diff.len() {
468 0 => {
469 eyre::ensure!(
475 overloaded_fun.name != first_fun.name,
476 "Function with same name and parameter types defined twice: {}",
477 overloaded_fun.name
478 );
479
480 let overloaded_id = overloaded_fun.name.to_snake_case();
481 let first_fun_id = first_fun.name.to_snake_case();
482 if first_fun_id != overloaded_id {
483 overloaded_id
485 } else {
486 let overloaded_alias = MethodAlias {
487 function_name: util::safe_ident(&overloaded_fun.name),
488 struct_name: util::safe_ident(&overloaded_fun.name),
489 };
490 aliases.insert(overloaded_fun.abi_signature(), overloaded_alias);
491
492 let first_fun_alias = MethodAlias {
493 function_name: util::safe_ident(&first_fun.name),
494 struct_name: util::safe_ident(&first_fun.name),
495 };
496 aliases.insert(first_fun.abi_signature(), first_fun_alias);
497 continue
498 }
499 }
500 1 => {
501 if diff[0].name.is_empty() ||
503 num_functions > NAME_ALIASING_OVERLOADED_FUNCTIONS_CAP ||
504 name_conflicts(*idx, &diffs)
505 {
506 needs_alias_for_first_fun_using_idx = true;
507 format!("{}{idx}", overloaded_fun.name.to_snake_case())
508 } else {
509 format!(
510 "{}_with_{}",
511 overloaded_fun.name.to_snake_case(),
512 diff[0].name.to_snake_case()
513 )
514 }
515 }
516 _ => {
517 if diff.iter().any(|d| d.name.is_empty()) ||
518 num_functions > NAME_ALIASING_OVERLOADED_FUNCTIONS_CAP ||
519 name_conflicts(*idx, &diffs)
520 {
521 needs_alias_for_first_fun_using_idx = true;
522 format!("{}{idx}", overloaded_fun.name.to_snake_case())
523 } else {
524 let and = diff
526 .iter()
527 .skip(1)
528 .map(|i| i.name.to_snake_case())
529 .collect::<Vec<_>>()
530 .join("_and_");
531 format!(
532 "{}_with_{}_and_{}",
533 overloaded_fun.name.to_snake_case(),
534 diff[0].name.to_snake_case(),
535 and
536 )
537 }
538 }
539 };
540 let alias = MethodAlias::new(&alias);
541 aliases.insert(overloaded_fun.abi_signature(), alias);
542 }
543
544 if needs_alias_for_first_fun_using_idx {
545 let prev_alias = format!("{}{first_fun_idx}", first_fun.name.to_snake_case());
547
548 let alias = MethodAlias::new(&prev_alias);
549
550 aliases.insert(first_fun.abi_signature(), alias);
551 }
552 }
553
554 for (name, functions) in self.abi.functions.iter() {
559 if name.starts_with('_') || name.ends_with('_') {
560 let ident = name.trim_matches('_').trim_end_matches('_');
561 if self.abi.functions.contains_key(ident) {
563 for function in functions {
564 if let Entry::Vacant(entry) = aliases.entry(function.abi_signature()) {
565 entry.insert(MethodAlias::new(name.as_str()));
567 }
568 }
569 }
570 }
571 }
572 Ok(aliases)
573 }
574}
575
576fn expand_selector(selector: Selector) -> TokenStream {
577 let bytes = selector.iter().copied().map(Literal::u8_unsuffixed);
578 quote!([ #( #bytes ),* ])
579}
580
581#[derive(Debug, Clone)]
583pub struct MethodAlias {
584 pub function_name: Ident,
585 pub struct_name: Ident,
586}
587
588impl MethodAlias {
589 pub fn new(alias: &str) -> Self {
590 MethodAlias {
591 function_name: util::safe_snake_case_ident(alias),
592 struct_name: util::safe_pascal_case_ident(alias),
593 }
594 }
595}
596
597fn expand_function_name(function: &Function, alias: Option<&MethodAlias>) -> Ident {
598 if let Some(alias) = alias {
599 alias.function_name.clone()
600 } else {
601 util::safe_ident(&util::safe_snake_case(&function.name))
602 }
603}
604
605fn expand_struct_name_postfix(
607 function: &Function,
608 alias: Option<&MethodAlias>,
609 postfix: &str,
610) -> Ident {
611 let name = if let Some(alias) = alias {
612 format!("{}{postfix}", alias.struct_name)
613 } else {
614 format!("{}{postfix}", util::safe_pascal_case(&function.name))
615 };
616 util::ident(&name)
617}
618
619fn expand_call_struct_name(function: &Function, alias: Option<&MethodAlias>) -> Ident {
621 expand_struct_name_postfix(function, alias, "Call")
622}
623
624fn expand_return_struct_name(function: &Function, alias: Option<&MethodAlias>) -> Ident {
626 expand_struct_name_postfix(function, alias, "Return")
627}
628
629fn expand_call_struct_variant_name(function: &Function, alias: Option<&MethodAlias>) -> Ident {
631 if let Some(alias) = alias {
632 alias.struct_name.clone()
633 } else {
634 util::safe_ident(&util::safe_pascal_case(&function.name))
635 }
636}
637
638#[cfg(test)]
639mod tests {
640 use super::*;
641
642 fn expand_fn_outputs(outputs: &[Param]) -> Result<TokenStream> {
643 match outputs.len() {
644 0 => Ok(quote! { () }),
645 1 => types::expand(&outputs[0].kind),
646 _ => {
647 let types = outputs
648 .iter()
649 .map(|param| types::expand(¶m.kind))
650 .collect::<Result<Vec<_>>>()?;
651 Ok(quote! { (#( #types ),*) })
652 }
653 }
654 }
655
656 fn expand_inputs_call_arg(inputs: &[Param]) -> TokenStream {
658 let names = inputs
659 .iter()
660 .enumerate()
661 .map(|(i, param)| {
662 let name = util::expand_input_name(i, ¶m.name);
663 match param.kind {
664 ParamType::Tuple(_) if inputs.len() == 1 => {
672 quote! {(#name,)}
674 }
675 _ => name,
676 }
677 })
678 .collect::<Vec<TokenStream>>();
679 match names.len() {
680 0 => quote! { () },
681 1 => quote! { #( #names )* },
682 _ => quote! { ( #(#names, )* ) },
683 }
684 }
685
686 fn expand_inputs(inputs: &[Param]) -> Result<TokenStream> {
688 let params = inputs
689 .iter()
690 .enumerate()
691 .map(|(i, param)| {
692 let name = util::expand_input_name(i, ¶m.name);
693 let kind = types::expand(¶m.kind)?;
694 Ok(quote! { #name: #kind })
695 })
696 .collect::<Result<Vec<_>>>()?;
697 Ok(quote! { #( , #params )* })
698 }
699
700 #[test]
701 fn test_expand_inputs_call_arg() {
702 let params = vec![];
704 let token_stream = expand_inputs_call_arg(¶ms);
705 assert_eq!(token_stream.to_string(), "()");
706
707 let params = vec![Param {
709 name: "arg_a".to_string(),
710 kind: ParamType::Address,
711 internal_type: None,
712 }];
713 let token_stream = expand_inputs_call_arg(¶ms);
714 assert_eq!(token_stream.to_string(), "arg_a");
715
716 let params = vec![
718 Param { name: "arg_a".to_string(), kind: ParamType::Address, internal_type: None },
719 Param {
720 name: "arg_b".to_string(),
721 kind: ParamType::Uint(256usize),
722 internal_type: None,
723 },
724 ];
725 let token_stream = expand_inputs_call_arg(¶ms);
726 assert_eq!(token_stream.to_string(), "(arg_a , arg_b ,)");
727
728 let params = vec![
730 Param { name: "arg_a".to_string(), kind: ParamType::Address, internal_type: None },
731 Param {
732 name: "arg_b".to_string(),
733 kind: ParamType::Uint(128usize),
734 internal_type: None,
735 },
736 Param { name: "arg_c".to_string(), kind: ParamType::Bool, internal_type: None },
737 ];
738 let token_stream = expand_inputs_call_arg(¶ms);
739 assert_eq!(token_stream.to_string(), "(arg_a , arg_b , arg_c ,)");
740 }
741
742 #[test]
743 fn expand_inputs_empty() {
744 assert_quote!(expand_inputs(&[]).unwrap().to_string(), {},);
745 }
746
747 #[test]
748 fn test_expand_inputs() {
749 assert_quote!(
750 expand_inputs(&[
751 Param {
752 name: "a".to_string(),
753 kind: ParamType::Bool,
754 internal_type: None,
755 },
756 Param {
757 name: "b".to_string(),
758 kind: ParamType::Address,
759 internal_type: None,
760 },
761 ])
762 .unwrap(),
763 { , a: bool, b: ::ethers_core::types::Address },
764 );
765 }
766
767 #[test]
768 fn expand_fn_outputs_empty() {
769 assert_quote!(expand_fn_outputs(&[]).unwrap(), { () });
770 }
771
772 #[test]
773 fn expand_fn_outputs_single() {
774 assert_quote!(
775 expand_fn_outputs(&[Param {
776 name: "a".to_string(),
777 kind: ParamType::Bool,
778 internal_type: None,
779 }])
780 .unwrap(),
781 { bool },
782 );
783 }
784
785 #[test]
786 fn expand_fn_outputs_multiple() {
787 assert_quote!(
788 expand_fn_outputs(&[
789 Param { name: "a".to_string(), kind: ParamType::Bool, internal_type: None },
790 Param { name: "b".to_string(), kind: ParamType::Address, internal_type: None },
791 ])
792 .unwrap(),
793 { (bool, ::ethers_core::types::Address) },
794 );
795 }
796}