cast/cmd/
constructor_args.rs
1use super::{
2 creation_code::fetch_creation_code,
3 interface::{fetch_abi_from_etherscan, load_abi_from_file},
4};
5use alloy_dyn_abi::DynSolType;
6use alloy_primitives::{Address, Bytes};
7use alloy_provider::Provider;
8use clap::{command, Parser};
9use eyre::{eyre, OptionExt, Result};
10use foundry_block_explorers::Client;
11use foundry_cli::{
12 opts::{EtherscanOpts, RpcOpts},
13 utils::{self, LoadConfig},
14};
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 Self { contract, mut etherscan, rpc, abi_path } = self;
37
38 let config = rpc.load_config()?;
39 let provider = utils::get_provider(&config)?;
40 let api_key = etherscan.key().unwrap_or_default();
41 let chain = provider.get_chain_id().await?;
42 etherscan.chain = Some(chain.into());
43 let client = Client::new(chain.into(), api_key)?;
44
45 let bytecode = fetch_creation_code(contract, client, provider).await?;
46
47 let args_arr = parse_constructor_args(bytecode, contract, ðerscan, abi_path).await?;
48 for arg in args_arr {
49 let _ = sh_println!("{arg}");
50 }
51
52 Ok(())
53 }
54}
55
56async fn parse_constructor_args(
58 bytecode: Bytes,
59 contract: Address,
60 etherscan: &EtherscanOpts,
61 abi_path: Option<String>,
62) -> Result<Vec<String>> {
63 let abi = if let Some(abi_path) = abi_path {
64 load_abi_from_file(&abi_path, None)?
65 } else {
66 fetch_abi_from_etherscan(contract, etherscan).await?
67 };
68
69 let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?;
70 let (abi, _) = abi;
71
72 let constructor = abi.constructor.ok_or_else(|| eyre!("No constructor found."))?;
73
74 if constructor.inputs.is_empty() {
75 return Err(eyre!("No constructor arguments found."));
76 }
77
78 let args_size = constructor.inputs.len() * 32;
79 let args_bytes = Bytes::from(bytecode[bytecode.len() - args_size..].to_vec());
80
81 let display_args: Vec<String> = args_bytes
82 .chunks(32)
83 .enumerate()
84 .map(|(i, arg)| {
85 format_arg(&constructor.inputs[i].ty, arg).expect("Failed to format argument.")
86 })
87 .collect();
88
89 Ok(display_args)
90}
91
92fn format_arg(ty: &str, arg: &[u8]) -> Result<String> {
93 let arg_type: DynSolType = ty.parse().expect("Invalid ABI type.");
94 let decoded = arg_type.abi_decode(arg)?;
95 let bytes = Bytes::from(arg.to_vec());
96
97 Ok(format!("{bytes} → {decoded:?}"))
98}