Skip to content

Commit fe27372

Browse files
authored
Merge pull request #348 from crytic/foundry-multiple-compilation-units-mypy
support multiple compilation units for foundry (2)
2 parents a2662cb + f464090 commit fe27372

File tree

2 files changed

+119
-232
lines changed

2 files changed

+119
-232
lines changed

crytic_compile/platform/foundry.py

Lines changed: 9 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
"""
22
Truffle platform
33
"""
4-
import json
54
import logging
65
import os
76
import shutil
87
import subprocess
98
from pathlib import Path
10-
from typing import TYPE_CHECKING, List, Tuple, Optional
9+
from typing import TYPE_CHECKING, List
1110

12-
from crytic_compile.compilation_unit import CompilationUnit
13-
from crytic_compile.compiler.compiler import CompilerVersion
1411
from crytic_compile.platform.abstract_platform import AbstractPlatform
15-
from crytic_compile.platform.exceptions import InvalidCompilation
1612
from crytic_compile.platform.types import Type
17-
from crytic_compile.utils.naming import convert_filename
18-
from crytic_compile.utils.natspec import Natspec
13+
from crytic_compile.platform.hardhat import hardhat_like_parsing
1914
from crytic_compile.utils.subprocess import run
2015

2116
# Handle cycle
@@ -42,8 +37,6 @@ def compile(self, crytic_compile: "CryticCompile", **kwargs: str) -> None:
4237
crytic_compile (CryticCompile): CryticCompile object to populate
4338
**kwargs: optional arguments. Used: "foundry_ignore_compile", "foundry_out_directory"
4439
45-
Raises:
46-
InvalidCompilation: If foundry failed to run
4740
"""
4841

4942
ignore_compile = kwargs.get("foundry_ignore_compile", False) or kwargs.get(
@@ -61,14 +54,7 @@ def compile(self, crytic_compile: "CryticCompile", **kwargs: str) -> None:
6154
cmd = [
6255
"forge",
6356
"build",
64-
"--extra-output",
65-
"abi",
66-
"--extra-output",
67-
"userdoc",
68-
"--extra-output",
69-
"devdoc",
70-
"--extra-output",
71-
"evm.methodIdentifiers",
57+
"--build-info",
7258
"--force",
7359
]
7460

@@ -95,69 +81,14 @@ def compile(self, crytic_compile: "CryticCompile", **kwargs: str) -> None:
9581
if stderr:
9682
LOGGER.error(stderr)
9783

98-
filenames = Path(self._target, out_directory).rglob("*.json")
99-
100-
# foundry only support solc for now
101-
compiler = "solc"
102-
compilation_unit = CompilationUnit(crytic_compile, str(self._target))
103-
104-
for filename_txt in filenames:
105-
with open(filename_txt, encoding="utf8") as file_desc:
106-
target_loaded = json.load(file_desc)
107-
108-
userdoc = target_loaded.get("userdoc", {})
109-
devdoc = target_loaded.get("devdoc", {})
110-
natspec = Natspec(userdoc, devdoc)
111-
112-
if not "ast" in target_loaded:
113-
continue
114-
115-
filename_str = target_loaded["ast"]["absolutePath"]
116-
117-
try:
118-
filename = convert_filename(
119-
filename_str, lambda x: x, crytic_compile, working_dir=self._target
120-
)
121-
except InvalidCompilation as i:
122-
txt = str(i)
123-
txt += "\nSomething went wrong, please open an issue in https://github.com/crytic/crytic-compile"
124-
# pylint: disable=raise-missing-from
125-
raise InvalidCompilation(txt)
126-
127-
source_unit = compilation_unit.create_source_unit(filename)
128-
129-
source_unit.ast = target_loaded["ast"]
130-
131-
contract_name = filename_txt.parts[-1]
132-
contract_name = contract_name[: -len(".json")]
133-
134-
source_unit.natspec[contract_name] = natspec
135-
compilation_unit.filename_to_contracts[filename].add(contract_name)
136-
source_unit.contracts_names.add(contract_name)
137-
source_unit.abis[contract_name] = target_loaded["abi"]
138-
source_unit.bytecodes_init[contract_name] = target_loaded["bytecode"][
139-
"object"
140-
].replace("0x", "")
141-
source_unit.bytecodes_runtime[contract_name] = target_loaded["deployedBytecode"][
142-
"object"
143-
].replace("0x", "")
144-
source_unit.srcmaps_init[contract_name] = (
145-
target_loaded["bytecode"]["sourceMap"].split(";")
146-
if target_loaded["bytecode"].get("sourceMap")
147-
else []
148-
)
149-
source_unit.srcmaps_runtime[contract_name] = (
150-
target_loaded["deployedBytecode"]["sourceMap"].split(";")
151-
if target_loaded["deployedBytecode"].get("sourceMap")
152-
else []
153-
)
154-
155-
version, optimized, runs = _get_config_info(self._target)
156-
157-
compilation_unit.compiler_version = CompilerVersion(
158-
compiler=compiler, version=version, optimized=optimized, optimize_runs=runs
84+
build_directory = Path(
85+
self._target,
86+
out_directory,
87+
"build-info",
15988
)
16089

90+
hardhat_like_parsing(crytic_compile, self._target, build_directory, self._target)
91+
16192
def clean(self, **kwargs: str) -> None:
16293
"""Clean compilation artifacts
16394
@@ -214,65 +145,3 @@ def _guessed_tests(self) -> List[str]:
214145
List[str]: The guessed unit tests commands
215146
"""
216147
return ["forge test"]
217-
218-
219-
def _get_config_info(target: str) -> Tuple[str, Optional[bool], Optional[int]]:
220-
"""get the compiler version from solidity-files-cache.json
221-
222-
Args:
223-
target (str): path to the project directory
224-
225-
Returns:
226-
(str, str, str): compiler version, optimized, runs
227-
228-
Raises:
229-
InvalidCompilation: If cache/solidity-files-cache.json cannot be parsed
230-
"""
231-
config = Path(target, "cache", "solidity-files-cache.json")
232-
if not config.exists():
233-
raise InvalidCompilation(
234-
"Could not find the cache/solidity-files-cache.json file."
235-
+ "If you are using 'cache = true' in foundry's config file, please remove it."
236-
+ " Otherwise please open an issue in https://github.com/crytic/crytic-compile"
237-
)
238-
with open(config, "r", encoding="utf8") as config_f:
239-
config_dict = json.load(config_f)
240-
241-
version: Optional[str] = None
242-
optimizer: Optional[bool] = None
243-
runs: Optional[int] = None
244-
245-
if "files" in config_dict:
246-
items = list(config_dict["files"].values())
247-
# On the form
248-
# { ..
249-
# "artifacts": {
250-
# "CONTRACT_NAME": {
251-
# "0.8.X+commit...": "filename"}
252-
#
253-
if len(items) >= 1:
254-
item = items[0]
255-
if "artifacts" in item:
256-
items_artifact = list(item["artifacts"].values())
257-
if len(items_artifact) >= 1:
258-
item_version = items_artifact[0]
259-
version = list(item_version.keys())[0]
260-
assert version
261-
plus_position = version.find("+")
262-
if plus_position > 0:
263-
version = version[:plus_position]
264-
if (
265-
"solcConfig" in item
266-
and "settings" in item["solcConfig"]
267-
and "optimizer" in item["solcConfig"]["settings"]
268-
):
269-
optimizer = item["solcConfig"]["settings"]["optimizer"]["enabled"]
270-
runs = item["solcConfig"]["settings"]["optimizer"].get("runs", None)
271-
272-
if version is None:
273-
raise InvalidCompilation(
274-
"Something went wrong with cache/solidity-files-cache.json parsing"
275-
+ ". Please open an issue in https://github.com/crytic/crytic-compile"
276-
)
277-
278-
return version, optimizer, runs

0 commit comments

Comments
 (0)