Refactor crate determination in new ethers-macro crate (#555)
* fix: compute ethers-core path in derive eip712 Co-authored-by: Ryan <ryan.tate@fieldresponder.io> * refactor: move crate determination to ethers-macro * docs: update fmt command * fix: change cargo_metadata dep to optional Co-authored-by: Ryan <ryan.tate@fieldresponder.io>
This commit is contained in:
parent
6cd5625787
commit
e72636210c
|
@ -118,7 +118,7 @@ This section lists some commonly needed commands.
|
|||
|
||||
```
|
||||
cargo check --all-features
|
||||
cargo fmt --all
|
||||
cargo +nightly fmt --all
|
||||
cargo build --all-features
|
||||
cargo test --all-features
|
||||
```
|
||||
|
|
|
@ -950,7 +950,6 @@ version = "0.5.3"
|
|||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"cfg-if 1.0.0",
|
||||
"ethers-core",
|
||||
"getrandom 0.2.3",
|
||||
|
@ -985,6 +984,7 @@ dependencies = [
|
|||
"arrayvec 0.7.2",
|
||||
"bincode",
|
||||
"bytes",
|
||||
"cargo_metadata",
|
||||
"convert_case",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
|
|
|
@ -10,7 +10,7 @@ repository = "https://github.com/gakonst/ethers-rs"
|
|||
keywords = ["ethereum", "web3", "celo", "ethers"]
|
||||
|
||||
[dependencies]
|
||||
ethers-core = { version = "^0.5.0", path = "../../ethers-core" }
|
||||
ethers-core = { version = "^0.5.0", path = "../../ethers-core", features = ["macros"] }
|
||||
|
||||
anyhow = "1.0.37"
|
||||
Inflector = "0.11"
|
||||
|
@ -23,7 +23,6 @@ serde = { version = "1.0.124", features = ["derive"] }
|
|||
hex = { version = "0.4.2", default-features = false, features = ["std"] }
|
||||
reqwest = { version = "0.11.3", features = ["blocking"] }
|
||||
once_cell = "1.8.0"
|
||||
cargo_metadata = "0.14.0"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
|
|
|
@ -8,7 +8,10 @@ mod types;
|
|||
use super::{util, Abigen};
|
||||
use crate::{contract::structs::InternalStructs, rawabi::RawAbi};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use ethers_core::abi::{Abi, AbiParser};
|
||||
use ethers_core::{
|
||||
abi::{Abi, AbiParser},
|
||||
macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate},
|
||||
};
|
||||
|
||||
use proc_macro2::{Ident, Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
@ -111,9 +114,9 @@ impl Context {
|
|||
// 5. Declare the structs parsed from the human readable abi
|
||||
let abi_structs_decl = self.abi_structs()?;
|
||||
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_providers = util::ethers_providers_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
let ethers_providers = ethers_providers_crate();
|
||||
|
||||
let contract = quote! {
|
||||
#struct_decl
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::{util, Context};
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use super::util::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate};
|
||||
use ethers_core::macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate};
|
||||
|
||||
pub(crate) fn imports(name: &str) -> TokenStream {
|
||||
let doc = util::expand_doc(&format!("{} was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs", name));
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use super::{types, util, Context};
|
||||
use anyhow::Result;
|
||||
use ethers_core::abi::{Event, EventExt, EventParam, ParamType, SolStruct};
|
||||
use ethers_core::{
|
||||
abi::{Event, EventExt, EventParam, ParamType, SolStruct},
|
||||
macros::{ethers_contract_crate, ethers_core_crate},
|
||||
};
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::{Ident, Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
@ -61,8 +64,8 @@ impl Context {
|
|||
|
||||
let enum_name = self.expand_event_enum_name();
|
||||
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
quote! {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, #ethers_contract::EthAbiType)]
|
||||
|
@ -106,7 +109,7 @@ impl Context {
|
|||
let sorted_events: BTreeMap<_, _> = self.abi.events.clone().into_iter().collect();
|
||||
|
||||
let mut iter = sorted_events.values().flatten();
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
if let Some(event) = iter.next() {
|
||||
let ty = if iter.next().is_some() {
|
||||
|
@ -134,7 +137,7 @@ impl Context {
|
|||
/// If a complex types matches with a struct previously parsed by the AbiParser,
|
||||
/// we can replace it
|
||||
fn expand_input_type(&self, input: &EventParam) -> Result<TokenStream> {
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
Ok(match (&input.kind, input.indexed) {
|
||||
(ParamType::Array(ty), true) => {
|
||||
if let ParamType::Tuple(..) = **ty {
|
||||
|
@ -202,7 +205,7 @@ impl Context {
|
|||
|
||||
/// Expands into a single method for contracting an event stream.
|
||||
fn expand_filter(&self, event: &Event) -> TokenStream {
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
let alias = self.event_aliases.get(&event.abi_signature()).cloned();
|
||||
|
||||
let name = if let Some(id) = alias.clone() {
|
||||
|
@ -246,7 +249,7 @@ impl Context {
|
|||
|
||||
let derives = util::expand_derives(&self.event_derives);
|
||||
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
Ok(quote! {
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthEvent, #ethers_contract::EthDisplay, #derives)]
|
||||
|
@ -318,7 +321,7 @@ mod tests {
|
|||
/// quasi-quoting for code generation. We do this to avoid allocating at runtime
|
||||
fn expand_hash(hash: Hash) -> TokenStream {
|
||||
let bytes = hash.as_bytes().iter().copied().map(Literal::u8_unsuffixed);
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
|
||||
quote! {
|
||||
#ethers_core::types::H256([#( #bytes ),*])
|
||||
|
|
|
@ -8,6 +8,7 @@ use syn::Ident;
|
|||
|
||||
use ethers_core::{
|
||||
abi::{Function, FunctionExt, Param, ParamType},
|
||||
macros::{ethers_contract_crate, ethers_core_crate},
|
||||
types::Selector,
|
||||
};
|
||||
|
||||
|
@ -63,7 +64,7 @@ impl Context {
|
|||
function.selector()
|
||||
);
|
||||
let abi_signature_doc = util::expand_doc(&doc);
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
// use the same derives as for events
|
||||
let derives = util::expand_derives(&self.event_derives);
|
||||
|
||||
|
@ -98,8 +99,8 @@ impl Context {
|
|||
return Ok(struct_def_tokens)
|
||||
}
|
||||
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
let enum_name = self.expand_calls_enum_name();
|
||||
Ok(quote! {
|
||||
|
@ -238,7 +239,7 @@ impl Context {
|
|||
// TODO use structs
|
||||
let outputs = expand_fn_outputs(&function.outputs)?;
|
||||
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
let result = quote! { #ethers_contract::builders::ContractCall<M, #outputs> };
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@ use inflector::Inflector;
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use ethers_core::abi::{
|
||||
param_type::Reader,
|
||||
struct_def::{FieldDeclaration, FieldType, StructFieldType, StructType},
|
||||
ParamType, SolStruct,
|
||||
use ethers_core::{
|
||||
abi::{
|
||||
param_type::Reader,
|
||||
struct_def::{FieldDeclaration, FieldType, StructFieldType, StructType},
|
||||
ParamType, SolStruct,
|
||||
},
|
||||
macros::ethers_contract_crate,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -123,7 +126,7 @@ impl Context {
|
|||
// use the same derives as for events
|
||||
let derives = util::expand_derives(&self.event_derives);
|
||||
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
Ok(quote! {
|
||||
#abi_signature_doc
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #derives)]
|
||||
|
@ -184,7 +187,7 @@ impl Context {
|
|||
let derives = &self.event_derives;
|
||||
let derives = quote! {#(#derives),*};
|
||||
|
||||
let ethers_contract = util::ethers_contract_crate();
|
||||
let ethers_contract = ethers_contract_crate();
|
||||
|
||||
Ok(quote! {
|
||||
#abi_signature_doc
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use ethers_core::abi::ParamType;
|
||||
use ethers_core::{abi::ParamType, macros::ethers_core_crate};
|
||||
use proc_macro2::{Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
use super::util;
|
||||
|
||||
pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
||||
let ethers_core = util::ethers_core_crate();
|
||||
let ethers_core = ethers_core_crate();
|
||||
|
||||
match kind {
|
||||
ParamType::Address => Ok(quote! { #ethers_core::types::Address }),
|
||||
|
|
|
@ -21,7 +21,7 @@ mod util;
|
|||
|
||||
pub use ethers_core::types::Address;
|
||||
pub use source::Source;
|
||||
pub use util::{ethers_contract_crate, ethers_core_crate, parse_address};
|
||||
pub use util::parse_address;
|
||||
|
||||
use anyhow::Result;
|
||||
use proc_macro2::TokenStream;
|
||||
|
|
|
@ -1,86 +1,12 @@
|
|||
use ethers_core::types::Address;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cargo_metadata::{DependencyKind, MetadataCommand};
|
||||
use inflector::Inflector;
|
||||
use once_cell::sync::Lazy;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
use syn::{Ident as SynIdent, Path};
|
||||
|
||||
/// See `determine_ethers_crates`
|
||||
///
|
||||
/// This ensures that the `MetadataCommand` is only run once
|
||||
static ETHERS_CRATES: Lazy<(&'static str, &'static str, &'static str)> =
|
||||
Lazy::new(determine_ethers_crates);
|
||||
|
||||
/// Convenience function to turn the `ethers_core` name in `ETHERS_CRATE` into a `Path`
|
||||
pub fn ethers_core_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.0).expect("valid path; qed")
|
||||
}
|
||||
/// Convenience function to turn the `ethers_contract` name in `ETHERS_CRATE` into an `Path`
|
||||
pub fn ethers_contract_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.1).expect("valid path; qed")
|
||||
}
|
||||
pub fn ethers_providers_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.2).expect("valid path; qed")
|
||||
}
|
||||
|
||||
/// The crates name to use when deriving macros: (`core`, `contract`)
|
||||
///
|
||||
/// We try to determine which crate ident to use based on the dependencies of
|
||||
/// the project in which the macro is used. This is useful because the macros,
|
||||
/// like `EthEvent` are provided by the `ethers-contract` crate which depends on
|
||||
/// `ethers_core`. Most commonly `ethers` will be used as dependency which
|
||||
/// reexports all the different crates, essentially `ethers::core` is
|
||||
/// `ethers_core` So depending on the dependency used `ethers` ors `ethers_core
|
||||
/// | ethers_contract`, we need to use the fitting crate ident when expand the
|
||||
/// macros This will attempt to parse the current `Cargo.toml` and check the
|
||||
/// ethers related dependencies.
|
||||
///
|
||||
/// This process is a bit hacky, we run `cargo metadata` internally which
|
||||
/// resolves the current package but creates a new `Cargo.lock` file in the
|
||||
/// process. This is not a problem for regular workspaces but becomes an issue
|
||||
/// during publishing with `cargo publish` if the project does not ignore
|
||||
/// `Cargo.lock` in `.gitignore`, because then cargo can't proceed with
|
||||
/// publishing the crate because the created `Cargo.lock` leads to a modified
|
||||
/// workspace, not the `CARGO_MANIFEST_DIR` but the workspace `cargo publish`
|
||||
/// created in `./target/package/..`. Therefore we check prior to executing
|
||||
/// `cargo metadata` if a `Cargo.lock` file exists and delete it afterwards if
|
||||
/// it was created by `cargo metadata`.
|
||||
pub fn determine_ethers_crates() -> (&'static str, &'static str, &'static str) {
|
||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("No Manifest found");
|
||||
|
||||
// check if the lock file exists, if it's missing we need to clean up afterward
|
||||
let lock_file = format!("{}/Cargo.lock", manifest_dir);
|
||||
let needs_lock_file_cleanup = !std::path::Path::new(&lock_file).exists();
|
||||
|
||||
let res = MetadataCommand::new()
|
||||
.manifest_path(&format!("{}/Cargo.toml", manifest_dir))
|
||||
.exec()
|
||||
.ok()
|
||||
.and_then(|metadata| {
|
||||
metadata.root_package().and_then(|pkg| {
|
||||
pkg.dependencies.iter().filter(|dep| dep.kind == DependencyKind::Normal).find_map(
|
||||
|dep| {
|
||||
(dep.name == "ethers")
|
||||
.then(|| ("ethers::core", "ethers::contract", "ethers::providers"))
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or(("ethers_core", "ethers_contract", "ethers_providers"));
|
||||
|
||||
if needs_lock_file_cleanup {
|
||||
// delete the `Cargo.lock` file that was created by `cargo metadata`
|
||||
// if the package is not part of a workspace
|
||||
let _ = std::fs::remove_file(lock_file);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// Expands a identifier string into an token.
|
||||
pub fn ident(name: &str) -> Ident {
|
||||
Ident::new(name, Span::call_site())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Helper functions for deriving `EthAbiType`
|
||||
|
||||
use ethers_contract_abigen::ethers_core_crate;
|
||||
use ethers_core::macros::ethers_core_crate;
|
||||
use proc_macro2::{Ident, Literal, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{parse::Error, spanned::Spanned as _, Data, DeriveInput, Fields, Variant};
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
//! Helper functions for deriving `EthCall`
|
||||
|
||||
use ethers_contract_abigen::{ethers_contract_crate, ethers_core_crate};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse::Error, spanned::Spanned as _, AttrStyle, DeriveInput, Lit, Meta, NestedMeta};
|
||||
|
||||
use ethers_core::abi::{param_type::Reader, AbiParser, Function, FunctionExt, Param, ParamType};
|
||||
use ethers_core::{
|
||||
abi::{param_type::Reader, AbiParser, Function, FunctionExt, Param, ParamType},
|
||||
macros::{ethers_contract_crate, ethers_core_crate},
|
||||
};
|
||||
|
||||
use crate::{abi_ty, utils};
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@ use proc_macro2::TokenStream;
|
|||
use quote::quote;
|
||||
use syn::{parse::Error, spanned::Spanned as _, Data, DeriveInput, Fields, Index};
|
||||
|
||||
use ethers_contract_abigen::ethers_core_crate;
|
||||
use ethers_core::abi::ParamType;
|
||||
use ethers_core::{abi::ParamType, macros::ethers_core_crate};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Helper functions for deriving `EthEvent`
|
||||
|
||||
use ethers_contract_abigen::{ethers_contract_crate, ethers_core_crate, Source};
|
||||
use ethers_contract_abigen::Source;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
|
@ -8,7 +8,10 @@ use syn::{
|
|||
NestedMeta,
|
||||
};
|
||||
|
||||
use ethers_core::abi::{param_type::Reader, AbiParser, Event, EventExt, EventParam, ParamType};
|
||||
use ethers_core::{
|
||||
abi::{param_type::Reader, AbiParser, Event, EventExt, EventParam, ParamType},
|
||||
macros::{ethers_contract_crate, ethers_core_crate},
|
||||
};
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::{abi_ty, utils};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use ethers_contract_abigen::ethers_core_crate;
|
||||
use ethers_core::{abi::ParamType, types::Selector};
|
||||
use ethers_core::{abi::ParamType, macros::ethers_core_crate, types::Selector};
|
||||
use proc_macro2::Literal;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
|
|
|
@ -31,6 +31,9 @@ bytes = { version = "1.1.0", features = ["serde"] }
|
|||
hex = { version = "0.4.3", default-features = false, features = ["std"] }
|
||||
once_cell = "1.8.0"
|
||||
|
||||
# macros feature enabled dependencies
|
||||
cargo_metadata = { version = "0.14.0", optional = true }
|
||||
|
||||
# eip712 feature enabled dependencies
|
||||
convert_case = { version = "0.4.0", optional = true }
|
||||
syn = { version = "1.0.81", optional = true }
|
||||
|
@ -55,6 +58,7 @@ celo = ["legacy"] # celo support extends the transaction format with extra field
|
|||
setup = ["tokio", "futures-util"] # async support for concurrent setup
|
||||
legacy = []
|
||||
eip712 = ["convert_case", "syn", "quote", "proc-macro2"]
|
||||
macros = ["syn", "cargo_metadata"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
|
|
@ -10,7 +10,7 @@ proc-macro = true
|
|||
[dependencies]
|
||||
quote = "1.0.9"
|
||||
syn = "1.0.77"
|
||||
ethers-core = { version = "^0.5.0", path = "../", default-features = false, features = ["eip712"] }
|
||||
ethers-core = { version = "^0.5.0", path = "../", default-features = false, features = ["eip712", "macros"] }
|
||||
hex = "0.4.3"
|
||||
serde = "1.0.130"
|
||||
serde_json = "1.0.68"
|
||||
|
@ -19,4 +19,4 @@ proc-macro2 = "1.0.29"
|
|||
[dev-dependencies]
|
||||
ethers-contract = { version = "^0.5.0", path = "../../ethers-contract"}
|
||||
ethers-contract-derive = { version = "^0.5.0", path = "../../ethers-contract/ethers-contract-derive" }
|
||||
ethers-signers = { version = "^0.5.0", path = "../../ethers-signers" }
|
||||
ethers-signers = { version = "^0.5.0", path = "../../ethers-signers" }
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
//! determine if there is a nested eip712 struct. However, this work is not yet complete.
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use ethers_core::types::transaction::eip712;
|
||||
use ethers_core::{macros::ethers_core_crate, types::transaction::eip712};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
|
@ -104,13 +104,16 @@ fn impl_eip_712_macro(ast: &syn::DeriveInput) -> TokenStream {
|
|||
Err(e) => return TokenStream::from(e),
|
||||
};
|
||||
|
||||
// Compute the type hash for the derived struct using the parsed fields from above;
|
||||
// Compute the type hash for the derived struct using the parsed fields from above.
|
||||
let type_hash =
|
||||
hex::encode(eip712::make_type_hash(primary_type.clone().to_string(), &parsed_fields));
|
||||
|
||||
// Use reference to ethers_core instead of directly using the crate itself.
|
||||
let ethers_core = ethers_core_crate();
|
||||
|
||||
let implementation = quote! {
|
||||
impl Eip712 for #primary_type {
|
||||
type Error = ethers_core::types::transaction::eip712::Eip712Error;
|
||||
type Error = #ethers_core::types::transaction::eip712::Eip712Error;
|
||||
|
||||
fn type_hash() -> Result<[u8; 32], Self::Error> {
|
||||
use std::convert::TryFrom;
|
||||
|
@ -127,34 +130,34 @@ fn impl_eip_712_macro(ast: &syn::DeriveInput) -> TokenStream {
|
|||
Ok(byte_array)
|
||||
}
|
||||
|
||||
fn domain(&self) -> Result<ethers_core::types::transaction::eip712::EIP712Domain, Self::Error> {
|
||||
let domain: ethers_core::types::transaction::eip712::EIP712Domain = serde_json::from_str(#domain_str)?;
|
||||
fn domain(&self) -> Result<#ethers_core::types::transaction::eip712::EIP712Domain, Self::Error> {
|
||||
let domain: #ethers_core::types::transaction::eip712::EIP712Domain = serde_json::from_str(#domain_str)?;
|
||||
|
||||
Ok(domain)
|
||||
}
|
||||
|
||||
fn struct_hash(&self) -> Result<[u8; 32], Self::Error> {
|
||||
use ethers_core::abi::Tokenizable;
|
||||
let mut items = vec![ethers_core::abi::Token::Uint(
|
||||
ethers_core::types::U256::from(&Self::type_hash()?[..]),
|
||||
use #ethers_core::abi::Tokenizable;
|
||||
let mut items = vec![#ethers_core::abi::Token::Uint(
|
||||
#ethers_core::types::U256::from(&Self::type_hash()?[..]),
|
||||
)];
|
||||
|
||||
if let ethers_core::abi::Token::Tuple(tokens) = self.clone().into_token() {
|
||||
if let #ethers_core::abi::Token::Tuple(tokens) = self.clone().into_token() {
|
||||
for token in tokens {
|
||||
match &token {
|
||||
ethers_core::abi::Token::Tuple(t) => {
|
||||
#ethers_core::abi::Token::Tuple(t) => {
|
||||
// TODO: check for nested Eip712 Type;
|
||||
// Challenge is determining the type hash
|
||||
return Err(Self::Error::NestedEip712StructNotImplemented);
|
||||
},
|
||||
_ => {
|
||||
items.push(ethers_core::types::transaction::eip712::encode_eip712_type(token));
|
||||
items.push(#ethers_core::types::transaction::eip712::encode_eip712_type(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let struct_hash = ethers_core::utils::keccak256(ethers_core::abi::encode(
|
||||
let struct_hash = #ethers_core::utils::keccak256(#ethers_core::abi::encode(
|
||||
&items,
|
||||
));
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ pub mod abi;
|
|||
/// Various utilities
|
||||
pub mod utils;
|
||||
|
||||
pub mod macros;
|
||||
|
||||
// re-export rand to avoid potential confusion when there's rand version mismatches
|
||||
pub use rand;
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
use cargo_metadata::{DependencyKind, MetadataCommand};
|
||||
use once_cell::sync::Lazy;
|
||||
use syn::Path;
|
||||
|
||||
/// See `determine_ethers_crates`
|
||||
///
|
||||
/// This ensures that the `MetadataCommand` is only run once
|
||||
static ETHERS_CRATES: Lazy<(&'static str, &'static str, &'static str)> =
|
||||
Lazy::new(determine_ethers_crates);
|
||||
|
||||
/// Convenience function to turn the `ethers_core` name in `ETHERS_CRATE` into a `Path`
|
||||
pub fn ethers_core_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.0).expect("valid path; qed")
|
||||
}
|
||||
/// Convenience function to turn the `ethers_contract` name in `ETHERS_CRATE` into an `Path`
|
||||
pub fn ethers_contract_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.1).expect("valid path; qed")
|
||||
}
|
||||
pub fn ethers_providers_crate() -> Path {
|
||||
syn::parse_str(ETHERS_CRATES.2).expect("valid path; qed")
|
||||
}
|
||||
|
||||
/// The crates name to use when deriving macros: (`core`, `contract`)
|
||||
///
|
||||
/// We try to determine which crate ident to use based on the dependencies of
|
||||
/// the project in which the macro is used. This is useful because the macros,
|
||||
/// like `EthEvent` are provided by the `ethers-contract` crate which depends on
|
||||
/// `ethers_core`. Most commonly `ethers` will be used as dependency which
|
||||
/// reexports all the different crates, essentially `ethers::core` is
|
||||
/// `ethers_core` So depending on the dependency used `ethers` ors `ethers_core
|
||||
/// | ethers_contract`, we need to use the fitting crate ident when expand the
|
||||
/// macros This will attempt to parse the current `Cargo.toml` and check the
|
||||
/// ethers related dependencies.
|
||||
///
|
||||
/// This process is a bit hacky, we run `cargo metadata` internally which
|
||||
/// resolves the current package but creates a new `Cargo.lock` file in the
|
||||
/// process. This is not a problem for regular workspaces but becomes an issue
|
||||
/// during publishing with `cargo publish` if the project does not ignore
|
||||
/// `Cargo.lock` in `.gitignore`, because then cargo can't proceed with
|
||||
/// publishing the crate because the created `Cargo.lock` leads to a modified
|
||||
/// workspace, not the `CARGO_MANIFEST_DIR` but the workspace `cargo publish`
|
||||
/// created in `./target/package/..`. Therefore we check prior to executing
|
||||
/// `cargo metadata` if a `Cargo.lock` file exists and delete it afterwards if
|
||||
/// it was created by `cargo metadata`.
|
||||
pub fn determine_ethers_crates() -> (&'static str, &'static str, &'static str) {
|
||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("No Manifest found");
|
||||
|
||||
// check if the lock file exists, if it's missing we need to clean up afterward
|
||||
let lock_file = format!("{}/Cargo.lock", manifest_dir);
|
||||
let needs_lock_file_cleanup = !std::path::Path::new(&lock_file).exists();
|
||||
|
||||
let res = MetadataCommand::new()
|
||||
.manifest_path(&format!("{}/Cargo.toml", manifest_dir))
|
||||
.exec()
|
||||
.ok()
|
||||
.and_then(|metadata| {
|
||||
metadata.root_package().and_then(|pkg| {
|
||||
pkg.dependencies.iter().filter(|dep| dep.kind == DependencyKind::Normal).find_map(
|
||||
|dep| {
|
||||
(dep.name == "ethers")
|
||||
.then(|| ("ethers::core", "ethers::contract", "ethers::providers"))
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or(("ethers_core", "ethers_contract", "ethers_providers"));
|
||||
|
||||
if needs_lock_file_cleanup {
|
||||
// delete the `Cargo.lock` file that was created by `cargo metadata`
|
||||
// if the package is not part of a workspace
|
||||
let _ = std::fs::remove_file(lock_file);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
mod ethers_crate;
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
pub use ethers_crate::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate};
|
Loading…
Reference in New Issue