Example #1
0
def compile_solfiles(files, proj_dir, solc_version=None, output_values=OUTPUT_VALUES):
    remappings = []
    node_modules_dir = find_node_modules_dir(proj_dir)

    if node_modules_dir is not None:
        zeppelin_path = os.path.abspath(os.path.join(
            node_modules_dir, 'zeppelin-solidity'))
        open_zeppelin_path = os.path.abspath(
            os.path.join(node_modules_dir, 'openzeppelin-solidity'))
        if os.path.isdir(zeppelin_path):
            remappings.append(f'zeppelin-solidity={zeppelin_path}')
        if os.path.isdir(open_zeppelin_path):
            remappings.append(f'openzeppelin-solidity={open_zeppelin_path}')

    if solc_version is None:
        solc_version = min(map(parse_version, files),
                           key=_version_to_tuple)

    binary = os.path.join(get_solc_folder(), f'solc-v{solc_version}')

    combined_json = ','.join(output_values)
    compiler_kwargs = {'import_remappings': remappings,
                       'allow_paths': proj_dir,
                       'source_files': files,
                       'solc_binary': binary,
                       'combined_json': combined_json}

    try:
        stdoutdata, _, _, _ = solc_wrapper(**compiler_kwargs)
        return _parse_compiler_output(stdoutdata)
    except SolcError as e:
        raise SolidityCompilationException(e, files)
Example #2
0
def _compile_combined_json(
    output_values: Optional[List],
    solc_binary: Union[str, Path, None],
    solc_version: Optional[Version],
    output_dir: Union[str, Path, None],
    overwrite: Optional[bool],
    allow_empty: Optional[bool],
    **kwargs: Any,
) -> Dict:

    if output_values is None:
        combined_json = _get_combined_json_outputs()
    else:
        combined_json = ",".join(output_values)

    if solc_binary is None:
        solc_binary = get_executable(solc_version)

    if output_dir:
        output_dir = Path(output_dir)
        if output_dir.is_file():
            raise FileExistsError(
                "`output_dir` must be as a directory, not a file")
        if output_dir.joinpath("combined.json").exists() and not overwrite:
            target_path = output_dir.joinpath("combined.json")
            raise FileExistsError(
                f"Target output file {target_path} already exists - use overwrite=True to overwrite"
            )

    stdoutdata, stderrdata, command, proc = wrapper.solc_wrapper(
        solc_binary=solc_binary,
        combined_json=combined_json,
        output_dir=output_dir,
        overwrite=overwrite,
        **kwargs,
    )

    if output_dir:
        output_path = Path(output_dir).joinpath("combined.json")
        if stdoutdata:
            output_path.parent.mkdir(parents=True, exist_ok=True)
            with output_path.open("w") as fp:
                fp.write(stdoutdata)
        else:
            with output_path.open() as fp:
                stdoutdata = fp.read()

    contracts = _parse_compiler_output(stdoutdata)

    if not contracts and not allow_empty:
        raise ContractsNotFound(
            command=command,
            return_code=proc.returncode,
            stdout_data=stdoutdata,
            stderr_data=stderrdata,
        )
    return contracts
Example #3
0
def _get_combined_json_outputs(solc_binary: Union[Path, str] = None) -> str:
    if solc_binary is None:
        solc_binary = get_executable()

    help_str = wrapper.solc_wrapper(solc_binary=solc_binary,
                                    help=True)[0].split("\n")
    combined_json_args = next(i for i in help_str
                              if i.startswith("  --combined-json"))
    return combined_json_args.split(" ")[-1]
