diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 357eca0..d369ed3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,7 +21,7 @@ jobs: github.event.pull_request.base.ref == 'main' env: ETHSCAN_API_KEY: ${{ secrets.ETHSCAN_API_KEY }} - QUORUM_PATH: "." + QUORUM_PATH: "Quorum/tests" ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} runs-on: ubuntu-latest container: @@ -39,4 +39,4 @@ jobs: - name: Execute Regression Tests run: | pytest Quorum/tests --maxfail=1 --disable-warnings --tb=short - CheckProposal --config Quorum/regression.json + CheckProposal --config Quorum/tests/regression.json diff --git a/Quorum/apis/block_explorers/chains_api.py b/Quorum/apis/block_explorers/chains_api.py index 1b58f8b..4ba28e6 100644 --- a/Quorum/apis/block_explorers/chains_api.py +++ b/Quorum/apis/block_explorers/chains_api.py @@ -1,6 +1,7 @@ import os import requests -import json +from json.decoder import JSONDecodeError +import json5 as json from Quorum.utils.chain_enum import Chain from Quorum.apis.block_explorers.source_code import SourceCode @@ -80,7 +81,7 @@ def get_source_code(self, proposal_address: str) -> list[SourceCode]: result = data['result'][0]["SourceCode"] try: json_data = json.loads(result) - except json.JSONDecodeError: + except (JSONDecodeError, ValueError): # Handle non-JSON formatted responses json_data = json.loads(result.removeprefix("{").removesuffix("}")) diff --git a/Quorum/apis/git_api/git_manager.py b/Quorum/apis/git_api/git_manager.py index 65bc069..34533bc 100644 --- a/Quorum/apis/git_api/git_manager.py +++ b/Quorum/apis/git_api/git_manager.py @@ -1,7 +1,7 @@ from pathlib import Path from git import Repo -import Quorum.config as config +import Quorum.utils.config as config import Quorum.utils.pretty_printer as pp class GitManager: diff --git a/Quorum/apis/price_feeds/price_feed_utils.py b/Quorum/apis/price_feeds/price_feed_utils.py index 7069c70..5d32b04 100644 --- a/Quorum/apis/price_feeds/price_feed_utils.py +++ b/Quorum/apis/price_feeds/price_feed_utils.py @@ -3,7 +3,7 @@ from typing import Optional from pydantic import BaseModel, Field from pathlib import Path -import json +import json5 as json import requests from Quorum.utils.chain_enum import Chain diff --git a/Quorum/auto_report/aave_tags.py b/Quorum/auto_report/aave_tags.py index b88ce8a..4a739af 100644 --- a/Quorum/auto_report/aave_tags.py +++ b/Quorum/auto_report/aave_tags.py @@ -1,6 +1,6 @@ import requests from dataclasses import dataclass -import json +import json5 as json BASE_BGD_CACHE_REPO = 'https://raw.githubusercontent.com/bgd-labs/v3-governance-cache/refs/heads/main/cache' diff --git a/Quorum/checks/check.py b/Quorum/checks/check.py index 0c4566e..4eb4504 100644 --- a/Quorum/checks/check.py +++ b/Quorum/checks/check.py @@ -1,9 +1,9 @@ from abc import ABC from datetime import datetime -import json +import json5 as json from pathlib import Path -import Quorum.config as config +import Quorum.utils.config as config from Quorum.apis.block_explorers.source_code import SourceCode from Quorum.utils.chain_enum import Chain diff --git a/Quorum/checks/new_listing.py b/Quorum/checks/new_listing.py index 551bf37..023ec60 100644 --- a/Quorum/checks/new_listing.py +++ b/Quorum/checks/new_listing.py @@ -1,6 +1,6 @@ from Quorum.checks.check import Check import Quorum.utils.pretty_printer as pp -import Quorum.config as config +import Quorum.utils.config as config from Quorum.llm.chains.first_deposit_chain import FirstDepositChain, ListingArray diff --git a/Quorum/entry_points/__init__.py b/Quorum/entry_points/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Quorum/check_proposal.py b/Quorum/entry_points/check_proposal.py similarity index 98% rename from Quorum/check_proposal.py rename to Quorum/entry_points/check_proposal.py index 339fec5..3cc0f59 100644 --- a/Quorum/check_proposal.py +++ b/Quorum/entry_points/check_proposal.py @@ -1,5 +1,6 @@ import argparse -import json +from json import JSONDecodeError +import json5 as json from typing import Any, Optional from Quorum.utils.chain_enum import Chain @@ -44,7 +45,7 @@ def load_config(config_path: str) -> dict[str, Any] | None: with open(config_path, 'r') as file: config_data = json.load(file) return config_data - except (FileNotFoundError, json.JSONDecodeError) as e: + except (FileNotFoundError, JSONDecodeError) as e: pp.pretty_print(f"Failed to parse given config file {config_path}:\n{e}", pp.Colors.FAILURE) diff --git a/Quorum/auto_report/create_report.py b/Quorum/entry_points/create_report.py similarity index 95% rename from Quorum/auto_report/create_report.py rename to Quorum/entry_points/create_report.py index 2b66b62..538a325 100644 --- a/Quorum/auto_report/create_report.py +++ b/Quorum/entry_points/create_report.py @@ -7,7 +7,7 @@ from jinja2 import Environment, FileSystemLoader -DEFAULT_TEMPLATE_PATH = Path(__file__).parent / 'AaveReportTemplate.md.j2' +DEFAULT_TEMPLATE_PATH = Path(__file__).parent.parent / 'auto_report/AaveReportTemplate.md.j2' def parse_args() -> argparse.Namespace: diff --git a/Quorum/ipfs_validator.py b/Quorum/entry_points/ipfs_validator.py similarity index 98% rename from Quorum/ipfs_validator.py rename to Quorum/entry_points/ipfs_validator.py index 96960fb..5bbf8af 100644 --- a/Quorum/ipfs_validator.py +++ b/Quorum/entry_points/ipfs_validator.py @@ -2,7 +2,7 @@ import Quorum.utils.arg_validations as arg_valid from Quorum.apis.block_explorers.chains_api import ChainAPI from Quorum.llm.chains.ipfs_validation_chain import IPFSValidationChain -import Quorum.config as config +import Quorum.utils.config as config from pathlib import Path import argparse diff --git a/Quorum/entry_points/setup_quorum.py b/Quorum/entry_points/setup_quorum.py new file mode 100644 index 0000000..4c1c931 --- /dev/null +++ b/Quorum/entry_points/setup_quorum.py @@ -0,0 +1,69 @@ +import shutil +import argparse +from pathlib import Path + +import Quorum.utils.pretty_printer as pp + + +def get_working_directory() -> Path: + parser = argparse.ArgumentParser(description="Setup Quorum project.") + parser.add_argument( + '--working_dir', + default=Path.cwd() / 'quorum_project', + type=Path, + help="Directory to set up the Quorum project." + ) + args = parser.parse_args() + return args.working_dir + + +def setup_quorum(working_dir: Path): + """ + Initializes Quorum environment by copying template files to the specified directory. + + Args: + working_dir (Path): Target directory for setting up Quorum. + + Raises: + shutil.Error: If copying files fails. + OSError: If directory creation fails. + """ + templates_dir = Path(__file__).parent.parent / 'templates' + target_dir = working_dir.resolve() + + if not target_dir.exists(): + pp.pretty_print(f"Creating directory: {target_dir}", pp.Colors.INFO) + target_dir.mkdir(parents=True, exist_ok=True) + + # Collect all file names to copy from the templates directory + template_files = [f.name for f in templates_dir.iterdir() if f.is_file()] + + for file_name in template_files: + src = templates_dir / file_name + dest = target_dir / '.env' if file_name == '.env.example' else target_dir / file_name + + if dest.exists(): + pp.pretty_print(f"File exists: {dest}. Skipping.", pp.Colors.WARNING) + continue + + shutil.copy(src, dest) + pp.pretty_print(f"Copied {file_name} to {dest}", pp.Colors.SUCCESS) + + # Add export QUORUM_PATH="path_to_your_quorum_directory" to the new .env file + with open(target_dir / '.env', 'a') as f: + f.write(f'\nexport QUORUM_PATH="{target_dir}"\n') + + pp.pretty_print("Quorum setup completed successfully!", pp.Colors.SUCCESS) + + +def main(): + working_dir = get_working_directory() + try: + setup_quorum(working_dir) + except Exception as e: + pp.pretty_print(f"Setup failed: {e}", pp.Colors.FAILURE) + exit(1) + + +if __name__ == "__main__": + main() diff --git a/Quorum/execution.json b/Quorum/execution.json deleted file mode 100644 index df3979c..0000000 --- a/Quorum/execution.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "Aave": { - "Ethereum": { - "Proposals": [] - }, - "Arbitrum": { - "Proposals": [] - }, - "Avalanche": { - "Proposals": [] - }, - "Base": { - "Proposals": [] - }, - "BNBChain": { - "Proposals": [] - }, - "Gnosis": { - "Proposals": [] - }, - "Metis": { - "Proposals": [] - }, - "Optimism": { - "Proposals": [] - }, - "Polygon": { - "Proposals": [] - }, - "Scroll": { - "Proposals": [] - }, - "zkSync": { - "Proposals": [] - } - } -} diff --git a/Quorum/llm/chains/cached_llm.py b/Quorum/llm/chains/cached_llm.py index e3440d9..f2458c7 100644 --- a/Quorum/llm/chains/cached_llm.py +++ b/Quorum/llm/chains/cached_llm.py @@ -1,6 +1,6 @@ from pathlib import Path -from Quorum.config import ANTHROPIC_MODEL, ANTHROPIC_API_KEY +from Quorum.utils.config import ANTHROPIC_MODEL, ANTHROPIC_API_KEY from langchain_anthropic import ChatAnthropic from langchain_community.cache import SQLiteCache diff --git a/Quorum/.env.example b/Quorum/templates/.env.example similarity index 100% rename from Quorum/.env.example rename to Quorum/templates/.env.example diff --git a/Quorum/templates/README.md b/Quorum/templates/README.md new file mode 100644 index 0000000..7d2db54 --- /dev/null +++ b/Quorum/templates/README.md @@ -0,0 +1,78 @@ +# Quorum Templates Guide + +This guide provides instructions on how to fill out the various template files in the Quorum project. + +## ground_truth.json + +This file contains the ground truth data for different protocols. Each protocol has its own section with the following fields: + +- `dev_repos`: A list of URLs to the development repositories. +- `review_repo`: The URL to the review repository. +- `price_feed_providers`: A list of price feed providers. +- `token_validation_providers`: A list of token validation providers. + +### Example +```json +{ + "Aave": + { + "dev_repos": + [ + "https://github.com/bgd-labs/aave-helpers", + "https://github.com/bgd-labs/aave-address-book", + "https://github.com/aave-dao/aave-v3-origin" + ], + "review_repo": "https://github.com/bgd-labs/aave-proposals-v3", + "price_feed_providers": ["Chainlink"], + "token_validation_providers": ["Coingecko"] + } +} +``` + +## execution.json + +This file contains the execution details for different protocols and networks. For each protocol, you need to specify the proposal addresses for various networks. + +### Instructions +- Replace `` with the name of the protocol as specified in `ground_truth.json`. +- Fill in the proposal addresses for each network. + +### Example +```jsonc +{ + "Aave": { + "Ethereum": { + "Proposals": ["0x..."] // Insert Ethereum proposals address here + }, + "Arbitrum": { + "Proposals": ["0x..."] // Insert Arbitrum proposals address here + }, + // ...other networks... + } +} +``` + +## .env + +This file contains environment variables that needs to be set for the project to run. +fill in the required values. + +### Instructions +- `ETHSCAN_API_KEY`: Your Etherscan API key. +- `ANTHROPIC_API_KEY`: Your Anthropic API key. +- `QUORUM_PATH`: The path to your Quorum directory. + +### Example +```bash +export ETHSCAN_API_KEY="your_etherscan_api_key" +export ANTHROPIC_API_KEY="your_anthropic_api_key" +export QUORUM_PATH="path_to_your_quorum_directory" +``` + +## Summary + +1. Fill in `ground_truth.json` with the appropriate data for each protocol. +2. Update `execution.json` with the proposal addresses for each network. +3. Set the required environment variables at `.env`. + +By following these instructions, you will ensure Quorum is correctly configured and ready to use. diff --git a/Quorum/templates/__init__.py b/Quorum/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Quorum/templates/execution.json b/Quorum/templates/execution.json new file mode 100644 index 0000000..892fdae --- /dev/null +++ b/Quorum/templates/execution.json @@ -0,0 +1,37 @@ +{ + "": { // Insert protocol / organization name here as specified in the ground_truth.json + "Ethereum": { + "Proposals": [] // Insert Ethereum proposals address here + }, + "Arbitrum": { + "Proposals": [] // Insert Arbitrum proposals address here + }, + "Avalanche": { + "Proposals": [] // Insert Avalanche proposals address here + }, + "Base": { + "Proposals": [] // Insert Base proposals address here + }, + "BNBChain": { + "Proposals": [] // Insert BNBChain proposals address here + }, + "Gnosis": { + "Proposals": [] // Insert Gnosis proposals address here + }, + "Metis": { + "Proposals": [] // Insert Metis proposals address here + }, + "Optimism": { + "Proposals": [] // Insert Optimism proposals address here + }, + "Polygon": { + "Proposals": [] // Insert Polygon proposals address here + }, + "Scroll": { + "Proposals": [] // Insert Scroll proposals address here + }, + "zkSync": { + "Proposals": [] // Insert zkSync proposals address here + } + } +} diff --git a/Quorum/templates/ground_truth.json b/Quorum/templates/ground_truth.json new file mode 100644 index 0000000..ef6aea1 --- /dev/null +++ b/Quorum/templates/ground_truth.json @@ -0,0 +1,26 @@ +{ + // Protocol or organization with the same name to be specified in the execution json + "": + { + // Main list of repositories for import diff checks + "dev_repos": [ + "", + "" + ], + + // Pre-deployment review repository for code verification + "review_repo": "", + + // Supported price feed providers for address validation e.g. Chainlink, Chronicle + "price_feed_providers": [ + "", + "" + ], + + // Token validation services for address verification e.g. Coingecko + "token_validation_providers": [ + "", + "" + ] + } +} \ No newline at end of file diff --git a/Quorum/tests/conftest.py b/Quorum/tests/conftest.py index 3b61bc0..815350a 100644 --- a/Quorum/tests/conftest.py +++ b/Quorum/tests/conftest.py @@ -1,7 +1,7 @@ import pytest from Quorum.apis.block_explorers.source_code import SourceCode -import Quorum.config as config +import Quorum.utils.config as config from pathlib import Path import shutil diff --git a/Quorum/tests/expected/test_auto_report/v3-132.md b/Quorum/tests/expected/test_auto_report/v3-132.md index 90a2b8a..9cff55d 100644 --- a/Quorum/tests/expected/test_auto_report/v3-132.md +++ b/Quorum/tests/expected/test_auto_report/v3-132.md @@ -53,70 +53,70 @@ Transaction: [0x423b2b381444d3a8a347536eaf643da3c7bc5e764ff4881863e012305d9542ba **`createProposal()` Parameters** ``` { - "payloads": [ + payloads: [ { - "chain": "1", - "accessLevel": 1, - "payloadsController": "0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5", - "payloadId": 146 + chain: "1", + accessLevel: 1, + payloadsController: "0xdAbad81aF85554E9ae636395611C58F7eC1aAEc5", + payloadId: 146, }, { - "chain": "137", - "accessLevel": 1, - "payloadsController": "0x401B5D0294E23637c18fcc38b1Bca814CDa2637C", - "payloadId": 71 + chain: "137", + accessLevel: 1, + payloadsController: "0x401B5D0294E23637c18fcc38b1Bca814CDa2637C", + payloadId: 71, }, { - "chain": "43114", - "accessLevel": 1, - "payloadsController": "0x1140CB7CAfAcC745771C2Ea31e7B5C653c5d0B80", - "payloadId": 42 + chain: "43114", + accessLevel: 1, + payloadsController: "0x1140CB7CAfAcC745771C2Ea31e7B5C653c5d0B80", + payloadId: 42, }, { - "chain": "10", - "accessLevel": 1, - "payloadsController": "0x0E1a3Af1f9cC76A62eD31eDedca291E63632e7c4", - "payloadId": 38 + chain: "10", + accessLevel: 1, + payloadsController: "0x0E1a3Af1f9cC76A62eD31eDedca291E63632e7c4", + payloadId: 38, }, { - "chain": "42161", - "accessLevel": 1, - "payloadsController": "0x89644CA1bB8064760312AE4F03ea41b05dA3637C", - "payloadId": 39 + chain: "42161", + accessLevel: 1, + payloadsController: "0x89644CA1bB8064760312AE4F03ea41b05dA3637C", + payloadId: 39, }, { - "chain": "1088", - "accessLevel": 1, - "payloadsController": "0x2233F8A66A728FBa6E1dC95570B25360D07D5524", - "payloadId": 19 + chain: "1088", + accessLevel: 1, + payloadsController: "0x2233F8A66A728FBa6E1dC95570B25360D07D5524", + payloadId: 19, }, { - "chain": "8453", - "accessLevel": 1, - "payloadsController": "0x2DC219E716793fb4b21548C0f009Ba3Af753ab01", - "payloadId": 25 + chain: "8453", + accessLevel: 1, + payloadsController: "0x2DC219E716793fb4b21548C0f009Ba3Af753ab01", + payloadId: 25, }, { - "chain": "100", - "accessLevel": 1, - "payloadsController": "0x9A1F491B86D09fC1484b5fab10041B189B60756b", - "payloadId": 23 + chain: "100", + accessLevel: 1, + payloadsController: "0x9A1F491B86D09fC1484b5fab10041B189B60756b", + payloadId: 23, }, { - "chain": "534352", - "accessLevel": 1, - "payloadsController": "0x6b6B41c0f8C223715f712BE83ceC3c37bbfDC3fE", - "payloadId": 15 + chain: "534352", + accessLevel: 1, + payloadsController: "0x6b6B41c0f8C223715f712BE83ceC3c37bbfDC3fE", + payloadId: 15, }, { - "chain": "56", - "accessLevel": 1, - "payloadsController": "0xE5EF2Dd06755A97e975f7E282f828224F2C3e627", - "payloadId": 17 - } + chain: "56", + accessLevel: 1, + payloadsController: "0xE5EF2Dd06755A97e975f7E282f828224F2C3e627", + payloadId: 17, + }, ], - "votingPortal": "0x9b24C168d6A76b5459B1d47071a54962a4df36c3", - "ipfsHash": "0x392c2cdfd6c2f57a7be73b170d472b4b8e6c662cb941451b449a0b2988ab3d57" + votingPortal: "0x9b24C168d6A76b5459B1d47071a54962a4df36c3", + ipfsHash: "0x392c2cdfd6c2f57a7be73b170d472b4b8e6c662cb941451b449a0b2988ab3d57", } ``` diff --git a/Quorum/ground_truth.json b/Quorum/tests/ground_truth.json similarity index 100% rename from Quorum/ground_truth.json rename to Quorum/tests/ground_truth.json diff --git a/Quorum/regression.json b/Quorum/tests/regression.json similarity index 100% rename from Quorum/regression.json rename to Quorum/tests/regression.json diff --git a/Quorum/tests/test_auto_report.py b/Quorum/tests/test_auto_report.py index fc555a4..358666a 100644 --- a/Quorum/tests/test_auto_report.py +++ b/Quorum/tests/test_auto_report.py @@ -2,7 +2,7 @@ import Quorum.tests.conftest as conftest -import Quorum.auto_report.create_report as create_report +import Quorum.entry_points.create_report as create_report from pathlib import Path diff --git a/Quorum/tests/test_price_feed_providers.py b/Quorum/tests/test_price_feed_providers.py index 5e6aca2..b4e690d 100644 --- a/Quorum/tests/test_price_feed_providers.py +++ b/Quorum/tests/test_price_feed_providers.py @@ -5,7 +5,7 @@ from Quorum.utils.chain_enum import Chain from Quorum.apis.price_feeds import PriceFeedData, ChainLinkAPI, ChronicleAPI, CoinGeckoAPI -import json +import json5 as json EXPECTED_DIR = conftest.EXPECTED_DIR / 'test_price_feed_providers' diff --git a/Quorum/tests/test_source_code.py b/Quorum/tests/test_source_code.py index c896b1d..b775312 100644 --- a/Quorum/tests/test_source_code.py +++ b/Quorum/tests/test_source_code.py @@ -4,7 +4,7 @@ from Quorum.apis.block_explorers.source_code import SourceCode -import json +import json5 as json EXPECTED_DIR = conftest.EXPECTED_DIR / 'test_source_code' diff --git a/Quorum/config.py b/Quorum/utils/config.py similarity index 71% rename from Quorum/config.py rename to Quorum/utils/config.py index 1dfff19..62b1dac 100644 --- a/Quorum/config.py +++ b/Quorum/utils/config.py @@ -1,5 +1,4 @@ import os -import shutil from pathlib import Path import Quorum.utils.pretty_printer as pp @@ -17,16 +16,9 @@ MAIN_PATH.mkdir(parents=True) GROUND_TRUTH_PATH = MAIN_PATH / "ground_truth.json" -DEFAULT_REPOS = Path(__file__).parent / "ground_truth.json" - -EXECUTION_PATH = MAIN_PATH / "execution.json" -DEFAULT_EXECUTION = Path(__file__).parent / "execution.json" if not GROUND_TRUTH_PATH.exists(): - shutil.copy(DEFAULT_REPOS, GROUND_TRUTH_PATH) - -if not EXECUTION_PATH.exists(): - shutil.copy(DEFAULT_EXECUTION, EXECUTION_PATH) + raise FileNotFoundError(f"Ground truth file not found at {GROUND_TRUTH_PATH}") ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY') if not ANTHROPIC_API_KEY: diff --git a/Quorum/utils/config_loader.py b/Quorum/utils/config_loader.py index 54b9abf..7b42e85 100644 --- a/Quorum/utils/config_loader.py +++ b/Quorum/utils/config_loader.py @@ -1,6 +1,6 @@ -import json +import json5 as json from typing import Dict -import Quorum.config as config +import Quorum.utils.config as config import Quorum.utils.pretty_printer as pp import Quorum.apis.price_feeds as price_feeds diff --git a/README.md b/README.md index 1507ee0..77b0a8b 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ Quorum is an open-source Python utility designed to verify the integrity of smar - **Verify Code Against Known Reviewed Repositories:** Generate diffs against specifically defined trusted auditor's repositories. - **Global Variable Check:** Ensure all global variables in unmatched contracts are either constant or immutable. - **Feed Price Check:** Verify the feed price of a contract is mentioned on ChainLink. -- **New Listing Check:** Check if proposal contain a new Listing. +- **New Listing Check:** Check if proposal contains a new Listing. - **Automated Repository Management:** Clone or update repositories based on customer configurations. +- **Quick Setup Command:** Streamline initial configuration with a single setup command that generates necessary files and guides proper setup. ## Prerequisites - Python 3.11 or higher @@ -28,44 +29,91 @@ Or clone the repository: git clone git@github.com:Certora/Quorum.git ``` +## Quick Setup + +To simplify the initial configuration, Quorum provides a setup command that generates essential configuration files and guides you through the setup process. + +### Using the Setup Command + +Run the following command in your desired working directory (defaults to the current directory if not specified): + +```sh +SetupQuorum [working_directory] +``` + +- **`working_directory`**: *(Optional)* Path to the desired working directory. Defaults to the current directory if not provided. + +**Example:** + +```sh +SetupQuorum ./my_quorum_project +``` + +This command will: +- Copy the following template files to your working directory: + - `ground_truth.json` + - `execution.json` + - `.env.example` + - `README.md` +- Provide guidance through comments within the configuration files, and a detailed README file to help you properly configure Quorum. + +### Post-Setup Configuration + +After running the setup command, perform the following steps: + +1. **Configure Environment Variables:** (Optional) + This step is optional if you prefer to set environment variables manually as described in the [Environment Variables](#environment-variables) section. + + Edit the `.env` file to include your actual API keys and desired paths: + + ```sh + export ETHSCAN_API_KEY="your_etherscan_api_key" + export ANTHROPIC_API_KEY="your_anthropic_api_key" + export QUORUM_PATH="/path/to/your/quorum_directory" + ``` + +2. **Fill Out Configuration Files:** + + - **`ground_truth.json`**: Define repositories and providers for each protocol. + - **`execution.json`**: Specify proposal addresses for each network. + - **`README.md`**: Follow the included guide to understand installation, configuration, available flags, and the checks performed by Quorum. + ## Clarifications -As part of tool process, the tool will use solcx to parse the contract code to AST. the version of solcx used is the latest. If the contract code is not compatible with the latest version of solcx, the tool will not be able to parse the contract code and will not be able to proceed with the global variable and new listing checks. +As part of the tool's process, Quorum uses `solcx` to parse contract code to AST. The version of `solcx` used is the latest. If the contract code is not compatible with the latest version of `solcx`, the tool will not be able to parse the contract code and will not be able to proceed with the global variable and new listing checks. ## Environment Variables -Before using Quorum, you need to configure the following environment variable for the Etherscan API key. This key is necessary to access the respective blockchain explorers: +Quorum requires specific environment variables to function correctly. These variables can be set in your shell or defined in a `.env` file. + +### Required Environment Variables - **ETHSCAN_API_KEY:** API key for Etherscan. +- **ANTHROPIC_API_KEY:** API key for Anthropic (required for advanced new listing first deposit checks). +- **QUORUM_PATH:** Path to specify where the repositories and diffs will be saved. -And for the new advanced new listing first deposit check, you need to configure the ANTHROPIC_API_KEY This key is necessary to access the Antropic API. +### Setting Environment Variables -You can set these environment variables in your shell: +**Using Shell:** ```sh export ETHSCAN_API_KEY="your_etherscan_api_key" export ANTHROPIC_API_KEY="your_anthropic_api_key" +export QUORUM_PATH="/path/to/artifacts" ``` -Replace `your_etherscan_api_key`, `your_anthropic_api_key` with your actual API keys. +**Using `.env` File:** -Alternatively, you can set these environment variables in a `.env` file in the current working directory where you use the tool: -(Please review /Quorum/.env.example) +After running the setup command, a `.env` file will be present. fill in the required values: + +Then edit `.env`: ```sh ETHSCAN_API_KEY=your_etherscan_api_key ANTHROPIC_API_KEY=your_anthropic_api_key +QUORUM_PATH="/path/to/artifacts" ``` - -Additionally, set the `QUORUM_PATH` environment variable to specify where the repositories and diffs will be saved: - -```sh -export QUORUM_PATH="/path/to/artifacts" -``` - -Replace `/path/to/artifacts` with the path where you want the tool to save cloned repositories and diff files. - ## Usage To run the tool, use the command line: @@ -86,7 +134,7 @@ Replace `CustomerName` with the customer identifier, `ChainName` with the blockc You can also execute multiple tasks using a configuration file: -Example config file `config.json`: +**Example config file `config.json`:** ```json { @@ -140,7 +188,7 @@ Example config file `config.json`: } ``` -To run using the config file: +**To run using the config file:** ```sh python3 Quorum/check_proposal.py --config path/to/config.json @@ -158,8 +206,7 @@ CheckProposal --config path/to/config.json The `ground_truth.json` file defines the repositories for each customer. It should be located under the `QUORUM_PATH`. If not found, a default `ground_truth.json` configuration will be created. - -Template for `ground_truth.json`: +### Template for `ground_truth.json`: ```json { @@ -175,40 +222,20 @@ Template for `ground_truth.json`: } ``` -Fields explanation: +**Fields explanation:** - `ProtocolName`: Your protocol or organization name - `dev_repos`: List of GitHub repositories containing your protocol's source code - `review_repo`: Repository containing pre-deployment code for review - `price_feed_providers`: List of supported price feed providers (Chainlink, Chronicle) - `token_validation_providers`: List of supported token validation providers (Coingecko) -``` -Example `ground_truth.json`: +### Current Supported Providers -```json -{ - "Aave": - { - "dev_repos": - [ - "https://github.com/bgd-labs/aave-helpers", - "https://github.com/bgd-labs/aave-address-book", - "https://github.com/aave-dao/aave-v3-origin" - ], - "review_repo": "https://github.com/bgd-labs/aave-proposals-v3", - "price_feed_providers": ["Chainlink"], - "token_validation_providers": ["Coingecko"] - } -} -``` - -This configuration is used by the tool to manage the ground truth information for each customer. The `dev_repos` array contains the URLs of the repositories associated with the customer. The `review_repo` field specifies the repository to compare against when checking proposals. The `price_feed_providers` array lists the feed price providers to check against (e.g., "Chainlink", "Chronicle"). The `token_validation_providers` array lists the token validation providers to check against (e.g., "Coingecko"). - -### current supported price feed providers are +**Price Feed Providers:** - Chainlink - Chronicle -## Current supported token validation providers are +**Token Validation Providers:** - Coingecko ## Artifacts Structure @@ -221,29 +248,29 @@ Quorum generates and organizes artifacts in a structured manner under the `QUORU QUORUM_PATH/ ├── ground_truth.json ├── CustomerName/ -| ├── modules/ -| │ ├── repository1/ -| │ ├── repository2/ -| │ ├── ... -| ├── checks/ -| | ├── ChainName/ -| | │ ├── ProposalAddress1/ -| | │ │ ├── DiffCheck_datetime/ -| | │ │ │ ├── file1.patch -| | │ │ │ ├── file2.patch -| | │ │ ├── FeedPriceCheck_datetime/ -| | │ │ │ ├── file1.json -| | │ │ ├── GlobalVariableCheck_datetime/ -| | │ │ │ ├── file1.json -| | │ │ │ ├── ... -| | │ │ ├── NewListingCheck_datetime/ -| | │ │ │ ├── file1.json -| | │ │ ├── ... -| | │ ├── ProposalAddress2/ -| | | ├── ... -| | ├── ... -| | ├── ProposalAddressN/ -| | | ├── ... +│ ├── modules/ +│ │ ├── repository1/ +│ │ ├── repository2/ +│ │ ├── ... +│ ├── checks/ +│ │ ├── ChainName/ +│ │ │ ├── ProposalAddress1/ +│ │ │ │ ├── DiffCheck_datetime/ +│ │ │ │ │ ├── file1.patch +│ │ │ │ │ ├── file2.patch +│ │ │ │ ├── FeedPriceCheck_datetime/ +│ │ │ │ │ ├── file1.json +│ │ │ │ ├── GlobalVariableCheck_datetime/ +│ │ │ │ │ ├── file1.json +│ │ │ │ │ ├── ... +│ │ │ │ ├── NewListingCheck_datetime/ +│ │ │ │ │ ├── file1.json +│ │ │ │ ├── ... +│ │ │ ├── ProposalAddress2/ +│ │ │ ├── ... +│ │ ├── ... +│ │ ├── ProposalAddressN/ +│ │ │ ├── ... ``` ### Description diff --git a/requirements.txt b/requirements.txt index db83cc1..aad7616 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,3 +12,4 @@ langchain-anthropic langgraph langchain_community python-dotenv +json5 diff --git a/setup.py b/setup.py index 1414741..ad12872 100644 --- a/setup.py +++ b/setup.py @@ -19,9 +19,10 @@ def read_version() -> str: }, entry_points={ "console_scripts": [ - "CheckProposal=Quorum.check_proposal:main", - "IPFSValidator=Quorum.ipfs_validator:main", - "CreateReport=Quorum.auto_report.create_report:main" + "CheckProposal=Quorum.entry_points.check_proposal:main", + "IPFSValidator=Quorum.entry_points.ipfs_validator:main", + "CreateReport=Quorum.entry_points.create_report:main", + "SetupQuorum=Quorum.entry_points.setup_quorum:main", ], }, )