Merge remote-tracking branch 'origin/dev-add-types' into HEAD

pull/1624/head
Feist Josselin 2 years ago
commit c8c7566841
  1. 16
      slither/__main__.py
  2. 57
      slither/core/cfg/node.py
  3. 2
      slither/core/cfg/scope.py
  4. 4
      slither/core/children/child_contract.py
  5. 2
      slither/core/children/child_event.py
  6. 9
      slither/core/children/child_expression.py
  7. 4
      slither/core/children/child_inheritance.py
  8. 4
      slither/core/children/child_node.py
  9. 4
      slither/core/children/child_structure.py
  10. 14
      slither/core/compilation_unit.py
  11. 1
      slither/core/declarations/__init__.py
  12. 46
      slither/core/declarations/contract.py
  13. 8
      slither/core/declarations/custom_error.py
  14. 4
      slither/core/declarations/enum.py
  15. 4
      slither/core/declarations/enum_top_level.py
  16. 4
      slither/core/declarations/event.py
  17. 65
      slither/core/declarations/function.py
  18. 8
      slither/core/declarations/function_contract.py
  19. 9
      slither/core/declarations/function_top_level.py
  20. 2
      slither/core/declarations/import_directive.py
  21. 4
      slither/core/declarations/pragma_directive.py
  22. 8
      slither/core/declarations/solidity_import_placeholder.py
  23. 36
      slither/core/declarations/solidity_variables.py
  24. 2
      slither/core/declarations/structure_top_level.py
  25. 4
      slither/core/declarations/using_for_top_level.py
  26. 12
      slither/core/dominators/utils.py
  27. 2
      slither/core/expressions/assignment_operation.py
  28. 6
      slither/core/expressions/call_expression.py
  29. 19
      slither/core/expressions/conditional_expression.py
  30. 5
      slither/core/expressions/elementary_type_name_expression.py
  31. 13
      slither/core/expressions/index_access.py
  32. 2
      slither/core/expressions/literal.py
  33. 4
      slither/core/expressions/member_access.py
  34. 11
      slither/core/expressions/new_array.py
  35. 4
      slither/core/expressions/new_contract.py
  36. 21
      slither/core/expressions/type_conversion.py
  37. 20
      slither/core/expressions/unary_operation.py
  38. 2
      slither/core/scope/scope.py
  39. 14
      slither/core/slither_core.py
  40. 23
      slither/core/solidity_types/array_type.py
  41. 6
      slither/core/solidity_types/elementary_type.py
  42. 7
      slither/core/solidity_types/function_type.py
  43. 16
      slither/core/solidity_types/mapping_type.py
  44. 16
      slither/core/solidity_types/type_alias.py
  45. 7
      slither/core/solidity_types/type_information.py
  46. 10
      slither/core/solidity_types/user_defined_type.py
  47. 2
      slither/core/variables/__init__.py
  48. 2
      slither/core/variables/event_variable.py
  49. 2
      slither/core/variables/local_variable_init_from_tuple.py
  50. 2
      slither/core/variables/state_variable.py
  51. 2
      slither/core/variables/top_level_variable.py
  52. 2
      slither/core/variables/variable.py
  53. 4
      slither/detectors/abstract_detector.py
  54. 7
      slither/detectors/assembly/shift_parameter_mixup.py
  55. 4
      slither/detectors/attributes/const_functions_asm.py
  56. 4
      slither/detectors/attributes/const_functions_state.py
  57. 5
      slither/detectors/attributes/constant_pragma.py
  58. 9
      slither/detectors/attributes/incorrect_solc.py
  59. 8
      slither/detectors/attributes/locked_ether.py
  60. 10
      slither/detectors/attributes/unimplemented_interface.py
  61. 20
      slither/detectors/compiler_bugs/array_by_reference.py
  62. 4
      slither/detectors/compiler_bugs/multiple_constructor_schemes.py
  63. 9
      slither/detectors/compiler_bugs/public_mapping_nested.py
  64. 18
      slither/detectors/compiler_bugs/reused_base_constructor.py
  65. 12
      slither/detectors/compiler_bugs/storage_ABIEncoderV2_array.py
  66. 17
      slither/detectors/compiler_bugs/uninitialized_function_ptr_in_constructor.py
  67. 15
      slither/detectors/erc/erc20/arbitrary_send_erc20.py
  68. 12
      slither/detectors/erc/erc20/incorrect_erc20_interface.py
  69. 12
      slither/detectors/erc/incorrect_erc721_interface.py
  70. 11
      slither/detectors/erc/unindexed_event_parameters.py
  71. 4
      slither/detectors/examples/backdoor.py
  72. 12
      slither/detectors/functions/arbitrary_send_eth.py
  73. 5
      slither/detectors/functions/dead_code.py
  74. 11
      slither/detectors/functions/modifier.py
  75. 5
      slither/detectors/functions/permit_domain_signature_collision.py
  76. 6
      slither/detectors/functions/protected_variable.py
  77. 10
      slither/detectors/functions/suicidal.py
  78. 12
      slither/detectors/functions/unimplemented.py
  79. 17
      slither/detectors/naming_convention/naming_convention.py
  80. 5
      slither/detectors/operations/block_timestamp.py
  81. 14
      slither/detectors/operations/low_level_calls.py
  82. 14
      slither/detectors/operations/missing_events_access_control.py
  83. 19
      slither/detectors/operations/missing_events_arithmetic.py
  84. 22
      slither/detectors/operations/missing_zero_address_validation.py
  85. 3
      slither/detectors/operations/unchecked_low_level_return_values.py
  86. 3
      slither/detectors/operations/unchecked_send_return_value.py
  87. 3
      slither/detectors/operations/unchecked_transfer.py
  88. 14
      slither/detectors/operations/unused_return_values.py
  89. 4
      slither/detectors/operations/void_constructor.py
  90. 9
      slither/detectors/reentrancy/reentrancy_benign.py
  91. 10
      slither/detectors/reentrancy/reentrancy_events.py
  92. 14
      slither/detectors/reentrancy/reentrancy_no_gas.py
  93. 17
      slither/detectors/shadowing/builtin_symbols.py
  94. 24
      slither/detectors/shadowing/local.py
  95. 12
      slither/detectors/shadowing/state.py
  96. 10
      slither/detectors/slither/name_reused.py
  97. 5
      slither/detectors/source/rtlo.py
  98. 10
      slither/detectors/statements/array_length_assignment.py
  99. 15
      slither/detectors/statements/assembly.py
  100. 11
      slither/detectors/statements/assert_state_change.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -25,7 +25,13 @@ from slither.printers import all_printers
