diff --git a/ethers-contract/ethers-contract-abigen/src/contract.rs b/ethers-contract/ethers-contract-abigen/src/contract.rs index 1d3bf00f..dd34a4b3 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract.rs @@ -271,7 +271,7 @@ impl Context { } let event_derives = args - .event_derives + .derives .iter() .map(|derive| syn::parse_str::(derive)) .collect::, _>>() diff --git a/ethers-contract/ethers-contract-abigen/src/lib.rs b/ethers-contract/ethers-contract-abigen/src/lib.rs index cf0659b6..3be23832 100644 --- a/ethers-contract/ethers-contract-abigen/src/lib.rs +++ b/ethers-contract/ethers-contract-abigen/src/lib.rs @@ -1,9 +1,13 @@ -#![deny(missing_docs, unsafe_code)] -#![deny(rustdoc::broken_intra_doc_links)] +//! # Abigen +//! +//! Programmatically generate type-safe Rust bindings for Ethereum smart contracts. +//! +//! This crate is intended to be used either indirectly with the [`abigen` procedural macro][abigen] +//! or directly from a build script / CLI. +//! +//! [abigen]: https://docs.rs/ethers/latest/ethers/contract/macro.abigen.html -//! Module for generating type-safe bindings to Ethereum smart contracts. This -//! module is intended to be used either indirectly with the `abigen` procedural -//! macro or directly from a build script / CLI +#![deny(rustdoc::broken_intra_doc_links, missing_docs, unsafe_code)] #[cfg(test)] #[allow(missing_docs)] @@ -33,19 +37,21 @@ use eyre::Result; use proc_macro2::TokenStream; use std::{collections::HashMap, fs::File, io::Write, path::Path}; -/// Builder struct for generating type-safe bindings from a contract's ABI +/// Programmatically generate type-safe Rust bindings for an Ethereum smart contract from its ABI. /// -/// Note: Your contract's ABI must contain the `stateMutability` field. This is -/// [still not supported by Vyper](https://github.com/vyperlang/vyper/issues/1931), so you must adjust your ABIs and replace -/// `constant` functions with `view` or `pure`. +/// For all the supported ABI sources, see [Source]. /// -/// To generate bindings for _multiple_ contracts at once see also [`crate::MultiAbigen`]. +/// To generate bindings for *multiple* contracts at once, see [`MultiAbigen`]. +/// +/// To generate bindings at compile time, see [the abigen! macro][abigen], or use in a `build.rs` +/// file. +/// +/// [abigen]: https://docs.rs/ethers/latest/ethers/contract/macro.abigen.html /// /// # Example /// -/// Running the code below will generate a file called `token.rs` containing the -/// bindings inside, which exports an `ERC20Token` struct, along with all its events. Put into a -/// `build.rs` file this will generate the bindings during `cargo build`. +/// Running the code below will generate a file called `token.rs` containing the bindings inside, +/// which exports an `ERC20Token` struct, along with all its events. /// /// ```no_run /// # use ethers_contract_abigen::Abigen; @@ -53,22 +59,22 @@ use std::{collections::HashMap, fs::File, io::Write, path::Path}; /// Abigen::new("ERC20Token", "./abi.json")?.generate()?.write_to_file("token.rs")?; /// # Ok(()) /// # } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] +#[must_use = "Abigen does nothing unless you generate or expand it."] pub struct Abigen { - /// The source of the ABI JSON for the contract whose bindings - /// are being generated. + /// The source of the ABI JSON for the contract whose bindings are being generated. abi_source: Source, - /// Override the contract name to use for the generated type. + /// The contract's name to use for the generated type. contract_name: String, /// Manually specified contract method aliases. method_aliases: HashMap, - /// Derives added to event structs and enums. - event_derives: Vec, + /// Manually specified `derive` macros added to all structs and enums. + derives: Vec, - /// Whether to format the code. Uses [`prettyplease`]. + /// Whether to format the generated bindings using [`prettyplease`]. format: bool, /// Manually specified event name aliases. @@ -79,22 +85,21 @@ pub struct Abigen { } impl Abigen { - /// Creates a new builder with the given ABI JSON source. - pub fn new>(contract_name: &str, abi_source: S) -> Result { + /// Creates a new builder with the given [ABI Source][Source]. + pub fn new, S: AsRef>(contract_name: T, abi_source: S) -> Result { let abi_source = abi_source.as_ref().parse()?; Ok(Self { abi_source, - contract_name: contract_name.to_owned(), - method_aliases: HashMap::new(), - event_derives: Vec::new(), - event_aliases: HashMap::new(), + contract_name: contract_name.into(), format: true, + method_aliases: Default::default(), + derives: Default::default(), + event_aliases: Default::default(), error_aliases: Default::default(), }) } - /// Attempts to load a new builder from an ABI JSON file at the specific - /// path. + /// Attempts to load a new builder from an ABI JSON file at the specific path. pub fn from_file(path: impl AsRef) -> Result { let name = path .as_ref() @@ -110,9 +115,10 @@ impl Abigen { Self::new(name, std::fs::read_to_string(path.as_ref())?) } - /// Manually adds a solidity event alias to specify what the event struct - /// and function name will be in Rust. - #[must_use] + /// Manually adds a solidity event alias to specify what the event struct and function name will + /// be in Rust. + /// + /// For events without an alias, the `PascalCase` event name will be used. pub fn add_event_alias(mut self, signature: S1, alias: S2) -> Self where S1: Into, @@ -122,10 +128,9 @@ impl Abigen { self } - /// Manually adds a solidity method alias to specify what the method name - /// will be in Rust. For solidity methods without an alias, the snake cased - /// method name will be used. - #[must_use] + /// Add a Solidity method error alias to specify the generated method name. + /// + /// For methods without an alias, the `snake_case` method name will be used. pub fn add_method_alias(mut self, signature: S1, alias: S2) -> Self where S1: Into, @@ -135,8 +140,9 @@ impl Abigen { self } - /// Manually adds a solidity error alias to specify what the error struct will be in Rust. - #[must_use] + /// Add a Solidity custom error alias to specify the generated struct's name. + /// + /// For errors without an alias, the `PascalCase` error name will be used. pub fn add_error_alias(mut self, signature: S1, alias: S2) -> Self where S1: Into, @@ -163,16 +169,18 @@ impl Abigen { self } - /// Add a custom derive to the derives for event structs and enums. + #[deprecated = "Use add_derive instead"] + #[doc(hidden)] + pub fn add_event_derive>(mut self, derive: S) -> Self { + self.derives.push(derive.into()); + self + } + + /// Add a custom derive to the derives for all structs and enums. /// - /// This makes it possible to for example derive serde::Serialize and - /// serde::Deserialize for events. - #[must_use] - pub fn add_event_derive(mut self, derive: S) -> Self - where - S: Into, - { - self.event_derives.push(derive.into()); + /// For example, this makes it possible to derive serde::Serialize and serde::Deserialize. + pub fn add_derive>(mut self, derive: S) -> Self { + self.derives.push(derive.into()); self } @@ -253,12 +261,12 @@ impl ContractBindings { self.tokens } - /// Generate the default module name (snake case of the contract name) + /// Generate the default module name (snake case of the contract name). pub fn module_name(&self) -> String { util::safe_module_name(&self.name) } - /// Generate the default filename of the module + /// Generate the default file name of the module. pub fn module_filename(&self) -> String { let mut name = self.module_name(); name.extend([".rs"]); diff --git a/ethers-contract/ethers-contract-derive/src/abigen.rs b/ethers-contract/ethers-contract-derive/src/abigen.rs index 8c803dbe..6d0de4b8 100644 --- a/ethers-contract/ethers-contract-derive/src/abigen.rs +++ b/ethers-contract/ethers-contract-derive/src/abigen.rs @@ -1,14 +1,13 @@ -//! Implementation of procedural macro for generating type-safe bindings to an -//! ethereum smart contract. +//! Implementation of procedural macro for generating type-safe bindings to an Ethereum smart +//! contract. + use crate::spanned::{ParseInner, Spanned}; - -use ethers_contract_abigen::Abigen; -use ethers_core::abi::{Function, FunctionExt, Param, StateMutability}; - use ethers_contract_abigen::{ contract::{Context, ExpandedContract}, multi::MultiExpansion, + Abigen, }; +use ethers_core::abi::{Function, FunctionExt, Param, StateMutability}; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::ToTokens; use std::{collections::HashSet, error::Error}; @@ -75,9 +74,9 @@ impl ContractArgs { Parameter::Methods(methods) => methods .into_iter() .fold(builder, |builder, m| builder.add_method_alias(m.signature, m.alias)), - Parameter::EventDerives(derives) => derives - .into_iter() - .fold(builder, |builder, derive| builder.add_event_derive(derive)), + Parameter::Derives(derives) => { + derives.into_iter().fold(builder, |builder, derive| builder.add_derive(derive)) + } }; } @@ -133,7 +132,7 @@ impl ParseInner for ContractArgs { #[cfg_attr(test, derive(Debug, Eq, PartialEq))] enum Parameter { Methods(Vec), - EventDerives(Vec), + Derives(Vec), } impl Parse for Parameter { @@ -171,7 +170,7 @@ impl Parse for Parameter { Parameter::Methods(methods) } - "event_derives" => { + "derives" | "event_derives" => { let content; parenthesized!(content in input); let derives = content @@ -179,7 +178,7 @@ impl Parse for Parameter { .into_iter() .map(|path| path.to_token_stream().to_string()) .collect(); - Parameter::EventDerives(derives) + Parameter::Derives(derives) } _ => { return Err(ParseError::new( @@ -295,7 +294,7 @@ mod tests { ContractArgs { name: "TestContract".to_string(), abi: "path/to/abi.json".to_string(), - parameters: vec![Parameter::EventDerives(vec![ + parameters: vec![Parameter::Derives(vec![ "serde :: Deserialize".into(), "serde :: Serialize".into(), ])], @@ -303,7 +302,7 @@ mod tests { ContractArgs { name: "TestContract2".to_string(), abi: "other.json".to_string(), - parameters: vec![Parameter::EventDerives(vec![ + parameters: vec![Parameter::Derives(vec![ "serde :: Deserialize".into(), "serde :: Serialize".into(), ])], @@ -341,7 +340,7 @@ mod tests { ContractArgs { name: "TestContract2".to_string(), abi: "other.json".to_string(), - parameters: vec![Parameter::EventDerives(vec![ + parameters: vec![Parameter::Derives(vec![ "serde :: Deserialize".into(), "serde :: Serialize".into(), ])], @@ -372,7 +371,7 @@ mod tests { ContractArgs { name: "TestContract2".to_string(), abi: "other.json".to_string(), - parameters: vec![Parameter::EventDerives(vec![ + parameters: vec![Parameter::Derives(vec![ "serde :: Deserialize".into(), "serde :: Serialize".into(), ])], @@ -423,7 +422,7 @@ mod tests { method("myMethod(uint256,bool)", "my_renamed_method"), method("myOtherMethod()", "my_other_renamed_method"), ]), - Parameter::EventDerives(vec![ + Parameter::Derives(vec![ "Asdf".into(), "a :: B".into(), "a :: b :: c :: D".into()