fix: set chain id explicitly (#1647)

This commit is contained in:
Matthias Seitz 2022-08-30 18:45:36 +02:00 committed by GitHub
parent 6e6d827f1f
commit 792d415845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 15 deletions

View File

@ -4,7 +4,7 @@
use ethers_contract::{abigen, Abigen, EthCall, EthEvent}; use ethers_contract::{abigen, Abigen, EthCall, EthEvent};
use ethers_core::{ use ethers_core::{
abi::{AbiDecode, AbiEncode, Address, Tokenizable}, abi::{AbiDecode, AbiEncode, Address, Tokenizable},
types::{transaction::eip2718::TypedTransaction, Eip1559TransactionRequest, U256}, types::{transaction::eip2718::TypedTransaction, Chain, Eip1559TransactionRequest, U256},
utils::Anvil, utils::Anvil,
}; };
use ethers_middleware::SignerMiddleware; use ethers_middleware::SignerMiddleware;
@ -608,7 +608,8 @@ async fn can_send_struct_param() {
let server = Anvil::new().spawn(); let server = Anvil::new().spawn();
let wallet: LocalWallet = server.keys()[0].clone().into(); let wallet: LocalWallet = server.keys()[0].clone().into();
let provider = Provider::try_from(server.endpoint()).unwrap(); let provider = Provider::try_from(server.endpoint()).unwrap();
let client = Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(1337u64))); let client =
Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(Chain::AnvilHardhat)));
let contract = StructContract::deploy(client, ()).unwrap().legacy().send().await.unwrap(); let contract = StructContract::deploy(client, ()).unwrap().legacy().send().await.unwrap();

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
types::Address, types::{Address, Chain},
utils::{secret_key_to_address, unused_port}, utils::{secret_key_to_address, unused_port},
}; };
use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey}; use k256::{ecdsa::SigningKey, SecretKey as K256SecretKey};
@ -21,6 +21,7 @@ pub struct AnvilInstance {
private_keys: Vec<K256SecretKey>, private_keys: Vec<K256SecretKey>,
addresses: Vec<Address>, addresses: Vec<Address>,
port: u16, port: u16,
chain_id: Option<u64>,
} }
impl AnvilInstance { impl AnvilInstance {
@ -39,6 +40,11 @@ impl AnvilInstance {
self.port self.port
} }
/// Returns the chain of the anvil instance
pub fn chain_id(&self) -> u64 {
self.chain_id.unwrap_or_else(|| Chain::AnvilHardhat.into())
}
/// Returns the HTTP endpoint of this instance /// Returns the HTTP endpoint of this instance
pub fn endpoint(&self) -> String { pub fn endpoint(&self) -> String {
format!("http://localhost:{}", self.port) format!("http://localhost:{}", self.port)
@ -82,6 +88,7 @@ pub struct Anvil {
program: Option<PathBuf>, program: Option<PathBuf>,
port: Option<u16>, port: Option<u16>,
block_time: Option<u64>, block_time: Option<u64>,
chain_id: Option<u64>,
mnemonic: Option<String>, mnemonic: Option<String>,
fork: Option<String>, fork: Option<String>,
fork_block_number: Option<u64>, fork_block_number: Option<u64>,
@ -139,6 +146,13 @@ impl Anvil {
self self
} }
/// Sets the chain_id the `anvil` instance will use.
#[must_use]
pub fn chain_id<T: Into<u64>>(mut self, chain_id: T) -> Self {
self.chain_id = Some(chain_id.into());
self
}
/// Sets the mnemonic which will be used when the `anvil` instance is launched. /// Sets the mnemonic which will be used when the `anvil` instance is launched.
#[must_use] #[must_use]
pub fn mnemonic<T: Into<String>>(mut self, mnemonic: T) -> Self { pub fn mnemonic<T: Into<String>>(mut self, mnemonic: T) -> Self {
@ -208,6 +222,10 @@ impl Anvil {
cmd.arg("-m").arg(mnemonic); cmd.arg("-m").arg(mnemonic);
} }
if let Some(chain_id) = self.chain_id {
cmd.arg("--chain-id").arg(chain_id.to_string());
}
if let Some(block_time) = self.block_time { if let Some(block_time) = self.block_time {
cmd.arg("-b").arg(block_time.to_string()); cmd.arg("-b").arg(block_time.to_string());
} }
@ -258,7 +276,7 @@ impl Anvil {
child.stdout = Some(reader.into_inner()); child.stdout = Some(reader.into_inner());
AnvilInstance { pid: child, private_keys, addresses, port } AnvilInstance { pid: child, private_keys, addresses, port, chain_id: self.chain_id }
} }
} }

View File

@ -50,6 +50,40 @@ async fn send_eth() {
assert!(balance_before > balance_after); assert!(balance_before > balance_after);
} }
// hardhat compatibility test, to show hardhat rejects tx signed for other chains
#[tokio::test]
#[cfg(not(feature = "celo"))]
#[ignore]
async fn send_with_chain_id_hardhat() {
let wallet: LocalWallet =
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
let provider = Provider::try_from("http://localhost:8545").unwrap();
let client = SignerMiddleware::new(provider, wallet);
let tx = TransactionRequest::new().to(Address::random()).value(100u64);
let res = client.send_transaction(tx, None).await;
let err = res.unwrap_err();
assert!(err
.to_string()
.contains("Trying to send an incompatible EIP-155 transaction, signed for another chain."));
}
#[tokio::test]
#[cfg(not(feature = "celo"))]
#[ignore]
async fn send_with_chain_id_anvil() {
let wallet: LocalWallet =
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse().unwrap();
let provider = Provider::try_from("http://localhost:8545").unwrap();
let client = SignerMiddleware::new(provider, wallet);
let tx = TransactionRequest::new().to(Address::random()).value(100u64);
let res = client.send_transaction(tx, None).await;
let _err = res.unwrap_err();
}
#[tokio::test] #[tokio::test]
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
async fn pending_txs_with_confirmations_testnet() { async fn pending_txs_with_confirmations_testnet() {

View File

@ -42,7 +42,7 @@ async fn main() -> Result<()> {
Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64)); Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
// 4. instantiate the client with the wallet // 4. instantiate the client with the wallet
let client = SignerMiddleware::new(provider, wallet); let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
let client = Arc::new(client); let client = Arc::new(client);
// 5. create a factory which will be used to deploy instances of the contract // 5. create a factory which will be used to deploy instances of the contract

View File

@ -31,7 +31,7 @@ async fn main() -> Result<()> {
Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64)); Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
// 4. instantiate the client with the wallet // 4. instantiate the client with the wallet
let client = SignerMiddleware::new(provider, wallet); let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
let client = Arc::new(client); let client = Arc::new(client);
// 5. create a factory which will be used to deploy instances of the contract // 5. create a factory which will be used to deploy instances of the contract