from slither.printers.abstract_printer import AbstractPrinter from slither.printers.abstract_printer import AbstractPrinter
from slither.slither import Slither from slither.slither import Slither
from slither.utils import codex from slither.utils import codex
from slither.utils.output import output_to_json, output_to_zip, output_to_sarif, ZIP_TYPES_ACCEPTED from slither.utils.output import (
output_to_json,
output_to_zip,
output_to_sarif,
ZIP_TYPES_ACCEPTED,
Output,
)
from slither.utils.output_capture import StandardOutputCapture from slither.utils.output_capture import StandardOutputCapture
from slither.utils.colors import red, set_colorization_enabled from slither.utils.colors import red, set_colorization_enabled
from slither.utils.command_line import ( from slither.utils.command_line import (
@ -112,7 +118,7 @@ def _process(
slither: Slither, slither: Slither,
detector_classes: List[Type[AbstractDetector]], detector_classes: List[Type[AbstractDetector]],
printer_classes: List[Type[AbstractPrinter]], printer_classes: List[Type[AbstractPrinter]],
) -> Tuple[Slither, List[Dict], List[Dict], int]: ) -> Tuple[Slither, List[Dict], List[Output], int]:
for detector_cls in detector_classes: for detector_cls in detector_classes:
slither.register_detector(detector_cls) slither.register_detector(detector_cls)
@ -125,9 +131,9 @@ def _process(
results_printers = [] results_printers = []
if not printer_classes: if not printer_classes:
detector_results = slither.run_detectors() detector_resultss = slither.run_detectors()
detector_results = [x for x in detector_results if x] # remove empty results detector_resultss = [x for x in detector_resultss if x] # remove empty results
detector_results = [item for sublist in detector_results for item in sublist] # flatten detector_results = [item for sublist in detector_resultss for item in sublist] # flatten
results_detectors.extend(detector_results) results_detectors.extend(detector_results)
else: else:

@ -4,16 +4,19 @@
from enum import Enum from enum import Enum
from typing import Optional, List, Set, Dict, Tuple, Union, TYPE_CHECKING from typing import Optional, List, Set, Dict, Tuple, Union, TYPE_CHECKING
from slither.all_exceptions import SlitherException
from slither.core.children.child_function import ChildFunction from slither.core.children.child_function import ChildFunction
from slither.core.declarations import Contract, Function
from slither.core.declarations.solidity_variables import ( from slither.core.declarations.solidity_variables import (
SolidityVariable, SolidityVariable,
SolidityFunction, SolidityFunction,
) )
from slither.core.expressions.expression import Expression
from slither.core.solidity_types import ElementaryType
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.core.solidity_types import ElementaryType
from slither.slithir.convert import convert_expression from slither.slithir.convert import convert_expression
from slither.slithir.operations import ( from slither.slithir.operations import (
HighLevelCall, HighLevelCall,
@ -38,10 +41,6 @@ from slither.slithir.variables import (
TemporaryVariable, TemporaryVariable,
TupleVariable, TupleVariable,
) )
from slither.all_exceptions import SlitherException
from slither.core.declarations import Contract, Function
from slither.core.expressions.expression import Expression
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
@ -119,7 +118,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
node_id: int, node_id: int,
scope: Union["Scope", "Function"], scope: Union["Scope", "Function"],
file_scope: "FileScope", file_scope: "FileScope",
): ) -> None:
super().__init__() super().__init__()
self._node_type = node_type self._node_type = node_type
@ -474,11 +473,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
return self._expression return self._expression
def add_expression(self, expression: Expression, bypass_verif_empty: bool = False): def add_expression(self, expression: Expression, bypass_verif_empty: bool = False) -> None:
assert self._expression is None or bypass_verif_empty assert self._expression is None or bypass_verif_empty
self._expression = expression self._expression = expression
def add_variable_declaration(self, var: LocalVariable): def add_variable_declaration(self, var: LocalVariable) -> None:
assert self._variable_declaration is None assert self._variable_declaration is None
self._variable_declaration = var self._variable_declaration = var
if var.expression: if var.expression:
@ -511,7 +510,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
for c in self.internal_calls for c in self.internal_calls
) )
def contains_if(self, include_loop=True) -> bool: def contains_if(self, include_loop: bool = True) -> bool:
""" """
Check if the node is a IF node Check if the node is a IF node
Returns: Returns:
@ -521,7 +520,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self.type in [NodeType.IF, NodeType.IFLOOP] return self.type in [NodeType.IF, NodeType.IFLOOP]
return self.type == NodeType.IF return self.type == NodeType.IF
def is_conditional(self, include_loop=True) -> bool: def is_conditional(self, include_loop: bool = True) -> bool:
""" """
Check if the node is a conditional node Check if the node is a conditional node
A conditional node is either a IF or a require/assert or a RETURN bool A conditional node is either a IF or a require/assert or a RETURN bool
@ -550,7 +549,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def inline_asm(self) -> Optional[Union[str, Dict]]: def inline_asm(self) -> Optional[Union[str, Dict]]:
return self._asm_source_code return self._asm_source_code
def add_inline_asm(self, asm: Union[str, Dict]): def add_inline_asm(self, asm: Union[str, Dict]) -> None:
self._asm_source_code = asm self._asm_source_code = asm
# endregion # endregion
@ -560,7 +559,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def add_father(self, father: "Node"): def add_father(self, father: "Node") -> None:
"""Add a father node """Add a father node
Args: Args:
@ -585,7 +584,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
return list(self._fathers) return list(self._fathers)
def remove_father(self, father: "Node"): def remove_father(self, father: "Node") -> None:
"""Remove the father node. Do nothing if the node is not a father """Remove the father node. Do nothing if the node is not a father
Args: Args:
@ -593,7 +592,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._fathers = [x for x in self._fathers if x.node_id != father.node_id] self._fathers = [x for x in self._fathers if x.node_id != father.node_id]
def remove_son(self, son: "Node"): def remove_son(self, son: "Node") -> None:
"""Remove the son node. Do nothing if the node is not a son """Remove the son node. Do nothing if the node is not a son
Args: Args:
@ -601,7 +600,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._sons = [x for x in self._sons if x.node_id != son.node_id] self._sons = [x for x in self._sons if x.node_id != son.node_id]
def add_son(self, son: "Node"): def add_son(self, son: "Node") -> None:
"""Add a son node """Add a son node
Args: Args:
@ -609,7 +608,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._sons.append(son) self._sons.append(son)
def set_sons(self, sons: List["Node"]): def set_sons(self, sons: List["Node"]) -> None:
"""Set the son nodes """Set the son nodes
Args: Args:
@ -667,14 +666,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def irs_ssa(self, irs): def irs_ssa(self, irs):
self._irs_ssa = irs self._irs_ssa = irs
def add_ssa_ir(self, ir: Operation): def add_ssa_ir(self, ir: Operation) -> None:
""" """
Use to place phi operation Use to place phi operation
""" """
ir.set_node(self) ir.set_node(self)
self._irs_ssa.append(ir) self._irs_ssa.append(ir)
def slithir_generation(self): def slithir_generation(self) -> None:
if self.expression: if self.expression:
expression = self.expression expression = self.expression
self._irs = convert_expression(expression, self) self._irs = convert_expression(expression, self)
@ -691,11 +690,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self._all_slithir_operations return self._all_slithir_operations
@staticmethod @staticmethod
def _is_non_slithir_var(var: Variable): def _is_non_slithir_var(var: Variable) -> bool:
return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable)) return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable))
@staticmethod @staticmethod
def _is_valid_slithir_var(var: Variable): def _is_valid_slithir_var(var: Variable) -> bool:
return isinstance(var, (ReferenceVariable, TemporaryVariable, TupleVariable)) return isinstance(var, (ReferenceVariable, TemporaryVariable, TupleVariable))
# endregion # endregion
@ -746,7 +745,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._dominance_frontier = doms self._dominance_frontier = doms
@property @property
def dominator_successors(self): def dominator_successors(self) -> Set["Node"]:
return self._dom_successors return self._dom_successors
@property @property
@ -788,14 +787,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
# def phi_origin_member_variables(self) -> Dict[str, Tuple[MemberVariable, Set["Node"]]]: # def phi_origin_member_variables(self) -> Dict[str, Tuple[MemberVariable, Set["Node"]]]:
# return self._phi_origins_member_variables # return self._phi_origins_member_variables
def add_phi_origin_local_variable(self, variable: LocalVariable, node: "Node"): def add_phi_origin_local_variable(self, variable: LocalVariable, node: "Node") -> None:
if variable.name not in self._phi_origins_local_variables: if variable.name not in self._phi_origins_local_variables:
self._phi_origins_local_variables[variable.name] = (variable, set()) self._phi_origins_local_variables[variable.name] = (variable, set())
(v, nodes) = self._phi_origins_local_variables[variable.name] (v, nodes) = self._phi_origins_local_variables[variable.name]
assert v == variable assert v == variable
nodes.add(node) nodes.add(node)
def add_phi_origin_state_variable(self, variable: StateVariable, node: "Node"): def add_phi_origin_state_variable(self, variable: StateVariable, node: "Node") -> None:
if variable.canonical_name not in self._phi_origins_state_variables: if variable.canonical_name not in self._phi_origins_state_variables:
self._phi_origins_state_variables[variable.canonical_name] = ( self._phi_origins_state_variables[variable.canonical_name] = (
variable, variable,
@ -819,7 +818,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _find_read_write_call(self): # pylint: disable=too-many-statements def _find_read_write_call(self) -> None: # pylint: disable=too-many-statements
for ir in self.irs: for ir in self.irs:
@ -895,7 +894,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._low_level_calls = list(set(self._low_level_calls)) self._low_level_calls = list(set(self._low_level_calls))
@staticmethod @staticmethod
def _convert_ssa(v: Variable): def _convert_ssa(v: Variable) -> Optional[Union[StateVariable, LocalVariable]]:
if isinstance(v, StateIRVariable): if isinstance(v, StateIRVariable):
contract = v.contract contract = v.contract
non_ssa_var = contract.get_state_variable_from_name(v.name) non_ssa_var = contract.get_state_variable_from_name(v.name)
@ -905,7 +904,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
non_ssa_var = function.get_local_variable_from_name(v.name) non_ssa_var = function.get_local_variable_from_name(v.name)
return non_ssa_var return non_ssa_var
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
if not self.expression: if not self.expression:
return return
for ir in self.irs_ssa: for ir in self.irs_ssa:
@ -969,7 +968,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __str__(self): def __str__(self) -> str:
additional_info = "" additional_info = ""
if self.expression: if self.expression:
additional_info += " " + str(self.expression) additional_info += " " + str(self.expression)
@ -987,12 +986,12 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
def link_nodes(node1: Node, node2: Node): def link_nodes(node1: Node, node2: Node) -> None:
node1.add_son(node2) node1.add_son(node2)
node2.add_father(node1) node2.add_father(node1)
def insert_node(origin: Node, node_inserted: Node): def insert_node(origin: Node, node_inserted: Node) -> None:
sons = origin.sons sons = origin.sons
link_nodes(origin, node_inserted) link_nodes(origin, node_inserted)
for son in sons: for son in sons:

@ -7,7 +7,7 @@ if TYPE_CHECKING:
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class Scope: class Scope:
def __init__(self, is_checked: bool, is_yul: bool, scope: Union["Scope", "Function"]): def __init__(self, is_checked: bool, is_yul: bool, scope: Union["Scope", "Function"]) -> None:
self.nodes: List["Node"] = [] self.nodes: List["Node"] = []
self.is_checked = is_checked self.is_checked = is_checked
self.is_yul = is_yul self.is_yul = is_yul

@ -7,11 +7,11 @@ if TYPE_CHECKING:
class ChildContract(SourceMapping): class ChildContract(SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._contract = None self._contract = None
def set_contract(self, contract: "Contract"): def set_contract(self, contract: "Contract") -> None:
self._contract = contract self._contract = contract
@property @property

@ -5,7 +5,7 @@ if TYPE_CHECKING:
class ChildEvent: class ChildEvent:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._event = None self._event = None

@ -1,17 +1,18 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Union
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.slithir.operations import Operation
class ChildExpression: class ChildExpression:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._expression = None self._expression = None
def set_expression(self, expression: "Expression"): def set_expression(self, expression: Union["Expression", "Operation"]) -> None:
self._expression = expression self._expression = expression
@property @property
def expression(self) -> "Expression": def expression(self) -> Union["Expression", "Operation"]:
return self._expression return self._expression

@ -5,11 +5,11 @@ if TYPE_CHECKING:
class ChildInheritance: class ChildInheritance:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._contract_declarer = None self._contract_declarer = None
def set_contract_declarer(self, contract: "Contract"): def set_contract_declarer(self, contract: "Contract") -> None:
self._contract_declarer = contract self._contract_declarer = contract
@property @property

@ -7,11 +7,11 @@ if TYPE_CHECKING:
class ChildNode: class ChildNode:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._node = None self._node = None
def set_node(self, node: "Node"): def set_node(self, node: "Node") -> None:
self._node = node self._node = node
@property @property

@ -5,11 +5,11 @@ if TYPE_CHECKING:
class ChildStructure: class ChildStructure:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._structure = None self._structure = None
def set_structure(self, structure: "Structure"): def set_structure(self, structure: "Structure") -> None:
self._structure = structure self._structure = structure
@property @property

@ -16,10 +16,10 @@ from slither.core.declarations import (
from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error import CustomError
from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.using_for_top_level import UsingForTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel
from slither.core.solidity_types.type_alias import TypeAliasTopLevel from slither.core.declarations.using_for_top_level import UsingForTopLevel
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.top_level_variable import TopLevelVariable from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.operations import InternalCall from slither.slithir.operations import InternalCall
@ -31,7 +31,7 @@ if TYPE_CHECKING:
# pylint: disable=too-many-instance-attributes,too-many-public-methods # pylint: disable=too-many-instance-attributes,too-many-public-methods
class SlitherCompilationUnit(Context): class SlitherCompilationUnit(Context):
def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit): def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
super().__init__() super().__init__()
self._core = core self._core = core
@ -150,21 +150,21 @@ class SlitherCompilationUnit(Context):
def functions(self) -> List[Function]: def functions(self) -> List[Function]:
return list(self._all_functions) return list(self._all_functions)
def add_function(self, func: Function): def add_function(self, func: Function) -> None:
self._all_functions.add(func) self._all_functions.add(func)
@property @property
def modifiers(self) -> List[Modifier]: def modifiers(self) -> List[Modifier]:
return list(self._all_modifiers) return list(self._all_modifiers)
def add_modifier(self, modif: Modifier): def add_modifier(self, modif: Modifier) -> None:
self._all_modifiers.add(modif) self._all_modifiers.add(modif)
@property @property
def functions_and_modifiers(self) -> List[Function]: def functions_and_modifiers(self) -> List[Function]:
return self.functions + self.modifiers return self.functions + self.modifiers
def propagate_function_calls(self): def propagate_function_calls(self) -> None:
for f in self.functions_and_modifiers: for f in self.functions_and_modifiers:
for node in f.nodes: for node in f.nodes:
for ir in node.irs_ssa: for ir in node.irs_ssa:
@ -256,7 +256,7 @@ class SlitherCompilationUnit(Context):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def compute_storage_layout(self): def compute_storage_layout(self) -> None:
for contract in self.contracts_derived: for contract in self.contracts_derived:
self._storage_layouts[contract.name] = {} self._storage_layouts[contract.name] = {}

@ -17,3 +17,4 @@ from .structure_contract import StructureContract
from .structure_top_level import StructureTopLevel from .structure_top_level import StructureTopLevel
from .function_contract import FunctionContract from .function_contract import FunctionContract
from .function_top_level import FunctionTopLevel from .function_top_level import FunctionTopLevel
from .custom_error_contract import CustomErrorContract

@ -4,7 +4,7 @@
import logging import logging
from collections import defaultdict from collections import defaultdict
from pathlib import Path from pathlib import Path
from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set, Any
from crytic_compile.platform import Type as PlatformType from crytic_compile.platform import Type as PlatformType
@ -38,13 +38,13 @@ if TYPE_CHECKING:
EnumContract, EnumContract,
StructureContract, StructureContract,
FunctionContract, FunctionContract,
CustomErrorContract,
) )
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
from slither.core.variables.variable import Variable from slither.core.variables import Variable, StateVariable
from slither.core.variables.state_variable import StateVariable
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations.custom_error_contract import CustomErrorContract
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.core.cfg.node import Node
LOGGER = logging.getLogger("Contract") LOGGER = logging.getLogger("Contract")
@ -55,7 +55,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
Contract class Contract class
""" """
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__() super().__init__()
self._name: Optional[str] = None self._name: Optional[str] = None
@ -366,7 +366,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
""" """
return list(self._variables_ordered) return list(self._variables_ordered)
def add_variables_ordered(self, new_vars: List["StateVariable"]): def add_variables_ordered(self, new_vars: List["StateVariable"]) -> None:
self._variables_ordered += new_vars self._variables_ordered += new_vars
@property @property
@ -534,7 +534,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def add_function(self, func: "FunctionContract"): def add_function(self, func: "FunctionContract"):
self._functions[func.canonical_name] = func self._functions[func.canonical_name] = func
def set_functions(self, functions: Dict[str, "FunctionContract"]): def set_functions(self, functions: Dict[str, "FunctionContract"]) -> None:
""" """
Set the functions Set the functions
@ -578,7 +578,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]: def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]:
return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed} return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
def set_modifiers(self, modifiers: Dict[str, "Modifier"]): def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
""" """
Set the modifiers Set the modifiers
@ -688,7 +688,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
inheritance: List["Contract"], inheritance: List["Contract"],
immediate_inheritance: List["Contract"], immediate_inheritance: List["Contract"],
called_base_constructor_contracts: List["Contract"], called_base_constructor_contracts: List["Contract"],
): ) -> None:
self._inheritance = inheritance self._inheritance = inheritance
self._immediate_inheritance = immediate_inheritance self._immediate_inheritance = immediate_inheritance
self._explicit_base_constructor_calls = called_base_constructor_contracts self._explicit_base_constructor_calls = called_base_constructor_contracts
@ -803,23 +803,25 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
""" """
return next((v for v in self.state_variables if v.name == canonical_name), None) return next((v for v in self.state_variables if v.name == canonical_name), None)
def get_structure_from_name(self, structure_name: str) -> Optional["Structure"]: def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
""" """
Return a structure from a name Return a structure from a name
Args: Args:
structure_name (str): name of the structure structure_name (str): name of the structure
Returns: Returns:
Structure StructureContract
""" """
return next((st for st in self.structures if st.name == structure_name), None) return next((st for st in self.structures if st.name == structure_name), None)
def get_structure_from_canonical_name(self, structure_name: str) -> Optional["Structure"]: def get_structure_from_canonical_name(
self, structure_name: str
) -> Optional["StructureContract"]:
""" """
Return a structure from a canonical name Return a structure from a canonical name
Args: Args:
structure_name (str): canonical name of the structure structure_name (str): canonical name of the structure
Returns: Returns:
Structure StructureContract
""" """
return next((st for st in self.structures if st.canonical_name == structure_name), None) return next((st for st in self.structures if st.canonical_name == structure_name), None)
@ -1216,7 +1218,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
for function in self.functions + self.modifiers: for function in self.functions + self.modifiers:
function.update_read_write_using_ssa() function.update_read_write_using_ssa()
@ -1311,7 +1313,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def is_incorrectly_constructed(self, incorrect: bool): def is_incorrectly_constructed(self, incorrect: bool):
self._is_incorrectly_parsed = incorrect self._is_incorrectly_parsed = incorrect
def add_constructor_variables(self): def add_constructor_variables(self) -> None:
from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.function_contract import FunctionContract
if self.state_variables: if self.state_variables:
@ -1380,7 +1382,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def _create_node( def _create_node(
self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function] self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
): ) -> "Node":
from slither.core.cfg.node import Node, NodeType from slither.core.cfg.node import Node, NodeType
from slither.core.expressions import ( from slither.core.expressions import (
AssignmentOperationType, AssignmentOperationType,
@ -1412,7 +1414,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def convert_expression_to_slithir_ssa(self): def convert_expression_to_slithir_ssa(self) -> None:
""" """
Assume generate_slithir_and_analyze was called on all functions Assume generate_slithir_and_analyze was called on all functions
@ -1437,7 +1439,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
for func in self.functions + self.modifiers: for func in self.functions + self.modifiers:
func.generate_slithir_ssa(all_ssa_state_variables_instances) func.generate_slithir_ssa(all_ssa_state_variables_instances)
def fix_phi(self): def fix_phi(self) -> None:
last_state_variables_instances = {} last_state_variables_instances = {}
initial_state_variables_instances = {} initial_state_variables_instances = {}
for v in self._initial_state_variables: for v in self._initial_state_variables:
@ -1459,20 +1461,20 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __eq__(self, other): def __eq__(self, other: SourceMapping) -> bool:
if isinstance(other, str): if isinstance(other, str):
return other == self.name return other == self.name
return NotImplemented return NotImplemented
def __neq__(self, other): def __neq__(self, other: Any) -> bool:
if isinstance(other, str): if isinstance(other, str):
return other != self.name return other != self.name
return NotImplemented return NotImplemented
def __str__(self): def __str__(self) -> str:
return self.name return self.name
def __hash__(self): def __hash__(self) -> int:
return self._id return self._id
# endregion # endregion

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class CustomError(SourceMapping): class CustomError(SourceMapping):
def __init__(self, compilation_unit: "SlitherCompilationUnit"): def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__() super().__init__()
self._name: str = "" self._name: str = ""
self._parameters: List[LocalVariable] = [] self._parameters: List[LocalVariable] = []
@ -30,7 +30,7 @@ class CustomError(SourceMapping):
def parameters(self) -> List[LocalVariable]: def parameters(self) -> List[LocalVariable]:
return self._parameters return self._parameters
def add_parameters(self, p: "LocalVariable"): def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p) self._parameters.append(p)
@property @property
@ -42,7 +42,7 @@ class CustomError(SourceMapping):
################################################################################### ###################################################################################
@staticmethod @staticmethod
def _convert_type_for_solidity_signature(t: Optional[Union[Type, List[Type]]]): def _convert_type_for_solidity_signature(t: Optional[Union[Type, List[Type]]]) -> str:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.core.declarations import Contract from slither.core.declarations import Contract
@ -92,5 +92,5 @@ class CustomError(SourceMapping):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __str__(self): def __str__(self) -> str:
return "revert " + self.solidity_signature return "revert " + self.solidity_signature

@ -4,7 +4,7 @@ from slither.core.source_mapping.source_mapping import SourceMapping
class Enum(SourceMapping): class Enum(SourceMapping):
def __init__(self, name: str, canonical_name: str, values: List[str]): def __init__(self, name: str, canonical_name: str, values: List[str]) -> None:
super().__init__() super().__init__()
self._name = name self._name = name
self._canonical_name = canonical_name self._canonical_name = canonical_name
@ -33,5 +33,5 @@ class Enum(SourceMapping):
def max(self) -> int: def max(self) -> int:
return self._max return self._max
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -8,6 +8,8 @@ if TYPE_CHECKING:
class EnumTopLevel(Enum, TopLevel): class EnumTopLevel(Enum, TopLevel):
def __init__(self, name: str, canonical_name: str, values: List[str], scope: "FileScope"): def __init__(
self, name: str, canonical_name: str, values: List[str], scope: "FileScope"
) -> None:
super().__init__(name, canonical_name, values) super().__init__(name, canonical_name, values)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class Event(ChildContract, SourceMapping): class Event(ChildContract, SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._name = None self._name = None
self._elems: List[EventVariable] = [] self._elems: List[EventVariable] = []
@ -59,5 +59,5 @@ class Event(ChildContract, SourceMapping):
""" """
return self.contract == contract return self.contract == contract
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -6,7 +6,7 @@ from abc import abstractmethod, ABCMeta
from collections import namedtuple from collections import namedtuple
from enum import Enum from enum import Enum
from itertools import groupby from itertools import groupby
from typing import Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple from typing import Any, Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple
from slither.core.cfg.scope import Scope from slither.core.cfg.scope import Scope
from slither.core.declarations.solidity_variables import ( from slither.core.declarations.solidity_variables import (
@ -27,6 +27,7 @@ from slither.core.variables.state_variable import StateVariable
from slither.utils.type import convert_type_for_solidity_signature_to_string from slither.utils.type import convert_type_for_solidity_signature_to_string
from slither.utils.utils import unroll from slither.utils.utils import unroll
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines # pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING: if TYPE_CHECKING:
@ -45,6 +46,8 @@ if TYPE_CHECKING:
from slither.slithir.operations import Operation from slither.slithir.operations import Operation
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
from slither.core.declarations.function_contract import FunctionContract
LOGGER = logging.getLogger("Function") LOGGER = logging.getLogger("Function")
ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"]) ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
@ -56,7 +59,7 @@ class ModifierStatements:
modifier: Union["Contract", "Function"], modifier: Union["Contract", "Function"],
entry_point: "Node", entry_point: "Node",
nodes: List["Node"], nodes: List["Node"],
): ) -> None:
self._modifier = modifier self._modifier = modifier
self._entry_point = entry_point self._entry_point = entry_point
self._nodes = nodes self._nodes = nodes
@ -116,7 +119,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
Function class Function class
""" """
def __init__(self, compilation_unit: "SlitherCompilationUnit"): def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__() super().__init__()
self._internal_scope: List[str] = [] self._internal_scope: List[str] = []
self._name: Optional[str] = None self._name: Optional[str] = None
@ -295,7 +298,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def contains_assembly(self, c: bool): def contains_assembly(self, c: bool):
self._contains_assembly = c self._contains_assembly = c
def can_reenter(self, callstack=None) -> bool: def can_reenter(self, callstack: Optional[List["FunctionContract"]] = None) -> bool:
""" """
Check if the function can re-enter Check if the function can re-enter
Follow internal calls. Follow internal calls.
@ -370,7 +373,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def set_function_type(self, t: FunctionType): def set_function_type(self, t: FunctionType) -> None:
assert isinstance(t, FunctionType) assert isinstance(t, FunctionType)
self._function_type = t self._function_type = t
@ -455,7 +458,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def visibility(self, v: str): def visibility(self, v: str):
self._visibility = v self._visibility = v
def set_visibility(self, v: str): def set_visibility(self, v: str) -> None:
self._visibility = v self._visibility = v
@property @property
@ -554,7 +557,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def entry_point(self, node: "Node"): def entry_point(self, node: "Node"):
self._entry_point = node self._entry_point = node
def add_node(self, node: "Node"): def add_node(self, node: "Node") -> None:
if not self._entry_point: if not self._entry_point:
self._entry_point = node self._entry_point = node
self._nodes.append(node) self._nodes.append(node)
@ -598,7 +601,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._parameters) return list(self._parameters)
def add_parameters(self, p: "LocalVariable"): def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p) self._parameters.append(p)
@property @property
@ -608,7 +611,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._parameters_ssa) return list(self._parameters_ssa)
def add_parameter_ssa(self, var: "LocalIRVariable"): def add_parameter_ssa(self, var: "LocalIRVariable") -> None:
self._parameters_ssa.append(var) self._parameters_ssa.append(var)
def parameters_src(self) -> SourceMapping: def parameters_src(self) -> SourceMapping:
@ -651,7 +654,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._returns) return list(self._returns)
def add_return(self, r: "LocalVariable"): def add_return(self, r: "LocalVariable") -> None:
self._returns.append(r) self._returns.append(r)
@property @property
@ -661,7 +664,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._returns_ssa) return list(self._returns_ssa)
def add_return_ssa(self, var: "LocalIRVariable"): def add_return_ssa(self, var: "LocalIRVariable") -> None:
self._returns_ssa.append(var) self._returns_ssa.append(var)
# endregion # endregion
@ -680,7 +683,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return [c.modifier for c in self._modifiers] return [c.modifier for c in self._modifiers]
def add_modifier(self, modif: "ModifierStatements"): def add_modifier(self, modif: "ModifierStatements") -> None:
self._modifiers.append(modif) self._modifiers.append(modif)
@property @property
@ -714,7 +717,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
# This is a list of contracts internally, so we convert it to a list of constructor functions. # This is a list of contracts internally, so we convert it to a list of constructor functions.
return list(self._explicit_base_constructor_calls) return list(self._explicit_base_constructor_calls)
def add_explicit_base_constructor_calls_statements(self, modif: ModifierStatements): def add_explicit_base_constructor_calls_statements(self, modif: ModifierStatements) -> None:
self._explicit_base_constructor_calls.append(modif) self._explicit_base_constructor_calls.append(modif)
# endregion # endregion
@ -1057,7 +1060,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
self._all_reachable_from_functions = functions self._all_reachable_from_functions = functions
return self._all_reachable_from_functions return self._all_reachable_from_functions
def add_reachable_from_node(self, n: "Node", ir: "Operation"): def add_reachable_from_node(self, n: "Node", ir: "Operation") -> None:
self._reachable_from_nodes.add(ReacheableNode(n, ir)) self._reachable_from_nodes.add(ReacheableNode(n, ir))
self._reachable_from_functions.add(n.function) self._reachable_from_functions.add(n.function)
@ -1068,7 +1071,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _explore_functions(self, f_new_values: Callable[["Function"], List]): def _explore_functions(self, f_new_values: Callable[["Function"], List]) -> List[Any]:
values = f_new_values(self) values = f_new_values(self)
explored = [self] explored = [self]
to_explore = [ to_explore = [
@ -1218,11 +1221,13 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
func: "Function", func: "Function",
f: Callable[["Node"], List[SolidityVariable]], f: Callable[["Node"], List[SolidityVariable]],
include_loop: bool, include_loop: bool,
): ) -> List[Any]:
ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)] ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
def all_conditional_solidity_variables_read(self, include_loop=True) -> List[SolidityVariable]: def all_conditional_solidity_variables_read(
self, include_loop: bool = True
) -> List[SolidityVariable]:
""" """
Return the Soldiity variables directly used in a condtion Return the Soldiity variables directly used in a condtion
@ -1258,7 +1263,9 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return [var for var in ret if isinstance(var, SolidityVariable)] return [var for var in ret if isinstance(var, SolidityVariable)]
@staticmethod @staticmethod
def _explore_func_nodes(func: "Function", f: Callable[["Node"], List[SolidityVariable]]): def _explore_func_nodes(
func: "Function", f: Callable[["Node"], List[SolidityVariable]]
) -> List[Union[Any, SolidityVariableComposed]]:
ret = [f(n) for n in func.nodes] ret = [f(n) for n in func.nodes]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
@ -1367,7 +1374,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
with open(filename, "w", encoding="utf8") as f: with open(filename, "w", encoding="utf8") as f:
f.write(content) f.write(content)
def slithir_cfg_to_dot_str(self, skip_expressions=False) -> str: def slithir_cfg_to_dot_str(self, skip_expressions: bool = False) -> str:
""" """
Export the CFG to a DOT format. The nodes includes the Solidity expressions and the IRs Export the CFG to a DOT format. The nodes includes the Solidity expressions and the IRs
:return: the DOT content :return: the DOT content
@ -1512,7 +1519,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _analyze_read_write(self): def _analyze_read_write(self) -> None:
"""Compute variables read/written/...""" """Compute variables read/written/..."""
write_var = [x.variables_written_as_expression for x in self.nodes] write_var = [x.variables_written_as_expression for x in self.nodes]
write_var = [x for x in write_var if x] write_var = [x for x in write_var if x]
@ -1570,7 +1577,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
slithir_variables = [x for x in slithir_variables if x] slithir_variables = [x for x in slithir_variables if x]
self._slithir_variables = [item for sublist in slithir_variables for item in sublist] self._slithir_variables = [item for sublist in slithir_variables for item in sublist]
def _analyze_calls(self): def _analyze_calls(self) -> None:
calls = [x.calls_as_expression for x in self.nodes] calls = [x.calls_as_expression for x in self.nodes]
calls = [x for x in calls if x] calls = [x for x in calls if x]
calls = [item for sublist in calls for item in sublist] calls = [item for sublist in calls for item in sublist]
@ -1702,7 +1709,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return self._get_last_ssa_variable_instances(target_state=False, target_local=True) return self._get_last_ssa_variable_instances(target_state=False, target_local=True)
@staticmethod @staticmethod
def _unchange_phi(ir: "Operation"): def _unchange_phi(ir: "Operation") -> bool:
from slither.slithir.operations import Phi, PhiCallback from slither.slithir.operations import Phi, PhiCallback
if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1: if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1:
@ -1711,7 +1718,13 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return True return True
return ir.rvalues[0] == ir.lvalue return ir.rvalues[0] == ir.lvalue
def fix_phi(self, last_state_variables_instances, initial_state_variables_instances): def fix_phi(
self,
last_state_variables_instances: Dict[
str, Union[List[Any], List[Union[Any, "StateIRVariable"]], List["StateIRVariable"]]
],
initial_state_variables_instances: Dict[str, "StateIRVariable"],
) -> None:
from slither.slithir.operations import InternalCall, PhiCallback from slither.slithir.operations import InternalCall, PhiCallback
from slither.slithir.variables import Constant, StateIRVariable from slither.slithir.variables import Constant, StateIRVariable
@ -1745,7 +1758,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)] node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)]
def generate_slithir_and_analyze(self): def generate_slithir_and_analyze(self) -> None:
for node in self.nodes: for node in self.nodes:
node.slithir_generation() node.slithir_generation()
@ -1756,7 +1769,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(self, all_ssa_state_variables_instances):
pass pass
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
for node in self.nodes: for node in self.nodes:
node.update_read_write_using_ssa() node.update_read_write_using_ssa()
self._analyze_read_write() self._analyze_read_write()
@ -1767,7 +1780,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __str__(self): def __str__(self) -> str:
return self.name return self.name
# endregion # endregion

