Skip to content

Auto Report Generation #19

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

Merged
merged 20 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f8c5bf0
Initial template processing
liav-certora Nov 23, 2024
41cd331
Merge f8c5bf077181f7e245deca78a8a1486b21a23f93 into 23cef171762b95d14…
liav-certora Nov 24, 2024
a71b067
Auto change version.
liav-certora Nov 24, 2024
e7c83b5
Merge branch 'main' into liav/cert-7500-auto-report
liav-certora Dec 8, 2024
9b651a0
Merge e7c83b5fc14b0798cb050e3d0fb1215537b01eb4 into 6f4b497e620679e12…
liav-certora Dec 8, 2024
c61c70c
Auto change version.
liav-certora Dec 8, 2024
e5de7fc
Niv CR
liav-certora Dec 8, 2024
85bba1a
Merge branch 'liav/cert-7500-auto-report' of https://github.com/Certo…
liav-certora Dec 8, 2024
3f7affc
Merge 85bba1a858e794aeabd199df758d0ad226727111 into 6f4b497e620679e12…
liav-certora Dec 8, 2024
e21bbb9
Auto change version.
liav-certora Dec 8, 2024
631d5e5
tag info
liav-certora Dec 9, 2024
6779bf1
Merge 631d5e5fc0bc1a533ccf8034c0a2337089ea80b8 into 6f4b497e620679e12…
liav-certora Dec 9, 2024
06d24d2
Auto change version.
liav-certora Dec 9, 2024
b573477
Added session and dict safety
liav-certora Dec 10, 2024
6ffa4cb
Merge b5734776c8e816ed201e78b6ca845544980a0c93 into 6f4b497e620679e12…
liav-certora Dec 10, 2024
b67510f
Auto change version.
liav-certora Dec 10, 2024
a23d142
convert to jinja2
liav-certora Dec 10, 2024
4544ee0
Merge branch 'liav/cert-7500-auto-report' of https://github.com/Certo…
liav-certora Dec 10, 2024
bfc104c
Merge 4544ee087be29326bfa1d58632fd3141ebb4683f into 6f4b497e620679e12…
liav-certora Dec 10, 2024
31d3709
Auto change version.
liav-certora Dec 10, 2024
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
58 changes: 58 additions & 0 deletions Quorum/auto_report/AaveReportTemplate.md.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Proposal {{ proposal_id }}. {{ proposal_title }}

### Voting Link
[Link to voting page]({{ voting_link }})

### Governance Forum Discussions
[Link to forum discussions]({{ gov_forum_link }})

### Payloads
{% for chain, payload_link in zip(chain, payload_link) %}
* {{ chain }} - [proposal payloads]({{ payload_link }})
{% endfor %}


## Certora Analysis

### Proposal Types
{**TODO: Choose types from the following list.**}
* :scroll: :small_red_triangle: Contract upgrades
* :moneybag: :receipt: Asset transfers
* :handshake: Permission granting and revoking
* :wrench: :bar_chart: Configuration updates
* :gem: :new: Listing new assets

### Context
{**TODO: Write context.**}

### Proposal Creation
Transaction: [{{ transaction_hash }}]({{ transaction_link }})
- `proposalId`: {{ proposal_id }}
- `creator`: {{ creator }}
- `accessLevel`: {{ access_level }}
- `ipfsHash`: {{ ipfs_hash }}

**`createProposal()` Parameters**
```
{{ createProposal_parameters_data }}
```

### Aave Seatbelt Report
**Proposal Report**
[Link to Seatbelt proposal report]({{ seatbelt_link }})

**Payload Reports**
{% for chain, payload_seatbelt_link in zip(chain, payload_seatbelt_link) %}
* {{ chain }} - [payload Seatbelt report]({{ payload_seatbelt_link }})
{% endfor %}

### Technical Analysis
{**TODO: Write technical analysis.**}

The proposal is consistent with the description on both Snapshot and the governance forum.

### Certora validations
* :white_check_mark: The code on the proposal payload corresponds to the proposal specification.
* :white_check_mark: The proposal includes a proper tests suite, checking all necessary post-conditions.
* :white_check_mark: BGD reviewed the payload before the proposal was submitted.
* :white_check_mark: Certora reviewed the procedure followed to submit the proposal.
85 changes: 85 additions & 0 deletions Quorum/auto_report/aave_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import requests
from dataclasses import dataclass
import json


BASE_BGD_CACHE_REPO = 'https://raw.githubusercontent.com/bgd-labs/v3-governance-cache/refs/heads/main/cache'
PROPOSALS_URL = f'{BASE_BGD_CACHE_REPO}/1/0x9AEE0B04504CeF83A65AC3f0e838D0593BCb2BC7/proposals'
BASE_SEATBELT_REPO = 'https://github.com/bgd-labs/seatbelt-gov-v3/blob/main/reports'
SEATBELT_PAYLOADS_URL = f'{BASE_SEATBELT_REPO}/payloads'


@dataclass
class ChainInfo:
name: str
block_explorer_link: str


AAVE_CHAIN_MAPPING = {
'1': ChainInfo('Ethereum', 'https://etherscan.io/address'),
'137': ChainInfo('Polygon', 'https://polygonscan.com/address'),
'43114': ChainInfo('Avalanche', 'https://snowtrace.io/address'),
'8453': ChainInfo('Base', 'https://basescan.org/address'),
'42161': ChainInfo('Arbitrum One', 'https://arbiscan.io/address'),
'1088': ChainInfo('Metis', 'https://explorer.metis.io/address'),
'10': ChainInfo('OP Mainnet', 'https://optimistic.etherscan.io/address'),
'56': ChainInfo('BNB Smart Chain', 'https://bscscan.com/address'),
'100': ChainInfo('Gnosis', 'https://gnosisscan.io/address'),
'534352': ChainInfo('Scroll', 'https://scrollscan.com/address'),
'324': ChainInfo('zkSync Era', 'https://era.zksync.network/address')
}


