Skip to content

Commit 191c6dd

Browse files
committed
test(forge): add verification test for bytecode mismatch with incorrect source code
1 parent 6830641 commit 191c6dd

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

crates/forge/tests/cli/verify_bytecode.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,60 @@ fn test_verify_bytecode_with_ignore(
144144
);
145145
}
146146
}
147+
148+
#[expect(clippy::too_many_arguments)]
149+
fn test_verify_bytecode_mismatch(
150+
prj: TestProject,
151+
mut cmd: TestCommand,
152+
addr: &str,
153+
contract_name: &str,
154+
source_code: &str,
155+
config: Config,
156+
verifier: &str,
157+
verifier_url: &str,
158+
) {
159+
let etherscan_key = next_etherscan_api_key();
160+
let rpc_url = next_http_archive_rpc_url();
161+
162+
// Fetch real source code
163+
let real_source = cmd
164+
.cast_fuse()
165+
.args(["source", addr, "--flatten", "--etherscan-api-key", &etherscan_key])
166+
.assert_success()
167+
.get_output()
168+
.stdout_lossy();
169+
170+
prj.add_source(contract_name, &real_source);
171+
prj.write_config(config);
172+
// Build once with correct source (creates cache)
173+
cmd.forge_fuse().arg("build").assert_success();
174+
175+
// Now replace with different incorrect source code
176+
prj.add_source(contract_name, source_code);
177+
let args = vec![
178+
"verify-bytecode",
179+
addr,
180+
contract_name,
181+
"--etherscan-api-key",
182+
&etherscan_key,
183+
"--verifier",
184+
verifier,
185+
"--verifier-url",
186+
verifier_url,
187+
"--rpc-url",
188+
&rpc_url,
189+
];
190+
let output = cmd.forge_fuse().args(args).assert_success().get_output().stderr_lossy();
191+
192+
// Verify that bytecode does NOT match (recompiled with incorrect source)
193+
assert!(
194+
output.contains(format!("Error: Creation code did not match").as_str()),
195+
);
196+
assert!(
197+
output.contains(format!("Error: Runtime code did not match").as_str()),
198+
);
199+
}
200+
147201
forgetest_async!(can_verify_bytecode_no_metadata, |prj, cmd| {
148202
test_verify_bytecode(
149203
prj,
@@ -296,6 +350,37 @@ forgetest_async!(can_ignore_runtime, |prj, cmd| {
296350
);
297351
});
298352

353+
// Test that verification fails when source code doesn't match deployed bytecode
354+
forgetest_async!(can_verify_bytecode_fails_on_source_mismatch, |prj, cmd| {
355+
let modified_source = r#"
356+
contract SystemConfig {
357+
uint256 public constant MODIFIED_VALUE = 999;
358+
359+
function someFunction() public pure returns (uint256) {
360+
return MODIFIED_VALUE;
361+
}
362+
}
363+
"#;
364+
365+
test_verify_bytecode_mismatch(
366+
prj,
367+
cmd,
368+
"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1",
369+
"SystemConfig",
370+
modified_source,
371+
Config {
372+
evm_version: EvmVersion::London,
373+
optimizer_runs: Some(999999),
374+
optimizer: Some(true),
375+
cbor_metadata: false,
376+
bytecode_hash: BytecodeHash::None,
377+
..Default::default()
378+
},
379+
"etherscan",
380+
"https://api.etherscan.io/v2/api?chainid=1",
381+
);
382+
});
383+
299384
// Test predeploy contracts
300385
// TODO: Add test utils for base such as basescan keys and alchemy keys.
301386
// WETH9 Predeploy

0 commit comments

Comments
 (0)