@ -1,17 +1,19 @@
""" """
Function module Function module
""" """
from typing import TYPE_CHECKING, List, Tuple from typing import Dict, TYPE_CHECKING, List, Tuple
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance from slither.core.children.child_inheritance import ChildInheritance
from slither.core.declarations import Function from slither.core.declarations import Function
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines # pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations import Contract from slither.core.declarations import Contract
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
class FunctionContract(Function, ChildContract, ChildInheritance): class FunctionContract(Function, ChildContract, ChildInheritance):
@ -96,7 +98,9 @@ class FunctionContract(Function, ChildContract, ChildInheritance):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(
self, all_ssa_state_variables_instances: Dict[str, "StateIRVariable"]
) -> None:
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import ( from slither.core.dominators.utils import (
compute_dominance_frontier, compute_dominance_frontier,

@ -1,7 +1,7 @@
""" """
Function module Function module
""" """
from typing import List, Tuple, TYPE_CHECKING from typing import Dict, List, Tuple, TYPE_CHECKING
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.declarations.top_level import TopLevel from slither.core.declarations.top_level import TopLevel
@ -9,10 +9,11 @@ from slither.core.declarations.top_level import TopLevel
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
class FunctionTopLevel(Function, TopLevel): class FunctionTopLevel(Function, TopLevel):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__(compilation_unit) super().__init__(compilation_unit)
self._scope: "FileScope" = scope self._scope: "FileScope" = scope
@ -78,7 +79,9 @@ class FunctionTopLevel(Function, TopLevel):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(
self, all_ssa_state_variables_instances: Dict[str, "StateIRVariable"]
) -> None:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import ( from slither.core.dominators.utils import (

@ -8,7 +8,7 @@ if TYPE_CHECKING:
class Import(SourceMapping): class Import(SourceMapping):
def __init__(self, filename: Path, scope: "FileScope"): def __init__(self, filename: Path, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._filename: Path = filename self._filename: Path = filename
self._alias: Optional[str] = None self._alias: Optional[str] = None

@ -7,7 +7,7 @@ if TYPE_CHECKING:
class Pragma(SourceMapping): class Pragma(SourceMapping):
def __init__(self, directive: List[str], scope: "FileScope"): def __init__(self, directive: List[str], scope: "FileScope") -> None:
super().__init__() super().__init__()
self._directive = directive self._directive = directive
self.scope: "FileScope" = scope self.scope: "FileScope" = scope
@ -39,5 +39,5 @@ class Pragma(SourceMapping):
return self._directive[0] == "experimental" and self._directive[1] == "ABIEncoderV2" return self._directive[0] == "experimental" and self._directive[1] == "ABIEncoderV2"
return False return False
def __str__(self): def __str__(self) -> str:
return "pragma " + "".join(self.directive) return "pragma " + "".join(self.directive)

@ -1,7 +1,11 @@
""" """
Special variable to model import with renaming Special variable to model import with renaming
""" """
from typing import Union
from slither.core.declarations import Import from slither.core.declarations import Import
from slither.core.declarations.contract import Contract
from slither.core.declarations.solidity_variables import SolidityVariable
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
@ -13,7 +17,7 @@ class SolidityImportPlaceHolder(Variable):
In the long term we should remove this and better integrate import aliases In the long term we should remove this and better integrate import aliases
""" """
def __init__(self, import_directive: Import): def __init__(self, import_directive: Import) -> None:
super().__init__() super().__init__()
assert import_directive.alias is not None assert import_directive.alias is not None
self._import_directive = import_directive self._import_directive = import_directive
@ -27,7 +31,7 @@ class SolidityImportPlaceHolder(Variable):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType("string") return ElementaryType("string")
def __eq__(self, other): def __eq__(self, other: Union[Contract, SolidityVariable]) -> bool:
return ( return (
self.__class__ == other.__class__ self.__class__ == other.__class__
and self._import_directive.filename == self._import_directive.filename and self._import_directive.filename == self._import_directive.filename

@ -1,13 +1,11 @@
# https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html # https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
from typing import List, Dict, Union, TYPE_CHECKING from typing import List, Dict, Union, Any
from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error import CustomError
from slither.core.solidity_types import ElementaryType, TypeInformation from slither.core.solidity_types import ElementaryType, TypeInformation
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.exceptions import SlitherException from slither.exceptions import SlitherException
if TYPE_CHECKING:
pass
SOLIDITY_VARIABLES = { SOLIDITY_VARIABLES = {
"now": "uint256", "now": "uint256",
@ -98,13 +96,13 @@ def solidity_function_signature(name):
class SolidityVariable(SourceMapping): class SolidityVariable(SourceMapping):
def __init__(self, name: str): def __init__(self, name: str) -> None:
super().__init__() super().__init__()
self._check_name(name) self._check_name(name)
self._name = name self._name = name
# dev function, will be removed once the code is stable # dev function, will be removed once the code is stable
def _check_name(self, name: str): # pylint: disable=no-self-use def _check_name(self, name: str) -> None: # pylint: disable=no-self-use
assert name in SOLIDITY_VARIABLES or name.endswith(("_slot", "_offset")) assert name in SOLIDITY_VARIABLES or name.endswith(("_slot", "_offset"))
@property @property
@ -124,18 +122,18 @@ class SolidityVariable(SourceMapping):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES[self.name]) return ElementaryType(SOLIDITY_VARIABLES[self.name])
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: SourceMapping) -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
class SolidityVariableComposed(SolidityVariable): class SolidityVariableComposed(SolidityVariable):
def _check_name(self, name: str): def _check_name(self, name: str) -> None:
assert name in SOLIDITY_VARIABLES_COMPOSED assert name in SOLIDITY_VARIABLES_COMPOSED
@property @property
@ -146,13 +144,13 @@ class SolidityVariableComposed(SolidityVariable):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES_COMPOSED[self.name]) return ElementaryType(SOLIDITY_VARIABLES_COMPOSED[self.name])
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
@ -162,7 +160,7 @@ class SolidityFunction(SourceMapping):
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
# As a result, we set return_type during the Ir conversion # As a result, we set return_type during the Ir conversion
def __init__(self, name: str): def __init__(self, name: str) -> None:
super().__init__() super().__init__()
assert name in SOLIDITY_FUNCTIONS assert name in SOLIDITY_FUNCTIONS
self._name = name self._name = name
@ -187,28 +185,28 @@ class SolidityFunction(SourceMapping):
def return_type(self, r: List[Union[TypeInformation, ElementaryType]]): def return_type(self, r: List[Union[TypeInformation, ElementaryType]]):
self._return_type = r self._return_type = r
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: "SolidityFunction") -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
class SolidityCustomRevert(SolidityFunction): class SolidityCustomRevert(SolidityFunction):
def __init__(self, custom_error: CustomError): # pylint: disable=super-init-not-called def __init__(self, custom_error: CustomError) -> None: # pylint: disable=super-init-not-called
self._name = "revert " + custom_error.solidity_signature self._name = "revert " + custom_error.solidity_signature
self._custom_error = custom_error self._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = [] self._return_type: List[Union[TypeInformation, ElementaryType]] = []
def __eq__(self, other): def __eq__(self, other: Union["SolidityCustomRevert", SolidityFunction]) -> bool:
return ( return (
self.__class__ == other.__class__ self.__class__ == other.__class__
and self.name == other.name and self.name == other.name
and self._custom_error == other._custom_error and self._custom_error == other._custom_error
) )
def __hash__(self): def __hash__(self) -> int:
return hash(hash(self.name) + hash(self._custom_error)) return hash(hash(self.name) + hash(self._custom_error))

@ -9,6 +9,6 @@ if TYPE_CHECKING:
class StructureTopLevel(Structure, TopLevel): class StructureTopLevel(Structure, TopLevel):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__(compilation_unit) super().__init__(compilation_unit)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope

@ -8,11 +8,11 @@ if TYPE_CHECKING:
class UsingForTopLevel(TopLevel): class UsingForTopLevel(TopLevel):
def __init__(self, scope: "FileScope"): def __init__(self, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._using_for: Dict[Union[str, Type], List[Type]] = {} self._using_for: Dict[Union[str, Type], List[Type]] = {}
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope
@property @property
def using_for(self) -> Dict[Type, List[Type]]: def using_for(self) -> Dict[Union[str, Type], List[Type]]:
return self._using_for return self._using_for

@ -1,4 +1,4 @@
from typing import List, TYPE_CHECKING from typing import Set, List, TYPE_CHECKING
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
@ -6,7 +6,7 @@ if TYPE_CHECKING:
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
def intersection_predecessor(node: "Node"): def intersection_predecessor(node: "Node") -> Set["Node"]:
if not node.fathers: if not node.fathers:
return set() return set()
ret = node.fathers[0].dominators ret = node.fathers[0].dominators
@ -15,7 +15,7 @@ def intersection_predecessor(node: "Node"):
return ret return ret
def _compute_dominators(nodes: List["Node"]): def _compute_dominators(nodes: List["Node"]) -> None:
changed = True changed = True
while changed: while changed:
@ -28,7 +28,7 @@ def _compute_dominators(nodes: List["Node"]):
changed = True changed = True
def _compute_immediate_dominators(nodes: List["Node"]): def _compute_immediate_dominators(nodes: List["Node"]) -> None:
for node in nodes: for node in nodes:
idom_candidates = set(node.dominators) idom_candidates = set(node.dominators)
idom_candidates.remove(node) idom_candidates.remove(node)
@ -58,7 +58,7 @@ def _compute_immediate_dominators(nodes: List["Node"]):
idom.dominator_successors.add(node) idom.dominator_successors.add(node)
def compute_dominators(nodes: List["Node"]): def compute_dominators(nodes: List["Node"]) -> None:
""" """
Naive implementation of Cooper, Harvey, Kennedy algo Naive implementation of Cooper, Harvey, Kennedy algo
See 'A Simple,Fast Dominance Algorithm' See 'A Simple,Fast Dominance Algorithm'
@ -74,7 +74,7 @@ def compute_dominators(nodes: List["Node"]):
_compute_immediate_dominators(nodes) _compute_immediate_dominators(nodes)
def compute_dominance_frontier(nodes: List["Node"]): def compute_dominance_frontier(nodes: List["Node"]) -> None:
""" """
Naive implementation of Cooper, Harvey, Kennedy algo Naive implementation of Cooper, Harvey, Kennedy algo
See 'A Simple,Fast Dominance Algorithm' See 'A Simple,Fast Dominance Algorithm'

@ -85,7 +85,7 @@ class AssignmentOperation(ExpressionTyped):
right_expression: Expression, right_expression: Expression,
expression_type: AssignmentOperationType, expression_type: AssignmentOperationType,
expression_return_type: Optional["Type"], expression_return_type: Optional["Type"],
): ) -> None:
assert isinstance(left_expression, Expression) assert isinstance(left_expression, Expression)
assert isinstance(right_expression, Expression) assert isinstance(right_expression, Expression)
super().__init__() super().__init__()

@ -1,10 +1,10 @@
from typing import Optional, List from typing import Any, Optional, List
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
class CallExpression(Expression): # pylint: disable=too-many-instance-attributes class CallExpression(Expression): # pylint: disable=too-many-instance-attributes
def __init__(self, called, arguments, type_call): def __init__(self, called: Expression, arguments: List[Any], type_call: str) -> None:
assert isinstance(called, Expression) assert isinstance(called, Expression)
super().__init__() super().__init__()
self._called: Expression = called self._called: Expression = called
@ -53,7 +53,7 @@ class CallExpression(Expression): # pylint: disable=too-many-instance-attribute
def type_call(self) -> str: def type_call(self) -> str:
return self._type_call return self._type_call
def __str__(self): def __str__(self) -> str:
txt = str(self._called) txt = str(self._called)
if self.call_gas or self.call_value: if self.call_gas or self.call_value:
gas = f"gas: {self.call_gas}" if self.call_gas else "" gas = f"gas: {self.call_gas}" if self.call_gas else ""

@ -1,10 +1,23 @@
from typing import List from typing import Union, List
from .expression import Expression from slither.core.expressions.binary_operation import BinaryOperation
from slither.core.expressions.expression import Expression
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
from slither.core.expressions.tuple_expression import TupleExpression
from slither.core.expressions.type_conversion import TypeConversion
from slither.core.expressions.unary_operation import UnaryOperation
class ConditionalExpression(Expression): class ConditionalExpression(Expression):
def __init__(self, if_expression, then_expression, else_expression): def __init__(
self,
if_expression: Union[BinaryOperation, Identifier, Literal],
then_expression: Union[
"ConditionalExpression", TypeConversion, Literal, TupleExpression, Identifier
],
else_expression: Union[TupleExpression, UnaryOperation, Identifier, Literal],
) -> None:
assert isinstance(if_expression, Expression) assert isinstance(if_expression, Expression)
assert isinstance(then_expression, Expression) assert isinstance(then_expression, Expression)
assert isinstance(else_expression, Expression) assert isinstance(else_expression, Expression)

@ -3,10 +3,11 @@
""" """
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.solidity_types.elementary_type import ElementaryType
class ElementaryTypeNameExpression(Expression): class ElementaryTypeNameExpression(Expression):
def __init__(self, t): def __init__(self, t: ElementaryType) -> None:
assert isinstance(t, Type) assert isinstance(t, Type)
super().__init__() super().__init__()
self._type = t self._type = t
@ -20,5 +21,5 @@ class ElementaryTypeNameExpression(Expression):
assert isinstance(new_type, Type) assert isinstance(new_type, Type)
self._type = new_type self._type = new_type
def __str__(self): def __str__(self) -> str:
return str(self._type) return str(self._type)

@ -1,6 +1,8 @@
from typing import List, TYPE_CHECKING from typing import Union, List, TYPE_CHECKING
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
if TYPE_CHECKING: if TYPE_CHECKING:
@ -9,7 +11,12 @@ if TYPE_CHECKING:
class IndexAccess(ExpressionTyped): class IndexAccess(ExpressionTyped):
def __init__(self, left_expression, right_expression, index_type): def __init__(
self,
left_expression: Union["IndexAccess", Identifier],
right_expression: Union[Literal, Identifier],
index_type: str,
) -> None:
super().__init__() super().__init__()
self._expressions = [left_expression, right_expression] self._expressions = [left_expression, right_expression]
# TODO type of undexAccess is not always a Type # TODO type of undexAccess is not always a Type
@ -32,5 +39,5 @@ class IndexAccess(ExpressionTyped):
def type(self) -> "Type": def type(self) -> "Type":
return self._type return self._type
def __str__(self): def __str__(self) -> str:
return str(self.expression_left) + "[" + str(self.expression_right) + "]" return str(self.expression_left) + "[" + str(self.expression_right) + "]"

@ -12,7 +12,7 @@ if TYPE_CHECKING:
class Literal(Expression): class Literal(Expression):
def __init__( def __init__(
self, value: Union[int, str], custom_type: "Type", subdenomination: Optional[str] = None self, value: Union[int, str], custom_type: "Type", subdenomination: Optional[str] = None
): ) -> None:
super().__init__() super().__init__()
self._value = value self._value = value
self._type = custom_type self._type = custom_type

@ -5,7 +5,7 @@ from slither.core.solidity_types.type import Type
class MemberAccess(ExpressionTyped): class MemberAccess(ExpressionTyped):
def __init__(self, member_name, member_type, expression): def __init__(self, member_name: str, member_type: str, expression: Expression) -> None:
# assert isinstance(member_type, Type) # assert isinstance(member_type, Type)
# TODO member_type is not always a Type # TODO member_type is not always a Type
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
@ -26,5 +26,5 @@ class MemberAccess(ExpressionTyped):
def type(self) -> Type: def type(self) -> Type:
return self._type return self._type
def __str__(self): def __str__(self) -> str:
return str(self.expression) + "." + self.member_name return str(self.expression) + "." + self.member_name

@ -1,11 +1,20 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class NewArray(Expression): class NewArray(Expression):
# note: dont conserve the size of the array if provided # note: dont conserve the size of the array if provided
def __init__(self, depth, array_type): def __init__(
self, depth: int, array_type: Union["TypeAliasTopLevel", "ElementaryType"]
) -> None:
super().__init__() super().__init__()
assert isinstance(array_type, Type) assert isinstance(array_type, Type)
self._depth: int = depth self._depth: int = depth

@ -2,7 +2,7 @@ from slither.core.expressions.expression import Expression
class NewContract(Expression): class NewContract(Expression):
def __init__(self, contract_name): def __init__(self, contract_name: str) -> None:
super().__init__() super().__init__()
self._contract_name: str = contract_name self._contract_name: str = contract_name
self._gas = None self._gas = None
@ -29,5 +29,5 @@ class NewContract(Expression):
def call_salt(self, salt): def call_salt(self, salt):
self._salt = salt self._salt = salt
def __str__(self): def __str__(self) -> str:
return "new " + str(self._contract_name) return "new " + str(self._contract_name)

@ -1,10 +1,27 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.expressions.call_expression import CallExpression
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
from slither.core.expressions.member_access import MemberAccess
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasContract
from slither.core.solidity_types.user_defined_type import UserDefinedType
class TypeConversion(ExpressionTyped): class TypeConversion(ExpressionTyped):
def __init__(self, expression, expression_type): def __init__(
self,
expression: Union[
"MemberAccess", "Literal", "CallExpression", "TypeConversion", "Identifier"
],
expression_type: Union["ElementaryType", "UserDefinedType", "TypeAliasContract"],
) -> None:
super().__init__() super().__init__()
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
assert isinstance(expression_type, Type) assert isinstance(expression_type, Type)
@ -15,5 +32,5 @@ class TypeConversion(ExpressionTyped):
def expression(self) -> Expression: def expression(self) -> Expression:
return self._expression return self._expression
def __str__(self): def __str__(self) -> str:
return str(self.type) + "(" + str(self.expression) + ")" return str(self.type) + "(" + str(self.expression) + ")"

@ -1,9 +1,15 @@
import logging import logging
from typing import Union
from enum import Enum from enum import Enum
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.exceptions import SlitherCoreError from slither.core.exceptions import SlitherCoreError
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.index_access import IndexAccess
from slither.core.expressions.literal import Literal
from slither.core.expressions.tuple_expression import TupleExpression
logger = logging.getLogger("UnaryOperation") logger = logging.getLogger("UnaryOperation")
@ -20,7 +26,7 @@ class UnaryOperationType(Enum):
MINUS_PRE = 8 # for stuff like uint(-1) MINUS_PRE = 8 # for stuff like uint(-1)
@staticmethod @staticmethod
def get_type(operation_type, isprefix): def get_type(operation_type: str, isprefix: bool) -> "UnaryOperationType":
if isprefix: if isprefix:
if operation_type == "!": if operation_type == "!":
return UnaryOperationType.BANG return UnaryOperationType.BANG
@ -43,7 +49,7 @@ class UnaryOperationType(Enum):
return UnaryOperationType.MINUSMINUS_POST return UnaryOperationType.MINUSMINUS_POST
raise SlitherCoreError(f"get_type: Unknown operation type {operation_type}") raise SlitherCoreError(f"get_type: Unknown operation type {operation_type}")
def __str__(self): def __str__(self) -> str:
if self == UnaryOperationType.BANG: if self == UnaryOperationType.BANG:
return "!" return "!"
if self == UnaryOperationType.TILD: if self == UnaryOperationType.TILD:
@ -65,7 +71,7 @@ class UnaryOperationType(Enum):
raise SlitherCoreError(f"str: Unknown operation type {self}") raise SlitherCoreError(f"str: Unknown operation type {self}")
@staticmethod @staticmethod
def is_prefix(operation_type): def is_prefix(operation_type: "UnaryOperationType") -> bool:
if operation_type in [ if operation_type in [
UnaryOperationType.BANG, UnaryOperationType.BANG,
UnaryOperationType.TILD, UnaryOperationType.TILD,
@ -86,7 +92,11 @@ class UnaryOperationType(Enum):
class UnaryOperation(ExpressionTyped): class UnaryOperation(ExpressionTyped):
def __init__(self, expression, expression_type): def __init__(
self,
expression: Union[Literal, Identifier, IndexAccess, TupleExpression],
expression_type: UnaryOperationType,
) -> None:
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
super().__init__() super().__init__()
self._expression: Expression = expression self._expression: Expression = expression
@ -114,7 +124,7 @@ class UnaryOperation(ExpressionTyped):
def is_prefix(self) -> bool: def is_prefix(self) -> bool:
return UnaryOperationType.is_prefix(self._type) return UnaryOperationType.is_prefix(self._type)
def __str__(self): def __str__(self) -> str:
if self.is_prefix: if self.is_prefix:
return str(self.type) + " " + str(self._expression) return str(self.type) + " " + str(self._expression)
return str(self._expression) + " " + str(self.type) return str(self._expression) + " " + str(self.type)

@ -25,7 +25,7 @@ def _dict_contain(d1: Dict, d2: Dict) -> bool:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class FileScope: class FileScope:
def __init__(self, filename: Filename): def __init__(self, filename: Filename) -> None:
self.filename = filename self.filename = filename
self.accessible_scopes: List[FileScope] = [] self.accessible_scopes: List[FileScope] = []

@ -8,7 +8,7 @@ import pathlib
import posixpath import posixpath
import re import re
from collections import defaultdict from collections import defaultdict
from typing import Optional, Dict, List, Set, Union from typing import Optional, Dict, List, Set, Union, Tuple
from crytic_compile import CryticCompile from crytic_compile import CryticCompile
from crytic_compile.utils.naming import Filename from crytic_compile.utils.naming import Filename
@ -40,7 +40,7 @@ class SlitherCore(Context):
Slither static analyzer Slither static analyzer
""" """
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._filename: Optional[str] = None self._filename: Optional[str] = None
@ -73,8 +73,8 @@ class SlitherCore(Context):
# Maps from file to detector name to the start/end ranges for that detector. # Maps from file to detector name to the start/end ranges for that detector.
# Infinity is used to signal a detector has no end range. # Infinity is used to signal a detector has no end range.
self._ignore_ranges: defaultdict[str, defaultdict[str, List[(int, int)]]] = defaultdict( self._ignore_ranges: Dict[str, Dict[str, List[Tuple[int, ...]]]] = defaultdict(
lambda: defaultdict(lambda: []) lambda: defaultdict(lambda: [(-1, -1)])
) )
self._compilation_units: List[SlitherCompilationUnit] = [] self._compilation_units: List[SlitherCompilationUnit] = []
@ -443,7 +443,7 @@ class SlitherCore(Context):
return True return True
def load_previous_results(self): def load_previous_results(self) -> None:
filename = self._previous_results_filename filename = self._previous_results_filename
try: try:
if os.path.isfile(filename): if os.path.isfile(filename):
@ -456,7 +456,7 @@ class SlitherCore(Context):
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:
logger.error(red(f"Impossible to decode {filename}. Consider removing the file")) logger.error(red(f"Impossible to decode {filename}. Consider removing the file"))
def write_results_to_hide(self): def write_results_to_hide(self) -> None:
if not self._results_to_hide: if not self._results_to_hide:
return return
filename = self._previous_results_filename filename = self._previous_results_filename
@ -464,7 +464,7 @@ class SlitherCore(Context):
results = self._results_to_hide + self._previous_results results = self._results_to_hide + self._previous_results
json.dump(results, f) json.dump(results, f)
def save_results_to_hide(self, results: List[Dict]): def save_results_to_hide(self, results: List[Dict]) -> None:
self._results_to_hide += results self._results_to_hide += results
def add_path_to_filter(self, path: str): def add_path_to_filter(self, path: str):

@ -1,13 +1,24 @@
from typing import Optional, Tuple from typing import Union, Optional, Tuple, Any, TYPE_CHECKING
from slither.core.expressions import Literal
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.visitors.expression.constants_folding import ConstantFolding from slither.visitors.expression.constants_folding import ConstantFolding
from slither.core.expressions.literal import Literal
if TYPE_CHECKING:
from slither.core.expressions.binary_operation import BinaryOperation
from slither.core.expressions.identifier import Identifier
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.function_type import FunctionType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class ArrayType(Type): class ArrayType(Type):
def __init__(self, t, length): def __init__(
self,
t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"],
length: Optional[Union["Identifier", Literal, "BinaryOperation", int]],
) -> None:
assert isinstance(t, Type) assert isinstance(t, Type)
if length: if length:
if isinstance(length, int): if isinstance(length, int):
@ -56,15 +67,15 @@ class ArrayType(Type):
return elem_size * int(str(self._length_value)), True return elem_size * int(str(self._length_value)), True
return 32, True return 32, True
def __str__(self): def __str__(self) -> str:
if self._length: if self._length:
return str(self._type) + f"[{str(self._length_value)}]" return str(self._type) + f"[{str(self._length_value)}]"
return str(self._type) + "[]" return str(self._type) + "[]"
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
if not isinstance(other, ArrayType): if not isinstance(other, ArrayType):
return False return False
return self._type == other.type and self.length == other.length return self._type == other.type and self.length == other.length
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -216,13 +216,13 @@ class ElementaryType(Type):
return MaxValues[self.name] return MaxValues[self.name]
raise SlitherException(f"{self.name} does not have a max value") raise SlitherException(f"{self.name} does not have a max value")
def __str__(self): def __str__(self) -> str:
return self._type return self._type
def __eq__(self, other): def __eq__(self, other) -> bool:
if not isinstance(other, ElementaryType): if not isinstance(other, ElementaryType):
return False return False
return self.type == other.type return self.type == other.type
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -1,7 +1,8 @@
from typing import List, Tuple from typing import List, Tuple, Any
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.variables.function_type_variable import FunctionTypeVariable from slither.core.variables.function_type_variable import FunctionTypeVariable
from slither.core.solidity_types.elementary_type import ElementaryType
class FunctionType(Type): class FunctionType(Type):
@ -9,7 +10,7 @@ class FunctionType(Type):
self, self,
params: List[FunctionTypeVariable], params: List[FunctionTypeVariable],
return_values: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable],
): ) -> None:
assert all(isinstance(x, FunctionTypeVariable) for x in params) assert all(isinstance(x, FunctionTypeVariable) for x in params)
assert all(isinstance(x, FunctionTypeVariable) for x in return_values) assert all(isinstance(x, FunctionTypeVariable) for x in return_values)
super().__init__() super().__init__()
@ -68,7 +69,7 @@ class FunctionType(Type):
return f"({params}) returns({return_values})" return f"({params}) returns({return_values})"
return f"({params})" return f"({params})"
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
if not isinstance(other, FunctionType): if not isinstance(other, FunctionType):
return False return False
return self.params == other.params and self.return_values == other.return_values return self.params == other.params and self.return_values == other.return_values

@ -1,10 +1,18 @@
from typing import Tuple from typing import Union, Tuple, TYPE_CHECKING
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class MappingType(Type): class MappingType(Type):
def __init__(self, type_from, type_to): def __init__(
self,
type_from: "ElementaryType",
type_to: Union["MappingType", "TypeAliasTopLevel", "ElementaryType"],
) -> None:
assert isinstance(type_from, Type) assert isinstance(type_from, Type)
assert isinstance(type_to, Type) assert isinstance(type_to, Type)
super().__init__() super().__init__()
@ -27,7 +35,7 @@ class MappingType(Type):
def is_dynamic(self) -> bool: def is_dynamic(self) -> bool:
return True return True
def __str__(self): def __str__(self) -> str:
return f"mapping({str(self._from)} => {str(self._to)})" return f"mapping({str(self._from)} => {str(self._to)})"
def __eq__(self, other): def __eq__(self, other):
@ -35,5 +43,5 @@ class MappingType(Type):
return False return False
return self.type_from == other.type_from and self.type_to == other.type_to return self.type_from == other.type_from and self.type_to == other.type_to
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Tuple
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.declarations.top_level import TopLevel from slither.core.declarations.top_level import TopLevel
from slither.core.solidity_types import Type from slither.core.solidity_types import Type, ElementaryType
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations import Contract from slither.core.declarations import Contract
@ -10,13 +10,13 @@ if TYPE_CHECKING:
class TypeAlias(Type): class TypeAlias(Type):
def __init__(self, underlying_type: Type, name: str): def __init__(self, underlying_type: ElementaryType, name: str) -> None:
super().__init__() super().__init__()
self.name = name self.name = name
self.underlying_type = underlying_type self.underlying_type = underlying_type
@property @property
def type(self) -> Type: def type(self) -> ElementaryType:
""" """
Return the underlying type. Alias for underlying_type Return the underlying type. Alias for underlying_type
@ -31,7 +31,7 @@ class TypeAlias(Type):
def storage_size(self) -> Tuple[int, bool]: def storage_size(self) -> Tuple[int, bool]:
return self.underlying_type.storage_size return self.underlying_type.storage_size
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))
@property @property
@ -40,18 +40,18 @@ class TypeAlias(Type):
class TypeAliasTopLevel(TypeAlias, TopLevel): class TypeAliasTopLevel(TypeAlias, TopLevel):
def __init__(self, underlying_type: Type, name: str, scope: "FileScope"): def __init__(self, underlying_type: Type, name: str, scope: "FileScope") -> None:
super().__init__(underlying_type, name) super().__init__(underlying_type, name)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope
def __str__(self): def __str__(self) -> str:
return self.name return self.name
class TypeAliasContract(TypeAlias, ChildContract): class TypeAliasContract(TypeAlias, ChildContract):
def __init__(self, underlying_type: Type, name: str, contract: "Contract"): def __init__(self, underlying_type: Type, name: str, contract: "Contract") -> None:
super().__init__(underlying_type, name) super().__init__(underlying_type, name)
self._contract: "Contract" = contract self._contract: "Contract" = contract
def __str__(self): def __str__(self) -> str:
return self.contract.name + "." + self.name return self.contract.name + "." + self.name

@ -1,16 +1,17 @@
from typing import TYPE_CHECKING, Tuple from typing import Union, TYPE_CHECKING, Tuple
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum
# Use to model the Type(X) function, which returns an undefined type # Use to model the Type(X) function, which returns an undefined type
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
class TypeInformation(Type): class TypeInformation(Type):
def __init__(self, c): def __init__(self, c: Union[ElementaryType, "Contract", "Enum"]) -> None:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum
@ -20,7 +21,7 @@ class TypeInformation(Type):
self._type = c self._type = c
@property @property
def type(self) -> "Contract": def type(self) -> Union["Contract", ElementaryType, "Enum"]:
return self._type return self._type
@property @property

@ -1,4 +1,4 @@
from typing import Union, TYPE_CHECKING, Tuple from typing import Union, TYPE_CHECKING, Tuple, Any
import math import math
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -11,7 +11,7 @@ if TYPE_CHECKING:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
class UserDefinedType(Type): class UserDefinedType(Type):
def __init__(self, t): def __init__(self, t: Union["Enum", "Contract", "Structure"]) -> None:
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
@ -62,7 +62,7 @@ class UserDefinedType(Type):
to_log = f"{self} does not have storage size" to_log = f"{self} does not have storage size"
raise SlitherException(to_log) raise SlitherException(to_log)
def __str__(self): def __str__(self) -> str:
from slither.core.declarations.structure_contract import StructureContract from slither.core.declarations.structure_contract import StructureContract
from slither.core.declarations.enum_contract import EnumContract from slither.core.declarations.enum_contract import EnumContract
@ -71,10 +71,10 @@ class UserDefinedType(Type):
return str(type_used.contract) + "." + str(type_used.name) return str(type_used.contract) + "." + str(type_used.name)
return str(type_used.name) return str(type_used.name)
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
if not isinstance(other, UserDefinedType): if not isinstance(other, UserDefinedType):
return False return False
return self.type == other.type return self.type == other.type
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -0,0 +1,2 @@
from .state_variable import StateVariable
from .variable import Variable

@ -3,7 +3,7 @@ from slither.core.children.child_event import ChildEvent
class EventVariable(ChildEvent, Variable): class EventVariable(ChildEvent, Variable):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._indexed = False self._indexed = False

@ -13,7 +13,7 @@ class LocalVariableInitFromTuple(LocalVariable):
""" """
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._tuple_index: Optional[int] = None self._tuple_index: Optional[int] = None

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class StateVariable(ChildContract, Variable): class StateVariable(ChildContract, Variable):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._node_initialization: Optional["Node"] = None self._node_initialization: Optional["Node"] = None

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class TopLevelVariable(TopLevel, Variable): class TopLevelVariable(TopLevel, Variable):
def __init__(self, scope: "FileScope"): def __init__(self, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._node_initialization: Optional["Node"] = None self._node_initialization: Optional["Node"] = None
self.file_scope = scope self.file_scope = scope

@ -12,7 +12,7 @@ if TYPE_CHECKING:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class Variable(SourceMapping): class Variable(SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._name: Optional[str] = None self._name: Optional[str] = None
self._initial_expression: Optional["Expression"] = None self._initial_expression: Optional["Expression"] = None

@ -5,9 +5,9 @@ from typing import Optional, List, TYPE_CHECKING, Dict, Union, Callable
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import Contract from slither.core.declarations import Contract
from slither.utils.colors import green, yellow, red
from slither.formatters.exceptions import FormatImpossible from slither.formatters.exceptions import FormatImpossible
from slither.formatters.utils.patches import apply_patch, create_diff from slither.formatters.utils.patches import apply_patch, create_diff
from slither.utils.colors import green, yellow, red
from slither.utils.comparable_enum import ComparableEnum from slither.utils.comparable_enum import ComparableEnum
from slither.utils.output import Output, SupportedOutput from slither.utils.output import Output, SupportedOutput
@ -81,7 +81,7 @@ class AbstractDetector(metaclass=abc.ABCMeta):
def __init__( def __init__(
self, compilation_unit: SlitherCompilationUnit, slither: "Slither", logger: Logger self, compilation_unit: SlitherCompilationUnit, slither: "Slither", logger: Logger
): ) -> None:
self.compilation_unit: SlitherCompilationUnit = compilation_unit self.compilation_unit: SlitherCompilationUnit = compilation_unit
self.contracts: List[Contract] = compilation_unit.contracts self.contracts: List[Contract] = compilation_unit.contracts
self.slither: "Slither" = slither self.slither: "Slither" = slither

@ -1,6 +1,9 @@
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Binary, BinaryType from slither.slithir.operations import Binary, BinaryType
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ShiftParameterMixup(AbstractDetector): class ShiftParameterMixup(AbstractDetector):
@ -36,7 +39,7 @@ The shift statement will right-shift the constant 8 by `a` bits"""
WIKI_RECOMMENDATION = "Swap the order of parameters." WIKI_RECOMMENDATION = "Swap the order of parameters."
def _check_function(self, f): def _check_function(self, f: FunctionContract) -> List[Union[Output, Any]]:
results = [] results = []
for node in f.nodes: for node in f.nodes:
@ -52,7 +55,7 @@ The shift statement will right-shift the constant 8 by `a` bits"""
results.append(json) results.append(json)
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
results = [] results = []
for c in self.contracts: for c in self.contracts:
for f in c.functions: for f in c.functions:

@ -2,12 +2,14 @@
Module detecting constant functions Module detecting constant functions
Recursively check the called functions Recursively check the called functions
""" """
from typing import List
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
ALL_SOLC_VERSIONS_04, ALL_SOLC_VERSIONS_04,
) )
from slither.formatters.attributes.const_functions import custom_format from slither.formatters.attributes.const_functions import custom_format
from slither.utils.output import Output
class ConstantFunctionsAsm(AbstractDetector): class ConstantFunctionsAsm(AbstractDetector):
@ -55,7 +57,7 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self): def _detect(self) -> List[Output]:
"""Detect the constant function using assembly code """Detect the constant function using assembly code
Recursively visit the calls Recursively visit the calls

