Merge branch 'dev' into dev-fix-parsing-test

pull/682/head
Josselin 4 years ago
commit 87844f0f86
  1. 1
      .github/workflows/linter.yml
  2. 1
      CONTRIBUTING.md
  3. 4
      plugin_example/setup.py
  4. 3
      pyproject.toml
  5. 10
      slither/__main__.py
  6. 19
      slither/analyses/data_dependency/data_dependency.py
  7. 5
      slither/analyses/write/are_variables_written.py
  8. 8
      slither/core/cfg/node.py
  9. 17
      slither/core/declarations/function.py
  10. 4
      slither/core/solidity_types/function_type.py
  11. 3
      slither/detectors/attributes/locked_ether.py
  12. 8
      slither/detectors/functions/arbitrary_send.py
  13. 14
      slither/detectors/naming_convention/naming_convention.py
  14. 4
      slither/detectors/operations/block_timestamp.py
  15. 3
      slither/detectors/reentrancy/reentrancy.py
  16. 12
      slither/detectors/reentrancy/reentrancy_benign.py
  17. 10
      slither/detectors/reentrancy/reentrancy_eth.py
  18. 12
      slither/detectors/reentrancy/reentrancy_events.py
  19. 18
      slither/detectors/reentrancy/reentrancy_no_gas.py
  20. 7
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  21. 7
      slither/formatters/attributes/constant_pragma.py
  22. 7
      slither/formatters/naming_convention/naming_convention.py
  23. 58
      slither/printers/call/call_graph.py
  24. 6
      slither/printers/functions/authorization.py
  25. 2
      slither/printers/guidance/echidna.py
  26. 6
      slither/printers/summary/evm.py
  27. 19
      slither/printers/summary/function.py
  28. 9
      slither/printers/summary/human_summary.py
  29. 5
      slither/printers/summary/require_calls.py
  30. 26
      slither/slithir/convert.py
  31. 6
      slither/slithir/operations/binary.py
  32. 6
      slither/slithir/operations/library_call.py
  33. 9
      slither/slithir/tmp_operations/tmp_call.py
  34. 18
      slither/slithir/utils/ssa.py
  35. 9
      slither/slithir/utils/utils.py
  36. 9
      slither/solc_parsing/declarations/contract.py
  37. 8
      slither/solc_parsing/declarations/function.py
  38. 9
      slither/solc_parsing/expressions/expression_parsing.py
  39. 12
      slither/solc_parsing/slitherSolc.py
  40. 9
      slither/solc_parsing/solidity_types/type_parsing.py
  41. 11
      slither/solc_parsing/yul/parse_yul.py
  42. 3
      slither/tools/erc_conformance/__main__.py
  43. 13
      slither/tools/flattening/__main__.py
  44. 4
      slither/tools/flattening/export/export.py
  45. 15
      slither/tools/flattening/flattening.py
  46. 11
      slither/tools/kspec_coverage/__main__.py
  47. 3
      slither/tools/possible_paths/__main__.py
  48. 3
      slither/tools/possible_paths/possible_paths.py
  49. 4
      slither/tools/properties/__main__.py
  50. 6
      slither/tools/properties/properties/erc20.py
  51. 11
      slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py
  52. 2
      slither/tools/properties/properties/properties.py
  53. 5
      slither/tools/similarity/__main__.py
  54. 11
      slither/tools/slither_format/__main__.py
  55. 5
      slither/tools/slither_format/slither_format.py
  56. 5
      slither/tools/upgradeability/__main__.py
  57. 43
      slither/utils/erc.py
  58. 12
      slither/utils/expression_manipulations.py
  59. 4
      slither/utils/inheritance_analysis.py
  60. 44
      slither/utils/output.py
  61. 10
      tests/test_ast_parsing.py

@ -72,6 +72,7 @@ jobs:
VALIDATE_PYTHON: false VALIDATE_PYTHON: false
VALIDATE_PYTHON_PYLINT: false VALIDATE_PYTHON_PYLINT: false
VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_BLACK: false
VALIDATE_PYTHON_ISORT: false
# Always false # Always false
VALIDATE_JSON: false VALIDATE_JSON: false
VALIDATE_JAVASCRIPT_STANDARD: false VALIDATE_JAVASCRIPT_STANDARD: false

@ -33,6 +33,7 @@ To run them locally:
- `pylint slither --rconfig pyproject.toml` - `pylint slither --rconfig pyproject.toml`
- `black slither --config pyproject.toml` - `black slither --config pyproject.toml`
We use black `19.10b0`.
## Detectors regression tests ## Detectors regression tests
For each new detector, at least one regression tests must be present. For each new detector, at least one regression tests must be present.

@ -9,7 +9,5 @@ setup(
packages=find_packages(), packages=find_packages(),
python_requires=">=3.6", python_requires=">=3.6",
install_requires=["slither-analyzer==0.1"], install_requires=["slither-analyzer==0.1"],
entry_points={ entry_points={"slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin",},
"slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin",
},
) )

@ -17,5 +17,6 @@ too-many-ancestors,
logging-fstring-interpolation, logging-fstring-interpolation,
logging-not-lazy, logging-not-lazy,
duplicate-code, duplicate-code,
import-error import-error,
unsubscriptable-object
""" """

