Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions crates/cheatcodes/assets/cheatcodes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions crates/cheatcodes/spec/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1925,51 +1925,59 @@ interface Vm {

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath) external returns (address deployedAddress);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts abi-encoded constructor arguments.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts `msg.value`.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts abi-encoded constructor arguments and `msg.value`.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) external returns (address deployedAddress);

/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress);

/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts abi-encoded constructor arguments.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) external returns (address deployedAddress);

/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts `msg.value`.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) external returns (address deployedAddress);

/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
/// Reverts if the target artifact contains unlinked library placeholders.
///
/// Additionally accepts abi-encoded constructor arguments and `msg.value`.
#[cheatcode(group = Filesystem)]
Expand Down
19 changes: 18 additions & 1 deletion crates/cheatcodes/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ fn deploy_code(
Ok(address.abi_encode())
}

/// Returns the path to the json artifact depending on the input
/// Returns the bytecode from a JSON artifact file.
///
/// Can parse following input formats:
/// - `path/to/artifact.json`
Expand All @@ -411,6 +411,10 @@ fn deploy_code(
/// - `path/to/contract.sol:0.8.23`
/// - `ContractName`
/// - `ContractName:0.8.23`
///
/// This function is safe to use with contracts that have library dependencies.
/// `alloy_json_abi::ContractObject` validates bytecode during JSON parsing and will
/// reject artifacts with unlinked library placeholders.
fn get_artifact_code(state: &Cheatcodes, path: &str, deployed: bool) -> Result<Bytes> {
let path = if path.ends_with(".json") {
PathBuf::from(path)
Expand Down Expand Up @@ -942,4 +946,17 @@ mod tests {
let artifact: ContractObject = serde_json::from_str(s).unwrap();
assert!(artifact.deployed_bytecode.is_some());
}

#[test]
fn test_alloy_json_abi_rejects_unlinked_bytecode() {
let artifact_json = r#"{
"abi": [],
"bytecode": "0x73__$987e73aeca5e61ce83e4cb0814d87beda9$__63baf2f868"
}"#;

let result: Result<ContractObject, _> = serde_json::from_str(artifact_json);
assert!(result.is_err(), "should reject unlinked bytecode with placeholders");
let err = result.unwrap_err().to_string();
assert!(err.contains("expected bytecode, found unlinked bytecode with placeholder"));
}
}
Loading