@ -2,12 +2,14 @@
Module detecting constant functions Module detecting constant functions
Recursively check the called functions Recursively check the called functions
""" """
from typing import List
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
ALL_SOLC_VERSIONS_04, ALL_SOLC_VERSIONS_04,
) )
from slither.formatters.attributes.const_functions import custom_format from slither.formatters.attributes.const_functions import custom_format
from slither.utils.output import Output
class ConstantFunctionsState(AbstractDetector): class ConstantFunctionsState(AbstractDetector):
@ -55,7 +57,7 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self): def _detect(self) -> List[Output]:
"""Detect the constant function changing the state """Detect the constant function changing the state
Recursively visit the calls Recursively visit the calls

@ -1,9 +1,10 @@
""" """
Check that the same pragma is used in all the files Check that the same pragma is used in all the files
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.attributes.constant_pragma import custom_format from slither.formatters.attributes.constant_pragma import custom_format
from slither.utils.output import Output
class ConstantPragma(AbstractDetector): class ConstantPragma(AbstractDetector):
@ -22,7 +23,7 @@ class ConstantPragma(AbstractDetector):
WIKI_DESCRIPTION = "Detect whether different Solidity versions are used." WIKI_DESCRIPTION = "Detect whether different Solidity versions are used."
WIKI_RECOMMENDATION = "Use one Solidity version." WIKI_RECOMMENDATION = "Use one Solidity version."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
results = [] results = []
pragma = self.compilation_unit.pragma_directives pragma = self.compilation_unit.pragma_directives
versions = [p.version for p in pragma if p.is_solidity_version] versions = [p.version for p in pragma if p.is_solidity_version]

