feat: Adds support for launching ganache-cli
This commit is contained in:
parent
2bba40a788
commit
7a17b2dec2
|
@ -31,7 +31,7 @@ impl<'a, 'b, P, N, D: Detokenize> Event<'a, 'b, P, N, D> {
|
|||
}
|
||||
|
||||
pub fn topic0<T: Into<ValueOrArray<H256>>>(mut self, topic: T) -> Self {
|
||||
self.filter.topics[0] = topic.into();
|
||||
self.filter.topics[0] = Some(topic.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
use std::process::{Child, Command};
|
||||
|
||||
/// A ganache CLI instance. Will close the instance when dropped.
|
||||
pub struct Ganache(Child);
|
||||
|
||||
impl Drop for Ganache {
|
||||
fn drop(&mut self) {
|
||||
self.0.kill().expect("could not kill ganache");
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for launching `ganache-cli`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `spawn` is called without `ganache-cli` being available in the user's $PATH
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use ethers_utils::ganache::GanacheBuilder;
|
||||
/// let port = 8545u64;
|
||||
/// let url = format!("http://localhost:{}", port).to_string();
|
||||
///
|
||||
/// let ganache = GanacheBuilder::new()
|
||||
/// .port(port)
|
||||
/// .mnemonic("abstract vacuum mammal awkward pudding scene penalty purchase dinner depart evoke puzzle")
|
||||
/// .spawn();
|
||||
///
|
||||
/// drop(ganache); // this will kill the instance
|
||||
/// ```
|
||||
#[derive(Clone, Default)]
|
||||
pub struct GanacheBuilder {
|
||||
port: Option<u64>,
|
||||
mnemonic: Option<String>,
|
||||
}
|
||||
|
||||
impl GanacheBuilder {
|
||||
/// Creates an empty Ganache builder.
|
||||
/// The default port is 8545. The mnemonic is chosen randomly.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Sets the port which will be used when the `ganache-cli` instance is launched.
|
||||
pub fn port<T: Into<u64>>(mut self, port: T) -> Self {
|
||||
self.port = Some(port.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the mnemonic which will be used when the `ganache-cli` instance is launched.
|
||||
pub fn mnemonic<T: Into<String>>(mut self, mnemonic: T) -> Self {
|
||||
self.mnemonic = Some(mnemonic.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Consumes the builder and spawns `ganache-cli` with stdout redirected
|
||||
/// to /dev/null. This takes ~2 seconds to execute as it blocks while
|
||||
/// waiting for `ganache-cli` to launch.
|
||||
pub fn spawn(self) -> Ganache {
|
||||
let mut cmd = Command::new("ganache-cli");
|
||||
cmd.stdout(std::process::Stdio::null());
|
||||
if let Some(port) = self.port {
|
||||
cmd.arg("-p").arg(port.to_string());
|
||||
}
|
||||
|
||||
if let Some(mnemonic) = self.mnemonic {
|
||||
cmd.arg("-m").arg(mnemonic);
|
||||
}
|
||||
|
||||
let ganache_pid = cmd.spawn().expect("couldnt start ganache-cli");
|
||||
|
||||
// wait a couple of seconds for ganache to boot up
|
||||
// TODO: Change this to poll for `port`
|
||||
let sleep_time = std::time::Duration::from_secs(2);
|
||||
std::thread::sleep(sleep_time);
|
||||
Ganache(ganache_pid)
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
use ethereum_types::H256;
|
||||
use tiny_keccak::{Hasher, Keccak};
|
||||
|
||||
/// Utilities for launching a ganache-cli testnet instance
|
||||
pub mod ganache;
|
||||
|
||||
const PREFIX: &str = "\x19Ethereum Signed Message:\n";
|
||||
|
||||
/// Hash a message according to EIP-191.
|
||||
|
|
|
@ -13,7 +13,7 @@ async fn main() -> Result<()> {
|
|||
let filter = Filter::new()
|
||||
.address_str("f817796F60D268A36a57b8D2dF1B97B14C0D0E1d")?
|
||||
.event("ValueChanged(address,string,string)") // event name
|
||||
.topic("9729a6fbefefc8f6005933898b13dc45c3a2c8b7".parse::<Address>()?); // indexed param
|
||||
.topic0("9729a6fbefefc8f6005933898b13dc45c3a2c8b7".parse::<Address>()?); // indexed param
|
||||
|
||||
let logs = provider.get_logs(&filter).await?;
|
||||
println!("Got logs: {}", serde_json::to_string(&logs).unwrap());
|
||||
|
|
|
@ -1,16 +1,27 @@
|
|||
use anyhow::Result;
|
||||
use ethers::{providers::HttpProvider, signers::MainnetWallet, types::TransactionRequest};
|
||||
use ethers::{
|
||||
providers::HttpProvider, signers::MainnetWallet, types::TransactionRequest,
|
||||
utils::ganache::GanacheBuilder,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// connect to the network
|
||||
let provider = HttpProvider::try_from("http://localhost:8545")?;
|
||||
let port = 8545u64;
|
||||
let url = format!("http://localhost:{}", port).to_string();
|
||||
let _ganache = GanacheBuilder::new()
|
||||
.port(port)
|
||||
.mnemonic("abstract vacuum mammal awkward pudding scene penalty purchase dinner depart evoke puzzle")
|
||||
.spawn();
|
||||
// this private key belongs to the above mnemonic
|
||||
let wallet: MainnetWallet =
|
||||
"380eb0f3d505f087e438eca80bc4df9a7faa24f868e69fc0440261a0fc0567dc".parse()?;
|
||||
|
||||
// create a wallet and connect it to the provider
|
||||
let client = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"
|
||||
.parse::<MainnetWallet>()?
|
||||
.connect(&provider);
|
||||
// connect to the network
|
||||
let provider = HttpProvider::try_from(url.as_str())?;
|
||||
|
||||
// connect the wallet to the provider
|
||||
let client = wallet.connect(&provider);
|
||||
|
||||
// craft the transaction
|
||||
let tx = TransactionRequest::new()
|
||||
|
@ -25,8 +36,8 @@ async fn main() -> Result<()> {
|
|||
|
||||
let receipt = client.get_transaction_receipt(tx.hash).await?;
|
||||
|
||||
println!("{}", serde_json::to_string(&tx)?);
|
||||
println!("{}", serde_json::to_string(&receipt)?);
|
||||
println!("Send tx: {}", serde_json::to_string(&tx)?);
|
||||
println!("Tx receipt: {}", serde_json::to_string(&receipt)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,13 +2,18 @@ use anyhow::Result;
|
|||
use ethers::{
|
||||
providers::{networks::Any, HttpProvider},
|
||||
types::{BlockNumber, TransactionRequest},
|
||||
utils::ganache::GanacheBuilder,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let port = 8546u64;
|
||||
let url = format!("http://localhost:{}", port).to_string();
|
||||
let _ganache = GanacheBuilder::new().port(port).spawn();
|
||||
|
||||
// connect to the network
|
||||
let provider = HttpProvider::<Any>::try_from("http://localhost:8545")?;
|
||||
let provider = HttpProvider::<Any>::try_from(url.as_str())?;
|
||||
let accounts = provider.get_accounts().await?;
|
||||
let from = accounts[0];
|
||||
|
||||
|
|
Loading…
Reference in New Issue