test: replace ganache with anvil (#1286)

* ci: install anvil

* test: use anvil instead of ganache

* ci: fix anvil ver

* ci: re-enable example tests

* test: remove unnecessary assertions

* test: enable anvil launch test

* docs: typo

* test: fix anvil chain id

* ci: install ganache

Ganache is needed for the Ganache tests

* chore: remove legacy feature from some examples

* ci: correctly build examples

* test: use correct account balance for anvil

* chore: remove sub_id == 1 check

this was only possible in ganache because it gives serial
sub ids, but in every other reasonable client the ids are generated
randomly, so we cannot test for its value

* test: ensure txs are different

There is a bug in Ganache's mempool which accepts duplicate transactions (here with the same nonce), whereas here we pre-set all the nonces so that they end up having a different transaction hash.

* test: ignore ganache tests

* fix: terzor api changes

* ci(examples): install Anvil, remove geth/ganache

* test(provider): Anvil instead of Geth

some tests start to fail now

* fix: revert usage of Anvil in ipc tests

Anvil does not support IPC yet

* fix: update examples script

* ci: use anvil for wasm example

* replace last ganache usage

Co-authored-by: Oliver Nordbjerg <hi@notbjerg.me>
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
Matthias Seitz 2022-06-01 17:22:39 +02:00 committed by GitHub
parent 1a699ad72e
commit 89bc6420bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 306 additions and 296 deletions

View File

@ -21,12 +21,10 @@ jobs:
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Set up node - name: Install Anvil
uses: actions/setup-node@v1 uses: foundry-rs/foundry-toolchain@v1
with: with:
node-version: 10 version: nightly
- name: Install ganache
run: npm install -g ganache
- name: Install Solc - name: Install Solc
run: | run: |
mkdir -p "$HOME/bin" mkdir -p "$HOME/bin"
@ -66,13 +64,11 @@ jobs:
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Set up node
uses: actions/setup-node@v1
with:
node-version: 10
# TODO: can we combine these shared steps in github actions? # TODO: can we combine these shared steps in github actions?
- name: Install ganache - name: Install Anvil
run: npm install -g ganache uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Install Solc - name: Install Solc
run: | run: |
mkdir -p "$HOME/bin" mkdir -p "$HOME/bin"
@ -133,12 +129,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout sources
uses: actions/checkout@v1 uses: actions/checkout@v2
- name: Install node
uses: actions/setup-node@v1
with:
node-version: 10
- name: Install rust - name: Install rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@ -147,6 +139,11 @@ jobs:
profile: minimal profile: minimal
override: true override: true
- name: Install Anvil
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
with: with:
cache-on-failure: true cache-on-failure: true
@ -157,11 +154,8 @@ jobs:
command: check command: check
args: --target wasm32-unknown-unknown args: --target wasm32-unknown-unknown
- name: Launch Ganache - name: Launch Anvil
run: | run: anvil --block-time 2 -m "stuff inherit faith park genre spread huge knee ecology private marble supreme" &
cd examples/ethers-wasm
npm install
npm run ganache &
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
@ -176,59 +170,66 @@ jobs:
cd examples/ethers-wasm cd examples/ethers-wasm
wasm-pack test --headless --chrome wasm-pack test --headless --chrome
# TODO: Re-enable once we figure out why examples are running forever. examples:
# examples: name: Examples
# name: Examples runs-on: ubuntu-latest
# runs-on: ubuntu-latest steps:
# steps: - name: Checkout sources
# - name: Checkout sources uses: actions/checkout@v2
# uses: actions/checkout@v2
# - name: Set up node
# uses: actions/setup-node@v1
# with:
# node-version: 10
# - name: Install ganache
# run: npm install -g ganache
# - name: Install Solc
# run: |
# mkdir -p "$HOME/bin"
# wget -q https://github.com/ethereum/solidity/releases/download/v0.8.10/solc-static-linux -O $HOME/bin/solc
# chmod u+x "$HOME/bin/solc"
# export PATH=$HOME/bin:$PATH
# solc --version
# - name: Install geth - name: Install Anvil
# run: | uses: foundry-rs/foundry-toolchain@v1
# mkdir -p "$HOME/bin" with:
# wget -q https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.23-8c2f2715.tar.gz version: nightly
# tar -xvf geth-linux-amd64-1.9.23-8c2f2715.tar.gz
# mv geth-linux-amd64-1.9.23-8c2f2715/geth $HOME/bin/geth - name: Install Solc
# chmod u+x "$HOME/bin/geth" run: |
# export PATH=$HOME/bin:$PATH mkdir -p "$HOME/bin"
# geth version wget -q https://github.com/ethereum/solidity/releases/download/v0.8.10/solc-static-linux -O $HOME/bin/solc
# - name: Install stable toolchain chmod u+x "$HOME/bin/solc"
# uses: actions-rs/toolchain@v1 export PATH=$HOME/bin:$PATH
# with: solc --version
# profile: minimal
# toolchain: stable - name: Install stable toolchain
# override: true uses: actions-rs/toolchain@v1
# components: rustfmt, clippy with:
# - uses: Swatinem/rust-cache@v1 profile: minimal
# with: toolchain: stable
# cache-on-failure: true override: true
# - name: Build all examples components: rustfmt, clippy
# run: | - uses: Swatinem/rust-cache@v1
# export PATH=$HOME/bin:$PATH with:
# for file in examples/*.rs; do cache-on-failure: true
# name="$(echo "$file" | cut -f 1 -d '.')" - name: Build all examples
# echo "building $name" run: |
# cargo build -p ethers --example "$(basename "$name")" export PATH=$HOME/bin:$PATH
# done examples=$(cargo metadata --format-version 1 | \
# - name: Run all examples jq -c '.packages[]
# run: | | select(.name == "ethers")
# export PATH=$HOME/bin:$PATH | .targets[]
# chmod +x ./scripts/examples.sh | select(.kind[] | contains("example"))
# ./scripts/examples.sh | with_entries(select([.key]
| inside(["name", "required-features"])))'
)
for example in $examples; do
name="$(echo "$example" | jq -r '.name')"
args=(
-p ethers
--example "$name"
)
features="$(echo "$example" | jq -r 'try(."required-features" | join(","))')"
if [[ ! -z "$features" ]]; then
args+=(--features "$features")
fi
echo "building $name"
cargo build "${args[@]}"
done
- name: Run all examples
run: |
export PATH=$HOME/bin:$PATH
chmod +x ./scripts/examples.sh
./scripts/examples.sh
windows-build: windows-build:
runs-on: windows-latest runs-on: windows-latest

View File

@ -115,17 +115,14 @@ opt-level = "s"
[[example]] [[example]]
name = "contract_human_readable" name = "contract_human_readable"
path = "examples/contract_human_readable.rs" path = "examples/contract_human_readable.rs"
required-features = ["legacy"]
[[example]] [[example]]
name = "contract_with_abi" name = "contract_with_abi"
path = "examples/contract_with_abi.rs" path = "examples/contract_with_abi.rs"
required-features = ["legacy"]
[[example]] [[example]]
name = "contract_with_abi_and_bytecode" name = "contract_with_abi_and_bytecode"
path = "examples/contract_with_abi_and_bytecode.rs" path = "examples/contract_with_abi_and_bytecode.rs"
required-features = ["legacy"]
[[example]] [[example]]
name = "ipc" name = "ipc"
@ -151,3 +148,8 @@ required-features = ["trezor"]
name = "yubi" name = "yubi"
path = "examples/yubi.rs" path = "examples/yubi.rs"
required-features = ["yubi"] required-features = ["yubi"]
[[example]]
name = "paginated_logs"
path = "examples/paginated_logs.rs"
required-features = ["rustls"]

View File

