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