slither.slither

  1import logging
  2from typing import Union, List, Type, Dict, Optional
  3
  4from crytic_compile import CryticCompile, InvalidCompilation
  5
  6# pylint: disable= no-name-in-module
  7from slither.core.compilation_unit import SlitherCompilationUnit
  8from slither.core.slither_core import SlitherCore
  9from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
 10from slither.exceptions import SlitherError
 11from slither.printers.abstract_printer import AbstractPrinter
 12from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
 13from slither.vyper_parsing.vyper_compilation_unit import VyperCompilationUnit
 14from slither.utils.output import Output
 15from slither.vyper_parsing.ast.ast import parse
 16
 17logger = logging.getLogger("Slither")
 18logging.basicConfig()
 19
 20logger_detector = logging.getLogger("Detectors")
 21logger_printer = logging.getLogger("Printers")
 22
 23
 24def _check_common_things(
 25    thing_name: str, cls: Type, base_cls: Type, instances_list: List[Type[AbstractDetector]]
 26) -> None:
 27
 28    if not issubclass(cls, base_cls) or cls is base_cls:
 29        raise SlitherError(
 30            f"You can't register {cls!r} as a {thing_name}. You need to pass a class that inherits from {base_cls.__name__}"
 31        )
 32
 33    if any(type(obj) == cls for obj in instances_list):  # pylint: disable=unidiomatic-typecheck
 34        raise SlitherError(f"You can't register {cls!r} twice.")
 35
 36
 37def _update_file_scopes(
 38    sol_parser: SlitherCompilationUnitSolc,
 39):  # pylint: disable=too-many-branches
 40    """
 41    Since all definitions in a file are exported by default, including definitions from its (transitive) dependencies,
 42    we can identify all top level items that could possibly be referenced within the file from its exportedSymbols.
 43    It is not as straightforward for user defined types and functions as well as aliasing. See add_accessible_scopes for more details.
 44    """
 45    candidates = sol_parser.compilation_unit.scopes.values()
 46    learned_something = False
 47    # Because solc's import allows cycle in the import graph, iterate until we aren't adding new information to the scope.
 48    while True:
 49        for candidate in candidates:
 50            learned_something |= candidate.add_accessible_scopes()
 51        if not learned_something:
 52            break
 53        learned_something = False
 54
 55    for scope in candidates:
 56        for refId in scope.exported_symbols:
 57            if refId in sol_parser.contracts_by_id:
 58                contract = sol_parser.contracts_by_id[refId]
 59                scope.contracts[contract.name] = contract
 60            elif refId in sol_parser.functions_by_id:
 61                functions = sol_parser.functions_by_id[refId]
 62                assert len(functions) == 1
 63                scope.functions.add(functions[0])
 64            elif refId in sol_parser.imports_by_id:
 65                import_directive = sol_parser.imports_by_id[refId]
 66                scope.imports.add(import_directive)
 67            elif refId in sol_parser.top_level_variables_by_id:
 68                top_level_variable = sol_parser.top_level_variables_by_id[refId]
 69                scope.variables[top_level_variable.name] = top_level_variable
 70            elif refId in sol_parser.top_level_events_by_id:
 71                top_level_event = sol_parser.top_level_events_by_id[refId]
 72                scope.events.add(top_level_event)
 73            elif refId in sol_parser.top_level_structures_by_id:
 74                top_level_struct = sol_parser.top_level_structures_by_id[refId]
 75                scope.structures[top_level_struct.name] = top_level_struct
 76            elif refId in sol_parser.top_level_type_aliases_by_id:
 77                top_level_type_alias = sol_parser.top_level_type_aliases_by_id[refId]
 78                scope.type_aliases[top_level_type_alias.name] = top_level_type_alias
 79            elif refId in sol_parser.top_level_enums_by_id:
 80                top_level_enum = sol_parser.top_level_enums_by_id[refId]
 81                scope.enums[top_level_enum.name] = top_level_enum
 82            elif refId in sol_parser.top_level_errors_by_id:
 83                top_level_custom_error = sol_parser.top_level_errors_by_id[refId]
 84                scope.custom_errors.add(top_level_custom_error)
 85            else:
 86                logger.error(
 87                    f"Failed to resolved name for reference id {refId} in {scope.filename.absolute}."
 88                )
 89
 90
 91class Slither(
 92    SlitherCore
 93):  # pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,too-many-branches
 94    def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None:
 95        """
 96        Args:
 97            target (str | CryticCompile)
 98        Keyword Args:
 99            solc (str): solc binary location (default 'solc')
100            disable_solc_warnings (bool): True to disable solc warnings (default false)
101            solc_args (str): solc arguments (default '')
102            ast_format (str): ast format (default '--ast-compact-json')
103            filter_paths (list(str)): list of path to filter (default [])
104            triage_mode (bool): if true, switch to triage mode (default false)
105            exclude_dependencies (bool): if true, exclude results that are only related to dependencies
106            generate_patches (bool): if true, patches are generated (json output only)
107            change_line_prefix (str): Change the line prefix (default #)
108                for the displayed source codes (i.e. file.sol#1).
109
110        """
111        super().__init__()
112
113        self._disallow_partial: bool = kwargs.get("disallow_partial", False)
114        self._skip_assembly: bool = kwargs.get("skip_assembly", False)
115        self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False)
116
117        self.line_prefix = kwargs.get("change_line_prefix", "#")
118
119        # Indicate if Codex related features should be used
120        self.codex_enabled = kwargs.get("codex", False)
121        self.codex_contracts = kwargs.get("codex_contracts", "all")
122        self.codex_model = kwargs.get("codex_model", "text-davinci-003")
123        self.codex_temperature = kwargs.get("codex_temperature", 0)
124        self.codex_max_tokens = kwargs.get("codex_max_tokens", 300)
125        self.codex_log = kwargs.get("codex_log", False)
126        self.codex_organization: Optional[str] = kwargs.get("codex_organization", None)
127
128        self.no_fail = kwargs.get("no_fail", False)
129
130        self._parsers: List[SlitherCompilationUnitSolc] = []
131        try:
132            if isinstance(target, CryticCompile):
133                crytic_compile = target
134            else:
135                crytic_compile = CryticCompile(target, **kwargs)
136            self._crytic_compile = crytic_compile
137        except InvalidCompilation as e:
138            # pylint: disable=raise-missing-from
139            raise SlitherError(f"Invalid compilation: \n{str(e)}")
140        for compilation_unit in crytic_compile.compilation_units.values():
141            compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit)
142            self._compilation_units.append(compilation_unit_slither)
143
144            if compilation_unit_slither.is_vyper:
145                vyper_parser = VyperCompilationUnit(compilation_unit_slither)
146                for path, ast in compilation_unit.asts.items():
147                    ast_nodes = parse(ast["ast"])
148                    vyper_parser.parse_module(ast_nodes, path)
149                self._parsers.append(vyper_parser)
150            else:
151                # Solidity specific
152                assert compilation_unit_slither.is_solidity
153                sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither)
154                self._parsers.append(sol_parser)
155                for path, ast in compilation_unit.asts.items():
156                    sol_parser.parse_top_level_items(ast, path)
157                    self.add_source_code(path)
158
159                for contract in sol_parser._underlying_contract_to_parser:
160                    if contract.name.startswith("SlitherInternalTopLevelContract"):
161                        raise SlitherError(
162                            # region multi-line-string
163                            """Your codebase has a contract named 'SlitherInternalTopLevelContract'.
164        Please rename it, this name is reserved for Slither's internals"""
165                            # endregion multi-line
166                        )
167                    sol_parser._contracts_by_id[contract.id] = contract
168                    sol_parser._compilation_unit.contracts.append(contract)
169
170                _update_file_scopes(sol_parser)
171
172        if kwargs.get("generate_patches", False):
173            self.generate_patches = True
174
175        self._markdown_root = kwargs.get("markdown_root", "")
176
177        self._detectors = []
178        self._printers = []
179
180        filter_paths = kwargs.get("filter_paths", [])
181        for p in filter_paths:
182            self.add_path_to_filter(p)
183
184        include_paths = kwargs.get("include_paths", [])
185        for p in include_paths:
186            self.add_path_to_include(p)
187
188        self._exclude_dependencies = kwargs.get("exclude_dependencies", False)
189
190        triage_mode = kwargs.get("triage_mode", False)
191        triage_database = kwargs.get("triage_database", "slither.db.json")
192        self._triage_mode = triage_mode
193        self._previous_results_filename = triage_database
194
195        printers_to_run = kwargs.get("printers_to_run", "")
196        if printers_to_run == "echidna":
197            self.skip_data_dependency = True
198
199        # Used in inheritance-graph printer
200        self.include_interfaces = kwargs.get("include_interfaces", False)
201
202        self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))
203
204    def _init_parsing_and_analyses(self, skip_analyze: bool) -> None:
205        for parser in self._parsers:
206            try:
207                parser.parse_contracts()
208            except Exception as e:
209                if self.no_fail:
210                    continue
211                raise e
212
213        # skip_analyze is only used for testing
214        if not skip_analyze:
215            for parser in self._parsers:
216                try:
217                    parser.analyze_contracts()
218                except Exception as e:
219                    if self.no_fail:
220                        continue
221                    raise e
222
223    @property
224    def detectors(self):
225        return self._detectors
226
227    @property
228    def detectors_high(self):
229        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
230
231    @property
232    def detectors_medium(self):
233        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
234
235    @property
236    def detectors_low(self):
237        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
238
239    @property
240    def detectors_informational(self):
241        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
242
243    @property
244    def detectors_optimization(self):
245        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]
246
247    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
248        """
249        :param detector_class: Class inheriting from `AbstractDetector`.
250        """
251        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
252
253        for compilation_unit in self.compilation_units:
254            instance = detector_class(compilation_unit, self, logger_detector)
255            self._detectors.append(instance)
256
257    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
258        """
259        :param detector_class: Class inheriting from `AbstractDetector`.
260        """
261
262        for obj in self._detectors:
263            if isinstance(obj, detector_class):
264                self._detectors.remove(obj)
265                return
266
267    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
268        """
269        :param printer_class: Class inheriting from `AbstractPrinter`.
270        """
271        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
272
273        instance = printer_class(self, logger_printer)
274        self._printers.append(instance)
275
276    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
277        """
278        :param printer_class: Class inheriting from `AbstractPrinter`.
279        """
280
281        for obj in self._printers:
282            if isinstance(obj, printer_class):
283                self._printers.remove(obj)
284                return
285
286    def run_detectors(self) -> List[Dict]:
287        """
288        :return: List of registered detectors results.
289        """
290
291        self.load_previous_results()
292        results = [d.detect() for d in self._detectors]
293
294        self.write_results_to_hide()
295        return results
296
297    def run_printers(self) -> List[Output]:
298        """
299        :return: List of registered printers outputs.
300        """
301
302        return [p.output(self._crytic_compile.target).data for p in self._printers]
303
304    @property
305    def triage_mode(self) -> bool:
306        return self._triage_mode
logger = <Logger Slither (WARNING)>
logger_detector = <Logger Detectors (WARNING)>
logger_printer = <Logger Printers (WARNING)>
class Slither(slither.core.slither_core.SlitherCore):
 92class Slither(
 93    SlitherCore
 94):  # pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,too-many-branches
 95    def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None:
 96        """
 97        Args:
 98            target (str | CryticCompile)
 99        Keyword Args:
100            solc (str): solc binary location (default 'solc')
101            disable_solc_warnings (bool): True to disable solc warnings (default false)
102            solc_args (str): solc arguments (default '')
103            ast_format (str): ast format (default '--ast-compact-json')
104            filter_paths (list(str)): list of path to filter (default [])
105            triage_mode (bool): if true, switch to triage mode (default false)
106            exclude_dependencies (bool): if true, exclude results that are only related to dependencies
107            generate_patches (bool): if true, patches are generated (json output only)
108            change_line_prefix (str): Change the line prefix (default #)
109                for the displayed source codes (i.e. file.sol#1).
110
111        """
112        super().__init__()
113
114        self._disallow_partial: bool = kwargs.get("disallow_partial", False)
115        self._skip_assembly: bool = kwargs.get("skip_assembly", False)
116        self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False)
117
118        self.line_prefix = kwargs.get("change_line_prefix", "#")
119
120        # Indicate if Codex related features should be used
121        self.codex_enabled = kwargs.get("codex", False)
122        self.codex_contracts = kwargs.get("codex_contracts", "all")
123        self.codex_model = kwargs.get("codex_model", "text-davinci-003")
124        self.codex_temperature = kwargs.get("codex_temperature", 0)
125        self.codex_max_tokens = kwargs.get("codex_max_tokens", 300)
126        self.codex_log = kwargs.get("codex_log", False)
127        self.codex_organization: Optional[str] = kwargs.get("codex_organization", None)
128
129        self.no_fail = kwargs.get("no_fail", False)
130
131        self._parsers: List[SlitherCompilationUnitSolc] = []
132        try:
133            if isinstance(target, CryticCompile):
134                crytic_compile = target
135            else:
136                crytic_compile = CryticCompile(target, **kwargs)
137            self._crytic_compile = crytic_compile
138        except InvalidCompilation as e:
139            # pylint: disable=raise-missing-from
140            raise SlitherError(f"Invalid compilation: \n{str(e)}")
141        for compilation_unit in crytic_compile.compilation_units.values():
142            compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit)
143            self._compilation_units.append(compilation_unit_slither)
144
145            if compilation_unit_slither.is_vyper:
146                vyper_parser = VyperCompilationUnit(compilation_unit_slither)
147                for path, ast in compilation_unit.asts.items():
148                    ast_nodes = parse(ast["ast"])
149                    vyper_parser.parse_module(ast_nodes, path)
150                self._parsers.append(vyper_parser)
151            else:
152                # Solidity specific
153                assert compilation_unit_slither.is_solidity
154                sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither)
155                self._parsers.append(sol_parser)
156                for path, ast in compilation_unit.asts.items():
157                    sol_parser.parse_top_level_items(ast, path)
158                    self.add_source_code(path)
159
160                for contract in sol_parser._underlying_contract_to_parser:
161                    if contract.name.startswith("SlitherInternalTopLevelContract"):
162                        raise SlitherError(
163                            # region multi-line-string
164                            """Your codebase has a contract named 'SlitherInternalTopLevelContract'.
165        Please rename it, this name is reserved for Slither's internals"""
166                            # endregion multi-line
167                        )
168                    sol_parser._contracts_by_id[contract.id] = contract
169                    sol_parser._compilation_unit.contracts.append(contract)
170
171                _update_file_scopes(sol_parser)
172
173        if kwargs.get("generate_patches", False):
174            self.generate_patches = True
175
176        self._markdown_root = kwargs.get("markdown_root", "")
177
178        self._detectors = []
179        self._printers = []
180
181        filter_paths = kwargs.get("filter_paths", [])
182        for p in filter_paths:
183            self.add_path_to_filter(p)
184
185        include_paths = kwargs.get("include_paths", [])
186        for p in include_paths:
187            self.add_path_to_include(p)
188
189        self._exclude_dependencies = kwargs.get("exclude_dependencies", False)
190
191        triage_mode = kwargs.get("triage_mode", False)
192        triage_database = kwargs.get("triage_database", "slither.db.json")
193        self._triage_mode = triage_mode
194        self._previous_results_filename = triage_database
195
196        printers_to_run = kwargs.get("printers_to_run", "")
197        if printers_to_run == "echidna":
198            self.skip_data_dependency = True
199
200        # Used in inheritance-graph printer
201        self.include_interfaces = kwargs.get("include_interfaces", False)
202
203        self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))
204
205    def _init_parsing_and_analyses(self, skip_analyze: bool) -> None:
206        for parser in self._parsers:
207            try:
208                parser.parse_contracts()
209            except Exception as e:
210                if self.no_fail:
211                    continue
212                raise e
213
214        # skip_analyze is only used for testing
215        if not skip_analyze:
216            for parser in self._parsers:
217                try:
218                    parser.analyze_contracts()
219                except Exception as e:
220                    if self.no_fail:
221                        continue
222                    raise e
223
224    @property
225    def detectors(self):
226        return self._detectors
227
228    @property
229    def detectors_high(self):
230        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
231
232    @property
233    def detectors_medium(self):
234        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
235
236    @property
237    def detectors_low(self):
238        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
239
240    @property
241    def detectors_informational(self):
242        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
243
244    @property
245    def detectors_optimization(self):
246        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]
247
248    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
249        """
250        :param detector_class: Class inheriting from `AbstractDetector`.
251        """
252        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
253
254        for compilation_unit in self.compilation_units:
255            instance = detector_class(compilation_unit, self, logger_detector)
256            self._detectors.append(instance)
257
258    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
259        """
260        :param detector_class: Class inheriting from `AbstractDetector`.
261        """
262
263        for obj in self._detectors:
264            if isinstance(obj, detector_class):
265                self._detectors.remove(obj)
266                return
267
268    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
269        """
270        :param printer_class: Class inheriting from `AbstractPrinter`.
271        """
272        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
273
274        instance = printer_class(self, logger_printer)
275        self._printers.append(instance)
276
277    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
278        """
279        :param printer_class: Class inheriting from `AbstractPrinter`.
280        """
281
282        for obj in self._printers:
283            if isinstance(obj, printer_class):
284                self._printers.remove(obj)
285                return
286
287    def run_detectors(self) -> List[Dict]:
288        """
289        :return: List of registered detectors results.
290        """
291
292        self.load_previous_results()
293        results = [d.detect() for d in self._detectors]
294
295        self.write_results_to_hide()
296        return results
297
298    def run_printers(self) -> List[Output]:
299        """
300        :return: List of registered printers outputs.
301        """
302
303        return [p.output(self._crytic_compile.target).data for p in self._printers]
304
305    @property
306    def triage_mode(self) -> bool:
307        return self._triage_mode

