Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ethers-contract circular dep on ethers-signers #2291

Merged
merged 9 commits into from Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -94,7 +94,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: live tests
run: cargo test -p ethers --test live --all-features
run: cargo test -p ethers --all-features

# TODO: [#2191](https://github.com/gakonst/ethers-rs/issues/2191)
# feature-checks:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ethers-contract/Cargo.toml
Expand Up @@ -43,8 +43,8 @@ ethers-contract-derive = { workspace = true, optional = true }
ethers-derive-eip712 = { workspace = true, optional = true }

[dev-dependencies]
ethers-signers.workspace = true
ethers-solc.workspace = true
ethers-providers = { workspace = true, features = ["ws"] }

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
tokio = { workspace = true, features = ["macros"] }
Expand Down
2 changes: 0 additions & 2 deletions ethers-contract/src/contract.rs
Expand Up @@ -75,7 +75,6 @@ pub type Contract<M> = ContractInstance<std::sync::Arc<M>, M>;
/// };
/// use ethers_contract::Contract;
/// use ethers_providers::{Provider, Http};
/// use ethers_signers::Wallet;
/// use std::{convert::TryFrom, sync::Arc};
///
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
Expand Down Expand Up @@ -122,7 +121,6 @@ pub type Contract<M> = ContractInstance<std::sync::Arc<M>, M>;
/// use ethers_core::{abi::Abi, types::Address};
/// use ethers_contract::{Contract, EthEvent};
/// use ethers_providers::{Provider, Http, Middleware};
/// use ethers_signers::Wallet;
/// use std::{convert::TryFrom, sync::Arc};
/// use ethers_core::abi::{Detokenize, Token, InvalidOutputType};
/// # // this is a fake address used just for this example
Expand Down
1 change: 0 additions & 1 deletion ethers-contract/src/factory.rs
Expand Up @@ -323,7 +323,6 @@ where
/// use ethers_solc::Solc;
/// use ethers_contract::ContractFactory;
/// use ethers_providers::{Provider, Http};
/// use ethers_signers::Wallet;
/// use std::convert::TryFrom;
///
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
154 changes: 3 additions & 151 deletions ethers-contract/tests/it/contract.rs
@@ -1,18 +1,14 @@
use crate::common::*;
use ethers_contract::{
abigen, ContractFactory, ContractInstance, EthAbiType, EthEvent, LogMeta, Multicall,
MulticallError, MulticallVersion,
abigen, ContractFactory, ContractInstance, EthEvent, LogMeta, Multicall, MulticallError,
MulticallVersion,
};
use ethers_core::{
abi::{encode, AbiEncode, Token, Tokenizable},
types::{
transaction::eip712::Eip712, Address, BlockId, Bytes, Filter, ValueOrArray, H160, H256,
I256, U256,
},
types::{Address, BlockId, Bytes, Filter, ValueOrArray, H160, H256, U256},
utils::{keccak256, Anvil},
};
use ethers_providers::{Http, Middleware, MiddlewareError, Provider, StreamExt};
use ethers_signers::{LocalWallet, Signer};
use std::{sync::Arc, time::Duration};

#[derive(Debug)]
Expand Down Expand Up @@ -330,7 +326,6 @@ async fn call_past_hash_test() {
}

#[tokio::test]
#[cfg(feature = "abigen")]
async fn watch_events() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let anvil = Anvil::new().spawn();
Expand Down Expand Up @@ -784,146 +779,3 @@ async fn multicall_aggregate() {
assert_eq!(bytes[..4], keccak256("CustomErrorWithData(string)")[..4]);
assert_eq!(bytes[4..], encode(&[Token::String("Data".to_string())]));
}

#[tokio::test]
#[cfg(feature = "eip712")]
async fn test_derive_eip712() {
use ethers_derive_eip712::*;

// Generate Contract ABI Bindings
abigen!(
DeriveEip712Test,
"./ethers-contract/tests/solidity-contracts/derive_eip712_abi.json",
event_derives(serde::Deserialize, serde::Serialize)
);

// Create derived structs

#[derive(Debug, Clone, Eip712, EthAbiType)]
#[eip712(
name = "Eip712Test",
version = "1",
chain_id = 1,
verifying_contract = "0x0000000000000000000000000000000000000001",
salt = "eip712-test-75F0CCte"
)]
struct FooBar {
foo: I256,
bar: U256,
fizz: Bytes,
buzz: [u8; 32],
far: String,
out: Address,
}

