-
Notifications
You must be signed in to change notification settings - Fork 93
Description
Currently, crytic-compile fails in hardhat 3 projects. One easy way to re-create this is to create two Hardhat starter projects (one in v2 and the other in v3).
Potential cause
On compilation, hardhat v2 produced one file under build-info with the "output" parameter. Hardhat v3 introduces a new way to generate build info with a different format.
-
Hardhat 2 produces a single artifacts/build-info/.json that mixed compiler input and output. Hardhat 3 keeps input (+ metadata) in solc-….json and writes the actual compiler output to a sibling solc-….output.json. The main file now declares _format: "hh3-sol-build-info-1".
-
In Hardhat 2 the top-level object had { _format: "hh-sol-build-info-1", id, solcVersion, input, output }. Version 3 removes output entirely, adds the hh3… format tag, and expects consumers to read the separate *.output.json
This leads to crytic-compile throwing the following error:
Traceback (most recent call last):
File "/root/.crytic/bin/crytic-compile", line 8, in <module>
sys.exit(main())
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/__main__.py", line 220, in main
compilations = compile_all(**vars(args))
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/crytic_compile.py", line 722, in compile_all
compilations.append(CryticCompile(target, **kwargs))
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/crytic_compile.py", line 211, in __init__
self._compile(**kwargs)
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/crytic_compile.py", line 633, in _compile
self._platform.compile(self, **kwargs)
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/platform/hardhat.py", line 184, in compile
hardhat_like_parsing(crytic_compile, self._target, build_directory, hardhat_working_dir)
File "/root/.crytic/lib/python3.10/site-packages/crytic_compile/platform/hardhat.py", line 72, in hardhat_like_parsing
targets_json = loaded_json["output"]
KeyError: 'output'
Potential remediation
- Read both build-info JSONs instead if we detect that the project is run using hardhat 3. Changes need to happen at the parser level.
crytic-compile/crytic_compile/platform/hardhat.py
Lines 62 to 112 in 46ab5fd
| for file in files: | |
| build_info = Path(build_directory, file) | |
| # The file here should always ends .json, but just in case use ife | |
| uniq_id = file if ".json" not in file else file[0:-5] | |
| compilation_unit = CompilationUnit(crytic_compile, uniq_id) | |
| with open(build_info, encoding="utf8") as file_desc: | |
| loaded_json = json.load(file_desc) | |
| targets_json = loaded_json["output"] | |
| version_from_config = loaded_json["solcVersion"] # TODO supper vyper | |
| input_json = loaded_json["input"] | |
| compiler = "solc" if input_json["language"] == "Solidity" else "vyper" | |
| # Foundry has the optimizer dict empty when the "optimizer" key is not set in foundry.toml | |
| optimized = input_json["settings"]["optimizer"].get("enabled", False) | |
| compilation_unit.compiler_version = CompilerVersion( | |
| compiler=compiler, version=version_from_config, optimized=optimized | |
| ) | |
| skip_filename = compilation_unit.compiler_version.version in [ | |
| f"0.4.{x}" for x in range(0, 10) | |
| ] | |
| if "sources" in targets_json: | |
| for path, info in targets_json["sources"].items(): | |
| if skip_filename: | |
| path = convert_filename( | |
| target, | |
| relative_to_short, | |
| crytic_compile, | |
| working_dir=working_dir, | |
| ) | |
| else: | |
| path = convert_filename( | |
| path, | |
| relative_to_short, | |
| crytic_compile, | |
| working_dir=working_dir, | |
| ) | |
| source_unit = compilation_unit.create_source_unit(path) | |
| source_unit.ast = info.get("ast", info.get("legacyAST")) | |
| if source_unit.ast is None: | |
| raise InvalidCompilation( | |
| f"AST not found for {path} in {build_info} directory" | |
| ) | |
| if "contracts" in targets_json: |
Am I missing anything? Otherwise I can take a stab at fixing this.