Esempio n. 1
0
def _check_events(erc_event, contract, ret):
    name = erc_event.name
    parameters = erc_event.parameters
    indexes = erc_event.indexes

    sig = f'{name}({",".join(parameters)})'
    event = contract.get_event_from_signature(sig)

    if not event:
        txt = f"[ ] {sig} is missing"
        logger.info(txt)

        missing_event = output.Output(txt, additional_fields={"event": sig})
        missing_event.add(contract)
        ret["missing_event"].append(missing_event.data)
        return

    txt = f"[✓] {sig} is present"
    logger.info(txt)

    for i, index in enumerate(indexes):
        if index:
            if event.elems[i].indexed:
                txt = f"\t[✓] parameter {i} is indexed"
                logger.info(txt)
            else:
                txt = f"\t[ ] parameter {i} should be indexed"
                logger.info(txt)

                missing_event_index = output.Output(txt, additional_fields={"missing_index": i})
                missing_event_index.add_event(event)
                ret["missing_event_index"].append(missing_event_index.data)
Esempio n. 2
0
    def output(self, _filename):
        info = ''
        for contract in self.contracts:
            stack_name = []
            stack_definition = []
            info += "\n\nContact Name: " + contract.name
            info += "	Constructor Call Sequence: "
            cst = contract.constructors_declared
            if cst:
                stack_name.append(contract.name)
                stack_definition.append(self._get_soruce_code(cst))
            for inherited_contract in contract.inheritance:
                cst = inherited_contract.constructors_declared
                if cst:
                    stack_name.append(inherited_contract.name)
                    stack_definition.append(self._get_soruce_code(cst))
            if len(stack_name) > 0:
                info += " " + ' '.join(stack_name[len(stack_name) - 1])
                count = len(stack_name) - 2
                while count >= 0:
                    info += "-->" + ' '.join(stack_name[count])
                    count = count - 1
                info += "\n Constructor Definitions:"
                count = len(stack_definition) - 1
                while count >= 0:
                    info += "\n Contract name:" + str(stack_name[count])
                    info += "\n" + str(stack_definition[count])
                    count = count - 1

        self.info(info)
        res = output.Output(info)
        return res
    def generate_output(self, info, additional_fields=None):
        if additional_fields is None:
            additional_fields = {}
        printer_output = output.Output(info, additional_fields)
        printer_output.data["printer"] = self.ARGUMENT

        return printer_output
Esempio n. 4
0
    def output(self, _filename):
        info = ''
        for contract in self.slither.contracts_derived:
            stack_name = []
            stack_definition = []
            cst = contract.constructors_declared
            if cst:
                stack_name.append(contract.name)
                stack_definition.append(self._get_soruce_code(cst))
            for inherited_contract in contract.inheritance:
                cst = inherited_contract.constructors_declared
                if cst:
                    stack_name.append(inherited_contract.name)
                    stack_definition.append(self._get_soruce_code(cst))

            if len(stack_name) > 0:

                info += '\n########' + "#" * len(contract.name) + "########\n"
                info += "####### " + contract.name + " #######\n"
                info += '########' + "#" * len(contract.name) + "########\n\n"
                info += "## Constructor Call Sequence" + '\n'

                for name in stack_name[::-1]:
                    info += "\t- " + name + '\n'
                info += "\n## Constructor Definitions" + '\n'
                count = len(stack_definition) - 1
                while count >= 0:
                    info += "\n### " + stack_name[count] + '\n'
                    info += "\n" + str(stack_definition[count]) + '\n'
                    count = count - 1

        self.info(info)
        res = output.Output(info)
        return res
Esempio n. 5
0
    def generate_output(self, info, additional_fields=None):
        if additional_fields is None:
            additional_fields = {}
        d = output.Output(info, additional_fields)
        d.data['printer'] = self.ARGUMENT

        return d
Esempio n. 6
0
    def generate_output(
        self,
        info: Union[str, List[Union[str, SupportedOutput]]],
        additional_fields: Optional[Dict] = None,
    ) -> output.Output:
        if additional_fields is None:
            additional_fields = {}
        printer_output = output.Output(info, additional_fields)
        printer_output.data["printer"] = self.ARGUMENT

        return printer_output
Esempio n. 7
0
def _generate_output_unresolved(kspec, message, color, generate_json):
    info = ""
    for contract, function in kspec:
        info += f"{message} {contract}.{function}\n"
    if info:
        logger.info(color(info))

    if generate_json:
        json_kspec_present = output.Output(info, additional_fields={"signatures": kspec})
        return json_kspec_present.data
    return None
