diff --git a/slither/printers/summary/human_summary.py b/slither/printers/summary/human_summary.py index cadd41948..18ea7c516 100644 --- a/slither/printers/summary/human_summary.py +++ b/slither/printers/summary/human_summary.py @@ -13,33 +13,53 @@ class PrinterHumanSummary(AbstractPrinter): HELP = 'Print a human readable summary of the contracts' @staticmethod - def get_summary_erc20(contract): - txt = '' + def _get_summary_erc20(contract): + functions_name = [f.name for f in contract.functions] state_variables = [v.name for v in contract.state_variables] - if 'pause' in functions_name: - txt += "\t\t Can be paused? : {}\n".format(yellow('Yes')) - else: - txt += "\t\t Can be paused? : {}\n".format(green('No')) + pause = 'pause' in functions_name if 'mint' in functions_name: if not 'mintingFinished' in state_variables: - txt += "\t\t Minting restriction? : {}\n".format(red('None')) + mint_limited = False else: - txt += "\t\t Minting restriction? : {}\n".format(yellow('Yes')) + mint_limited = True + else: + mint = None # no minting + + race_condition_mitigated = 'increaseApproval' in functions_name or\ + 'safeIncreaseAllowance' in functions_name + + return pause, mint_limited, race_condition_mitigated + + + def get_summary_erc20(self, contract): + txt = '' + + pause, mint_limited, race_condition_mitigated = self._get_summary_erc20(contract) + + if pause: + txt += "\t\t Can be paused? : {}\n".format(yellow('Yes')) else: + txt += "\t\t Can be paused? : {}\n".format(green('No')) + + if mint_limited is None: txt += "\t\t Minting restriction? : {}\n".format(green('No Minting')) + else: + if mint_limited: + txt += "\t\t Minting restriction? : {}\n".format(red('Yes')) + else: + txt += "\t\t Minting restriction? : {}\n".format(yellow('No')) - if 'increaseApproval' in functions_name or 'safeIncreaseAllowance' in functions_name: + if race_condition_mitigated: txt += "\t\t ERC20 race condition mitigation: {}\n".format(green('Yes')) else: txt += "\t\t ERC20 race condition mitigation: {}\n".format(red('No')) return txt - def get_detectors_result(self): - + def _get_detectors_result(self): # disable detectors logger logger = logging.getLogger('Detectors') logger.setLevel(logging.ERROR) @@ -57,16 +77,28 @@ class PrinterHumanSummary(AbstractPrinter): issues_medium = [c for c in issues_medium if c] issues_high = [c.detect() for c in checks_high] issues_high = [c for c in issues_high if c] + return (len(issues_informational), + len(issues_low), + len(issues_medium), + len(issues_high)) - txt = "Number of informational issues: {}\n".format(green(len(issues_informational))) - txt += "Number of low issues: {}\n".format(green(len(issues_low))) - txt += "Number of medium issues: {}\n".format(yellow(len(issues_medium))) - txt += "Number of high issues: {}\n".format(red(len(issues_high))) + def get_detectors_result(self): + issues_informational, issues_low, issues_medium, issues_high = self._get_detectors_result() + txt = "Number of informational issues: {}\n".format(green(issues_informational)) + txt += "Number of low issues: {}\n".format(green(issues_low)) + txt += "Number of medium issues: {}\n".format(yellow(issues_medium)) + txt += "Number of high issues: {}\n".format(red(issues_high)) return txt @staticmethod - def is_complex_code(contract): + def _is_complex_code(contract): + for f in contract.functions: + if compute_cyclomatic_complexity(f) > 7: + return True + return False + + def is_complex_code(self, contract): """ Check if the code is complex Heuristic, the code is complex if: @@ -74,16 +106,17 @@ class PrinterHumanSummary(AbstractPrinter): Args: contract """ - is_complex = False - for f in contract.functions: - if compute_cyclomatic_complexity(f) > 7: - is_complex = True + is_complex = self._is_complex_code(contract) result = red('Yes') if is_complex else green('No') return "\tComplex code? {}\n".format(result) + @staticmethod + def _number_functions(contract): + return len(contract.functions) + def output(self, _filename): """ _filename is not used @@ -97,7 +130,7 @@ class PrinterHumanSummary(AbstractPrinter): txt += "\nContract {}\n".format(contract.name) txt += self.is_complex_code(contract) is_erc20 = contract.is_erc20() - txt += '\tNumber of functions:{}'.format(len(contract.functions)) + txt += '\tNumber of functions:{}'.format(self._number_functions(contract)) txt += "\tIs ERC20 token: {}\n".format(contract.is_erc20()) if is_erc20: txt += self.get_summary_erc20(contract)