foundry_cli/utils/
abi.rs

1use alloy_chains::Chain;
2use alloy_ens::NameOrAddress;
3use alloy_json_abi::Function;
4use alloy_primitives::{hex, Address};
5use alloy_provider::{network::AnyNetwork, Provider};
6use eyre::{OptionExt, Result};
7use foundry_block_explorers::EtherscanApiVersion;
8use foundry_common::abi::{encode_function_args, get_func, get_func_etherscan};
9use futures::future::join_all;
10
11async fn resolve_name_args<P: Provider<AnyNetwork>>(args: &[String], provider: &P) -> Vec<String> {
12    join_all(args.iter().map(|arg| async {
13        if arg.contains('.') {
14            let addr = NameOrAddress::Name(arg.to_string()).resolve(provider).await;
15            match addr {
16                Ok(addr) => addr.to_string(),
17                Err(_) => arg.to_string(),
18            }
19        } else {
20            arg.to_string()
21        }
22    }))
23    .await
24}
25
26pub async fn parse_function_args<P: Provider<AnyNetwork>>(
27    sig: &str,
28    args: Vec<String>,
29    to: Option<Address>,
30    chain: Chain,
31    provider: &P,
32    etherscan_api_key: Option<&str>,
33    etherscan_api_version: EtherscanApiVersion,
34) -> Result<(Vec<u8>, Option<Function>)> {
35    if sig.trim().is_empty() {
36        eyre::bail!("Function signature or calldata must be provided.")
37    }
38
39    let args = resolve_name_args(&args, provider).await;
40
41    if let Ok(data) = hex::decode(sig) {
42        return Ok((data, None))
43    }
44
45    let func = if sig.contains('(') {
46        // a regular function signature with parentheses
47        get_func(sig)?
48    } else {
49        let etherscan_api_key = etherscan_api_key.ok_or_eyre(
50            "If you wish to fetch function data from Etherscan, please provide an Etherscan API key.",
51        )?;
52        let to = to.ok_or_eyre("A 'to' address must be provided to fetch function data.")?;
53        get_func_etherscan(sig, to, &args, chain, etherscan_api_key, etherscan_api_version).await?
54    };
55
56    Ok((encode_function_args(&func, &args)?, Some(func)))
57}