Skip to content

Commit

Permalink
improve foundry config parsing
Browse files Browse the repository at this point in the history
- support snake and kebab case
- add warning if version not available
- support solc config as path
  • Loading branch information
0xalpharush committed Oct 18, 2023
1 parent 76d911c commit b6a24dd
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 26 deletions.
47 changes: 33 additions & 14 deletions crytic_compile/crytic_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from solc_select.solc_select import (
install_artifacts,
installed_versions,
current_version,
artifact_path,
)
from crytic_compile.compilation_unit import CompilationUnit
Expand Down Expand Up @@ -86,6 +85,31 @@ def _extract_libraries(libraries_str: Optional[str]) -> Optional[Dict[str, int]]
return ret


def _configure_solc(solc_requested: str, offline: bool) -> str:
"""
Determine which solc binary to use based on the requested version or path (e.g. '0.8.0' or '/usr/bin/solc-0.8.0').
Args:
solc_requested (str): solc version or path
offline (bool): whether to allow network requests
Returns:
str: path to solc binary
"""
if Path(solc_requested).exists():
solc_path = Path(solc_requested)
else:
solc_version = solc_requested
if solc_requested in installed_versions():
solc_path = artifact_path(solc_requested)
else:
# Respect foundry offline option and skip installation.
if not offline:
install_artifacts([solc_version])
solc_path = artifact_path(solc_version)
return solc_path.absolute().as_posix()


# pylint: disable=too-many-instance-attributes
class CryticCompile:
"""
Expand Down Expand Up @@ -139,7 +163,7 @@ def __init__(self, target: Union[str, AbstractPlatform], **kwargs: str) -> None:
),
None,
)
# If no platform has been found or if it's a Solc we can't do anything
# If no platform has been found or if it's the Solc platform, we can't automatically compile.
if platform_wd and not isinstance(platform_wd, Solc):
platform_config = platform_wd.config(str(self._working_dir))
if platform_config:
Expand All @@ -148,18 +172,13 @@ def __init__(self, target: Union[str, AbstractPlatform], **kwargs: str) -> None:

if platform_config.remappings:
kwargs["solc_remaps"] = platform_config.remappings
if (
platform_config.solc_version
and platform_config.solc_version != current_version()[0]
):
solc_version = platform_config.solc_version
if solc_version in installed_versions():
kwargs["solc"] = str(artifact_path(solc_version).absolute())
else:
# Respect foundry offline option and don't install a missing solc version
if not platform_config.offline:
install_artifacts([solc_version])
kwargs["solc"] = str(artifact_path(solc_version).absolute())
if platform_config.solc_version is None:
message = f"Could not detect solc version from {platform_wd.NAME} config. Falling back to system version..."
LOGGER.warning(message)
else:
kwargs["solc"] = _configure_solc(
platform_config.solc_version, platform_config.offline
)
if platform_config.optimizer:
kwargs["solc_args"] += "--optimize"
if platform_config.optimizer_runs:
Expand Down
38 changes: 26 additions & 12 deletions crytic_compile/platform/foundry.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import os
import subprocess
from pathlib import Path
from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, List, Optional, Dict, TypeVar

import toml

from crytic_compile.platform.abstract_platform import AbstractPlatform, PlatformConfig
Expand All @@ -17,6 +18,8 @@
if TYPE_CHECKING:
from crytic_compile import CryticCompile

T = TypeVar("T")

LOGGER = logging.getLogger("CryticCompile")


Expand Down Expand Up @@ -135,26 +138,37 @@ def config(working_dir: str) -> Optional[PlatformConfig]:
foundry_toml = toml.loads(f.read())
default_profile = foundry_toml["profile"]["default"]

if "solc_version" in default_profile:
result.solc_version = default_profile["solc_version"]
def lookup_by_keys(keys: List[str], dictionary: Dict[str, T]) -> Optional[T]:
for key in keys:
if key in dictionary:
return dictionary[key]
return None

# Foundry supports snake and kebab case.
result.solc_version = lookup_by_keys(
["solc", "solc_version", "solc-version"], default_profile
)
via_ir = lookup_by_keys(["via_ir", "via-ir"], default_profile)
if via_ir:
result.via_ir = via_ir
result.allow_paths = lookup_by_keys(["allow_paths", "allow-paths"], default_profile)

if "offline" in default_profile:
result.offline = default_profile["offline"]
if "optimizer" in default_profile:
result.optimizer = default_profile["optimizer"]
else:
# Default to true
result.optimizer = True
if "optimizer_runs" in default_profile:
result.optimizer_runs = default_profile["optimizer_runs"]
else:
optimizer_runs = lookup_by_keys(["optimizer_runs", "optimizer-runs"], default_profile)
if optimizer_runs is None:
# Default to 200
result.optimizer_runs = 200
if "via_ir" in default_profile:
result.via_ir = default_profile["via_ir"]
if "allow_paths" in default_profile:
result.allow_paths = default_profile["allow_paths"]
if "evm_version" in default_profile:
result.evm_version = default_profile["evm_version"]
else:
result.optimizer_runs = optimizer_runs
evm_version = lookup_by_keys(["evm_version", "evm-version"], default_profile)
if evm_version is None:
result.evm_version = evm_version
else:
# Default to london
result.evm_version = "london"
Expand Down

0 comments on commit b6a24dd

Please sign in to comment.