@ -402,10 +402,7 @@ def parse_args(detector_classes, printer_classes):
) )
group_misc.add_argument( group_misc.add_argument(
"--markdown-root", "--markdown-root", help="URL for markdown generation", action="store", default="",
help="URL for markdown generation",
action="store",
default="",
) )
group_misc.add_argument( group_misc.add_argument(
@ -440,10 +437,7 @@ def parse_args(detector_classes, printer_classes):
) )
group_misc.add_argument( group_misc.add_argument(
"--solc-ast", "--solc-ast", help="Provide the contract as a json AST", action="store_true", default=False,
help="Provide the contract as a json AST",
action="store_true",
default=False,
) )
group_misc.add_argument( group_misc.add_argument(

@ -135,9 +135,7 @@ def is_tainted_ssa(variable, context, only_unprotected=False, ignore_generic_tai
def get_dependencies( def get_dependencies(
variable: Variable, variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False,
context: Union[Contract, Function],
only_unprotected: bool = False,
) -> Set[Variable]: ) -> Set[Variable]:
""" """
Return the variables for which `variable` depends on. Return the variables for which `variable` depends on.
@ -172,9 +170,7 @@ def get_all_dependencies(
def get_dependencies_ssa( def get_dependencies_ssa(
variable: Variable, variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False,
context: Union[Contract, Function],
only_unprotected: bool = False,
) -> Set[Variable]: ) -> Set[Variable]:
""" """
Return the variables for which `variable` depends on (SSA version). Return the variables for which `variable` depends on (SSA version).
@ -380,16 +376,7 @@ def convert_variable_to_non_ssa(v):
return v.non_ssa_version return v.non_ssa_version
assert isinstance( assert isinstance(
v, v,
( (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,),
Constant,
SolidityVariable,
Contract,
Enum,
SolidityFunction,
Structure,
Function,
Type,
),
) )
return v return v

@ -35,10 +35,7 @@ class State: # pylint: disable=too-few-public-methods
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def _visit( def _visit(
node: Node, node: Node, state: State, variables_written: Set[Variable], variables_to_write: List[Variable],
state: State,
variables_written: Set[Variable],
variables_to_write: List[Variable],
): ):
""" """
Explore all the nodes to look for values not written when the node's function return Explore all the nodes to look for values not written when the node's function return

@ -800,15 +800,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
@property @property
def phi_origins_local_variables( def phi_origins_local_variables(self,) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
self,
) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]:
return self._phi_origins_local_variables return self._phi_origins_local_variables
@property @property
def phi_origins_state_variables( def phi_origins_state_variables(self,) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
self,
) -> Dict[str, Tuple[StateVariable, Set["Node"]]]:
return self._phi_origins_state_variables return self._phi_origins_state_variables
# @property # @property

@ -53,10 +53,7 @@ ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
class ModifierStatements: class ModifierStatements:
def __init__( def __init__(
self, self, modifier: Union["Contract", "Function"], entry_point: "Node", nodes: List["Node"],
modifier: Union["Contract", "Function"],
entry_point: "Node",
nodes: List["Node"],
): ):
self._modifier = modifier self._modifier = modifier
self._entry_point = entry_point self._entry_point = entry_point
@ -1144,9 +1141,7 @@ class Function(
@staticmethod @staticmethod
def _explore_func_conditional( def _explore_func_conditional(
func: "Function", func: "Function", f: Callable[["Node"], List[SolidityVariable]], include_loop: bool,
f: Callable[["Node"], List[SolidityVariable]],
include_loop: bool,
): ):
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]
@ -1602,14 +1597,10 @@ class Function(
return ret return ret
def get_last_ssa_state_variables_instances( def get_last_ssa_state_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]:
self,
) -> Dict[str, Set["SlithIRVariable"]]:
return self._get_last_ssa_variable_instances(target_state=True, target_local=False) return self._get_last_ssa_variable_instances(target_state=True, target_local=False)
def get_last_ssa_local_variables_instances( def get_last_ssa_local_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]:
self,
) -> Dict[str, Set["SlithIRVariable"]]:
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

@ -6,9 +6,7 @@ from slither.core.variables.function_type_variable import FunctionTypeVariable
class FunctionType(Type): class FunctionType(Type):
def __init__( def __init__(
self, self, params: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable],
params: List[FunctionTypeVariable],
return_values: List[FunctionTypeVariable],
): ):
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)

@ -53,8 +53,7 @@ Every Ether sent to `Locked` will be lost."""
for node in function.nodes: for node in function.nodes:
for ir in node.irs: for ir in node.irs:
if isinstance( if isinstance(
ir, ir, (Send, Transfer, HighLevelCall, LowLevelCall, NewContract),
(Send, Transfer, HighLevelCall, LowLevelCall, NewContract),
): ):
if ir.call_value and ir.call_value != 0: if ir.call_value and ir.call_value != 0:
return False return False

@ -41,9 +41,7 @@ def arbitrary_send(func):
if ir.variable_right == SolidityVariableComposed("msg.sender"): if ir.variable_right == SolidityVariableComposed("msg.sender"):
return False return False
if is_dependent( if is_dependent(
ir.variable_right, ir.variable_right, SolidityVariableComposed("msg.sender"), func.contract,
SolidityVariableComposed("msg.sender"),
func.contract,
): ):
return False return False
if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)): if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)):
@ -56,9 +54,7 @@ def arbitrary_send(func):
if ir.call_value == SolidityVariableComposed("msg.value"): if ir.call_value == SolidityVariableComposed("msg.value"):
continue continue
if is_dependent( if is_dependent(
ir.call_value, ir.call_value, SolidityVariableComposed("msg.value"), func.contract,
SolidityVariableComposed("msg.value"),
func.contract,
): ):
continue continue

@ -86,14 +86,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
if func.is_constructor: if func.is_constructor:
continue continue
if not self.is_mixed_case(func.name): if not self.is_mixed_case(func.name):
if ( if func.visibility in [
func.visibility
in [
"internal", "internal",
"private", "private",
] ] and self.is_mixed_case_with_underscore(func.name):
and self.is_mixed_case_with_underscore(func.name)
):
continue continue
if func.name.startswith("echidna_") or func.name.startswith("crytic_"): if func.name.startswith("echidna_") or func.name.startswith("crytic_"):
continue continue
@ -129,11 +125,7 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
res = self.generate_result(info) res = self.generate_result(info)
res.add( res.add(
var, var, {"target": "variable", "convention": "l_O_I_should_not_be_used",},
{
"target": "variable",
"convention": "l_O_I_should_not_be_used",
},
) )
results.append(res) results.append(res)

@ -36,9 +36,7 @@ def _timestamp(func: Function) -> List[Node]:
return sorted(list(ret), key=lambda x: x.node_id) return sorted(list(ret), key=lambda x: x.node_id)
def _detect_dangerous_timestamp( def _detect_dangerous_timestamp(contract: Contract,) -> List[Tuple[Function, List[Node]]]:
contract: Contract,
) -> List[Tuple[Function, List[Node]]]:
""" """
Args: Args:
contract (Contract) contract (Contract)

@ -127,8 +127,7 @@ class AbstractState:
) )
self._reads = union_dict(self._reads, father.context[detector.KEY].reads) self._reads = union_dict(self._reads, father.context[detector.KEY].reads)
self._reads_prior_calls = union_dict( self._reads_prior_calls = union_dict(
self.reads_prior_calls, self.reads_prior_calls, father.context[detector.KEY].reads_prior_calls,
father.context[detector.KEY].reads_prior_calls,
) )
def analyze_node(self, node, detector): def analyze_node(self, node, detector):

@ -63,11 +63,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
if v in node.context[self.KEY].reads_prior_calls[c] if v in node.context[self.KEY].reads_prior_calls[c]
] ]
not_read_then_written = { not_read_then_written = {
FindingValue( FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items() for (v, nodes) in node.context[self.KEY].written.items()
if v not in read_then_written if v not in read_then_written
} }
@ -130,8 +126,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# #
@ -143,8 +138,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# Add all variables written via nodes which write them. # Add all variables written via nodes which write them.

@ -63,9 +63,7 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
continue continue
read_then_written |= { read_then_written |= {
FindingValue( FindingValue(
v, v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
) )
for (v, nodes) in node.context[self.KEY].written.items() for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c] if v in node.context[self.KEY].reads_prior_calls[c]
@ -130,8 +128,7 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# If the calls are not the same ones that send eth, add the eth sending nodes. # If the calls are not the same ones that send eth, add the eth sending nodes.
@ -141,8 +138,7 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# Add all variables written via nodes which write them. # Add all variables written via nodes which write them.

@ -61,11 +61,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
send_eth=to_hashable(node.context[self.KEY].send_eth), send_eth=to_hashable(node.context[self.KEY].send_eth),
) )
finding_vars = { finding_vars = {
FindingValue( FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
e,
e.node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (e, nodes) in node.context[self.KEY].events.items() for (e, nodes) in node.context[self.KEY].events.items()
} }
if finding_vars: if finding_vars:
@ -119,8 +115,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# #
@ -132,8 +127,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
for finding_value in events: for finding_value in events:

@ -72,19 +72,11 @@ Only report reentrancy that is based on `transfer` or `send`."""
send_eth=to_hashable(node.context[self.KEY].send_eth), send_eth=to_hashable(node.context[self.KEY].send_eth),
) )
finding_vars = { finding_vars = {
FindingValue( FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
v,
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (v, nodes) in node.context[self.KEY].written.items() for (v, nodes) in node.context[self.KEY].written.items()
} }
finding_vars |= { finding_vars |= {
FindingValue( FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),)
e,
e.node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
)
for (e, nodes) in node.context[self.KEY].events.items() for (e, nodes) in node.context[self.KEY].events.items()
} }
if finding_vars: if finding_vars:
@ -159,8 +151,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# #
@ -172,8 +163,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# Add all variables written via nodes which write them. # Add all variables written via nodes which write them.

