foundry_test_utils/
etherscan.rs

1//! Etherscan utilities for tests.
2
3use alloy_chains::Chain;
4use alloy_primitives::Address;
5use eyre::Result;
6use foundry_block_explorers::Client;
7use foundry_common::{compile::etherscan_project, flatten};
8use std::str::FromStr;
9
10/// Fetches the source code of a verified contract from Etherscan, flattens it, and returns it.
11///
12/// This provides the same functionality as `cast source --flatten` but using the library directly,
13/// avoiding the need to shell out to the `cast` binary.
14pub async fn fetch_etherscan_source_flattened(
15    address: &str,
16    etherscan_api_key: &str,
17    chain: Chain,
18) -> Result<String> {
19    let client = Client::builder().chain(chain)?.with_api_key(etherscan_api_key).build()?;
20
21    let address = Address::from_str(address)?;
22    let metadata = client.contract_source_code(address).await?;
23    let Some(metadata) = metadata.items.first() else {
24        eyre::bail!("Empty contract source code for {address}")
25    };
26
27    let tmp = tempfile::tempdir()?;
28    let project = etherscan_project(metadata, tmp.path())?;
29    let target_path = project.find_contract_path(&metadata.contract_name)?;
30
31    flatten(project, &target_path)
32}