View File

@ -22,7 +22,7 @@ async fn main() -> Result<()> {
Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64)); Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
// 4. instantiate the client with the wallet // 4. instantiate the client with the wallet
let client = Arc::new(SignerMiddleware::new(provider, wallet)); let client = Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id())));
// 5. deploy contract // 5. deploy contract
let greeter_contract = let greeter_contract =

View File

@ -1,12 +1,14 @@
#![cfg(target_arch = "wasm32")] #![cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*; use ethers::{
prelude::{
use ethers::prelude::{
abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws, abigen, ContractFactory, Http, JsonRpcClient, LocalWallet, Provider, SignerMiddleware, Ws,
},
signers::Signer,
types::Chain,
}; };
use std::{convert::TryFrom, sync::Arc}; use std::{convert::TryFrom, sync::Arc};
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser); wasm_bindgen_test_configure!(run_in_browser);
@ -22,14 +24,14 @@ abigen!(
async fn http_connect_and_deploy() { async fn http_connect_and_deploy() {
console_log!("connecting http..."); console_log!("connecting http...");
let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap(); let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
deploy(provider, ethers_wasm::utils::key(0)).await; deploy(provider, ethers_wasm::utils::key(0).with_chain_id(Chain::AnvilHardhat)).await;
} }
#[wasm_bindgen_test] #[wasm_bindgen_test]
async fn ws_connect_and_deploy() { async fn ws_connect_and_deploy() {
console_log!("connecting ws..."); console_log!("connecting ws...");
let provider = Provider::new(Ws::connect("ws://localhost:8545").await.unwrap()); let provider = Provider::new(Ws::connect("ws://localhost:8545").await.unwrap());
deploy(provider, ethers_wasm::utils::key(1)).await; deploy(provider, ethers_wasm::utils::key(1).with_chain_id(Chain::AnvilHardhat)).await;
} }
async fn deploy<T: JsonRpcClient>(provider: Provider<T>, wallet: LocalWallet) { async fn deploy<T: JsonRpcClient>(provider: Provider<T>, wallet: LocalWallet) {

View File

@ -13,7 +13,7 @@ async fn main() -> Result<()> {
let provider = Provider::<Http>::try_from(anvil.endpoint())?; let provider = Provider::<Http>::try_from(anvil.endpoint())?;
// connect the wallet to the provider // connect the wallet to the provider
let client = SignerMiddleware::new(provider, wallet); let client = SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id()));
// craft the transaction // craft the transaction
let tx = TransactionRequest::new().to(wallet2.address()).value(10000); let tx = TransactionRequest::new().to(wallet2.address()).value(10000);