def __extract_payload_address(session: requests.Session, chain_id: str, controller: str, payload_id: int) -> str:
resp = session.get(f'{BASE_BGD_CACHE_REPO}/{chain_id}/{controller}/payloads/{payload_id}.json')
resp.raise_for_status()

payload_data = resp.json()

return payload_data['payload']['actions'][0]['target']


def get_aave_tags(proposal_id: int) -> dict:
with requests.Session() as session:
proposal_data_link = f'{PROPOSALS_URL}/{proposal_id}.json'
resp = session.get(proposal_data_link)
resp.raise_for_status()

proposal_data: dict = resp.json()

ipfs: dict = proposal_data.get('ipfs', {})
proposal: dict = proposal_data.get('proposal', {})
create_event: dict = proposal_data.get('events', [{}])[0] # The create event is always the first.

tags = {}
tags['proposal_id'] = str(proposal_id)
tags['proposal_title'] = ipfs.get('title', 'N/A')
tags['voting_link'] = f'https://vote.onaave.com/proposal/?proposalId={proposal_id}'
tags['gov_forum_link'] = ipfs.get('discussions', 'N/A')

tags['chain'], tags['payload_link'], tags['payload_seatbelt_link'] = [], [], []
for p in proposal.get('payloads', []):
# These are necessary fields in the payload data to construct the payload fields.
if not all(k in p for k in ['chain', 'payloadsController', 'payloadId']):
continue
address = __extract_payload_address(session, p['chain'], p['payloadsController'], p['payloadId'])
tags['chain'].append(AAVE_CHAIN_MAPPING[p['chain']].name)
tags['payload_link'].append(f'{AAVE_CHAIN_MAPPING[p["chain"]].block_explorer_link}/{address}')
tags['payload_seatbelt_link'].append(
f'{SEATBELT_PAYLOADS_URL}/{p["chain"]}/{p["payloadsController"]}/{p["payloadId"]}.md'
)

tags['transaction_hash'] = create_event.get('transactionHash', 'N/A')
tags['transaction_link'] = f'https://etherscan.io/tx/{tags["transaction_hash"]}'

args: dict = create_event.get('args', {})
tags['creator'] = args.get('creator', 'N/A')
tags['access_level'] = str(args.get('accessLevel', 'N/A'))
tags['ipfs_hash'] = args.get('ipfsHash', 'N/A')

tags['createProposal_parameters_data'] = json.dumps({k: proposal.get(k, 'N/A') for k
in ['payloads', 'votingPortal', 'ipfsHash']}, indent=4)

tags['seatbelt_link'] = f'{BASE_SEATBELT_REPO}/proposals/{proposal_id}.md'

return tags
47 changes: 47 additions & 0 deletions Quorum/auto_report/create_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Quorum.auto_report.aave_tags as aave_tags
import Quorum.utils.pretty_printer as pprinter

import argparse
from pathlib import Path

from jinja2 import Environment, FileSystemLoader


DEFAULT_TEMPLATE_PATH = Path(__file__).parent / 'AaveReportTemplate.md.j2'


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description='This tool generates automatic proposal reports.')
parser.add_argument('--proposal_id', required=True, type=int, help='The proposal id to generate report to.')
parser.add_argument('--template', default=DEFAULT_TEMPLATE_PATH, help='The report template to use.')

args = parser.parse_args()

if not Path(args.template).exists():
raise FileNotFoundError(f'could not find template at {args.template}.')

return parser.parse_args()


def main():
args = parse_args()

pprinter.pretty_print(f'Generating a report using template in {args.template}', pprinter.Colors.INFO)
env = Environment(loader=FileSystemLoader(args.template.parent))
env.globals.update(zip=zip)
template = env.get_template(args.template.name)

pprinter.pretty_print(f'Retrieving tag information for proposal {args.proposal_id}', pprinter.Colors.INFO)
tags = aave_tags.get_aave_tags(args.proposal_id)
pprinter.pretty_print(f'Tag information retrieved', pprinter.Colors.INFO)

report = template.render(tags)

with open((report_path:=f'v3-{args.proposal_id}.md'), 'w') as f:
f.write(report)

pprinter.pretty_print(f'Created report at {report_path}.', pprinter.Colors.SUCCESS)


if __name__ == '__main__':
main()
23 changes: 23 additions & 0 deletions Quorum/auto_report/create_report_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Auto Report Generation
This tool automatically fetches data from Aave Governance and generates a report automatically using an editable template. To let the generator know where to use the different data tags can be used in the template.

The template for the report is using Jinja2: https://jinja.palletsprojects.com/en/stable/templates/

## Available Tags
### Aave
#### Single Value Tags
* `{{ proposal_id }}` - The proposal id.
* `{{ title }}` - The proposal title.
* `{{ voting_link }}` - The link to the voting page.
* `{{ gov_forum_link }}` - The link to the governance forum discussions.
* `{{ transaction_link }}` - Link to the transaction of the proposal creation.
* `{{ creator }}` - Creator of the proposal.
* `{{ access_level }}` - Access level of the proposal.
* `{{ ipfs_hash }}` - The IPFS hash.
* `{{ createProposal_parameters_data }}` - The parameters in `createProposal()`.
* `{{ seatbelt_link }}` - Link to proposal Seatbelt report.

#### List Values Tags
* `{{ chain }}` - The chain of each payload in the proposal.
* `{{ payload_link }}` - List of links to the different payloads.
* `{{ payload_seatbelt_link }}` - List of Seatbelt report of each payload.
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20241205.162300.009632
20241210.135112.911775