dexe-mcp 0.5.8 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +707 -536
  2. package/README.md +291 -270
  3. package/SECURITY.md +100 -46
  4. package/dist/config.d.ts +19 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +79 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/governor/adapter.d.ts +90 -0
  9. package/dist/governor/adapter.d.ts.map +1 -0
  10. package/dist/governor/adapter.js +169 -0
  11. package/dist/governor/adapter.js.map +1 -0
  12. package/dist/governor/configs/compound.json +32 -0
  13. package/dist/governor/configs/optimism.json +28 -0
  14. package/dist/governor/configs/uniswap.json +32 -0
  15. package/dist/governor/encoder.d.ts +59 -0
  16. package/dist/governor/encoder.d.ts.map +1 -0
  17. package/dist/governor/encoder.js +290 -0
  18. package/dist/governor/encoder.js.map +1 -0
  19. package/dist/governor/index.d.ts +11 -0
  20. package/dist/governor/index.d.ts.map +1 -0
  21. package/dist/governor/index.js +20 -0
  22. package/dist/governor/index.js.map +1 -0
  23. package/dist/governor/loader.d.ts +42 -0
  24. package/dist/governor/loader.d.ts.map +1 -0
  25. package/dist/governor/loader.js +103 -0
  26. package/dist/governor/loader.js.map +1 -0
  27. package/dist/governor/tally.d.ts +48 -0
  28. package/dist/governor/tally.d.ts.map +1 -0
  29. package/dist/governor/tally.js +103 -0
  30. package/dist/governor/tally.js.map +1 -0
  31. package/dist/governor/tools/build.d.ts +3 -0
  32. package/dist/governor/tools/build.d.ts.map +1 -0
  33. package/dist/governor/tools/build.js +137 -0
  34. package/dist/governor/tools/build.js.map +1 -0
  35. package/dist/governor/tools/extras.d.ts +4 -0
  36. package/dist/governor/tools/extras.d.ts.map +1 -0
  37. package/dist/governor/tools/extras.js +197 -0
  38. package/dist/governor/tools/extras.js.map +1 -0
  39. package/dist/governor/tools/read.d.ts +4 -0
  40. package/dist/governor/tools/read.d.ts.map +1 -0
  41. package/dist/governor/tools/read.js +174 -0
  42. package/dist/governor/tools/read.js.map +1 -0
  43. package/dist/governor/tools/simulate.d.ts +6 -0
  44. package/dist/governor/tools/simulate.d.ts.map +1 -0
  45. package/dist/governor/tools/simulate.js +191 -0
  46. package/dist/governor/tools/simulate.js.map +1 -0
  47. package/dist/lib/broadcastGuards.d.ts +41 -0
  48. package/dist/lib/broadcastGuards.d.ts.map +1 -0
  49. package/dist/lib/broadcastGuards.js +85 -0
  50. package/dist/lib/broadcastGuards.js.map +1 -0
  51. package/dist/lib/ethersProvider.d.ts +96 -0
  52. package/dist/lib/ethersProvider.d.ts.map +1 -0
  53. package/dist/lib/ethersProvider.js +170 -0
  54. package/dist/lib/ethersProvider.js.map +1 -0
  55. package/dist/lib/signer.d.ts +2 -0
  56. package/dist/lib/signer.d.ts.map +1 -1
  57. package/dist/lib/signer.js +4 -0
  58. package/dist/lib/signer.js.map +1 -1
  59. package/dist/lib/walletconnect.d.ts +62 -0
  60. package/dist/lib/walletconnect.d.ts.map +1 -0
  61. package/dist/lib/walletconnect.js +184 -0
  62. package/dist/lib/walletconnect.js.map +1 -0
  63. package/dist/tools/flow.d.ts.map +1 -1
  64. package/dist/tools/flow.js +13 -0
  65. package/dist/tools/flow.js.map +1 -1
  66. package/dist/tools/getConfig.d.ts.map +1 -1
  67. package/dist/tools/getConfig.js +27 -0
  68. package/dist/tools/getConfig.js.map +1 -1
  69. package/dist/tools/inbox.js +8 -8
  70. package/dist/tools/index.d.ts.map +1 -1
  71. package/dist/tools/index.js +11 -1
  72. package/dist/tools/index.js.map +1 -1
  73. package/dist/tools/predict.js +17 -17
  74. package/dist/tools/safe.d.ts +5 -0
  75. package/dist/tools/safe.d.ts.map +1 -0
  76. package/dist/tools/safe.js +264 -0
  77. package/dist/tools/safe.js.map +1 -0
  78. package/dist/tools/simulate.d.ts +7 -0
  79. package/dist/tools/simulate.d.ts.map +1 -1
  80. package/dist/tools/simulate.js +8 -0
  81. package/dist/tools/simulate.js.map +1 -1
  82. package/dist/tools/subgraph.js +162 -162
  83. package/dist/tools/txSend.d.ts +2 -1
  84. package/dist/tools/txSend.d.ts.map +1 -1
  85. package/dist/tools/txSend.js +111 -3
  86. package/dist/tools/txSend.js.map +1 -1
  87. package/dist/tools/walletconnectStatus.d.ts +18 -0
  88. package/dist/tools/walletconnectStatus.d.ts.map +1 -0
  89. package/dist/tools/walletconnectStatus.js +132 -0
  90. package/dist/tools/walletconnectStatus.js.map +1 -0
  91. package/package.json +96 -92
