Skip to content

Commit

Permalink
Cairo project allow multiple contracts at once (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
smonicas authored Sep 20, 2023
1 parent 8fb08d6 commit 102bcd3
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 39 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ Run printers:
caracal print path/file/to/analyze --printer printer_to_use --corelib path/to/corelib/src
```
### Cairo project
If you have a cairo project with multiple files and contracts you may need to specify which contract with `--contract-path`. The local cairo compiler binary is used if available otherwise a bundled compiler is used. In the latter case you also need to specify the corelib as explained above for the standalone case. The path is the directory where `cairo_project.toml` resides.
If you have a cairo project with multiple files and contracts you may need to specify which contracts with `--contract-path`. The local cairo compiler binary is used if available otherwise a bundled compiler is used. In the latter case you also need to specify the corelib as explained above for the standalone case. The path is the directory where `cairo_project.toml` resides.
Run detectors:
```bash
caracal detect path/to/dir
```
```bash
caracal detect path/to/dir --contract-path token::myerc20::...
caracal detect path/to/dir --contract-path token::myerc20::... token::myerc721::...
```
Run printers:
```bash
Expand Down
6 changes: 3 additions & 3 deletions src/cli/commands/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pub struct DetectArgs {
#[arg(long)]
corelib: Option<PathBuf>,

/// Path to the contract to compile when using a cairo project with multiple contracts
#[arg(long)]
contract_path: Option<String>,
/// Path to the contracts to compile when using a cairo project with multiple contracts
#[arg(long, num_args(0..))]
contract_path: Option<Vec<String>>,

/// Detectors to run
#[arg(long, num_args(0..), conflicts_with_all(["exclude", "exclude_informational", "exclude_low", "exclude_medium", "exclude_high"]))]
Expand Down
6 changes: 3 additions & 3 deletions src/cli/commands/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub struct PrintArgs {
#[arg(long)]
corelib: Option<PathBuf>,

/// Path to the contract to compile when using a cairo project with multiple contracts
#[arg(long)]
contract_path: Option<String>,
/// Path to the contracts to compile when using a cairo project with multiple contracts
#[arg(long, num_args(0..))]
contract_path: Option<Vec<String>>,

/// Which functions to run the printer (all, user-functions)
#[arg(short, long, default_value_t = Filter::UserFunctions)]
Expand Down
76 changes: 46 additions & 30 deletions src/compilation/cairo_project.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::{anyhow, bail, Context, Result};
use std::env;
use std::process;
use std::process::Output;
use std::sync::Arc;

use super::ProgramCompiled;
Expand Down Expand Up @@ -97,41 +98,56 @@ pub fn compile(opts: CoreOpts) -> Result<Vec<ProgramCompiled>> {
}

fn local_compiler(opts: CoreOpts) -> Result<Vec<ProgramCompiled>> {
let output = if let Some(contract_path) = opts.contract_path {
process::Command::new("starknet-compile")
.arg(opts.target)
.arg("--contract-path")
.arg(contract_path)
.arg("--replace-ids")
.output()?
let mut compiler_calls: Vec<Output> = vec![];
if let Some(contract_paths) = opts.contract_path {
contract_paths.iter().for_each(|c| {
compiler_calls.push(
process::Command::new("starknet-compile")
.arg(opts.target.clone())
.arg("--contract-path")
.arg(c)
.arg("--replace-ids")
.output()
.unwrap(),
)
});
} else {
process::Command::new("starknet-compile")
.arg(opts.target)
.arg("--replace-ids")
.output()?
compiler_calls.push(
process::Command::new("starknet-compile")
.arg(opts.target)
.arg("--replace-ids")
.output()
.unwrap(),
);
};

if !output.status.success() {
bail!(anyhow!(
"starknet-compile failed to compile.\n Status {}\n {}",
output.status,
String::from_utf8(output.stderr)?
));
}
let mut programs_compiled: Vec<ProgramCompiled> = vec![];

for compiler_call in compiler_calls {
if !compiler_call.status.success() {
bail!(anyhow!(
"starknet-compile failed to compile.\n Status {}\n {}",
compiler_call.status,
String::from_utf8(compiler_call.stderr)?
));
}

let contract_class: ContractClass =
serde_json::from_str(&String::from_utf8(output.stdout)?).unwrap();
let contract_class: ContractClass =
serde_json::from_str(&String::from_utf8(compiler_call.stdout)?).unwrap();

// We don't have to check the existence because we ran the compiler with --replace-ids
let debug_info = contract_class.sierra_program_debug_info.unwrap();
// We don't have to check the existence because we ran the compiler with --replace-ids
let debug_info = contract_class.sierra_program_debug_info.unwrap();

let sierra = sierra_from_felt252s(&contract_class.sierra_program)
.unwrap()
.2;
let sierra = SierraProgramDebugReplacer { debug_info }.apply(&sierra);
let sierra = sierra_from_felt252s(&contract_class.sierra_program)
.unwrap()
.2;
let sierra = SierraProgramDebugReplacer { debug_info }.apply(&sierra);

programs_compiled.push(ProgramCompiled {
sierra,
abi: contract_class.abi.unwrap(),
});
}

Ok(vec![ProgramCompiled {
sierra,
abi: contract_class.abi.unwrap(),
}])
Ok(programs_compiled)
}
2 changes: 1 addition & 1 deletion src/core/core_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::core::compilation_unit::CompilationUnit;
pub struct CoreOpts {
pub target: PathBuf,
pub corelib: Option<PathBuf>,
pub contract_path: Option<String>,
pub contract_path: Option<Vec<String>>,
}

pub struct CoreUnit {
Expand Down

0 comments on commit 102bcd3

Please sign in to comment.