crytic_compile.platform.solc_standard_json

Handle compilation through the standard solc json format

  1"""
  2Handle compilation through the standard solc json format
  3"""
  4import json
  5import logging
  6import os
  7import shutil
  8import subprocess
  9from pathlib import Path
 10from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
 11
 12from crytic_compile.compilation_unit import CompilationUnit
 13from crytic_compile.compiler.compiler import CompilerVersion
 14from crytic_compile.platform.exceptions import InvalidCompilation
 15from crytic_compile.platform.solc import (
 16    Solc,
 17    get_version,
 18    is_optimized,
 19    relative_to_short,
 20)
 21from crytic_compile.platform.types import Type
 22from crytic_compile.utils.naming import convert_filename
 23
 24# Cycle dependency
 25from crytic_compile.utils.natspec import Natspec
 26
 27if TYPE_CHECKING:
 28    from crytic_compile import CryticCompile
 29
 30LOGGER = logging.getLogger("CryticCompile")
 31
 32
 33# pylint: disable=too-many-arguments
 34def standalone_compile(
 35    filenames: List[str],
 36    compilation_unit: CompilationUnit,
 37    working_dir: Optional[str] = None,
 38    remappings: Optional[List[str]] = None,
 39    evm_version: Optional[str] = None,
 40    via_ir: Optional[bool] = None,
 41) -> None:
 42    """
 43    Boilerplate function to run the the standardjson. compilation_unit.compiler_version must be set before calling this function
 44
 45    Example of usage:
 46        compilation_unit = CompilationUnit(crytic_compile, name_target)
 47        compilation_unit.compiler_version = CompilerVersion(
 48            compiler="solc", version=compiler_version, optimized=optimization_used, optimize_runs=optimize_runs
 49        )
 50        standalone_compile(filenames_to_compile, compilation_unit
 51
 52    Args:
 53        filenames (List[str]): list of the files to compile
 54        compilation_unit (CompilationUnit): compilation unit object to populate
 55        working_dir (Optional[str]): working directory
 56        remappings (Optional[List[str]]): list of solc remaps to use
 57        evm_version (Optional[str]): EVM version to target. None for default
 58        via_ir (Optional[bool]): whether to enable the viaIR compilation flag. None for unset
 59
 60    Returns:
 61
 62    """
 63
 64    if compilation_unit.compiler_version.version == "N/A":
 65        LOGGER.error("The compiler version of the compilation unit must be set")
 66        return
 67
 68    standard_json_dict: Dict = {}
 69    build_standard_json_default(standard_json_dict)
 70
 71    for filename in filenames:
 72        add_source_file(standard_json_dict, filename)
 73
 74    if remappings is not None:
 75        for remap in remappings:
 76            add_remapping(standard_json_dict, remap)
 77
 78    if evm_version is not None:
 79        add_evm_version(standard_json_dict, evm_version)
 80
 81    if via_ir is not None:
 82        add_via_ir(standard_json_dict, via_ir)
 83
 84    add_optimization(
 85        standard_json_dict,
 86        compilation_unit.compiler_version.optimized,
 87        compilation_unit.compiler_version.optimize_runs,
 88    )
 89
 90    targets_json = run_solc_standard_json(
 91        standard_json_dict,
 92        compiler_version=compilation_unit.compiler_version,
 93        solc_disable_warnings=False,
 94        working_dir=working_dir,
 95    )
 96
 97    parse_standard_json_output(targets_json, compilation_unit, solc_working_dir=working_dir)
 98
 99