Slither static analyzer

Slither( target: Union[str, crytic_compile.crytic_compile.CryticCompile], **kwargs)
 95    def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None:
 96        """
 97        Args:
 98            target (str | CryticCompile)
 99        Keyword Args:
100            solc (str): solc binary location (default 'solc')
101            disable_solc_warnings (bool): True to disable solc warnings (default false)
102            solc_args (str): solc arguments (default '')
103            ast_format (str): ast format (default '--ast-compact-json')
104            filter_paths (list(str)): list of path to filter (default [])
105            triage_mode (bool): if true, switch to triage mode (default false)
106            exclude_dependencies (bool): if true, exclude results that are only related to dependencies
107            generate_patches (bool): if true, patches are generated (json output only)
108            change_line_prefix (str): Change the line prefix (default #)
109                for the displayed source codes (i.e. file.sol#1).
110
111        """
112        super().__init__()
113
114        self._disallow_partial: bool = kwargs.get("disallow_partial", False)
115        self._skip_assembly: bool = kwargs.get("skip_assembly", False)
116        self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False)
117
118        self.line_prefix = kwargs.get("change_line_prefix", "#")
119
120        # Indicate if Codex related features should be used
121        self.codex_enabled = kwargs.get("codex", False)
122        self.codex_contracts = kwargs.get("codex_contracts", "all")
123        self.codex_model = kwargs.get("codex_model", "text-davinci-003")
124        self.codex_temperature = kwargs.get("codex_temperature", 0)
125        self.codex_max_tokens = kwargs.get("codex_max_tokens", 300)
126        self.codex_log = kwargs.get("codex_log", False)
127        self.codex_organization: Optional[str] = kwargs.get("codex_organization", None)
128
129        self.no_fail = kwargs.get("no_fail", False)
130
131        self._parsers: List[SlitherCompilationUnitSolc] = []
132        try:
133            if isinstance(target, CryticCompile):
134                crytic_compile = target
135            else:
136                crytic_compile = CryticCompile(target, **kwargs)
137            self._crytic_compile = crytic_compile
138        except InvalidCompilation as e:
139            # pylint: disable=raise-missing-from
140            raise SlitherError(f"Invalid compilation: \n{str(e)}")
141        for compilation_unit in crytic_compile.compilation_units.values():
142            compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit)
143            self._compilation_units.append(compilation_unit_slither)
144
145            if compilation_unit_slither.is_vyper:
146                vyper_parser = VyperCompilationUnit(compilation_unit_slither)
147                for path, ast in compilation_unit.asts.items():
148                    ast_nodes = parse(ast["ast"])
149                    vyper_parser.parse_module(ast_nodes, path)
150                self._parsers.append(vyper_parser)
151            else:
152                # Solidity specific
153                assert compilation_unit_slither.is_solidity
154                sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither)
155                self._parsers.append(sol_parser)
156                for path, ast in compilation_unit.asts.items():
157                    sol_parser.parse_top_level_items(ast, path)
158                    self.add_source_code(path)
159
160                for contract in sol_parser._underlying_contract_to_parser:
161                    if contract.name.startswith("SlitherInternalTopLevelContract"):
162                        raise SlitherError(
163                            # region multi-line-string
164                            """Your codebase has a contract named 'SlitherInternalTopLevelContract'.
165        Please rename it, this name is reserved for Slither's internals"""
166                            # endregion multi-line
167                        )
168                    sol_parser._contracts_by_id[contract.id] = contract
169                    sol_parser._compilation_unit.contracts.append(contract)
170
171                _update_file_scopes(sol_parser)
172
173        if kwargs.get("generate_patches", False):
174            self.generate_patches = True
175
176        self._markdown_root = kwargs.get("markdown_root", "")
177
178        self._detectors = []
179        self._printers = []
180
181        filter_paths = kwargs.get("filter_paths", [])
182        for p in filter_paths:
183            self.add_path_to_filter(p)
184
185        include_paths = kwargs.get("include_paths", [])
186        for p in include_paths:
187            self.add_path_to_include(p)
188
189        self._exclude_dependencies = kwargs.get("exclude_dependencies", False)
190
191        triage_mode = kwargs.get("triage_mode", False)
192        triage_database = kwargs.get("triage_database", "slither.db.json")
193        self._triage_mode = triage_mode
194        self._previous_results_filename = triage_database
195
196        printers_to_run = kwargs.get("printers_to_run", "")
197        if printers_to_run == "echidna":
198            self.skip_data_dependency = True
199
200        # Used in inheritance-graph printer
201        self.include_interfaces = kwargs.get("include_interfaces", False)
202
203        self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))

