diff --git a/cli/src/cmd/build.rs b/cli/src/cmd/build.rs index 18776cf041d2..3a5bdac4b660 100644 --- a/cli/src/cmd/build.rs +++ b/cli/src/cmd/build.rs @@ -113,6 +113,12 @@ pub struct BuildArgs { #[serde(flatten)] pub compiler: CompilerArgs, + #[clap(help = "print compiled contract names", long = "names")] + pub names: bool, + + #[clap(help = "print compiled contract sizes", long = "sizes")] + pub sizes: bool, + #[clap(help = "ignore warnings with specific error codes", long)] #[serde(skip_serializing_if = "Vec::is_empty")] pub ignored_error_codes: Vec, @@ -155,7 +161,7 @@ impl Cmd for BuildArgs { type Output = ProjectCompileOutput; fn run(self) -> eyre::Result { let project = self.project()?; - super::compile(&project) + super::compile(&project, self.names, self.sizes) } } diff --git a/cli/src/cmd/create.rs b/cli/src/cmd/create.rs index 7ac160cc2d84..e9b677b6e721 100644 --- a/cli/src/cmd/create.rs +++ b/cli/src/cmd/create.rs @@ -60,7 +60,7 @@ impl Cmd for CreateArgs { fn run(self) -> Result { // Find Project & Compile let project = self.opts.project()?; - let compiled = super::compile(&project)?; + let compiled = super::compile(&project, self.opts.names, self.opts.sizes)?; // Get ABI and BIN let (abi, bin, _) = super::read_artifact(&project, compiled, self.contract.clone())?; diff --git a/cli/src/cmd/flatten.rs b/cli/src/cmd/flatten.rs index 2b4afb8e3baf..44f2f335994c 100644 --- a/cli/src/cmd/flatten.rs +++ b/cli/src/cmd/flatten.rs @@ -73,6 +73,8 @@ impl Cmd for FlattenArgs { lib_paths, out_path: None, compiler: Default::default(), + names: false, + sizes: false, ignored_error_codes: vec![], no_auto_detect: false, offline: false, diff --git a/cli/src/cmd/mod.rs b/cli/src/cmd/mod.rs index a74401fb1186..3543b367d2d1 100644 --- a/cli/src/cmd/mod.rs +++ b/cli/src/cmd/mod.rs @@ -57,7 +57,7 @@ use ethers::{ prelude::artifacts::{CompactBytecode, CompactDeployedBytecode}, solc::cache::SolFilesCache, }; -use std::path::PathBuf; +use std::{collections::BTreeMap, path::PathBuf}; /// Common trait for all cli commands pub trait Cmd: clap::Parser + Sized { @@ -67,9 +67,15 @@ pub trait Cmd: clap::Parser + Sized { use ethers::solc::{artifacts::CompactContractBytecode, Project, ProjectCompileOutput}; +use foundry_utils::to_table; + /// Compiles the provided [`Project`], throws if there's any compiler error and logs whether /// compilation was successful or if there was a cache hit. -pub fn compile(project: &Project) -> eyre::Result { +pub fn compile( + project: &Project, + print_names: bool, + print_sizes: bool, +) -> eyre::Result { if !project.paths.sources.exists() { eyre::bail!( r#"no contracts to compile, contracts folder "{}" does not exist. @@ -88,9 +94,51 @@ If you are in a subdirectory in a Git repository, try adding `--root .`"#, } else if output.is_unchanged() { println!("no files changed, compilation skipped."); } else { + if print_names { + let compiled_contracts = output.compiled_contracts_by_compiler_version(); + println!("compiled contracts:"); + for (version, contracts) in compiled_contracts.into_iter() { + println!( + " compiler version: {}.{}.{}", + version.major, version.minor, version.patch + ); + for (name, _) in contracts { + println!(" - {}", name); + } + } + } + if print_sizes { + // add extra newline if names were already printed + if print_names { + println!(); + } + let compiled_contracts = output.compiled_contracts_by_compiler_version(); + let mut sizes = BTreeMap::new(); + for (_, contracts) in compiled_contracts.into_iter() { + for (name, contract) in contracts { + let bytecode: CompactContractBytecode = contract.into(); + let size = if let Some(code) = bytecode.bytecode { + if let Some(object) = code.object.as_bytes() { + object.to_vec().len() + } else { + 0 + } + } else { + 0 + }; + sizes.insert(name, size); + } + } + let json = serde_json::to_value(&sizes)?; + println!("name size (bytes)"); + println!("-----------------------------"); + println!("{}", to_table(json)); + } + println!("{}", output); println!("success."); } + Ok(output) } diff --git a/config/src/lib.rs b/config/src/lib.rs index 5e7c641bb1e3..3810480dbffe 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -186,6 +186,10 @@ pub struct Config { /// by proptest, to be encountered during usage of `vm.assume` /// cheatcode. pub fuzz_max_global_rejects: u32, + /// Print the names of the compiled contracts + pub names: bool, + /// Print the sizes of the compiled contracts + pub sizes: bool, /// The root path where the config detection started from, `Config::with_root` #[doc(hidden)] // We're skipping serialization here, so it won't be included in the [`Config::to_string()`] @@ -800,6 +804,8 @@ impl Default for Config { optimizer_details: None, extra_output: Default::default(), extra_output_files: Default::default(), + names: false, + sizes: false, fuzz_runs: 256, fuzz_max_local_rejects: 1024, fuzz_max_global_rejects: 65536,