100def build_standard_json_default(json_dict: Dict) -> None:
101    """
102    Populate the given json_dict with the default values for the solc standard json input
103    Only write values for which the keys are not existing
104
105    Args:
106        json_dict (Dict): dictionary used for the solc standard input
107
108    Returns:
109
110    """
111    if "language" not in json_dict:
112        json_dict["language"] = "Solidity"
113    if "sources" not in json_dict:
114        json_dict["sources"] = {}
115    if "settings" not in json_dict:
116        json_dict["settings"] = {}
117
118    if "remappings" not in json_dict["settings"]:
119        json_dict["settings"]["remappings"] = []
120    if "optimizer" not in json_dict["settings"]:
121        json_dict["settings"]["optimizer"] = {"enabled": False}
122    if "outputSelection" not in json_dict["settings"]:
123        json_dict["settings"]["outputSelection"] = {
124            "*": {
125                "*": [
126                    "abi",
127                    "metadata",
128                    "devdoc",
129                    "userdoc",
130                    "evm.bytecode",
131                    "evm.deployedBytecode",
132                ],
133                "": ["ast"],
134            }
135        }
136
137
138# pylint: disable=too-many-locals
139def run_solc_standard_json(
140    solc_input: Dict,
141    compiler_version: CompilerVersion,
142    solc_disable_warnings: bool = False,
143    working_dir: Optional[str] = None,
144) -> Dict:
145    """Run the solc standard json compilation.
146    Ensure that crytic_compile.compiler_version is set prior calling _run_solc
147
148    Args:
149        solc_input (Dict): standard json object
150        compiler_version (CompilerVersion): info regarding the compiler
151        solc_disable_warnings (bool): True to not print the solc warnings. Defaults to False.
152        working_dir (Optional[str], optional): Working directory to run solc. Defaults to None.
153
154    Raises:
155        InvalidCompilation: If the compilation failed
156
157    Returns:
158        Dict: Solc json output
159    """
160    working_dir_resolved = Path(working_dir if working_dir else ".").resolve()
161    cmd = [compiler_version.compiler, "--standard-json", "--allow-paths", str(working_dir_resolved)]
162    additional_kwargs: Dict = {"cwd": working_dir} if working_dir else {}
163
164    env = dict(os.environ)
165    if compiler_version.version:
166        env["SOLC_VERSION"] = compiler_version.version
167
168    stderr = ""
169    LOGGER.info(
170        "'%s' running",
171        " ".join(cmd),
172    )
173    try:
174        with subprocess.Popen(
175            cmd,
176            stdin=subprocess.PIPE,
177            stdout=subprocess.PIPE,
178            stderr=subprocess.PIPE,
179            env=env,
180            executable=shutil.which(cmd[0]),
181            **additional_kwargs,
182        ) as process:
183            stdout_b, stderr_b = process.communicate(json.dumps(solc_input).encode("utf-8"))
184            stdout, stderr = (
185                stdout_b.decode(),
186                stderr_b.decode(errors="backslashreplace"),
187            )  # convert bytestrings to unicode strings
188
189            solc_json_output = json.loads(stdout)
190
191            # Check for errors and raise them if any exist.
192            solc_errors = solc_json_output.get("errors", [])
193            if solc_errors:
194                solc_error_occurred = False
195                solc_exception_str = ""
196                for solc_error in solc_errors:
197                    if solc_error["severity"] != "warning":
198                        solc_error_occurred = True
199                    elif solc_disable_warnings:
200                        continue
201                    solc_exception_str += (
202                        f"{solc_error.get('type', 'UnknownExceptionType')}: "
203                        f"{solc_error.get('formattedMessage', 'N/A')}\n"
204                    )
205
206                if solc_error_occurred:
207                    raise InvalidCompilation(solc_exception_str)
208                if solc_exception_str:
209                    LOGGER.warning(solc_exception_str)
210
211            return solc_json_output
212
213    except OSError as error:
214        # pylint: disable=raise-missing-from
215        raise InvalidCompilation(error)
216
217    except json.decoder.JSONDecodeError:
218        # pylint: disable=raise-missing-from
219        raise InvalidCompilation(f"Invalid solc compilation {stderr}")
220
221
222def add_source_file(json_dict: Dict, file_path: str) -> None:
223    """
224    Add a path to the solc standard json input
225
226    Args:
227        json_dict (Dict): solc standard json input
228        file_path (str): file to add
229
230    Returns:
231
232    """
233    json_dict["sources"][file_path] = {"urls": [file_path]}
234
235
236def add_remapping(json_dict: Dict, remapping: str) -> None:
237    """
238    Add a remapping to the solc standard json input
239
240    Args:
241        json_dict (Dict): solc standard json input
242        remapping (str): remapping
243
244    Returns:
245
246    """
247    json_dict["settings"]["remappings"].append(remapping)
248
249
250def add_optimization(
251    json_dict: Dict, optimize: Optional[bool], optimize_runs: Optional[int]
252) -> None:
253    """
254    Add optimization settings to the solc standard json input
255
256    Args:
257        json_dict (Dict): solc standard json input
258        optimize (bool): true if optimization are enabled
259        optimize_runs (Optional[int]): number of optimize runs
260
261    Returns:
262
263    """
264    if optimize:
265        json_dict["settings"]["optimizer"] = {"enabled": True}
266        if optimize_runs:
267            json_dict["settings"]["optimizer"]["runs"] = optimize_runs
268        return
269    json_dict["settings"]["optimizer"] = {"enabled": False}
270
271
272def add_evm_version(json_dict: Dict, version: str) -> None:
273    """
274    Add the version of the EVM to compile for.
275
276    Can be one of the following values: homestead, tangerineWhistle,
277    spuriousDragon, byzantium, constantinople, petersburg, istanbul,
278    berlin, london or paris
279
280    Args:
281        json_dict (Dict): solc standard json input
282        version (str): the EVM version to target
283
284    Returns:
285
286    """
287    json_dict["settings"]["evmVersion"] = version
288
289
290def add_via_ir(json_dict: Dict, enabled: bool) -> None:
291    """
292    Enable or disable the "viaIR" compilation flag.
293
294    Args:
295        json_dict (Dict): solc standard json input
296        enabled (bool): whether viaIR is enabled
297
298    Returns:
299
300    """
301    json_dict["settings"]["viaIR"] = enabled
302
303
304def parse_standard_json_output(
305    targets_json: Dict, compilation_unit: CompilationUnit, solc_working_dir: Optional[str] = None
306) -> None:
307    """
308    Parse the targets_json output from solc, and populate compilation_unit accordingly
309
310
311    Args:
312        targets_json (Dict): output from solc
313        compilation_unit (CompilationUnit): compilation unit to populate
314        solc_working_dir (Optional[str]): working dir
315
316    Returns:
317
318    """
319
320    skip_filename = compilation_unit.compiler_version.version in [f"0.4.{x}" for x in range(0, 10)]
321
322    if "sources" in targets_json:
323        for path, info in targets_json["sources"].items():
324            if skip_filename:
325                path = convert_filename(
326                    path,
327                    relative_to_short,
328                    compilation_unit.crytic_compile,
329                    working_dir=solc_working_dir,
330                )
331            else:
332                path = convert_filename(
333                    path,
334                    relative_to_short,
335                    compilation_unit.crytic_compile,
336                    working_dir=solc_working_dir,
337                )
338            source_unit = compilation_unit.create_source_unit(path)
339
340            source_unit.ast = info.get("ast")
341
342    if "contracts" in targets_json:
343        for file_path, file_contracts in targets_json["contracts"].items():
344            for contract_name, info in file_contracts.items():
345                # for solc < 0.4.10 we cant retrieve the filename from the ast
346                if skip_filename:
347                    filename = convert_filename(
348                        file_path,
349                        relative_to_short,
350                        compilation_unit.crytic_compile,
351                        working_dir=solc_working_dir,
352                    )
353                else:
354                    filename = convert_filename(
355                        file_path,
356                        relative_to_short,
357                        compilation_unit.crytic_compile,
358                        working_dir=solc_working_dir,
359                    )
360
361                source_unit = compilation_unit.create_source_unit(filename)
362
363                source_unit.add_contract_name(contract_name)
364                compilation_unit.filename_to_contracts[filename].add(contract_name)
365                source_unit.abis[contract_name] = info["abi"]
366
367                userdoc = info.get("userdoc", {})
368                devdoc = info.get("devdoc", {})
369                natspec = Natspec(userdoc, devdoc)
370                source_unit.natspec[contract_name] = natspec
371
372                source_unit.bytecodes_init[contract_name] = info["evm"]["bytecode"]["object"]
373                source_unit.bytecodes_runtime[contract_name] = info["evm"]["deployedBytecode"][
374                    "object"
375                ]
376                source_unit.srcmaps_init[contract_name] = info["evm"]["bytecode"][
377                    "sourceMap"
378                ].split(";")
379                source_unit.srcmaps_runtime[contract_name] = info["evm"]["deployedBytecode"][
380                    "sourceMap"
381                ].split(";")
382
383
384# Inherits is_dependency/is_supported from Solc
385class SolcStandardJson(Solc):
386    """
387    Represent the Standard solc Json object
388    """
389
390    NAME = "Solc-json"
391    PROJECT_URL = "https://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description"
392    TYPE = Type.SOLC_STANDARD_JSON
393
394    def __init__(self, target: Union[str, dict] = None, **kwargs: str):
395        """Initializes an object which represents solc standard json
396
397        Args:
398            target (Union[str, dict], optional): A string path to a standard json, or a standard json. Defaults to None.
399            **kwargs: optional arguments.
400
401        Raises:
402            ValueError: If invalid json
403        """
404
405        super().__init__(str(target), **kwargs)
406
407        if target is None:
408            self._json: Dict = {}
409        elif isinstance(target, str):
410            if os.path.isfile(target):
411                with open(target, mode="r", encoding="utf-8") as target_file:
412                    self._json = json.load(target_file)
413            else:
414                self._json = json.loads(target)
415
416        elif isinstance(target, dict):
417            self._json = target
418        else:
419            raise ValueError("Invalid target for solc standard json input.")
420
421        build_standard_json_default(self._json)
422
423    def add_source_file(self, file_path: str) -> None:
424        """Append file
425
426        Args:
427            file_path (str): file to append
428        """
429        add_source_file(self._json, file_path)
430
431    def add_source_files(self, files_path: List[str]) -> None:
432        """Append files
433
434        Args:
435            files_path (List[str]): files to append
436        """
437        for file_path in files_path:
438            add_source_file(self._json, file_path)
439
440    def add_remapping(self, remapping: str) -> None:
441        """Append our remappings
442
443        Args:
444            remapping (str): remapping to add
445        """
446        add_remapping(self._json, remapping)
447
448    def to_dict(self) -> Dict:
449        """Patch in our desired output types
450
451        Returns:
452            Dict:
453        """
454        return self._json
455
456    # pylint: disable=too-many-locals
457    def compile(self, crytic_compile: "CryticCompile", **kwargs: Any) -> None:
458        """[summary]
459
460        Args:
461            crytic_compile (CryticCompile): Associated CryticCompile object
462            **kwargs: optional arguments. Used: "solc", "solc_disable_warnings", "solc_args", "solc_working_dir",
463                "solc_remaps", "solc_env"
464        """
465
466        solc: str = kwargs.get("solc", "solc")
467        solc_disable_warnings: bool = kwargs.get("solc_disable_warnings", False)
468        solc_arguments: str = kwargs.get("solc_args", "")
469
470        solc_remaps: Optional[Union[str, List[str]]] = kwargs.get("solc_remaps", None)
471        solc_working_dir: Optional[str] = kwargs.get("solc_working_dir", None)
472        solc_env: Optional[Dict] = kwargs.get("solc_env", None)
473
474        compilation_unit = CompilationUnit(crytic_compile, "standard_json")
475
476        compilation_unit.compiler_version = CompilerVersion(
477            compiler="solc",
478            version=get_version(solc, solc_env),
479            optimized=is_optimized(solc_arguments)
480            or self.to_dict().get("settings", {}).get("optimizer", {}).get("enabled", False),
481            optimize_runs=self.to_dict().get("settings", {}).get("optimizer", {}).get("runs", None),
482        )
483
484        add_optimization(
485            self._json,
486            compilation_unit.compiler_version.optimized,
487            compilation_unit.compiler_version.optimize_runs,
488        )
489
490        # Add all remappings
491        if solc_remaps:
492            if isinstance(solc_remaps, str):
493                solc_remaps = solc_remaps.split(" ")
494            for solc_remap in solc_remaps:
495                self.add_remapping(solc_remap)
496
497        # Invoke solc
498        targets_json = run_solc_standard_json(
499            self.to_dict(),
500            compilation_unit.compiler_version,
501            solc_disable_warnings=solc_disable_warnings,
502            working_dir=solc_working_dir,
503        )
504
505        parse_standard_json_output(
506            targets_json, compilation_unit, solc_working_dir=solc_working_dir
507        )
508
509    def _guessed_tests(self) -> List[str]:
510        """Guess the potential unit tests commands
511
512        Returns:
513            List[str]: The guessed unit tests commands
514        """
515        return []
LOGGER = <Logger CryticCompile (WARNING)>
def standalone_compile( filenames: List[str], compilation_unit: crytic_compile.compilation_unit.CompilationUnit, working_dir: Union[str, NoneType] = None, remappings: Union[List[str], NoneType] = None, evm_version: Union[str, NoneType] = None, via_ir: Union[bool, NoneType] = None) -> None:
35def standalone_compile(
36    filenames: List[str],
37    compilation_unit: CompilationUnit,
38    working_dir: Optional[str] = None,
39    remappings: Optional[List[str]] = None,
40    evm_version: Optional[str] = None,
41    via_ir: Optional[bool] = None,
42) -> None:
43    """
44    Boilerplate function to run the the standardjson. compilation_unit.compiler_version must be set before calling this function
45
46    Example of usage:
47        compilation_unit = CompilationUnit(crytic_compile, name_target)
48        compilation_unit.compiler_version = CompilerVersion(
49            compiler="solc", version=compiler_version, optimized=optimization_used, optimize_runs=optimize_runs
50        )
51        standalone_compile(filenames_to_compile, compilation_unit
52
53    Args:
54        filenames (List[str]): list of the files to compile
55        compilation_unit (CompilationUnit): compilation unit object to populate
56        working_dir (Optional[str]): working directory
57        remappings (Optional[List[str]]): list of solc remaps to use
58        evm_version (Optional[str]): EVM version to target. None for default
59        via_ir (Optional[bool]): whether to enable the viaIR compilation flag. None for unset
60
61    Returns:
62
63    """
64
65    if compilation_unit.compiler_version.version == "N/A":
66        LOGGER.error("The compiler version of the compilation unit must be set")
67        return
68
69    standard_json_dict: Dict = {}
70    build_standard_json_default(standard_json_dict)
71
72    for filename in filenames:
73        add_source_file(standard_json_dict, filename)
74
75    if remappings is not None:
76        for remap in remappings:
77            add_remapping(standard_json_dict, remap)
78
79    if evm_version is not None:
80        add_evm_version(standard_json_dict, evm_version)
81
82    if via_ir is not None:
83        add_via_ir(standard_json_dict, via_ir)
84
85    add_optimization(
86        standard_json_dict,
87        compilation_unit.compiler_version.optimized,
88        compilation_unit.compiler_version.optimize_runs,
89    )
90
91    targets_json = run_solc_standard_json(
92        standard_json_dict,
93        compiler_version=compilation_unit.compiler_version,
94        solc_disable_warnings=False,
95        working_dir=working_dir,
96    )
97
98    parse_standard_json_output(targets_json, compilation_unit, solc_working_dir=working_dir)

