From ef711fc6b61660e1bd21f40450c1d07891073d75 Mon Sep 17 00:00:00 2001 From: liav-certora Date: Mon, 6 Jan 2025 18:10:23 +0200 Subject: [PATCH] more formatting (live with michael) --- .gitignore | 1 + Quorum/apis/git_api/git_manager.py | 4 ++-- Quorum/checks/diff.py | 2 +- Quorum/checks/new_listing.py | 27 ++++++++++++++----------- Quorum/checks/price_feed.py | 6 +++--- Quorum/entry_points/check_proposal.py | 29 ++++++++++++++++----------- Quorum/utils/pretty_printer.py | 13 +++++++++--- version | 2 +- 8 files changed, 50 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index 8e477f8..4ecd9a4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ CustomerClones/ **.DS_Store !**cached_llm.py quorum_project/ +dist/ diff --git a/Quorum/apis/git_api/git_manager.py b/Quorum/apis/git_api/git_manager.py index 8969181..9e21d61 100644 --- a/Quorum/apis/git_api/git_manager.py +++ b/Quorum/apis/git_api/git_manager.py @@ -57,7 +57,7 @@ def __clone_or_update_for_repo(repo_name: str, repo_url: str, to_path: Path): repo.git.pull() repo.git.submodule('update', '--init', '--recursive') else: - pp.pprint(f"Cloning {repo_name} from URL: {repo_url} to {repo_path}...", pp.Colors.INFO) + pp.pprint(f'Cloning {repo_name} from URL: {repo_url} to {repo_path}...', pp.Colors.INFO) Repo.clone_from(repo_url, repo_path, multi_options=["--recurse-submodules"]) @@ -68,7 +68,7 @@ def clone_or_update(self) -> None: If the repository already exists locally, it will update the repository and its submodules. Otherwise, it will clone the repository and initialize submodules. """ - pp.pprint('Cloning and updating preliminaries', pp.Colors.INFO) + pp.pprint('Cloning and updating preliminaries', pp.Colors.INFO, pp.Heading.HEADING_2) for repo_name, repo_url in self.repos.items(): GitManager.__clone_or_update_for_repo(repo_name, repo_url, self.modules_path) diff --git a/Quorum/checks/diff.py b/Quorum/checks/diff.py index 78edcc7..2115d51 100644 --- a/Quorum/checks/diff.py +++ b/Quorum/checks/diff.py @@ -129,7 +129,7 @@ def __print_diffs_results(self, missing_files: list[SourceCode], files_with_diff num_identical = num_total_files - num_missing_files - num_diff_files # Identical files message. - pp.pprint(f'Files found identical: {num_identical}/{num_total_files}', pp.Colors.SUCCESS) + pp.pprint(f'Files found identical: {num_identical}/{num_total_files}\n', pp.Colors.SUCCESS) # Diffs files message. if num_diff_files > 0: diff --git a/Quorum/checks/new_listing.py b/Quorum/checks/new_listing.py index 4f6f192..faa7e8a 100644 --- a/Quorum/checks/new_listing.py +++ b/Quorum/checks/new_listing.py @@ -14,10 +14,13 @@ def new_listing_check(self) -> None: """ functions = self._get_functions_from_source_codes() if functions.get('newListings', functions.get('newListingsCustom')): - pp.pprint(f"New listings detected for {self.proposal_address}", pp.Colors.WARNING) + pp.pprint(f'New listings detected for payload {self.proposal_address}', pp.Colors.WARNING) - # Check if Anthropic API key is configured - if not config.ANTHROPIC_API_KEY: + proposal_code = self.source_codes[0].file_content + proposal_code_str = '\n'.join(proposal_code) + try: + listings: ListingArray | None = FirstDepositChain().execute(proposal_code_str) + except: pp.pprint( 'New listings were detected in payload but first deposit check is skipped.\n' 'If you have a LLM API key, you can add it to your environment variables to enable this check', @@ -25,21 +28,21 @@ def new_listing_check(self) -> None: ) return - proposal_code = self.source_codes[0].file_content - proposal_code_str = '\n'.join(proposal_code) - listings: ListingArray | None = FirstDepositChain().execute(proposal_code_str) if listings is None: pp.pprint('New listings were detected in payload but LLM failed to retrieve them.', pp.Colors.FAILURE) return - msg = f'{len(listings.listings)} new asset listings were detected:\n' + pp.pprint(f'{len(listings.listings)} new asset listings were detected:', pp.Colors.INFO) for i, listing in enumerate(listings.listings, 1): - if listing.approve_indicator and listing.supply_indicator: - msg += f'\t{i}. New listing detected for {listing.asset_symbol}\n' - else: - msg += f'\t{i}. New listing detected for {listing.asset_symbol} but no approval or supply detected\n' - pp.pprint(msg, pp.Colors.INFO) + pp.pprint(f'\t{i}. Variable: {listing.asset_symbol}\n' + f'\t Asset address: {listing.asset_address}\n' + f'\t Approve indicator: {listing.approve_indicator}\n' + f'\t Supply seed amount: {listing.supply_seed_amount}\n' + f'\t Supply indicator: {listing.supply_indicator}', + (pp.Colors.SUCCESS if listing.approve_indicator and listing.supply_indicator + else pp.Colors.FAILURE)) + self._write_to_file('new_listings.json', listings.model_dump()) else: diff --git a/Quorum/checks/price_feed.py b/Quorum/checks/price_feed.py index fe0f198..590c280 100644 --- a/Quorum/checks/price_feed.py +++ b/Quorum/checks/price_feed.py @@ -102,14 +102,14 @@ def verify_price_feed(self) -> None: self._write_to_file(verified_sources_path, verified_variables) num_addresses = len(all_addresses) - pp.pprint(f'{num_addresses} addresses identified in the payload.', pp.Colors.INFO) + pp.pprint(f'{num_addresses} addresses identified in the payload.\n', pp.Colors.INFO) coingecko_name = CoinGeckoAPI().get_name() token_validation_res = {r for r in overall_verified_vars if r.found_on == coingecko_name} price_feed_validation_res = overall_verified_vars - token_validation_res # Print price feed validation - pp.pprint('Price feed validation', pp.Colors.INFO) + pp.pprint('Price Feed Validation', pp.Colors.INFO, pp.Heading.HEADING_3) msg = (f'{len(price_feed_validation_res)}/{num_addresses} ' 'were identified as price feeds of the configured providers:\n') for i, var_res in enumerate(price_feed_validation_res, 1): @@ -119,7 +119,7 @@ def verify_price_feed(self) -> None: pp.pprint(msg, pp.Colors.SUCCESS) # Print token validation - pp.pprint('Token validation', pp.Colors.INFO) + pp.pprint('Token Validation', pp.Colors.INFO, pp.Heading.HEADING_3) msg = (f'{len(token_validation_res)}/{num_addresses} ' 'were identified as tokens of the configured providers:\n') for i, var_res in enumerate(token_validation_res, 1): diff --git a/Quorum/entry_points/check_proposal.py b/Quorum/entry_points/check_proposal.py index eaec8fe..d4d3a68 100644 --- a/Quorum/entry_points/check_proposal.py +++ b/Quorum/entry_points/check_proposal.py @@ -64,7 +64,7 @@ def proposals_check(customer: str, chain: Chain, proposal_addresses: list[str], api = ChainAPI(chain) for proposal_address in proposal_addresses: - pp.pprint(f'Analyzing payload {proposal_address} on {chain}', pp.Colors.INFO, is_heading=True) + pp.pprint(f'Analyzing payload {proposal_address} on {chain}', pp.Colors.INFO, pp.Heading.HEADING_1) try: source_codes = api.get_source_code(proposal_address) @@ -82,27 +82,29 @@ def proposals_check(customer: str, chain: Chain, proposal_addresses: list[str], continue # Diff check - pp.pprint('Check 1 - Comparing payload contract and imports with the source of truth', pp.Colors.INFO) + pp.pprint('Check 1 - Comparing payload contract and imports with the source of truth', + pp.Colors.INFO, pp.Heading.HEADING_2) missing_files = Checks.DiffCheck(customer, chain, proposal_address, source_codes).find_diffs() pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) # Review diff check - pp.pprint(f'Check 2 - Verifying missing files against customer review repo', pp.Colors.INFO) + pp.pprint(f'Check 2 - Verifying missing files against customer review repo', + pp.Colors.INFO, pp.Heading.HEADING_2) Checks.ReviewDiffCheck(customer, chain, proposal_address, missing_files).find_diffs() pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) # Global variables check - pp.pprint('Check 3 - Global variables', pp.Colors.INFO) + pp.pprint('Check 3 - Global variables', pp.Colors.INFO, pp.Heading.HEADING_2) Checks.GlobalVariableCheck(customer, chain, proposal_address, missing_files).check_global_variables() pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) # Feed price check - pp.pprint('Check 4 - Explicit addresses validation', pp.Colors.INFO) + pp.pprint('Check 4 - Explicit addresses validation', pp.Colors.INFO, pp.Heading.HEADING_2) Checks.PriceFeedCheck(customer, chain, proposal_address, missing_files, providers).verify_price_feed() pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) # New listing check - pp.pprint('Check 5 - First deposit for new listing', pp.Colors.INFO) + pp.pprint('Check 5 - First deposit for new listing', pp.Colors.INFO, pp.Heading.HEADING_2) Checks.NewListingCheck(customer, chain, proposal_address, missing_files).new_listing_check() pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) @@ -110,10 +112,10 @@ def proposals_check(customer: str, chain: Chain, proposal_addresses: list[str], def format_metadata(customer: str, chain_info: dict[str, list[str]]) -> str: msg = f'Customer: {customer}\nChains and payloads:\n' for chain, addresses in chain_info.items(): - if len(addresses) == 0: + if len(addresses['Proposals']) == 0: continue msg += f'* {chain}:\n' - for address in addresses: + for address in addresses['Proposals']: msg += f'\t- {address}\n' return msg @@ -130,13 +132,13 @@ def main() -> None: if config_data: # Multi-task mode using JSON configuration for customer, chain_info in config_data.items(): - pp.pprint('Run Preparation', pp.Colors.INFO, is_heading=True) + pp.pprint('Run Preparation', pp.Colors.INFO, pp.Heading.HEADING_1) ground_truth_config = ConfigLoader.load_customer_config(customer) GitManager(customer, ground_truth_config).clone_or_update() price_feed_providers = ground_truth_config.get('price_feed_providers', []) pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) - pp.pprint('Run Metadata', pp.Colors.INFO, is_heading=True) + pp.pprint('Run Metadata', pp.Colors.INFO, pp.Heading.HEADING_2) pp.pprint(format_metadata(customer, chain_info), pp.Colors.INFO) pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) for chain, proposals in chain_info.items(): @@ -148,12 +150,15 @@ def main() -> None: # Single-task mode using command line arguments if not (customer and chain and proposal_address): raise ValueError("Customer, chain, and proposal_address must be specified if not using a config file.") - pp.pprint('Run Preparation', pp.Colors.INFO) + pp.pprint('Run Preparation', pp.Colors.INFO, pp.Heading.HEADING_1) ground_truth_config = ConfigLoader.load_customer_config(customer) GitManager(customer, ground_truth_config).clone_or_update() price_feed_providers = ground_truth_config.get("price_feed_providers", []) - pp.pprint('Run Metadata', pp.Colors.INFO) + pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) + + pp.pprint('Run Metadata', pp.Colors.INFO, pp.Heading.HEADING_2) pp.pprint(f'Customer: {customer}\nChains and payloads:\n{chain}: {proposal_address}', pp.Colors.INFO) + pp.pprint(pp.SEPARATOR_LINE, pp.Colors.INFO) proposals_check(customer, chain, [proposal_address], price_feed_providers) diff --git a/Quorum/utils/pretty_printer.py b/Quorum/utils/pretty_printer.py index 139d4b8..0d6cb84 100644 --- a/Quorum/utils/pretty_printer.py +++ b/Quorum/utils/pretty_printer.py @@ -1,9 +1,16 @@ from enum import StrEnum +from typing import Optional SEPARATOR_LINE = '\n' + '-' * 110 + '\n' +class Heading(StrEnum): + HEADING_1 = '=' + HEADING_2 = '-' + HEADING_3 = '.' + + class Colors(StrEnum): SUCCESS = '\033[92m' FAILURE = '\033[91m' @@ -12,8 +19,8 @@ class Colors(StrEnum): RESET = '\033[0m' -def pprint(message: str, status: Colors, is_heading: bool = False): +def pprint(message: str, status: Colors, heading: Optional[Heading]=None): s = status + message + Colors.RESET - if is_heading: - s += '\n' + '-' * len(message) + if heading: + s += '\n' + heading * len(message) + '\n' print(s) diff --git a/version b/version index 6c30ebe..64c614d 100644 --- a/version +++ b/version @@ -1 +1 @@ -20250105.235907.619968 +20250106.181023.639435