Esempio n. 8
0
def _generate_output(kspec, message, color, generate_json):
    info = ""
    for function in kspec:
        info += f"{message} {function.contract.name}.{function.full_name}\n"
    if info:
        logger.info(color(info))

    if generate_json:
        json_kspec_present = output.Output(info)
        for function in kspec:
            json_kspec_present.add(function)
        return json_kspec_present.data
    return None
Esempio n. 9
0
def approval_race_condition(contract, ret):
    increaseAllowance = contract.get_function_from_signature(
        'increaseAllowance(address,uint256)')

    if not increaseAllowance:
        increaseAllowance = contract.get_function_from_signature(
            'safeIncreaseAllowance(address,uint256)')

    if increaseAllowance:
        txt = f'\t[✓] {contract.name} has {increaseAllowance.full_name}'
        logger.info(txt)
    else:
        txt = f'\t[ ] {contract.name} is not protected for the ERC20 approval race condition'
        logger.info(txt)

        lack_of_erc20_race_condition_protection = output.Output(txt)
        lack_of_erc20_race_condition_protection.add(contract)
        ret["lack_of_erc20_race_condition_protection"].append(
            lack_of_erc20_race_condition_protection.data)
Esempio n. 10
0
def check_variable_initialization(contract):
    results = {'variables-initialized': []}

    logger.info(
        green(
            '\n## Run variable initialization checks... (see https://github.com/crytic/slither/wiki/Upgradeability-Checks)'
        ))

    error_found = False

    for s in contract.state_variables:
        if s.initialized and not s.is_constant:
            info = f'{s.canonical_name} has an initial value ({s.source_mapping_str})'
            logger.info(red(info))
            res = output.Output(info)
            res.add(s)
            results['variables-initialized'].append(res.data)
            error_found = True

    if not error_found:
        logger.info(green('No error found'))

    return results
Esempio n. 11
0
def events_safeBatchTransferFrom(contract, ret):
    function = contract.get_function_from_signature(
        "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
    )
    events = [
        {
            "name": "TransferSingle",
            "parameters": ["address", "address", "address", "uint256", "uint256"],
        },
        {
            "name": "TransferBatch",
            "parameters": ["address", "address", "address", "uint256[]", "uint256[]"],
        },
    ]

    event_counter_name = 0
    event_counter_parameters = 0
    if function:
        for event in events:
            for ir in function.all_slithir_operations():
                if isinstance(ir, EventCall) and ir.name == event["name"]:
                    event_counter_name += 1
                    if event["parameters"] == [str(a.type) for a in ir.arguments]:
                        event_counter_parameters += 1
    if event_counter_parameters == 1 and event_counter_name == 1:
        txt = "[✓] safeBatchTransferFrom emit TransferSingle or TransferBatch"
        logger.info(txt)
    else:
        txt = "[ ] safeBatchTransferFrom must emit TransferSingle or TransferBatch"
        logger.info(txt)

        erroneous_erc1155_safeBatchTransferFrom_event = output.Output(txt)
        erroneous_erc1155_safeBatchTransferFrom_event.add(contract)
        ret["erroneous_erc1155_safeBatchTransferFrom_event"].append(
            erroneous_erc1155_safeBatchTransferFrom_event.data
        )
Esempio n. 12
0
    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': [],
        }

        lines_number = self._lines_number()
        if lines_number:
            total_lines, total_dep_lines = lines_number
            txt += f'Number of lines: {total_lines} (+ {total_dep_lines} in dependencies)\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 = self._number_contracts()
        txt += f'Number of contracts: {number_contracts} (+ {number_contracts_deps} in dependencies) \n\n'

        txt += self.get_detectors_result()

        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]

        for contract in self.slither.contracts_derived:
            txt += "\nContract {}\n".format(contract.name)
            txt += self.is_complex_code(contract)
            txt += '\tNumber of functions: {}\n'.format(
                self._number_functions(contract))
            ercs = contract.ercs()
            if ercs:
                txt += '\tERCs: ' + ','.join(ercs) + '\n'
            is_erc20 = contract.is_erc20()
            if is_erc20:
                txt += '\tERC20 info:\n'
                txt += self.get_summary_erc20(contract)

        self.info(txt)

        results_contract = output.Output('')
        for contract in self.slither.contracts_derived:
            optimization, info, low, medium, high = self._get_detectors_result(
            )
            contract_d = {
                'contract_name': contract.name,
                'is_complex_code': self._is_complex_code(contract),
                'optimization_issues': optimization,
                'informational_issues': info,
                'low_issues': low,
                'medium_issues': medium,
                'high_issues': high,
                'is_erc20': contract.is_erc20(),
                'number_functions': self._number_functions(contract)
            }
            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