@ -32,7 +32,7 @@ ethers = { git = "https://github.com/gakonst/ethers-rs" }
Tests require the following installed: Tests require the following installed:
1. [`solc`](https://solidity.readthedocs.io/en/latest/installing-solidity.html) (>=0.8.10). We also recommend using [solc-select](https://github.com/crytic/solc-select) for more flexibility. 1. [`solc`](https://solidity.readthedocs.io/en/latest/installing-solidity.html) (>=0.8.10). We also recommend using [solc-select](https://github.com/crytic/solc-select) for more flexibility.
2. [`ganache-cli`](https://github.com/trufflesuite/ganache-cli#installation) 2. [`anvil`](https://github.com/foundry-rs/foundry/blob/master/anvil/README.md)
3. [`geth`](https://github.com/ethereum/go-ethereum) 3. [`geth`](https://github.com/ethereum/go-ethereum)
In addition, it is recommended that you set the `ETHERSCAN_API_KEY` environment variable In addition, it is recommended that you set the `ETHERSCAN_API_KEY` environment variable

View File

@ -4,7 +4,7 @@ use ethers_contract::{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, Eip1559TransactionRequest, U256},
utils::Ganache, utils::Anvil,
}; };
use ethers_middleware::SignerMiddleware; use ethers_middleware::SignerMiddleware;
use ethers_providers::{MockProvider, Provider}; use ethers_providers::{MockProvider, Provider};
@ -305,10 +305,10 @@ async fn can_handle_underscore_functions() {
"ethers-contract/tests/solidity-contracts/simplestorage_abi.json", "ethers-contract/tests/solidity-contracts/simplestorage_abi.json",
); );
// launcht the network & connect to it // launch the network & connect to it
let ganache = ethers_core::utils::Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let from = ganache.addresses()[0]; let from = anvil.addresses()[0];
let provider = Provider::try_from(ganache.endpoint()) let provider = Provider::try_from(anvil.endpoint())
.unwrap() .unwrap()
.with_sender(from) .with_sender(from)
.interval(std::time::Duration::from_millis(10)); .interval(std::time::Duration::from_millis(10));
@ -484,9 +484,9 @@ fn can_handle_case_sensitive_calls() {
#[tokio::test] #[tokio::test]
async fn can_deploy_greeter() { async fn can_deploy_greeter() {
abigen!(Greeter, "ethers-contract/tests/solidity-contracts/greeter.json",); abigen!(Greeter, "ethers-contract/tests/solidity-contracts/greeter.json",);
let ganache = ethers_core::utils::Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let from = ganache.addresses()[0]; let from = anvil.addresses()[0];
let provider = Provider::try_from(ganache.endpoint()) let provider = Provider::try_from(anvil.endpoint())
.unwrap() .unwrap()
.with_sender(from) .with_sender(from)
.interval(std::time::Duration::from_millis(10)); .interval(std::time::Duration::from_millis(10));
@ -502,9 +502,9 @@ async fn can_deploy_greeter() {
#[tokio::test] #[tokio::test]
async fn can_abiencoderv2_output() { async fn can_abiencoderv2_output() {
abigen!(AbiEncoderv2Test, "ethers-contract/tests/solidity-contracts/abiencoderv2test_abi.json",); abigen!(AbiEncoderv2Test, "ethers-contract/tests/solidity-contracts/abiencoderv2test_abi.json",);
let ganache = ethers_core::utils::Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let from = ganache.addresses()[0]; let from = anvil.addresses()[0];
let provider = Provider::try_from(ganache.endpoint()) let provider = Provider::try_from(anvil.endpoint())
.unwrap() .unwrap()
.with_sender(from) .with_sender(from)
.interval(std::time::Duration::from_millis(10)); .interval(std::time::Duration::from_millis(10));
@ -575,7 +575,7 @@ fn can_handle_overloaded_events() {
async fn can_send_struct_param() { async fn can_send_struct_param() {
abigen!(StructContract, "./tests/solidity-contracts/StructContract.json"); abigen!(StructContract, "./tests/solidity-contracts/StructContract.json");
let server = Ganache::default().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(1337u64)));

View File

@ -10,7 +10,7 @@ use ethers_contract::EthEvent;
mod derive; mod derive;
use ethers_contract::{Contract, ContractFactory}; use ethers_contract::{Contract, ContractFactory};
use ethers_core::{abi::Abi, types::Bytes, utils::GanacheInstance}; use ethers_core::{abi::Abi, types::Bytes, utils::AnvilInstance};
use ethers_providers::{Http, Middleware, Provider}; use ethers_providers::{Http, Middleware, Provider};
use ethers_solc::Solc; use ethers_solc::Solc;
use std::{convert::TryFrom, sync::Arc, time::Duration}; use std::{convert::TryFrom, sync::Arc, time::Duration};
@ -38,16 +38,16 @@ pub fn compile_contract(name: &str, filename: &str) -> (Abi, Bytes) {
} }
/// connects the private key to http://localhost:8545 /// connects the private key to http://localhost:8545
pub fn connect(ganache: &GanacheInstance, idx: usize) -> Arc<Provider<Http>> { pub fn connect(anvil: &AnvilInstance, idx: usize) -> Arc<Provider<Http>> {
let sender = ganache.addresses()[idx]; let sender = anvil.addresses()[idx];
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(10u64)) .interval(Duration::from_millis(10u64))
.with_sender(sender); .with_sender(sender);
Arc::new(provider) Arc::new(provider)
} }
/// Launches a ganache instance and deploys the SimpleStorage contract /// Launches a Anvil instance and deploys the SimpleStorage contract
pub async fn deploy<M: Middleware>(client: Arc<M>, abi: Abi, bytecode: Bytes) -> Contract<M> { pub async fn deploy<M: Middleware>(client: Arc<M>, abi: Abi, bytecode: Bytes) -> Contract<M> {
let factory = ContractFactory::new(abi, bytecode, client); let factory = ContractFactory::new(abi, bytecode, client);
let deployer = factory.deploy("initial value".to_string()).unwrap(); let deployer = factory.deploy("initial value".to_string()).unwrap();

View File

@ -11,7 +11,7 @@ mod eth_tests {
use ethers_core::{ use ethers_core::{
abi::{Detokenize, Token, Tokenizable}, abi::{Detokenize, Token, Tokenizable},
types::{transaction::eip712::Eip712, Address, BlockId, Bytes, I256, U256}, types::{transaction::eip712::Eip712, Address, BlockId, Bytes, I256, U256},
utils::{keccak256, Ganache}, utils::{keccak256, Anvil},
}; };
use ethers_derive_eip712::*; use ethers_derive_eip712::*;
use ethers_middleware::signer::SignerMiddleware; use ethers_middleware::signer::SignerMiddleware;
@ -23,15 +23,15 @@ mod eth_tests {
async fn deploy_and_call_contract() { async fn deploy_and_call_contract() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
// launch ganache // launch anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// Instantiate the clients. We assume that clients consume the provider and the wallet // Instantiate the clients. We assume that clients consume the provider and the wallet
// (which makes sense), so for multi-client tests, you must clone the provider. // (which makes sense), so for multi-client tests, you must clone the provider.
let addrs = ganache.addresses().to_vec(); let addrs = anvil.addresses().to_vec();
let addr2 = addrs[1]; let addr2 = addrs[1];
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let client2 = connect(&ganache, 1); let client2 = connect(&anvil, 1);
// create a factory which will be used to deploy instances of the contract // create a factory which will be used to deploy instances of the contract
let factory = ContractFactory::new(abi, bytecode, client.clone()); let factory = ContractFactory::new(abi, bytecode, client.clone());
@ -97,8 +97,8 @@ mod eth_tests {
#[cfg(feature = "abigen")] #[cfg(feature = "abigen")]
async fn get_past_events() { async fn get_past_events() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let address = client.get_accounts().await.unwrap()[0]; let address = client.get_accounts().await.unwrap()[0];
let contract = deploy(client.clone(), abi, bytecode).await; let contract = deploy(client.clone(), abi, bytecode).await;
@ -136,9 +136,9 @@ mod eth_tests {
#[cfg(feature = "abigen")] #[cfg(feature = "abigen")]
async fn get_events_with_meta() { async fn get_events_with_meta() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let address = ganache.addresses()[0]; let address = anvil.addresses()[0];
let contract = deploy(client.clone(), abi, bytecode).await; let contract = deploy(client.clone(), abi, bytecode).await;
// and we can fetch the events // and we can fetch the events
@ -168,8 +168,8 @@ mod eth_tests {
#[tokio::test] #[tokio::test]
async fn call_past_state() { async fn call_past_state() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let contract = deploy(client.clone(), abi, bytecode).await; let contract = deploy(client.clone(), abi, bytecode).await;
let deployed_block = client.get_block_number().await.unwrap(); let deployed_block = client.get_block_number().await.unwrap();
@ -257,24 +257,21 @@ mod eth_tests {
#[cfg(feature = "abigen")] #[cfg(feature = "abigen")]
async fn watch_events() { async fn watch_events() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let contract = deploy(client.clone(), abi.clone(), bytecode).await; let contract = deploy(client.clone(), abi.clone(), bytecode).await;
// We spawn the event listener: // We spawn the event listener:
let event = contract.event::<ValueChanged>(); let event = contract.event::<ValueChanged>();
let mut stream = event.stream().await.unwrap(); let mut stream = event.stream().await.unwrap();
assert_eq!(stream.id, 1.into());
// Also set up a subscription for the same thing // Also set up a subscription for the same thing
let ws = Provider::connect(ganache.ws_endpoint()).await.unwrap(); let ws = Provider::connect(anvil.ws_endpoint()).await.unwrap();
let contract2 = ethers_contract::Contract::new(contract.address(), abi, ws); let contract2 = ethers_contract::Contract::new(contract.address(), abi, ws);
let event2 = contract2.event::<ValueChanged>(); let event2 = contract2.event::<ValueChanged>();
let mut subscription = event2.subscribe().await.unwrap(); let mut subscription = event2.subscribe().await.unwrap();
assert_eq!(subscription.id, 2.into());
let mut subscription_meta = event2.subscribe().await.unwrap().with_meta(); let mut subscription_meta = event2.subscribe().await.unwrap().with_meta();
assert_eq!(subscription_meta.0.id, 3.into());
let num_calls = 3u64; let num_calls = 3u64;
@ -303,12 +300,12 @@ mod eth_tests {
#[tokio::test] #[tokio::test]
async fn watch_subscription_events_multiple_addresses() { async fn watch_subscription_events_multiple_addresses() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let contract_1 = deploy(client.clone(), abi.clone(), bytecode.clone()).await; let contract_1 = deploy(client.clone(), abi.clone(), bytecode.clone()).await;
let contract_2 = deploy(client.clone(), abi.clone(), bytecode).await; let contract_2 = deploy(client.clone(), abi.clone(), bytecode).await;
let ws = Provider::connect(ganache.ws_endpoint()).await.unwrap(); let ws = Provider::connect(anvil.ws_endpoint()).await.unwrap();
let filter = Filter::new() let filter = Filter::new()
.address(ValueOrArray::Array(vec![contract_1.address(), contract_2.address()])); .address(ValueOrArray::Array(vec![contract_1.address(), contract_2.address()]));
let mut stream = ws.subscribe_logs(&filter).await.unwrap(); let mut stream = ws.subscribe_logs(&filter).await.unwrap();
@ -332,11 +329,11 @@ mod eth_tests {
#[tokio::test] #[tokio::test]
async fn signer_on_node() { async fn signer_on_node() {
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
// spawn ganache // spawn anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// connect // connect
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(std::time::Duration::from_millis(50u64)); .interval(std::time::Duration::from_millis(50u64));
@ -373,9 +370,8 @@ mod eth_tests {
// get ABI and bytecode for the SimpleStorage contract // get ABI and bytecode for the SimpleStorage contract
let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol"); let (abi, bytecode) = compile_contract("SimpleStorage", "SimpleStorage.sol");
// launch ganache // launch anvil
// some tests expect 100 ether (-e === --wallet.defaultBalance in ether) let anvil = Anvil::new().spawn();
let ganache = Ganache::new().arg("-e").arg("100").spawn();
// Instantiate the clients. We assume that clients consume the provider and the wallet // Instantiate the clients. We assume that clients consume the provider and the wallet
// (which makes sense), so for multi-client tests, you must clone the provider. // (which makes sense), so for multi-client tests, you must clone the provider.
@ -383,13 +379,13 @@ mod eth_tests {
// `client2` is used to deploy the first SimpleStorage contract // `client2` is used to deploy the first SimpleStorage contract
// `client3` is used to deploy the second SimpleStorage contract // `client3` is used to deploy the second SimpleStorage contract
// `client4` is used to make the aggregate call // `client4` is used to make the aggregate call
let addrs = ganache.addresses().to_vec(); let addrs = anvil.addresses().to_vec();
let addr2 = addrs[1]; let addr2 = addrs[1];
let addr3 = addrs[2]; let addr3 = addrs[2];
let client = connect(&ganache, 0); let client = connect(&anvil, 0);
let client2 = connect(&ganache, 1); let client2 = connect(&anvil, 1);
let client3 = connect(&ganache, 2); let client3 = connect(&anvil, 2);
let client4 = connect(&ganache, 3); let client4 = connect(&anvil, 3);
// create a factory which will be used to deploy instances of the contract // create a factory which will be used to deploy instances of the contract
let multicall_factory = let multicall_factory =
@ -491,7 +487,7 @@ mod eth_tests {
assert_eq!(return_data.2, multicall_contract.address()); assert_eq!(return_data.2, multicall_contract.address());
assert_eq!(return_data.3, multicall_contract.address()); assert_eq!(return_data.3, multicall_contract.address());
let addrs = ganache.addresses(); let addrs = anvil.addresses();
// query ETH balances of multiple addresses // query ETH balances of multiple addresses
// these keys haven't been used to do any tx // these keys haven't been used to do any tx
// so should have 100 ETH // so should have 100 ETH
@ -502,9 +498,9 @@ mod eth_tests {
.eth_balance_of(addrs[6]); .eth_balance_of(addrs[6]);
let balances: (U256, U256, U256) = multicall.call().await.unwrap(); let balances: (U256, U256, U256) = multicall.call().await.unwrap();
assert_eq!(balances.0, U256::from(100_000_000_000_000_000_000u128)); assert_eq!(balances.0, U256::from(10_000_000_000_000_000_000_000u128));
assert_eq!(balances.1, U256::from(100_000_000_000_000_000_000u128)); assert_eq!(balances.1, U256::from(10_000_000_000_000_000_000_000u128));
assert_eq!(balances.2, U256::from(100_000_000_000_000_000_000u128)); assert_eq!(balances.2, U256::from(10_000_000_000_000_000_000_000u128));
// clear multicall so we can test `call_raw` w/ >16 calls // clear multicall so we can test `call_raw` w/ >16 calls
multicall.clear_calls(); multicall.clear_calls();
@ -569,13 +565,13 @@ mod eth_tests {
// get ABI and bytecode for the DeriveEip712Test contract // get ABI and bytecode for the DeriveEip712Test contract
let (abi, bytecode) = compile_contract("DeriveEip712Test", "DeriveEip712Test.sol"); let (abi, bytecode) = compile_contract("DeriveEip712Test", "DeriveEip712Test.sol");
// launch ganache // launch anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.expect("failed to instantiate provider from ganache endpoint") .expect("failed to instantiate provider from anvil endpoint")
.interval(Duration::from_millis(10u64)); .interval(Duration::from_millis(10u64));
let client = let client =

View File

@ -210,7 +210,6 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
#[ignore]
fn can_launch_anvil() { fn can_launch_anvil() {
let _ = Anvil::new().spawn(); let _ = Anvil::new().spawn();
} }

View File

@ -222,11 +222,13 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
#[ignore]
fn configurable_startup_timeout() { fn configurable_startup_timeout() {
Ganache::new().startup_timeout_millis(100000_u64).spawn(); Ganache::new().startup_timeout_millis(100000_u64).spawn();
} }
#[test] #[test]
#[ignore]
fn default_startup_works() { fn default_startup_works() {
Ganache::new().spawn(); Ganache::new().spawn();
} }

View File

@ -27,7 +27,7 @@ pub enum EtherscanError {
RateLimitExceeded, RateLimitExceeded,
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
#[error("Local networks (e.g. ganache, geth --dev) cannot be indexed by etherscan")] #[error("Local networks (e.g. anvil, ganache, geth --dev) cannot be indexed by etherscan")]
LocalNetworksNotSupported, LocalNetworksNotSupported,
#[error("Unknown error: {0}")] #[error("Unknown error: {0}")]
Unknown(String), Unknown(String),

View File

@ -336,7 +336,7 @@ mod tests {
use super::*; use super::*;
use ethers_core::{ use ethers_core::{
types::TransactionRequest, types::TransactionRequest,
utils::{self, keccak256, Ganache}, utils::{self, keccak256, Anvil},
}; };
use ethers_providers::Provider; use ethers_providers::Provider;
use ethers_signers::LocalWallet; use ethers_signers::LocalWallet;
@ -360,11 +360,10 @@ mod tests {
let chain_id = 1u64; let chain_id = 1u64;
// Signer middlewares now rely on a working provider which it can query the chain id from, // Signer middlewares now rely on a working provider which it can query the chain id from,
// so we make sure ganache is started with the chain id that the expected tx was signed // so we make sure Anvil is started with the chain id that the expected tx was signed
// with // with
let ganache = let anvil = Anvil::new().args(vec!["--chain-id".to_string(), chain_id.to_string()]).spawn();
Ganache::new().args(vec!["--chain.chainId".to_string(), chain_id.to_string()]).spawn(); let provider = Provider::try_from(anvil.endpoint()).unwrap();
let provider = Provider::try_from(ganache.endpoint()).unwrap();
let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318" let key = "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
.parse::<LocalWallet>() .parse::<LocalWallet>()
.unwrap() .unwrap()
@ -384,11 +383,11 @@ mod tests {
} }
#[tokio::test] #[tokio::test]
async fn ganache_consistent_chainid() { async fn anvil_consistent_chainid() {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let provider = Provider::try_from(ganache.endpoint()).unwrap(); let provider = Provider::try_from(anvil.endpoint()).unwrap();
let chain_id = provider.get_chainid().await.unwrap(); let chain_id = provider.get_chainid().await.unwrap();
assert_eq!(chain_id, U256::from(1337)); assert_eq!(chain_id, U256::from(31337));
// Intentionally do not set the chain id here so we ensure that the signer pulls the // Intentionally do not set the chain id here so we ensure that the signer pulls the
// provider's chain id. // provider's chain id.
@ -406,9 +405,9 @@ mod tests {
} }
#[tokio::test] #[tokio::test]
async fn ganache_consistent_chainid_not_default() { async fn anvil_consistent_chainid_not_default() {
let ganache = Ganache::new().args(vec!["--chain.chainId", "13371337"]).spawn(); let anvil = Anvil::new().args(vec!["--chain-id", "13371337"]).spawn();
let provider = Provider::try_from(ganache.endpoint()).unwrap(); let provider = Provider::try_from(anvil.endpoint()).unwrap();
let chain_id = provider.get_chainid().await.unwrap(); let chain_id = provider.get_chainid().await.unwrap();
assert_eq!(chain_id, U256::from(13371337)); assert_eq!(chain_id, U256::from(13371337));
@ -429,9 +428,9 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn handles_tx_from_field() { async fn handles_tx_from_field() {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let acc = ganache.addresses()[0]; let acc = anvil.addresses()[0];
let provider = Provider::try_from(ganache.endpoint()).unwrap(); let provider = Provider::try_from(anvil.endpoint()).unwrap();
let key = LocalWallet::new(&mut rand::thread_rng()).with_chain_id(1u32); let key = LocalWallet::new(&mut rand::thread_rng()).with_chain_id(1u32);
provider provider
.send_transaction( .send_transaction(
@ -459,7 +458,7 @@ mod tests {
assert_eq!(tx.from, client.address()); assert_eq!(tx.from, client.address());
// signing a TransactionRequest with a from address that is not the // signing a TransactionRequest with a from address that is not the
// signer should result in the default ganache account being used // signer should result in the default anvil account being used
let request_from_other = request.from(acc); let request_from_other = request.from(acc);
let hash = *client.send_transaction(request_from_other, None).await.unwrap(); let hash = *client.send_transaction(request_from_other, None).await.unwrap();
let tx = client.get_transaction(hash).await.unwrap().unwrap(); let tx = client.get_transaction(hash).await.unwrap().unwrap();

View File

@ -4,7 +4,7 @@ use std::convert::TryFrom;
use async_trait::async_trait; use async_trait::async_trait;
use ethers_core::{types::*, utils::Ganache}; use ethers_core::{types::*, utils::Anvil};
use ethers_middleware::gas_oracle::{ use ethers_middleware::gas_oracle::{
EthGasStation, Etherchain, Etherscan, GasCategory, GasOracle, GasOracleError, EthGasStation, Etherchain, Etherscan, GasCategory, GasOracle, GasOracleError,
GasOracleMiddleware, GasOracleMiddleware,
@ -31,14 +31,14 @@ impl GasOracle for FakeGasOracle {
#[tokio::test] #[tokio::test]
async fn using_gas_oracle() { async fn using_gas_oracle() {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let from = ganache.addresses()[0]; let from = anvil.addresses()[0];
// connect to the network // connect to the network
let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap(); let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
// this is set because ganache now sets 875000000 as the first block's base fee // this is set because anvil now sets 875000000 as the first block's base fee
let base_fee = 875000000; let base_fee = 875000000;
// assign a gas oracle to use // assign a gas oracle to use
let gas_oracle = FakeGasOracle { gas_price: (base_fee + 1337).into() }; let gas_oracle = FakeGasOracle { gas_price: (base_fee + 1337).into() };

View File

@ -22,16 +22,16 @@ static WALLETS: Lazy<TestWallets> = Lazy::new(|| {
#[tokio::test] #[tokio::test]
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
async fn send_eth() { async fn send_eth() {
use ethers_core::utils::Ganache; use ethers_core::utils::Anvil;
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// this private key belongs to the above mnemonic // this private key belongs to the above mnemonic
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
let wallet2: LocalWallet = ganache.keys()[1].clone().into(); let wallet2: LocalWallet = anvil.keys()[1].clone().into();
// connect to the network // connect to the network
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(10u64)); .interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64(); let chain_id = provider.get_chainid().await.unwrap().as_u64();
@ -156,17 +156,17 @@ async fn test_send_transaction() {
#[tokio::test] #[tokio::test]
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
async fn send_transaction_handles_tx_from_field() { async fn send_transaction_handles_tx_from_field() {
use ethers_core::utils::Ganache; use ethers_core::utils::Anvil;
// launch ganache // launch anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// grab 2 wallets // grab 2 wallets
let signer: LocalWallet = ganache.keys()[0].clone().into(); let signer: LocalWallet = anvil.keys()[0].clone().into();
let other: LocalWallet = ganache.keys()[1].clone().into(); let other: LocalWallet = anvil.keys()[1].clone().into();
// connect to the network // connect to the network
let provider = Provider::try_from(ganache.endpoint()).unwrap(); let provider = Provider::try_from(anvil.endpoint()).unwrap();
let provider = let provider =
SignerMiddleware::new_with_provider_chain(provider, signer.clone()).await.unwrap(); SignerMiddleware::new_with_provider_chain(provider, signer.clone()).await.unwrap();

View File

@ -1,7 +1,7 @@
#![cfg(not(target_arch = "wasm32"))] #![cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
mod tests { mod tests {
use ethers_core::{rand::thread_rng, types::TransactionRequest, utils::Ganache}; use ethers_core::{rand::thread_rng, types::TransactionRequest, utils::Anvil};
use ethers_middleware::{ use ethers_middleware::{
gas_escalator::{Frequency, GasEscalatorMiddleware, GeometricGasPrice}, gas_escalator::{Frequency, GasEscalatorMiddleware, GeometricGasPrice},
gas_oracle::{EthGasStation, GasCategory, GasOracleMiddleware}, gas_oracle::{EthGasStation, GasCategory, GasOracleMiddleware},
@ -52,13 +52,13 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn can_stack_middlewares() { async fn can_stack_middlewares() {
let ganache = Ganache::new().block_time(5u64).spawn(); let anvil = Anvil::new().block_time(5u64).spawn();
let gas_oracle = EthGasStation::new(None).category(GasCategory::SafeLow); let gas_oracle = EthGasStation::new(None).category(GasCategory::SafeLow);
let signer: LocalWallet = ganache.keys()[0].clone().into(); let signer: LocalWallet = anvil.keys()[0].clone().into();
let address = signer.address(); let address = signer.address();
// the base provider // the base provider
let provider = Arc::new(Provider::<Http>::try_from(ganache.endpoint()).unwrap()); let provider = Arc::new(Provider::<Http>::try_from(anvil.endpoint()).unwrap());
let chain_id = provider.get_chainid().await.unwrap().as_u64(); let chain_id = provider.get_chainid().await.unwrap().as_u64();
let signer = signer.with_chain_id(chain_id); let signer = signer.with_chain_id(chain_id);

View File

@ -1,7 +1,7 @@
#![cfg(not(target_arch = "wasm32"))] #![cfg(not(target_arch = "wasm32"))]
#![allow(unused)] #![allow(unused)]
use ethers_contract::{BaseContract, ContractFactory}; use ethers_contract::{BaseContract, ContractFactory};
use ethers_core::{abi::Abi, types::*, utils::Ganache}; use ethers_core::{abi::Abi, types::*, utils::Anvil};
use ethers_middleware::{ use ethers_middleware::{
transformer::{DsProxy, TransformerMiddleware}, transformer::{DsProxy, TransformerMiddleware},
SignerMiddleware, SignerMiddleware,
@ -29,10 +29,10 @@ async fn ds_proxy_transformer() {
// randomness // randomness
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
// spawn ganache and instantiate a signer middleware. // spawn anvil and instantiate a signer middleware.
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(10u64)); .interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64(); let chain_id = provider.get_chainid().await.unwrap().as_u64();
@ -88,10 +88,10 @@ async fn ds_proxy_code() {
// randomness // randomness
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
// spawn ganache and instantiate a signer middleware. // spawn anvil and instantiate a signer middleware.
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let wallet: LocalWallet = ganache.keys()[1].clone().into(); let wallet: LocalWallet = anvil.keys()[1].clone().into();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(10u64)); .interval(Duration::from_millis(10u64));
let chain_id = provider.get_chainid().await.unwrap().as_u64(); let chain_id = provider.get_chainid().await.unwrap().as_u64();

View File

@ -30,15 +30,15 @@ use wasm_timer::Delay;
/// ///
///``` ///```
/// # use ethers_providers::{Provider, Http}; /// # use ethers_providers::{Provider, Http};
/// # use ethers_core::utils::Ganache; /// # use ethers_core::utils::Anvil;
/// # use std::convert::TryFrom; /// # use std::convert::TryFrom;
/// use ethers_providers::Middleware; /// use ethers_providers::Middleware;
/// use ethers_core::types::TransactionRequest; /// use ethers_core::types::TransactionRequest;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> { /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let ganache = Ganache::new().spawn(); /// # let anvil = Anvil::new().spawn();
/// # let client = Provider::<Http>::try_from(ganache.endpoint()).unwrap(); /// # let client = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
/// # let accounts = client.get_accounts().await?; /// # let accounts = client.get_accounts().await?;
/// # let from = accounts[0]; /// # let from = accounts[0];
/// # let to = accounts[1]; /// # let to = accounts[1];

View File

@ -1204,7 +1204,7 @@ impl<P: JsonRpcClient> Provider<P> {
} }
#[cfg(test)] #[cfg(test)]
/// ganache-only function for mining empty blocks /// Anvil and Ganache-only function for mining empty blocks
pub async fn mine(&self, num_blocks: usize) -> Result<(), ProviderError> { pub async fn mine(&self, num_blocks: usize) -> Result<(), ProviderError> {
for _ in 0..num_blocks { for _ in 0..num_blocks {
self.inner.request::<_, U256>("evm_mine", None::<()>).await.map_err(Into::into)?; self.inner.request::<_, U256>("evm_mine", None::<()>).await.map_err(Into::into)?;
@ -1365,13 +1365,13 @@ impl Provider<RetryClient<HttpProvider>> {
///``` ///```
/// use ethers_providers::{Provider, Http, Middleware, DevRpcMiddleware}; /// use ethers_providers::{Provider, Http, Middleware, DevRpcMiddleware};
/// use ethers_core::types::TransactionRequest; /// use ethers_core::types::TransactionRequest;
/// use ethers_core::utils::Ganache; /// use ethers_core::utils::Anvil;
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> { /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ganache = Ganache::new().spawn(); /// let anvil = Anvil::new().spawn();
/// let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap(); /// let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
/// let client = DevRpcMiddleware::new(provider); /// let client = DevRpcMiddleware::new(provider);
/// ///
/// // snapshot the initial state /// // snapshot the initial state
@ -1450,7 +1450,7 @@ pub mod dev_rpc {
Self(inner) Self(inner)
} }
// both ganache and hardhat increment snapshot id even if no state has changed // Ganache, Hardhat and Anvil increment snapshot ID even if no state has changed
pub async fn snapshot(&self) -> Result<U256, DevRpcMiddlewareError<M>> { pub async fn snapshot(&self) -> Result<U256, DevRpcMiddlewareError<M>> {
self.provider().request::<(), U256>("evm_snapshot", ()).await.map_err(From::from) self.provider().request::<(), U256>("evm_snapshot", ()).await.map_err(From::from)
} }
@ -1474,14 +1474,13 @@ pub mod dev_rpc {
mod tests { mod tests {
use super::*; use super::*;
use crate::{Http, Provider}; use crate::{Http, Provider};
use ethers_core::utils::Ganache; use ethers_core::utils::Anvil;
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::test] #[tokio::test]
async fn test_snapshot() { async fn test_snapshot() {
// launch ganache let anvil = Anvil::new().spawn();
let ganache = Ganache::new().spawn(); let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap();
let client = DevRpcMiddleware::new(provider); let client = DevRpcMiddleware::new(provider);
// snapshot initial state // snapshot initial state
@ -1544,7 +1543,7 @@ mod tests {
types::{ types::{
transaction::eip2930::AccessList, Eip1559TransactionRequest, TransactionRequest, H256, transaction::eip2930::AccessList, Eip1559TransactionRequest, TransactionRequest, H256,
}, },
utils::Geth, utils::Anvil,
}; };
use futures_util::StreamExt; use futures_util::StreamExt;
@ -1625,7 +1624,7 @@ mod tests {
#[cfg_attr(feature = "celo", ignore)] #[cfg_attr(feature = "celo", ignore)]
async fn test_new_block_filter() { async fn test_new_block_filter() {
let num_blocks = 3; let num_blocks = 3;
let geth = Geth::new().block_time(2u64).spawn(); let geth = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(geth.endpoint()) let provider = Provider::<Http>::try_from(geth.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(1000)); .interval(Duration::from_millis(1000));
@ -1644,16 +1643,15 @@ mod tests {
#[tokio::test] #[tokio::test]
#[cfg_attr(feature = "celo", ignore)] #[cfg_attr(feature = "celo", ignore)]
async fn test_is_signer() { async fn test_is_signer() {
use ethers_core::utils::Ganache; use ethers_core::utils::Anvil;
use std::str::FromStr; use std::str::FromStr;
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider =
.unwrap() Provider::<Http>::try_from(anvil.endpoint()).unwrap().with_sender(anvil.addresses()[0]);
.with_sender(ganache.addresses()[0]);
assert!(provider.is_signer().await); assert!(provider.is_signer().await);
let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap(); let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
assert!(!provider.is_signer().await); assert!(!provider.is_signer().await);
let sender = Address::from_str("635B4764D1939DfAcD3a8014726159abC277BecC") let sender = Address::from_str("635B4764D1939DfAcD3a8014726159abC277BecC")
@ -1670,7 +1668,7 @@ mod tests {
async fn test_new_pending_txs_filter() { async fn test_new_pending_txs_filter() {
let num_txs = 5; let num_txs = 5;
let geth = Geth::new().block_time(2u64).spawn(); let geth = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(geth.endpoint()) let provider = Provider::<Http>::try_from(geth.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(1000)); .interval(Duration::from_millis(1000));
@ -1693,10 +1691,10 @@ mod tests {
async fn receipt_on_unmined_tx() { async fn receipt_on_unmined_tx() {
use ethers_core::{ use ethers_core::{
types::TransactionRequest, types::TransactionRequest,
utils::{parse_ether, Ganache}, utils::{parse_ether, Anvil},
}; };
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap(); let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap();
let accounts = provider.get_accounts().await.unwrap(); let accounts = provider.get_accounts().await.unwrap();
let tx = TransactionRequest::pay(accounts[0], parse_ether(1u64).unwrap()).from(accounts[0]); let tx = TransactionRequest::pay(accounts[0], parse_ether(1u64).unwrap()).from(accounts[0]);
@ -1724,10 +1722,10 @@ mod tests {
// Celo blocks can not get parsed when used with Ganache // Celo blocks can not get parsed when used with Ganache
#[cfg(not(feature = "celo"))] #[cfg(not(feature = "celo"))]
async fn block_subscribe() { async fn block_subscribe() {
use ethers_core::utils::Ganache; use ethers_core::utils::Anvil;
use futures_util::StreamExt; use futures_util::StreamExt;
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let provider = Provider::connect(ganache.ws_endpoint()).await.unwrap(); let provider = Provider::connect(anvil.ws_endpoint()).await.unwrap();
let stream = provider.subscribe_blocks().await.unwrap(); let stream = provider.subscribe_blocks().await.unwrap();
let blocks = stream.take(3).map(|x| x.number.unwrap().as_u64()).collect::<Vec<_>>().await; let blocks = stream.take(3).map(|x| x.number.unwrap().as_u64()).collect::<Vec<_>>().await;

View File

@ -265,7 +265,7 @@ mod tests {
use crate::{Http, Ws}; use crate::{Http, Ws};
use ethers_core::{ use ethers_core::{
types::{TransactionReceipt, TransactionRequest}, types::{TransactionReceipt, TransactionRequest},
utils::{Ganache, Geth}, utils::Anvil,
}; };
use futures_util::{FutureExt, StreamExt}; use futures_util::{FutureExt, StreamExt};
use std::{collections::HashSet, convert::TryFrom}; use std::{collections::HashSet, convert::TryFrom};
@ -273,7 +273,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn can_stream_pending_transactions() { async fn can_stream_pending_transactions() {
let num_txs = 5; let num_txs = 5;
let geth = Geth::new().block_time(2u64).spawn(); let geth = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(geth.endpoint()) let provider = Provider::<Http>::try_from(geth.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(1000)); .interval(Duration::from_millis(1000));
@ -327,17 +327,17 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn can_stream_transactions() { async fn can_stream_transactions() {
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider =
.unwrap() Provider::<Http>::try_from(anvil.endpoint()).unwrap().with_sender(anvil.addresses()[0]);
.with_sender(ganache.addresses()[0]);
let accounts = provider.get_accounts().await.unwrap(); let accounts = provider.get_accounts().await.unwrap();
let tx = TransactionRequest::new().from(accounts[0]).to(accounts[0]).value(1e18 as u64); let tx = TransactionRequest::new().from(accounts[0]).to(accounts[0]).value(1e18 as u64);
let txs = vec![tx.clone().nonce(0u64), tx.clone().nonce(1u64), tx.clone().nonce(2u64)];
let txs = let txs =
futures_util::future::join_all(std::iter::repeat(tx.clone()).take(3).map(|tx| async { futures_util::future::join_all(txs.into_iter().map(|tx| async {
provider.send_transaction(tx, None).await.unwrap().await.unwrap() provider.send_transaction(tx, None).await.unwrap().await.unwrap()
})) }))
.await; .await;

View File

@ -488,13 +488,13 @@ mod tests {
use super::*; use super::*;
use ethers_core::{ use ethers_core::{
types::{Block, TxHash, U256}, types::{Block, TxHash, U256},
utils::Ganache, utils::Anvil,
}; };
#[tokio::test] #[tokio::test]
async fn request() { async fn request() {
let ganache = Ganache::new().block_time(1u64).spawn(); let anvil = Anvil::new().block_time(1u64).spawn();
let ws = Ws::connect(ganache.ws_endpoint()).await.unwrap(); let ws = Ws::connect(anvil.ws_endpoint()).await.unwrap();
let block_num: U256 = ws.request("eth_blockNumber", ()).await.unwrap(); let block_num: U256 = ws.request("eth_blockNumber", ()).await.unwrap();
std::thread::sleep(std::time::Duration::new(3, 0)); std::thread::sleep(std::time::Duration::new(3, 0));
@ -504,8 +504,8 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn subscription() { async fn subscription() {
let ganache = Ganache::new().block_time(1u64).spawn(); let anvil = Anvil::new().block_time(1u64).spawn();
let ws = Ws::connect(ganache.ws_endpoint()).await.unwrap(); let ws = Ws::connect(anvil.ws_endpoint()).await.unwrap();
// Subscribing requires sending the sub request and then subscribing to // Subscribing requires sending the sub request and then subscribing to
// the returned sub_id // the returned sub_id
@ -519,14 +519,13 @@ mod tests {
blocks.push(block.number.unwrap_or_default().as_u64()); blocks.push(block.number.unwrap_or_default().as_u64());
} }
assert_eq!(sub_id, 1.into());
assert_eq!(blocks, vec![1, 2, 3]) assert_eq!(blocks, vec![1, 2, 3])
} }
#[tokio::test] #[tokio::test]
async fn deserialization_fails() { async fn deserialization_fails() {
let ganache = Ganache::new().block_time(1u64).spawn(); let anvil = Anvil::new().block_time(1u64).spawn();
let (ws, _) = tokio_tungstenite::connect_async(ganache.ws_endpoint()).await.unwrap(); let (ws, _) = tokio_tungstenite::connect_async(anvil.ws_endpoint()).await.unwrap();
let malformed_data = String::from("not a valid message"); let malformed_data = String::from("not a valid message");
let (_, stream) = mpsc::unbounded(); let (_, stream) = mpsc::unbounded();
let resp = WsServer::new(ws, stream).handle_text(malformed_data).await; let resp = WsServer::new(ws, stream).handle_text(malformed_data).await;

View File

@ -7,7 +7,7 @@ mod eth_tests {
use super::*; use super::*;
use ethers_core::{ use ethers_core::{
types::{Address, BlockId, TransactionRequest, H256}, types::{Address, BlockId, TransactionRequest, H256},
utils::Ganache, utils::Anvil,
}; };
use ethers_providers::RINKEBY; use ethers_providers::RINKEBY;
@ -45,8 +45,8 @@ mod eth_tests {
use ethers_core::types::H256; use ethers_core::types::H256;
use ethers_providers::{StreamExt, Ws}; use ethers_providers::{StreamExt, Ws};
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let (ws, _) = tokio_tungstenite::connect_async(ganache.ws_endpoint()).await.unwrap(); let (ws, _) = tokio_tungstenite::connect_async(anvil.ws_endpoint()).await.unwrap();
let provider = Provider::new(Ws::new(ws)).interval(Duration::from_millis(500u64)); let provider = Provider::new(Ws::new(ws)).interval(Duration::from_millis(500u64));
let stream = provider.watch_blocks().await.unwrap().stream(); let stream = provider.watch_blocks().await.unwrap().stream();
@ -56,9 +56,9 @@ mod eth_tests {
} }
#[tokio::test] #[tokio::test]
async fn pending_txs_with_confirmations_ganache() { async fn pending_txs_with_confirmations_anvil() {
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let provider = Provider::<Http>::try_from(ganache.endpoint()) let provider = Provider::<Http>::try_from(anvil.endpoint())
.unwrap() .unwrap()
.interval(Duration::from_millis(500u64)); .interval(Duration::from_millis(500u64));
let accounts = provider.get_accounts().await.unwrap(); let accounts = provider.get_accounts().await.unwrap();
@ -66,10 +66,10 @@ mod eth_tests {
} }
#[tokio::test] #[tokio::test]
async fn websocket_pending_txs_with_confirmations_ganache() { async fn websocket_pending_txs_with_confirmations_anvil() {
use ethers_providers::Ws; use ethers_providers::Ws;
let ganache = Ganache::new().block_time(2u64).spawn(); let anvil = Anvil::new().block_time(2u64).spawn();
let ws = Ws::connect(ganache.ws_endpoint()).await.unwrap(); let ws = Ws::connect(anvil.ws_endpoint()).await.unwrap();
let provider = Provider::new(ws); let provider = Provider::new(ws);
let accounts = provider.get_accounts().await.unwrap(); let accounts = provider.get_accounts().await.unwrap();
generic_pending_txs_test(provider, accounts[0]).await; generic_pending_txs_test(provider, accounts[0]).await;

View File

@ -1,14 +1,14 @@
#![cfg(not(target_arch = "wasm32"))] #![cfg(not(target_arch = "wasm32"))]
use ethers_core::{ use ethers_core::{
types::{TransactionRequest, U256}, types::{TransactionRequest, U256},
utils::Geth, utils::Anvil,
}; };
use ethers_providers::{Http, Middleware, Provider}; use ethers_providers::{Http, Middleware, Provider};
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::test] #[tokio::test]
async fn txpool() { async fn txpool() {
let geth = Geth::new().block_time(20u64).spawn(); let geth = Anvil::new().block_time(20u64).spawn();
let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap(); let provider = Provider::<Http>::try_from(geth.endpoint()).unwrap();
let account = provider.get_accounts().await.unwrap()[0]; let account = provider.get_accounts().await.unwrap()[0];

View File

@ -1,7 +1,7 @@
use ethers::{ use ethers::{
prelude::*, prelude::*,
solc::{Project, ProjectPathsConfig}, solc::{Project, ProjectPathsConfig},
utils::Ganache, utils::Anvil,
}; };
use eyre::Result; use eyre::Result;
use std::{convert::TryFrom, path::PathBuf, sync::Arc, time::Duration}; use std::{convert::TryFrom, path::PathBuf, sync::Arc, time::Duration};
@ -33,13 +33,13 @@ async fn main() -> Result<()> {
let contract = output.find("SimpleStorage").expect("could not find contract").clone(); let contract = output.find("SimpleStorage").expect("could not find contract").clone();
let (abi, bytecode, _) = contract.into_parts(); let (abi, bytecode, _) = contract.into_parts();
// 2. instantiate our wallet & ganache // 2. instantiate our wallet & anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
// 3. connect to the network // 3. connect to the network
let provider = let provider =
Provider::<Http>::try_from(ganache.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);
@ -49,7 +49,7 @@ async fn main() -> Result<()> {
let factory = ContractFactory::new(abi.unwrap(), bytecode.unwrap(), client.clone()); let factory = ContractFactory::new(abi.unwrap(), bytecode.unwrap(), client.clone());
// 6. deploy it with the constructor arguments // 6. deploy it with the constructor arguments
let contract = factory.deploy("initial value".to_string())?.legacy().send().await?; let contract = factory.deploy("initial value".to_string())?.send().await?;
// 7. get the contract's address // 7. get the contract's address
let addr = contract.address(); let addr = contract.address();
@ -59,7 +59,7 @@ async fn main() -> Result<()> {
// 9. call the `setValue` method // 9. call the `setValue` method
// (first `await` returns a PendingTransaction, second one waits for it to be mined) // (first `await` returns a PendingTransaction, second one waits for it to be mined)
let _receipt = contract.set_value("hi".to_owned()).legacy().send().await?.await?; let _receipt = contract.set_value("hi".to_owned()).send().await?.await?;
// 10. get all events // 10. get all events
let logs = contract.value_changed_filter().from_block(0u64).query().await?; let logs = contract.value_changed_filter().from_block(0u64).query().await?;

View File

@ -1,4 +1,4 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use eyre::Result; use eyre::Result;
use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration}; use std::{convert::TryFrom, path::Path, sync::Arc, time::Duration};
@ -13,8 +13,8 @@ abigen!(
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// 1. compile the contract (note this requires that you are inside the `examples` directory) and // 1. compile the contract (note this requires that you are inside the `examples` directory) and
// launch ganache // launch anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// set the path to the contract, `CARGO_MANIFEST_DIR` points to the directory containing the // set the path to the contract, `CARGO_MANIFEST_DIR` points to the directory containing the
// manifest of `ethers`. which will be `../` relative to this file // manifest of `ethers`. which will be `../` relative to this file
@ -24,11 +24,11 @@ async fn main() -> Result<()> {
compiled.find("SimpleStorage").expect("could not find contract").into_parts_or_default(); compiled.find("SimpleStorage").expect("could not find contract").into_parts_or_default();
// 2. instantiate our wallet // 2. instantiate our wallet
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
// 3. connect to the network // 3. connect to the network
let provider = let provider =
Provider::<Http>::try_from(ganache.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);
@ -38,7 +38,7 @@ async fn main() -> Result<()> {
let factory = ContractFactory::new(abi, bytecode, client.clone()); let factory = ContractFactory::new(abi, bytecode, client.clone());
// 6. deploy it with the constructor arguments // 6. deploy it with the constructor arguments
let contract = factory.deploy("initial value".to_string())?.legacy().send().await?; let contract = factory.deploy("initial value".to_string())?.send().await?;
// 7. get the contract's address // 7. get the contract's address
let addr = contract.address(); let addr = contract.address();
@ -48,7 +48,7 @@ async fn main() -> Result<()> {
// 9. call the `setValue` method // 9. call the `setValue` method
// (first `await` returns a PendingTransaction, second one waits for it to be mined) // (first `await` returns a PendingTransaction, second one waits for it to be mined)
let _receipt = contract.set_value("hi".to_owned()).legacy().send().await?.await?; let _receipt = contract.set_value("hi".to_owned()).send().await?.await?;
// 10. get all events // 10. get all events
let logs = contract.value_changed_filter().from_block(0u64).query().await?; let logs = contract.value_changed_filter().from_block(0u64).query().await?;

View File

@ -1,4 +1,4 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use eyre::Result; use eyre::Result;
use std::{convert::TryFrom, sync::Arc, time::Duration}; use std::{convert::TryFrom, sync::Arc, time::Duration};
@ -11,22 +11,22 @@ abigen!(Greeter, "ethers-contract/tests/solidity-contracts/greeter.json",);
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// 1. compile the contract (note this requires that you are inside the `examples` directory) and // 1. compile the contract (note this requires that you are inside the `examples` directory) and
// launch ganache // launch anvil
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// 2. instantiate our wallet // 2. instantiate our wallet
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
// 3. connect to the network // 3. connect to the network
let provider = let provider =
Provider::<Http>::try_from(ganache.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));
// 5. deploy contract, note the `legacy` call required for non EIP-1559 // 5. deploy contract
let greeter_contract = let greeter_contract =
Greeter::deploy(client, "Hello World!".to_string()).unwrap().legacy().send().await.unwrap(); Greeter::deploy(client, "Hello World!".to_string()).unwrap().send().await.unwrap();
// 6. call contract function // 6. call contract function
let greeting = greeter_contract.greet().call().await.unwrap(); let greeting = greeter_contract.greet().call().await.unwrap();

View File

@ -1,6 +1,6 @@
//! Main entry point for ContractMonitor //! Main entry point for ContractMonitor
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use std::{convert::TryFrom, sync::Arc, time::Duration}; use std::{convert::TryFrom, sync::Arc, time::Duration};
abigen!(VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json"); abigen!(VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi.json");
@ -9,10 +9,10 @@ abigen!(VerifierContract, "ethers-contract/tests/solidity-contracts/verifier_abi
/// have structs as input. /// have structs as input.
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let provider = let provider =
Provider::<Http>::try_from(ganache.endpoint())?.interval(Duration::from_millis(10u64)); Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
let client = SignerMiddleware::new(provider, wallet); let client = SignerMiddleware::new(provider, wallet);
let client = Arc::new(client); let client = Arc::new(client);

View File

@ -1,16 +1,15 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use eyre::Result; use eyre::Result;
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// fork mainnet // fork mainnet
let ganache = Ganache::new() let anvil =
.fork("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27") Anvil::new().fork("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27").spawn();
.spawn(); let from = anvil.addresses()[0].clone();
let from = ganache.addresses()[0].clone();
// connect to the network // connect to the network
let provider = Provider::<Http>::try_from(ganache.endpoint()).unwrap().with_sender(from); let provider = Provider::<Http>::try_from(anvil.endpoint()).unwrap().with_sender(from);
// craft the transaction // craft the transaction
let tx = TransactionRequest::new().to("vitalik.eth").value(100_000); let tx = TransactionRequest::new().to("vitalik.eth").value(100_000);

View File

@ -1,16 +1,16 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use eyre::Result; use eyre::Result;
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let wallet: LocalWallet = ganache.keys()[0].clone().into(); let wallet: LocalWallet = anvil.keys()[0].clone().into();
let wallet2: LocalWallet = ganache.keys()[1].clone().into(); let wallet2: LocalWallet = anvil.keys()[1].clone().into();
// connect to the network // connect to the network
let provider = Provider::<Http>::try_from(ganache.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);

View File

@ -1,22 +1,22 @@
//! Example usage for the `QuorumProvider` that requests multiple backends and only returns //! Example usage for the `QuorumProvider` that requests multiple backends and only returns
//! a value if the configured `Quorum` was reached. //! a value if the configured `Quorum` was reached.
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use std::{str::FromStr, time::Duration}; use std::{str::FromStr, time::Duration};
#[tokio::main] #[tokio::main]
async fn main() -> eyre::Result<()> { async fn main() -> eyre::Result<()> {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// create a quorum provider with some providers // create a quorum provider with some providers
let quorum = QuorumProvider::dyn_rpc() let quorum = QuorumProvider::dyn_rpc()
.add_provider(WeightedProvider::new(Box::new(Http::from_str(&ganache.endpoint())?))) .add_provider(WeightedProvider::new(Box::new(Http::from_str(&anvil.endpoint())?)))
.add_provider(WeightedProvider::with_weight( .add_provider(WeightedProvider::with_weight(
Box::new(Ws::connect(ganache.ws_endpoint()).await?), Box::new(Ws::connect(anvil.ws_endpoint()).await?),
2, 2,
)) ))
.add_provider(WeightedProvider::with_weight( .add_provider(WeightedProvider::with_weight(
Box::new(Ws::connect(ganache.ws_endpoint()).await?), Box::new(Ws::connect(anvil.ws_endpoint()).await?),
2, 2,
)) ))
// the quorum provider will yield the response if >50% of the weighted inner provider // the quorum provider will yield the response if >50% of the weighted inner provider

View File

@ -1,15 +1,15 @@
//! Example usage for the `RwClinet` that uses a didicated client to send transaction and nother one //! Example usage for the `RwClient` that uses a didicated client to send transaction and nother one
//! for read ops //! for read ops
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use std::{str::FromStr, time::Duration}; use std::{str::FromStr, time::Duration};
#[tokio::main] #[tokio::main]
async fn main() -> eyre::Result<()> { async fn main() -> eyre::Result<()> {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
let http = Http::from_str(&ganache.endpoint())?; let http = Http::from_str(&anvil.endpoint())?;
let ws = Ws::connect(ganache.ws_endpoint()).await?; let ws = Ws::connect(anvil.ws_endpoint()).await?;
let provider = Provider::rw(http, ws).interval(Duration::from_millis(10u64)); let provider = Provider::rw(http, ws).interval(Duration::from_millis(10u64));

View File

@ -1,13 +1,13 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use eyre::Result; use eyre::Result;
use std::convert::TryFrom; use std::convert::TryFrom;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let ganache = Ganache::new().spawn(); let anvil = Anvil::new().spawn();
// connect to the network // connect to the network
let provider = Provider::<Http>::try_from(ganache.endpoint())?; let provider = Provider::<Http>::try_from(anvil.endpoint())?;
let accounts = provider.get_accounts().await?; let accounts = provider.get_accounts().await?;
let from = accounts[0]; let from = accounts[0];
let to = accounts[1]; let to = accounts[1];
@ -16,18 +16,16 @@ async fn main() -> Result<()> {
let tx = TransactionRequest::new().to(to).value(1000).from(from); // specify the `from` field so that the client knows which account to use let tx = TransactionRequest::new().to(to).value(1000).from(from); // specify the `from` field so that the client knows which account to use
let balance_before = provider.get_balance(from, None).await?; let balance_before = provider.get_balance(from, None).await?;
let nonce1 = provider.get_transaction_count(from, None).await?;
// broadcast it via the eth_sendTransaction API // broadcast it via the eth_sendTransaction API
let tx = provider.send_transaction(tx, None).await?.await?; let tx = provider.send_transaction(tx, None).await?.await?;
println!("{}", serde_json::to_string(&tx)?); println!("{}", serde_json::to_string(&tx)?);
let nonce1 = provider.get_transaction_count(from, Some(BlockNumber::Latest.into())).await?; let nonce2 = provider.get_transaction_count(from, None).await?;
let nonce2 = assert!(nonce1 < nonce2);
provider.get_transaction_count(from, Some(BlockNumber::Number(0.into()).into())).await?;
assert!(nonce2 < nonce1);
let balance_after = provider.get_balance(from, None).await?; let balance_after = provider.get_balance(from, None).await?;
assert!(balance_after < balance_before); assert!(balance_after < balance_before);

View File

@ -10,7 +10,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// (here: mainnet) for EIP155 support. // (here: mainnet) for EIP155 support.
// EIP1559 support // EIP1559 support
// No EIP712 support yet. // No EIP712 support yet.
let trezor = Trezor::new(TrezorHDPath::TrezorLive(0), 1).await?; let trezor = Trezor::new(TrezorHDPath::TrezorLive(0), 1, None).await?;
let client = SignerMiddleware::new(provider, trezor); let client = SignerMiddleware::new(provider, trezor);
// Create and broadcast a transaction (ENS disabled!) // Create and broadcast a transaction (ENS disabled!)

View File

@ -1,10 +1,10 @@
use ethers::{prelude::*, utils::Ganache}; use ethers::{prelude::*, utils::Anvil};
use std::time::Duration; use std::time::Duration;
#[tokio::main] #[tokio::main]
async fn main() -> eyre::Result<()> { async fn main() -> eyre::Result<()> {
let ganache = Ganache::new().block_time(1u64).spawn(); let anvil = Anvil::new().block_time(1u64).spawn();
let ws = Ws::connect(ganache.ws_endpoint()).await?; let ws = Ws::connect(anvil.ws_endpoint()).await?;
let provider = Provider::new(ws).interval(Duration::from_millis(2000)); let provider = Provider::new(ws).interval(Duration::from_millis(2000));
let mut stream = provider.watch_blocks().await?.take(5); let mut stream = provider.watch_blocks().await?.take(5);
while let Some(block) = stream.next().await { while let Some(block) = stream.next().await {

View File

@ -1,7 +1,24 @@
set -e set -e
# shellcheck shell=bash # shellcheck shell=bash
# examples that we can't run because they require some additional infra, docker or ledger for example
ignored=(
"moonbeam_with_abi"
"ipc"
"ledger"
"paginated_logs"
"subscribe_logs"
"trezor"
"yubi"
)
# run all examples # run all examples
for file in examples/*.rs; do for file in examples/*.rs; do
name="$(echo "$file" | cut -f 1 -d '.')" name="$(echo "$file" | cut -f 1 -d '.')"
if [[ "${ignored[*]}" =~ $(basename "$name") ]]; then
echo "skipping: $file"
continue
fi
echo "running: $file"
cargo r -p ethers --example "$(basename "$name")" cargo r -p ethers --example "$(basename "$name")"
done done

View File

@ -29,7 +29,7 @@
//! //!
//! Contains all the [necessary data structures](core::types) for interacting //! Contains all the [necessary data structures](core::types) for interacting
//! with Ethereum, along with cryptographic utilities for signing and verifying //! with Ethereum, along with cryptographic utilities for signing and verifying
//! ECDSA signatures on `secp256k1`. Bindings to the solidity compiler and `ganache-cli` //! ECDSA signatures on `secp256k1`. Bindings to the Solidity compiler, Anvil and `ganache-cli`
//! are also provided as helpers. To simplify your imports, consider using the re-exported //! are also provided as helpers. To simplify your imports, consider using the re-exported
//! modules described in the next subsection. //! modules described in the next subsection.
//! //!