@ -3,8 +3,11 @@
""" """
import re import re
from typing import Any, List, Optional, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.attributes.incorrect_solc import custom_format from slither.formatters.attributes.incorrect_solc import custom_format
from slither.utils.output import Output
# group: # group:
# 0: ^ > >= < <= (optional) # 0: ^ > >= < <= (optional)
@ -83,7 +86,7 @@ Consider using the latest version of Solidity for testing."""
"^0.8.8", "^0.8.8",
] ]
def _check_version(self, version): def _check_version(self, version: Tuple[str, str, str, str, str]) -> Optional[str]:
op = version[0] op = version[0]
if op and op not in [">", ">=", "^"]: if op and op not in [">", ">=", "^"]:
return self.LESS_THAN_TXT return self.LESS_THAN_TXT
@ -96,7 +99,7 @@ Consider using the latest version of Solidity for testing."""
return self.OLD_VERSION_TXT return self.OLD_VERSION_TXT
return None return None
def _check_pragma(self, version): def _check_pragma(self, version: str) -> Optional[str]:
if version in self.BUGGY_VERSIONS: if version in self.BUGGY_VERSIONS:
return self.BUGGY_VERSION_TXT return self.BUGGY_VERSION_TXT
versions = PATTERN.findall(version) versions = PATTERN.findall(version)
@ -117,7 +120,7 @@ Consider using the latest version of Solidity for testing."""
return self._check_version(version_left) return self._check_version(version_left)
return self.COMPLEX_PRAGMA_TXT return self.COMPLEX_PRAGMA_TXT
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
""" """
Detects pragma statements that allow for outdated solc versions. Detects pragma statements that allow for outdated solc versions.
:return: Returns the relevant JSON data for the findings. :return: Returns the relevant JSON data for the findings.

@ -1,7 +1,7 @@
""" """
Check if ethers are locked in the contract Check if ethers are locked in the contract
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import ( from slither.slithir.operations import (
HighLevelCall, HighLevelCall,
@ -12,6 +12,8 @@ from slither.slithir.operations import (
LibraryCall, LibraryCall,
InternalCall, InternalCall,
) )
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
class LockedEther(AbstractDetector): # pylint: disable=too-many-nested-blocks class LockedEther(AbstractDetector): # pylint: disable=too-many-nested-blocks
@ -41,7 +43,7 @@ Every Ether sent to `Locked` will be lost."""
WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function." WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function."
@staticmethod @staticmethod
def do_no_send_ether(contract): def do_no_send_ether(contract: Contract) -> bool:
functions = contract.all_functions_called functions = contract.all_functions_called
to_explore = functions to_explore = functions
explored = [] explored = []
@ -73,7 +75,7 @@ Every Ether sent to `Locked` will be lost."""
return True return True
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
results = [] results = []
for contract in self.compilation_unit.contracts_derived: for contract in self.compilation_unit.contracts_derived:

@ -4,8 +4,10 @@ Module detecting unimplemented interfaces
Collect all the interfaces Collect all the interfaces
Check for contracts which implement all interface functions but do not explicitly derive from those interfaces. Check for contracts which implement all interface functions but do not explicitly derive from those interfaces.
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
class MissingInheritance(AbstractDetector): class MissingInheritance(AbstractDetector):
@ -42,7 +44,9 @@ contract Something {
WIKI_RECOMMENDATION = "Inherit from the missing interface or contract." WIKI_RECOMMENDATION = "Inherit from the missing interface or contract."
@staticmethod @staticmethod
def detect_unimplemented_interface(contract, interfaces): def detect_unimplemented_interface(
contract: Contract, interfaces: List[Union[Any, Contract]]
) -> List[Union[Any, Contract]]:
""" """
Detects if contract intends to implement one of the interfaces but does not explicitly do so by deriving from it Detects if contract intends to implement one of the interfaces but does not explicitly do so by deriving from it
:param contract: The contract to check :param contract: The contract to check
@ -111,7 +115,7 @@ contract Something {
return intended_interfaces return intended_interfaces
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect unimplemented interfaces """Detect unimplemented interfaces
Returns: Returns:
list: {'contract'} list: {'contract'}

@ -1,13 +1,17 @@
""" """
Detects the passing of arrays located in memory to functions which expect to modify arrays via storage reference. Detects the passing of arrays located in memory to functions which expect to modify arrays via storage reference.
""" """
from typing import Any, List, Set, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.solidity_types.array_type import ArrayType from slither.core.solidity_types.array_type import ArrayType
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.slithir.operations.high_level_call import HighLevelCall from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations.internal_call import InternalCall from slither.slithir.operations.internal_call import InternalCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ArrayByReference(AbstractDetector): class ArrayByReference(AbstractDetector):
@ -55,7 +59,7 @@ As a result, Bob's usage of the contract is incorrect."""
WIKI_RECOMMENDATION = "Ensure the correct usage of `memory` and `storage` in the function parameters. Make all the locations explicit." WIKI_RECOMMENDATION = "Ensure the correct usage of `memory` and `storage` in the function parameters. Make all the locations explicit."
@staticmethod @staticmethod
def get_funcs_modifying_array_params(contracts): def get_funcs_modifying_array_params(contracts: List[Contract]) -> Set[FunctionContract]:
""" """
Obtains a set of functions which take arrays not located in storage as parameters, and writes to them. Obtains a set of functions which take arrays not located in storage as parameters, and writes to them.
:param contracts: The collection of contracts to check functions in. :param contracts: The collection of contracts to check functions in.
@ -83,7 +87,15 @@ As a result, Bob's usage of the contract is incorrect."""
return results return results
@staticmethod @staticmethod
def detect_calls_passing_ref_to_function(contracts, array_modifying_funcs): def detect_calls_passing_ref_to_function(
contracts: List[Contract], array_modifying_funcs: Set[FunctionContract]
) -> List[
Union[
Tuple[Node, StateVariable, FunctionContract],
Tuple[Node, LocalVariable, FunctionContract],
Any,
]
]:
""" """
Obtains all calls passing storage arrays by value to a function which cannot write to them successfully. Obtains all calls passing storage arrays by value to a function which cannot write to them successfully.
:param contracts: The collection of contracts to check for problematic calls in. :param contracts: The collection of contracts to check for problematic calls in.
@ -134,7 +146,7 @@ As a result, Bob's usage of the contract is incorrect."""
results.append((node, arg, ir.function)) results.append((node, arg, ir.function))
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
""" """
Detects passing of arrays located in memory to functions which expect to modify arrays via storage reference. Detects passing of arrays located in memory to functions which expect to modify arrays via storage reference.
:return: The JSON results of the detector, which contains the calling_node, affected_argument_variable and :return: The JSON results of the detector, which contains the calling_node, affected_argument_variable and