Esempio n. 13
0
    def output(self, _filename):
        """
            _filename is not used
            Args:
                _filename(string)
        """

        txt = ""

        all_contracts = []
        for c in self.contracts:
            if c.is_top_level:
                continue

            is_upgradeable_proxy = c.is_upgradeable_proxy
            is_upgradeable = c.is_upgradeable

            additional_txt_info = ''

            if is_upgradeable_proxy:
                additional_txt_info += ' (Upgradeable Proxy)'

            if is_upgradeable:
                additional_txt_info += ' (Upgradeable)'

            if c in self.slither.contracts_derived:
                additional_txt_info += ' (Most derived contract)'

            txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n")
            additional_fields = output.Output(
                '',
                additional_fields={
                    'is_upgradeable_proxy': is_upgradeable_proxy,
                    'is_upgradeable': is_upgradeable,
                    'is_most_derived': c in self.slither.contracts_derived
                })

            # Order the function with
            # contract_declarer -> list_functions
            public = [(f.contract_declarer.name, f) for f in c.functions
                      if (not f.is_shadowed and not f.is_constructor_variables)
                      ]
            collect = collections.defaultdict(list)
            for a, b in public:
                collect[a].append(b)
            public = list(collect.items())

            for contract, functions in public:
                txt += blue("  - From {}\n".format(contract))

                functions = sorted(functions, key=lambda f: f.full_name)

                for function in functions:
                    if function.visibility in ['external', 'public']:
                        txt += green("    - {} ({})\n".format(
                            function.full_name, function.visibility))
                    if function.visibility in ['internal', 'private']:
                        txt += magenta("    - {} ({})\n".format(
                            function.full_name, function.visibility))
                    if function.visibility not in [
                            'external', 'public', 'internal', 'private'
                    ]:
                        txt += "    - {}  ({})\n".format(
                            function.full_name, function.visibility)

                    additional_fields.add(
                        function,
                        additional_fields={"visibility": function.visibility})

            all_contracts.append((c, additional_fields.data))

        self.info(txt)

        res = self.generate_output(txt)
        for contract, additional_fields in all_contracts:
            res.add(contract, additional_fields=additional_fields)

        return res