@ -58,9 +58,7 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
continue continue
read_then_written |= { read_then_written |= {
FindingValue( FindingValue(
v, v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),
node,
tuple(sorted(nodes, key=lambda x: x.node_id)),
) )
for (v, nodes) in node.context[self.KEY].written.items() for (v, nodes) in node.context[self.KEY].written.items()
if v in node.context[self.KEY].reads_prior_calls[c] if v in node.context[self.KEY].reads_prior_calls[c]
@ -116,8 +114,7 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
for call_list_info in calls_list: for call_list_info in calls_list:
if call_list_info != call_info: if call_list_info != call_info:
res.add( res.add(
call_list_info, call_list_info, {"underlying_type": "external_calls_sending_eth"},
{"underlying_type": "external_calls_sending_eth"},
) )
# Add all variables written via nodes which write them. # Add all variables written via nodes which write them.

@ -70,10 +70,5 @@ def _patch(
in_file_str = slither.source_code[in_file].encode("utf8") in_file_str = slither.source_code[in_file].encode("utf8")
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end]
create_patch( create_patch(
result, result, in_file, int(modify_loc_start), int(modify_loc_end), old_str_of_interest, pragma,
in_file,
int(modify_loc_start),
int(modify_loc_end),
old_str_of_interest,
pragma,
) )

@ -575,12 +575,7 @@ def _explore_irs(slither, irs, result, target, convert):
loc_end = loc_start + len(old_str) loc_end = loc_start + len(old_str)
create_patch( create_patch(
result, result, filename_source_code, loc_start, loc_end, old_str, new_str,
filename_source_code,
loc_start,
loc_end,
old_str,
new_str,
) )

@ -33,39 +33,21 @@ def _edge(from_node, to_node):
# return dot language string to add graph node (with optional label) # return dot language string to add graph node (with optional label)
def _node(node, label=None): def _node(node, label=None):
return " ".join( return " ".join((f'"{node}"', f'[label="{label}"]' if label is not None else "",))
(
f'"{node}"',
f'[label="{label}"]' if label is not None else "",
)
)
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
def _process_internal_call( def _process_internal_call(
contract, contract, function, internal_call, contract_calls, solidity_functions, solidity_calls,
function,
internal_call,
contract_calls,
solidity_functions,
solidity_calls,
): ):
if isinstance(internal_call, (Function)): if isinstance(internal_call, (Function)):
contract_calls[contract].add( contract_calls[contract].add(
_edge( _edge(_function_node(contract, function), _function_node(contract, internal_call),)
_function_node(contract, function),
_function_node(contract, internal_call),
)
) )
elif isinstance(internal_call, (SolidityFunction)): elif isinstance(internal_call, (SolidityFunction)):
solidity_functions.add( solidity_functions.add(_node(_solidity_function_node(internal_call)),)
_node(_solidity_function_node(internal_call)),
)
solidity_calls.add( solidity_calls.add(
_edge( _edge(_function_node(contract, function), _solidity_function_node(internal_call),)
_function_node(contract, function),
_solidity_function_node(internal_call),
)
) )
@ -102,12 +84,7 @@ def _render_solidity_calls(solidity_functions, solidity_calls):
def _process_external_call( def _process_external_call(
contract, contract, function, external_call, contract_functions, external_calls, all_contracts,
function,
external_call,
contract_functions,
external_calls,
all_contracts,
): ):
external_contract, external_function = external_call external_contract, external_function = external_call
@ -117,10 +94,7 @@ def _process_external_call(
# add variable as node to respective contract # add variable as node to respective contract
if isinstance(external_function, (Variable)): if isinstance(external_function, (Variable)):
contract_functions[external_contract].add( contract_functions[external_contract].add(
_node( _node(_function_node(external_contract, external_function), external_function.name,)
_function_node(external_contract, external_function),
external_function.name,
)
) )
external_calls.add( external_calls.add(
@ -142,27 +116,15 @@ def _process_function(
external_calls, external_calls,
all_contracts, all_contracts,
): ):
contract_functions[contract].add( contract_functions[contract].add(_node(_function_node(contract, function), function.name),)
_node(_function_node(contract, function), function.name),
)
for internal_call in function.internal_calls: for internal_call in function.internal_calls:
_process_internal_call( _process_internal_call(
contract, contract, function, internal_call, contract_calls, solidity_functions, solidity_calls,
function,
internal_call,
contract_calls,
solidity_functions,
solidity_calls,
) )
for external_call in function.high_level_calls: for external_call in function.high_level_calls:
_process_external_call( _process_external_call(
contract, contract, function, external_call, contract_functions, external_calls, all_contracts,
function,
external_call,
contract_functions,
external_calls,
all_contracts,
) )

@ -52,11 +52,7 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter):
state_variables_written = [v.name for v in function.all_state_variables_written()] state_variables_written = [v.name for v in function.all_state_variables_written()]
msg_sender_condition = self.get_msg_sender_checks(function) msg_sender_condition = self.get_msg_sender_checks(function)
table.add_row( table.add_row(
[ [function.name, str(state_variables_written), str(msg_sender_condition),]
function.name,
str(state_variables_written),
str(msg_sender_condition),
]
) )
all_tables.append((contract.name, table)) all_tables.append((contract.name, table))
txt += str(table) + "\n" txt += str(table) + "\n"

@ -158,7 +158,7 @@ def json_serializable(cls):
@json_serializable @json_serializable
class ConstantValue(NamedTuple): class ConstantValue(NamedTuple): # pylint: disable=inherit-non-class,too-few-public-methods
# Here value should be Union[str, int, bool] # Here value should be Union[str, int, bool]
# But the json lib in Echidna does not handle large integer in json # But the json lib in Echidna does not handle large integer in json
# So we convert everything to string # So we convert everything to string

@ -101,8 +101,7 @@ class PrinterEVM(AbstractPrinter):
) )
txt += green( txt += green(
"\t\tSource line {}: {}\n".format( "\t\tSource line {}: {}\n".format(
node_source_line, node_source_line, contract_file_lines[node_source_line - 1].rstrip(),
contract_file_lines[node_source_line - 1].rstrip(),
) )
) )
txt += magenta("\t\tEVM Instructions:\n") txt += magenta("\t\tEVM Instructions:\n")
@ -124,8 +123,7 @@ class PrinterEVM(AbstractPrinter):
) )
txt += green( txt += green(
"\t\tSource line {}: {}\n".format( "\t\tSource line {}: {}\n".format(
node_source_line, node_source_line, contract_file_lines[node_source_line - 1].rstrip(),
contract_file_lines[node_source_line - 1].rstrip(),
) )
) )
txt += magenta("\t\tEVM Instructions:\n") txt += magenta("\t\tEVM Instructions:\n")

