def test_echidna_instrumentation(self): self.inorder_config.instrumentation.predicates = [ 'previously(b_called) -> c_called', 'b_called -> since(c_called, a_called)' ] self.inorder_config.instrumentation.for_echidna = True self.inorder_config.verification.verisol.use = False proof_found, verisol_counterexample = self.inorder_veriman.analyze_contract( self.inorder_config, reuse_pre_process=True) # Restore test configs: self.inorder_config.instrumentation.for_echidna = False self.inorder_config.verification.verisol.use = True self.check_contract_compiles(self.inorder_veriman.contract_path) slither = Slither(self.inorder_veriman.contract_path) contract_info = slither.get_contract_from_name('InOrder') echidna_invariants = list( filter(lambda func: func.name.startswith('echidna_'), contract_info.functions)) self.assertEqual(len(echidna_invariants), 2) for invariant in echidna_invariants: self.assertEqual(invariant.return_type[0].name, 'bool') self.check_functions_with_asserts(self.inorder_veriman, []) os.remove(self.inorder_veriman.contract_path)
def test_inheritance(self): inheritance_config = TestVeriMan.get_test_config() inheritance_config.contract.path = os.path.dirname( os.path.abspath(__file__)) + '/Inheritance.sol' inheritance_config.contract.name = 'D' inheritance_config.instrumentation.predicates = [ 'a_var + b_var + c_var + d_var < 10', 'block.number > 10' ] inheritance_config.verification.verisol.use = False veriman = VeriMan() proof_found, verisol_counterexample = veriman.analyze_contract( inheritance_config) self.check_contract_compiles(veriman.contract_path) slither = Slither(veriman.contract_path) contract_info = slither.get_contract_from_name( inheritance_config.contract.name) expected_functions = set( list([ 'aFunction', 'toBeOverwritten', 'bFunction', 'withTheSameName', 'callsC', 'dFunction', 'constructor' ])) found_functions = list( map(lambda func: func.name, contract_info.functions_declared)) self.assertEqual(found_functions.count('withTheSameName'), 3) self.assertEqual(found_functions.count('toBeOverwritten'), 1) self.assertEqual(expected_functions, set(found_functions)) os.remove(veriman.contract_path)
def process_truffle(dirname, args, detector_classes, printer_classes): if args.truffle_version: cmd = ['npx', args.truffle_version, 'compile'] elif os.path.isfile('package.json'): cmd = ['truffle', 'compile'] with open('package.json') as f: package = json.load(f) if 'devDependencies' in package: if 'truffle' in package['devDependencies']: truffle_version = 'truffle@{}'.format( package['devDependencies']['truffle']) cmd = ['npx', truffle_version, 'compile'] logger.info( "'{}' running (use --truffle-version [email protected] to use specific version)" .format(' '.join(cmd))) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() stdout, stderr = stdout.decode(), stderr.decode( ) # convert bytestrings to unicode strings logger.info(stdout) if stderr: logger.error(stderr) slither = Slither(dirname, args.solc, args.disable_solc_warnings, args.solc_args, is_truffle=True) return _process(slither, detector_classes, printer_classes)
def process(filename, args, detector_classes, printer_classes): """ The core high-level code for running Slither static analysis. Returns: list(result), int: Result list and number of contracts analyzed """ slither = Slither(filename, args.solc, args.disable_solc_warnings, args.solc_args) for detector_cls in detector_classes: slither.register_detector(detector_cls) for printer_cls in printer_classes: slither.register_printer(printer_cls) analyzed_contracts_count = len(slither.contracts) results = [] if printer_classes: slither.run_printers() # Currently printers does not return results elif detector_classes: detector_results = slither.run_detectors() detector_results = [x for x in detector_results if x] # remove empty results detector_results = [item for sublist in detector_results for item in sublist] # flatten results.extend(detector_results) return results, analyzed_contracts_count
def getSummaryOfFile(f): slither = Slither(f) summaries = [] for contract in slither.contracts: events = getSummaryOfContract(contract) summaries.append({"name": contract.name, "functions": events}) return summaries
def process_truffle(dirname, args, detector_classes, printer_classes): cmd = ['npx',args.truffle_version,'compile'] if args.truffle_version else ['truffle','compile'] logger.info('truffle compile running...') process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() stdout, stderr = stdout.decode(), stderr.decode() # convert bytestrings to unicode strings logger.info(stdout) if stderr: logger.error(stderr) if not os.path.isdir(os.path.join(dirname, 'build'))\ or not os.path.isdir(os.path.join(dirname, 'build', 'contracts')): logger.info(red('No truffle build directory found, did you run `truffle compile`?')) return ([], 0) filenames = glob.glob(os.path.join(dirname,'build','contracts', '*.json')) all_contracts = [] all_filenames = [] for filename in filenames: with open(filename) as f: contract_loaded = json.load(f) all_contracts.append(contract_loaded['ast']) all_filenames.append(contract_loaded['sourcePath']) slither = Slither(all_contracts, args.solc, args.disable_solc_warnings, args.solc_args) return _process(slither, detector_classes, printer_classes)
def run(filename, contract_name): """Executes script""" # Init Slither slither = Slither(filename) # Get an instance of the contract to be analyzed contract = slither.get_contract_from_name(contract_name) if not contract: print(f"Contract {contract_name} not found") print( "Either you mispelled the contract's name or solc cannot compile the contract." ) exit(-1) # Obtain all visible functions, filtering out any that comes from an interface contract visible_functions = get_visible_functions( get_implemented_functions(contract.functions)) erc20_fx_matches = verify_signatures(visible_functions, ERC20_FX_SIGNATURES) print("== ERC20 functions definition ==") log_matches(erc20_fx_matches) print("\n== Custom modifiers ==") log_modifiers_per_function(verify_custom_modifiers(erc20_fx_matches)) print("\n== ERC20 events ==") log_matches(verify_signatures(contract.events, ERC20_EVENT_SIGNATURES), log_return=False) log_event_per_function( verify_event_calls(erc20_fx_matches, ERC20_EVENT_BY_FX), ERC20_EVENT_BY_FX) print("\n== ERC20 getters ==") log_matches( verify_getters(contract.state_variables, visible_functions, ERC20_GETTERS)) print("\n== Allowance frontrunning mitigation ==") frontrun_fx_matches = verify_signatures(visible_functions, ALLOWANCE_FRONTRUN_FX_SIGNATURES) log_matches(frontrun_fx_matches) log_event_per_function(verify_event_calls(frontrun_fx_matches, ALLOWANCE_FRONTRUN_EVENT_BY_FX), ALLOWANCE_FRONTRUN_EVENT_BY_FX, must=False) print("\n== Balance check in approve function ==") approve_signature = ERC20_FX_SIGNATURES[1].to_string(with_return=False, with_spaces=False) approve_function = contract.get_function_from_signature(approve_signature) is_checking_balance = any( checks_sender_balance_in_require(node) for node in approve_function.nodes) log_approve_checking_balance(is_checking_balance)
def process_files(filenames, args, detector_classes, printer_classes): all_contracts = [] for filename in filenames: with open(filename) as f: contract_loaded = json.load(f) all_contracts.append(contract_loaded['ast']) slither = Slither(all_contracts, args.solc, args.disable_solc_warnings, args.solc_args) return _process(slither, detector_classes, printer_classes)
def process(filename, args, detectors, printers): slither = Slither(filename, args.solc, args.disable_solc_warnings, args.solc_args) if args.printers_to_run: [printers.run_printer(slither, p) for p in args.printers_to_run] return [] else: checks = determineChecks(detectors, args) results = [detectors.run_detector(slither, c) for c in checks] results = [x for x in results if x] # remove empty results results = [item for sublist in results for item in sublist] #flatten return results
def process_single(target, args, detector_classes, printer_classes): """ The core high-level code for running Slither static analysis. Returns: list(result), int: Result list and number of contracts analyzed """ ast = '--ast-compact-json' if args.legacy_ast: ast = '--ast-json' slither = Slither(target, ast_format=ast, **vars(args)) return _process(slither, detector_classes, printer_classes)
def process(filename, args, detector_classes, printer_classes): """ The core high-level code for running Slither static analysis. Returns: list(result), int: Result list and number of contracts analyzed """ ast = '--ast-json' if args.compact_ast: ast = '--ast-compact-json' slither = Slither(filename, args.solc, args.disable_solc_warnings, args.solc_args, ast) return _process(slither, detector_classes, printer_classes)
def pre_process_contract(self, contract_path, contract_name): self.contract_path = contract_path self.contract_name = contract_name slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name) if self.contract_info is None: raise Exception('Check config file for contract name') with open(self.contract_path) as contract_file: self.contract_lines = contract_file.readlines() self.__add_constructor(slither) self.__add_inherited_functions() # TODO improve efficiency: with open(self.contract_path, 'w') as contract_file: contract_file.writelines(self.contract_lines) slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name)
def process_files(filenames, args, detector_classes, printer_classes): all_contracts = [] for filename in filenames: with open(filename, encoding='utf8') as f: contract_loaded = json.load(f) all_contracts.append(contract_loaded['ast']) slither = Slither(all_contracts, solc=args.solc, disable_solc_warnings=args.disable_solc_warnings, solc_arguments=args.solc_args, filter_paths=parse_filter_paths(args), triage_mode=args.triage_mode) return _process(slither, detector_classes, printer_classes)
def instrument(self, contract_path, contract_name, predicates, instrument_for_echidna): self.contract_path = contract_path self.contract_name = contract_name slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name) if self.contract_info is None: raise Exception('Check config file for contract name') with open(self.contract_path) as contract_file: contract = contract_file.read() contract = contract.replace('}', '\n}') self.contract_lines = contract.split('\n') self.__pre_process_contract() parser = Parser() echidna_function = '' for index, predicate_string in enumerate(predicates): predicate = parser.parse(predicate_string) functions_to_instrument = self.__get_functions_to_instrument( predicate) self.__instrument_new_variables(predicate, functions_to_instrument, instrument_for_echidna) if instrument_for_echidna: echidna_function += '(' + predicate.solidity_repr + ')\n&& ' else: assert_string = f'assert({predicate.solidity_repr}); // VERIMAN ASSERT FOR PREDICATE NO. {index + 1}' self.__insert_in_functions(functions_to_instrument, assert_string, self.__insert_at_end_of_functions) if instrument_for_echidna: echidna_function = 'function echidna_invariant() public returns(bool) {\nreturn ' \ + echidna_function.rsplit('\n&& ', 1)[0]\ + ';\n}' self.__insert_in_contract(echidna_function) contract = '\n'.join(self.contract_lines) with open(self.contract_path, 'w') as contract_file: contract_file.write(contract)
def check_functions_with_asserts(self, veriman, expected): slither = Slither(veriman.contract_path) contract_info = slither.get_contract_from_name(veriman.contract_name) expected_functions = set(list(expected)) found_functions = list( filter( lambda func: next( filter(lambda call: call.name == 'assert(bool)', func. solidity_calls), None) is not None, contract_info.functions_declared)) found_functions_names = list( map(lambda func: func.name, found_functions)) self.assertEqual(expected_functions, set(found_functions_names))
def process_truffle(dirname, args, detector_classes, printer_classes): # Truffle on windows has naming conflicts where it will invoke truffle.js directly instead # of truffle.cmd (unless in powershell or git bash). The cleanest solution is to explicitly call # truffle.cmd. Reference: # https://truffleframework.com/docs/truffle/reference/configuration#resolving-naming-conflicts-on-windows if not args.ignore_truffle_compile: truffle_base_command = "truffle" if platform.system( ) != 'Windows' else "truffle.cmd" cmd = [truffle_base_command, 'compile'] if args.truffle_version: cmd = ['npx', args.truffle_version, 'compile'] elif os.path.isfile('package.json'): with open('package.json') as f: package = json.load(f) if 'devDependencies' in package: if 'truffle' in package['devDependencies']: version = package['devDependencies']['truffle'] if version.startswith('^'): version = version[1:] truffle_version = 'truffle@{}'.format(version) cmd = ['npx', truffle_version, 'compile'] logger.info( "'{}' running (use --truffle-version [email protected] to use specific version)" .format(' '.join(cmd))) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() stdout, stderr = stdout.decode(), stderr.decode( ) # convert bytestrings to unicode strings logger.info(stdout) if stderr: logger.error(stderr) slither = Slither(dirname, solc=args.solc, disable_solc_warnings=args.disable_solc_warnings, solc_arguments=args.solc_args, is_truffle=True, filter_paths=parse_filter_paths(args), triage_mode=args.triage_mode) return _process(slither, detector_classes, printer_classes)
def main(sol_file): seed = None # assert False logger.info('Analyzing Input...') deps, refs = analyze(sol_file, "C", "foo()") lambdas = analyze_lambdas(sol_file, "C", "foo()") logger.info('Analysis Successful!') # print(deps.dependencies) # print(refs.pprint_refinement()) actual_spec, prog_decl, types, i_global, global_vars = instantiate_dsl( sol_file, refs.types, lambdas) # print(actual_spec) logger.info('Parsing Spec...') spec = S.parse(actual_spec) logger.info('Parsing succeeded') # Fetch other contract names slither = Slither(sol_file) other_contracts = list( filter(lambda x: x != 'C', map(str, slither.contracts))) logger.info('Building synthesizer...') synthesizer = Synthesizer( enumerator=DependencyEnumerator(spec, max_depth=4, seed=seed, analysis=deps.dependencies, types=types), decider=SymdiffDecider(interpreter=SymDiffInterpreter( prog_decl, other_contracts, i_global, global_vars), example=sol_file, equal_output=check_eq)) logger.info('Synthesizing programs...') prog = synthesizer.synthesize() if prog is not None: logger.info('Solution found: {}'.format(prog)) return True else: logger.info('Solution not found!') return False
def process(filename, args, detector_classes, printer_classes): """ The core high-level code for running Slither static analysis. Returns: list(result), int: Result list and number of contracts analyzed """ ast = '--ast-compact-json' if args.legacy_ast: ast = '--ast-json' slither = Slither(filename, solc=args.solc, disable_solc_warnings=args.disable_solc_warnings, solc_arguments=args.solc_args, ast_format=ast, filter_paths=parse_filter_paths(args), triage_mode=args.triage_mode) return _process(slither, detector_classes, printer_classes)
def main(args): if len(args) < 2: print("Usage: python get-conditions.py FILENAME") exit(1) slither = Slither(args[1]) for contract in slither.contracts: # print('Contract: '+ contract.name) for function in contract.functions: # print('Function: {}'.format(function.name)) for node in function.nodes: # NOTE: This will also give `return bool;` as a condition. I'm not sure that this really should count, so I used a different machnism to get this information. # if node.is_conditional(): # print(node) if node.contains_if() or node.contains_require_or_assert(): print(looks_like_state_check(contract, node), node)
def process_truffle(dirname, args, detector_classes, printer_classes): if not args.ignore_truffle_compile: cmd = ['truffle', 'compile'] if args.truffle_version: cmd = ['npx', args.truffle_version, 'compile'] elif os.path.isfile('package.json'): with open('package.json') as f: package = json.load(f) if 'devDependencies' in package: if 'truffle' in package['devDependencies']: version = package['devDependencies']['truffle'] if version.startswith('^'): version = version[1:] truffle_version = 'truffle@{}'.format(version) cmd = ['npx', truffle_version, 'compile'] logger.info( "'{}' running (use --truffle-version [email protected] to use specific version)" .format(' '.join(cmd))) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() stdout, stderr = stdout.decode(), stderr.decode( ) # convert bytestrings to unicode strings logger.info(stdout) if stderr: logger.error(stderr) slither = Slither(dirname, solc=args.solc, disable_solc_warnings=args.disable_solc_warnings, solc_arguments=args.solc_args, is_truffle=True, filter_paths=parse_filter_paths(args), triage_mode=args.triage_mode) return _process(slither, detector_classes, printer_classes)
def process_truffle(dirname, args, detector_classes, printer_classes): if not os.path.isdir(os.path.join(dirname, 'build'))\ or not os.path.isdir(os.path.join(dirname, 'build', 'contracts')): logger.info( red('No truffle build directory found, did you run `truffle compile`?' )) return (0, 0) filenames = glob.glob(os.path.join(dirname, 'build', 'contracts', '*.json')) all_contracts = [] for filename in filenames: with open(filename) as f: contract_loaded = json.load(f) all_contracts += contract_loaded['ast']['nodes'] contract = {"nodeType": "SourceUnit", "nodes": all_contracts} slither = Slither(contract, args.solc, args.disable_solc_warnings, args.solc_args) return _process(slither, detector_classes, printer_classes)
from slither.slither import Slither slither = Slither('coin.sol') coin = slither.get_contract_from_name('Coin')[0] # Iterate over all the contracts for contract in slither.contracts: # If the contract is derived from MyContract if coin in contract.inheritance: # Get the function definition mint = contract.get_function_from_signature('_mint(address,uint256)') # If the function was not declarer by coin, there is a bug ! if mint.contract != coin: print(f'Error, {contract} overrides {mint}')
from slither.slither import Slither # Init slither slither = Slither('functions_writing.sol') # Get the contract contract = slither.get_contract_from_name('Contract') # Get the variable var_a = contract.get_state_variable_from_name('a') # Get the functions writing the variable functions_writing_a = contract.get_functions_writing_variable(var_a) # Print the result print 'The function writing "a" are {}'.format( [f.name for f in functions_writing_a])
# Successfully analyzed contracts counter contract_processed = 0 # Dictionary which counts vulnerabilities found on contracts by type statistics = {"front-running": 0} directory = argv[1] for filename in os.listdir(directory): if filename.endswith(".sol"): # only run procedure on Solidity files filePath = os.path.join(directory, filename) logger.info("Analyzing file: " + filePath) try: # in case of compiling errors just skip the contract (and don't count it as processed) # Load contracts from file slither = Slither(filePath) # Register detector slither.register_detector(FrontRunning) # Start detecting detector_results = slither.run_detectors() detector_results = [x for x in detector_results if x] # remove empty results # Update contract count (here I can safely assume the contract is successfully processed contract_processed += len(slither.contracts) # Update vulnerabilities found to statistics dict for sublist in detector_results: for item in sublist: detector = item["check"]
import sys from slither.slither import Slither if len(sys.argv) != 2: print("python function_called.py contract.sol") sys.exit(-1) # Init slither slither = Slither(sys.argv[1]) for contract in slither.contracts: for function in contract.functions + contract.modifiers: filename = "{}-{}-{}.dot".format(sys.argv[1], contract.name, function.full_name) print("Export {}".format(filename)) function.slithir_cfg_to_dot(filename)
read_function_name) # 跨函数的全局变量依赖 if write_function_name != read_function_name: cross_function_edges.append( (from_node_id, to_node_id, { 'type': "state_cross", 'color': "blue" })) TPG.add_edges_from(cross_function_edges) get_graph_png(TPG, "TPG") if __name__ == '__main__': slither = Slither(EXAMPLE_PERFIX + '0x09515cb5e3acaef239ab83d78b2f3e3764fcab9b.sol') for contract in slither.contracts: state_var_declare_function_map = {} # 全局变量定义函数 state_var_write_function_map = {} # 全局变量写函数列表 state_var_read_function_map = {} # 全局变量读函数列表 transaction_state_vars = [] # 与交易行为相关的全局变量 transaction_state_vars_stmts = {} eth_send_functions = {} functions_slice_criterias = {} # 每个函数对应的切片准则:阶段1、4都会生成切片准则 # NOTE: stat_var <==> function 对应表 print("\n=====阶段1:stat_var <==> function 对应表=====\n") for v in contract.state_variables:
def instantiate_dsl(sol_file, analysis, lambdas): ## Step 1: parse the original source .sol. # Init slither slither = Slither(sol_file) # Get the contract, all the contact's name is C by default. contract = slither.get_contract_from_name('C') other_contracts = list( filter(lambda x: x != 'C', map(str, slither.contracts))) harness_fun = contract.functions[0] vars_map = {} # Get the function, which has name 'foo' by default. assert harness_fun.name == 'foo' for var in harness_fun.variables_read: add_var(vars_map, var) for var in harness_fun.variables_written: add_var(vars_map, var) actual_spec = toy_spec_str int_str = "" address_str = "" maparray_str = "" mapint_str = "" prog_decl = "" with open(sol_file, "r") as f: ind = "//#LOOPVARS: " body = f.read() if ind in body: global_vars = body[body.index(ind) + 12:].split("\n")[0] global_vars = global_vars.replace('[', "").replace( ']', "").replace("'", "").replace(" ", "").split(", ") else: global_vars = ["i"] #TODO: HANDLE NESTED LOOPS i_global = global_vars[0] in list(map(str, contract.variables)) for k in vars_map: for v in vars_map[k]: if v == global_vars[0]: if i_global: prog_decl += k + ' ' + v + '; \n' else: prog_decl += k + ' ' + v + '; \n' # TODO: Presumes all constants are integers or booleans for const in analysis[5]: try: if 'uint256' in vars_map: vars_map['uint256'].append(str(int(const))) else: vars_map['uint256'] = [str(int(const))] except: if 'bool' in vars_map: vars_map['bool'].append(const) else: vars_map['bool'] = [const] base_types = ["uint", "bool", "address", "bytes"] + other_contracts map_types = list( map(lambda x: "mapping({0} => {1})".format(x[0], x[1]), product(base_types, repeat=2))) all_types = base_types + map_types type_table = {} length_vars = [] for k in vars_map: v = map(lambda x: '"' + x + '"', vars_map[k]) actual_symbols = ",".join(list(v)) print('parsing key:', k, ",".join(list(v))) if "[]" in k: length_vars += vars_map[k] k = "mapping(uint => {0})".format(k.replace("[]", "")) k = k.replace("uint8", "uint") k = k.replace("uint128", "uint") k = k.replace("uint256", "uint") k = k.replace("bytes32", "bytes") if k in all_types: if k in map_types: matches = re.findall(r"(mapping\((.*) => (.*)\))", k) if matches != []: full_dec = matches[0][0] dom = matches[0][1] codom = matches[0][2] k = "mapping_{0}_{1}".format(dom, codom) if not k in type_table: type_table[k] = actual_symbols.split(",") else: type_table[k] += actual_symbols.split(",") else: print("IGNORED TYPE: {0}!".format(k)) pass if "uint" in type_table: type_table["uint"] += list( map(lambda v: '"{0}.length"'.format(v), length_vars)) else: type_table["uint"] = list( map(lambda v: '"{0}.length"'.format(v), length_vars)) typ_enums, final_typ_dict = create_refinement_types( analysis, type_table, lambdas) actual_spec = expand_dsl(actual_spec, final_typ_dict, base_types) actual_spec = actual_spec.format(types=typ_enums) # print(actual_spec) return actual_spec, prog_decl, final_typ_dict, i_global, global_vars
from slither.slither import Slither # Init slither slither = Slither('variable_in_condition.sol') # Get the contract contract = slither.get_contract_from_name('Contract') # Get the variable var_a = contract.get_state_variable_from_name('a') # Get the functions reading the variable functions_reading_a = contract.get_functions_reading_variable(var_a) function_using_a_as_condition = [f for f in functions_reading_a if\ f.is_reading_in_conditional_node(var_a) or\ f.is_reading_in_require_or_assert(var_a)] # Print the result print 'The function using "a" in condition are {}'.format( [f.name for f in function_using_a_as_condition])
def analyze(fname): res = { 'fname': fname, 'external_func': Counter(), 'external_call': Counter(), 'internal_func': Counter(), 'internal_call': Counter(), 'library_func': Counter(), 'library_call': Counter(), 'internal_state_change_call': Counter(), 'internal_state_change_func': Counter(), 'writes_after_internal_call': False, 'writes_after_internal_state_change_call': False, 'writes_after_external_call': False, 'writes_after_non_library_call': False, 'reads_after_internal_call': False, 'reads_after_internal_state_change_call': False, 'reads_after_external_call': False, 'reads_after_non_library_call': False, 'external_call_num': 0, 'external_call_checked_num': 0, 'call_graph': {}, 'success': False } try: slither = Slither(fname, disable_solc_warnings=True) for c in slither.contracts: # print('Contract: {}'.format(c.name)) state_changing_func_names = set(func.name for func in c.functions if len(func.all_state_variables_written()) > 0) for function in c.functions: record_call_set(res, 'external', function.all_high_level_calls()) record_call_set(res, 'internal', [(declarer(c, f), f) for f in function.all_internal_calls()]) record_call_set(res, 'internal_state_change', [(declarer(c, f), f) for f in function.all_internal_calls() if f.name in state_changing_func_names]) record_call_set(res, 'library', function.all_library_calls()) this_func = (c.name, signature(function)) res['call_graph'][this_func] = set() for con, func in function.all_high_level_calls(): if func is not None: res['call_graph'][this_func].add((str(con), signature(func))) for func in function.all_internal_calls(): if func is not None and isinstance(func, Function): res['call_graph'][this_func].add((str(func.contract_declarer), signature(func))) res['writes_after_internal_call'] |= do_explore(internal_calls, lambda n: n.state_variables_written, function.entry_point) res['writes_after_internal_state_change_call'] |= do_explore(internal_state_change_calls(state_changing_func_names), lambda n: n.state_variables_written, function.entry_point) res['writes_after_external_call'] |= do_explore(external_calls, lambda n: n.state_variables_written, function.entry_point) res['writes_after_non_library_call'] |= do_explore(non_library_calls, lambda n: n.state_variables_written, function.entry_point) res['reads_after_internal_call'] |= do_explore(internal_calls, lambda n: n.state_variables_read, function.entry_point) res['reads_after_internal_state_change_call'] |= do_explore(internal_state_change_calls(state_changing_func_names), lambda n: n.state_variables_read, function.entry_point) res['reads_after_external_call'] |= do_explore(external_calls, lambda n: n.state_variables_read, function.entry_point) res['reads_after_non_library_call'] |= do_explore(non_library_calls, lambda n: n.state_variables_read, function.entry_point) for node in function.nodes: num = len(node.high_level_calls) if num > 0: res['external_call_num'] += num if node.is_conditional(): res['external_call_checked_num'] += num # print('External calls: {}'.format(external_calls)) res['success'] = True except SlitherError as e: # raise e pass for k in res: if isinstance(res[k], Counter): res[k] = dict(res[k]) print(res)
from slither.slither import Slither # Init slither slither = Slither('functions_called.sol') # Get the contract contract = slither.get_contract_from_name('Contract') # Get the variable entry_point = contract.get_function_from_signature('entry_point()') all_calls = entry_point.all_calls() all_calls_formated = [f.contract.name + '.' + f.name for f in all_calls] # Print the result print 'From entry_point the functions reached are {}'.format(all_calls_formated)