Args: target (str | CryticCompile) Keyword Args: solc (str): solc binary location (default 'solc') disable_solc_warnings (bool): True to disable solc warnings (default false) solc_args (str): solc arguments (default '') ast_format (str): ast format (default '--ast-compact-json') filter_paths (list(str)): list of path to filter (default []) triage_mode (bool): if true, switch to triage mode (default false) exclude_dependencies (bool): if true, exclude results that are only related to dependencies generate_patches (bool): if true, patches are generated (json output only) change_line_prefix (str): Change the line prefix (default #) for the displayed source codes (i.e. file.sol#1).

line_prefix
codex_enabled
codex_contracts
codex_model
codex_temperature
codex_max_tokens
codex_log
codex_organization: Union[str, NoneType]
no_fail
include_interfaces
detectors
224    @property
225    def detectors(self):
226        return self._detectors
detectors_high
228    @property
229    def detectors_high(self):
230        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
detectors_medium
232    @property
233    def detectors_medium(self):
234        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
detectors_low
236    @property
237    def detectors_low(self):
238        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
detectors_informational
240    @property
241    def detectors_informational(self):
242        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
detectors_optimization
244    @property
245    def detectors_optimization(self):
246        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]
def register_detector( self, detector_class: Type[slither.detectors.abstract_detector.AbstractDetector]) -> None:
248    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
249        """
250        :param detector_class: Class inheriting from `AbstractDetector`.
251        """
252        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
253
254        for compilation_unit in self.compilation_units:
255            instance = detector_class(compilation_unit, self, logger_detector)
256            self._detectors.append(instance)
Parameters
  • detector_class: Class inheriting from AbstractDetector.