@ -1,4 +1,6 @@
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class MultipleConstructorSchemes(AbstractDetector): class MultipleConstructorSchemes(AbstractDetector):
@ -43,7 +45,7 @@ In Solidity [0.4.22](https://github.com/ethereum/solidity/releases/tag/v0.4.23),
WIKI_RECOMMENDATION = "Only declare one constructor, preferably using the new scheme `constructor(...)` instead of `function <contractName>(...)`." WIKI_RECOMMENDATION = "Only declare one constructor, preferably using the new scheme `constructor(...)` instead of `function <contractName>(...)`."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
""" """
Detect multiple constructor schemes in the same contract Detect multiple constructor schemes in the same contract
:return: Returns a list of contract JSON result, where each result contains all constructor definitions. :return: Returns a list of contract JSON result, where each result contains all constructor definitions.

@ -1,7 +1,7 @@
""" """
Module detecting public mappings with nested variables (returns incorrect values prior to 0.5.x) Module detecting public mappings with nested variables (returns incorrect values prior to 0.5.x)
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
@ -10,9 +10,12 @@ from slither.detectors.abstract_detector import (
from slither.core.solidity_types.mapping_type import MappingType from slither.core.solidity_types.mapping_type import MappingType
from slither.core.solidity_types.user_defined_type import UserDefinedType from slither.core.solidity_types.user_defined_type import UserDefinedType
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.contract import Contract
from slither.core.variables.state_variable import StateVariable
from slither.utils.output import Output
def detect_public_nested_mappings(contract): def detect_public_nested_mappings(contract: Contract) -> List[Union[StateVariable, Any]]:
""" """
Detect any state variables that are initialized from an immediate function call (prior to constructor run). Detect any state variables that are initialized from an immediate function call (prior to constructor run).
:param contract: The contract to detect state variable definitions for. :param contract: The contract to detect state variable definitions for.
@ -68,7 +71,7 @@ class PublicMappingNested(AbstractDetector):
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self): def _detect(self) -> List[Output]:
""" """
Detect public mappings with nested variables (returns incorrect values prior to 0.5.x) Detect public mappings with nested variables (returns incorrect values prior to 0.5.x)

@ -1,18 +1,24 @@
""" """
Module detecting re-used base constructors in inheritance hierarchy. Module detecting re-used base constructors in inheritance hierarchy.
""" """
from typing import Any, Dict, List, Tuple, Union
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
ALL_SOLC_VERSIONS_04, ALL_SOLC_VERSIONS_04,
) )
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
# Helper: adds explicitly called constructors with arguments to the results lookup. # Helper: adds explicitly called constructors with arguments to the results lookup.
def _add_constructors_with_args( def _add_constructors_with_args(
base_constructors, called_by_constructor, current_contract, results base_constructors: List[Union[Any, FunctionContract]],
): called_by_constructor: bool,
current_contract: Contract,
results: Dict[FunctionContract, List[Tuple[Contract, bool]]],
) -> None:
for explicit_base_constructor in base_constructors: for explicit_base_constructor in base_constructors:
if len(explicit_base_constructor.parameters) > 0: if len(explicit_base_constructor.parameters) > 0:
if explicit_base_constructor not in results: if explicit_base_constructor not in results:
@ -77,7 +83,9 @@ The constructor of `A` is called multiple times in `D` and `E`:
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect_explicitly_called_base_constructors(self, contract): def _detect_explicitly_called_base_constructors(
self, contract: Contract
) -> Dict[FunctionContract, List[Tuple[Contract, bool]]]:
""" """
Detects explicitly calls to base constructors with arguments in the inheritance hierarchy. Detects explicitly calls to base constructors with arguments in the inheritance hierarchy.
:param contract: The contract to detect explicit calls to a base constructor with arguments to. :param contract: The contract to detect explicit calls to a base constructor with arguments to.
@ -124,7 +132,7 @@ The constructor of `A` is called multiple times in `D` and `E`:
return results return results
def _detect(self): def _detect(self) -> List[Output]:
""" """
Detect reused base constructors. Detect reused base constructors.
:return: Returns a list of JSON results. :return: Returns a list of JSON results.

@ -1,7 +1,7 @@
""" """
Module detecting ABIEncoderV2 array bug Module detecting ABIEncoderV2 array bug
""" """
from typing import List, Set, Tuple
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
@ -16,6 +16,10 @@ from slither.core.declarations.solidity_variables import SolidityFunction
from slither.slithir.operations import EventCall from slither.slithir.operations import EventCall
from slither.slithir.operations import HighLevelCall from slither.slithir.operations import HighLevelCall
from slither.utils.utils import unroll from slither.utils.utils import unroll
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ABIEncoderV2Array(AbstractDetector): class ABIEncoderV2Array(AbstractDetector):
@ -55,7 +59,9 @@ contract A {
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 7, 25) + make_solc_versions(5, 0, 9) VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 7, 25) + make_solc_versions(5, 0, 9)
@staticmethod @staticmethod
def _detect_storage_abiencoderv2_arrays(contract): def _detect_storage_abiencoderv2_arrays(
contract: Contract,
) -> Set[Tuple[FunctionContract, Node]]:
""" """
Detects and returns all nodes with storage-allocated abiencoderv2 arrays of arrays/structs in abi.encode, events or external calls Detects and returns all nodes with storage-allocated abiencoderv2 arrays of arrays/structs in abi.encode, events or external calls
:param contract: Contract to detect within :param contract: Contract to detect within
@ -98,7 +104,7 @@ contract A {
# Return the resulting set of tuples # Return the resulting set of tuples
return results return results
def _detect(self): def _detect(self) -> List[Output]:
""" """
Detect ABIEncoderV2 array bug Detect ABIEncoderV2 array bug
""" """

@ -1,7 +1,7 @@
""" """
Module detecting uninitialized function pointer calls in constructors Module detecting uninitialized function pointer calls in constructors
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
@ -10,9 +10,14 @@ from slither.detectors.abstract_detector import (
from slither.slithir.operations import InternalDynamicCall, OperationWithLValue from slither.slithir.operations import InternalDynamicCall, OperationWithLValue
from slither.slithir.variables import ReferenceVariable from slither.slithir.variables import ReferenceVariable
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.slithir.variables.state_variable import StateIRVariable
from slither.utils.output import Output
def _get_variables_entrance(function): def _get_variables_entrance(function: FunctionContract) -> List[Union[Any, StateIRVariable]]:
""" """
Return the first SSA variables of the function Return the first SSA variables of the function
Catpure the phi operation at the entry point Catpure the phi operation at the entry point
@ -25,7 +30,7 @@ def _get_variables_entrance(function):
return ret return ret
def _is_vulnerable(node, variables_entrance): def _is_vulnerable(node: Node, variables_entrance: List[Union[Any, StateIRVariable]]) -> bool:
""" """
Vulnerable if an IR ssa: Vulnerable if an IR ssa:
- It is an internal dynamic call - It is an internal dynamic call
@ -84,7 +89,9 @@ The call to `a(10)` will lead to unexpected behavior because function pointer `a
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 5, 25) + make_solc_versions(5, 0, 8) VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 5, 25) + make_solc_versions(5, 0, 8)
@staticmethod @staticmethod
def _detect_uninitialized_function_ptr_in_constructor(contract): def _detect_uninitialized_function_ptr_in_constructor(
contract: Contract,
) -> List[Union[Any, Node]]:
""" """
Detect uninitialized function pointer calls in constructors Detect uninitialized function pointer calls in constructors
:param contract: The contract of interest for detection :param contract: The contract of interest for detection
@ -99,7 +106,7 @@ The call to `a(10)` will lead to unexpected behavior because function pointer `a
] ]
return results return results
def _detect(self): def _detect(self) -> List[Output]:
""" """
Detect uninitialized function pointer calls in constructors of contracts Detect uninitialized function pointer calls in constructors of contracts
Returns: Returns:

@ -1,16 +1,17 @@
from typing import List from typing import List
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import Contract, Function, SolidityVariableComposed
from slither.core.declarations.solidity_variables import SolidityVariable from slither.core.declarations.solidity_variables import SolidityVariable
from slither.slithir.operations import HighLevelCall, LibraryCall from slither.slithir.operations import HighLevelCall, LibraryCall
from slither.core.declarations import Contract, Function, SolidityVariableComposed
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.compilation_unit import SlitherCompilationUnit
class ArbitrarySendErc20: class ArbitrarySendErc20:
"""Detects instances where ERC20 can be sent from an arbitrary from address.""" """Detects instances where ERC20 can be sent from an arbitrary from address."""
def __init__(self, compilation_unit: SlitherCompilationUnit): def __init__(self, compilation_unit: SlitherCompilationUnit) -> None:
self._compilation_unit = compilation_unit self._compilation_unit = compilation_unit
self._no_permit_results: List[Node] = [] self._no_permit_results: List[Node] = []
self._permit_results: List[Node] = [] self._permit_results: List[Node] = []
@ -27,7 +28,7 @@ class ArbitrarySendErc20:
def permit_results(self) -> List[Node]: def permit_results(self) -> List[Node]:
return self._permit_results return self._permit_results
def _detect_arbitrary_from(self, contract: Contract): def _detect_arbitrary_from(self, contract: Contract) -> None:
for f in contract.functions: for f in contract.functions:
all_high_level_calls = [ all_high_level_calls = [
f_called[1].solidity_signature f_called[1].solidity_signature
@ -48,7 +49,7 @@ class ArbitrarySendErc20:
ArbitrarySendErc20._arbitrary_from(f.nodes, self._no_permit_results) ArbitrarySendErc20._arbitrary_from(f.nodes, self._no_permit_results)
@staticmethod @staticmethod
def _arbitrary_from(nodes: List[Node], results: List[Node]): def _arbitrary_from(nodes: List[Node], results: List[Node]) -> None:
"""Finds instances of (safe)transferFrom that do not use msg.sender or address(this) as from parameter.""" """Finds instances of (safe)transferFrom that do not use msg.sender or address(this) as from parameter."""
for node in nodes: for node in nodes:
for ir in node.irs: for ir in node.irs:
@ -89,7 +90,7 @@ class ArbitrarySendErc20:
): ):
results.append(ir.node) results.append(ir.node)
def detect(self): def detect(self) -> None:
"""Detect transfers that use arbitrary `from` parameter.""" """Detect transfers that use arbitrary `from` parameter."""
for c in self.compilation_unit.contracts_derived: for c in self.compilation_unit.contracts_derived:
self._detect_arbitrary_from(c) self._detect_arbitrary_from(c)

