Skip to content

Commit 1e0ea76

Browse files
committed
gnd: Support Hardhat/Foundry ABI artifact formats in codegen
Extract the ABI array from wrapper objects produced by Hardhat, Foundry, and Truffle. These tools output artifacts with the ABI nested inside an object (e.g., {"abi": [...], ...}) rather than as a raw array.
1 parent 13eeea1 commit 1e0ea76

File tree

1 file changed

+91
-2
lines changed

1 file changed

+91
-2
lines changed

gnd/src/commands/codegen.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,48 @@ fn generate_schema_types(
280280
Ok(true)
281281
}
282282

283+
/// Normalize ABI JSON to extract the actual ABI array from various artifact formats.
284+
///
285+
/// Supports:
286+
/// - Raw ABI array: `[{...}]`
287+
/// - Foundry/Hardhat format: `{"abi": [...], ...}`
288+
/// - Truffle format: `{"compilerOutput": {"abi": [...], ...}, ...}`
289+
fn normalize_abi_json(abi_str: &str) -> Result<serde_json::Value> {
290+
let value: serde_json::Value =
291+
serde_json::from_str(abi_str).context("Failed to parse ABI JSON")?;
292+
293+
// Case 1: Already an array - return as-is
294+
if value.is_array() {
295+
return Ok(value);
296+
}
297+
298+
// Case 2: Object with "abi" field (Foundry/Hardhat format)
299+
if let Some(abi) = value.get("abi") {
300+
if abi.is_array() {
301+
return Ok(abi.clone());
302+
}
303+
}
304+
305+
// Case 3: Object with "compilerOutput.abi" field (Truffle format)
306+
if let Some(compiler_output) = value.get("compilerOutput") {
307+
if let Some(abi) = compiler_output.get("abi") {
308+
if abi.is_array() {
309+
return Ok(abi.clone());
310+
}
311+
}
312+
}
313+
314+
Err(anyhow!(
315+
"Invalid ABI format: expected an array or an object with 'abi' field"
316+
))
317+
}
318+
283319
/// Preprocess ABI JSON to add default names for unnamed parameters.
284320
/// The ethabi crate requires all parameters to have names, but Solidity ABIs
285321
/// can have unnamed parameters. This function adds `param0`, `param1`, etc.
286322
fn preprocess_abi_json(abi_str: &str) -> Result<String> {
287-
let mut abi: serde_json::Value =
288-
serde_json::from_str(abi_str).context("Failed to parse ABI JSON")?;
323+
// First normalize to get the ABI array from various artifact formats
324+
let mut abi = normalize_abi_json(abi_str)?;
289325

290326
if let Some(items) = abi.as_array_mut() {
291327
for item in items {
@@ -1093,4 +1129,57 @@ dataSources:
10931129
"Contract should have static bind method"
10941130
);
10951131
}
1132+
1133+
#[test]
1134+
fn test_normalize_abi_json_raw_array() {
1135+
let raw_abi = r#"[{"type": "event", "name": "Transfer"}]"#;
1136+
let result = normalize_abi_json(raw_abi).unwrap();
1137+
assert!(result.is_array());
1138+
assert_eq!(result.as_array().unwrap().len(), 1);
1139+
}
1140+
1141+
#[test]
1142+
fn test_normalize_abi_json_hardhat_format() {
1143+
let hardhat_abi = r#"{
1144+
"_format": "hh-sol-artifact-1",
1145+
"contractName": "MyContract",
1146+
"abi": [{"type": "event", "name": "Transfer"}],
1147+
"bytecode": "0x..."
1148+
}"#;
1149+
let result = normalize_abi_json(hardhat_abi).unwrap();
1150+
assert!(result.is_array());
1151+
assert_eq!(result.as_array().unwrap().len(), 1);
1152+
assert_eq!(
1153+
result.as_array().unwrap()[0].get("name").unwrap(),
1154+
"Transfer"
1155+
);
1156+
}
1157+
1158+
#[test]
1159+
fn test_normalize_abi_json_truffle_format() {
1160+
let truffle_abi = r#"{
1161+
"contractName": "MyContract",
1162+
"compilerOutput": {
1163+
"abi": [{"type": "event", "name": "Transfer"}]
1164+
}
1165+
}"#;
1166+
let result = normalize_abi_json(truffle_abi).unwrap();
1167+
assert!(result.is_array());
1168+
assert_eq!(result.as_array().unwrap().len(), 1);
1169+
assert_eq!(
1170+
result.as_array().unwrap()[0].get("name").unwrap(),
1171+
"Transfer"
1172+
);
1173+
}
1174+
1175+
#[test]
1176+
fn test_normalize_abi_json_invalid_format() {
1177+
let invalid_abi = r#"{"contractName": "MyContract"}"#;
1178+
let result = normalize_abi_json(invalid_abi);
1179+
assert!(result.is_err());
1180+
assert!(result
1181+
.unwrap_err()
1182+
.to_string()
1183+
.contains("Invalid ABI format"));
1184+
}
10961185
}

0 commit comments

Comments
 (0)