def output(self, _filename): """ _filename is not used Args: _filename(string) """ all_tables = [] all_txt = '' for c in self.contracts: if c.is_top_level: continue (name, inheritance, var, func_summaries, modif_summaries) = c.get_summary() txt = "\nContract %s" % name txt += '\nContract vars: ' + str(var) txt += '\nInheritance:: ' + str(inheritance) table = MyPrettyTable([ "Function", "Visibility", "Modifiers", "Read", "Write", "Internal Calls", "External Calls" ]) for (_c_name, f_name, visi, modifiers, read, write, internal_calls, external_calls) in func_summaries: read = self._convert(read) write = self._convert(write) internal_calls = self._convert(internal_calls) external_calls = self._convert(external_calls) table.add_row([ f_name, visi, modifiers, read, write, internal_calls, external_calls ]) txt += "\n \n" + str(table) table = MyPrettyTable([ "Modifiers", "Visibility", "Read", "Write", "Internal Calls", "External Calls" ]) for (_c_name, f_name, visi, _, read, write, internal_calls, external_calls) in modif_summaries: read = self._convert(read) write = self._convert(write) internal_calls = self._convert(internal_calls) external_calls = self._convert(external_calls) table.add_row([ f_name, visi, read, write, internal_calls, external_calls ]) txt += "\n\n" + str(table) txt += "\n" self.info(txt) all_tables.append((name, table)) all_txt += txt res = self.generate_output(all_txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" all_tables = [] for contract in self.slither.contracts_derived: txt += "\n{}:\n".format(contract.name) table = MyPrettyTable(["Name", "Type", "Slot", "Offset"]) for variable in contract.state_variables_ordered: if not variable.is_constant: slot, offset = contract.compilation_unit.storage_layout_of( contract, variable) table.add_row([ variable.canonical_name, str(variable.type), slot, offset ]) all_tables.append((contract.name, table)) txt += str(table) + "\n" self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = '' all_tables = [] for contract in self.slither.contracts_derived: txt += '\n{}:\n'.format(contract.name) table = MyPrettyTable(['Name', 'Type']) for variable in contract.state_variables_ordered: if not variable.is_constant: table.add_row( [variable.canonical_name, str(variable.type)]) all_tables.append((contract.name, table)) txt += str(table) + '\n' self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = '' all_tables = [] for contract in self.slither.contracts_derived: txt += '\n{}:\n'.format(contract.name) table = MyPrettyTable(['Name', 'ID']) for function in contract.functions: if function.visibility in ['public', 'external']: table.add_row([ function.solidity_signature, hex(get_function_id(function.solidity_signature)) ]) for variable in contract.state_variables: if variable.visibility in ['public']: sig = variable.function_name table.add_row([sig, hex(get_function_id(sig))]) txt += str(table) + '\n' all_tables.append((contract.name, table)) self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ all_tables = [] all_txt = "" for contract in self.slither.contracts_derived: txt = "\nContract %s" % contract.name table = MyPrettyTable(["Function", "require or assert"]) for function in contract.functions: require = function.all_slithir_operations() require = [ ir for ir in require if isinstance(ir, SolidityCall) and ir.function in require_or_assert ] require = [ir.node for ir in require] table.add_row([ function.name, self._convert([str(m.expression) for m in set(require)]), ]) txt += "\n" + str(table) self.info(txt) all_tables.append((contract.name, table)) all_txt += txt res = self.generate_output(all_txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ all_txt = "" all_tables = [] for contract in self.slither.contracts_derived: txt = f"\nContract {contract.name}" table = MyPrettyTable(["Function", "Modifiers"]) for function in contract.functions: modifiers = function.modifiers for call in function.all_internal_calls(): if isinstance(call, Function): modifiers += call.modifiers for (_, call) in function.all_library_calls(): if isinstance(call, Function): modifiers += call.modifiers table.add_row([function.name, [m.name for m in set(modifiers)]]) txt += "\n" + str(table) self.info(txt) all_txt += txt all_tables.append((contract.name, table)) res = self.generate_output(all_txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "" all_tables = [] for contract in self.slither.contracts_derived: txt += f"\n{contract.name}:\n" table = MyPrettyTable(["Name", "ID"]) for function in contract.functions: if function.visibility in ["public", "external"]: function_id = get_function_id(function.solidity_signature) table.add_row([ function.solidity_signature, f"{function_id:#0{10}x}" ]) for variable in contract.state_variables: if variable.visibility in ["public"]: sig = variable.function_name function_id = get_function_id(sig) table.add_row([sig, f"{function_id:#0{10}x}"]) txt += str(table) + "\n" all_tables.append((contract.name, table)) self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output_detectors(detector_classes): detectors_list = [] for detector in detector_classes: argument = detector.ARGUMENT help_info = detector.HELP impact = detector.IMPACT require_proxy = detector.REQUIRE_PROXY require_v2 = detector.REQUIRE_CONTRACT_V2 detectors_list.append( (argument, help_info, impact, require_proxy, require_v2)) table = MyPrettyTable( ["Num", "Check", "What it Detects", "Impact", "Proxy", "Contract V2"]) # Sort by impact, confidence, and name detectors_list = sorted(detectors_list, key=lambda element: (element[2], element[0])) idx = 1 for (argument, help_info, impact, proxy, v2) in detectors_list: table.add_row([ idx, argument, help_info, classification_txt[impact], "X" if proxy else "", "X" if v2 else "", ]) idx = idx + 1 print(table)
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = '' all_tables = [] for contract in self.contracts: txt += "\nContract %s\n" % contract.name table = MyPrettyTable([ "Function", "State variables written", "Conditions on msg.sender" ]) for function in contract.functions: state_variables_written = [ v.name for v in function.all_state_variables_written() ] msg_sender_condition = self.get_msg_sender_checks(function) table.add_row([ function.name, str(state_variables_written), str(msg_sender_condition) ]) all_tables.append((contract.name, table)) txt += str(table) + '\n' self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename: str) -> output.Output: """ _filename is not used Args: _filename(string) """ modifier_name: str = "whenNotPaused" txt = "" txt += "Constructor and pure/view functions are not displayed\n" all_tables = [] for contract in self.slither.contracts: txt += f"\n{contract.name}:\n" table = MyPrettyTable(["Name", "Use whenNotPaused"]) for function in contract.functions_entry_points: status = "X" if _use_modifier(function, modifier_name) else "" table.add_row([function.solidity_signature, status]) txt += str(table) + "\n" all_tables.append((contract.name, table)) self.info(txt) res = self.generate_output(txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def _all_properties(): table = MyPrettyTable(["Num", "Description", "Scenario"]) idx = 0 for scenario, value in ERC20_PROPERTIES.items(): for prop in value.properties: table.add_row([idx, prop.description, scenario]) idx = idx + 1 return table
def output(self, _filename): """ _filename is not used Args: _filename(string) """ all_tables = [] all_txt = "" txt = "" for c in self.contracts: if c.is_top_level: continue txt += f"\nContract {c.name}\n" table = MyPrettyTable(["Variable", "Dependencies"]) for v in c.state_variables: table.add_row([v.name, _get(v, c)]) txt += str(table) txt += "\n" for f in c.functions_and_modifiers_declared: txt += f"\nFunction {f.full_name}\n" table = MyPrettyTable(["Variable", "Dependencies"]) for v in f.variables: table.add_row([v.name, _get(v, f)]) for v in c.state_variables: table.add_row([v.canonical_name, _get(v, f)]) txt += str(table) self.info(txt) all_txt += txt all_tables.append((c.name, table)) res = self.generate_output(all_txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output(self, _filename): """ _filename is not used Args: _filename(string) """ all_tables = [] all_txt = '' txt = '' for c in self.contracts: txt += "\nContract %s\n" % c.name table = MyPrettyTable(['Variable', 'Dependencies']) for v in c.state_variables: table.add_row([v.name, _get(v, c)]) txt += str(table) txt += "\n" for f in c.functions_and_modifiers_declared: txt += "\nFunction %s\n" % f.full_name table = MyPrettyTable(['Variable', 'Dependencies']) for v in f.variables: table.add_row([v.name, _get(v, f)]) for v in c.state_variables: table.add_row([v.canonical_name, _get(v, f)]) txt += str(table) self.info(txt) all_txt += txt all_tables.append((c.name, table)) res = self.generate_output(all_txt) for name, table in all_tables: res.add_pretty_table(table, name) return res
def output_printers(printer_classes): printers_list = [] for printer in printer_classes: argument = printer.ARGUMENT help_info = printer.HELP printers_list.append((argument, help_info)) table = MyPrettyTable(["Num", "Printer", "What it Does"]) # Sort by impact, confidence, and name printers_list = sorted(printers_list, key=lambda element: (element[0])) idx = 1 for (argument, help_info) in printers_list: table.add_row([idx, argument, help_info]) idx = idx + 1 print(table)
def output_mutators(mutators_classes): mutators_list = [] for detector in mutators_classes: argument = detector.NAME help_info = detector.HELP fault_class = detector.FAULTCLASS.name fault_nature = detector.FAULTNATURE.name mutators_list.append((argument, help_info, fault_class, fault_nature)) table = MyPrettyTable( ["Num", "Name", "What it Does", "Fault Class", "Fault Nature"]) # Sort by class, nature, name mutators_list = sorted(mutators_list, key=lambda element: (element[2], element[3], element[0])) idx = 1 for (argument, help_info, fault_class, fault_nature) in mutators_list: table.add_row([idx, argument, help_info, fault_class, fault_nature]) idx = idx + 1 print(table)
def output_detectors(detector_classes): detectors_list = [] for detector in detector_classes: argument = detector.ARGUMENT # dont show the backdoor example if argument == "backdoor": continue help_info = detector.HELP impact = detector.IMPACT confidence = classification_txt[detector.CONFIDENCE] detectors_list.append((argument, help_info, impact, confidence)) table = MyPrettyTable( ["Num", "Check", "What it Detects", "Impact", "Confidence"]) # Sort by impact, confidence, and name detectors_list = sorted(detectors_list, key=lambda element: (element[2], element[3], element[0])) idx = 1 for (argument, help_info, impact, confidence) in detectors_list: table.add_row( [idx, argument, help_info, classification_txt[impact], confidence]) idx = idx + 1 print(table)
def output(self, _filename): # pylint: disable=too-many-locals,too-many-statements """ _filename is not used Args: _filename(string) """ txt = "\n" txt += self._compilation_type() results = { "contracts": {"elements": []}, "number_lines": 0, "number_lines_in_dependencies": 0, "number_lines_assembly": 0, "standard_libraries": [], "ercs": [], "number_findings": dict(), "detectors": [], } lines_number = self._lines_number() if lines_number: total_lines, total_dep_lines, total_tests_lines = lines_number txt += f"Number of lines: {total_lines} (+ {total_dep_lines} in dependencies, + {total_tests_lines} in tests)\n" results["number_lines"] = total_lines results["number_lines__dependencies"] = total_dep_lines total_asm_lines = self._get_number_of_assembly_lines() txt += f"Number of assembly lines: {total_asm_lines}\n" results["number_lines_assembly"] = total_asm_lines ( number_contracts, number_contracts_deps, number_contracts_tests, ) = self._number_contracts() txt += f"Number of contracts: {number_contracts} (+ {number_contracts_deps} in dependencies, + {number_contracts_tests} tests) \n\n" ( txt_detectors, detectors_results, optimization, info, low, medium, high, ) = self.get_detectors_result() txt += txt_detectors results["number_findings"] = { "optimization_issues": optimization, "informational_issues": info, "low_issues": low, "medium_issues": medium, "high_issues": high, } results["detectors"] = detectors_results libs = self._standard_libraries() if libs: txt += f'\nUse: {", ".join(libs)}\n' results["standard_libraries"] = [str(l) for l in libs] ercs = self._ercs() if ercs: txt += f'ERCs: {", ".join(ercs)}\n' results["ercs"] = [str(e) for e in ercs] table = MyPrettyTable( ["Name", "# functions", "ERCS", "ERC20 info", "Complex code", "Features"] ) for contract in self.slither.contracts_derived: if contract.is_from_dependency() or contract.is_test: continue is_complex = self.is_complex_code(contract) number_functions = self._number_functions(contract) ercs = ",".join(contract.ercs()) is_erc20 = contract.is_erc20() erc20_info = "" if is_erc20: erc20_info += self.get_summary_erc20(contract) features = "\n".join( [name for name, to_print in self._get_features(contract).items() if to_print] ) table.add_row( [contract.name, number_functions, ercs, erc20_info, is_complex, features,] ) self.info(txt + "\n" + str(table)) results_contract = output.Output("") for contract in self.slither.contracts_derived: if contract.is_test or contract.is_from_dependency(): continue contract_d = { "contract_name": contract.name, "is_complex_code": self._is_complex_code(contract), "is_erc20": contract.is_erc20(), "number_functions": self._number_functions(contract), "features": [ name for name, to_print in self._get_features(contract).items() if to_print ], } if contract_d["is_erc20"]: pause, mint_limited, race_condition_mitigated = self._get_summary_erc20(contract) contract_d["erc20_pause"] = pause if mint_limited is not None: contract_d["erc20_can_mint"] = True contract_d["erc20_mint_limited"] = mint_limited else: contract_d["erc20_can_mint"] = False contract_d["erc20_race_condition_mitigated"] = race_condition_mitigated results_contract.add_contract(contract, additional_fields=contract_d) results["contracts"]["elements"] = results_contract.elements json = self.generate_output(txt, additional_fields=results) return json
def output(self, _filename): """ _filename is not used Args: _filename(string) """ txt = "\n" txt += self._compilation_type() results = { 'contracts': { "elements": [] }, 'number_lines': 0, 'number_lines_in_dependencies': 0, 'number_lines_assembly': 0, 'standard_libraries': [], 'ercs': [], 'number_findings': dict(), 'detectors': [] } lines_number = self._lines_number() if lines_number: total_lines, total_dep_lines, total_tests_lines = lines_number txt += f'Number of lines: {total_lines} (+ {total_dep_lines} in dependencies, + {total_tests_lines} in tests)\n' results['number_lines'] = total_lines results['number_lines__dependencies'] = total_dep_lines total_asm_lines = self._get_number_of_assembly_lines() txt += f"Number of assembly lines: {total_asm_lines}\n" results['number_lines_assembly'] = total_asm_lines number_contracts, number_contracts_deps, number_contracts_tests = self._number_contracts( ) txt += f'Number of contracts: {number_contracts} (+ {number_contracts_deps} in dependencies, + {number_contracts_tests} tests) \n\n' txt_detectors, detectors_results, optimization, info, low, medium, high = self.get_detectors_result( ) txt += txt_detectors results['number_findings'] = { 'optimization_issues': optimization, 'informational_issues': info, 'low_issues': low, 'medium_issues': medium, 'high_issues': high } results['detectors'] = detectors_results libs = self._standard_libraries() if libs: txt += f'\nUse: {", ".join(libs)}\n' results['standard_libraries'] = [str(l) for l in libs] ercs = self._ercs() if ercs: txt += f'ERCs: {", ".join(ercs)}\n' results['ercs'] = [str(e) for e in ercs] table = MyPrettyTable([ "Name", "# functions", "ERCS", "ERC20 info", "Complex code", "Features" ]) for contract in self.slither.contracts_derived: if contract.is_from_dependency() or contract.is_test: continue is_complex = self.is_complex_code(contract) number_functions = self._number_functions(contract) ercs = ','.join(contract.ercs()) is_erc20 = contract.is_erc20() erc20_info = '' if is_erc20: erc20_info += self.get_summary_erc20(contract) features = "\n".join([ name for name, to_print in self._get_features(contract).items() if to_print ]) table.add_row([ contract.name, number_functions, ercs, erc20_info, is_complex, features ]) self.info(txt + '\n' + str(table)) results_contract = output.Output('') for contract in self.slither.contracts_derived: if contract.is_test or contract.is_from_dependency(): continue contract_d = { 'contract_name': contract.name, 'is_complex_code': self._is_complex_code(contract), 'is_erc20': contract.is_erc20(), 'number_functions': self._number_functions(contract), 'features': [ name for name, to_print in self._get_features(contract).items() if to_print ] } if contract_d['is_erc20']: pause, mint_limited, race_condition_mitigated = self._get_summary_erc20( contract) contract_d['erc20_pause'] = pause if mint_limited is not None: contract_d['erc20_can_mint'] = True contract_d['erc20_mint_limited'] = mint_limited else: contract_d['erc20_can_mint'] = False contract_d[ 'erc20_race_condition_mitigated'] = race_condition_mitigated results_contract.add_contract(contract, additional_fields=contract_d) results['contracts']['elements'] = results_contract.elements json = self.generate_output(txt, additional_fields=results) return json