@ -2,7 +2,11 @@
Detect incorrect erc20 interface. Detect incorrect erc20 interface.
Some contracts do not return a bool on transfer/transferFrom/approve, which may lead to preventing the contract to be used with contracts compiled with recent solc (>0.4.22) Some contracts do not return a bool on transfer/transferFrom/approve, which may lead to preventing the contract to be used with contracts compiled with recent solc (>0.4.22)
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class IncorrectERC20InterfaceDetection(AbstractDetector): class IncorrectERC20InterfaceDetection(AbstractDetector):
@ -36,7 +40,9 @@ contract Token{
) )
@staticmethod @staticmethod
def incorrect_erc20_interface(signature): def incorrect_erc20_interface(
signature: Union[Tuple[str, List[str], List[Any]], Tuple[str, List[Any], List[Any]]]
) -> bool:
(name, parameters, returnVars) = signature (name, parameters, returnVars) = signature
if name == "transfer" and parameters == ["address", "uint256"] and returnVars != ["bool"]: if name == "transfer" and parameters == ["address", "uint256"] and returnVars != ["bool"]:
@ -68,7 +74,7 @@ contract Token{
return False return False
@staticmethod @staticmethod
def detect_incorrect_erc20_interface(contract): def detect_incorrect_erc20_interface(contract: Contract) -> List[Union[FunctionContract, Any]]:
"""Detect incorrect ERC20 interface """Detect incorrect ERC20 interface
Returns: Returns:
@ -93,7 +99,7 @@ contract Token{
return functions return functions
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect incorrect erc20 interface """Detect incorrect erc20 interface
Returns: Returns:

@ -1,7 +1,11 @@
""" """
Detect incorrect erc721 interface. Detect incorrect erc721 interface.
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class IncorrectERC721InterfaceDetection(AbstractDetector): class IncorrectERC721InterfaceDetection(AbstractDetector):
@ -37,7 +41,9 @@ contract Token{
) )
@staticmethod @staticmethod
def incorrect_erc721_interface(signature): def incorrect_erc721_interface(
signature: Union[Tuple[str, List[str], List[str]], Tuple[str, List[str], List[Any]]]
) -> bool:
(name, parameters, returnVars) = signature (name, parameters, returnVars) = signature
# ERC721 # ERC721
@ -83,7 +89,7 @@ contract Token{
return False return False
@staticmethod @staticmethod
def detect_incorrect_erc721_interface(contract): def detect_incorrect_erc721_interface(contract: Contract) -> List[Union[FunctionContract, Any]]:
"""Detect incorrect ERC721 interface """Detect incorrect ERC721 interface
Returns: Returns:
@ -102,7 +108,7 @@ contract Token{
] ]
return functions return functions
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect incorrect erc721 interface """Detect incorrect erc721 interface
Returns: Returns:

@ -1,7 +1,12 @@
""" """
Detect mistakenly un-indexed ERC20 event parameters Detect mistakenly un-indexed ERC20 event parameters
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.event import Event
from slither.core.variables.event_variable import EventVariable
from slither.utils.output import Output
class UnindexedERC20EventParameters(AbstractDetector): class UnindexedERC20EventParameters(AbstractDetector):
@ -39,7 +44,9 @@ Failure to include these keywords will exclude the parameter data in the transac
STANDARD_JSON = False STANDARD_JSON = False
@staticmethod @staticmethod
def detect_erc20_unindexed_event_params(contract): def detect_erc20_unindexed_event_params(
contract: Contract,
) -> List[Union[Tuple[Event, EventVariable], Any]]:
""" """
Detect un-indexed ERC20 event parameters in a given contract. Detect un-indexed ERC20 event parameters in a given contract.
:param contract: The contract to check ERC20 events for un-indexed parameters in. :param contract: The contract to check ERC20 events for un-indexed parameters in.
@ -68,7 +75,7 @@ Failure to include these keywords will exclude the parameter data in the transac
# Return the results. # Return the results.
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
""" """
Detect un-indexed ERC20 event parameters in all contracts. Detect un-indexed ERC20 event parameters in all contracts.
""" """

@ -1,4 +1,6 @@
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class Backdoor(AbstractDetector): class Backdoor(AbstractDetector):
@ -17,7 +19,7 @@ class Backdoor(AbstractDetector):
WIKI_EXPLOIT_SCENARIO = ".." WIKI_EXPLOIT_SCENARIO = ".."
WIKI_RECOMMENDATION = ".." WIKI_RECOMMENDATION = ".."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
results = [] results = []
for contract in self.compilation_unit.contracts_derived: for contract in self.compilation_unit.contracts_derived:

@ -9,11 +9,12 @@
TODO: dont report if the value is tainted by msg.value TODO: dont report if the value is tainted by msg.value
""" """
from typing import List from typing import Any, Tuple, Union, List
from slither.analyses.data_dependency.data_dependency import is_tainted, is_dependent
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
from slither.core.declarations import Function, Contract from slither.core.declarations import Function, Contract
from slither.analyses.data_dependency.data_dependency import is_tainted, is_dependent from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.solidity_variables import ( from slither.core.declarations.solidity_variables import (
SolidityFunction, SolidityFunction,
SolidityVariableComposed, SolidityVariableComposed,
@ -28,12 +29,11 @@ from slither.slithir.operations import (
Transfer, Transfer,
) )
# pylint: disable=too-many-nested-blocks,too-many-branches # pylint: disable=too-many-nested-blocks,too-many-branches
from slither.utils.output import Output from slither.utils.output import Output
def arbitrary_send(func: Function): def arbitrary_send(func: Function) -> Union[bool, List[Node]]:
if func.is_protected(): if func.is_protected():
return [] return []
@ -74,7 +74,9 @@ def arbitrary_send(func: Function):
return ret return ret
def detect_arbitrary_send(contract: Contract): def detect_arbitrary_send(
contract: Contract,
) -> List[Union[Tuple[FunctionContract, List[Node]], Any]]:
""" """
Detect arbitrary send Detect arbitrary send
Args: Args:

@ -1,10 +1,11 @@
""" """
Module detecting dead code Module detecting dead code
""" """
from typing import List, Tuple from typing import Any, Union, List, Tuple
from slither.core.declarations import Function, FunctionContract, Contract from slither.core.declarations import Function, FunctionContract, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class DeadCode(AbstractDetector): class DeadCode(AbstractDetector):
@ -34,7 +35,7 @@ contract Contract{
WIKI_RECOMMENDATION = "Remove unused functions." WIKI_RECOMMENDATION = "Remove unused functions."
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
results = [] results = []

@ -5,18 +5,19 @@ Note that require()/assert() are not considered here. Even if they
are in the outermost scope, they do not guarantee a revert, so a are in the outermost scope, they do not guarantee a revert, so a
default value can still be returned. default value can still be returned.
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.cfg.node import NodeType from slither.core.cfg.node import Node, NodeType
from slither.utils.output import Output
def is_revert(node): def is_revert(node: Node) -> bool:
return node.type == NodeType.THROW or any( return node.type == NodeType.THROW or any(
c.name in ["revert()", "revert(string"] for c in node.internal_calls c.name in ["revert()", "revert(string"] for c in node.internal_calls
) )
def _get_false_son(node): def _get_false_son(node: Node) -> Node:
"""Select the son node corresponding to a false branch """Select the son node corresponding to a false branch
Following this node stays on the outer scope of the function Following this node stays on the outer scope of the function
""" """
@ -60,7 +61,7 @@ If the condition in `myModif` is false, the execution of `get()` will return 0."
WIKI_RECOMMENDATION = "All the paths in a modifier must execute `_` or revert." WIKI_RECOMMENDATION = "All the paths in a modifier must execute `_` or revert."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
results = [] results = []
for c in self.contracts: for c in self.contracts:
for mod in c.modifiers: for mod in c.modifiers:

@ -1,13 +1,14 @@
""" """
Module detecting EIP-2612 domain separator collision Module detecting EIP-2612 domain separator collision
""" """
from typing import Union, List from typing import Any, Union, List
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.function import get_function_id from slither.utils.function import get_function_id
from slither.utils.output import Output
class DomainSeparatorCollision(AbstractDetector): class DomainSeparatorCollision(AbstractDetector):
@ -39,7 +40,7 @@ contract Contract{
WIKI_RECOMMENDATION = "Remove or rename the function that collides with DOMAIN_SEPARATOR()." WIKI_RECOMMENDATION = "Remove or rename the function that collides with DOMAIN_SEPARATOR()."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
domain_sig = get_function_id("DOMAIN_SEPARATOR()") domain_sig = get_function_id("DOMAIN_SEPARATOR()")
for contract in self.compilation_unit.contracts_derived: for contract in self.compilation_unit.contracts_derived:
if contract.is_erc20(): if contract.is_erc20():

@ -3,10 +3,10 @@ Module detecting suicidal contract
A suicidal contract is an unprotected function that calls selfdestruct A suicidal contract is an unprotected function that calls selfdestruct
""" """
from typing import List from typing import Any, Union, List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations import Function, Contract from slither.core.declarations import Function, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output from slither.utils.output import Output
@ -71,7 +71,7 @@ contract Buggy{
results.append(res) results.append(res)
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect the suicidal functions""" """Detect the suicidal functions"""
results = [] results = []
for contract in self.compilation_unit.contracts_derived: for contract in self.compilation_unit.contracts_derived:

@ -3,8 +3,12 @@ Module detecting suicidal contract
A suicidal contract is an unprotected function that calls selfdestruct A suicidal contract is an unprotected function that calls selfdestruct
""" """
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class Suicidal(AbstractDetector): class Suicidal(AbstractDetector):
@ -37,7 +41,7 @@ Bob calls `kill` and destructs the contract."""
WIKI_RECOMMENDATION = "Protect access to all sensitive functions." WIKI_RECOMMENDATION = "Protect access to all sensitive functions."
@staticmethod @staticmethod
def detect_suicidal_func(func): def detect_suicidal_func(func: FunctionContract) -> bool:
"""Detect if the function is suicidal """Detect if the function is suicidal
Detect the public functions calling suicide/selfdestruct without protection Detect the public functions calling suicide/selfdestruct without protection
@ -60,14 +64,14 @@ Bob calls `kill` and destructs the contract."""
return True return True
def detect_suicidal(self, contract): def detect_suicidal(self, contract: Contract) -> List[Union[Any, FunctionContract]]:
ret = [] ret = []
for f in contract.functions_declared: for f in contract.functions_declared:
if self.detect_suicidal_func(f): if self.detect_suicidal_func(f):
ret.append(f) ret.append(f)
return ret return ret
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect the suicidal functions""" """Detect the suicidal functions"""
results = [] results = []
for c in self.contracts: for c in self.contracts:

@ -7,8 +7,12 @@ Check for unimplemented functions that are never implemented
Consider public state variables as implemented functions Consider public state variables as implemented functions
Do not consider fallback function or constructor Do not consider fallback function or constructor
""" """
from typing import Any, List, Set, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
# Since 0.5.1, Solidity allows creating state variable matching a function signature. # Since 0.5.1, Solidity allows creating state variable matching a function signature.
older_solc_versions = ["0.5.0"] + ["0.4." + str(x) for x in range(0, 27)] older_solc_versions = ["0.5.0"] + ["0.4." + str(x) for x in range(0, 27)]
@ -55,10 +59,10 @@ All unimplemented functions must be implemented on a contract that is meant to b
WIKI_RECOMMENDATION = "Implement all unimplemented functions in any contract you intend to use directly (not simply inherit from)." WIKI_RECOMMENDATION = "Implement all unimplemented functions in any contract you intend to use directly (not simply inherit from)."
@staticmethod @staticmethod
def _match_state_variable(contract, f): def _match_state_variable(contract: Contract, f: FunctionContract) -> bool:
return any(s.full_name == f.full_name for s in contract.state_variables) return any(s.full_name == f.full_name for s in contract.state_variables)
def _detect_unimplemented_function(self, contract): def _detect_unimplemented_function(self, contract: Contract) -> Set[FunctionContract]:
""" """
Detects any function definitions which are not implemented in the given contract. Detects any function definitions which are not implemented in the given contract.
:param contract: The contract to search unimplemented functions for. :param contract: The contract to search unimplemented functions for.
@ -87,7 +91,7 @@ All unimplemented functions must be implemented on a contract that is meant to b
unimplemented.add(f) unimplemented.add(f)
return unimplemented return unimplemented
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect unimplemented functions """Detect unimplemented functions
Recursively visit the calls Recursively visit the calls

@ -1,6 +1,8 @@
import re import re
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.naming_convention.naming_convention import custom_format from slither.formatters.naming_convention.naming_convention import custom_format
from slither.utils.output import Output
class NamingConvention(AbstractDetector): class NamingConvention(AbstractDetector):
@ -36,28 +38,31 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
STANDARD_JSON = False STANDARD_JSON = False
@staticmethod @staticmethod
def is_cap_words(name): def is_cap_words(name: str) -> bool:
return re.search("^[A-Z]([A-Za-z0-9]+)?_?$", name) is not None return re.search("^[A-Z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod @staticmethod
def is_mixed_case(name): def is_mixed_case(name: str) -> bool:
return re.search("^[a-z]([A-Za-z0-9]+)?_?$", name) is not None return re.search("^[a-z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod @staticmethod
def is_mixed_case_with_underscore(name): def is_mixed_case_with_underscore(name: str) -> bool:
# Allow _ at the beginning to represent private variable # Allow _ at the beginning to represent private variable
# or unused parameters # or unused parameters
return re.search("^[_]?[a-z]([A-Za-z0-9]+)?_?$", name) is not None return re.search("^[_]?[a-z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod @staticmethod
def is_upper_case_with_underscores(name): def is_upper_case_with_underscores(name: str) -> bool:
return re.search("^[A-Z0-9_]+_?$", name) is not None return re.search("^[A-Z0-9_]+_?$", name) is not None
@staticmethod @staticmethod
def should_avoid_name(name): def should_avoid_name(name: str) -> bool:
return re.search("^[lOI]$", name) is not None return re.search("^[lOI]$", name) is not None
def _detect(self): # pylint: disable=too-many-branches,too-many-statements # pylint: disable=too-many-branches,too-many-statements
def _detect(
self,
) -> List[Union[Any, Output]]:
results = [] results = []
for contract in self.contracts: for contract in self.contracts:

@ -2,7 +2,7 @@
Module detecting dangerous use of block.timestamp Module detecting dangerous use of block.timestamp
""" """
from typing import List, Tuple from typing import Any, Union, List, Tuple
from slither.analyses.data_dependency.data_dependency import is_dependent from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
@ -13,6 +13,7 @@ from slither.core.declarations.solidity_variables import (
) )
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Binary, BinaryType from slither.slithir.operations import Binary, BinaryType
from slither.utils.output import Output
def _timestamp(func: Function) -> List[Node]: def _timestamp(func: Function) -> List[Node]:
@ -69,7 +70,7 @@ class Timestamp(AbstractDetector):
WIKI_EXPLOIT_SCENARIO = """"Bob's contract relies on `block.timestamp` for its randomness. Eve is a miner and manipulates `block.timestamp` to exploit Bob's contract.""" WIKI_EXPLOIT_SCENARIO = """"Bob's contract relies on `block.timestamp` for its randomness. Eve is a miner and manipulates `block.timestamp` to exploit Bob's contract."""
WIKI_RECOMMENDATION = "Avoid relying on `block.timestamp`." WIKI_RECOMMENDATION = "Avoid relying on `block.timestamp`."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""""" """"""
results = [] results = []

@ -1,9 +1,13 @@
""" """
Module detecting usage of low level calls Module detecting usage of low level calls
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import LowLevelCall from slither.slithir.operations import LowLevelCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class LowLevelCalls(AbstractDetector): class LowLevelCalls(AbstractDetector):
@ -23,7 +27,7 @@ class LowLevelCalls(AbstractDetector):
WIKI_RECOMMENDATION = "Avoid low-level calls. Check the call success. If the call is meant for a contract, check for code existence." WIKI_RECOMMENDATION = "Avoid low-level calls. Check the call success. If the call is meant for a contract, check for code existence."
@staticmethod @staticmethod
def _contains_low_level_calls(node): def _contains_low_level_calls(node: Node) -> bool:
""" """
Check if the node contains Low Level Calls Check if the node contains Low Level Calls
Returns: Returns:
@ -31,7 +35,9 @@ class LowLevelCalls(AbstractDetector):
""" """
return any(isinstance(ir, LowLevelCall) for ir in node.irs) return any(isinstance(ir, LowLevelCall) for ir in node.irs)
def detect_low_level_calls(self, contract): def detect_low_level_calls(
self, contract: Contract
) -> List[Union[Any, Tuple[FunctionContract, List[Node]]]]:
ret = [] ret = []
for f in [f for f in contract.functions if contract == f.contract_declarer]: for f in [f for f in contract.functions if contract == f.contract_declarer]:
nodes = f.nodes nodes = f.nodes
@ -40,7 +46,7 @@ class LowLevelCalls(AbstractDetector):
ret.append((f, assembly_nodes)) ret.append((f, assembly_nodes))
return ret return ret
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect the functions that use low level calls""" """Detect the functions that use low level calls"""
results = [] results = []
for c in self.contracts: for c in self.contracts:

@ -2,11 +2,17 @@
Module detecting missing events for critical contract parameters set by owners and used in access control Module detecting missing events for critical contract parameters set by owners and used in access control
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.slithir.operations.event_call import EventCall from slither.slithir.operations.event_call import EventCall
from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.variables.state_variable import StateVariable
from slither.utils.output import Output
class MissingEventsAccessControl(AbstractDetector): class MissingEventsAccessControl(AbstractDetector):
@ -45,7 +51,9 @@ contract C {
WIKI_RECOMMENDATION = "Emit an event for critical parameter changes." WIKI_RECOMMENDATION = "Emit an event for critical parameter changes."
@staticmethod @staticmethod
def _detect_missing_events(contract): def _detect_missing_events(
contract: Contract,
) -> List[Union[Any, Tuple[FunctionContract, List[Tuple[Node, StateVariable, Modifier]]]]]:
""" """
Detects if critical contract parameters set by owners and used in access control are missing events Detects if critical contract parameters set by owners and used in access control are missing events
:param contract: The contract to check :param contract: The contract to check
@ -80,7 +88,7 @@ contract C {
results.append((function, nodes)) results.append((function, nodes))
return results return results
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect missing events for critical contract parameters set by owners and used in access control """Detect missing events for critical contract parameters set by owners and used in access control
Returns: Returns:
list: {'(function, node)'} list: {'(function, node)'}

@ -2,11 +2,16 @@
Module detecting missing events for critical contract parameters set by owners and used in arithmetic Module detecting missing events for critical contract parameters set by owners and used in arithmetic
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.slithir.operations.event_call import EventCall from slither.slithir.operations.event_call import EventCall
from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.state_variable import StateVariable
from slither.utils.output import Output
class MissingEventsArithmetic(AbstractDetector): class MissingEventsArithmetic(AbstractDetector):
@ -49,7 +54,9 @@ contract C {
WIKI_RECOMMENDATION = "Emit an event for critical parameter changes." WIKI_RECOMMENDATION = "Emit an event for critical parameter changes."
@staticmethod @staticmethod
def _detect_unprotected_use(contract, sv): def _detect_unprotected_use(
contract: Contract, sv: StateVariable
) -> List[Union[Tuple[Node, FunctionContract], Any]]:
unprotected_functions = [ unprotected_functions = [
function for function in contract.functions_declared if not function.is_protected() function for function in contract.functions_declared if not function.is_protected()
] ]
@ -60,7 +67,11 @@ contract C {
if sv in node.state_variables_read if sv in node.state_variables_read
] ]
def _detect_missing_events(self, contract): def _detect_missing_events(
self, contract: Contract
) -> List[
Union[Tuple[FunctionContract, List[Tuple[Node, List[Tuple[Node, FunctionContract]]]]], Any]
]:
""" """
Detects if critical contract parameters set by owners and used in arithmetic are missing events Detects if critical contract parameters set by owners and used in arithmetic are missing events
:param contract: The contract to check :param contract: The contract to check
@ -101,7 +112,7 @@ contract C {
results.append((function, nodes)) results.append((function, nodes))
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect missing events for critical contract parameters set by owners and used in arithmetic """Detect missing events for critical contract parameters set by owners and used in arithmetic
Returns: Returns:
list: {'(function, node)'} list: {'(function, node)'}

@ -3,12 +3,18 @@ Module detecting missing zero address validation
""" """
from collections import defaultdict from collections import defaultdict
from typing import Any, DefaultDict, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.solidity_types.elementary_type import ElementaryType
from slither.slithir.operations import Send, Transfer, LowLevelCall from slither.slithir.operations import Send, Transfer, LowLevelCall
from slither.slithir.operations import Call from slither.slithir.operations import Call
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function import ModifierStatements
from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.local_variable import LocalVariable
from slither.utils.output import Output
class MissingZeroAddressValidation(AbstractDetector): class MissingZeroAddressValidation(AbstractDetector):
@ -46,7 +52,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
WIKI_RECOMMENDATION = "Check that the address is not zero." WIKI_RECOMMENDATION = "Check that the address is not zero."
def _zero_address_validation_in_modifier(self, var, modifier_exprs): def _zero_address_validation_in_modifier(
self, var: LocalVariable, modifier_exprs: List[Union[ModifierStatements, Any]]
) -> bool:
for mod in modifier_exprs: for mod in modifier_exprs:
for node in mod.nodes: for node in mod.nodes:
# Skip validation if the modifier's parameters contains more than one variable # Skip validation if the modifier's parameters contains more than one variable
@ -62,7 +70,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
return True return True
return False return False
def _zero_address_validation(self, var, node, explored): def _zero_address_validation(
self, var: LocalVariable, node: Node, explored: List[Union[Any, Node]]
) -> bool:
""" """
Detects (recursively) if var is (zero address) checked in the function node Detects (recursively) if var is (zero address) checked in the function node
""" """
@ -83,7 +93,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
return True return True
return False return False
def _detect_missing_zero_address_validation(self, contract): def _detect_missing_zero_address_validation(
self, contract: Contract
) -> List[Union[Tuple[FunctionContract, DefaultDict[LocalVariable, List[Node]]], Any]]:
""" """
Detects if addresses are zero address validated before use. Detects if addresses are zero address validated before use.
:param contract: The contract to check :param contract: The contract to check
@ -130,7 +142,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
results.append((function, var_nodes)) results.append((function, var_nodes))
return results return results
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect if addresses are zero address validated before use. """Detect if addresses are zero address validated before use.
Returns: Returns:
list: {'(function, node)'} list: {'(function, node)'}

@ -4,6 +4,7 @@ Module detecting unused return values from low level
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import LowLevelCall from slither.slithir.operations import LowLevelCall
from slither.slithir.operations.operation import Operation
class UncheckedLowLevel(UnusedReturnValues): class UncheckedLowLevel(UnusedReturnValues):
@ -37,5 +38,5 @@ If the low level is used to prevent blocking operations, consider logging failed
WIKI_RECOMMENDATION = "Ensure that the return value of a low-level call is checked or logged." WIKI_RECOMMENDATION = "Ensure that the return value of a low-level call is checked or logged."
def _is_instance(self, ir): # pylint: disable=no-self-use def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, LowLevelCall) return isinstance(ir, LowLevelCall)

@ -5,6 +5,7 @@ Module detecting unused return values from send
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import Send from slither.slithir.operations import Send
from slither.slithir.operations.operation import Operation
class UncheckedSend(UnusedReturnValues): class UncheckedSend(UnusedReturnValues):
@ -38,5 +39,5 @@ If `send` is used to prevent blocking operations, consider logging the failed `s
WIKI_RECOMMENDATION = "Ensure that the return value of `send` is checked or logged." WIKI_RECOMMENDATION = "Ensure that the return value of `send` is checked or logged."
def _is_instance(self, ir): # pylint: disable=no-self-use def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, Send) return isinstance(ir, Send)

@ -6,6 +6,7 @@ from slither.core.declarations import Function
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import HighLevelCall from slither.slithir.operations import HighLevelCall
from slither.slithir.operations.operation import Operation
class UncheckedTransfer(UnusedReturnValues): class UncheckedTransfer(UnusedReturnValues):
@ -45,7 +46,7 @@ Several tokens do not revert in case of failure and return false. If one of thes
"Use `SafeERC20`, or ensure that the transfer/transferFrom return value is checked." "Use `SafeERC20`, or ensure that the transfer/transferFrom return value is checked."
) )
def _is_instance(self, ir): # pylint: disable=no-self-use def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return ( return (
isinstance(ir, HighLevelCall) isinstance(ir, HighLevelCall)
and isinstance(ir.function, Function) and isinstance(ir.function, Function)

@ -1,11 +1,15 @@
""" """
Module detecting unused return values from external calls Module detecting unused return values from external calls
""" """
from typing import Any, List, Union
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import HighLevelCall from slither.slithir.operations import HighLevelCall
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.cfg.node import Node
from slither.core.declarations.function_contract import FunctionContract
from slither.slithir.operations.operation import Operation
from slither.utils.output import Output
class UnusedReturnValues(AbstractDetector): class UnusedReturnValues(AbstractDetector):
@ -40,7 +44,7 @@ contract MyConc{
WIKI_RECOMMENDATION = "Ensure that all the return values of the function calls are used." WIKI_RECOMMENDATION = "Ensure that all the return values of the function calls are used."
def _is_instance(self, ir): # pylint: disable=no-self-use def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, HighLevelCall) and ( return isinstance(ir, HighLevelCall) and (
( (
isinstance(ir.function, Function) isinstance(ir.function, Function)
@ -50,7 +54,9 @@ contract MyConc{
or not isinstance(ir.function, Function) or not isinstance(ir.function, Function)
) )
def detect_unused_return_values(self, f): # pylint: disable=no-self-use def detect_unused_return_values(
self, f: FunctionContract
) -> List[Union[Node, Any]]: # pylint: disable=no-self-use
""" """
Return the nodes where the return value of a call is unused Return the nodes where the return value of a call is unused
Args: Args:
@ -73,7 +79,7 @@ contract MyConc{
return [nodes_origin[value].node for value in values_returned] return [nodes_origin[value].node for value in values_returned]
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect high level calls which return a value that are never used""" """Detect high level calls which return a value that are never used"""
results = [] results = []
for c in self.compilation_unit.contracts: for c in self.compilation_unit.contracts:

@ -1,5 +1,7 @@
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Nop from slither.slithir.operations import Nop
from slither.utils.output import Output
class VoidConstructor(AbstractDetector): class VoidConstructor(AbstractDetector):
@ -26,7 +28,7 @@ contract B is A{
When reading `B`'s constructor definition, we might assume that `A()` initiates the contract, but no code is executed.""" When reading `B`'s constructor definition, we might assume that `A()` initiates the contract, but no code is executed."""
# endregion wiki_exploit_scenario # endregion wiki_exploit_scenario
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""""" """"""
results = [] results = []
for c in self.contracts: for c in self.contracts:

@ -5,10 +5,11 @@
Iterate over all the nodes of the graph until reaching a fixpoint Iterate over all the nodes of the graph until reaching a fixpoint
""" """
from collections import namedtuple, defaultdict from collections import namedtuple, defaultdict
from typing import List from typing import Any, DefaultDict, Set, Union, List
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"]) FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"]) FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -50,7 +51,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
STANDARD_JSON = False STANDARD_JSON = False
def find_reentrancies(self): def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]:
result = defaultdict(set) result = defaultdict(set)
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_declared: for f in contract.functions_and_modifiers_declared:
@ -87,7 +88,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
result[finding_key] |= not_read_then_written result[finding_key] |= not_read_then_written
return result return result
def _detect(self): # pylint: disable=too-many-branches def _detect(self) -> List[Union[Output, Any]]: # pylint: disable=too-many-branches
"""""" """"""
super()._detect() super()._detect()

@ -5,9 +5,11 @@
Iterate over all the nodes of the graph until reaching a fixpoint Iterate over all the nodes of the graph until reaching a fixpoint
""" """
from collections import namedtuple, defaultdict from collections import namedtuple, defaultdict
from typing import Any, DefaultDict, List, Set, Union
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"]) FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"]) FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -48,7 +50,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
STANDARD_JSON = False STANDARD_JSON = False
def find_reentrancies(self): def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]:
result = defaultdict(set) result = defaultdict(set)
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_declared: for f in contract.functions_and_modifiers_declared:
@ -80,7 +82,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
result[finding_key] |= finding_vars result[finding_key] |= finding_vars
return result return result
def _detect(self): # pylint: disable=too-many-branches def _detect(self) -> List[Union[Any, Output]]: # pylint: disable=too-many-branches
"""""" """"""
super()._detect() super()._detect()

@ -5,11 +5,15 @@
Iterate over all the nodes of the graph until reaching a fixpoint Iterate over all the nodes of the graph until reaching a fixpoint
""" """
from collections import namedtuple, defaultdict from collections import namedtuple, defaultdict
from typing import Any, DefaultDict, List, Union
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.abstract_detector import DetectorClassification
from slither.slithir.operations import Send, Transfer, EventCall from slither.slithir.operations import Send, Transfer, EventCall
from .reentrancy import Reentrancy, to_hashable from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations.member import Member
from slither.slithir.operations.return_operation import Return
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"]) FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"]) FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -50,7 +54,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
@staticmethod @staticmethod
def can_callback(ir): def can_callback(ir: Union[Member, Return, HighLevelCall]) -> bool:
""" """
Same as Reentrancy, but also consider Send and Transfer Same as Reentrancy, but also consider Send and Transfer
@ -59,7 +63,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
STANDARD_JSON = False STANDARD_JSON = False
def find_reentrancies(self): def find_reentrancies(self) -> DefaultDict[Any, Any]:
result = defaultdict(set) result = defaultdict(set)
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_declared: for f in contract.functions_and_modifiers_declared:
@ -97,7 +101,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
result[finding_key] |= finding_vars result[finding_key] |= finding_vars
return result return result
def _detect(self): # pylint: disable=too-many-branches,too-many-locals def _detect(self) -> List[Any]: # pylint: disable=too-many-branches,too-many-locals
"""""" """"""
super()._detect() super()._detect()

@ -1,8 +1,13 @@
""" """
Module detecting reserved keyword shadowing Module detecting reserved keyword shadowing
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.variables.local_variable import LocalVariable
from slither.utils.output import Output
class BuiltinSymbolShadowing(AbstractDetector): class BuiltinSymbolShadowing(AbstractDetector):
@ -114,7 +119,7 @@ contract Bug {
"unchecked", "unchecked",
] ]
def is_builtin_symbol(self, word): def is_builtin_symbol(self, word: str) -> bool:
"""Detects if a given word is a built-in symbol. """Detects if a given word is a built-in symbol.
Returns: Returns:
@ -122,7 +127,9 @@ contract Bug {
return word in self.BUILTIN_SYMBOLS or word in self.RESERVED_KEYWORDS return word in self.BUILTIN_SYMBOLS or word in self.RESERVED_KEYWORDS
def detect_builtin_shadowing_locals(self, function_or_modifier): def detect_builtin_shadowing_locals(
self, function_or_modifier: Union[Modifier, FunctionContract]
) -> List[Union[Any, Tuple[str, LocalVariable]]]:
"""Detects if local variables in a given function/modifier are named after built-in symbols. """Detects if local variables in a given function/modifier are named after built-in symbols.
Any such items are returned in a list. Any such items are returned in a list.
@ -135,7 +142,7 @@ contract Bug {
results.append((self.SHADOWING_LOCAL_VARIABLE, local)) results.append((self.SHADOWING_LOCAL_VARIABLE, local))
return results return results
def detect_builtin_shadowing_definitions(self, contract): def detect_builtin_shadowing_definitions(self, contract: Contract) -> List[Any]:
"""Detects if functions, access modifiers, events, state variables, or local variables are named after built-in """Detects if functions, access modifiers, events, state variables, or local variables are named after built-in
symbols. Any such definitions are returned in a list. symbols. Any such definitions are returned in a list.
@ -164,7 +171,7 @@ contract Bug {
return result return result
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect shadowing of built-in symbols """Detect shadowing of built-in symbols
Recursively visit the calls Recursively visit the calls

@ -1,8 +1,15 @@
""" """
Module detecting local variable shadowing Module detecting local variable shadowing
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.event import Event
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.utils.output import Output
class LocalShadowing(AbstractDetector): class LocalShadowing(AbstractDetector):
@ -50,7 +57,18 @@ contract Bug {
OVERSHADOWED_STATE_VARIABLE = "state variable" OVERSHADOWED_STATE_VARIABLE = "state variable"
OVERSHADOWED_EVENT = "event" OVERSHADOWED_EVENT = "event"
def detect_shadowing_definitions(self, contract): # pylint: disable=too-many-branches # pylint: disable=too-many-branches
def detect_shadowing_definitions(
self, contract: Contract
) -> List[
Union[
Any,
Tuple[LocalVariable, List[Tuple[str, StateVariable]]],
Tuple[LocalVariable, List[Tuple[str, FunctionContract]]],
Tuple[LocalVariable, List[Tuple[str, Modifier]]],
Tuple[LocalVariable, List[Tuple[str, Event]]],
]
]:
"""Detects if functions, access modifiers, events, state variables, and local variables are named after """Detects if functions, access modifiers, events, state variables, and local variables are named after
reserved keywords. Any such definitions are returned in a list. reserved keywords. Any such definitions are returned in a list.
@ -93,7 +111,7 @@ contract Bug {
return result return result
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
"""Detect shadowing local variables """Detect shadowing local variables
Recursively visit the calls Recursively visit the calls

@ -2,12 +2,16 @@
Module detecting shadowing of state variables Module detecting shadowing of state variables
""" """
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from typing import Any, List, Union
from slither.core.declarations import Contract from slither.core.declarations import Contract
from .common import is_upgradable_gap_variable from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
from slither.detectors.shadowing.common import is_upgradable_gap_variable
def detect_shadowing(contract: Contract): def detect_shadowing(contract: Contract) -> List[Union[List[StateVariable], Any]]:
ret = [] ret = []
variables_fathers = [] variables_fathers = []
for father in contract.inheritance: for father in contract.inheritance:
@ -70,7 +74,7 @@ contract DerivedContract is BaseContract{
WIKI_RECOMMENDATION = "Remove the state variable shadowing." WIKI_RECOMMENDATION = "Remove the state variable shadowing."
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect shadowing """Detect shadowing
Recursively visit the calls Recursively visit the calls

@ -1,10 +1,11 @@
from collections import defaultdict from collections import defaultdict
from typing import Any, List, Union
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
def _find_missing_inheritance(compilation_unit: SlitherCompilationUnit): def _find_missing_inheritance(compilation_unit: SlitherCompilationUnit) -> List[Any]:
""" """
Filter contracts with missing inheritance to return only the "most base" contracts Filter contracts with missing inheritance to return only the "most base" contracts
in the inheritance tree. in the inheritance tree.
@ -50,7 +51,10 @@ As a result, the second contract cannot be analyzed.
WIKI_RECOMMENDATION = "Rename the contract." WIKI_RECOMMENDATION = "Rename the contract."
def _detect(self): # pylint: disable=too-many-locals,too-many-branches # pylint: disable=too-many-locals,too-many-branches
def _detect(
self,
) -> List[Union[Any, Output]]:
results = [] results = []
compilation_unit = self.compilation_unit compilation_unit = self.compilation_unit

@ -1,5 +1,8 @@
import re import re
from typing import Any, List, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
# pylint: disable=bidirectional-unicode # pylint: disable=bidirectional-unicode
class RightToLeftOverride(AbstractDetector): class RightToLeftOverride(AbstractDetector):
@ -52,7 +55,7 @@ contract Token
RTLO_CHARACTER_ENCODED = "\u202e".encode("utf-8") RTLO_CHARACTER_ENCODED = "\u202e".encode("utf-8")
STANDARD_JSON = False STANDARD_JSON = False
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
results = [] results = []
pattern = re.compile(".*\u202e.*".encode("utf-8")) pattern = re.compile(".*\u202e.*".encode("utf-8"))

@ -1,21 +1,23 @@
""" """
Module detecting assignment of array length Module detecting assignment of array length
""" """
from typing import List, Set
from slither.detectors.abstract_detector import ( from slither.detectors.abstract_detector import (
AbstractDetector, AbstractDetector,
DetectorClassification, DetectorClassification,
ALL_SOLC_VERSIONS_04, ALL_SOLC_VERSIONS_04,
ALL_SOLC_VERSIONS_05, ALL_SOLC_VERSIONS_05,
) )
from slither.core.cfg.node import NodeType from slither.core.cfg.node import Node, NodeType
from slither.slithir.operations import Assignment, Length from slither.slithir.operations import Assignment, Length
from slither.slithir.variables.reference import ReferenceVariable from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.operations.binary import Binary from slither.slithir.operations.binary import Binary
from slither.analyses.data_dependency.data_dependency import is_tainted from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
def detect_array_length_assignment(contract): def detect_array_length_assignment(contract: Contract) -> Set[Node]:
""" """
Detects and returns all nodes which assign array length. Detects and returns all nodes which assign array length.
:param contract: Contract to detect assignment within. :param contract: Contract to detect assignment within.
@ -110,7 +112,7 @@ Otherwise, thoroughly review the contract to ensure a user-controlled variable c
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 + ALL_SOLC_VERSIONS_05 VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04 + ALL_SOLC_VERSIONS_05
def _detect(self): def _detect(self) -> List[Output]:
""" """
Detect array length assignments Detect array length assignments
""" """

@ -1,9 +1,12 @@
""" """
Module detecting usage of inline assembly Module detecting usage of inline assembly
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.cfg.node import NodeType from slither.core.cfg.node import Node, NodeType
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class Assembly(AbstractDetector): class Assembly(AbstractDetector):
@ -23,7 +26,7 @@ class Assembly(AbstractDetector):
WIKI_RECOMMENDATION = "Do not use `evm` assembly." WIKI_RECOMMENDATION = "Do not use `evm` assembly."
@staticmethod @staticmethod
def _contains_inline_assembly_use(node): def _contains_inline_assembly_use(node: Node) -> bool:
""" """
Check if the node contains ASSEMBLY type Check if the node contains ASSEMBLY type
Returns: Returns:
@ -31,7 +34,9 @@ class Assembly(AbstractDetector):
""" """
return node.type == NodeType.ASSEMBLY return node.type == NodeType.ASSEMBLY
def detect_assembly(self, contract): def detect_assembly(
self, contract: Contract
) -> List[Union[Any, Tuple[FunctionContract, List[Node]]]]:
ret = [] ret = []
for f in contract.functions: for f in contract.functions:
if f.contract_declarer != contract: if f.contract_declarer != contract:
@ -42,7 +47,7 @@ class Assembly(AbstractDetector):
ret.append((f, assembly_nodes)) ret.append((f, assembly_nodes))
return ret return ret
def _detect(self): def _detect(self) -> List[Union[Output, Any]]:
"""Detect the functions that use inline assembly""" """Detect the functions that use inline assembly"""
results = [] results = []
for c in self.contracts: for c in self.contracts:

@ -1,11 +1,18 @@
""" """
Module detecting state changes in assert calls Module detecting state changes in assert calls
""" """
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations.internal_call import InternalCall from slither.slithir.operations.internal_call import InternalCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
def detect_assert_state_change(contract): def detect_assert_state_change(
contract: Contract,
) -> List[Union[Tuple[FunctionContract, Node], Any]]:
""" """
Detects and returns all nodes with assert calls that change contract state from within the invariant Detects and returns all nodes with assert calls that change contract state from within the invariant
:param contract: Contract to detect :param contract: Contract to detect
@ -69,7 +76,7 @@ The assert in `bad()` increments the state variable `s_a` while checking for the
WIKI_RECOMMENDATION = """Use `require` for invariants modifying the state.""" WIKI_RECOMMENDATION = """Use `require` for invariants modifying the state."""
def _detect(self): def _detect(self) -> List[Union[Any, Output]]:
""" """
Detect assert calls that change state from within the invariant Detect assert calls that change state from within the invariant
""" """

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save