Skip to main content

cast/cmd/
constructor_args.rs

1use super::creation_code::{
2    constructor_args_offset, constructor_with_args, fetch_creation_code, load_abi,
3};
4use alloy_dyn_abi::DynSolType;
5use alloy_primitives::{Address, Bytes};
6use clap::Parser;
7use eyre::Result;
8use foundry_cli::{
9    opts::{EtherscanOpts, RpcOpts},
10    utils::LoadConfig,
11};
12
13foundry_config::impl_figment_convert!(ConstructorArgsArgs, etherscan, rpc);
14
15/// CLI arguments for `cast creation-args`.
16#[derive(Parser)]
17pub struct ConstructorArgsArgs {
18    /// An Ethereum address, for which the bytecode will be fetched.
19    contract: Address,
20
21    /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is
22    /// not verified on Etherscan
23    #[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 mut config = self.load_config()?;
36        let Self { contract, abi_path, .. } = self;
37
38        let bytecode = fetch_creation_code(&mut config, contract).await?;
39        let abi = load_abi(contract, &config, abi_path.as_deref()).await?;
40        let constructor = constructor_with_args(&abi)?;
41        let split = constructor_args_offset(constructor, &bytecode)?;
42
43        for (input, arg) in constructor.inputs.iter().zip(bytecode[split..].chunks(32)) {
44            let decoded = DynSolType::parse(&input.ty)?.abi_decode(arg)?;
45            sh_println!("{} → {decoded:?}", Bytes::copy_from_slice(arg))?;
46        }
47        Ok(())
48    }
49}