@ -65,26 +65,11 @@ class FunctionSummary(AbstractPrinter):
internal_calls = self._convert(internal_calls) internal_calls = self._convert(internal_calls)
external_calls = self._convert(external_calls) external_calls = self._convert(external_calls)
table.add_row( table.add_row(
[ [f_name, visi, modifiers, read, write, internal_calls, external_calls,]
f_name,
visi,
modifiers,
read,
write,
internal_calls,
external_calls,
]
) )
txt += "\n \n" + str(table) txt += "\n \n" + str(table)
table = MyPrettyTable( table = MyPrettyTable(
[ ["Modifiers", "Visibility", "Read", "Write", "Internal Calls", "External Calls",]
"Modifiers",
"Visibility",
"Read",
"Write",
"Internal Calls",
"External Calls",
]
) )
for ( for (
_c_name, _c_name,

@ -379,14 +379,7 @@ class PrinterHumanSummary(AbstractPrinter):
) )
table.add_row( table.add_row(
[ [contract.name, number_functions, ercs, erc20_info, is_complex, features,]
contract.name,
number_functions,
ercs,
erc20_info,
is_complex,
features,
]
) )
self.info(txt + "\n" + str(table)) self.info(txt + "\n" + str(table))

@ -46,10 +46,7 @@ class RequireOrAssert(AbstractPrinter):
] ]
require = [ir.node for ir in require] require = [ir.node for ir in require]
table.add_row( table.add_row(
[ [function.name, self._convert([str(m.expression) for m in set(require)]),]
function.name,
self._convert([str(m.expression) for m in set(require)]),
]
) )
txt += "\n" + str(table) txt += "\n" + str(table)
self.info(txt) self.info(txt)

@ -206,8 +206,7 @@ def convert_arguments(arguments):
def is_temporary(ins): def is_temporary(ins):
return isinstance( return isinstance(
ins, ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
(Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
) )
@ -646,8 +645,7 @@ def propagate_types(ir, node): # pylint: disable=too-many-locals
# We dont need to check for function collision, as solc prevents the use of selector # We dont need to check for function collision, as solc prevents the use of selector
# if there are multiple functions with the same name # if there are multiple functions with the same name
f = next( f = next(
(f for f in type_t.functions if f.name == ir.variable_right), (f for f in type_t.functions if f.name == ir.variable_right), None,
None,
) )
if f: if f:
ir.lvalue.set_type(f) ir.lvalue.set_type(f)
@ -854,10 +852,7 @@ def extract_tmp_call(ins, contract): # pylint: disable=too-many-locals
ins.called = SolidityFunction("blockhash(uint256)") ins.called = SolidityFunction("blockhash(uint256)")
elif str(ins.called) == "this.balance": elif str(ins.called) == "this.balance":
s = SolidityCall( s = SolidityCall(
SolidityFunction("this.balance()"), SolidityFunction("this.balance()"), ins.nbr_arguments, ins.lvalue, ins.type_call,
ins.nbr_arguments,
ins.lvalue,
ins.type_call,
) )
s.set_expression(ins.expression) s.set_expression(ins.expression)
return s return s
@ -1148,11 +1143,7 @@ def look_for_library(contract, ir, using_for, t):
lib_contract = contract.slither.get_contract_from_name(str(destination)) lib_contract = contract.slither.get_contract_from_name(str(destination))
if lib_contract: if lib_contract:
lib_call = LibraryCall( lib_call = LibraryCall(
lib_contract, lib_contract, ir.function_name, ir.nbr_arguments, ir.lvalue, ir.type_call,
ir.function_name,
ir.nbr_arguments,
ir.lvalue,
ir.type_call,
) )
lib_call.set_expression(ir.expression) lib_call.set_expression(ir.expression)
lib_call.set_node(ir.node) lib_call.set_node(ir.node)
@ -1385,14 +1376,7 @@ def remove_temporary(result):
ins ins
for ins in result for ins in result
if not isinstance( if not isinstance(
ins, ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure,),
(
Argument,
TmpNewElementaryType,
TmpNewContract,
TmpNewArray,
TmpNewStructure,
),
) )
] ]

