2020-05-26 18:57:59 +00:00
|
|
|
//! Implementation of procedural macro for generating type-safe bindings to an
|
|
|
|
//! ethereum smart contract.
|
2021-10-16 08:19:42 +00:00
|
|
|
#![deny(missing_docs, unsafe_code, unused)]
|
2020-05-26 18:57:59 +00:00
|
|
|
|
2021-03-15 11:59:52 +00:00
|
|
|
use proc_macro::TokenStream;
|
2021-10-16 08:19:42 +00:00
|
|
|
use syn::{parse_macro_input, DeriveInput};
|
2020-05-26 18:57:59 +00:00
|
|
|
|
2021-10-11 14:18:09 +00:00
|
|
|
use abigen::Contracts;
|
2020-05-26 18:57:59 +00:00
|
|
|
|
2021-10-16 08:19:42 +00:00
|
|
|
pub(crate) mod abi_ty;
|
2021-03-15 11:59:52 +00:00
|
|
|
mod abigen;
|
2021-10-16 08:19:42 +00:00
|
|
|
mod event;
|
2021-03-15 11:59:52 +00:00
|
|
|
mod spanned;
|
2021-10-16 08:19:42 +00:00
|
|
|
pub(crate) mod utils;
|
2020-05-26 18:57:59 +00:00
|
|
|
|
2021-10-16 08:19:42 +00:00
|
|
|
/// Proc macro to generate type-safe bindings to a contract(s). This macro
|
|
|
|
/// accepts one or more Ethereum contract ABI or a path. Note that this path is
|
|
|
|
/// rooted in the crate's root `CARGO_MANIFEST_DIR`.
|
2020-05-26 18:57:59 +00:00
|
|
|
///
|
2020-06-10 20:26:37 +00:00
|
|
|
/// # Examples
|
2020-05-26 18:57:59 +00:00
|
|
|
///
|
2020-06-11 09:33:09 +00:00
|
|
|
/// ```ignore
|
|
|
|
/// # use ethers_contract_derive::abigen;
|
2020-06-10 20:26:37 +00:00
|
|
|
/// // ABI Path
|
|
|
|
/// abigen!(MyContract, "MyContract.json");
|
2020-05-26 18:57:59 +00:00
|
|
|
///
|
|
|
|
/// // HTTP(S) source
|
2020-06-11 09:33:09 +00:00
|
|
|
/// abigen!(MyContract, "https://my.domain.local/path/to/contract.json");
|
2020-06-10 20:26:37 +00:00
|
|
|
///
|
2020-05-26 18:57:59 +00:00
|
|
|
/// // Etherscan.io
|
2020-06-03 21:05:05 +00:00
|
|
|
/// abigen!(MyContract, "etherscan:0x0001020304050607080910111213141516171819");
|
|
|
|
/// abigen!(MyContract, "https://etherscan.io/address/0x0001020304050607080910111213141516171819");
|
2020-06-10 20:26:37 +00:00
|
|
|
///
|
2020-05-26 18:57:59 +00:00
|
|
|
/// // npmjs
|
2020-06-11 09:33:09 +00:00
|
|
|
/// abigen!(MyContract, "npm:@org/package@1.0.0/path/to/contract.json");
|
2020-05-26 18:57:59 +00:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Note that Etherscan rate-limits requests to their API, to avoid this an
|
|
|
|
/// `ETHERSCAN_API_KEY` environment variable can be set. If it is, it will use
|
|
|
|
/// that API key when retrieving the contract ABI.
|
|
|
|
///
|
|
|
|
/// Currently the proc macro accepts additional parameters to configure some
|
|
|
|
/// aspects of the code generation. Specifically it accepts:
|
|
|
|
/// - `methods`: A list of mappings from method signatures to method names
|
|
|
|
/// allowing methods names to be explicitely set for contract methods. This
|
|
|
|
/// also provides a workaround for generating code for contracts with multiple
|
|
|
|
/// methods with the same name.
|
|
|
|
/// - `event_derives`: A list of additional derives that should be added to
|
|
|
|
/// contract event structs and enums.
|
|
|
|
///
|
2021-10-11 14:18:09 +00:00
|
|
|
/// # Example
|
|
|
|
///
|
2020-06-11 09:33:09 +00:00
|
|
|
/// ```ignore
|
2020-06-03 21:05:05 +00:00
|
|
|
/// abigen!(
|
2020-06-10 20:26:37 +00:00
|
|
|
/// MyContract,
|
|
|
|
/// "path/to/MyContract.json",
|
2020-05-26 18:57:59 +00:00
|
|
|
/// methods {
|
|
|
|
/// myMethod(uint256,bool) as my_renamed_method;
|
|
|
|
/// },
|
|
|
|
/// event_derives (serde::Deserialize, serde::Serialize),
|
|
|
|
/// );
|
|
|
|
/// ```
|
2021-10-11 14:18:09 +00:00
|
|
|
///
|
|
|
|
/// `abigen!` supports multiple abigen definitions separated by a semicolon `;`
|
2021-10-16 08:19:42 +00:00
|
|
|
/// This is useful if the contracts use ABIEncoderV2 structs. In which case
|
|
|
|
/// `abigen!` bundles all type duplicates so that all rust contracts also use
|
|
|
|
/// the same rust types.
|
2021-10-11 14:18:09 +00:00
|
|
|
///
|
|
|
|
/// # Example Multiple contracts
|
|
|
|
/// ```ignore
|
|
|
|
/// abigen!(
|
|
|
|
/// MyContract,
|
|
|
|
/// "path/to/MyContract.json",
|
|
|
|
/// methods {
|
|
|
|
/// myMethod(uint256,bool) as my_renamed_method;
|
|
|
|
/// },
|
|
|
|
/// event_derives (serde::Deserialize, serde::Serialize);
|
|
|
|
///
|
|
|
|
/// MyOtherContract,
|
|
|
|
/// "path/to/MyOtherContract.json",
|
|
|
|
/// event_derives (serde::Deserialize, serde::Serialize);
|
|
|
|
/// );
|
|
|
|
/// ```
|
2020-05-26 18:57:59 +00:00
|
|
|
#[proc_macro]
|
|
|
|
pub fn abigen(input: TokenStream) -> TokenStream {
|
2021-10-11 14:18:09 +00:00
|
|
|
let contracts = parse_macro_input!(input as Contracts);
|
2020-05-26 18:57:59 +00:00
|
|
|
|
2021-10-11 14:18:09 +00:00
|
|
|
contracts
|
|
|
|
.expand()
|
|
|
|
.unwrap_or_else(|err| err.to_compile_error())
|
2020-05-26 18:57:59 +00:00
|
|
|
.into()
|
|
|
|
}
|
2021-03-15 11:59:52 +00:00
|
|
|
|
2021-10-16 08:19:42 +00:00
|
|
|
/// Derives the `Tokenizable` trait for the labeled type.
|
|
|
|
///
|
|
|
|
/// This derive macro automatically adds a type bound `field: Tokenizable` for
|
|
|
|
/// each field type.
|
|
|
|
#[proc_macro_derive(EthAbiType)]
|
|
|
|
pub fn derive_abi_type(input: TokenStream) -> TokenStream {
|
|
|
|
let input = parse_macro_input!(input as DeriveInput);
|
|
|
|
TokenStream::from(abi_ty::derive_tokenizeable_impl(&input))
|
|
|
|
}
|
|
|
|
|
2021-03-15 11:59:52 +00:00
|
|
|
/// Derives the `EthEvent` and `Tokenizeable` trait for the labeled type.
|
|
|
|
///
|
2021-10-16 08:19:42 +00:00
|
|
|
/// Additional arguments can be specified using the `#[ethevent(...)]`
|
|
|
|
/// attribute:
|
2021-03-15 11:59:52 +00:00
|
|
|
///
|
2021-03-19 15:44:59 +00:00
|
|
|
/// For the struct:
|
|
|
|
///
|
2021-10-16 08:19:42 +00:00
|
|
|
/// - `name`, `name = "..."`: Overrides the generated `EthEvent` name, default
|
|
|
|
/// is the
|
2021-03-16 08:12:32 +00:00
|
|
|
/// struct's name.
|
2021-10-16 08:19:42 +00:00
|
|
|
/// - `signature`, `signature = "..."`: The signature as hex string to override
|
|
|
|
/// the
|
2021-03-16 08:12:32 +00:00
|
|
|
/// event's signature.
|
2021-10-16 08:19:42 +00:00
|
|
|
/// - `abi`, `abi = "..."`: The ABI signature for the event this event's data
|
|
|
|
/// corresponds to.
|
|
|
|
/// The `abi` should be solidity event definition or a tuple of the event's
|
|
|
|
/// types in case the event has non elementary (other `EthAbiType`) types as
|
|
|
|
/// members
|
2021-03-19 15:44:59 +00:00
|
|
|
/// - `anonymous`: A flag to mark this as an anonymous event
|
|
|
|
///
|
|
|
|
/// For fields:
|
|
|
|
///
|
|
|
|
/// - `indexed`: flag to mark a field as an indexed event input
|
2021-10-16 08:19:42 +00:00
|
|
|
/// - `name`: override the name of an indexed event input, default is the rust
|
|
|
|
/// field name
|
2021-03-16 08:12:32 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```ignore
|
2021-03-19 15:44:59 +00:00
|
|
|
/// # use ethers_core::types::Address;
|
|
|
|
///
|
2021-03-16 08:12:32 +00:00
|
|
|
/// #[derive(Debug, EthAbiType)]
|
|
|
|
/// struct Inner {
|
|
|
|
/// inner: Address,
|
|
|
|
/// msg: String,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(Debug, EthEvent)]
|
|
|
|
/// #[ethevent(abi = "ValueChangedEvent((address,string),string)")]
|
|
|
|
/// struct ValueChangedEvent {
|
2021-03-19 15:44:59 +00:00
|
|
|
/// #[ethevent(indexed, name = "_target")]
|
|
|
|
/// target: Address,
|
2021-03-16 08:12:32 +00:00
|
|
|
/// msg: String,
|
2021-03-19 15:44:59 +00:00
|
|
|
/// inner: Inner,
|
2021-03-16 08:12:32 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2021-03-15 11:59:52 +00:00
|
|
|
#[proc_macro_derive(EthEvent, attributes(ethevent))]
|
|
|
|
pub fn derive_abi_event(input: TokenStream) -> TokenStream {
|
|
|
|
let input = parse_macro_input!(input as DeriveInput);
|
2021-10-16 08:19:42 +00:00
|
|
|
TokenStream::from(event::derive_eth_event_impl(input))
|
2021-03-15 11:59:52 +00:00
|
|
|
}
|