Example #4
0
def compile_solfiles(files,
                     proj_dir,
                     solc_version=None,
                     output_values=OUTPUT_VALUES,
                     remappings=None):
    def complete_remapping(remapping):
        name, old_path = remapping.split('=')
        new_path = os.path.join(proj_dir, old_path)
        return f'{name}={new_path}'

    if remappings is None:
        remappings = []
    remappings = [complete_remapping(remapping) for remapping in remappings]
    node_modules_dir = find_node_modules_dir(proj_dir)
    if node_modules_dir is not None:
        zeppelin_path = os.path.abspath(
            os.path.join(node_modules_dir, 'zeppelin-solidity'))
        open_zeppelin_path = os.path.abspath(
            os.path.join(node_modules_dir, 'openzeppelin-solidity'))
        if os.path.isdir(zeppelin_path):
            remappings.append(f'zeppelin-solidity={zeppelin_path}')
        if os.path.isdir(open_zeppelin_path):
            remappings.append(f'openzeppelin-solidity={open_zeppelin_path}')

    if solc_version is None:
        if len(get_supported_solc_versions()) == 0:
            raise CompilerVersionNotSupported(
                "No compiler available. No connection to GitHub?")
        all_conditions = []
        for source in files:
            all_conditions.extend(_parse_conditions(source))
        solc_version = _find_version_for_conditions(all_conditions)

    try:
        install_solc(f'v{solc_version}')
    except (requests.exceptions.ConnectionError,
            subprocess.CalledProcessError):
        raise CompilerVersionNotSupported(
            f'Failed to install v{solc_version} compiler.')

    binary = _get_binary(solc_version)

    combined_json = ','.join(output_values)
    compiler_kwargs = {
        'import_remappings': remappings,
        'allow_paths': proj_dir,
        'source_files': files,
        'solc_binary': binary,
        'combined_json': combined_json
    }

    try:
        stdoutdata, _, _, _ = solc_wrapper(**compiler_kwargs)
        return _parse_compiler_output(stdoutdata)
    except SolcError as e:
        raise SolidityCompilationException(e, solc_version, files)
Example #5
0
def compile_solfiles(files,
                     proj_dir,
                     solc_version=None,
                     output_values=OUTPUT_VALUES,
                     remappings=None):
    def complete_remapping(remapping):
        name, old_path = remapping.split('=')
        new_path = os.path.join(proj_dir, old_path)
        return f'{name}={new_path}'

    if remappings is None:
        remappings = []
    remappings = [complete_remapping(remapping) for remapping in remappings]
    node_modules_dir = find_node_modules_dir(proj_dir)
    if node_modules_dir is not None:
        zeppelin_path = os.path.abspath(
            os.path.join(node_modules_dir, 'zeppelin-solidity'))
        open_zeppelin_path = os.path.abspath(
            os.path.join(node_modules_dir, 'openzeppelin-solidity'))
        if os.path.isdir(zeppelin_path):
            remappings.append(f'zeppelin-solidity={zeppelin_path}')
        if os.path.isdir(open_zeppelin_path):
            remappings.append(f'openzeppelin-solidity={open_zeppelin_path}')

    if solc_version is None:
        solc_version = max(map(parse_version, files))

    binary = _get_binary(solc_version)

    combined_json = ','.join(output_values)
    compiler_kwargs = {
        'import_remappings': remappings,
        'allow_paths': proj_dir,
        'source_files': files,
        'solc_binary': binary,
        'combined_json': combined_json
    }

    try:
        stdoutdata, _, _, _ = solc_wrapper(**compiler_kwargs)
        return _parse_compiler_output(stdoutdata)
    except SolcError as e:
        raise SolidityCompilationException(e, files)
Example #6
0
    def _compile_solfiles(self,
                          files,
                          solc_version=None,
                          output_values=utils.OUTPUT_VALUES):
        """Compiles the files using the solc compiler.
        """
        node_modules_dir = utils.find_node_modules_dir(self.project_root)

        remappings = []

        if node_modules_dir is not None:
            zeppelin_path = os.path.abspath(
                os.path.join(node_modules_dir, 'zeppelin-solidity'))
            open_zeppelin_path = os.path.abspath(
                os.path.join(node_modules_dir, 'openzeppelin-solidity'))
            if os.path.isdir(zeppelin_path):
                remappings.append(f'zeppelin-solidity={zeppelin_path}')
            if os.path.isdir(open_zeppelin_path):
                remappings.append(
                    f'openzeppelin-solidity={open_zeppelin_path}')

        if solc_version is None:
            solc_version = min(map(utils.parse_sol_version, files),
                               key=utils.version_to_tuple)

        binary = _get_binary(solc_version)

        combined_json = ','.join(output_values)
        compiler_kwargs = {
            'import_remappings': remappings,
            'allow_paths': self.project_root,
            'source_files': files,
            'solc_binary': binary,
            'combined_json': combined_json
        }

        try:
            stdoutdata, _, _, _ = solc_wrapper(**compiler_kwargs)
            return _parse_compiler_output(stdoutdata)
        except SolcError as e:
            raise utils.SolidityCompilationException(e, files)