@ -175,11 +175,7 @@ class Binary(OperationWithLValue):
while isinstance(points, ReferenceVariable): while isinstance(points, ReferenceVariable):
points = points.points_to points = points.points_to
return "{}(-> {}) = {} {} {}".format( return "{}(-> {}) = {} {} {}".format(
str(self.lvalue), str(self.lvalue), points, self.variable_left, self.type_str, self.variable_right,
points,
self.variable_left,
self.type_str,
self.variable_right,
) )
return "{}({}) = {} {} {}".format( return "{}({}) = {} {} {}".format(
str(self.lvalue), str(self.lvalue),

@ -38,9 +38,5 @@ class LibraryCall(HighLevelCall):
lvalue = "{}({}) = ".format(self.lvalue, self.lvalue.type) lvalue = "{}({}) = ".format(self.lvalue, self.lvalue.type)
txt = "{}LIBRARY_CALL, dest:{}, function:{}, arguments:{} {}" txt = "{}LIBRARY_CALL, dest:{}, function:{}, arguments:{} {}"
return txt.format( return txt.format(
lvalue, lvalue, self.destination, self.function_name, [str(x) for x in arguments], gas,
self.destination,
self.function_name,
[str(x) for x in arguments],
gas,
) )

@ -13,14 +13,7 @@ class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attribu
def __init__(self, called, nbr_arguments, result, type_call): def __init__(self, called, nbr_arguments, result, type_call):
assert isinstance( assert isinstance(
called, called,
( (Contract, Variable, SolidityVariableComposed, SolidityFunction, Structure, Event,),
Contract,
Variable,
SolidityVariableComposed,
SolidityFunction,
Structure,
Event,
),
) )
super().__init__() super().__init__()
self._called = called self._called = called

@ -173,9 +173,7 @@ def add_ssa_ir(function, all_state_variables_instances):
init_state_variables_instances = dict(all_state_variables_instances) init_state_variables_instances = dict(all_state_variables_instances)
initiate_all_local_variables_instances( initiate_all_local_variables_instances(
function.nodes, function.nodes, init_local_variables_instances, all_init_local_variables_instances,
init_local_variables_instances,
all_init_local_variables_instances,
) )
generate_ssa_irs( generate_ssa_irs(
@ -508,8 +506,7 @@ def add_phi_origins(node, local_variables_definition, state_variables_definition
# We keep the instance as we want to avoid to add __hash__ on v.name in Variable # We keep the instance as we want to avoid to add __hash__ on v.name in Variable
# That might work for this used, but could create collision for other uses # That might work for this used, but could create collision for other uses
local_variables_definition = dict( local_variables_definition = dict(
local_variables_definition, local_variables_definition, **{v.name: (v, node) for v in node.local_variables_written},
**{v.name: (v, node) for v in node.local_variables_written},
) )
state_variables_definition = dict( state_variables_definition = dict(
state_variables_definition, state_variables_definition,
@ -601,16 +598,7 @@ def get(
return tuple_variables_instances[variable.index] return tuple_variables_instances[variable.index]
assert isinstance( assert isinstance(
variable, variable,
( (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,),
Constant,
SolidityVariable,
Contract,
Enum,
SolidityFunction,
Structure,
Function,
Type,
),
) # type for abi.decode(.., t) ) # type for abi.decode(.., t)
return variable return variable

@ -25,12 +25,5 @@ def is_valid_rvalue(v):
def is_valid_lvalue(v): def is_valid_lvalue(v):
return isinstance( return isinstance(
v, v, (StateVariable, LocalVariable, TemporaryVariable, ReferenceVariable, TupleVariable,),
(
StateVariable,
LocalVariable,
TemporaryVariable,
ReferenceVariable,
TupleVariable,
),
) )

@ -441,15 +441,10 @@ class ContractSolc:
elem.set_contract(self._contract) elem.set_contract(self._contract)
elem.set_contract_declarer(element_parser.underlying_function.contract_declarer) elem.set_contract_declarer(element_parser.underlying_function.contract_declarer)
elem.set_offset( elem.set_offset(
element_parser.function_not_parsed["src"], element_parser.function_not_parsed["src"], self._contract.slither,
self._contract.slither,
) )
elem_parser = Cls_parser( elem_parser = Cls_parser(elem, element_parser.function_not_parsed, self,)
elem,
element_parser.function_not_parsed,
self,
)
elem_parser.analyze_params() elem_parser.analyze_params()
if isinstance(elem, Modifier): if isinstance(elem, Modifier):
self._contract.slither.add_modifier(elem) self._contract.slither.add_modifier(elem)

@ -48,10 +48,7 @@ class FunctionSolc:
# elems = [(type, name)] # elems = [(type, name)]
def __init__( def __init__(
self, self, function: Function, function_data: Dict, contract_parser: "ContractSolc",
function: Function,
function_data: Dict,
contract_parser: "ContractSolc",
): ):
self._slither_parser: "SlitherSolc" = contract_parser.slither_parser self._slither_parser: "SlitherSolc" = contract_parser.slither_parser
self._contract_parser = contract_parser self._contract_parser = contract_parser
@ -575,8 +572,7 @@ class FunctionSolc:
link_underlying_nodes(node_startDoWhile, node_condition) link_underlying_nodes(node_startDoWhile, node_condition)
else: else:
link_nodes( link_nodes(
node_startDoWhile.underlying_node, node_startDoWhile.underlying_node, node_condition.underlying_node.sons[0],
node_condition.underlying_node.sons[0],
) )
link_underlying_nodes(statement, node_condition) link_underlying_nodes(statement, node_condition)
link_underlying_nodes(node_condition, node_endDoWhile) link_underlying_nodes(node_condition, node_endDoWhile)

@ -84,14 +84,7 @@ def find_variable( # pylint: disable=too-many-locals,too-many-statements
referenced_declaration: Optional[int] = None, referenced_declaration: Optional[int] = None,
is_super=False, is_super=False,
) -> Union[ ) -> Union[
Variable, Variable, Function, Contract, SolidityVariable, SolidityFunction, Event, Enum, Structure,
Function,
Contract,
SolidityVariable,
SolidityFunction,
Event,
Enum,
Structure,
]: ]:
from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.contract import ContractSolc
from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.function import FunctionSolc

@ -379,9 +379,7 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract] contracts_to_be_analyzed += [contract]
def _analyze_first_part( def _analyze_first_part(
self, self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
): ):
for lib in libraries: for lib in libraries:
self._parse_struct_var_modifiers_functions(lib) self._parse_struct_var_modifiers_functions(lib)
@ -406,9 +404,7 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract] contracts_to_be_analyzed += [contract]
def _analyze_second_part( def _analyze_second_part(
self, self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
): ):
for lib in libraries: for lib in libraries:
self._analyze_struct_events(lib) self._analyze_struct_events(lib)
@ -433,9 +429,7 @@ Please rename it, this name is reserved for Slither's internals"""
contracts_to_be_analyzed += [contract] contracts_to_be_analyzed += [contract]
def _analyze_third_part( def _analyze_third_part(
self, self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc],
contracts_to_be_analyzed: List[ContractSolc],
libraries: List[ContractSolc],
): ):
for lib in libraries: for lib in libraries:
self._analyze_variables_modifiers_functions(lib) self._analyze_variables_modifiers_functions(lib)

@ -134,8 +134,7 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t
found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([a-zA-Z0-9\.\[\]]*)\)", name) found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([a-zA-Z0-9\.\[\]]*)\)", name)
else: else:
found = re.findall( found = re.findall(
"mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)", "mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)", name,
name,
) )
assert len(found) == 1 assert len(found) == 1
from_ = found[0][0] from_ = found[0][0]
@ -191,11 +190,7 @@ def parse_type(t: Union[Dict, UnknownType], caller_context):
if t[key] == "UserDefinedTypeName": if t[key] == "UserDefinedTypeName":
if is_compact_ast: if is_compact_ast:
return _find_from_type_name( return _find_from_type_name(
t["typeDescriptions"]["typeString"], t["typeDescriptions"]["typeString"], contract, contracts, structures, enums,
contract,
contracts,
structures,
enums,
) )
# Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').

@ -162,10 +162,7 @@ class YulScope(metaclass=abc.ABCMeta):
self._yul_local_functions.append(func) self._yul_local_functions.append(func)
def get_yul_local_function_from_name(self, func_name): def get_yul_local_function_from_name(self, func_name):
return next( return next((v for v in self._yul_local_functions if v.underlying.name == func_name), None,)
(v for v in self._yul_local_functions if v.underlying.name == func_name),
None,
)
class YulLocalVariable: # pylint: disable=too-few-public-methods class YulLocalVariable: # pylint: disable=too-few-public-methods
@ -456,11 +453,7 @@ def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
"name": "eq", "name": "eq",
}, },
"arguments": [ "arguments": [
{ {"nodeType": "YulIdentifier", "src": case_ast["src"], "name": switch_expr_var,},
"nodeType": "YulIdentifier",
"src": case_ast["src"],
"name": switch_expr_var,
},
value_ast, value_ast,
], ],
}, },

