Skip to content

Commit 8c24df2

Browse files
authored
Merge branch 'dev' into implementation_address
2 parents 9c086fc + ee04ee3 commit 8c24df2

File tree

19 files changed

+576
-157
lines changed

19 files changed

+576
-157
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
fail-fast: false
2323
matrix:
2424
os: ["ubuntu-latest", "windows-2022"]
25-
type: ["brownie", "buidler", "dapp", "embark", "hardhat", "solc", "truffle", "waffle", "foundry", "standard"]
25+
type: ["brownie", "buidler", "dapp", "embark", "hardhat", "solc", "truffle", "waffle", "foundry", "standard", "vyper"]
2626
exclude:
2727
# Currently broken, tries to pull git:// which is blocked by GH
2828
- type: embark

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ jobs:
4545
path: dist/
4646

4747
- name: publish
48-
uses: pypa/[email protected].8
48+
uses: pypa/[email protected].10
4949

5050
- name: sign
51-
uses: sigstore/gh-action-sigstore-python@v2.0.0
51+
uses: sigstore/gh-action-sigstore-python@v2.1.0
5252
with:
5353
inputs: ./dist/*.tar.gz ./dist/*.whl
5454
release-signing-artifacts: true

crytic_compile/crytic_compile.py

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@
1414
from pathlib import Path
1515
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, Union
1616

17+
from solc_select.solc_select import (
18+
install_artifacts,
19+
installed_versions,
20+
current_version,
21+
artifact_path,
22+
)
1723
from crytic_compile.compilation_unit import CompilationUnit
18-
from crytic_compile.platform import all_platforms, solc_standard_json
24+
from crytic_compile.platform import all_platforms
25+
from crytic_compile.platform.solc_standard_json import SolcStandardJson
26+
from crytic_compile.platform.vyper import VyperStandardJson
1927
from crytic_compile.platform.abstract_platform import AbstractPlatform
2028
from crytic_compile.platform.all_export import PLATFORMS_EXPORT
2129
from crytic_compile.platform.solc import Solc
@@ -84,6 +92,7 @@ class CryticCompile:
8492
Main class.
8593
"""
8694

95+
# pylint: disable=too-many-branches
8796
def __init__(self, target: Union[str, AbstractPlatform], **kwargs: str) -> None:
8897
"""See https://github.com/crytic/crytic-compile/wiki/Configuration
8998
Target is usually a file or a project directory. It can be an AbstractPlatform
@@ -114,8 +123,55 @@ def __init__(self, target: Union[str, AbstractPlatform], **kwargs: str) -> None:
114123

115124
self._working_dir = Path.cwd()
116125

126+
# pylint: disable=too-many-nested-blocks
117127
if isinstance(target, str):
118128
platform = self._init_platform(target, **kwargs)
129+
# If the platform is Solc it means we are trying to compile a single
130+
# we try to see if we are in a known compilation framework to retrieve
131+
# information like remappings and solc version
132+
if isinstance(platform, Solc):
133+
# Try to get the platform of the current working directory
134+
platform_wd = next(
135+
(
136+
p(target)
137+
for p in get_platforms()
138+
if p.is_supported(str(self._working_dir), **kwargs)
139+
),
140+
None,
141+
)
142+
# If no platform has been found or if it's a Solc we can't do anything
143+
if platform_wd and not isinstance(platform_wd, Solc):
144+
platform_config = platform_wd.config(str(self._working_dir))
145+
if platform_config:
146+
kwargs["solc_args"] = ""
147+
kwargs["solc_remaps"] = ""
148+
149+
if platform_config.remappings:
150+
kwargs["solc_remaps"] = platform_config.remappings
151+
if (
152+
platform_config.solc_version
153+
and platform_config.solc_version != current_version()[0]
154+
):
155+
solc_version = platform_config.solc_version
156+
if solc_version in installed_versions():
157+
kwargs["solc"] = str(artifact_path(solc_version).absolute())
158+
else:
159+
# Respect foundry offline option and don't install a missing solc version
160+
if not platform_config.offline:
161+
install_artifacts([solc_version])
162+
kwargs["solc"] = str(artifact_path(solc_version).absolute())
163+
if platform_config.optimizer:
164+
kwargs["solc_args"] += "--optimize"
165+
if platform_config.optimizer_runs:
166+
kwargs[
167+
"solc_args"
168+
] += f"--optimize-runs {platform_config.optimizer_runs}"
169+
if platform_config.via_ir:
170+
kwargs["solc_args"] += "--via-ir"
171+
if platform_config.allow_paths:
172+
kwargs["solc_args"] += f"--allow-paths {platform_config.allow_paths}"
173+
if platform_config.evm_version:
174+
kwargs["solc_args"] += f"--evm-version {platform_config.evm_version}"
119175
else:
120176
platform = target
121177

@@ -622,18 +678,14 @@ def compile_all(target: str, **kwargs: str) -> List[CryticCompile]:
622678
**kwargs: optional arguments. Used: "solc_standard_json"
623679
624680
Raises:
625-
ValueError: If the target could not be compiled
681+
NotImplementedError: If the target could not be compiled
626682
627683
Returns:
628684
List[CryticCompile]: Returns a list of CryticCompile instances for all compilations which occurred.
629685
"""
630686
use_solc_standard_json = kwargs.get("solc_standard_json", False)
631687

632-
# Attempt to perform glob expansion of target/filename
633-
globbed_targets = glob.glob(target, recursive=True)
634-
635688
# Check if the target refers to a valid target already.
636-
# If it does not, we assume it's a glob pattern.
637689
compilations: List[CryticCompile] = []
638690
if os.path.isfile(target) or is_supported(target):
639691
if target.endswith(".zip"):
@@ -645,28 +697,33 @@ def compile_all(target: str, **kwargs: str) -> List[CryticCompile]:
645697
compilations = load_from_zip(tmp.name)
646698
else:
647699
compilations.append(CryticCompile(target, **kwargs))
648-
elif os.path.isdir(target) or len(globbed_targets) > 0:
649-
# We create a new glob to find solidity files at this path (in case this is a directory)
650-
filenames = glob.glob(os.path.join(target, "*.sol"))
651-
if not filenames:
652-
filenames = glob.glob(os.path.join(target, "*.vy"))
653-
if not filenames:
654-
filenames = globbed_targets
655-
700+
elif os.path.isdir(target):
701+
solidity_filenames = glob.glob(os.path.join(target, "*.sol"))
702+
vyper_filenames = glob.glob(os.path.join(target, "*.vy"))
656703
# Determine if we're using --standard-solc option to
657704
# aggregate many files into a single compilation.
658705
if use_solc_standard_json:
659706
# If we're using standard solc, then we generated our
660707
# input to create a single compilation with all files
661-
standard_json = solc_standard_json.SolcStandardJson()
662-
for filename in filenames:
663-
standard_json.add_source_file(filename)
664-
compilations.append(CryticCompile(standard_json, **kwargs))
708+
solc_standard_json = SolcStandardJson()
709+
solc_standard_json.add_source_files(solidity_filenames)
710+
compilations.append(CryticCompile(solc_standard_json, **kwargs))
665711
else:
666712
# We compile each file and add it to our compilations.
667-
for filename in filenames:
713+
for filename in solidity_filenames:
668714
compilations.append(CryticCompile(filename, **kwargs))
715+
716+
if vyper_filenames:
717+
vyper_standard_json = VyperStandardJson()
718+
vyper_standard_json.add_source_files(vyper_filenames)
719+
compilations.append(CryticCompile(vyper_standard_json, **kwargs))
669720
else:
670-
raise ValueError(f"{str(target)} is not a file or directory.")
721+
raise NotImplementedError()
722+
# TODO split glob into language
723+
# # Attempt to perform glob expansion of target/filename
724+
# globbed_targets = glob.glob(target, recursive=True)
725+
# print(globbed_targets)
726+
727+
# raise ValueError(f"{str(target)} is not a file or directory.")
671728

672729
return compilations

crytic_compile/cryticparser/cryticparser.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,30 @@ def _init_etherscan(parser: ArgumentParser) -> None:
385385
default=DEFAULTS_FLAG_IN_CONFIG["etherscan_api_key"],
386386
)
387387

388+
group_etherscan.add_argument(
389+
"--base-apikey",
390+
help="Basescan API key.",
391+
action="store",
392+
dest="base_api_key",
393+
default=DEFAULTS_FLAG_IN_CONFIG["etherscan_api_key"],
394+
)
395+
396+
group_etherscan.add_argument(
397+
"--gno-apikey",
398+
help="Gnosisscan API key.",
399+
action="store",
400+
dest="gno_api_key",
401+
default=DEFAULTS_FLAG_IN_CONFIG["etherscan_api_key"],
402+
)
403+
404+
group_etherscan.add_argument(
405+
"--polyzk-apikey",
406+
help="zkEVM Polygonscan API key.",
407+
action="store",
408+
dest="polyzk_api_key",
409+
default=DEFAULTS_FLAG_IN_CONFIG["etherscan_api_key"],
410+
)
411+
388412
group_etherscan.add_argument(
389413
"--etherscan-export-directory",
390414
help="Directory in which to save the analyzed contracts.",
@@ -496,3 +520,11 @@ def _init_foundry(parser: ArgumentParser) -> None:
496520
dest="foundry_out_directory",
497521
default=DEFAULTS_FLAG_IN_CONFIG["foundry_out_directory"],
498522
)
523+
524+
group_foundry.add_argument(
525+
"--foundry-compile-all",
526+
help="Don't skip compiling test and script",
527+
action="store_true",
528+
dest="foundry_compile_all",
529+
default=DEFAULTS_FLAG_IN_CONFIG["foundry_compile_all"],
530+
)

crytic_compile/cryticparser/defaults.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"hardhat_artifacts_directory": None,
4646
"foundry_ignore_compile": False,
4747
"foundry_out_directory": "out",
48+
"foundry_compile_all": False,
4849
"export_dir": "crytic-export",
4950
"compile_libraries": None,
5051
}

crytic_compile/platform/abstract_platform.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
This gives the skeleton for any platform supported by crytic-compile
55
"""
66
import abc
7-
from typing import TYPE_CHECKING, List, Dict
7+
from typing import TYPE_CHECKING, List, Dict, Optional
8+
from dataclasses import dataclass, field
89

910
from crytic_compile.platform import Type
1011
from crytic_compile.utils.unit_tests import guess_tests
@@ -22,6 +23,27 @@ class IncorrectPlatformInitialization(Exception):
2223
pass
2324

2425

26+
# pylint: disable=too-many-instance-attributes
27+
@dataclass
28+
class PlatformConfig:
29+
"""
30+
This class represents a generic platform configuration
31+
"""
32+
33+
offline: bool = False
34+
remappings: Optional[str] = None
35+
solc_version: Optional[str] = None
36+
optimizer: bool = False
37+
optimizer_runs: Optional[int] = None
38+
via_ir: bool = False
39+
allow_paths: Optional[str] = None
40+
evm_version: Optional[str] = None
41+
src_path: str = "src"
42+
tests_path: str = "test"
43+
libs_path: List[str] = field(default_factory=lambda: ["lib"])
44+
scripts_path: str = "script"
45+
46+
2547
class AbstractPlatform(metaclass=abc.ABCMeta):
2648
"""
2749
This is the abstract class for the platform
@@ -154,6 +176,18 @@ def is_dependency(self, path: str) -> bool:
154176
"""
155177
return False
156178

179+
@staticmethod
180+
def config(working_dir: str) -> Optional[PlatformConfig]: # pylint: disable=unused-argument
181+
"""Return configuration data that should be passed to solc, such as version, remappings ecc.
182+
183+
Args:
184+
working_dir (str): path to the target
185+
186+
Returns:
187+
Optional[PlatformConfig]: Platform configuration data such as optimization, remappings...
188+
"""
189+
return None
190+
157191
# Only _guessed_tests is an abstract method
158192
# guessed_tests will call the generic guess_tests and appends to the list
159193
# platforms-dependent tests

crytic_compile/platform/all_platforms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
from .solc_standard_json import SolcStandardJson
1515
from .standard import Standard
1616
from .truffle import Truffle
17-
from .vyper import Vyper
17+
from .vyper import VyperStandardJson
1818
from .waffle import Waffle
1919
from .foundry import Foundry

crytic_compile/platform/buidler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
from pathlib import Path
1010
from typing import TYPE_CHECKING, List, Tuple
1111

12+
from crytic_compile.compilation_unit import CompilationUnit
1213
from crytic_compile.compiler.compiler import CompilerVersion
14+
from crytic_compile.platform.abstract_platform import AbstractPlatform
1315
from crytic_compile.platform.exceptions import InvalidCompilation
1416
from crytic_compile.platform.types import Type
1517
from crytic_compile.utils.naming import convert_filename, extract_name
1618
from crytic_compile.utils.natspec import Natspec
17-
from crytic_compile.compilation_unit import CompilationUnit
18-
from .abstract_platform import AbstractPlatform
1919

2020
# Handle cycle
2121
from .solc import relative_to_short

crytic_compile/platform/dapp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
from crytic_compile.platform.abstract_platform import AbstractPlatform
2020
from crytic_compile.platform.types import Type
2121
from crytic_compile.utils.naming import convert_filename, extract_name
22-
from crytic_compile.utils.subprocess import run
2322

2423
# Handle cycle
2524
from crytic_compile.utils.natspec import Natspec
25+
from crytic_compile.utils.subprocess import run
2626

2727
if TYPE_CHECKING:
2828
from crytic_compile import CryticCompile

crytic_compile/platform/etherscan.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
"testnet.avax:": ("-testnet.snowtrace.io", "testnet.snowtrace.io"),
5151
"ftm:": (".ftmscan.com", "ftmscan.com"),
5252
"goerli.base:": ("-goerli.basescan.org", "goerli.basescan.org"),
53+
"base:": (".basescan.org", "basescan.org"),
54+
"gno:": (".gnosisscan.io", "gnosisscan.io"),
55+
"polyzk:": ("-zkevm.polygonscan.com", "zkevm.polygonscan.com"),
5356
}
5457

5558

@@ -237,6 +240,9 @@ def compile(self, crytic_compile: "CryticCompile", **kwargs: str) -> None:
237240
ftmscan_api_key = kwargs.get("ftmscan_api_key", None)
238241
bscan_api_key = kwargs.get("bscan_api_key", None)
239242
optim_api_key = kwargs.get("optim_api_key", None)
243+
base_api_key = kwargs.get("base_api_key", None)
244+
gno_api_key = kwargs.get("gno_api_key", None)
245+
polyzk_api_key = kwargs.get("polyzk_api_key", None)
240246

241247
export_dir = kwargs.get("export_dir", "crytic-export")
242248
export_dir = os.path.join(
@@ -267,6 +273,15 @@ def compile(self, crytic_compile: "CryticCompile", **kwargs: str) -> None:
267273
if optim_api_key and "optim" in etherscan_url:
268274
etherscan_url += f"&apikey={optim_api_key}"
269275
etherscan_bytecode_url += f"&apikey={optim_api_key}"
276+
if base_api_key and "base" in etherscan_url:
277+
etherscan_url += f"&apikey={base_api_key}"
278+
etherscan_bytecode_url += f"&apikey={base_api_key}"
279+
if gno_api_key and "gno" in etherscan_url:
280+
etherscan_url += f"&apikey={gno_api_key}"
281+
etherscan_bytecode_url += f"&apikey={gno_api_key}"
282+
if polyzk_api_key and "zkevm" in etherscan_url:
283+
etherscan_url += f"&apikey={polyzk_api_key}"
284+
etherscan_bytecode_url += f"&apikey={polyzk_api_key}"
270285

271286
source_code: str = ""
272287
result: Dict[str, Union[bool, str, int]] = {}

0 commit comments

Comments
 (0)