// get ABI and bytecode for the DeriveEip712Test contract
let (abi, bytecode) = compile_contract("DeriveEip712Test", "DeriveEip712Test.sol");

// launch the network & connect to it
let anvil = Anvil::new().spawn();
let from = anvil.addresses()[0];
let provider = Provider::try_from(anvil.endpoint())
.unwrap()
.with_sender(from)
.interval(std::time::Duration::from_millis(10));
let client = Arc::new(provider);

let wallet: LocalWallet = anvil.keys()[0].clone().into();

let factory = ContractFactory::new(abi.clone(), bytecode.clone(), client.clone());

let contract = factory
.deploy(())
.expect("failed to deploy DeriveEip712Test contract")
.legacy()
.send()
.await
.expect("failed to instantiate factory for DeriveEip712 contract");

let addr = contract.address();

let contract = DeriveEip712Test::new(addr, client.clone());

let foo_bar = FooBar {
foo: I256::from(10u64),
bar: U256::from(20u64),
fizz: b"fizz".into(),
buzz: keccak256("buzz"),
far: String::from("space"),
out: Address::from([0; 20]),
};

let derived_foo_bar = derive_eip_712_test::FooBar {
foo: foo_bar.foo,
bar: foo_bar.bar,
fizz: foo_bar.fizz.clone(),
buzz: foo_bar.buzz,
far: foo_bar.far.clone(),
out: foo_bar.out,
};

let sig = wallet.sign_typed_data(&foo_bar).await.expect("failed to sign typed data");

let r = <[u8; 32]>::try_from(sig.r)
.expect("failed to parse 'r' value from signature into [u8; 32]");
let s = <[u8; 32]>::try_from(sig.s)
.expect("failed to parse 's' value from signature into [u8; 32]");
let v = u8::try_from(sig.v).expect("failed to parse 'v' value from signature into u8");

let domain_separator = contract
.domain_separator()
.call()
.await
.expect("failed to retrieve domain_separator from contract");
let type_hash =
contract.type_hash().call().await.expect("failed to retrieve type_hash from contract");
let struct_hash = contract
.struct_hash(derived_foo_bar.clone())
.call()
.await
.expect("failed to retrieve struct_hash from contract");
let encoded = contract
.encode_eip_712(derived_foo_bar.clone())
.call()
.await
.expect("failed to retrieve eip712 encoded hash from contract");
let verify = contract
.verify_foo_bar(wallet.address(), derived_foo_bar, r, s, v)
.call()
.await
.expect("failed to verify signed typed data eip712 payload");

assert_eq!(
domain_separator,
foo_bar
.domain()
.expect("failed to return domain_separator from Eip712 implemented struct")
.separator(),
"domain separator does not match contract domain separator!"
);

assert_eq!(
type_hash,
FooBar::type_hash().expect("failed to return type_hash from Eip712 implemented struct"),
"type hash does not match contract struct type hash!"
);

assert_eq!(
struct_hash,
foo_bar
.clone()
.struct_hash()
.expect("failed to return struct_hash from Eip712 implemented struct"),
"struct hash does not match contract struct hash!"
);

assert_eq!(
encoded,
foo_bar
.encode_eip712()
.expect("failed to return domain_separator from Eip712 implemented struct"),
"Encoded value does not match!"
);

