Skip to content

Feat: Add support for Foundry output ABI format#466

Closed
diyahir wants to merge 2 commits into
enviodev:mainfrom
diyahir:main
Closed

Feat: Add support for Foundry output ABI format#466
diyahir wants to merge 2 commits into
enviodev:mainfrom
diyahir:main

Conversation

@diyahir

@diyahir diyahir commented Mar 6, 2025

Copy link
Copy Markdown

This PR adds support for Foundry output ABI format, which places the ABI definition in an "abi" child field within the JSON file. Previously, the code would fail early when trying to parse these files, as it expected the ABI to be at the root level of the JSON.

Changes

  • Enhanced the ABI parsing logic in LocalImportArgs::parse_contract_abi to handle nested ABI structures
  • Added a two-step parsing approach:
    1. First attempt to parse the JSON directly as an ABI
    2. If that fails, try to parse it as a JSON object that might contain an "abi" field
  • Added comprehensive error messages to help users troubleshoot ABI parsing issues
  • Added test cases to verify both direct and nested ABI parsing works correctly

Test Coverage

Added two test cases to verify the functionality:

  • test_parse_contract_abi_direct: Tests parsing a standard ABI file
  • test_parse_contract_abi_nested: Tests parsing an ABI file with the "abi" field at the root level (Foundry format)

Also added test fixtures:

  • Added a sample Foundry-style ABI file (Contract3.json) with the ABI in an "abi" child field
  • Added a corresponding test configuration (nested-abi.yaml) to test the system config parsing

Foundry outputs have the json in an "abi" child which causes an early breaking of the code
@DZakh

DZakh commented Mar 7, 2025

Copy link
Copy Markdown
Member

Good morning. Thank you for your contribution! Really appreciated 🙏
A single comment and request is that we already have the logic for parsing ABI already set in the config. It would be nice to unify it with contract import you added, so the logic is not duplicated.

Here's the existing code:

pub fn from_file(
abi_file_path: &Option<String>,
project_paths: &ParsedProjectPaths,
) -> Result<Option<Self>> {
match &abi_file_path {
None => Ok(None),
Some(abi_file_path) => {
#[derive(Deserialize)]
#[serde(untagged)]
enum AbiOrNestedAbi {
Abi(ethers::abi::Abi),
NestedAbi { abi: ethers::abi::Abi },
}
let relative_path_buf = PathBuf::from(abi_file_path);
let path =
path_utils::get_config_path_relative_to_root(project_paths, relative_path_buf)
.context("Failed to get path to ABI relative to the root of the project")?;
let mut raw = fs::read_to_string(&path)
.context(format!("Failed to read ABI file at \"{}\"", abi_file_path))?;
// Abi files generated by the hardhat plugin can contain a nested abi field. This code to support that.
let typed = match serde_json::from_str::<AbiOrNestedAbi>(&raw).context(format!(
"Failed to decode ABI file at \"{}\"",
abi_file_path
))? {
AbiOrNestedAbi::Abi(abi) => abi,
AbiOrNestedAbi::NestedAbi { abi } => {
raw = serde_json::to_string(&abi)
.context("Failed serializing ABI from nested field")?;
abi
}
};
Ok(Some(Self {
path: Some(path),
raw,
typed,
}))
}
}

@diyahir

diyahir commented Mar 7, 2025

Copy link
Copy Markdown
Author

Updated

@DZakh

DZakh commented Mar 12, 2025

Copy link
Copy Markdown
Member

@diyahir, thank you for your contribution. I reimplemented your changes in another PR to fit it into the next release.

@DZakh DZakh closed this Mar 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants