cast/cmd/
constructor_args.rs1use super::{creation_code::fetch_creation_code_from_etherscan, interface::load_abi_from_file};
2use alloy_dyn_abi::DynSolType;
3use alloy_primitives::{Address, Bytes};
4use alloy_provider::Provider;
5use clap::{Parser, command};
6use eyre::{OptionExt, Result, eyre};
7use foundry_cli::{
8 opts::{EtherscanOpts, RpcOpts},
9 utils::{self, LoadConfig},
10};
11use foundry_common::abi::fetch_abi_from_etherscan;
12use foundry_config::Config;
13
14foundry_config::impl_figment_convert!(ConstructorArgsArgs, etherscan, rpc);
15
16#[derive(Parser)]
18pub struct ConstructorArgsArgs {
19 contract: Address,
21
22 #[arg(long)]
25 abi_path: Option<String>,
26
27 #[command(flatten)]
28 etherscan: EtherscanOpts,
29
30 #[command(flatten)]
31 rpc: RpcOpts,
32}
33
34impl ConstructorArgsArgs {
35 pub async fn run(self) -> Result<()> {
36 let mut config = self.load_config()?;
37
38 let Self { contract, abi_path, etherscan: _, rpc: _ } = self;
39
40 let provider = utils::get_provider(&config)?;
41 config.chain = Some(provider.get_chain_id().await?.into());
42
43 let bytecode = fetch_creation_code_from_etherscan(contract, &config, provider).await?;
44
45 let args_arr = parse_constructor_args(bytecode, contract, &config, abi_path).await?;
46 for arg in args_arr {
47 let _ = sh_println!("{arg}");
48 }
49
50 Ok(())
51 }
52}
53
54async fn parse_constructor_args(
56 bytecode: Bytes,
57 contract: Address,
58 config: &Config,
59 abi_path: Option<String>,
60) -> Result<Vec<String>> {
61 let abi = if let Some(abi_path) = abi_path {
62 load_abi_from_file(&abi_path, None)?
63 } else {
64 fetch_abi_from_etherscan(contract, config).await?
65 };
66
67 let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?;
68 let (abi, _) = abi;
69
70 let constructor = abi.constructor.ok_or_else(|| eyre!("No constructor found."))?;
71
72 if constructor.inputs.is_empty() {
73 return Err(eyre!("No constructor arguments found."));
74 }
75
76 let args_size = constructor.inputs.len() * 32;
77 let args_bytes = Bytes::from(bytecode[bytecode.len() - args_size..].to_vec());
78
79 let display_args: Vec<String> = args_bytes
80 .chunks(32)
81 .enumerate()
82 .map(|(i, arg)| {
83 format_arg(&constructor.inputs[i].ty, arg).expect("Failed to format argument.")
84 })
85 .collect();
86
87 Ok(display_args)
88}
89
90fn format_arg(ty: &str, arg: &[u8]) -> Result<String> {
91 let arg_type: DynSolType = ty.parse().expect("Invalid ABI type.");
92 let decoded = arg_type.abi_decode(arg)?;
93 let bytes = Bytes::from(arg.to_vec());
94
95 Ok(format!("{bytes} → {decoded:?}"))
96}