package/SECURITY.md CHANGED
@@ -1,46 +1,100 @@
1
- # Security Policy
2
-
3
- ## Supported Versions
4
-
5
- Only the latest published version on npm receives security updates. Pin to the latest minor (`^0.5`) in your MCP client config.
6
-
7
- ## Reporting a Vulnerability
8
-
9
- If you find a vulnerability in `dexe-mcp` whether in the calldata builders, the optional signer (`DEXE_PRIVATE_KEY`), IPFS upload paths, or the Hardhat bridge — please **do not** open a public GitHub issue.
10
-
11
- Email: **edward.arinin@gmail.com**
12
-
13
- Include:
14
-
15
- - A description of the issue and its impact (what an attacker can do, under what conditions).
16
- - A minimal reproduction: the tool call, env vars (redacted), and the resulting behavior.
17
- - Affected version (`dexe-mcp --version` or check `package.json`).
18
- - Suggested mitigation, if you have one.
19
-
20
- You should expect an acknowledgement within 72 hours. A coordinated-disclosure timeline will be agreed before any public advisory is filed.
21
-
22
- ## Scope
23
-
24
- In scope:
25
-
26
- - Calldata-builder tools (`dexe_proposal_build_*`, `dexe_vote_build_*`, `dexe_dao_build_deploy`) that produce calldata that does not match the intended action.
27
- - Signer mode (`dexe_tx_send`, auto-broadcast in `dexe_proposal_create` / `dexe_proposal_vote_and_execute`) leaking or misusing the configured private key.
28
- - IPFS upload paths that exfiltrate non-public data or accept unsafe input.
29
- - Hardhat bridge (`dexe_compile`, `dexe_test`, etc.) executing unintended shell commands.
30
- - Dependency vulnerabilities reachable through `dexe-mcp`'s exposed tool surface.
31
-
32
- Out of scope:
33
-
34
- - Vulnerabilities in the on-chain DeXe Protocol contracts (report at <https://github.com/dexe-network>).
35
- - Issues that require the operator to set obviously unsafe env values (e.g. `DEXE_PRIVATE_KEY=<a key the attacker already controls>`).
36
- - General npm-registry / npm-cli / Node.js issues unrelated to this package.
37
-
38
- ## Threat Model
39
-
40
- `dexe-mcp` runs **locally** alongside an MCP client (Claude Desktop, Claude Code, etc.). It does not bind a network port and does not expose itself to the public internet. The interesting attack surfaces are:
41
-
42
- 1. The operator's private key in signer mode never logged, never sent off-host, only used by `ethers.Wallet` to sign payloads the operator has already approved at the agent level.
43
- 2. Calldata correctness — every `_build_*` tool emits a `TxPayload` the operator can decode (`dexe_decode_calldata`, `dexe_decode_proposal`) and sign-verify before broadcasting.
44
- 3. IPFS pinning credentials — keep `PINATA_JWT` scoped to a project-specific key.
45
-
46
- If you believe any of the above is broken, please report per the process above.
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Only the latest published version on npm receives security updates. Pin to the latest minor (`^0.5`) in your MCP client config.
6
+
7
+ ## Automated security checks
8
+
9
+ The repo runs four GitHub Actions security workflows continuously:
10
+
11
+ - **CI** (`ci.yml`) — typecheck and build on every push to `main` and every pull request, against Node 20 and 22, plus a `verify-lockfile` integrity job. The test step (`vitest`) runs whenever test files are present on the branch; it is currently a no-op via `--passWithNoTests` (the suite lives on `governor-adapter`) and becomes an enforcing gate once those tests merge. Read-only `GITHUB_TOKEN` scope.
12
+ - **Dependency Review** (`dependency-review.yml`) — every PR is checked against the GitHub Advisory Database. Fails the PR check if any added/updated dependency carries a `high` or `critical` CVE, or if it introduces a forbidden license (GPL/AGPL).
13
+ - **OSSF Scorecard** (`scorecard.yml`) — weekly + on push to `main`. Audits branch protection, signed releases, pinned dependencies, token permissions, and a dozen other supply-chain checks. Results uploaded to GitHub code-scanning (SARIF) and published as a public score at `https://api.securityscorecards.dev/projects/github.com/edward-arinin-web-dev/dexe-mcp/badge`.
14
+ - **CodeQL** (`codeql.yml`) — GitHub-native SAST with the `security-extended` query suite. Runs on every PR/main push and weekly. Scans for prototype pollution, command injection, ReDoS, unsafe deserialization, path traversal, and other CWE patterns. Findings land in the repo's Security tab.
15
+
16
+ ## Release provenance
17
+
18
+ Every npm release from `v0.5.9` onwards is published via `.github/workflows/release.yml` with `npm publish --provenance`. The signed attestation links the tarball to the exact git commit and GitHub Actions run that produced it. Verify in three ways:
19
+
20
+ - The npmjs.com page for the package shows a "Provenance" badge with the source repo and workflow run.
21
+ - `npm view dexe-mcp dist.signatures` returns Sigstore signatures.
22
+ - `npm audit signatures` against an installed copy fails if the registry tarball was tampered with.
23
+
24
+ If you ever install a `dexe-mcp` version that lacks a provenance attestation (and is not a pre-`v0.5.9` historical release), treat it as suspect and report.
25
+
26
+ ## Signed release tags
27
+
28
+ Every release tag is GPG-signed by the maintainer, and `release.yml` runs `git verify-tag "$GITHUB_REF_NAME"` **before** the publish step — an unsigned tag, an invalid signature, or a tag signed by an unknown key aborts the release, so a pushed tag can never publish to npm without a valid maintainer signature.
29
+
30
+ To verify a tag yourself after cloning the repo:
31
+
32
+ ```bash
33
+ # Import the maintainer's public key once (key id published alongside releases).
34
+ gpg --recv-keys <MAINTAINER_KEY_ID>
35
+
36
+ # Verify a specific tag — exits non-zero if unsigned or signed by an unknown key.
37
+ git verify-tag v0.5.9
38
+ # Equivalent shorthand:
39
+ git tag -v v0.5.9
40
+ ```
41
+
42
+ A clean `gpg: Good signature from "<maintainer>"` line is the only acceptable result. `error: ... no signature found` (unsigned) or `Can't check signature: No public key` (unknown signer) means do not trust the tag.
43
+
44
+ ## Reporting a Vulnerability
45
+
46
+ If you find a vulnerability in `dexe-mcp` — whether in the calldata builders, the optional signer (`DEXE_PRIVATE_KEY`), IPFS upload paths, or the Hardhat bridge — please **do not** open a public GitHub issue.
47
+
48
+ Email: **edward.arinin@gmail.com**
49
+
50
+ Include:
51
+
52
+ - A description of the issue and its impact (what an attacker can do, under what conditions).
53
+ - A minimal reproduction: the tool call, env vars (redacted), and the resulting behavior.
54
+ - Affected version (`dexe-mcp --version` or check `package.json`).
55
+ - Suggested mitigation, if you have one.
56
+
57
+ You should expect an acknowledgement within 72 hours. A coordinated-disclosure timeline will be agreed before any public advisory is filed.
58
+
59
+ ## Scope
60
+
61
+ In scope:
62
+
63
+ - Calldata-builder tools (`dexe_proposal_build_*`, `dexe_vote_build_*`, `dexe_dao_build_deploy`) that produce calldata that does not match the intended action.
64
+ - Signer mode (`dexe_tx_send`, auto-broadcast in `dexe_proposal_create` / `dexe_proposal_vote_and_execute`) leaking or misusing the configured private key.
65
+ - IPFS upload paths that exfiltrate non-public data or accept unsafe input.
66
+ - Hardhat bridge (`dexe_compile`, `dexe_test`, etc.) executing unintended shell commands.
67
+ - Dependency vulnerabilities reachable through `dexe-mcp`'s exposed tool surface.
68
+
69
+ Out of scope:
70
+
71
+ - Vulnerabilities in the on-chain DeXe Protocol contracts (report at <https://github.com/dexe-network>).
72
+ - Issues that require the operator to set obviously unsafe env values (e.g. `DEXE_PRIVATE_KEY=<a key the attacker already controls>`).
73
+ - General npm-registry / npm-cli / Node.js issues unrelated to this package.
74
+
75
+ ## Threat Model
76
+
77
+ `dexe-mcp` runs **locally** alongside an MCP client (Claude Desktop, Claude Code, etc.). It does not bind a network port and does not expose itself to the public internet. The interesting attack surfaces are:
78
+
79
+ 1. The operator's private key in signer mode — never logged, never sent off-host, only used by `ethers.Wallet` to sign payloads the operator has already approved at the agent level.
80
+ 2. Calldata correctness — every `_build_*` tool emits a `TxPayload` the operator can decode (`dexe_decode_calldata`, `dexe_decode_proposal`) and sign-verify before broadcasting.
81
+ 3. IPFS pinning credentials — keep `PINATA_JWT` scoped to a project-specific key.
82
+
83
+ If you believe any of the above is broken, please report per the process above.
84
+
85
+ ## Signer broadcast guards
86
+
87
+ When signer mode is enabled (`DEXE_PRIVATE_KEY`), `dexe_tx_send` runs four opt-in guards before broadcasting (`src/lib/broadcastGuards.ts`). They narrow the blast radius of a compromised or runaway MCP host — the host can still *call* the tool, but cannot send to arbitrary destinations, drain arbitrary value, pay gas for reverting txs, or loop unbounded. Each is a no-op unless its env var is set; a failed guard returns `{ status: "rejected", guard, reason }` with **no gas spent**.
88
+
89
+ | Guard | Env var | What it blocks |
90
+ |-------|---------|----------------|
91
+ | **B6** destination allowlist | `DEXE_SIGNER_ALLOWLIST` | Broadcasts to any `to` not on the comma-separated list. |
92
+ | **B7** value cap | `DEXE_SIGNER_MAX_VALUE_WEI` | Broadcasts whose `value` (wei) exceeds the cap. |
93
+ | **B9** auto-simulation | _(always on in signer mode)_ | Doomed txs — `eth_call` preflight aborts with the decoded revert reason before gas is spent. |
94
+ | **B10** rate limit | `DEXE_SIGNER_MAX_BROADCASTS_PER_MIN` | More than N broadcasts in a rolling 60s window. |
95
+
96
+ These are defense-in-depth, **not** a substitute for keeping the key off-host. For prod governance/treasury actions, prefer calldata mode + Safe Multisig / Ledger. See `docs/ENVIRONMENT.md` §4 for the recommended config block.
97
+
98
+ ## WalletConnect signer mode (C12)
99
+
100
+ `signerMode: walletconnect` (activated by `DEXE_WALLETCONNECT_PROJECT_ID` when **no** `DEXE_PRIVATE_KEY` is set) removes the hot key from the threat model entirely: the signing key never leaves the operator's phone wallet, and **every** transaction is gated by an explicit per-tx approval on that device. The MCP process holds only a relay session, never key material. The broadcast guards above (B6/B7/B9/B10) still run on the `tx` *before* it is forwarded to the relay — the phone approval is an **additional** human gate, not a replacement. A hard approval timeout (`DEXE_WALLETCONNECT_APPROVAL_TIMEOUT_MS`, default 120 s) bounds how long a request can block. Phase A (current) ships config + the read-only `dexe_wc_status` tool only — no relay connection, no new dependency. The live session lands in v0.6.0. See `docs/WALLETCONNECT.md`.
package/dist/config.d.ts CHANGED
@@ -34,6 +34,25 @@ export interface DexeConfig {
34
34
  forkBlock?: number;
35
35
  /** Private key for tx signing. When set, `dexe_tx_send` can broadcast. */
36
36
  privateKey?: string;
37
+ /**
38
+ * B6 — destination allowlist for `dexe_tx_send`. Lowercased, checksummed-then-
39
+ * lowercased addresses. Undefined/empty = no restriction.
40
+ */
41
+ signerAllowlist?: string[];
42
+ /** B7 — max wei value per broadcast. Undefined = no cap. */
43
+ signerMaxValueWei?: bigint;
44
+ /** B10 — max broadcasts per rolling minute. Undefined = no limit. */
45
+ signerMaxBroadcastsPerMin?: number;
46
+ /**
47
+ * C12 — WalletConnect project id (Reown cloud.reown.com). When set and
48
+ * `privateKey` is absent, `signerMode` resolves to `walletconnect`: broadcast
49
+ * convenience without a hot key (every tx approved on the operator's phone).
50
+ */
51
+ walletConnectProjectId?: string;
52
+ /** C12 — relay websocket override. Default `wss://relay.walletconnect.com`. */
53
+ walletConnectRelayUrl?: string;
54
+ /** C12 — per-tx phone-approval timeout in ms. Default 120000. */
55
+ walletConnectApprovalTimeoutMs?: number;
37
56
  }
38
57
  /**
39
58
  * Reads environment and returns a frozen config. **Fast and side-effect-free**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IAErB,uEAAuE;IACvE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzC;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CA4ItD;AAcD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,CAW9E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IAErB,uEAAuE;IACvE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzC;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,+EAA+E;IAC/E,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CA+NtD;AAcD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,CAW9E"}
package/dist/config.js CHANGED
@@ -34,6 +34,20 @@ export async function loadConfig() {
34
34
  if (rpcMainnet) {
35
35
  chains.set(56, { chainId: 56, rpcUrl: rpcMainnet });
36
36
  }
37
+ // Generic per-chain RPC: DEXE_RPC_URL_<chainId> (e.g. DEXE_RPC_URL_1,
38
+ // DEXE_RPC_URL_10). Enables chains beyond BSC — notably the external
39
+ // Governor DAOs, which live on Ethereum (1) and Optimism (10). The numeric
40
+ // suffix never collides with the named *_TESTNET / *_MAINNET vars above.
41
+ for (const [key, val] of Object.entries(process.env)) {
42
+ const m = /^DEXE_RPC_URL_(\d+)$/.exec(key);
43
+ if (!m)
44
+ continue;
45
+ const url = val?.trim();
46
+ if (!url)
47
+ continue;
48
+ const cid = Number(m[1]);
49
+ chains.set(cid, { chainId: cid, rpcUrl: url });
50
+ }
37
51
  // Legacy single-chain env (still supported)
38
52
  const legacyRpc = process.env.DEXE_RPC_URL?.trim() || undefined;
39
53
  let legacyChainId;
@@ -106,6 +120,65 @@ export async function loadConfig() {
106
120
  const addr = new Wallet(privateKey).address;
107
121
  process.stderr.write(`[dexe-mcp] signing enabled for ${addr}\n`);
108
122
  }
123
+ // ---- signer broadcast guard B6 (destination allowlist) -----------------
124
+ // Opt-in; only meaningful in signer mode. Parses to undefined when unset,
125
+ // leaving the default posture unchanged.
126
+ let signerAllowlist;
127
+ const allowlistRaw = process.env.DEXE_SIGNER_ALLOWLIST?.trim();
128
+ if (allowlistRaw) {
129
+ const { isAddress, getAddress } = await import("ethers");
130
+ const normalized = [];
131
+ for (const entry of allowlistRaw.split(",").map(s => s.trim()).filter(Boolean)) {
132
+ if (!isAddress(entry)) {
133
+ fatal(`DEXE_SIGNER_ALLOWLIST contains an invalid address: ${entry}`);
134
+ }
135
+ normalized.push(getAddress(entry).toLowerCase());
136
+ }
137
+ if (normalized.length > 0)
138
+ signerAllowlist = normalized;
139
+ }
140
+ // ---- signer broadcast guard B7 (value cap) -----------------------------
141
+ let signerMaxValueWei;
142
+ const maxValueRaw = process.env.DEXE_SIGNER_MAX_VALUE_WEI?.trim();
143
+ if (maxValueRaw) {
144
+ let parsed;
145
+ try {
146
+ parsed = BigInt(maxValueRaw);
147
+ }
148
+ catch {
149
+ fatal(`DEXE_SIGNER_MAX_VALUE_WEI must be a non-negative integer (wei), got: ${maxValueRaw}`);
150
+ }
151
+ if (parsed < 0n) {
152
+ fatal(`DEXE_SIGNER_MAX_VALUE_WEI must be a non-negative integer (wei), got: ${maxValueRaw}`);
153
+ }
154
+ signerMaxValueWei = parsed;
155
+ }
156
+ // ---- signer broadcast guard B10 (rate limit) ---------------------------
157
+ let signerMaxBroadcastsPerMin;
158
+ const maxBroadcastsRaw = process.env.DEXE_SIGNER_MAX_BROADCASTS_PER_MIN?.trim();
159
+ if (maxBroadcastsRaw) {
160
+ const n = Number(maxBroadcastsRaw);
161
+ if (!Number.isInteger(n) || n <= 0) {
162
+ fatal(`DEXE_SIGNER_MAX_BROADCASTS_PER_MIN must be a positive integer, got: ${maxBroadcastsRaw}`);
163
+ }
164
+ signerMaxBroadcastsPerMin = n;
165
+ }
166
+ // ---- C12 WalletConnect signer mode ------------------------------------
167
+ // Phase A: parse + expose config only. No relay connection, no dependency.
168
+ const walletConnectProjectId = process.env.DEXE_WALLETCONNECT_PROJECT_ID?.trim() || undefined;
169
+ const walletConnectRelayUrl = process.env.DEXE_WALLETCONNECT_RELAY_URL?.trim() || "wss://relay.walletconnect.com";
170
+ let walletConnectApprovalTimeoutMs = 120000;
171
+ const wcTimeoutRaw = process.env.DEXE_WALLETCONNECT_APPROVAL_TIMEOUT_MS?.trim();
172
+ if (wcTimeoutRaw) {
173
+ const n = Number(wcTimeoutRaw);
174
+ if (!Number.isInteger(n) || n <= 0) {
175
+ fatal(`DEXE_WALLETCONNECT_APPROVAL_TIMEOUT_MS must be a positive integer (ms), got: ${wcTimeoutRaw}`);
176
+ }
177
+ walletConnectApprovalTimeoutMs = n;
178
+ }
179
+ if (walletConnectProjectId) {
180
+ process.stderr.write(`[dexe-mcp] WalletConnect project id configured${privateKey ? " (inactive — DEXE_PRIVATE_KEY takes precedence)" : ""}\n`);
181
+ }
109
182
  let forkBlock;
110
183
  if (process.env.DEXE_FORK_BLOCK) {
111
184
  const n = Number(process.env.DEXE_FORK_BLOCK);
@@ -128,6 +201,12 @@ export async function loadConfig() {
128
201
  subgraphInteractionsUrl,
129
202
  forkBlock,
130
203
  privateKey,
204
+ signerAllowlist,
205
+ signerMaxValueWei,
206
+ signerMaxBroadcastsPerMin,
207
+ walletConnectProjectId,
208
+ walletConnectRelayUrl,
209
+ walletConnectApprovalTimeoutMs,
131
210
  });
132
211
  }
133
212
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ import { Contract, type JsonRpcProvider } from "ethers";
2
+ import type { GovernorConfig } from "./loader.js";
3
+ /**
4
+ * Read surfaces for the two Governor families we target.
5
+ *
6
+ * - **OZ v4 / v5** (Optimism, post-2022 OZ Governor deploys): `state`,
7
+ * `proposalSnapshot`, `proposalDeadline`, `proposalVotes`, `quorum(uint256)`,
8
+ * `proposalThreshold`, etc.
9
+ * - **Bravo v3** (Uniswap, Compound): `state`, `proposals(uint256)` returning a
10
+ * flat struct, `quorumVotes()` (fixed quorum, no per-block snapshot),
11
+ * `proposalThreshold`. No `proposalSnapshot` / `proposalDeadline` /
12
+ * `quorum(blockNumber)`.
13
+ *
14
+ * The canonical `ProposalState` enum order is identical across both families.
15
+ */
16
+ export declare const GOVERNOR_OZ_READ_ABI: readonly ["function state(uint256 proposalId) view returns (uint8)", "function proposalSnapshot(uint256 proposalId) view returns (uint256)", "function proposalDeadline(uint256 proposalId) view returns (uint256)", "function proposalVotes(uint256 proposalId) view returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes)", "function proposalThreshold() view returns (uint256)", "function quorum(uint256 blockNumber) view returns (uint256)", "function votingDelay() view returns (uint256)", "function votingPeriod() view returns (uint256)", "function hasVoted(uint256 proposalId, address account) view returns (bool)", "function hashProposal(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) pure returns (uint256)", "function name() view returns (string)", "function version() view returns (string)"];
17
+ export declare const GOVERNOR_BRAVO_READ_ABI: readonly ["function state(uint256 proposalId) view returns (uint8)", "function proposals(uint256 proposalId) view returns (uint256 id, address proposer, uint256 eta, uint256 startBlock, uint256 endBlock, uint256 forVotes, uint256 againstVotes, uint256 abstainVotes, bool canceled, bool executed)", "function proposalThreshold() view returns (uint256)", "function quorumVotes() view returns (uint256)", "function votingDelay() view returns (uint256)", "function votingPeriod() view returns (uint256)", "function hasVoted(uint256 proposalId, address account) view returns (bool)", "function name() view returns (string)"];
18
+ export declare const IVOTES_ABI: readonly ["function getVotes(address account) view returns (uint256)", "function getPastVotes(address account, uint256 blockNumber) view returns (uint256)", "function delegates(address account) view returns (address)"];
19
+ /**
20
+ * Compound-style vote getters. Bravo voting tokens (COMP, UNI) expose
21
+ * `getCurrentVotes(address)` / `getPriorVotes(address, uint256)` instead of the
22
+ * OZ `getVotes` / `getPastVotes`. Routing is static by `votingToken.type`
23
+ * (see `readVotingPower`) — `ERC20VotesComp` always uses these getters; there is
24
+ * no runtime fallback between the two interfaces.
25
+ */
26
+ export declare const IVOTES_COMP_ABI: readonly ["function getCurrentVotes(address account) view returns (uint96)", "function getPriorVotes(address account, uint256 blockNumber) view returns (uint96)", "function delegates(address account) view returns (address)"];
27
+ export declare const PROPOSAL_STATE: readonly string[];
28
+ export declare function stateName(stateIndex: number): string;
29
+ export declare function isBravo(cfg: GovernorConfig): boolean;
30
+ export declare function governorContract(provider: JsonRpcProvider, cfg: GovernorConfig): Contract;
31
+ export declare function votesContract(provider: JsonRpcProvider, cfg: GovernorConfig): Contract;
32
+ /**
33
+ * Family-agnostic voting-power read. ERC20VotesComp (UNI, COMP) exposes
34
+ * `getCurrentVotes` / `getPriorVotes`; ERC20Votes (OP, modern OZ) exposes
35
+ * `getVotes` / `getPastVotes`. Returns wei + the actual method invoked.
36
+ */
37
+ export declare function readVotingPower(c: Contract, cfg: GovernorConfig, account: string, blockNumber: number | undefined): Promise<{
38
+ power: bigint;
39
+ method: string;
40
+ }>;
41
+ export interface ProposalReadout {
42
+ state: {
43
+ index: number;
44
+ name: string;
45
+ };
46
+ snapshotBlock: string;
47
+ deadlineBlock: string;
48
+ votes: {
49
+ against: string;
50
+ for: string;
51
+ abstain: string;
52
+ };
53
+ bravoExtra?: {
54
+ proposer: string;
55
+ eta: string;
56
+ canceled: boolean;
57
+ executed: boolean;
58
+ };
59
+ }
60
+ /**
61
+ * Family-agnostic proposal read. Maps Bravo's `proposals(uint256)` struct onto
62
+ * the OZ-style {snapshot, deadline, votes} shape so callers don't branch.
63
+ */
64
+ export declare function readProposal(c: Contract, cfg: GovernorConfig, proposalId: bigint): Promise<ProposalReadout>;
65
+ /**
66
+ * Returns the active quorum value. For OZ v4+ this is `quorum(blockNumber)`;
67
+ * for Bravo it's the fixed `quorumVotes()` (blockNumber is ignored, surfaced
68
+ * as `latest` in the response).
69
+ */
70
+ export declare function readQuorum(c: Contract, cfg: GovernorConfig, blockNumber: number): Promise<{
71
+ quorum: bigint;
72
+ method: "quorum(blockNumber)" | "quorumVotes()";
73
+ }>;
74
+ export interface VoteTally {
75
+ against: bigint;
76
+ for: bigint;
77
+ abstain: bigint;
78
+ }
79
+ /**
80
+ * Pure projection of a hypothetical vote onto current tallies. Quorum semantics
81
+ * branch by family: OZ `GovernorCountingSimple` counts `for + abstain` toward
82
+ * quorum, Bravo counts only `forVotes`. `willPass` requires quorum met AND
83
+ * strictly more For than Against. No I/O — unit-testable in isolation.
84
+ */
85
+ export declare function projectVoteImpact(bravo: boolean, current: VoteTally, support: number, weight: bigint, quorum: bigint): {
86
+ projected: VoteTally;
87
+ quorumMet: boolean;
88
+ willPass: boolean;
89
+ };
90
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/governor/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,oBAAoB,60BAavB,CAAC;AAEX,eAAO,MAAM,uBAAuB,6mBAS1B,CAAC;AAEX,eAAO,MAAM,UAAU,4NAIb,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,kOAIlB,CAAC;AAEX,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EASlC,CAAC;AAEX,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,QAAQ,CAGzF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,QAAQ,CAGtF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,CAAC,EAAE,QAAQ,EACX,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAU5C;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,CAAC,EAAE,QAAQ,EACX,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAoC1B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,CAAC,EAAE,QAAQ,EACX,GAAG,EAAE,cAAc,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAAA;CAAE,CAAC,CAO9E;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAUjE"}
@@ -0,0 +1,169 @@
1
+ import { Contract } from "ethers";
2
+ /**
3
+ * Read surfaces for the two Governor families we target.
4
+ *
5
+ * - **OZ v4 / v5** (Optimism, post-2022 OZ Governor deploys): `state`,
6
+ * `proposalSnapshot`, `proposalDeadline`, `proposalVotes`, `quorum(uint256)`,
7
+ * `proposalThreshold`, etc.
8
+ * - **Bravo v3** (Uniswap, Compound): `state`, `proposals(uint256)` returning a
9
+ * flat struct, `quorumVotes()` (fixed quorum, no per-block snapshot),
10
+ * `proposalThreshold`. No `proposalSnapshot` / `proposalDeadline` /
11
+ * `quorum(blockNumber)`.
12
+ *
13
+ * The canonical `ProposalState` enum order is identical across both families.
14
+ */
15
+ export const GOVERNOR_OZ_READ_ABI = [
16
+ "function state(uint256 proposalId) view returns (uint8)",
17
+ "function proposalSnapshot(uint256 proposalId) view returns (uint256)",
18
+ "function proposalDeadline(uint256 proposalId) view returns (uint256)",
19
+ "function proposalVotes(uint256 proposalId) view returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes)",
20
+ "function proposalThreshold() view returns (uint256)",
21
+ "function quorum(uint256 blockNumber) view returns (uint256)",
22
+ "function votingDelay() view returns (uint256)",
23
+ "function votingPeriod() view returns (uint256)",
24
+ "function hasVoted(uint256 proposalId, address account) view returns (bool)",
25
+ "function hashProposal(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) pure returns (uint256)",
26
+ "function name() view returns (string)",
27
+ "function version() view returns (string)",
28
+ ];
29
+ export const GOVERNOR_BRAVO_READ_ABI = [
30
+ "function state(uint256 proposalId) view returns (uint8)",
31
+ "function proposals(uint256 proposalId) view returns (uint256 id, address proposer, uint256 eta, uint256 startBlock, uint256 endBlock, uint256 forVotes, uint256 againstVotes, uint256 abstainVotes, bool canceled, bool executed)",
32
+ "function proposalThreshold() view returns (uint256)",
33
+ "function quorumVotes() view returns (uint256)",
34
+ "function votingDelay() view returns (uint256)",
35
+ "function votingPeriod() view returns (uint256)",
36
+ "function hasVoted(uint256 proposalId, address account) view returns (bool)",
37
+ "function name() view returns (string)",
38
+ ];
39
+ export const IVOTES_ABI = [
40
+ "function getVotes(address account) view returns (uint256)",
41
+ "function getPastVotes(address account, uint256 blockNumber) view returns (uint256)",
42
+ "function delegates(address account) view returns (address)",
43
+ ];
44
+ /**
45
+ * Compound-style vote getters. Bravo voting tokens (COMP, UNI) expose
46
+ * `getCurrentVotes(address)` / `getPriorVotes(address, uint256)` instead of the
47
+ * OZ `getVotes` / `getPastVotes`. Routing is static by `votingToken.type`
48
+ * (see `readVotingPower`) — `ERC20VotesComp` always uses these getters; there is
49
+ * no runtime fallback between the two interfaces.
50
+ */
51
+ export const IVOTES_COMP_ABI = [
52
+ "function getCurrentVotes(address account) view returns (uint96)",
53
+ "function getPriorVotes(address account, uint256 blockNumber) view returns (uint96)",
54
+ "function delegates(address account) view returns (address)",
55
+ ];
56
+ export const PROPOSAL_STATE = [
57
+ "Pending",
58
+ "Active",
59
+ "Canceled",
60
+ "Defeated",
61
+ "Succeeded",
62
+ "Queued",
63
+ "Expired",
64
+ "Executed",
65
+ ];
66
+ export function stateName(stateIndex) {
67
+ return PROPOSAL_STATE[stateIndex] ?? `Unknown(${stateIndex})`;
68
+ }
69
+ export function isBravo(cfg) {
70
+ return cfg.governorVersion === "bravo-v3";
71
+ }
72
+ export function governorContract(provider, cfg) {
73
+ const abi = isBravo(cfg) ? GOVERNOR_BRAVO_READ_ABI : GOVERNOR_OZ_READ_ABI;
74
+ return new Contract(cfg.governorAddress, abi, provider);
75
+ }
76
+ export function votesContract(provider, cfg) {
77
+ const abi = cfg.votingToken.type === "ERC20VotesComp" ? IVOTES_COMP_ABI : IVOTES_ABI;
78
+ return new Contract(cfg.votingToken.address, abi, provider);
79
+ }
80
+ /**
81
+ * Family-agnostic voting-power read. ERC20VotesComp (UNI, COMP) exposes
82
+ * `getCurrentVotes` / `getPriorVotes`; ERC20Votes (OP, modern OZ) exposes
83
+ * `getVotes` / `getPastVotes`. Returns wei + the actual method invoked.
84
+ */
85
+ export async function readVotingPower(c, cfg, account, blockNumber) {
86
+ const isComp = cfg.votingToken.type === "ERC20VotesComp";
87
+ if (blockNumber === undefined) {
88
+ const method = isComp ? "getCurrentVotes" : "getVotes";
89
+ const power = await c.getFunction(method).staticCall(account);
90
+ return { power, method };
91
+ }
92
+ const method = isComp ? "getPriorVotes" : "getPastVotes";
93
+ const power = await c.getFunction(method).staticCall(account, blockNumber);
94
+ return { power, method };
95
+ }
96
+ /**
97
+ * Family-agnostic proposal read. Maps Bravo's `proposals(uint256)` struct onto
98
+ * the OZ-style {snapshot, deadline, votes} shape so callers don't branch.
99
+ */
100
+ export async function readProposal(c, cfg, proposalId) {
101
+ const stateIdx = Number(await c.getFunction("state").staticCall(proposalId));
102
+ if (isBravo(cfg)) {
103
+ const p = await c.getFunction("proposals").staticCall(proposalId);
104
+ return {
105
+ state: { index: stateIdx, name: stateName(stateIdx) },
106
+ snapshotBlock: p.startBlock.toString(),
107
+ deadlineBlock: p.endBlock.toString(),
108
+ votes: {
109
+ against: p.againstVotes.toString(),
110
+ for: p.forVotes.toString(),
111
+ abstain: p.abstainVotes.toString(),
112
+ },
113
+ bravoExtra: {
114
+ proposer: p.proposer,
115
+ eta: p.eta.toString(),
116
+ canceled: p.canceled,
117
+ executed: p.executed,
118
+ },
119
+ };
120
+ }
121
+ const [snapshot, deadline, votes] = await Promise.all([
122
+ c.getFunction("proposalSnapshot").staticCall(proposalId),
123
+ c.getFunction("proposalDeadline").staticCall(proposalId),
124
+ c.getFunction("proposalVotes").staticCall(proposalId),
125
+ ]);
126
+ return {
127
+ state: { index: stateIdx, name: stateName(stateIdx) },
128
+ snapshotBlock: snapshot.toString(),
129
+ deadlineBlock: deadline.toString(),
130
+ votes: {
131
+ against: votes[0].toString(),
132
+ for: votes[1].toString(),
133
+ abstain: votes[2].toString(),
134
+ },
135
+ };
136
+ }
137
+ /**
138
+ * Returns the active quorum value. For OZ v4+ this is `quorum(blockNumber)`;
139
+ * for Bravo it's the fixed `quorumVotes()` (blockNumber is ignored, surfaced
140
+ * as `latest` in the response).
141
+ */
142
+ export async function readQuorum(c, cfg, blockNumber) {
143
+ if (isBravo(cfg)) {
144
+ const q = await c.getFunction("quorumVotes").staticCall();
145
+ return { quorum: q, method: "quorumVotes()" };
146
+ }
147
+ const q = await c.getFunction("quorum").staticCall(blockNumber);
148
+ return { quorum: q, method: "quorum(blockNumber)" };
149
+ }
150
+ /**
151
+ * Pure projection of a hypothetical vote onto current tallies. Quorum semantics
152
+ * branch by family: OZ `GovernorCountingSimple` counts `for + abstain` toward
153
+ * quorum, Bravo counts only `forVotes`. `willPass` requires quorum met AND
154
+ * strictly more For than Against. No I/O — unit-testable in isolation.
155
+ */
156
+ export function projectVoteImpact(bravo, current, support, weight, quorum) {
157
+ const projected = { ...current };
158
+ if (support === 0)
159
+ projected.against += weight;
160
+ else if (support === 1)
161
+ projected.for += weight;
162
+ else
163
+ projected.abstain += weight;
164
+ const quorumPool = bravo ? projected.for : projected.for + projected.abstain;
165
+ const quorumMet = quorumPool >= quorum;
166
+ const willPass = quorumMet && projected.for > projected.against;
167
+ return { projected, quorumMet, willPass };
168
+ }
169
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/governor/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ {
2
+ "id": "compound",
3
+ "chainId": 1,
4
+ "governorAddress": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529",
5
+ "governorVersion": "bravo-v3",
6
+ "votingToken": {
7
+ "type": "ERC20VotesComp",
8
+ "address": "0xc00e94Cb662C3520282E6f5717214004A7f26888",
9
+ "symbol": "COMP",
10
+ "decimals": 18
11
+ },
12
+ "timelock": {
13
+ "address": "0x6d903f6003cca6255D85CcA4D3B5E5146dC33925",
14
+ "minDelay": 172800
15
+ },
16
+ "votingParams": {
17
+ "votingDelay": 13140,
18
+ "votingPeriod": 19710,
19
+ "proposalThreshold": "25000000000000000000000",
20
+ "quorumNumerator": 400000,
21
+ "quorumDenominator": 1
22
+ },
23
+ "executor": {
24
+ "type": "timelock",
25
+ "id": null
26
+ },
27
+ "explorer": {
28
+ "etherscanBase": "https://etherscan.io",
29
+ "tallyOrgSlug": "compound"
30
+ },
31
+ "notes": "Compound GovernorBravoDelegate. Bravo signatures, Compound-style votes interface (getPriorVotes / getCurrentVotes — NOT OZ getPastVotes). quorumVotes() is a fixed value (400k COMP); quorumNumerator/Denominator here are descriptive only."
32
+ }