1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//! # alloy-sol-macro
//!
//! This crate provides the [`sol!`] procedural macro, which parses Solidity
//! syntax to generate types that implement [`alloy-sol-types`] traits.
//!
//! Refer to the [macro's documentation](sol!) for more information.
//!
//! [`alloy-sol-types`]: https://docs.rs/alloy-sol-types
#![doc(
html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg",
html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico"
)]
#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs, rustdoc::all)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[macro_use]
extern crate proc_macro_error;
extern crate syn_solidity as ast;
use proc_macro::TokenStream;
use syn::parse_macro_input;
mod attr;
mod expand;
mod input;
mod utils;
#[cfg(feature = "json")]
mod verbatim;
#[cfg(feature = "json")]
mod json;
/// Generate types that implement [`alloy-sol-types`] traits, which can be used
/// for type-safe [ABI] and [EIP-712] serialization to interface with Ethereum
/// smart contracts.
///
/// [ABI]: https://docs.soliditylang.org/en/latest/abi-spec.html
/// [EIP-712]: https://eips.ethereum.org/EIPS/eip-712
///
/// # Examples
///
/// > Note: the following example code blocks cannot be tested here because the
/// > generated code references [`alloy-sol-types`], so they are [tested in that
/// > crate][tests] and included with [`include_str!`] in this doc instead.
///
/// [tests]: https://github.com/alloy-rs/core/tree/main/crates/sol-types/tests/doctests
/// [`alloy-sol-types`]: https://docs.rs/alloy-sol-types
///
/// There are two main ways to use this macro:
/// - you can [write Solidity code](#solidity), or provide a path to a Solidity file,
/// - if you enable the `json` feature, you can provide [an ABI, or a path to one, in JSON
/// format](#json-abi).
///
/// Note:
/// - relative file system paths are rooted at the `CARGO_MANIFEST_DIR` environment variable
/// - no casing convention is enforced for any identifier,
/// - unnamed arguments will be given a name based on their index in the list, e.g. `_0`, `_1`...
/// - a current limitation for certain items is that custom types, like structs, must be defined in
/// the same macro scope, otherwise a signature cannot be generated at compile time. You can bring
/// them in scope with a [Solidity type alias](#udvt-and-type-aliases).
///
/// ## Solidity
///
/// This macro uses [`syn-solidity`][ast] to parse Solidity-like syntax. See
/// [its documentation][ast] for more.
///
/// Solidity input can be either one of the following:
/// - a Solidity item, which is a [Solidity source unit][sol-item] which generates one or more Rust
/// items,
/// - a [Solidity type name][sol-types], which simply expands to the corresponding Rust type.
///
/// [sol-item]: https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.sourceUnit
/// [sol-types]: https://docs.soliditylang.org/en/latest/types.html
///
/// ### Attributes
///
/// Inner attributes (`#![...]`) are parsed at the top of the input, just like a
/// Rust module. These can only be `sol` attributes, and they will apply to the
/// entire input.
///
/// Outer attributes (`#[...]`) are parsed as part of each individual item, like
/// structs, enums, etc. These can be any Rust attribute, and they will be added
/// to every Rust item generated from the Solidity item.
///
/// This macro provides the `sol` attribute, which can be used to customize the
/// generated code. Note that unused attributes are currently silently ignored,
/// but this may change in the future.
///
/// List of all `#[sol(...)]` supported attributes:
/// - `all_derives [ = <bool = false>]`: adds all possible `#[derive(...)]` attributes to all
/// generated types. May significantly increase compile times due to all the extra generated code.
/// This is the default behaviour of [`abigen`][abigen]
/// - `extra_methods [ = <bool = false>]`: adds extra implementations and methods to all applicable
/// generated types, such as `From` impls and `as_<variant>` methods. May significantly increase
/// compile times due to all the extra generated code. This is the default behaviour of
/// [`abigen`][abigen]
/// - `docs [ = <bool = true>]`: adds doc comments to all generated types. This is the default
/// behaviour of [`abigen`][abigen]
/// - `abi [ = <bool = false>]`: generates functions which return the dynamic ABI representation
/// (provided by [`alloy_json_abi`](https://docs.rs/alloy-json-abi)) of all the generated items.
/// Requires the `"json"` feature. For:
/// - contracts: generates an `abi` module nested inside of the contract module, which contains:
/// - `pub fn contract() -> JsonAbi`,
/// - `pub fn constructor() -> Option<Constructor>`
/// - `pub fn fallback() -> Option<Fallback>`
/// - `pub fn receive() -> Option<Receive>`
/// - `pub fn functions() -> BTreeMap<String, Vec<Function>>`
/// - `pub fn events() -> BTreeMap<String, Vec<Event>>`
/// - `pub fn errors() -> BTreeMap<String, Vec<Error>>`
/// - items: generates implementations of the `SolAbiExt` trait, alongside the existing
/// [`alloy-sol-types`] traits
/// - `bytecode = <hex string literal>`: specifies the creation/init bytecode of a contract. This
/// will emit a `static` item with the specified bytes.
/// - `deployed_bytecode = <hex string literal>`: specifies the deployed bytecode of a contract.
/// This will emit a `static` item with the specified bytes.
///
/// ### Structs and enums
///
/// Structs and enums generate their corresponding Rust types. Enums are
/// additionally annotated with `#[repr(u8)]`, and as such can have a maximum of
/// 256 variants.
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/structs.rs"))]
/// ```
///
/// ### UDVT and type aliases
///
/// User defined value types (UDVT) generate a tuple struct with the type as
/// its only field, and type aliases simply expand to the corresponding Rust
/// type.
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/types.rs"))]
/// ```
///
/// ### Functions and errors
///
/// Functions generate two structs that implement `SolCall`: `<name>Call` for
/// the function arguments, and `<name>Return` for the return values.
///
/// In the case of overloaded functions, an underscore and the index of the
/// function will be appended to `<name>` (like `foo_0`, `foo_1`...) for
/// disambiguation, but the signature will remain the same.
///
/// E.g. if there are two functions named `foo`, the generated types will be
/// `foo_0Call` and `foo_1Call`, each of which will implement `SolCall`
/// with their respective signatures.
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/function_like.rs"))]
/// ```
///
/// ### Events
///
/// Events generate a struct that implements `SolEvent`.
///
/// Note that events have special encoding rules in Solidity. For example,
/// `string indexed` will be encoded in the topics as its `bytes32` Keccak-256
/// hash, and as such the generated field for this argument will be `bytes32`,
/// and not `string`.
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/events.rs"))]
/// ```
///
/// ### Contracts/interfaces
///
/// Contracts generate a module with the same name, which contains all the items.
/// This module will also contain 3 container enums which implement
/// `SolInterface`, one for each:
/// - functions: `<contract_name>Calls`
/// - errors: `<contract_name>Errors`
/// - events: `<contract_name>Events`
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/contracts.rs"))]
/// ```
///
/// ## JSON ABI
///
/// Contracts can also be generated from ABI JSON strings and files, similar to
/// the [ethers-rs `abigen!` macro][abigen].
///
/// JSON objects containing the `abi`, `evm`, `bytecode`, `deployedBytecode`,
/// and similar keys are also supported.
///
/// Note that only valid JSON is supported, and not the human-readable ABI
/// format, also used by [`abigen!`][abigen]. This should instead be easily converted to
/// [normal Solidity input](#solidity).
///
/// Prefer using [Solidity input](#solidity) when possible, as the JSON ABI
/// format omits some information which is useful to this macro, such as enum
/// variants and visibility modifiers on functions.
///
/// [abigen]: https://docs.rs/ethers/latest/ethers/contract/macro.abigen.html
/// ```ignore
#[cfg_attr(doc, doc = include_str!("../doctests/json.rs"))]
/// ```
#[proc_macro]
#[proc_macro_error]
pub fn sol(input: TokenStream) -> TokenStream {
parse_macro_input!(input as input::SolInput)
.expand()
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}