Example #7
0
def link_code(
    unlinked_bytecode: str,
    libraries: Dict,
    solc_binary: Union[str, Path] = None,
    solc_version: Version = None,
) -> str:
    """
    Add library addresses into unlinked bytecode.

    Arguments
    ---------
    unlinked_bytecode : str
        Compiled bytecode containing one or more library placeholders.
    libraries : Dict
        Library addresses given as {"library name": "address"}
    solc_binary : str | Path, optional
        Path of the `solc` binary to use. If not given, the currently active
        version is used (as set by `solcx.set_solc_version`)
    solc_version: Version, optional
        `solc` version to use. If not given, the currently active version is used.
        Ignored if `solc_binary` is also given.

    Returns
    -------
    str
        Linked bytecode
    """
    if solc_binary is None:
        solc_binary = get_executable(solc_version)

    library_list = [f"{name}:{address}" for name, address in libraries.items()]

    stdoutdata = wrapper.solc_wrapper(solc_binary=solc_binary,
                                      stdin=unlinked_bytecode,
                                      link=True,
                                      libraries=library_list)[0]

    return stdoutdata.replace("Linking completed.", "").strip()
Example #8
0
def compile_standard(
    input_data: Dict,
    base_path: str = None,
    allow_paths: List = None,
    output_dir: str = None,
    overwrite: bool = False,
    solc_binary: Union[str, Path] = None,
    solc_version: Version = None,
    allow_empty: bool = False,
) -> Dict:
    """
    Compile Solidity contracts using the JSON-input-output interface.

    See the Solidity documentation for details on the expected JSON input and output
    formats.

    Arguments
    ---------
    input_data : Dict
        Compiler JSON input.
    base_path : Path | str, optional
        Use the given path as the root of the source tree instead of the root
        of the filesystem.
    allow_paths : List | Path | str, optional
        A path, or list of paths, to allow for imports.
    output_dir : str, optional
        Creates one file per component and contract/file at the specified directory.
    overwrite : bool, optional
        Overwrite existing files (used in combination with `output_dir`)
    solc_binary : str | Path, optional
        Path of the `solc` binary to use. If not given, the currently active
        version is used (as set by `solcx.set_solc_version`)
    solc_version: Version, optional
        `solc` version to use. If not given, the currently active version is used.
        Ignored if `solc_binary` is also given.
    allow_empty : bool, optional
        If `True`, do not raise when no compiled contracts are returned.

    Returns
    -------
    Dict
        Compiler JSON output.
    """
    if not input_data.get("sources") and not allow_empty:
        raise ContractsNotFound(
            "Input JSON does not contain any sources",
            stdin_data=json.dumps(input_data, sort_keys=True, indent=2),
        )

    if solc_binary is None:
        solc_binary = get_executable(solc_version)

    stdoutdata, stderrdata, command, proc = wrapper.solc_wrapper(
        solc_binary=solc_binary,
        stdin=json.dumps(input_data),
        standard_json=True,
        base_path=base_path,
        allow_paths=allow_paths,
        output_dir=output_dir,
        overwrite=overwrite,
    )

    compiler_output = json.loads(stdoutdata)
    if "errors" in compiler_output:
        has_errors = any(error["severity"] == "error"
                         for error in compiler_output["errors"])
        if has_errors:
            error_message = "\n".join(
                tuple(error["formattedMessage"]
                      for error in compiler_output["errors"]
                      if error["severity"] == "error"))
            raise SolcError(
                error_message,
                command=command,
                return_code=proc.returncode,
                stdin_data=json.dumps(input_data),
                stdout_data=stdoutdata,
                stderr_data=stderrdata,
                error_dict=compiler_output["errors"],
            )
    return compiler_output
Example #9
0
def _get_combined_json_outputs() -> str:
    help_str = wrapper.solc_wrapper(help=True)[0].split("\n")
    combined_json_args = next(i for i in help_str
                              if i.startswith("  --combined-json"))
    return combined_json_args.split(" ")[-1]