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        self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))
200
201    def _init_parsing_and_analyses(self, skip_analyze: bool) -> None:
202
203        for parser in self._parsers:
204            try:
205                parser.parse_contracts()
206            except Exception as e:
207                if self.no_fail:
208                    continue
209                raise e
210
211        # skip_analyze is only used for testing
212        if not skip_analyze:
213            for parser in self._parsers:
214                try:
215                    parser.analyze_contracts()
216                except Exception as e:
217                    if self.no_fail:
218                        continue
219                    raise e
220
221    @property
222    def detectors(self):
223        return self._detectors
224
225    @property
226    def detectors_high(self):
227        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
228
229    @property
230    def detectors_medium(self):
231        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
232
233    @property
234    def detectors_low(self):
235        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
236
237    @property
238    def detectors_informational(self):
239        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
240
241    @property
242    def detectors_optimization(self):
243        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]
244
245    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
246        """
247        :param detector_class: Class inheriting from `AbstractDetector`.
248        """
249        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
250
251        for compilation_unit in self.compilation_units:
252            instance = detector_class(compilation_unit, self, logger_detector)
253            self._detectors.append(instance)
254
255    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
256        """
257        :param detector_class: Class inheriting from `AbstractDetector`.
258        """
259
260        for obj in self._detectors:
261            if isinstance(obj, detector_class):
262                self._detectors.remove(obj)
263                return
264
265    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
266        """
267        :param printer_class: Class inheriting from `AbstractPrinter`.
268        """
269        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
270
271        instance = printer_class(self, logger_printer)
272        self._printers.append(instance)
273
274    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
275        """
276        :param printer_class: Class inheriting from `AbstractPrinter`.
277        """
278
279        for obj in self._printers:
280            if isinstance(obj, printer_class):
281                self._printers.remove(obj)
282                return
283
284    def run_detectors(self) -> List[Dict]:
285        """
286        :return: List of registered detectors results.
287        """
288
289        self.load_previous_results()
290        results = [d.detect() for d in self._detectors]
291
292        self.write_results_to_hide()
293        return results
294
295    def run_printers(self) -> List[Output]:
296        """
297        :return: List of registered printers outputs.
298        """
299
300        return [p.output(self._crytic_compile.target).data for p in self._printers]
301
302    @property
303    def triage_mode(self) -> bool:
304        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        self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))
201
202    def _init_parsing_and_analyses(self, skip_analyze: bool) -> None:
203
204        for parser in self._parsers:
205            try:
206                parser.parse_contracts()
207            except Exception as e:
208                if self.no_fail:
209                    continue
210                raise e
211
212        # skip_analyze is only used for testing
213        if not skip_analyze:
214            for parser in self._parsers:
215                try:
216                    parser.analyze_contracts()
217                except Exception as e:
218                    if self.no_fail:
219                        continue
220                    raise e
221
222    @property
223    def detectors(self):
224        return self._detectors
225
226    @property
227    def detectors_high(self):
228        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
229
230    @property
231    def detectors_medium(self):
232        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
233
234    @property
235    def detectors_low(self):
236        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
237
238    @property
239    def detectors_informational(self):
240        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
241
242    @property
243    def detectors_optimization(self):
244        return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION]
245
246    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
247        """
248        :param detector_class: Class inheriting from `AbstractDetector`.
249        """
250        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
251
252        for compilation_unit in self.compilation_units:
253            instance = detector_class(compilation_unit, self, logger_detector)
254            self._detectors.append(instance)
255
256    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
257        """
258        :param detector_class: Class inheriting from `AbstractDetector`.
259        """
260
261        for obj in self._detectors:
262            if isinstance(obj, detector_class):
263                self._detectors.remove(obj)
264                return
265
266    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
267        """
268        :param printer_class: Class inheriting from `AbstractPrinter`.
269        """
270        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
271
272        instance = printer_class(self, logger_printer)
273        self._printers.append(instance)
274
275    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
276        """
277        :param printer_class: Class inheriting from `AbstractPrinter`.
278        """
279
280        for obj in self._printers:
281            if isinstance(obj, printer_class):
282                self._printers.remove(obj)
283                return
284
285    def run_detectors(self) -> List[Dict]:
286        """
287        :return: List of registered detectors results.
288        """
289
290        self.load_previous_results()
291        results = [d.detect() for d in self._detectors]
292
293        self.write_results_to_hide()
294        return results
295
296    def run_printers(self) -> List[Output]:
297        """
298        :return: List of registered printers outputs.
299        """
300
301        return [p.output(self._crytic_compile.target).data for p in self._printers]
302
303    @property
304    def triage_mode(self) -> bool:
305        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        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
detectors
222    @property
223    def detectors(self):
224        return self._detectors
detectors_high
226    @property
227    def detectors_high(self):
228        return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH]
detectors_medium
230    @property
231    def detectors_medium(self):
232        return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM]
detectors_low
234    @property
235    def detectors_low(self):
236        return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW]
detectors_informational
238    @property
239    def detectors_informational(self):
240        return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL]
detectors_optimization
242    @property
243    def detectors_optimization(self):
244        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:
246    def register_detector(self, detector_class: Type[AbstractDetector]) -> None:
247        """
248        :param detector_class: Class inheriting from `AbstractDetector`.
249        """
250        _check_common_things("detector", detector_class, AbstractDetector, self._detectors)
251
252        for compilation_unit in self.compilation_units:
253            instance = detector_class(compilation_unit, self, logger_detector)
254            self._detectors.append(instance)
Parameters
  • detector_class: Class inheriting from AbstractDetector.
def unregister_detector( self, detector_class: Type[slither.detectors.abstract_detector.AbstractDetector]) -> None:
256    def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
257        """
258        :param detector_class: Class inheriting from `AbstractDetector`.
259        """
260
261        for obj in self._detectors:
262            if isinstance(obj, detector_class):
263                self._detectors.remove(obj)
264                return
Parameters
  • detector_class: Class inheriting from AbstractDetector.
def register_printer( self, printer_class: Type[slither.printers.abstract_printer.AbstractPrinter]) -> None:
266    def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
267        """
268        :param printer_class: Class inheriting from `AbstractPrinter`.
269        """
270        _check_common_things("printer", printer_class, AbstractPrinter, self._printers)
271
272        instance = printer_class(self, logger_printer)
273        self._printers.append(instance)
Parameters
  • printer_class: Class inheriting from AbstractPrinter.
def unregister_printer( self, printer_class: Type[slither.printers.abstract_printer.AbstractPrinter]) -> None:
275    def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
276        """
277        :param printer_class: Class inheriting from `AbstractPrinter`.
278        """
279
280        for obj in self._printers:
281            if isinstance(obj, printer_class):
282                self._printers.remove(obj)
283                return
Parameters
  • printer_class: Class inheriting from AbstractPrinter.
def run_detectors(self) -> List[Dict]:
285    def run_detectors(self) -> List[Dict]:
286        """
287        :return: List of registered detectors results.
288        """
289
290        self.load_previous_results()
291        results = [d.detect() for d in self._detectors]
292
293        self.write_results_to_hide()
294        return results
Returns

List of registered detectors results.

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

List of registered printers outputs.

triage_mode: bool
303    @property
304    def triage_mode(self) -> bool:
305        return self._triage_mode