Skip to content

Commit

Permalink
feat: setup for running checks locally (#29)
Browse files Browse the repository at this point in the history
* feat: allow any RPC URL (remove dependence on Infura)

* feat: save files locally when not in CI

* docs: update README

* chore: add .env files to .gitignore
  • Loading branch information
mds1 authored Oct 1, 2021
1 parent 4930ade commit adb959d
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/governance-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
INFURA_API_KEY: ${{ secrets.INFURA_API_KEY }}
RPC_URL: ${{ secrets.RPC_URL }}
DAO_NAME: ${{ matrix.DAO_NAME }}
GOVERNOR_ADDRESS: ${{ matrix.GOVERNOR_ADDRESS }}
RUNNING_LOCALLY: 0
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
.idea

reports/
.env
.env.local
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ including automated scripts that apply checks to live proposals to allow
for better informed voting.


# Reports
## Reports

Find the reports [here](https://github.com/Uniswap/governance-seatbelt/tree/reports)
Find the reports [here](https://github.com/Uniswap/governance-seatbelt/tree/reports) when run in CI, or in the `reports` folder if running locally

## Development

Create a file called `.env` with the following environment variables:

```sh
# URL to your node, e.g. Infura or Alchemy endpoint
RPC_URL=yourNodeUrl

# Etherscan API key: https://etherscan.io/myapikey
ETHERSCAN_API_KEY=yourEtherscanApiKey

# Name of the DAO to check
DAO_NAME=Compound

# Address of that DAO's governor contract
GOVERNOR_ADDRESS=0xc0Da02939E1441F497fd74F78cE7Decb17B66529

# Set to 1 if running locally, or 0 for CI
RUNNING_LOCALLY=1
```

Other environment variables needed for CI can be found in `.github/workflows/governance-checks.yaml`
66 changes: 39 additions & 27 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
require('dotenv').config()
import fs from 'fs';
import {
DAO_NAME,
GITHUB_REPO_NAME,
GITHUB_REPO_OWNER,
GOVERNOR_ADDRESS,
REPORTS_BRANCH,
RUNNING_LOCALLY
} from "./utils/constants";
import { github } from "./utils/clients/github";
import { governorBravo } from "./utils/contracts/governor-bravo";
import { provider } from "./utils/clients/ethers";
import { AllCheckResults, Proposal } from "./types";
Expand All @@ -32,6 +34,7 @@ async function main() {
.map((proposal) => proposal.args as unknown as Proposal);

for (const proposal of activeProposals) {
console.log(`Checking proposal ${proposal.id}...`);
const checkResults: AllCheckResults = Object.fromEntries(
await Promise.all(
Object.keys(ALL_CHECKS).map(async (checkId) => [
Expand All @@ -56,37 +59,46 @@ async function main() {
: null,
]);

let sha: string | undefined;
try {
const { data } = await github.rest.repos.getContent({
const report = toProposalReport(
{ start: startBlock, end: endBlock, current: latestBlock },
proposal,
checkResults
);

if (RUNNING_LOCALLY) {
// Running locally, dump to file
const dir = `./reports/${DAO_NAME}/${GOVERNOR_ADDRESS}/`; // TODO more robust way to keep this in sync with `path`
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(`${dir}/${proposal.id}.md`, report);

} else {
// Running in CI, save to file on REPORTS_BRANCH
const { github } = await import("./utils/clients/github"); // lazy load to avoid errors about missing env vars when not in CI
let sha: string | undefined;
try {
const { data } = await github.rest.repos.getContent({
owner: GITHUB_REPO_OWNER,
repo: GITHUB_REPO_NAME,
ref: REPORTS_BRANCH,
path,
});
if ("sha" in data) {
sha = data.sha;
}
} catch (error) {
console.warn("Failed to get sha for file at path", path, error);
}

await github.rest.repos.createOrUpdateFileContents({
owner: GITHUB_REPO_OWNER,
repo: GITHUB_REPO_NAME,
ref: REPORTS_BRANCH,
branch: REPORTS_BRANCH,
message: `Update ${path} as of ${formattedDateTime}`,
content: Buffer.from(report, "utf-8").toString("base64"),
path,
sha,
});
if ("sha" in data) {
sha = data.sha;
}
} catch (error) {
console.warn("Failed to get sha for file at path", path, error);
}

await github.rest.repos.createOrUpdateFileContents({
owner: GITHUB_REPO_OWNER,
repo: GITHUB_REPO_NAME,
branch: REPORTS_BRANCH,
message: `Update ${path} as of ${formattedDateTime}`,
content: Buffer.from(
toProposalReport(
{ start: startBlock, end: endBlock, current: latestBlock },
proposal,
checkResults
),
"utf-8"
).toString("base64"),
path,
sha,
});
} catch (error) {
console.error("Failed to update file contents", error);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@ethercast/etherscan-client": "^1.0.1",
"@octokit/action": "^3.15.2",
"@types/node": "^16.7.13",
"dotenv": "^10.0.0",
"ethers": "^5.4.6",
"ts-node": "^10.2.1",
"typescript": "^4.4.2"
Expand Down
4 changes: 2 additions & 2 deletions utils/clients/ethers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { providers } from "ethers";
import { INFURA_API_KEY } from "../constants";
import { RPC_URL } from "../constants";

export const provider = new providers.InfuraProvider(1, INFURA_API_KEY);
export const provider = new providers.JsonRpcProvider(RPC_URL);
3 changes: 2 additions & 1 deletion utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export const REPOSITORY: string = process.env.GITHUB_REPOSITORY!;
export const [GITHUB_REPO_OWNER, GITHUB_REPO_NAME] =
typeof REPOSITORY === "string" ? REPOSITORY.split("/") : [];
export const GOVERNOR_ADDRESS: string = process.env.GOVERNOR_ADDRESS!;
export const INFURA_API_KEY: string = process.env.INFURA_API_KEY!;
export const RPC_URL: string = process.env.RPC_URL!;
export const ETHERSCAN_API_KEY: string = process.env.ETHERSCAN_API_KEY!;
export const DAO_NAME: string = process.env.DAO_NAME!;
export const REPORTS_BRANCH = "reports";
export const RUNNING_LOCALLY = Boolean(process.env.RUNNING_LOCALLY) // use 1 or 0 because Boolean('false') = true
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,11 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==

dotenv@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==

[email protected]:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
Expand Down

0 comments on commit adb959d

Please sign in to comment.