Boilerplate function to run the the standardjson. compilation_unit.compiler_version must be set before calling this function

Example of usage: compilation_unit = CompilationUnit(crytic_compile, name_target) compilation_unit.compiler_version = CompilerVersion( compiler="solc", version=compiler_version, optimized=optimization_used, optimize_runs=optimize_runs ) standalone_compile(filenames_to_compile, compilation_unit

Args: filenames (List[str]): list of the files to compile compilation_unit (CompilationUnit): compilation unit object to populate working_dir (Optional[str]): working directory remappings (Optional[List[str]]): list of solc remaps to use evm_version (Optional[str]): EVM version to target. None for default via_ir (Optional[bool]): whether to enable the viaIR compilation flag. None for unset

Returns:

def build_standard_json_default(json_dict: Dict) -> None:
101def build_standard_json_default(json_dict: Dict) -> None:
102    """
103    Populate the given json_dict with the default values for the solc standard json input
104    Only write values for which the keys are not existing
105
106    Args:
107        json_dict (Dict): dictionary used for the solc standard input
108
109    Returns:
110
111    """
112    if "language" not in json_dict:
113        json_dict["language"] = "Solidity"
114    if "sources" not in json_dict:
115        json_dict["sources"] = {}
116    if "settings" not in json_dict:
117        json_dict["settings"] = {}
118
119    if "remappings" not in json_dict["settings"]:
120        json_dict["settings"]["remappings"] = []
121    if "optimizer" not in json_dict["settings"]:
122        json_dict["settings"]["optimizer"] = {"enabled": False}
123    if "outputSelection" not in json_dict["settings"]:
124        json_dict["settings"]["outputSelection"] = {
125            "*": {
126                "*": [
127                    "abi",
128                    "metadata",
129                    "devdoc",
130                    "userdoc",
131                    "evm.bytecode",
132                    "evm.deployedBytecode",
133                ],
134                "": ["ast"],
135            }
136        }

Populate the given json_dict with the default values for the solc standard json input Only write values for which the keys are not existing

Args: json_dict (Dict): dictionary used for the solc standard input

Returns:

def run_solc_standard_json( solc_input: Dict, compiler_version: crytic_compile.compiler.compiler.CompilerVersion, solc_disable_warnings: bool = False, working_dir: Union[str, NoneType] = None) -> Dict:
140def run_solc_standard_json(
141    solc_input: Dict,
142    compiler_version: CompilerVersion,
143    solc_disable_warnings: bool = False,
144    working_dir: Optional[str] = None,
145) -> Dict:
146    """Run the solc standard json compilation.
147    Ensure that crytic_compile.compiler_version is set prior calling _run_solc
148
149    Args:
150        solc_input (Dict): standard json object
151        compiler_version (CompilerVersion): info regarding the compiler
152        solc_disable_warnings (bool): True to not print the solc warnings. Defaults to False.
153        working_dir (Optional[str], optional): Working directory to run solc. Defaults to None.
154
155    Raises:
156        InvalidCompilation: If the compilation failed
157
158    Returns:
159        Dict: Solc json output
160    """
161    working_dir_resolved = Path(working_dir if working_dir else ".").resolve()
162    cmd = [compiler_version.compiler, "--standard-json", "--allow-paths", str(working_dir_resolved)]
163    additional_kwargs: Dict = {"cwd": working_dir} if working_dir else {}
164
165    env = dict(os.environ)
166    if compiler_version.version:
167        env["SOLC_VERSION"] = compiler_version.version
168
169    stderr = ""
170    LOGGER.info(
171        "'%s' running",
172        " ".join(cmd),
173    )
174    try:
175        with subprocess.Popen(
176            cmd,
177            stdin=subprocess.PIPE,
178            stdout=subprocess.PIPE,
179            stderr=subprocess.PIPE,
180            env=env,
181            executable=shutil.which(cmd[0]),
182            **additional_kwargs,
183        ) as process:
184            stdout_b, stderr_b = process.communicate(json.dumps(solc_input).encode("utf-8"))
185            stdout, stderr = (
186                stdout_b.decode(),
187                stderr_b.decode(errors="backslashreplace"),
188            )  # convert bytestrings to unicode strings
189
190            solc_json_output = json.loads(stdout)
191
192            # Check for errors and raise them if any exist.
193            solc_errors = solc_json_output.get("errors", [])
194            if solc_errors:
195                solc_error_occurred = False
196                solc_exception_str = ""
197                for solc_error in solc_errors:
198                    if solc_error["severity"] != "warning":
199                        solc_error_occurred = True
200                    elif solc_disable_warnings:
201                        continue
202                    solc_exception_str += (
203                        f"{solc_error.get('type', 'UnknownExceptionType')}: "
204                        f"{solc_error.get('formattedMessage', 'N/A')}\n"
205                    )
206
207                if solc_error_occurred:
208                    raise InvalidCompilation(solc_exception_str)
209                if solc_exception_str:
210                    LOGGER.warning(solc_exception_str)
211
212            return solc_json_output
213
214    except OSError as error:
215        # pylint: disable=raise-missing-from
216        raise InvalidCompilation(error)
217
218    except json.decoder.JSONDecodeError:
219        # pylint: disable=raise-missing-from
220        raise InvalidCompilation(f"Invalid solc compilation {stderr}")

Run the solc standard json compilation. Ensure that crytic_compile.compiler_version is set prior calling _run_solc

Args: solc_input (Dict): standard json object compiler_version (CompilerVersion): info regarding the compiler solc_disable_warnings (bool): True to not print the solc warnings. Defaults to False. working_dir (Optional[str], optional): Working directory to run solc. Defaults to None.

Raises: InvalidCompilation: If the compilation failed

Returns: Dict: Solc json output

def add_source_file(json_dict: Dict, file_path: str) -> None:
223def add_source_file(json_dict: Dict, file_path: str) -> None:
224    """
225    Add a path to the solc standard json input
226
227    Args:
228        json_dict (Dict): solc standard json input
229        file_path (str): file to add
230
231    Returns:
232
233    """
234    json_dict["sources"][file_path] = {"urls": [file_path]}

Add a path to the solc standard json input

Args: json_dict (Dict): solc standard json input file_path (str): file to add

Returns:

def add_remapping(json_dict: Dict, remapping: str) -> None:
237def add_remapping(json_dict: Dict, remapping: str) -> None:
238    """
239    Add a remapping to the solc standard json input
240
241    Args:
242        json_dict (Dict): solc standard json input
243        remapping (str): remapping
244
245    Returns:
246
247    """
248    json_dict["settings"]["remappings"].append(remapping)

Add a remapping to the solc standard json input

Args: json_dict (Dict): solc standard json input remapping (str): remapping

Returns:

def add_optimization( json_dict: Dict, optimize: Union[bool, NoneType], optimize_runs: Union[int, NoneType]) -> None:
251def add_optimization(
252    json_dict: Dict, optimize: Optional[bool], optimize_runs: Optional[int]
253) -> None:
254    """
255    Add optimization settings to the solc standard json input
256
257    Args:
258        json_dict (Dict): solc standard json input
259        optimize (bool): true if optimization are enabled
260        optimize_runs (Optional[int]): number of optimize runs
261
262    Returns:
263
264    """
265    if optimize:
266        json_dict["settings"]["optimizer"] = {"enabled": True}
267        if optimize_runs:
268            json_dict["settings"]["optimizer"]["runs"] = optimize_runs
269        return
270    json_dict["settings"]["optimizer"] = {"enabled": False}

Add optimization settings to the solc standard json input

Args: json_dict (Dict): solc standard json input optimize (bool): true if optimization are enabled optimize_runs (Optional[int]): number of optimize runs

Returns:

def add_evm_version(json_dict: Dict, version: str) -> None:
273def add_evm_version(json_dict: Dict, version: str) -> None:
274    """
275    Add the version of the EVM to compile for.
276
277    Can be one of the following values: homestead, tangerineWhistle,
278    spuriousDragon, byzantium, constantinople, petersburg, istanbul,
279    berlin, london or paris
280
281    Args:
282        json_dict (Dict): solc standard json input
283        version (str): the EVM version to target
284
285    Returns:
286
287    """
288    json_dict["settings"]["evmVersion"] = version

Add the version of the EVM to compile for.

Can be one of the following values: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul, berlin, london or paris

Args: json_dict (Dict): solc standard json input version (str): the EVM version to target

Returns:

def add_via_ir(json_dict: Dict, enabled: bool) -> None:
291def add_via_ir(json_dict: Dict, enabled: bool) -> None:
292    """
293    Enable or disable the "viaIR" compilation flag.
294
295    Args:
296        json_dict (Dict): solc standard json input
297        enabled (bool): whether viaIR is enabled
298
299    Returns:
300
301    """
302    json_dict["settings"]["viaIR"] = enabled

Enable or disable the "viaIR" compilation flag.

Args: json_dict (Dict): solc standard json input enabled (bool): whether viaIR is enabled

Returns:

def parse_standard_json_output( targets_json: Dict, compilation_unit: crytic_compile.compilation_unit.CompilationUnit, solc_working_dir: Union[str, NoneType] = None) -> None:
305def parse_standard_json_output(
306    targets_json: Dict, compilation_unit: CompilationUnit, solc_working_dir: Optional[str] = None
307) -> None:
308    """
309    Parse the targets_json output from solc, and populate compilation_unit accordingly
310
311
312    Args:
313        targets_json (Dict): output from solc
314        compilation_unit (CompilationUnit): compilation unit to populate
315        solc_working_dir (Optional[str]): working dir
316
317    Returns:
318
319    """
320
321    skip_filename = compilation_unit.compiler_version.version in [f"0.4.{x}" for x in range(0, 10)]
322
323    if "sources" in targets_json:
324        for path, info in targets_json["sources"].items():
325            if skip_filename:
326                path = convert_filename(
327                    path,
328                    relative_to_short,
329                    compilation_unit.crytic_compile,
330                    working_dir=solc_working_dir,
331                )
332            else:
333                path = convert_filename(
334                    path,
335                    relative_to_short,
336                    compilation_unit.crytic_compile,
337                    working_dir=solc_working_dir,
338                )
339            source_unit = compilation_unit.create_source_unit(path)
340
341            source_unit.ast = info.get("ast")
342
343    if "contracts" in targets_json:
344        for file_path, file_contracts in targets_json["contracts"].items():
345            for contract_name, info in file_contracts.items():
346                # for solc < 0.4.10 we cant retrieve the filename from the ast
347                if skip_filename:
348                    filename = convert_filename(
349                        file_path,
350                        relative_to_short,
351                        compilation_unit.crytic_compile,
352                        working_dir=solc_working_dir,
353                    )
354                else:
355                    filename = convert_filename(
356                        file_path,
357                        relative_to_short,
358                        compilation_unit.crytic_compile,
359                        working_dir=solc_working_dir,
360                    )
361
362                source_unit = compilation_unit.create_source_unit(filename)
363
364                source_unit.add_contract_name(contract_name)
365                compilation_unit.filename_to_contracts[filename].add(contract_name)
366                source_unit.abis[contract_name] = info["abi"]
367
368                userdoc = info.get("userdoc", {})
369                devdoc = info.get("devdoc", {})
370                natspec = Natspec(userdoc, devdoc)
371                source_unit.natspec[contract_name] = natspec
372
373                source_unit.bytecodes_init[contract_name] = info["evm"]["bytecode"]["object"]
374                source_unit.bytecodes_runtime[contract_name] = info["evm"]["deployedBytecode"][
375                    "object"
376                ]
377                source_unit.srcmaps_init[contract_name] = info["evm"]["bytecode"][
378                    "sourceMap"
379                ].split(";")
380                source_unit.srcmaps_runtime[contract_name] = info["evm"]["deployedBytecode"][
381                    "sourceMap"
382                ].split(";")

Parse the targets_json output from solc, and populate compilation_unit accordingly

Args: targets_json (Dict): output from solc compilation_unit (CompilationUnit): compilation unit to populate solc_working_dir (Optional[str]): working dir

Returns:

class SolcStandardJson(crytic_compile.platform.solc.Solc):
386class SolcStandardJson(Solc):
387    """
388    Represent the Standard solc Json object
389    """
390
391    NAME = "Solc-json"
392    PROJECT_URL = "https://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description"
393    TYPE = Type.SOLC_STANDARD_JSON
394
395    def __init__(self, target: Union[str, dict] = None, **kwargs: str):
396        """Initializes an object which represents solc standard json
397
398        Args:
399            target (Union[str, dict], optional): A string path to a standard json, or a standard json. Defaults to None.
400            **kwargs: optional arguments.
401
402        Raises:
403            ValueError: If invalid json
404        """
405
406        super().__init__(str(target), **kwargs)
407
408        if target is None:
409            self._json: Dict = {}
410        elif isinstance(target, str):
411            if os.path.isfile(target):
412                with open(target, mode="r", encoding="utf-8") as target_file:
413                    self._json = json.load(target_file)
414            else:
415                self._json = json.loads(target)
416
417        elif isinstance(target, dict):
418            self._json = target
419        else:
420            raise ValueError("Invalid target for solc standard json input.")
421
422        build_standard_json_default(self._json)
423
424    def add_source_file(self, file_path: str) -> None:
425        """Append file
426
427        Args:
428            file_path (str): file to append
429        """
430        add_source_file(self._json, file_path)
431
432    def add_source_files(self, files_path: List[str]) -> None:
433        """Append files
434
435        Args:
436            files_path (List[str]): files to append
437        """
438        for file_path in files_path:
439            add_source_file(self._json, file_path)
440
441    def add_remapping(self, remapping: str) -> None:
442        """Append our remappings
443
444        Args:
445            remapping (str): remapping to add
446        """
447        add_remapping(self._json, remapping)
448
449    def to_dict(self) -> Dict:
450        """Patch in our desired output types
451
452        Returns:
453            Dict:
454        """
455        return self._json
456
457    # pylint: disable=too-many-locals
458    def compile(self, crytic_compile: "CryticCompile", **kwargs: Any) -> None:
459        """[summary]
460
461        Args:
462            crytic_compile (CryticCompile): Associated CryticCompile object
463            **kwargs: optional arguments. Used: "solc", "solc_disable_warnings", "solc_args", "solc_working_dir",
464                "solc_remaps", "solc_env"
465        """
466
467        solc: str = kwargs.get("solc", "solc")
468        solc_disable_warnings: bool = kwargs.get("solc_disable_warnings", False)
469        solc_arguments: str = kwargs.get("solc_args", "")
470
471        solc_remaps: Optional[Union[str, List[str]]] = kwargs.get("solc_remaps", None)
472        solc_working_dir: Optional[str] = kwargs.get("solc_working_dir", None)
473        solc_env: Optional[Dict] = kwargs.get("solc_env", None)
474
475        compilation_unit = CompilationUnit(crytic_compile, "standard_json")
476
477        compilation_unit.compiler_version = CompilerVersion(
478            compiler="solc",
479            version=get_version(solc, solc_env),
480            optimized=is_optimized(solc_arguments)
481            or self.to_dict().get("settings", {}).get("optimizer", {}).get("enabled", False),
482            optimize_runs=self.to_dict().get("settings", {}).get("optimizer", {}).get("runs", None),
483        )
484
485        add_optimization(
486            self._json,
487            compilation_unit.compiler_version.optimized,
488            compilation_unit.compiler_version.optimize_runs,
489        )
490
491        # Add all remappings
492        if solc_remaps:
493            if isinstance(solc_remaps, str):
494                solc_remaps = solc_remaps.split(" ")
495            for solc_remap in solc_remaps:
496                self.add_remapping(solc_remap)
497
498        # Invoke solc
499        targets_json = run_solc_standard_json(
500            self.to_dict(),
501            compilation_unit.compiler_version,
502            solc_disable_warnings=solc_disable_warnings,
503            working_dir=solc_working_dir,
504        )
505
506        parse_standard_json_output(
507            targets_json, compilation_unit, solc_working_dir=solc_working_dir
508        )
509
510    def _guessed_tests(self) -> List[str]:
511        """Guess the potential unit tests commands
512
513        Returns:
514            List[str]: The guessed unit tests commands
515        """
516        return []

Represent the Standard solc Json object

SolcStandardJson(target: Union[str, dict] = None, **kwargs: str)
395    def __init__(self, target: Union[str, dict] = None, **kwargs: str):
396        """Initializes an object which represents solc standard json
397
398        Args:
399            target (Union[str, dict], optional): A string path to a standard json, or a standard json. Defaults to None.
400            **kwargs: optional arguments.
401
402        Raises:
403            ValueError: If invalid json
404        """
405
406        super().__init__(str(target), **kwargs)
407
408        if target is None:
409            self._json: Dict = {}
410        elif isinstance(target, str):
411            if os.path.isfile(target):
412                with open(target, mode="r", encoding="utf-8") as target_file:
413                    self._json = json.load(target_file)
414            else:
415                self._json = json.loads(target)
416
417        elif isinstance(target, dict):
418            self._json = target
419        else:
420            raise ValueError("Invalid target for solc standard json input.")
421
422        build_standard_json_default(self._json)

Initializes an object which represents solc standard json

Args: target (Union[str, dict], optional): A string path to a standard json, or a standard json. Defaults to None. **kwargs: optional arguments.

Raises: ValueError: If invalid json

NAME: str = 'Solc-json'
PROJECT_URL: str = 'https://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description'
TYPE: crytic_compile.platform.types.Type = <Type.SOLC_STANDARD_JSON: 10>
def add_source_file(self, file_path: str) -> None:
424    def add_source_file(self, file_path: str) -> None:
425        """Append file
426
427        Args:
428            file_path (str): file to append
429        """
430        add_source_file(self._json, file_path)

Append file

Args: file_path (str): file to append

def add_source_files(self, files_path: List[str]) -> None:
432    def add_source_files(self, files_path: List[str]) -> None:
433        """Append files
434
435        Args:
436            files_path (List[str]): files to append
437        """
438        for file_path in files_path:
439            add_source_file(self._json, file_path)

Append files

Args: files_path (List[str]): files to append

def add_remapping(self, remapping: str) -> None:
441    def add_remapping(self, remapping: str) -> None:
442        """Append our remappings
443
444        Args:
445            remapping (str): remapping to add
446        """
447        add_remapping(self._json, remapping)

Append our remappings

Args: remapping (str): remapping to add

def to_dict(self) -> Dict:
449    def to_dict(self) -> Dict:
450        """Patch in our desired output types
451
452        Returns:
453            Dict:
454        """
455        return self._json

Patch in our desired output types

Returns: Dict:

def compile( self, crytic_compile: crytic_compile.crytic_compile.CryticCompile, **kwargs: Any) -> None:
458    def compile(self, crytic_compile: "CryticCompile", **kwargs: Any) -> None:
459        """[summary]
460
461        Args:
462            crytic_compile (CryticCompile): Associated CryticCompile object
463            **kwargs: optional arguments. Used: "solc", "solc_disable_warnings", "solc_args", "solc_working_dir",
464                "solc_remaps", "solc_env"
465        """
466
467        solc: str = kwargs.get("solc", "solc")
468        solc_disable_warnings: bool = kwargs.get("solc_disable_warnings", False)
469        solc_arguments: str = kwargs.get("solc_args", "")
470
471        solc_remaps: Optional[Union[str, List[str]]] = kwargs.get("solc_remaps", None)
472        solc_working_dir: Optional[str] = kwargs.get("solc_working_dir", None)
473        solc_env: Optional[Dict] = kwargs.get("solc_env", None)
474
475        compilation_unit = CompilationUnit(crytic_compile, "standard_json")
476
477        compilation_unit.compiler_version = CompilerVersion(
478            compiler="solc",
479            version=get_version(solc, solc_env),
480            optimized=is_optimized(solc_arguments)
481            or self.to_dict().get("settings", {}).get("optimizer", {}).get("enabled", False),
482            optimize_runs=self.to_dict().get("settings", {}).get("optimizer", {}).get("runs", None),
483        )
484
485        add_optimization(
486            self._json,
487            compilation_unit.compiler_version.optimized,
488            compilation_unit.compiler_version.optimize_runs,
489        )
490
491        # Add all remappings
492        if solc_remaps:
493            if isinstance(solc_remaps, str):
494                solc_remaps = solc_remaps.split(" ")
495            for solc_remap in solc_remaps:
496                self.add_remapping(solc_remap)
497
498        # Invoke solc
499        targets_json = run_solc_standard_json(
500            self.to_dict(),
501            compilation_unit.compiler_version,
502            solc_disable_warnings=solc_disable_warnings,
503            working_dir=solc_working_dir,
504        )
505
506        parse_standard_json_output(
507            targets_json, compilation_unit, solc_working_dir=solc_working_dir
508        )

[summary]

Args: crytic_compile (CryticCompile): Associated CryticCompile object **kwargs: optional arguments. Used: "solc", "solc_disable_warnings", "solc_args", "solc_working_dir", "solc_remaps", "solc_env"