use crate::{
cli_utils::{
absolute_path, assert_command_success, execute_command, CommandResult, ResolcOptSettings,
SolcOptSettings, SOLIDITY_CONTRACT_PATH, STANDARD_JSON_CONTRACTS_PATH,
YUL_MEMSET_CONTRACT_PATH,
},
SolcCompiler,
};
const PVM_BLOB_START: &str = "50564d";
const EVM_BLOB_START_FROM_SOLIDITY: &str = "6080";
const EVM_BLOB_START_FROM_YUL: &str = "";
fn assert_pvm_blob(result: &CommandResult) {
assert_binary_blob(result, "Binary:\n", PVM_BLOB_START);
}
fn assert_evm_blob_from_solidity(result: &CommandResult) {
assert_binary_blob(result, "Binary:\n", EVM_BLOB_START_FROM_SOLIDITY);
}
fn assert_evm_blob_from_yul(result: &CommandResult) {
assert_binary_blob(result, "Binary representation:\n", EVM_BLOB_START_FROM_YUL);
}
fn assert_pvm_blob_from_json(result: &CommandResult, file_name: &str, contract_name: &str) {
assert_binary_blob_from_json(result, file_name, contract_name, PVM_BLOB_START);
}
fn assert_evm_blob_from_json(result: &CommandResult, file_name: &str, contract_name: &str) {
assert_binary_blob_from_json(
result,
file_name,
contract_name,
EVM_BLOB_START_FROM_SOLIDITY,
);
}
fn assert_binary_blob(result: &CommandResult, blob_prefix: &str, blob_start: &str) {
assert_command_success(result, "Executing the command");
let is_blob = result
.stdout
.split(blob_prefix)
.collect::<Vec<&str>>()
.get(1)
.is_some_and(|blob| blob.starts_with(blob_start));
assert!(
is_blob,
"expected a binary blob starting with `{blob_start}`",
);
}
fn assert_binary_blob_from_json(
result: &CommandResult,
file_name: &str,
contract_name: &str,
blob_start: &str,
) {
assert_command_success(result, "Executing the command with stdin JSON input");
let parsed_output: serde_json::Value =
serde_json::from_str(&result.stdout).expect("expected valid JSON output");
let contract = &parsed_output["contracts"][file_name][contract_name];
let errors = contract["errors"].as_array();
assert!(
errors.is_none(),
"errors found for JSON-provided contract `{contract_name}` in `{file_name}`: {}",
get_first_json_error(errors.unwrap()),
);
let blob = contract["evm"]["bytecode"]["object"]
.as_str()
.unwrap_or_else(|| {
panic!(
"expected a binary blob for JSON-provided contract `{contract_name}` in `{file_name}`",
)
});
assert!(
blob.starts_with(blob_start),
"expected a binary blob starting with `{blob_start}`",
);
}
fn get_first_json_error(errors: &[serde_json::Value]) -> &str {
errors.first().unwrap()["message"].as_str().unwrap()
}
#[test]
fn compiles_solidity_to_binary_blob() {
let path = absolute_path(SOLIDITY_CONTRACT_PATH);
let resolc_arguments = &[&path, "--bin", ResolcOptSettings::PERFORMANCE];
let solc_arguments = &[
&path,
"--bin",
"--via-ir",
"--optimize",
"--optimize-runs",
SolcOptSettings::PERFORMANCE,
];
let resolc_result = execute_command(crate::DEFAULT_EXECUTABLE_NAME, resolc_arguments, None);
assert_pvm_blob(&resolc_result);
let solc_result = execute_command(SolcCompiler::DEFAULT_EXECUTABLE_NAME, solc_arguments, None);
assert_evm_blob_from_solidity(&solc_result);
}
#[test]
fn compiles_yul_to_binary_blob() {
let path = absolute_path(YUL_MEMSET_CONTRACT_PATH);
let resolc_arguments = &[&path, "--yul", "--bin", ResolcOptSettings::PERFORMANCE];
let solc_arguments = &[
&path,
"--strict-assembly",
"--bin",
"--optimize",
"--optimize-runs",
SolcOptSettings::PERFORMANCE,
];
let resolc_result = execute_command(crate::DEFAULT_EXECUTABLE_NAME, resolc_arguments, None);
assert_pvm_blob(&resolc_result);
let solc_result = execute_command(SolcCompiler::DEFAULT_EXECUTABLE_NAME, solc_arguments, None);
assert_evm_blob_from_yul(&solc_result);
}
#[test]
fn compiles_json_to_binary_blob() {
let path = absolute_path(STANDARD_JSON_CONTRACTS_PATH);
let resolc_arguments = &["--standard-json"];
let solc_arguments = &["--standard-json"];
let resolc_result = execute_command(
crate::DEFAULT_EXECUTABLE_NAME,
resolc_arguments,
Some(&path),
);
assert_pvm_blob_from_json(&resolc_result, "src/Counter.sol", "Counter");
let solc_result = execute_command(
SolcCompiler::DEFAULT_EXECUTABLE_NAME,
solc_arguments,
Some(&path),
);
assert_evm_blob_from_json(&solc_result, "src/Counter.sol", "Counter");
}