1use super::{
2 creation_code::{fetch_creation_code_from_etherscan, parse_code_output},
3 interface::load_abi_from_file,
4};
5use alloy_primitives::Address;
6use alloy_provider::Provider;
7use clap::{Parser, command};
8use eyre::Result;
9use foundry_cli::{
10 opts::{EtherscanOpts, RpcOpts},
11 utils::{self, LoadConfig},
12};
13use foundry_common::{abi::fetch_abi_from_etherscan, fs};
14use serde_json::json;
15use std::path::PathBuf;
16
17foundry_config::impl_figment_convert!(ArtifactArgs, etherscan, rpc);
18
19#[derive(Parser)]
21pub struct ArtifactArgs {
22 contract: Address,
24
25 #[arg(long)]
28 abi_path: Option<String>,
29
30 #[arg(
34 short,
35 long,
36 value_hint = clap::ValueHint::FilePath,
37 value_name = "PATH",
38 )]
39 output: Option<PathBuf>,
40
41 #[command(flatten)]
42 etherscan: EtherscanOpts,
43
44 #[command(flatten)]
45 rpc: RpcOpts,
46}
47
48impl ArtifactArgs {
49 pub async fn run(self) -> Result<()> {
50 let mut config = self.load_config()?;
51
52 let Self { contract, output: output_location, abi_path, etherscan: _, rpc: _ } = self;
53
54 let provider = utils::get_provider(&config)?;
55 let chain = provider.get_chain_id().await?;
56 config.chain = Some(chain.into());
57
58 let abi = if let Some(ref abi_path) = abi_path {
59 load_abi_from_file(abi_path, None)?
60 } else {
61 fetch_abi_from_etherscan(contract, &config).await?
62 };
63
64 let (abi, _) = abi.first().ok_or_else(|| eyre::eyre!("No ABI found"))?;
65
66 let bytecode = fetch_creation_code_from_etherscan(contract, &config, provider).await?;
67 let bytecode =
68 parse_code_output(bytecode, contract, &config, abi_path.as_deref(), true, false)
69 .await?;
70
71 let artifact = json!({
72 "abi": abi,
73 "bytecode": {
74 "object": bytecode
75 }
76 });
77
78 let artifact = serde_json::to_string_pretty(&artifact)?;
79
80 if let Some(loc) = output_location {
81 if let Some(parent) = loc.parent() {
82 fs::create_dir_all(parent)?;
83 }
84 fs::write(&loc, artifact)?;
85 sh_println!("Saved artifact at {}", loc.display())?;
86 } else {
87 sh_println!("{artifact}")?;
88 }
89
90 Ok(())
91 }
92}