@@ -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.
286322fn 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