@ -31,8 +31,7 @@ def parse_args():
:return: Returns the arguments for the program. :return: Returns the arguments for the program.
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Check the ERC 20 conformance", description="Check the ERC 20 conformance", usage="slither-check-erc project contractName",
usage="slither-check-erc project contractName",
) )
parser.add_argument("project", help="The codebase to be tested.") parser.add_argument("project", help="The codebase to be tested.")

@ -41,9 +41,7 @@ def parse_args():
group_export = parser.add_argument_group("Export options") group_export = parser.add_argument_group("Export options")
group_export.add_argument( group_export.add_argument(
"--dir", "--dir", help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).", default=None,
help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).",
default=None,
) )
group_export.add_argument( group_export.add_argument(
@ -54,10 +52,7 @@ def parse_args():
) )
parser.add_argument( parser.add_argument(
"--zip", "--zip", help="Export all the files to a zip file", action="store", default=None,
help="Export all the files to a zip file",
action="store",
default=None,
) )
parser.add_argument( parser.add_argument(
@ -74,9 +69,7 @@ def parse_args():
) )
group_patching.add_argument( group_patching.add_argument(
"--convert-private", "--convert-private", help="Convert private variables to internal.", action="store_true",
help="Convert private variables to internal.",
action="store_true",
) )
group_patching.add_argument( group_patching.add_argument(

@ -24,9 +24,7 @@ def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"):
""" """
logger.info(f"Export {zip_filename}") logger.info(f"Export {zip_filename}")
with zipfile.ZipFile( with zipfile.ZipFile(
zip_filename, zip_filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
"w",
compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
) as file_desc: ) as file_desc:
for f in files: for f in files:
file_desc.writestr(str(f.filename), f.content) file_desc.writestr(str(f.filename), f.content)

@ -108,10 +108,7 @@ class Flattening:
regex = re.search(r"((\sexternal)\s+)|(\sexternal)$|(\)external)$", attributes) regex = re.search(r"((\sexternal)\s+)|(\sexternal)$|(\)external)$", attributes)
if regex: if regex:
to_patch.append( to_patch.append(
Patch( Patch(attributes_start + regex.span()[0] + 1, "public_to_external",)
attributes_start + regex.span()[0] + 1,
"public_to_external",
)
) )
else: else:
raise SlitherException(f"External keyword not found {f.name} {attributes}") raise SlitherException(f"External keyword not found {f.name} {attributes}")
@ -122,10 +119,7 @@ class Flattening:
calldata_end = calldata_start + var.source_mapping["length"] calldata_end = calldata_start + var.source_mapping["length"]
calldata_idx = content[calldata_start:calldata_end].find(" calldata ") calldata_idx = content[calldata_start:calldata_end].find(" calldata ")
to_patch.append( to_patch.append(
Patch( Patch(calldata_start + calldata_idx + 1, "calldata_to_memory",)
calldata_start + calldata_idx + 1,
"calldata_to_memory",
)
) )
if self._private_to_internal: if self._private_to_internal:
@ -139,10 +133,7 @@ class Flattening:
regex = re.search(r" private ", attributes) regex = re.search(r" private ", attributes)
if regex: if regex:
to_patch.append( to_patch.append(
Patch( Patch(attributes_start + regex.span()[0] + 1, "private_to_internal",)
attributes_start + regex.span()[0] + 1,
"private_to_internal",
)
) )
else: else:
raise SlitherException( raise SlitherException(

@ -22,23 +22,18 @@ def parse_args():
:return: Returns the arguments for the program. :return: Returns the arguments for the program.
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="slither-kspec-coverage", description="slither-kspec-coverage", usage="slither-kspec-coverage contract.sol kspec.md",
usage="slither-kspec-coverage contract.sol kspec.md",
) )
parser.add_argument( parser.add_argument(
"contract", help="The filename of the contract or truffle directory to analyze." "contract", help="The filename of the contract or truffle directory to analyze."
) )
parser.add_argument( parser.add_argument(
"kspec", "kspec", help="The filename of the Klab spec markdown for the analyzed contract(s)",
help="The filename of the Klab spec markdown for the analyzed contract(s)",
) )
parser.add_argument( parser.add_argument(
"--version", "--version", help="displays the current version", version="0.1.0", action="version",
help="displays the current version",
version="0.1.0",
action="version",
) )
parser.add_argument( parser.add_argument(
"--json", "--json",

@ -21,8 +21,7 @@ def parse_args():
:return: Returns the arguments for the program. :return: Returns the arguments for the program.
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="PossiblePaths", description="PossiblePaths", usage="possible_paths.py filename [contract.function targets]",
usage="possible_paths.py filename [contract.function targets]",
) )
parser.add_argument( parser.add_argument(

@ -18,8 +18,7 @@ def resolve_function(slither, contract_name, function_name):
# Obtain the target function # Obtain the target function
target_function = next( target_function = next(
(function for function in contract.functions if function.name == function_name), (function for function in contract.functions if function.name == function_name), None,
None,
) )
# Verify we have resolved the function specified. # Verify we have resolved the function specified.

@ -105,9 +105,7 @@ def parse_args():
) )
parser.add_argument( parser.add_argument(
"--address-attacker", "--address-attacker", help=f"Attacker address. Default {ATTACKER_ADDRESS}", default=None,
help=f"Attacker address. Default {ATTACKER_ADDRESS}",
default=None,
) )
# Add default arguments from crytic-compile # Add default arguments from crytic-compile

@ -107,11 +107,7 @@ def generate_erc20(
# Generate the Test contract # Generate the Test contract
initialization_recommendation = _initialization_recommendation(type_property) initialization_recommendation = _initialization_recommendation(type_property)
contract_filename, contract_name = generate_test_contract( contract_filename, contract_name = generate_test_contract(
contract, contract, type_property, output_dir, property_file, initialization_recommendation,
type_property,
output_dir,
property_file,
initialization_recommendation,
) )
# Generate Echidna config file # Generate Echidna config file

@ -15,10 +15,7 @@ logger = logging.getLogger("Slither")
def generate_truffle_test( def generate_truffle_test(
contract: Contract, contract: Contract, type_property: str, unit_tests: List[Property], addresses: Addresses,
type_property: str,
unit_tests: List[Property],
addresses: Addresses,
) -> str: ) -> str:
test_contract = f"Test{contract.name}{type_property}" test_contract = f"Test{contract.name}{type_property}"
filename_init = f"Initialization{test_contract}.js" filename_init = f"Initialization{test_contract}.js"
@ -38,11 +35,7 @@ def generate_truffle_test(
) )
generate_unit_test( generate_unit_test(
test_contract, test_contract, filename, unit_tests, output_dir, addresses,
filename,
unit_tests,
output_dir,
addresses,
) )
log_info = "\n" log_info = "\n"

@ -24,7 +24,7 @@ class PropertyCaller(Enum):
ANY = 5 # If the caller does not matter ANY = 5 # If the caller does not matter
class Property(NamedTuple): class Property(NamedTuple): # pylint: disable=inherit-non-class,too-few-public-methods
name: str name: str
content: str content: str
type: PropertyType type: PropertyType

@ -54,10 +54,7 @@ def parse_args():
) )
parser.add_argument( parser.add_argument(
"--version", "--version", help="displays the current version", version="0.0", action="version",
help="displays the current version",
version="0.0",
action="version",
) )
cryticparser.init(parser) cryticparser.init(parser)

