Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setup for the tool usage #59

Merged
merged 22 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
5 changes: 3 additions & 2 deletions Quorum/apis/block_explorers/chains_api.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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("}"))

Expand Down
2 changes: 1 addition & 1 deletion Quorum/apis/git_api/git_manager.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Quorum/apis/price_feeds/price_feed_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Optional
from pydantic import BaseModel, Field
from pathlib import Path
import json
import json5 as json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change that to simply import json5. I'm afraid that down the line it will get confusing because these 2 packages do act a little bit differently in certain things (as you saw).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference between them is agnostic, if it will cause any issue in the future we can change it. for now, i prefer it to be called json instead of a variable with number name just for apperance.

import requests

from Quorum.utils.chain_enum import Chain
Expand Down
2 changes: 1 addition & 1 deletion Quorum/auto_report/aave_tags.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import requests
from dataclasses import dataclass
import json
import json5 as json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same



BASE_BGD_CACHE_REPO = 'https://raw.githubusercontent.com/bgd-labs/v3-governance-cache/refs/heads/main/cache'
Expand Down
4 changes: 2 additions & 2 deletions Quorum/checks/check.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from abc import ABC
from datetime import datetime
import json
import json5 as json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

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

Expand Down
2 changes: 1 addition & 1 deletion Quorum/checks/new_listing.py
Original file line number Diff line number Diff line change
@@ -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


Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
import json
from json import JSONDecodeError
import json5 as json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

from typing import Any, Optional

from Quorum.utils.chain_enum import Chain
Expand Down Expand Up @@ -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)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 67 additions & 0 deletions Quorum/entry_points/setup_quorum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import shutil
import argparse
from pathlib import Path
import Quorum.utils.pretty_printer as pp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank line above please :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done



def get_working_directory() -> Path:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change name to parse_args. I know that this function only returns the directory for Quorum but it became kind of an unwritten convention over all of our command line tools that we call parse_args for parsing the arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer a more accurate name here. if ever we need to add more argument here ill re name it to parse args

parser = argparse.ArgumentParser(description="Setup Quorum project.")
parser.add_argument(
'--working_dir',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest change the name to --target_dir or something similar. "working_dir" is too confusing with the "current working directory" imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working dir is more accurate to the user as its going to be the directory he going work from.

default=Path.cwd(),
nivcertora marked this conversation as resolved.
Show resolved Hide resolved
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 a Quorum environment by copying template files to the specified directory.
nivcertora marked this conversation as resolved.
Show resolved Hide resolved

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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey you actually named it "target_dir" here lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it serves as a target for the copy file therefore the new variable name is introduced which adds additional clarity for the code readable. (For us not the user).


if not target_dir.exists():
pp.pretty_print(f"Creating directory: {target_dir}", pp.Colors.INFO)
target_dir.mkdir(parents=True, exist_ok=True)

template_files = ['ground_truth.json', 'execution.json', '.env.example', 'Readme.md']

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():
yoav-el-certora marked this conversation as resolved.
Show resolved Hide resolved
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)
Comment on lines +41 to +50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked and if .env is in a subdirectory it won't be found automatically so you can rename .env.example to .env without worrying. With that you can just use shutil.copytree instead of the whole for loop but that means everything will be overridden, unlike how you skip existing files. Which I actually think can be better because if a user messes his directory or one of the files he can easily just run this tool again.
You have the option, whatever you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the current state, and also i would suggest to not upload a .env to the repo.


# 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()
37 changes: 0 additions & 37 deletions Quorum/execution.json

This file was deleted.

2 changes: 1 addition & 1 deletion Quorum/llm/chains/cached_llm.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
File renamed without changes.
78 changes: 78 additions & 0 deletions Quorum/templates/Readme.md
nivcertora marked this conversation as resolved.
Show resolved Hide resolved
nivcertora marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -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 `<protocol_name>` 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 need to be set for the project to run.
nivcertora marked this conversation as resolved.
Show resolved Hide resolved
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. `.env` set the required environment variables.
nivcertora marked this conversation as resolved.
Show resolved Hide resolved

By following these instructions, you will ensure that the Quorum project is correctly configured and ready to use.
nivcertora marked this conversation as resolved.
Show resolved Hide resolved
Empty file added Quorum/templates/__init__.py
Empty file.
37 changes: 37 additions & 0 deletions Quorum/templates/execution.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"<protocol_name>": { // 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
}
}
}
26 changes: 26 additions & 0 deletions Quorum/templates/ground_truth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
// Protocol or organization with the same name to be specified in the execution json
"<protocol_name>":
{
// Main list of repositories for import diff checks
"dev_repos": [
"<https://github.com/org/repo1>",
"<https://github.com/org/repo2>"
],

// Pre-deployment review repository for code verification
"review_repo": "<https://github.com/org/review-repo>",

// Supported price feed providers for address validation e.g. Chainlink, Chronicle
"price_feed_providers": [
"<price_feed_provider1>",
"<price_feed_provider2>"
],

// Token validation services for address verification e.g. Coingecko
"token_validation_providers": [
"<token_validation_provider1>",
"<token_validation_provider2>"
]
}
}
2 changes: 1 addition & 1 deletion Quorum/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading
Loading