|
|
@ -3,63 +3,86 @@ |
|
|
|
|
|
|
|
|
|
|
|
import json |
|
|
|
import json |
|
|
|
from collections import defaultdict |
|
|
|
from collections import defaultdict |
|
|
|
|
|
|
|
from typing import Dict, List, Set, Tuple |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from slither.core.cfg.node import Node |
|
|
|
|
|
|
|
from slither.core.declarations import Function |
|
|
|
|
|
|
|
from slither.core.slither_core import Slither |
|
|
|
|
|
|
|
from slither.core.variables.variable import Variable |
|
|
|
from slither.printers.abstract_printer import AbstractPrinter |
|
|
|
from slither.printers.abstract_printer import AbstractPrinter |
|
|
|
from slither.core.declarations.solidity_variables import SolidityVariableComposed, SolidityFunction |
|
|
|
from slither.core.declarations.solidity_variables import SolidityVariableComposed, SolidityFunction, SolidityVariable |
|
|
|
|
|
|
|
from slither.slithir.operations import Member, Operation |
|
|
|
from slither.slithir.operations.binary import Binary, BinaryType |
|
|
|
from slither.slithir.operations.binary import Binary, BinaryType |
|
|
|
from slither.core.variables.state_variable import StateVariable |
|
|
|
from slither.core.variables.state_variable import StateVariable |
|
|
|
from slither.slithir.variables import Constant |
|
|
|
from slither.slithir.variables import Constant |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _extract_payable(slither): |
|
|
|
def _get_name(f: Function) -> str: |
|
|
|
ret = {} |
|
|
|
if f.is_fallback or f.is_receive: |
|
|
|
|
|
|
|
return f'()' |
|
|
|
|
|
|
|
return f.full_name |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _extract_payable(slither: Slither) -> Dict[str, List[str]]: |
|
|
|
|
|
|
|
ret: Dict[str, List[str]] = {} |
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in slither.contracts: |
|
|
|
payable_functions = [f.full_name for f in contract.functions_entry_points if f.payable] |
|
|
|
payable_functions = [_get_name(f) for f in contract.functions_entry_points if f.payable] |
|
|
|
if payable_functions: |
|
|
|
if payable_functions: |
|
|
|
ret[contract.name] = payable_functions |
|
|
|
ret[contract.name] = payable_functions |
|
|
|
return ret |
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
def _extract_solidity_variable_usage(slither, sol_var): |
|
|
|
|
|
|
|
ret = {} |
|
|
|
def _extract_solidity_variable_usage(slither: Slither, sol_var: SolidityVariable) -> Dict[str, List[str]]: |
|
|
|
|
|
|
|
ret: Dict[str, List[str]] = {} |
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in slither.contracts: |
|
|
|
functions_using_sol_var = [] |
|
|
|
functions_using_sol_var = [] |
|
|
|
for f in contract.functions_entry_points: |
|
|
|
for f in contract.functions_entry_points: |
|
|
|
for v in f.all_solidity_variables_read(): |
|
|
|
for v in f.all_solidity_variables_read(): |
|
|
|
if v == sol_var: |
|
|
|
if v == sol_var: |
|
|
|
functions_using_sol_var.append(f.full_name) |
|
|
|
functions_using_sol_var.append(_get_name(f)) |
|
|
|
break |
|
|
|
break |
|
|
|
if functions_using_sol_var: |
|
|
|
if functions_using_sol_var: |
|
|
|
ret[contract.name] = functions_using_sol_var |
|
|
|
ret[contract.name] = functions_using_sol_var |
|
|
|
return ret |
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
def _extract_constant_functions(slither): |
|
|
|
|
|
|
|
ret = {} |
|
|
|
def _extract_constant_functions(slither: Slither) -> Dict[str, List[str]]: |
|
|
|
|
|
|
|
ret: Dict[str, List[str]] = {} |
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in slither.contracts: |
|
|
|
cst_functions = [f.full_name for f in contract.functions_entry_points if f.view or f.pure] |
|
|
|
cst_functions = [_get_name(f) for f in contract.functions_entry_points if f.view or f.pure] |
|
|
|
cst_functions += [v.function_name for v in contract.state_variables if v.visibility in ['public']] |
|
|
|
cst_functions += [v.function_name for v in contract.state_variables if v.visibility in ['public']] |
|
|
|
if cst_functions: |
|
|
|
if cst_functions: |
|
|
|
ret[contract.name] = cst_functions |
|
|
|
ret[contract.name] = cst_functions |
|
|
|
return ret |
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
def _extract_assert(slither): |
|
|
|
|
|
|
|
ret = {} |
|
|
|
def _extract_assert(slither: Slither) -> Dict[str, List[str]]: |
|
|
|
|
|
|
|
ret: Dict[str, List[str]] = {} |
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in slither.contracts: |
|
|
|
functions_using_assert = [] |
|
|
|
functions_using_assert = [] |
|
|
|
for f in contract.functions_entry_points: |
|
|
|
for f in contract.functions_entry_points: |
|
|
|
for v in f.all_solidity_calls(): |
|
|
|
for v in f.all_solidity_calls(): |
|
|
|
if v == SolidityFunction('assert(bool)'): |
|
|
|
if v == SolidityFunction('assert(bool)'): |
|
|
|
functions_using_assert.append(f.full_name) |
|
|
|
functions_using_assert.append(_get_name(f)) |
|
|
|
break |
|
|
|
break |
|
|
|
if functions_using_assert: |
|
|
|
if functions_using_assert: |
|
|
|
ret[contract.name] = functions_using_assert |
|
|
|
ret[contract.name] = functions_using_assert |
|
|
|
return ret |
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
def _extract_constants_from_irs(irs, all_cst_used, all_cst_used_in_binary, context_explored): |
|
|
|
|
|
|
|
|
|
|
|
def _extract_constants_from_irs(irs: List[Operation], |
|
|
|
|
|
|
|
all_cst_used: List, |
|
|
|
|
|
|
|
all_cst_used_in_binary: Dict, |
|
|
|
|
|
|
|
context_explored: Set[Node]): |
|
|
|
for ir in irs: |
|
|
|
for ir in irs: |
|
|
|
if isinstance(ir, Binary): |
|
|
|
if isinstance(ir, Binary): |
|
|
|
for r in ir.read: |
|
|
|
for r in ir.read: |
|
|
|
if isinstance(r, Constant): |
|
|
|
if isinstance(r, Constant): |
|
|
|
all_cst_used_in_binary[BinaryType.str(ir.type)].append(r.value) |
|
|
|
all_cst_used_in_binary[BinaryType.str(ir.type)].append(r.value) |
|
|
|
for r in ir.read: |
|
|
|
for r in ir.read: |
|
|
|
|
|
|
|
# Do not report struct_name in a.struct_name |
|
|
|
|
|
|
|
if isinstance(ir, Member): |
|
|
|
|
|
|
|
continue |
|
|
|
if isinstance(r, Constant): |
|
|
|
if isinstance(r, Constant): |
|
|
|
all_cst_used.append(r.value) |
|
|
|
all_cst_used.append(r.value) |
|
|
|
if isinstance(r, StateVariable): |
|
|
|
if isinstance(r, StateVariable): |
|
|
@ -74,9 +97,10 @@ def _extract_constants_from_irs(irs, all_cst_used, all_cst_used_in_binary, conte |
|
|
|
all_cst_used_in_binary, |
|
|
|
all_cst_used_in_binary, |
|
|
|
context_explored) |
|
|
|
context_explored) |
|
|
|
|
|
|
|
|
|
|
|
def _extract_constants(slither): |
|
|
|
|
|
|
|
ret_cst_used = defaultdict(dict) |
|
|
|
def _extract_constants(slither: Slither) -> Tuple[Dict[str, Dict[str, List]], Dict[str, Dict[str, Dict]]]: |
|
|
|
ret_cst_used_in_binary = defaultdict(dict) |
|
|
|
ret_cst_used: Dict[str, Dict[str, List]] = defaultdict(dict) |
|
|
|
|
|
|
|
ret_cst_used_in_binary: Dict[str, Dict[str, Dict]] = defaultdict(dict) |
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in slither.contracts: |
|
|
|
for function in contract.functions_entry_points: |
|
|
|
for function in contract.functions_entry_points: |
|
|
|
all_cst_used = [] |
|
|
|
all_cst_used = [] |
|
|
@ -93,9 +117,7 @@ def _extract_constants(slither): |
|
|
|
ret_cst_used[contract.name][function.full_name] = all_cst_used |
|
|
|
ret_cst_used[contract.name][function.full_name] = all_cst_used |
|
|
|
if all_cst_used_in_binary: |
|
|
|
if all_cst_used_in_binary: |
|
|
|
ret_cst_used_in_binary[contract.name][function.full_name] = all_cst_used_in_binary |
|
|
|
ret_cst_used_in_binary[contract.name][function.full_name] = all_cst_used_in_binary |
|
|
|
return (ret_cst_used, ret_cst_used_in_binary) |
|
|
|
return ret_cst_used, ret_cst_used_in_binary |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Echidna(AbstractPrinter): |
|
|
|
class Echidna(AbstractPrinter): |
|
|
@ -104,7 +126,6 @@ class Echidna(AbstractPrinter): |
|
|
|
|
|
|
|
|
|
|
|
WIKI = 'https://github.com/trailofbits/slither/wiki/Printer-documentation#echidna' |
|
|
|
WIKI = 'https://github.com/trailofbits/slither/wiki/Printer-documentation#echidna' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def output(self, filename): |
|
|
|
def output(self, filename): |
|
|
|
""" |
|
|
|
""" |
|
|
|
Output the inheritance relation |
|
|
|
Output the inheritance relation |
|
|
@ -120,14 +141,13 @@ class Echidna(AbstractPrinter): |
|
|
|
block_number = _extract_solidity_variable_usage(self.slither, |
|
|
|
block_number = _extract_solidity_variable_usage(self.slither, |
|
|
|
SolidityVariableComposed('block.number')) |
|
|
|
SolidityVariableComposed('block.number')) |
|
|
|
msg_sender = _extract_solidity_variable_usage(self.slither, |
|
|
|
msg_sender = _extract_solidity_variable_usage(self.slither, |
|
|
|
SolidityVariableComposed('msg.sender')) |
|
|
|
SolidityVariableComposed('msg.sender')) |
|
|
|
msg_gas = _extract_solidity_variable_usage(self.slither, |
|
|
|
msg_gas = _extract_solidity_variable_usage(self.slither, |
|
|
|
SolidityVariableComposed('msg.gas')) |
|
|
|
SolidityVariableComposed('msg.gas')) |
|
|
|
assert_usage = _extract_assert(self.slither) |
|
|
|
assert_usage = _extract_assert(self.slither) |
|
|
|
cst_functions = _extract_constant_functions(self.slither) |
|
|
|
cst_functions = _extract_constant_functions(self.slither) |
|
|
|
(cst_used, cst_used_in_binary) = _extract_constants(self.slither) |
|
|
|
(cst_used, cst_used_in_binary) = _extract_constants(self.slither) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d = {'payable': payable, |
|
|
|
d = {'payable': payable, |
|
|
|
'timestamp': timestamp, |
|
|
|
'timestamp': timestamp, |
|
|
|
'block_number': block_number, |
|
|
|
'block_number': block_number, |
|
|
|