@ -41,17 +41,10 @@ def parse_args():
default=False, default=False,
) )
parser.add_argument( parser.add_argument(
"--verbose-json", "--verbose-json", "-j", help="verbose json output", action="store_true", default=False,
"-j",
help="verbose json output",
action="store_true",
default=False,
) )
parser.add_argument( parser.add_argument(
"--version", "--version", help="displays the current version", version="0.1.0", action="version",
help="displays the current version",
version="0.1.0",
action="version",
) )
parser.add_argument( parser.add_argument(

@ -65,10 +65,7 @@ def slither_format(slither, **kwargs): # pylint: disable=too-many-locals
logger.info(f"Issue: {one_line_description}") logger.info(f"Issue: {one_line_description}")
logger.info(f"Generated: ({export_result})") logger.info(f"Generated: ({export_result})")
for ( for (_, diff,) in result["patches_diff"].items():
_,
diff,
) in result["patches_diff"].items():
filename = f"fix_{counter}.patch" filename = f"fix_{counter}.patch"
path = Path(export_result, filename) path = Path(export_result, filename)
logger.info(f"\t- {filename}") logger.info(f"\t- {filename}")

@ -57,10 +57,7 @@ def parse_args():
) )
parser.add_argument( parser.add_argument(
"--markdown-root", "--markdown-root", help="URL for markdown generation", action="store", default="",
help="URL for markdown generation",
action="store",
default="",
) )
parser.add_argument( parser.add_argument(

@ -63,14 +63,7 @@ ERC223 = [
ERC("totalSupply", [], "uint256", True, True, []), ERC("totalSupply", [], "uint256", True, True, []),
ERC("balanceOf", ["address"], "uint256", True, True, []), ERC("balanceOf", ["address"], "uint256", True, True, []),
ERC("transfer", ["address", "uint256"], "bool", False, True, [ERC223_transfer_event]), ERC("transfer", ["address", "uint256"], "bool", False, True, [ERC223_transfer_event]),
ERC( ERC("transfer", ["address", "uint256", "bytes"], "bool", False, True, [ERC223_transfer_event],),
"transfer",
["address", "uint256", "bytes"],
"bool",
False,
True,
[ERC223_transfer_event],
),
ERC( ERC(
"transfer", "transfer",
["address", "uint256", "bytes", "string"], ["address", "uint256", "bytes", "string"],
@ -125,22 +118,10 @@ ERC721 = [
[ERC721_transfer_event], [ERC721_transfer_event],
), ),
ERC( ERC(
"transferFrom", "transferFrom", ["address", "address", "uint256"], "", False, True, [ERC721_transfer_event],
["address", "address", "uint256"],
"",
False,
True,
[ERC721_transfer_event],
), ),
ERC("approve", ["address", "uint256"], "", False, True, [ERC721_approval_event]), ERC("approve", ["address", "uint256"], "", False, True, [ERC721_approval_event]),
ERC( ERC("setApprovalForAll", ["address", "bool"], "", False, True, [ERC721_approvalforall_event],),
"setApprovalForAll",
["address", "bool"],
"",
False,
True,
[ERC721_approvalforall_event],
),
ERC("getApproved", ["uint256"], "address", True, True, []), ERC("getApproved", ["uint256"], "address", True, True, []),
ERC("isApprovedForAll", ["address", "address"], "bool", True, True, []), ERC("isApprovedForAll", ["address", "address"], "bool", True, True, []),
] + ERC165 ] + ERC165
@ -159,14 +140,7 @@ ERC721_signatures = erc_to_signatures(ERC721)
# https://eips.ethereum.org/EIPS/eip-1820 # https://eips.ethereum.org/EIPS/eip-1820
ERC1820_EVENTS: List = [] ERC1820_EVENTS: List = []
ERC1820 = [ ERC1820 = [
ERC( ERC("canImplementInterfaceForAddress", ["bytes32", "address"], "bytes32", True, True, [],)
"canImplementInterfaceForAddress",
["bytes32", "address"],
"bytes32",
True,
True,
[],
)
] ]
ERC1820_signatures = erc_to_signatures(ERC1820) ERC1820_signatures = erc_to_signatures(ERC1820)
@ -207,14 +181,7 @@ ERC777 = [
ERC("granularity", [], "uint256", True, True, []), ERC("granularity", [], "uint256", True, True, []),
ERC("defaultOperators", [], "address[]", True, True, []), ERC("defaultOperators", [], "address[]", True, True, []),
ERC("isOperatorFor", ["address", "address"], "bool", True, True, []), ERC("isOperatorFor", ["address", "address"], "bool", True, True, []),
ERC( ERC("authorizeOperator", ["address"], "", False, True, [ERC777_authorizedOperator_event],),
"authorizeOperator",
["address"],
"",
False,
True,
[ERC777_authorizedOperator_event],
),
ERC("revokeOperator", ["address"], "", False, True, [ERC777_revokedoperator_event]), ERC("revokeOperator", ["address"], "", False, True, [ERC777_revokedoperator_event]),
ERC("send", ["address", "uint256", "bytes"], "", False, True, [ERC777_sent_event]), ERC("send", ["address", "uint256", "bytes"], "", False, True, [ERC777_sent_event]),
ERC( ERC(

@ -110,27 +110,21 @@ class SplitTernaryExpression:
if self.apply_copy(next_expr, true_expression, false_expression, f_call): if self.apply_copy(next_expr, true_expression, false_expression, f_call):
# always on last arguments added # always on last arguments added
self.copy_expression( self.copy_expression(
next_expr, next_expr, true_expression.arguments[-1], false_expression.arguments[-1],
true_expression.arguments[-1],
false_expression.arguments[-1],
) )
elif isinstance(expression, TypeConversion): elif isinstance(expression, TypeConversion):
next_expr = expression.expression next_expr = expression.expression
if self.apply_copy(next_expr, true_expression, false_expression, f_expression): if self.apply_copy(next_expr, true_expression, false_expression, f_expression):
self.copy_expression( self.copy_expression(
expression.expression, expression.expression, true_expression.expression, false_expression.expression,
true_expression.expression,
false_expression.expression,
) )
elif isinstance(expression, UnaryOperation): elif isinstance(expression, UnaryOperation):
next_expr = expression.expression next_expr = expression.expression
if self.apply_copy(next_expr, true_expression, false_expression, f_expression): if self.apply_copy(next_expr, true_expression, false_expression, f_expression):
self.copy_expression( self.copy_expression(
expression.expression, expression.expression, true_expression.expression, false_expression.expression,
true_expression.expression,
false_expression.expression,
) )
else: else:

@ -10,9 +10,7 @@ if TYPE_CHECKING:
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
def detect_c3_function_shadowing( def detect_c3_function_shadowing(contract: "Contract",) -> Dict["Function", Set["Function"]]:
contract: "Contract",
) -> Dict["Function", Set["Function"]]:
""" """
Detects and obtains functions which are indirectly shadowed via multiple inheritance by C3 linearization Detects and obtains functions which are indirectly shadowed via multiple inheritance by C3 linearization
properties, despite not directly inheriting from each other. properties, despite not directly inheriting from each other.

@ -78,9 +78,7 @@ def output_to_zip(filename: str, error: Optional[str], results: Dict, zip_type:
logger.info(yellow(f"{filename} exists already, the overwrite is prevented")) logger.info(yellow(f"{filename} exists already, the overwrite is prevented"))
else: else:
with ZipFile( with ZipFile(
filename, filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
"w",
compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA),
) as file_desc: ) as file_desc:
file_desc.writestr("slither_results.json", json.dumps(json_result).encode("utf8")) file_desc.writestr("slither_results.json", json.dumps(json_result).encode("utf8"))
@ -357,11 +355,7 @@ class Output:
additional_fields = {} additional_fields = {}
type_specific_fields = {"parent": _create_parent_element(enum)} type_specific_fields = {"parent": _create_parent_element(enum)}
element = _create_base_element( element = _create_base_element(
"enum", "enum", enum.name, enum.source_mapping, type_specific_fields, additional_fields,
enum.name,
enum.source_mapping,
type_specific_fields,
additional_fields,
) )
self._data["elements"].append(element) self._data["elements"].append(element)
@ -377,11 +371,7 @@ class Output:
additional_fields = {} additional_fields = {}
type_specific_fields = {"parent": _create_parent_element(struct)} type_specific_fields = {"parent": _create_parent_element(struct)}
element = _create_base_element( element = _create_base_element(
"struct", "struct", struct.name, struct.source_mapping, type_specific_fields, additional_fields,
struct.name,
struct.source_mapping,
type_specific_fields,
additional_fields,
) )
self._data["elements"].append(element) self._data["elements"].append(element)
@ -400,11 +390,7 @@ class Output:
"signature": event.full_name, "signature": event.full_name,
} }
element = _create_base_element( element = _create_base_element(
"event", "event", event.name, event.source_mapping, type_specific_fields, additional_fields,
event.name,
event.source_mapping,
type_specific_fields,
additional_fields,
) )
self._data["elements"].append(element) self._data["elements"].append(element)
@ -424,11 +410,7 @@ class Output:
} }
node_name = str(node.expression) if node.expression else "" node_name = str(node.expression) if node.expression else ""
element = _create_base_element( element = _create_base_element(
"node", "node", node_name, node.source_mapping, type_specific_fields, additional_fields,
node_name,
node.source_mapping,
type_specific_fields,
additional_fields,
) )
self._data["elements"].append(element) self._data["elements"].append(element)
@ -479,10 +461,7 @@ class Output:
################################################################################### ###################################################################################
def add_pretty_table( def add_pretty_table(
self, self, content: MyPrettyTable, name: str, additional_fields: Optional[Dict] = None,
content: MyPrettyTable,
name: str,
additional_fields: Optional[Dict] = None,
): ):
if additional_fields is None: if additional_fields is None:
additional_fields = {} additional_fields = {}
@ -499,11 +478,7 @@ class Output:
################################################################################### ###################################################################################
def add_other( def add_other(
self, self, name: str, source_mapping, slither, additional_fields: Optional[Dict] = None,
name: str,
source_mapping,
slither,
additional_fields: Optional[Dict] = None,
): ):
# If this a tuple with (filename, start, end), convert it to a source mapping. # If this a tuple with (filename, start, end), convert it to a source mapping.
if additional_fields is None: if additional_fields is None:
@ -514,10 +489,7 @@ class Output:
source_id = next( source_id = next(
( (
source_unit_id source_unit_id
for ( for (source_unit_id, source_unit_filename,) in slither.source_units.items()
source_unit_id,
source_unit_filename,
) in slither.source_units.items()
if source_unit_filename == filename if source_unit_filename == filename
), ),
-1, -1,

@ -444,15 +444,7 @@ def get_tests(solc_versions) -> Dict[str, List[str]]:
return tests return tests
Item = namedtuple( Item = namedtuple("TestItem", ["test_id", "base_ver", "solc_ver", "is_legacy",],)
"TestItem",
[
"test_id",
"base_ver",
"solc_ver",
"is_legacy",
],
)
def get_all_test() -> List[Item]: def get_all_test() -> List[Item]:

Loading…
Cancel
Save