#![deny(missing_docs, unsafe_code)] //! 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 #[cfg(test)] #[allow(missing_docs)] #[macro_use] #[path = "test/macros.rs"] mod test_macros; /// Contains types to generate rust bindings for solidity contracts pub mod contract; use contract::Context; pub mod rawabi; mod rustfmt; mod source; mod util; pub use ethers_core::types::Address; pub use source::Source; pub use util::parse_address; use anyhow::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 /// /// 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`. /// /// # Example /// /// Running the command 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; /// # fn foo() -> Result<(), Box> { /// Abigen::new("ERC20Token", "./abi.json")?.generate()?.write_to_file("token.rs")?; /// # Ok(()) /// # } pub struct Abigen { /// 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. contract_name: String, /// Manually specified contract method aliases. method_aliases: HashMap, /// Derives added to event structs and enums. event_derives: Vec, /// Format the code using a locally installed copy of `rustfmt`. rustfmt: bool, /// Manually specified event name aliases. event_aliases: HashMap, } impl Abigen { /// Creates a new builder with the given ABI JSON source. pub fn new>(contract_name: &str, 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(), rustfmt: true, }) } /// Manually adds a solidity event alias to specify what the event struct /// and function name will be in Rust. #[must_use] pub fn add_event_alias(mut self, signature: S1, alias: S2) -> Self where S1: Into, S2: Into, { self.event_aliases.insert(signature.into(), alias.into()); 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] pub fn add_method_alias(mut self, signature: S1, alias: S2) -> Self where S1: Into, S2: Into, { self.method_aliases.insert(signature.into(), alias.into()); self } /// Specify whether or not to format the code using a locally installed copy /// of `rustfmt`. /// /// Note that in case `rustfmt` does not exist or produces an error, the /// unformatted code will be used. #[must_use] pub fn rustfmt(mut self, rustfmt: bool) -> Self { self.rustfmt = rustfmt; self } /// Add a custom derive to the derives for event 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()); self } /// Generates the contract bindings. pub fn generate(self) -> Result { let rustfmt = self.rustfmt; let tokens = Context::from_abigen(self)?.expand()?.into_tokens(); Ok(ContractBindings { tokens, rustfmt }) } } /// Type-safe contract bindings generated by a `Builder`. This type can be /// either written to file or into a token stream for use in a procedural macro. pub struct ContractBindings { /// The TokenStream representing the contract bindings. tokens: TokenStream, /// The output options used for serialization. rustfmt: bool, } impl ContractBindings { /// Writes the bindings to a given `Write`. pub fn write(&self, mut w: W) -> Result<()> where W: Write, { let source = { let raw = self.tokens.to_string(); if self.rustfmt { rustfmt::format(&raw).unwrap_or(raw) } else { raw } }; w.write_all(source.as_bytes())?; Ok(()) } /// Writes the bindings to the specified file. pub fn write_to_file

(&self, path: P) -> Result<()> where P: AsRef, { let file = File::create(path)?; self.write(file) } /// Converts the bindings into its underlying token stream. This allows it /// to be used within a procedural macro. pub fn into_tokens(self) -> TokenStream { self.tokens } }