ethrex_sdk_contract_utils/
compile.rs1use std::{
2 path::{Path, PathBuf},
3 process::Command,
4};
5
6#[derive(Debug, thiserror::Error)]
7pub enum ContractCompilationError {
8 #[error("The path is not a valid utf-8 string")]
9 FailedToGetStringFromPath,
10 #[error("Deployer compilation error: {0}")]
11 CompilationError(String),
12}
13
14pub fn compile_contract(
15 output_dir: &Path,
16 contract_path: &Path,
17 runtime_bin: bool,
18 abi_json: bool,
19 remappings: Option<&[(&str, PathBuf)]>,
20 allow_paths: &[&Path],
21 optimize_runs: Option<u64>,
22) -> Result<(), ContractCompilationError> {
23 let bin_flag = if runtime_bin {
24 "--bin-runtime"
25 } else {
26 "--bin"
27 };
28
29 let mut cmd = Command::new("solc");
30 cmd.arg(bin_flag);
31
32 if abi_json {
33 cmd.arg("--abi");
34 }
35
36 apply_remappings(&mut cmd, remappings)?;
37
38 if let Some(optimize_runs) = optimize_runs {
39 cmd.arg("--optimize")
40 .arg("--optimize-runs")
41 .arg(format!("{optimize_runs}"));
42 }
43
44 cmd.arg(
45 contract_path
46 .to_str()
47 .ok_or(ContractCompilationError::FailedToGetStringFromPath)?,
48 )
49 .arg("--via-ir")
50 .arg("-o")
51 .arg(
52 output_dir
53 .join("solc_out")
54 .to_str()
55 .ok_or(ContractCompilationError::FailedToGetStringFromPath)?,
56 )
57 .arg("--overwrite")
58 .arg("--no-cbor-metadata");
59
60 if !allow_paths.is_empty() {
61 apply_allow_paths(&mut cmd, allow_paths)?;
62 }
63
64 let cmd_succeeded = cmd
65 .spawn()
66 .map_err(|err| {
67 ContractCompilationError::CompilationError(format!("Failed to spawn solc: {err}"))
68 })?
69 .wait()
70 .map_err(|err| {
71 ContractCompilationError::CompilationError(format!("Failed to wait for solc: {err}"))
72 })?
73 .success();
74
75 if !cmd_succeeded {
76 return Err(ContractCompilationError::CompilationError(format!(
77 "Failed to compile {contract_path:?}"
78 )));
79 }
80
81 Ok(())
82}
83
84fn apply_remappings(
85 cmd: &mut Command,
86 remappings: Option<&[(&str, PathBuf)]>,
87) -> Result<(), ContractCompilationError> {
88 if let Some(remaps) = remappings {
89 for (prefix, path) in remaps {
90 let path_str = path
91 .to_str()
92 .ok_or(ContractCompilationError::FailedToGetStringFromPath)?;
93 cmd.arg(format!("{prefix}={path_str}"));
94 }
95 }
96 Ok(())
97}
98
99fn apply_allow_paths(
100 cmd: &mut Command,
101 allow_paths: &[&Path],
102) -> Result<(), ContractCompilationError> {
103 cmd.arg("--allow-paths");
104 let joined_paths = allow_paths
105 .iter()
106 .map(|p| {
107 p.to_str()
108 .ok_or(ContractCompilationError::FailedToGetStringFromPath)
109 })
110 .collect::<Result<Vec<_>, _>>()?
111 .join(",");
112 cmd.arg(joined_paths);
113 Ok(())
114}