diff --git a/Cargo.lock b/Cargo.lock index 1482f2d2..a7def727 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3580,12 +3580,20 @@ dependencies = [ "yansi", ] +[[package]] +name = "example-support" +version = "0.1.0" +dependencies = [ + "eyre", +] + [[package]] name = "examples-advanced" version = "0.1.0" dependencies = [ "alloy", "alloy-evm", + "example-support", "eyre", "foundry-fork-db", "helpers", @@ -3620,6 +3628,7 @@ name = "examples-contracts" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "serde_json", "tokio", @@ -3630,6 +3639,7 @@ name = "examples-ens" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "futures-util", "tokio", @@ -3651,6 +3661,7 @@ name = "examples-layers" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "http-body-util", "tokio", @@ -3663,6 +3674,7 @@ name = "examples-node-bindings" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "tokio", ] @@ -3680,6 +3692,7 @@ name = "examples-providers" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "futures-util", "tokio", @@ -3690,6 +3703,7 @@ name = "examples-queries" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "futures-util", "tokio", @@ -3712,6 +3726,7 @@ name = "examples-subscriptions" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "futures-util", "tokio", @@ -3722,6 +3737,7 @@ name = "examples-transactions" version = "0.1.0" dependencies = [ "alloy", + "example-support", "eyre", "rand 0.8.7", "tokio", @@ -3735,6 +3751,7 @@ dependencies = [ "alloy-chains", "aws-config", "aws-sdk-kms", + "example-support", "eyre", "gcloud-sdk", "rand 0.8.7", diff --git a/Cargo.toml b/Cargo.toml index d702a0ea..1998af24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["helpers", "examples/*", "benches"] +members = ["example-support", "helpers", "examples/*", "benches"] resolver = "2" [workspace.package] @@ -151,4 +151,5 @@ rlp-derive = "0.2.0" alloy-rlp = "0.3.12" # helpers +example-support = { path = "example-support" } helpers = { path = "helpers" } diff --git a/README.md b/README.md index 8785a5bf..6ffe77a9 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,27 @@ To run an example, use the command `cargo run --example `: cargo run --example mnemonic_signer ``` +Examples that query a live network or fork it with Anvil require you to supply an endpoint: + +```sh +RPC_URL=https://your-ethereum-endpoint cargo run --example http +``` + +WebSocket and IPC examples use `WS_URL` and `IPC_PATH`, respectively. Examples with authentication +also list their required credential variables in the error they return. + +The fallback-layer example accepts a comma-separated list instead: + +```sh +RPC_URLS=https://first-endpoint,https://second-endpoint cargo run --example fallback_layer +``` + +Use an endpoint for the network named by the example. For example, `any_network` expects an +Arbitrum Sepolia endpoint, while mainnet contract and ENS examples expect Ethereum mainnet. +Examples that fork a network also require [`anvil`](https://getfoundry.sh/anvil/overview/) in +`PATH`. Hardware-wallet and cloud-signer examples require the device or credentials described in +their source code. + ## Overview This repository contains the following examples: diff --git a/example-support/Cargo.toml b/example-support/Cargo.toml new file mode 100644 index 00000000..80c08cfd --- /dev/null +++ b/example-support/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "example-support" +publish.workspace = true +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +eyre.workspace = true diff --git a/example-support/src/lib.rs b/example-support/src/lib.rs new file mode 100644 index 00000000..5cf9c068 --- /dev/null +++ b/example-support/src/lib.rs @@ -0,0 +1,48 @@ +//! Shared configuration helpers for the examples workspace. + +use eyre::{bail, Result, WrapErr}; + +/// Returns a non-empty environment variable or an actionable error. +pub fn required_env(name: &str) -> Result { + let value = + std::env::var(name).wrap_err_with(|| format!("{name} must be set for this example"))?; + + if value.trim().is_empty() { + bail!("{name} must not be empty"); + } + + Ok(value) +} + +/// Returns the JSON-RPC endpoint configured through `RPC_URL`. +pub fn rpc_url() -> Result { + required_env("RPC_URL").wrap_err("RPC_URL must contain a JSON-RPC endpoint") +} + +/// Returns the WebSocket endpoint configured through `WS_URL`. +pub fn ws_url() -> Result { + required_env("WS_URL").wrap_err("WS_URL must contain a WebSocket JSON-RPC endpoint") +} + +/// Returns the IPC socket path configured through `IPC_PATH`. +pub fn ipc_path() -> Result { + required_env("IPC_PATH").wrap_err("IPC_PATH must contain a JSON-RPC IPC socket path") +} + +/// Returns the comma-separated JSON-RPC endpoints configured through `RPC_URLS`. +pub fn rpc_urls() -> Result> { + let value = std::env::var("RPC_URLS") + .wrap_err("RPC_URLS must be set to comma-separated JSON-RPC endpoints for this example")?; + let urls: Vec<_> = value + .split(',') + .map(str::trim) + .filter(|url| !url.is_empty()) + .map(ToOwned::to_owned) + .collect(); + + if urls.len() < 2 { + bail!("RPC_URLS must contain at least two JSON-RPC endpoints"); + } + + Ok(urls) +} diff --git a/examples/advanced/Cargo.toml b/examples/advanced/Cargo.toml index 163defec..59269e11 100644 --- a/examples/advanced/Cargo.toml +++ b/examples/advanced/Cargo.toml @@ -16,6 +16,7 @@ workspace = true foundry-fork-db.workspace = true alloy.workspace = true alloy-evm.workspace = true +example-support.workspace = true helpers.workspace = true # reth diff --git a/examples/advanced/examples/any_network.rs b/examples/advanced/examples/any_network.rs index dc0f2d61..d582f921 100644 --- a/examples/advanced/examples/any_network.rs +++ b/examples/advanced/examples/any_network.rs @@ -11,6 +11,7 @@ use alloy::{ signers::local::PrivateKeySigner, sol, }; +use example_support::{required_env, rpc_url}; use eyre::Result; // The address of the contract below deployed to Arbitrum Sepolia. @@ -44,10 +45,10 @@ struct ArbOtherFields { async fn main() -> Result<()> { // [RISK WARNING! Writing a private key in the code file is insecure behavior.] // The following code is for testing only. Set up signer from private key, be aware of danger. - let signer: PrivateKeySigner = "".parse().expect("should parse private key"); + let signer: PrivateKeySigner = required_env("PRIVATE_KEY")?.parse()?; // Create a provider with the Arbitrum Sepolia network and the wallet. - let rpc_url = "https://sepolia-rollup.arbitrum.io/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().network::().wallet(signer).connect_http(rpc_url); diff --git a/examples/advanced/examples/uniswap_u256_alloy_simulation.rs b/examples/advanced/examples/uniswap_u256_alloy_simulation.rs index 12ce25b4..a78aaf56 100644 --- a/examples/advanced/examples/uniswap_u256_alloy_simulation.rs +++ b/examples/advanced/examples/uniswap_u256_alloy_simulation.rs @@ -9,6 +9,7 @@ use alloy::{ sol, sol_types::SolCall, }; +use example_support::rpc_url; use eyre::Result; use helpers::alloy::{ get_amount_in, get_amount_out, get_sushi_pair, get_uniswap_pair, set_hash_storage_slot, @@ -38,8 +39,9 @@ async fn main() -> Result<()> { let sushi_pair = get_sushi_pair(); let wallet_address = address!("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); - let provider = ProviderBuilder::new() - .connect_anvil_with_wallet_and_config(|a| a.fork("https://reth-ethereum.ithaca.xyz/rpc"))?; + let rpc_url = rpc_url()?; + let provider = + ProviderBuilder::new().connect_anvil_with_wallet_and_config(|anvil| anvil.fork(rpc_url))?; let executor = FlashBotsMultiCall::deploy(provider.clone(), wallet_address).await?; let iweth = IERC20::new(WETH_ADDR, provider.clone()); diff --git a/examples/contracts/Cargo.toml b/examples/contracts/Cargo.toml index 1e7b70fa..dea316f4 100644 --- a/examples/contracts/Cargo.toml +++ b/examples/contracts/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/examples/contracts/examples/interact_with_abi.rs b/examples/contracts/examples/interact_with_abi.rs index ed365393..1e387692 100644 --- a/examples/contracts/examples/interact_with_abi.rs +++ b/examples/contracts/examples/interact_with_abi.rs @@ -1,6 +1,7 @@ //! Example of generating code from ABI file using the `sol!` macro to interact with the contract. use alloy::{primitives::address, providers::ProviderBuilder, sol}; +use example_support::rpc_url; use eyre::Result; // Codegen from ABI file to interact with the contract. @@ -15,7 +16,7 @@ sol!( async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new().connect_anvil_with_wallet_and_config(|anvil| anvil.fork(rpc_url))?; diff --git a/examples/contracts/examples/simulation_uni_v2.rs b/examples/contracts/examples/simulation_uni_v2.rs index 705f7f7b..08b844f3 100644 --- a/examples/contracts/examples/simulation_uni_v2.rs +++ b/examples/contracts/examples/simulation_uni_v2.rs @@ -16,6 +16,7 @@ use crate::helpers::{ get_amount_in, get_amount_out, get_sushi_pair, get_uniswap_pair, set_hash_storage_slot, DAI_ADDR, WETH_ADDR, }; +use example_support::rpc_url; use eyre::Result; sol! { @@ -39,7 +40,7 @@ sol!( async fn main() -> Result<()> { // Spawn `anvil` and fork mainnet // Make sure you have `anvil` in $PATH - let anvil = Anvil::new().fork("https://reth-ethereum.ithaca.xyz/rpc").try_spawn()?; + let anvil = Anvil::new().fork(rpc_url()?).try_spawn()?; // Get the pool contract interfaces let uniswap_pair = get_uniswap_pair(); diff --git a/examples/ens/Cargo.toml b/examples/ens/Cargo.toml index bd51e6d0..d75ff995 100644 --- a/examples/ens/Cargo.toml +++ b/examples/ens/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true futures-util.workspace = true diff --git a/examples/ens/examples/address_lookup.rs b/examples/ens/examples/address_lookup.rs index b1f3276c..e100c3bb 100644 --- a/examples/ens/examples/address_lookup.rs +++ b/examples/ens/examples/address_lookup.rs @@ -1,12 +1,13 @@ //! Example of looking up ENS names from Ethereum addresses. use alloy::{ens::ProviderEnsExt, primitives::address, providers::ProviderBuilder}; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Vitalik's Ethereum address. diff --git a/examples/ens/examples/name_resolution.rs b/examples/ens/examples/name_resolution.rs index 85685d7a..c4581d26 100644 --- a/examples/ens/examples/name_resolution.rs +++ b/examples/ens/examples/name_resolution.rs @@ -1,12 +1,13 @@ //! Example of resolving ENS names to Ethereum addresses. use alloy::{ens::ProviderEnsExt, providers::ProviderBuilder}; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Resolve the ENS name "vitalik.eth" to its Ethereum address. diff --git a/examples/layers/Cargo.toml b/examples/layers/Cargo.toml index 6860de81..acc0df57 100644 --- a/examples/layers/Cargo.toml +++ b/examples/layers/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy = { workspace = true, features = ["hyper"] } +example-support.workspace = true eyre.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/examples/layers/examples/fallback_layer.rs b/examples/layers/examples/fallback_layer.rs index 084ed4d4..1117c4b1 100644 --- a/examples/layers/examples/fallback_layer.rs +++ b/examples/layers/examples/fallback_layer.rs @@ -10,6 +10,7 @@ use alloy::{ layers::FallbackLayer, }, }; +use example_support::rpc_urls; use eyre::Result; use tower::ServiceBuilder; @@ -17,16 +18,16 @@ use tower::ServiceBuilder; async fn main() -> Result<()> { let _ = tracing_subscriber::fmt::try_init(); - // Configure the fallback layer + // Configure the fallback layer for the endpoints supplied in `RPC_URLS`. + let rpc_urls = rpc_urls()?; + let active_transport_count = + NonZeroUsize::new(rpc_urls.len()).expect("rpc_urls() rejects an empty list"); let fallback_layer = - FallbackLayer::default().with_active_transport_count(NonZeroUsize::new(3).unwrap()); - - // Define your list of transports to use - let transports = vec![ - Http::new(Url::parse("https://reth-ethereum.ithaca.xyz/rpc")?), - Http::new(Url::parse("https://eth.llamarpc.com")?), - Http::new(Url::parse("https://ethereum-rpc.publicnode.com")?), - ]; + FallbackLayer::default().with_active_transport_count(active_transport_count); + + // Define one transport for each configured endpoint. + let transports = + rpc_urls.iter().map(|url| Ok(Http::new(Url::parse(url)?))).collect::>>()?; // Apply the FallbackLayer to the transports let transport = ServiceBuilder::new().layer(fallback_layer).service(transports); diff --git a/examples/node-bindings/Cargo.toml b/examples/node-bindings/Cargo.toml index 1329513a..949df9fb 100644 --- a/examples/node-bindings/Cargo.toml +++ b/examples/node-bindings/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/examples/node-bindings/examples/anvil_fork_instance.rs b/examples/node-bindings/examples/anvil_fork_instance.rs index 20f16946..1b2321ed 100644 --- a/examples/node-bindings/examples/anvil_fork_instance.rs +++ b/examples/node-bindings/examples/anvil_fork_instance.rs @@ -4,14 +4,15 @@ use alloy::{ node_bindings::Anvil, providers::{ext::AnvilApi, ProviderBuilder}, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; - let anvil = Anvil::new().fork(rpc_url).try_spawn()?; + let rpc_url = rpc_url()?; + let anvil = Anvil::new().fork(rpc_url.clone()).try_spawn()?; let provider = ProviderBuilder::new().connect_http(anvil.endpoint_url()); // Get node info using the Anvil API. @@ -20,7 +21,7 @@ async fn main() -> Result<()> { println!("Node info: {info:#?}"); assert_eq!(info.environment.chain_id, 1); - assert_eq!(info.fork_config.fork_url, Some(rpc_url.to_string())); + assert_eq!(info.fork_config.fork_url, Some(rpc_url)); Ok(()) } diff --git a/examples/node-bindings/examples/anvil_fork_provider.rs b/examples/node-bindings/examples/anvil_fork_provider.rs index bd344f0f..8b88369d 100644 --- a/examples/node-bindings/examples/anvil_fork_provider.rs +++ b/examples/node-bindings/examples/anvil_fork_provider.rs @@ -1,14 +1,16 @@ //! Example of spinning up a forked Anvil node using the [`ProviderBuilder`]. use alloy::providers::{ext::AnvilApi, ProviderBuilder}; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; - let provider = ProviderBuilder::new().connect_anvil_with_config(|anvil| anvil.fork(rpc_url)); + let rpc_url = rpc_url()?; + let provider = + ProviderBuilder::new().connect_anvil_with_config(|anvil| anvil.fork(rpc_url.clone())); // Get node info using the Anvil API. let info = provider.anvil_node_info().await?; @@ -16,7 +18,7 @@ async fn main() -> Result<()> { println!("Node info: {info:#?}"); assert_eq!(info.environment.chain_id, 1); - assert_eq!(info.fork_config.fork_url, Some(rpc_url.to_string())); + assert_eq!(info.fork_config.fork_url, Some(rpc_url)); Ok(()) } diff --git a/examples/node-bindings/examples/anvil_set_storage_at.rs b/examples/node-bindings/examples/anvil_set_storage_at.rs index e2f54898..b87a0fe8 100644 --- a/examples/node-bindings/examples/anvil_set_storage_at.rs +++ b/examples/node-bindings/examples/anvil_set_storage_at.rs @@ -6,6 +6,7 @@ use alloy::{ sol, sol_types::SolValue, }; +use example_support::rpc_url; use eyre::Result; sol!( @@ -22,7 +23,7 @@ static WETH_ADDR: Address = address!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new().connect_anvil_with_config(|anvil| anvil.fork(rpc_url)); // Create an instance of the WETH contract. diff --git a/examples/providers/Cargo.toml b/examples/providers/Cargo.toml index 03db6434..3f78e968 100644 --- a/examples/providers/Cargo.toml +++ b/examples/providers/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true futures-util.workspace = true diff --git a/examples/providers/examples/batch_rpc.rs b/examples/providers/examples/batch_rpc.rs index fb5ca4fb..a4f1bdb4 100644 --- a/examples/providers/examples/batch_rpc.rs +++ b/examples/providers/examples/batch_rpc.rs @@ -13,7 +13,7 @@ async fn main() -> Result<()> { // Ensure `anvil` is available in $PATH. let anvil = Anvil::new().spawn(); - // Swap this out with a RPC_URL provider that supports JSON-RPC batch requests. e.g. https://reth-ethereum.ithaca.xyz/rpc + // Swap this out with an `RPC_URL` endpoint that supports JSON-RPC batch requests. let rpc_url = anvil.endpoint_url(); // Create a HTTP transport. diff --git a/examples/providers/examples/builtin.rs b/examples/providers/examples/builtin.rs index afa009ee..0a197092 100644 --- a/examples/providers/examples/builtin.rs +++ b/examples/providers/examples/builtin.rs @@ -4,6 +4,7 @@ use alloy::{ node_bindings::Anvil, providers::{Provider, ProviderBuilder}, }; +use example_support::ipc_path; use eyre::Result; use futures_util::StreamExt; @@ -42,8 +43,7 @@ async fn main() -> Result<()> { // This requires the `pubsub` and `ipc` features to be enabled. // This would throw a runtime error if the ipc does not exist. - let ipc_path = "/tmp/reth.ipc"; - let ipc_provider = ProviderBuilder::new().connect(ipc_path).await?; + let ipc_provider = ProviderBuilder::new().connect(&ipc_path()?).await?; let _block_number = ipc_provider.get_block_number().await?; diff --git a/examples/providers/examples/embed_consensus_rpc.rs b/examples/providers/examples/embed_consensus_rpc.rs index efaf1e58..551aa0fd 100644 --- a/examples/providers/examples/embed_consensus_rpc.rs +++ b/examples/providers/examples/embed_consensus_rpc.rs @@ -24,11 +24,12 @@ use alloy::{ primitives::b256, providers::{Provider, ProviderBuilder}, }; +use example_support::rpc_url; use eyre::OptionExt; #[tokio::main] async fn main() -> eyre::Result<()> { - let provider = ProviderBuilder::new().connect("https://reth-ethereum.ithaca.xyz/rpc").await?; + let provider = ProviderBuilder::new().connect(&rpc_url()?).await?; // Get the latest block from the RPC. let block = provider.get_block(BlockId::latest()).await?.ok_or_eyre("Block not found")?; diff --git a/examples/providers/examples/http.rs b/examples/providers/examples/http.rs index abe8c557..16f58782 100644 --- a/examples/providers/examples/http.rs +++ b/examples/providers/examples/http.rs @@ -1,12 +1,13 @@ //! Example of using the HTTP provider with the `reqwest` crate to get the latest block number. use alloy::providers::{Provider, ProviderBuilder}; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider with the HTTP transport using the `reqwest` crate. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Get latest block number. diff --git a/examples/providers/examples/http_with_auth.rs b/examples/providers/examples/http_with_auth.rs index 28a0d8bd..35033a4d 100644 --- a/examples/providers/examples/http_with_auth.rs +++ b/examples/providers/examples/http_with_auth.rs @@ -12,19 +12,20 @@ use alloy::{ Http, }, }; +use example_support::{required_env, rpc_url}; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Set the Authorization header. let mut headers = HeaderMap::new(); - headers.insert(AUTHORIZATION, HeaderValue::from_static("deadbeef")); + headers.insert(AUTHORIZATION, required_env("RPC_AUTHORIZATION")?.parse::()?); // Create the reqwest::Client with the AUTHORIZATION header. let client_with_auth = Client::builder().default_headers(headers).build()?; // Create the HTTP transport. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let http = Http::with_client(client_with_auth, rpc_url); let rpc_client = RpcClient::new(http, false); diff --git a/examples/providers/examples/ipc.rs b/examples/providers/examples/ipc.rs index 4b0ac5be..f94b3be4 100644 --- a/examples/providers/examples/ipc.rs +++ b/examples/providers/examples/ipc.rs @@ -1,15 +1,16 @@ //! Example of using the IPC provider to get the latest block number. use alloy::providers::{IpcConnect, Provider, ProviderBuilder}; +use example_support::ipc_path; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Set up the IPC transport which is consumed by the RPC client. - let ipc_path = "/tmp/reth.ipc"; + let ipc_path = ipc_path()?; // Create the provider. - let ipc = IpcConnect::new(ipc_path.to_string()); + let ipc = IpcConnect::new(ipc_path); let provider = ProviderBuilder::new().connect_ipc(ipc).await?; let latest_block = provider.get_block_number().await?; diff --git a/examples/providers/examples/multicall.rs b/examples/providers/examples/multicall.rs index de7bfb2f..a81d4ec2 100644 --- a/examples/providers/examples/multicall.rs +++ b/examples/providers/examples/multicall.rs @@ -6,6 +6,7 @@ use alloy::{ providers::{CallItemBuilder, Failure, Provider, ProviderBuilder}, sol, }; +use example_support::rpc_url; use IWETH9::IWETH9Instance; sol!( @@ -19,8 +20,9 @@ sol!( #[tokio::main] async fn main() -> eyre::Result<()> { // Create a new provider - let provider = ProviderBuilder::new() - .connect_anvil_with_wallet_and_config(|a| a.fork("https://reth-ethereum.ithaca.xyz/rpc"))?; + let rpc_url = rpc_url()?; + let provider = + ProviderBuilder::new().connect_anvil_with_wallet_and_config(|anvil| anvil.fork(rpc_url))?; // Create a new instance of the IWETH9 contract. let weth = IWETH9Instance::new(address!("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), &provider); diff --git a/examples/providers/examples/multicall_batching.rs b/examples/providers/examples/multicall_batching.rs index f1356afd..dd46d973 100644 --- a/examples/providers/examples/multicall_batching.rs +++ b/examples/providers/examples/multicall_batching.rs @@ -9,6 +9,7 @@ use alloy::{ providers::{layers::CallBatchLayer, Provider, ProviderBuilder}, sol, }; +use example_support::rpc_url; use eyre::Result; use IWETH9::{balanceOfCall, totalSupplyCall, IWETH9Instance}; @@ -23,6 +24,7 @@ sol!( #[tokio::main] async fn main() -> Result<()> { // Instantiate a provider with the `CallBatchLayer` enabled. + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new() // Enables `eth_call` batching by leveraging the Multicall3 contract. // The `CallBatchLayer` will wait for a certain amount of time before sending a request. See: . @@ -31,7 +33,7 @@ async fn main() -> Result<()> { .layer(CallBatchLayer::new().wait(Duration::from_millis(10))) // Can also use the shorthand `with_call_batching` on the build which set the delay to 1ms. // .with_call_batching() - .connect_anvil_with_wallet_and_config(|a| a.fork("https://reth-ethereum.ithaca.xyz/rpc"))?; + .connect_anvil_with_wallet_and_config(|anvil| anvil.fork(rpc_url))?; // Create a new instance of the IWETH9 contract. let weth = diff --git a/examples/providers/examples/ws.rs b/examples/providers/examples/ws.rs index a4b6585e..72f8de7a 100644 --- a/examples/providers/examples/ws.rs +++ b/examples/providers/examples/ws.rs @@ -1,14 +1,14 @@ //! Example of using the WS provider to subscribe to new blocks. use alloy::providers::{Provider, ProviderBuilder, WsConnect}; +use example_support::ws_url; use eyre::Result; use futures_util::StreamExt; #[tokio::main] async fn main() -> Result<()> { // Create the provider. - let rpc_url = "wss://eth-mainnet.g.alchemy.com/v2/your-api-key"; - let ws = WsConnect::new(rpc_url); + let ws = WsConnect::new(ws_url()?); let provider = ProviderBuilder::new().connect_ws(ws).await?; // Subscribe to new blocks. diff --git a/examples/providers/examples/ws_with_auth.rs b/examples/providers/examples/ws_with_auth.rs index ae72f7e9..35e718ba 100644 --- a/examples/providers/examples/ws_with_auth.rs +++ b/examples/providers/examples/ws_with_auth.rs @@ -4,18 +4,19 @@ use alloy::{ providers::{Provider, ProviderBuilder, WsConnect}, transports::Authorization, }; +use example_support::{required_env, ws_url}; use eyre::Result; use futures_util::StreamExt; #[tokio::main] async fn main() -> Result<()> { // Create authorization methods. - let auth = Authorization::basic("username", "password"); - let auth_bearer = Authorization::bearer("bearer-token"); + let auth = Authorization::basic(required_env("WS_USERNAME")?, required_env("WS_PASSWORD")?); + let auth_bearer = Authorization::bearer(required_env("WS_BEARER_TOKEN")?); // Create the WS connection object with authentication. - let rpc_url = "wss://your-ws-endpoint.com/"; - let ws_basic = WsConnect::new(rpc_url).with_auth(auth); + let rpc_url = ws_url()?; + let ws_basic = WsConnect::new(&rpc_url).with_auth(auth); let ws_bearer = WsConnect::new(rpc_url).with_auth(auth_bearer); // Create the provider. diff --git a/examples/queries/Cargo.toml b/examples/queries/Cargo.toml index 80bdb44a..f4702e9e 100644 --- a/examples/queries/Cargo.toml +++ b/examples/queries/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true futures-util.workspace = true diff --git a/examples/queries/examples/query_contract_storage.rs b/examples/queries/examples/query_contract_storage.rs index b3f064a6..2ad176c9 100644 --- a/examples/queries/examples/query_contract_storage.rs +++ b/examples/queries/examples/query_contract_storage.rs @@ -4,12 +4,13 @@ use alloy::{ primitives::{address, U256}, providers::{Provider, ProviderBuilder}, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Get storage slot 0 from the Uniswap V3 USDC-ETH pool on Ethereum mainnet. diff --git a/examples/queries/examples/query_deployed_bytecode.rs b/examples/queries/examples/query_deployed_bytecode.rs index 486880c3..6c106ab7 100644 --- a/examples/queries/examples/query_deployed_bytecode.rs +++ b/examples/queries/examples/query_deployed_bytecode.rs @@ -4,12 +4,13 @@ use alloy::{ primitives::address, providers::{Provider, ProviderBuilder}, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Get the bytecode of the Uniswap V3 USDC-ETH pool on Ethereum mainnet. diff --git a/examples/queries/examples/query_logs.rs b/examples/queries/examples/query_logs.rs index 5d203c54..c34197fd 100644 --- a/examples/queries/examples/query_logs.rs +++ b/examples/queries/examples/query_logs.rs @@ -5,12 +5,13 @@ use alloy::{ providers::{Provider, ProviderBuilder}, rpc::types::Filter, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Get logs from the latest block diff --git a/examples/queries/examples/query_logs_chunked.rs b/examples/queries/examples/query_logs_chunked.rs index 65be62d3..f92e4bcc 100644 --- a/examples/queries/examples/query_logs_chunked.rs +++ b/examples/queries/examples/query_logs_chunked.rs @@ -13,6 +13,7 @@ use alloy::{ sol, sol_types::SolEvent, }; +use example_support::rpc_url; use eyre::Result; sol! { @@ -23,7 +24,7 @@ sol! { #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://ethereum-rpc.publicnode.com".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); let latest_block = provider.get_block_number().await?; diff --git a/examples/subscriptions/Cargo.toml b/examples/subscriptions/Cargo.toml index c98a0490..276a6117 100644 --- a/examples/subscriptions/Cargo.toml +++ b/examples/subscriptions/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy.workspace = true +example-support.workspace = true eyre.workspace = true futures-util.workspace = true diff --git a/examples/subscriptions/examples/subscribe_all_logs.rs b/examples/subscriptions/examples/subscribe_all_logs.rs index c1ea226c..97f9c3ff 100644 --- a/examples/subscriptions/examples/subscribe_all_logs.rs +++ b/examples/subscriptions/examples/subscribe_all_logs.rs @@ -7,6 +7,7 @@ use alloy::{ sol, sol_types::SolEvent, }; +use example_support::ws_url; use eyre::Result; use futures_util::stream::StreamExt; @@ -21,8 +22,7 @@ sol!( #[tokio::main] async fn main() -> Result<()> { // Create the provider. - let rpc_url = "wss://eth-mainnet.g.alchemy.com/v2/your-api-key"; - let ws = WsConnect::new(rpc_url); + let ws = WsConnect::new(ws_url()?); let provider = ProviderBuilder::new().connect_ws(ws).await?; // Create a filter to watch for all WETH9 events. diff --git a/examples/subscriptions/examples/subscribe_logs.rs b/examples/subscriptions/examples/subscribe_logs.rs index 3ef08499..7940befd 100644 --- a/examples/subscriptions/examples/subscribe_logs.rs +++ b/examples/subscriptions/examples/subscribe_logs.rs @@ -5,14 +5,14 @@ use alloy::{ providers::{Provider, ProviderBuilder, WsConnect}, rpc::types::{BlockNumberOrTag, Filter}, }; +use example_support::ws_url; use eyre::Result; use futures_util::stream::StreamExt; #[tokio::main] async fn main() -> Result<()> { // Create the provider. - let rpc_url = "wss://eth-mainnet.g.alchemy.com/v2/your-api-key"; - let ws = WsConnect::new(rpc_url); + let ws = WsConnect::new(ws_url()?); let provider = ProviderBuilder::new().connect_ws(ws).await?; // Create a filter to watch for UNI token transfers. diff --git a/examples/subscriptions/examples/subscribe_pending_transactions.rs b/examples/subscriptions/examples/subscribe_pending_transactions.rs index a72a4164..46380cfb 100644 --- a/examples/subscriptions/examples/subscribe_pending_transactions.rs +++ b/examples/subscriptions/examples/subscribe_pending_transactions.rs @@ -2,14 +2,14 @@ //! `WebSocket` subscription. use alloy::providers::{Provider, ProviderBuilder, WsConnect}; +use example_support::ws_url; use eyre::Result; use futures_util::StreamExt; #[tokio::main] async fn main() -> Result<()> { // Create the provider. - let rpc_url = "wss://eth-mainnet.g.alchemy.com/v2/your-api-key"; - let ws = WsConnect::new(rpc_url); + let ws = WsConnect::new(ws_url()?); let provider = ProviderBuilder::new().connect_ws(ws).await?; // Subscribe to pending transactions. diff --git a/examples/transactions/Cargo.toml b/examples/transactions/Cargo.toml index 7080abd3..64eb3090 100644 --- a/examples/transactions/Cargo.toml +++ b/examples/transactions/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dev-dependencies] alloy = { workspace = true, features = ["eip712"]} +example-support.workspace = true eyre.workspace = true rand.workspace = true diff --git a/examples/transactions/examples/gas_price_usd.rs b/examples/transactions/examples/gas_price_usd.rs index 34e80b60..54019500 100644 --- a/examples/transactions/examples/gas_price_usd.rs +++ b/examples/transactions/examples/gas_price_usd.rs @@ -8,6 +8,7 @@ use alloy::{ sol, sol_types::SolCall, }; +use example_support::rpc_url; use eyre::Result; use std::str::FromStr; @@ -26,7 +27,7 @@ sol!( async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new().connect_anvil_with_config(|anvil| anvil.fork(rpc_url)); // Create a call to get the latest answer from the Chainlink ETH/USD feed. diff --git a/examples/transactions/examples/permit2_signature_transfer.rs b/examples/transactions/examples/permit2_signature_transfer.rs index 44367e99..58a4fb1a 100644 --- a/examples/transactions/examples/permit2_signature_transfer.rs +++ b/examples/transactions/examples/permit2_signature_transfer.rs @@ -15,6 +15,7 @@ use alloy::{ sol, sol_types::eip712_domain, }; +use example_support::rpc_url; use eyre::Result; use std::str::FromStr; @@ -68,7 +69,7 @@ impl From for ISignatureTransfer::PermitTransferFrom { async fn main() -> Result<()> { // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; // NOTE: ⚠️ Due to changes in EIP-7702 (see: https://getfoundry.sh/anvil/overview/#eip-7702-and-default-accounts), // the default mnemonic cannot be used for signature-based testing. Instead, we use a custom // mnemonic. diff --git a/examples/transactions/examples/trace_call.rs b/examples/transactions/examples/trace_call.rs index 8e9d0b10..1499fdc8 100644 --- a/examples/transactions/examples/trace_call.rs +++ b/examples/transactions/examples/trace_call.rs @@ -6,12 +6,13 @@ use alloy::{ providers::{ext::TraceApi, ProviderBuilder}, rpc::types::TransactionRequest, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Create a provider. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().connect_http(rpc_url); // Build a transaction to send 100 wei from Alice to Vitalik. diff --git a/examples/transactions/examples/trace_transaction.rs b/examples/transactions/examples/trace_transaction.rs index 5b542da0..6743e698 100644 --- a/examples/transactions/examples/trace_transaction.rs +++ b/examples/transactions/examples/trace_transaction.rs @@ -8,13 +8,14 @@ use alloy::{ GethDefaultTracingOptions, }, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new().connect_anvil_with_config(|anvil| anvil.fork(rpc_url)); // Hash of the tx we want to trace. diff --git a/examples/transactions/examples/transfer_erc20.rs b/examples/transactions/examples/transfer_erc20.rs index f9de5f29..63a9fec7 100644 --- a/examples/transactions/examples/transfer_erc20.rs +++ b/examples/transactions/examples/transfer_erc20.rs @@ -5,6 +5,7 @@ use alloy::{ providers::{Provider, ProviderBuilder}, sol, }; +use example_support::rpc_url; use eyre::Result; // Codegen from artifact. @@ -19,7 +20,7 @@ sol!( async fn main() -> Result<()> { // Spin up a forked Anvil node. // Ensure `anvil` is available in $PATH. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc"; + let rpc_url = rpc_url()?; let provider = ProviderBuilder::new().connect_anvil_with_wallet_and_config(|anvil| anvil.fork(rpc_url))?; diff --git a/examples/wallets/Cargo.toml b/examples/wallets/Cargo.toml index 3bbe7c58..2df17395 100644 --- a/examples/wallets/Cargo.toml +++ b/examples/wallets/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dev-dependencies] alloy.workspace = true alloy-chains.workspace = true +example-support.workspace = true aws-config = { workspace = true, default-features = false } aws-sdk-kms = { workspace = true, default-features = false } diff --git a/examples/wallets/examples/ledger_signer.rs b/examples/wallets/examples/ledger_signer.rs index 9a12bdda..01dd61b9 100644 --- a/examples/wallets/examples/ledger_signer.rs +++ b/examples/wallets/examples/ledger_signer.rs @@ -7,6 +7,7 @@ use alloy::{ rpc::types::TransactionRequest, signers::ledger::{HDPath, LedgerSigner}, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] @@ -15,7 +16,7 @@ async fn main() -> Result<()> { let signer = LedgerSigner::new(HDPath::LedgerLive(0), Some(1)).await?; // Create a provider with the wallet. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().wallet(signer).connect_http(rpc_url); // Build a transaction to send 100 wei from Alice to Vitalik. diff --git a/examples/wallets/examples/trezor_signer.rs b/examples/wallets/examples/trezor_signer.rs index e9515d09..b3db8835 100644 --- a/examples/wallets/examples/trezor_signer.rs +++ b/examples/wallets/examples/trezor_signer.rs @@ -7,6 +7,7 @@ use alloy::{ rpc::types::TransactionRequest, signers::trezor::{HDPath, TrezorSigner}, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] @@ -15,7 +16,7 @@ async fn main() -> Result<()> { let signer = TrezorSigner::new(HDPath::TrezorLive(0), Some(1)).await?; // Create a provider with the wallet. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().wallet(signer).connect_http(rpc_url); // Build a transaction to send 100 wei from Alice to Vitalik. diff --git a/examples/wallets/examples/yubi_signer.rs b/examples/wallets/examples/yubi_signer.rs index b2e60a8d..3379a591 100644 --- a/examples/wallets/examples/yubi_signer.rs +++ b/examples/wallets/examples/yubi_signer.rs @@ -10,6 +10,7 @@ use alloy::{ YubiSigner, }, }; +use example_support::rpc_url; use eyre::Result; #[tokio::main] @@ -24,7 +25,7 @@ async fn main() -> Result<()> { let signer = YubiSigner::connect(connector, Credentials::default(), 0); // Create a provider with the wallet. - let rpc_url = "https://reth-ethereum.ithaca.xyz/rpc".parse()?; + let rpc_url = rpc_url()?.parse()?; let provider = ProviderBuilder::new().wallet(signer).connect_http(rpc_url); // Build a transaction to send 100 wei from Alice to Vitalik.