assert!(verify, "typed data signature failed!");
}
1 change: 1 addition & 0 deletions ethers-solc/src/artifact_output/mod.rs
Expand Up @@ -659,6 +659,7 @@ pub trait ArtifactOutput {
if let Ok(stripped) = rel_candidate.strip_prefix(artifacts_folder) {
rel_candidate = stripped.to_path_buf();
}
#[allow(clippy::redundant_clone)] // false positive
let mut candidate = rel_candidate.clone();
let contract_file = contract_file.as_ref();
let mut current_parent = contract_file.parent();
Expand Down
38 changes: 10 additions & 28 deletions ethers/Cargo.toml
Expand Up @@ -26,14 +26,7 @@ all-features = true
[features]
default = ["abigen", "rustls"]

celo = [
"ethers-core/celo",
"ethers-providers/celo",
"ethers-signers/celo",
"ethers-contract/celo",
"ethers-middleware/celo",
"legacy",
]
celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo", "ethers-contract/celo", "ethers-middleware/celo", "legacy"]

legacy = ["ethers-core/legacy", "ethers-contract/legacy"]

Expand All @@ -43,20 +36,8 @@ eip712 = ["ethers-contract/eip712", "ethers-core/eip712"]
## providers
ws = ["ethers-providers/ws"]
ipc = ["ethers-providers/ipc"]
rustls = [
"ethers-middleware/rustls",
"ethers-providers/rustls",
"ethers-etherscan/rustls",
"ethers-contract/rustls",
"ethers-solc/rustls",
]
openssl = [
"ethers-middleware/openssl",
"ethers-providers/openssl",
"ethers-etherscan/openssl",
"ethers-contract/openssl",
"ethers-solc/openssl",
]
rustls = ["ethers-middleware/rustls", "ethers-providers/rustls", "ethers-etherscan/rustls", "ethers-contract/rustls", "ethers-solc/rustls"]
openssl = ["ethers-middleware/openssl", "ethers-providers/openssl", "ethers-etherscan/openssl", "ethers-contract/openssl", "ethers-solc/openssl"]
dev-rpc = ["ethers-providers/dev-rpc"]
## signers
ledger = ["ethers-signers/ledger"]
Expand All @@ -67,9 +48,8 @@ abigen = ["ethers-contract/abigen"]
### abigen without reqwest
abigen-offline = ["ethers-contract/abigen-offline"]
## solc
ethers-solc = ["dep:ethers-solc", "ethers-etherscan/ethers-solc"]
solc-full = ["ethers-solc?/full"]
solc-tests = ["ethers-solc?/tests"]
solc-full = ["ethers-solc/full"]
solc-tests = ["ethers-solc/tests"]

# Deprecated
solc-sha2-asm = []
Expand All @@ -78,12 +58,14 @@ solc-sha2-asm = []
ethers-addressbook.workspace = true
ethers-contract.workspace = true
ethers-core.workspace = true
ethers-etherscan.workspace = true
ethers-etherscan = { workspace = true, features = ["ethers-solc"] }
ethers-middleware.workspace = true
ethers-providers.workspace = true
ethers-signers.workspace = true

ethers-solc = { workspace = true, optional = true }
ethers-solc = { workspace = true }

[dev-dependencies]
serde.workspace = true
tokio = { workspace = true, features = ["macros", "rt"] }
ethers-contract = { workspace = true, features = ["eip712"] }
ethers-providers = { workspace = true, features = ["rustls"] } # allow https connections
2 changes: 0 additions & 2 deletions ethers/src/lib.rs
Expand Up @@ -98,7 +98,6 @@ pub use ethers_providers as providers;
#[doc(inline)]
pub use ethers_signers as signers;
#[doc(inline)]
#[cfg(feature = "ethers-solc")]
pub use ethers_solc as solc;

#[doc(inline)]
Expand All @@ -121,7 +120,6 @@ pub mod prelude {

pub use super::signers::*;

#[cfg(feature = "ethers-solc")]
pub use super::solc::*;
}

Expand Down
3 changes: 2 additions & 1 deletion ethers/tests/live/celo.rs → ethers/tests/celo.rs
@@ -1,7 +1,8 @@
use crate::simple_storage::SimpleStorage;
use ethers::prelude::*;
use std::{sync::Arc, time::Duration};

ethers::contract::abigen!(SimpleStorage, "../testdata/SimpleStorage.json");

static CELO_TESTNET_URL: &str = "https://alfajores-forno.celo-testnet.org";

#[tokio::test]
Expand Down