Esempio n. 14
0
def _check_signature(erc_function, contract, ret):
    name = erc_function.name
    parameters = erc_function.parameters
    return_type = erc_function.return_type
    view = erc_function.view
    required = erc_function.required
    events = erc_function.events

    sig = f'{name}({",".join(parameters)})'
    function = contract.get_function_from_signature(sig)

    if not function:
        # The check on state variable is needed until we have a better API to handle state variable getters
        state_variable_as_function = contract.get_state_variable_from_name(name)

        if not state_variable_as_function or not state_variable_as_function.visibility in [
            "public",
            "external",
        ]:
            txt = f'[ ] {sig} is missing {"" if required else "(optional)"}'
            logger.info(txt)
            missing_func = output.Output(
                txt, additional_fields={"function": sig, "required": required}
            )
            missing_func.add(contract)
            ret["missing_function"].append(missing_func.data)
            return

        types = [str(x) for x in export_nested_types_from_variable(state_variable_as_function)]

        if types != parameters:
            txt = f'[ ] {sig} is missing {"" if required else "(optional)"}'
            logger.info(txt)
            missing_func = output.Output(
                txt, additional_fields={"function": sig, "required": required}
            )
            missing_func.add(contract)
            ret["missing_function"].append(missing_func.data)
            return

        function_return_type = [export_return_type_from_variable(state_variable_as_function)]
        function = state_variable_as_function

        function_view = True
    else:
        function_return_type = function.return_type  # pylint: disable=no-member
        function_view = function.view  # pylint: disable=no-member

    txt = f"[✓] {sig} is present"
    logger.info(txt)

    if function_return_type:
        function_return_type = ",".join([str(x) for x in function_return_type])
        if function_return_type == return_type:
            txt = f"\t[✓] {sig} -> ({function_return_type}) (correct return type)"
            logger.info(txt)
        else:
            txt = f"\t[ ] {sig} -> ({function_return_type}) should return {return_type}"
            logger.info(txt)

            incorrect_return = output.Output(
                txt,
                additional_fields={
                    "expected_return_type": return_type,
                    "actual_return_type": function_return_type,
                },
            )
            incorrect_return.add(function)
            ret["incorrect_return_type"].append(incorrect_return.data)

    elif not return_type:
        txt = f"\t[✓] {sig} -> () (correct return type)"
        logger.info(txt)
    else:
        txt = f"\t[ ] {sig} -> () should return {return_type}"
        logger.info(txt)

        incorrect_return = output.Output(
            txt,
            additional_fields={
                "expected_return_type": return_type,
                "actual_return_type": function_return_type,
            },
        )
        incorrect_return.add(function)
        ret["incorrect_return_type"].append(incorrect_return.data)

    if view:
        if function_view:
            txt = f"\t[✓] {sig} is view"
            logger.info(txt)
        else:
            txt = f"\t[ ] {sig} should be view"
            logger.info(txt)

            should_be_view = output.Output(txt)
            should_be_view.add(function)
            ret["should_be_view"].append(should_be_view.data)

    if events:  # pylint: disable=too-many-nested-blocks
        for event in events:
            event_sig = f'{event.name}({",".join(event.parameters)})'

            if not function:
                txt = f"\t[ ] Must emit be view {event_sig}"
                logger.info(txt)

                missing_event_emmited = output.Output(
                    txt, additional_fields={"missing_event": event_sig}
                )
                missing_event_emmited.add(function)
                ret["missing_event_emmited"].append(missing_event_emmited.data)

            else:
                event_found = False
                for ir in function.all_slithir_operations():
                    if isinstance(ir, EventCall):
                        if ir.name == event.name:
                            if event.parameters == [str(a.type) for a in ir.arguments]:
                                event_found = True
                                break
                if event_found:
                    txt = f"\t[✓] {event_sig} is emitted"
                    logger.info(txt)
                else:
                    txt = f"\t[ ] Must emit be view {event_sig}"
                    logger.info(txt)

                    missing_event_emmited = output.Output(
                        txt, additional_fields={"missing_event": event_sig}
                    )
                    missing_event_emmited.add(function)
                    ret["missing_event_emmited"].append(missing_event_emmited.data)
Esempio n. 15
0
    def output(self, _filename):  # pylint: disable=too-many-locals
        """
        _filename is not used
        Args:
            _filename(string)
        """

        txt = ""

        all_contracts = []
        for c in self.contracts:
            if c.is_top_level:
                continue

            is_upgradeable_proxy = c.is_upgradeable_proxy
            is_upgradeable = c.is_upgradeable

            additional_txt_info = ""

            if is_upgradeable_proxy:
                additional_txt_info += " (Upgradeable Proxy)"

            if is_upgradeable:
                additional_txt_info += " (Upgradeable)"

            if c in self.slither.contracts_derived:
                additional_txt_info += " (Most derived contract)"

            txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n")
            additional_fields = output.Output(
                "",
                additional_fields={
                    "is_upgradeable_proxy": is_upgradeable_proxy,
                    "is_upgradeable": is_upgradeable,
                    "is_most_derived": c in self.slither.contracts_derived,
                },
            )

            # Order the function with
            # contract_declarer -> list_functions
            public = [
                (f.contract_declarer.name, f)
                for f in c.functions
                if (not f.is_shadowed and not f.is_constructor_variables)
            ]
            collect = collections.defaultdict(list)
            for a, b in public:
                collect[a].append(b)
            public = list(collect.items())

            for contract, functions in public:
                txt += blue(f"  - From {contract}\n")

                functions = sorted(functions, key=lambda f: f.full_name)

                for function in functions:
                    if function.visibility in ["external", "public"]:
                        txt += green(f"    - {function.full_name} ({function.visibility})\n")
                    if function.visibility in ["internal", "private"]:
                        txt += magenta(f"    - {function.full_name} ({function.visibility})\n")
                    if function.visibility not in [
                        "external",
                        "public",
                        "internal",
                        "private",
                    ]:
                        txt += f"    - {function.full_name}  ({function.visibility})\n"

                    additional_fields.add(
                        function, additional_fields={"visibility": function.visibility}
                    )

            all_contracts.append((c, additional_fields.data))

        self.info(txt)

        res = self.generate_output(txt)
        for contract, additional_fields in all_contracts:
            res.add(contract, additional_fields=additional_fields)

        return res
Esempio n. 16
0
    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
Esempio n. 17
0
    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