1use super::creation_code::{fetch_creation_code, load_abi, parse_code_output};
2use alloy_primitives::Address;
3use clap::Parser;
4use eyre::Result;
5use foundry_cli::{
6 opts::{EtherscanOpts, RpcOpts},
7 utils::LoadConfig,
8};
9use foundry_common::fs;
10use serde_json::json;
11use std::path::PathBuf;
12
13foundry_config::impl_figment_convert!(ArtifactArgs, etherscan, rpc);
14
15#[derive(Parser)]
17pub struct ArtifactArgs {
18 contract: Address,
20
21 #[arg(long)]
24 abi_path: Option<String>,
25
26 #[arg(
30 short,
31 long,
32 value_hint = clap::ValueHint::FilePath,
33 value_name = "PATH",
34 )]
35 output: Option<PathBuf>,
36
37 #[command(flatten)]
38 etherscan: EtherscanOpts,
39
40 #[command(flatten)]
41 rpc: RpcOpts,
42}
43
44impl ArtifactArgs {
45 pub async fn run(self) -> Result<()> {
46 let mut config = self.load_config()?;
47 let Self { contract, output, abi_path, .. } = self;
48
49 let bytecode = fetch_creation_code(&mut config, contract).await?;
50 let abi_path = abi_path.as_deref();
51 let abi = load_abi(contract, &config, abi_path).await?;
52 let bytecode =
53 parse_code_output(bytecode, contract, &config, abi_path, true, false).await?;
54
55 let artifact = json!({ "abi": abi, "bytecode": { "object": bytecode } });
56 let artifact = serde_json::to_string_pretty(&artifact)?;
57
58 if let Some(loc) = output {
59 if let Some(parent) = loc.parent() {
60 fs::create_dir_all(parent)?;
61 }
62 fs::write(&loc, artifact)?;
63 sh_status!("Saved artifact at {}", loc.display())?;
64 } else {
65 sh_println!("{artifact}")?;
66 }
67 Ok(())
68 }
69}