def unregister_detector( self, detector_class: Type[slither.detectors.abstract_detector.AbstractDetector]) -> None:
258    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
259        """
260        :param detector_class: Class inheriting from `AbstractDetector`.
261        """
262
263        for obj in self._detectors:
264            if isinstance(obj, detector_class):
265                self._detectors.remove(obj)
266                return
Parameters
  • detector_class: Class inheriting from AbstractDetector.
def register_printer( self, printer_class: Type[slither.printers.abstract_printer.AbstractPrinter]) -> None:
268    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
269        """
270        :param printer_class: Class inheriting from `AbstractPrinter`.
271        """
272        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
273
274        instance = printer_class(self, logger_printer)
275        self._printers.append(instance)
Parameters
  • printer_class: Class inheriting from AbstractPrinter.
def unregister_printer( self, printer_class: Type[slither.printers.abstract_printer.AbstractPrinter]) -> None:
277    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
278        """
279        :param printer_class: Class inheriting from `AbstractPrinter`.
280        """
281
282        for obj in self._printers:
283            if isinstance(obj, printer_class):
284                self._printers.remove(obj)
285                return
Parameters
  • printer_class: Class inheriting from AbstractPrinter.
def run_detectors(self) -> List[Dict]:
287    def run_detectors(self) -> List[Dict]:
288        """
289        :return: List of registered detectors results.
290        """
291
292        self.load_previous_results()
293        results = [d.detect() for d in self._detectors]
294
295        self.write_results_to_hide()
296        return results
Returns

List of registered detectors results.

def run_printers(self) -> List[slither.utils.output.Output]:
298    def run_printers(self) -> List[Output]:
299        """
300        :return: List of registered printers outputs.
301        """
302
303        return [p.output(self._crytic_compile.target).data for p in self._printers]
Returns

List of registered printers outputs.

triage_mode: bool
305    @property
306    def triage_mode(self) -> bool:
307        return self._triage_mode