dexe-mcp 0.5.3 → 0.5.7
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.
- package/CHANGELOG.md +149 -0
- package/README.md +24 -18
- package/dist/config.d.ts +27 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +105 -9
- package/dist/config.js.map +1 -1
- package/dist/lib/blacklist.d.ts +22 -0
- package/dist/lib/blacklist.d.ts.map +1 -0
- package/dist/lib/blacklist.js +43 -0
- package/dist/lib/blacklist.js.map +1 -0
- package/dist/lib/signer.d.ts +17 -4
- package/dist/lib/signer.d.ts.map +1 -1
- package/dist/lib/signer.js +33 -16
- package/dist/lib/signer.js.map +1 -1
- package/dist/rpc.d.ts +10 -5
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +18 -10
- package/dist/rpc.js.map +1 -1
- package/dist/tools/daoDeploy.d.ts.map +1 -1
- package/dist/tools/daoDeploy.js +27 -6
- package/dist/tools/daoDeploy.js.map +1 -1
- package/dist/tools/flow.d.ts +3 -0
- package/dist/tools/flow.d.ts.map +1 -1
- package/dist/tools/flow.js +29 -14
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/getConfig.d.ts +10 -0
- package/dist/tools/getConfig.d.ts.map +1 -0
- package/dist/tools/getConfig.js +52 -0
- package/dist/tools/getConfig.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/otc.d.ts.map +1 -1
- package/dist/tools/otc.js +28 -6
- package/dist/tools/otc.js.map +1 -1
- package/dist/tools/proposalBuild.d.ts.map +1 -1
- package/dist/tools/proposalBuild.js +11 -2
- package/dist/tools/proposalBuild.js.map +1 -1
- package/dist/tools/proposalBuildComplex.d.ts.map +1 -1
- package/dist/tools/proposalBuildComplex.js +49 -14
- package/dist/tools/proposalBuildComplex.js.map +1 -1
- package/dist/tools/proposalBuildMore.js +60 -20
- package/dist/tools/proposalBuildMore.js.map +1 -1
- package/dist/tools/proposalBuildOffchain.d.ts.map +1 -1
- package/dist/tools/proposalBuildOffchain.js +26 -15
- package/dist/tools/proposalBuildOffchain.js.map +1 -1
- package/dist/tools/txSend.d.ts +1 -1
- package/dist/tools/txSend.d.ts.map +1 -1
- package/dist/tools/txSend.js +37 -9
- package/dist/tools/txSend.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,154 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.7
|
|
4
|
+
|
|
5
|
+
Last broadcast sweep: **57 / 57 green** on Polaris (BSC testnet 97), 2026-05-12.
|
|
6
|
+
|
|
7
|
+
### Swarm coverage — 41 → 57 scenarios
|
|
8
|
+
|
|
9
|
+
- New broadcast-lifecycle scenarios for the three v0.5.6 builder rewrites: `S52-withdraw-treasury-execute`, `S53-apply-to-dao-execute`, `S54-reward-multiplier-execute`. Each runs the wrapper builder → `dexe_proposal_create` custom flow on the swarm fixture DAO and asserts the proposal lands in Voting / SucceededFor / ExecutedFor. Validates the Bug #29 / #30 / #31 fixes end-to-end against on-chain state, not just calldata shape.
|
|
10
|
+
- New broadcast scenarios for the most-used proposal types: `S55-token-transfer-execute`, `S56-blacklist-execute`, `S57-add-expert-execute`. Same build → create → state pattern.
|
|
11
|
+
- Refreshed `S18-withdraw-treasury-build` to pass the now-required `token` argument; refreshed `S31-reward-multiplier-build` to use Polaris's `nftMultiplier` (replacing retired Glacier address) and PRECISION-scaled multipliers (`1.5x => 1.5e25`) per v0.5.6's stricter validator.
|
|
12
|
+
- Replaced retired Glacier fixture with fresh **Polaris** testnet DAO (LINEAR, 50% quorum, deployed 2026-05-12). Sentinel (validator chamber) unchanged. README updated.
|
|
13
|
+
|
|
14
|
+
### Swarm tooling
|
|
15
|
+
|
|
16
|
+
- **`scripts/swarm/preflight.ts` now counts deposited tokens alongside the wallet balance.** A wallet with funds locked behind in-flight proposals had `ERC20.balanceOf=0` even though its governance power was intact in UserKeeper; the old check aborted nightly runs on a non-issue. Each token row now also reads `UserKeeper.tokenBalance(user, Personal)` from the parallel DAO and adds the deposited surplus to the threshold check. Falls back to wallet-only when the helper call reverts.
|
|
17
|
+
- **`scripts/swarm/nightly.sh` sanitizes the SUMMARY_LINE before posting to public targets.** The orchestrator's machine-greppable summary line ends with the absolute report path, which leaks the operator's filesystem layout when the repo is public. Local stdout still gets the full line; webhook + GitHub-issue posts get a stripped variant (runId + N/M + mode + chainTag, no path).
|
|
18
|
+
|
|
19
|
+
### Multi-chain config (chain-mixup guard)
|
|
20
|
+
|
|
21
|
+
- New optional env vars `DEXE_RPC_URL_TESTNET` + `DEXE_RPC_URL_MAINNET` + `DEXE_DEFAULT_CHAIN_ID`. Configure one or both; the MCP can now route reads and broadcasts to whichever chain a tool call requests, without an MCP restart.
|
|
22
|
+
- Write/composite tools accept an optional `chainId` arg: `dexe_tx_send`, `dexe_tx_status`, `dexe_dao_build_deploy`, `dexe_proposal_create`, `dexe_proposal_vote_and_execute`, `dexe_otc_dao_open_sale`, `dexe_otc_buyer_buy`, `dexe_otc_buyer_claim_all`. Omitting the arg uses the default chain. Requesting a chain with no configured RPC fails fast with a clear error before any tx is built or signed.
|
|
23
|
+
- Legacy `DEXE_RPC_URL` + `DEXE_CHAIN_ID` still works and stacks with the new vars — the legacy entry registers as one more chain in the pool. When `DEXE_CHAIN_ID` is omitted, the chain id is best-effort inferred from the URL hostname.
|
|
24
|
+
- New `dexe_get_config` diagnostic tool: returns the resolved chain set, the default chain, signer status, and IPFS/subgraph configuration. Call it at session start to orient before any write.
|
|
25
|
+
- Provider and signer are now per-chain caches (`RpcProvider`, `SignerManager`) so multi-chain usage doesn't churn through new connections.
|
|
26
|
+
|
|
27
|
+
## 0.5.6
|
|
28
|
+
|
|
29
|
+
Three Stage A mainnet bug fixes — all surfaced on `DexeClientDemo`
|
|
30
|
+
(BSC `0xCAe3…5B41`) and tracked as bugs #29 / #30 / #31.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Bug #30 — `dexe_proposal_build_withdraw_treasury` emitted wrong
|
|
35
|
+
selector.** Builder targeted `GovPool.withdraw(address,uint256,uint256[])`
|
|
36
|
+
(selector `0xfb8c5ef0`), which is the user-deposit-withdraw function on
|
|
37
|
+
GovPool, not a treasury transfer. `proposal_create` rejected it with
|
|
38
|
+
`Gov: invalid internal data`. Rewritten to emit one external
|
|
39
|
+
`ERC20.transfer(receiver, amount)` action per token and/or one
|
|
40
|
+
`ERC721.transferFrom(govPool, receiver, tokenId)` action per NFT —
|
|
41
|
+
treasury sits in the GovPool address as a regular ERC20/721 balance, so
|
|
42
|
+
withdrawal is just a plain external token call. New schema: drop the
|
|
43
|
+
single `(amount, nftIds)` shape; supply `token`+`amount` and/or
|
|
44
|
+
`nftAddress`+`nftIds`. At least one must be non-empty.
|
|
45
|
+
|
|
46
|
+
- **Bug #29 — `apply_to_dao` / `token_transfer` / `withdraw_treasury` had
|
|
47
|
+
no blacklist precheck.** `ERC20Gov.transfer` reverts on a blacklisted
|
|
48
|
+
recipient, and a proposal that passes voting then fails `execute()` sits
|
|
49
|
+
in `SucceededFor` permanently with no recovery. When `DEXE_RPC_URL` is
|
|
50
|
+
set, the three builders now `isBlacklisted(receiver)` against the token
|
|
51
|
+
before encoding and refuse to build with a clear error if the recipient
|
|
52
|
+
is blacklisted. When the token isn't ERC20Gov (call reverts) or RPC is
|
|
53
|
+
absent, the precheck soft-skips with a note in the result detail —
|
|
54
|
+
build always proceeds. New helper: `src/lib/blacklist.ts`.
|
|
55
|
+
|
|
56
|
+
- **Bug #31 — `dexe_proposal_build_reward_multiplier` mint/change_token
|
|
57
|
+
reverted silently.** `ERC721_MULTIPLIER_ABI` declared `duration` as
|
|
58
|
+
`uint256`, but `ERC721Multiplier.mint(address,uint256,uint64,string)`
|
|
59
|
+
uses `uint64`. ethers derives the selector from the canonical signature,
|
|
60
|
+
so the wrong-typed arg produced a different selector → no-match →
|
|
61
|
+
silent revert with no returndata when GovPool.execute called into the
|
|
62
|
+
multiplier (the contract has no `MAX_MULTIPLIER` check, so the original
|
|
63
|
+
scale-mismatch hypothesis was wrong). Fixed the ABI to `uint64
|
|
64
|
+
duration`. Builder now also rejects `multiplier=0`, multiplier values
|
|
65
|
+
below `PRECISION/100` (likely forgot the 1e25 scale), `duration > 2^64
|
|
66
|
+
− 1`, and `duration=0` for mint. Tool description spells out
|
|
67
|
+
`PRECISION = 1e25` and `duration = seconds (uint64)`.
|
|
68
|
+
|
|
69
|
+
## 0.5.5
|
|
70
|
+
|
|
71
|
+
Doc + RPC hygiene. Two issues surfaced after publishing 0.5.4:
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- **Internal RPC URL leaked into examples.** Three files referenced
|
|
76
|
+
`https://mbsc1.dexe.io/rpc`, an internal DeXe endpoint not intended for
|
|
77
|
+
public traffic. Replaced with the canonical public BSC RPC
|
|
78
|
+
`https://bsc-dataseed.binance.org` in:
|
|
79
|
+
- `docs/ENVIRONMENT.md` (3 occurrences — quick-start block, env table
|
|
80
|
+
example, BSC mainnet chain config)
|
|
81
|
+
- `tests/swarm/README.md` (`SWARM_RPC_URL_MAINNET` example)
|
|
82
|
+
- `tests/compat/FORM-GUIDE.md` (network-capture hint)
|
|
83
|
+
- `.env.example` (2 occurrences — `DEXE_RPC_URL` core block,
|
|
84
|
+
`SWARM_RPC_URL_MAINNET` swarm block)
|
|
85
|
+
- `scripts/swarm/test-mainnet-deploy.mjs` + `test-offchain-mainnet.mjs`
|
|
86
|
+
(now read `process.env.DEXE_RPC_URL` first, fall back to public BSC RPC)
|
|
87
|
+
Existing installs that copy-pasted the snippet still work — both URLs
|
|
88
|
+
serve BSC mainnet — but the public one carries no internal-infra hint.
|
|
89
|
+
- **README links broken on npmjs.com.** Relative links like
|
|
90
|
+
`./docs/TOOLS.md` work on GitHub but npm does NOT resolve them against the
|
|
91
|
+
repo URL — npm renders the README at the package home and a relative link
|
|
92
|
+
resolves to a non-existent path on `npmjs.com`. Converted all in-README
|
|
93
|
+
links to absolute GitHub URLs:
|
|
94
|
+
`./docs/X.md` → `https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/X.md`
|
|
95
|
+
Same pattern applied to the swarm-runbook + LICENSE links.
|
|
96
|
+
|
|
97
|
+
### Scope of exposure
|
|
98
|
+
|
|
99
|
+
Verified via `npm pack --dry-run`: the internal URL was **never shipped in
|
|
100
|
+
any npm tarball**. `package.json`'s `files` array only includes `dist/`,
|
|
101
|
+
`README.md`, `CHANGELOG.md`, `FUTURE.md`, and `.mcp.example.json` — all of
|
|
102
|
+
which used the public BSC RPC. The leak was confined to GitHub-only
|
|
103
|
+
artifacts (`docs/`, `tests/`, gitignored `.env.example` + swarm probe
|
|
104
|
+
scripts). No npm-deprecation needed.
|
|
105
|
+
|
|
106
|
+
### Notes
|
|
107
|
+
|
|
108
|
+
- Git history retains the original URL — full history rewrite via
|
|
109
|
+
`git filter-repo` was considered and declined: rewrites every commit SHA,
|
|
110
|
+
breaks PR refs and external clones, and the URL is an endpoint, not a
|
|
111
|
+
credential. Forward-fix is sufficient.
|
|
112
|
+
|
|
113
|
+
## 0.5.4
|
|
114
|
+
|
|
115
|
+
Off-chain backend + DAO deploy hardening. Two latent bugs surfaced during
|
|
116
|
+
mainnet client-demo lifecycle on `0xCAe32Fa6e6D1C223Ed1047caA58F7fC0b2D65B41`
|
|
117
|
+
(BSC) — both fixed at the boundary so callers don't have to know.
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
|
|
121
|
+
- **`dexe_dao_build_deploy`** (`src/tools/daoDeploy.ts`) — pre-flight reject
|
|
122
|
+
when `tokenParams.cap == mintedTotal` while creating a new gov token.
|
|
123
|
+
ERC20Gov init reverted silently inside `_initGovPool` with the generic
|
|
124
|
+
`Address: low-level delegate call failed`, hiding the real cause behind a
|
|
125
|
+
10M-gas wasted tx. The validator now throws a clear message:
|
|
126
|
+
`cap must be strictly greater than mintedTotal; pass cap=0 for uncapped, or
|
|
127
|
+
cap > mintedTotal`. Tool description updated.
|
|
128
|
+
- **`dexe_proposal_build_offchain_single_option` / `_multi_option` /
|
|
129
|
+
`_for_against`** (`src/tools/proposalBuildOffchain.ts`) — backend rejected
|
|
130
|
+
every off-chain proposal with HTTP 400 `proposal type was not found` because
|
|
131
|
+
the builders sent `attributes.type = String(Math.floor(Date.now()/1000))`
|
|
132
|
+
(unix timestamp) instead of a registered template name. Constants now wired
|
|
133
|
+
per voting type:
|
|
134
|
+
- `default_single_option_type` for `voting_type=one_of`
|
|
135
|
+
- `default_multi_option_type` for `voting_type=multiple_of`
|
|
136
|
+
- `default_for_against_type` for `voting_type=for_against`
|
|
137
|
+
- **Off-chain quorum percentages** — same three builders. The backend stores
|
|
138
|
+
`*_percent` as fractions (`0.5` = 50%), but the inputs accept whole-number
|
|
139
|
+
percentages (`50` = 50%) for ergonomic parity with the frontend form.
|
|
140
|
+
Boundary now divides by 100 once, via a new `pctToFraction` helper.
|
|
141
|
+
|
|
142
|
+
### Verified
|
|
143
|
+
|
|
144
|
+
- Smoke-tested all three off-chain builders: `outer.type` and
|
|
145
|
+
`custom_parameters.type` carry the correct constants; quorum fractions match
|
|
146
|
+
backend examples (live proposal #58 created end-to-end against
|
|
147
|
+
`https://api.dexe.io`).
|
|
148
|
+
- DAO deploy: `cap == mintedTotal` rejected pre-flight with the new message;
|
|
149
|
+
`cap > mintedTotal` and `cap == 0` (uncapped) pass the check.
|
|
150
|
+
- `tsc` clean, no project-test regressions.
|
|
151
|
+
|
|
3
152
|
## 0.5.3
|
|
4
153
|
|
|
5
154
|
`getProposals` ABI fix for the post-upgrade GovPool layout. On-chain
|
package/README.md
CHANGED
|
@@ -6,9 +6,9 @@ MCP server that gives AI agents **full DeXe Protocol DAO operations coverage**
|
|
|
6
6
|
|
|
7
7
|
**Two write modes, calldata-default.** Every write tool returns a ready-to-sign `TxPayload = { to, data, value, chainId, description }` that the agent's wallet (MetaMask, Safe, hardware, etc.) signs and submits — no key in the MCP. Power users who *want* the server to sign and broadcast can opt in by setting `DEXE_PRIVATE_KEY`; that unlocks `dexe_tx_send`, `dexe_tx_status`, and the auto-broadcast branch of `dexe_proposal_create` / `dexe_proposal_vote_and_execute`. Default stays calldata-only.
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**126 tools** across 14 groups. Call `dexe_proposal_catalog` at runtime for the full proposal-type map, or browse the [catalog](#tool-catalog) below.
|
|
10
10
|
|
|
11
|
-
> **End-to-end coverage.** Every proposal-builder tool ships with a swarm-test scenario that exercises it on BSC testnet. Latest pass: **
|
|
11
|
+
> **End-to-end coverage.** Every proposal-builder tool ships with a swarm-test scenario that exercises it on BSC testnet. Latest pass (2026-05-12): **57 scenarios shipped**, broadcasts validated against two fixture DAOs (Polaris 50%-quorum + Sentinel 5%-quorum-with-validators). See [Swarm test harness](#swarm-test-harness) below.
|
|
12
12
|
|
|
13
13
|
## Prerequisites
|
|
14
14
|
|
|
@@ -66,9 +66,9 @@ Minimum config to get **read-only** access to a BSC mainnet DAO:
|
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
Add `DEXE_PINATA_JWT` for IPFS uploads, `DEXE_BACKEND_API_URL` for off-chain proposals, and per-chain subgraph URLs for `dexe_proposal_voters` and the DAO-list reads. Full matrix → [`docs/ENVIRONMENT.md`](
|
|
69
|
+
Add `DEXE_PINATA_JWT` for IPFS uploads, `DEXE_BACKEND_API_URL` for off-chain proposals, and per-chain subgraph URLs for `dexe_proposal_voters` and the DAO-list reads. Full matrix → [`docs/ENVIRONMENT.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/ENVIRONMENT.md).
|
|
70
70
|
|
|
71
|
-
Three first-call examples (full set in [`docs/USAGE.md`](
|
|
71
|
+
Three first-call examples (full set in [`docs/USAGE.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/USAGE.md)):
|
|
72
72
|
|
|
73
73
|
```jsonc
|
|
74
74
|
// 1) discover available proposal types
|
|
@@ -94,7 +94,7 @@ Most tools don't need the protocol checkout at all — read/proposal/vote/deploy
|
|
|
94
94
|
|
|
95
95
|
## Environment variables
|
|
96
96
|
|
|
97
|
-
All optional. Tools that need a missing variable fail with a clear message pointing at exactly what to set. Full matrix + per-tool requirements → [`docs/ENVIRONMENT.md`](
|
|
97
|
+
All optional. Tools that need a missing variable fail with a clear message pointing at exactly what to set. Full matrix + per-tool requirements → [`docs/ENVIRONMENT.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/ENVIRONMENT.md).
|
|
98
98
|
|
|
99
99
|
| Variable | Required for | Purpose |
|
|
100
100
|
|----------|--------------|---------|
|
|
@@ -113,11 +113,11 @@ All optional. Tools that need a missing variable fail with a clear message point
|
|
|
113
113
|
|
|
114
114
|
## Documentation
|
|
115
115
|
|
|
116
|
-
Full docs in [`docs/`](
|
|
116
|
+
Full docs in [`docs/`](https://github.com/edward-arinin-web-dev/dexe-mcp/tree/main/docs):
|
|
117
117
|
|
|
118
|
-
- [`docs/TOOLS.md`](
|
|
119
|
-
- [`docs/USAGE.md`](
|
|
120
|
-
- [`docs/ENVIRONMENT.md`](
|
|
118
|
+
- [`docs/TOOLS.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/TOOLS.md) — complete catalog of all 126 tools, organized by category, with one-line descriptions and required envs per tool.
|
|
119
|
+
- [`docs/USAGE.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/USAGE.md) — 10 worked examples (deploy DAO, create proposals, vote, delegate, validator chamber, decode calldata, off-chain proposals, multicall batching). Copy-pasteable JSON.
|
|
120
|
+
- [`docs/ENVIRONMENT.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/ENVIRONMENT.md) — full env-var reference: minimum block to get started, per-category requirements, calldata vs signer mode, chain-specific config, IPFS gateway rationale, subgraph migration, swarm harness envs, common pitfalls.
|
|
121
121
|
|
|
122
122
|
## Tool surface (high-level)
|
|
123
123
|
|
|
@@ -133,14 +133,14 @@ Full docs in [`docs/`](./docs):
|
|
|
133
133
|
| Internal validator wrappers | 4 | `_change_validator_balances`, `_change_validator_settings`, `_monthly_withdraw`, `_offchain_internal_proposal` |
|
|
134
134
|
| Off-chain backend | 8 | `_offchain_single_option/_multi_option/_for_against/_settings`, auth flow (`_auth_request_nonce`, `_auth_login_request`), `_offchain_build_vote/_cancel_vote` |
|
|
135
135
|
| Vote / stake / delegate / execute / claim | 16 | `_vote_build_*` family — every direct EOA write on GovPool / Validators |
|
|
136
|
-
| Composite signing flows |
|
|
136
|
+
| Composite signing flows | 5 | `_proposal_create`, `_proposal_vote_and_execute`, `_tx_send`, `_tx_status`, `_get_config` (signing tools opt-in via `DEXE_PRIVATE_KEY`; `_get_config` is read-only diagnostic for the multi-chain config) |
|
|
137
137
|
| Subgraph reads | 7 | DAO list, members, experts, user activity, delegation map, distribution status, OTC sale tiers per DAO (decentralized network endpoints + RPC fallback) |
|
|
138
138
|
| Merkle utility | 2 | `dexe_merkle_build`, `dexe_merkle_proof` — OZ `StandardMerkleTree`-compatible (sorted-pair commutative keccak, double-hash leaf) |
|
|
139
|
-
| OTC composites | 4 | `dexe_otc_dao_open_sale`, `_buyer_status`, `_buyer_buy`, `_buyer_claim_all` — full project-owner + buyer flows over `TokenSaleProposal`. See [`docs/OTC.md`](
|
|
140
|
-
| Simulator | 3 | `dexe_sim_calldata`, `_sim_proposal`, `_sim_buy` — `eth_call`-based preflight with revert-reason decoding. See [`docs/SIMULATOR.md`](
|
|
141
|
-
| Multi-DAO inbox + forecast | 2 | `dexe_user_inbox` — pending items across N DAOs (unvoted proposals, claimable rewards, locked deposits). `_proposal_forecast` — pass-rate prediction with quorum projection + risk flags. See [`docs/INBOX.md`](
|
|
139
|
+
| OTC composites | 4 | `dexe_otc_dao_open_sale`, `_buyer_status`, `_buyer_buy`, `_buyer_claim_all` — full project-owner + buyer flows over `TokenSaleProposal`. See [`docs/OTC.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/OTC.md) |
|
|
140
|
+
| Simulator | 3 | `dexe_sim_calldata`, `_sim_proposal`, `_sim_buy` — `eth_call`-based preflight with revert-reason decoding. See [`docs/SIMULATOR.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/SIMULATOR.md) |
|
|
141
|
+
| Multi-DAO inbox + forecast | 2 | `dexe_user_inbox` — pending items across N DAOs (unvoted proposals, claimable rewards, locked deposits). `_proposal_forecast` — pass-rate prediction with quorum projection + risk flags. See [`docs/INBOX.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/INBOX.md) |
|
|
142
142
|
|
|
143
|
-
Total: **
|
|
143
|
+
Total: **126**. Per-tool descriptions, args, return shapes → [`docs/TOOLS.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/TOOLS.md).
|
|
144
144
|
|
|
145
145
|
## Swarm test harness
|
|
146
146
|
|
|
@@ -149,7 +149,7 @@ tool against real BSC-testnet DAOs. Scenarios are JSON specs; the orchestrator
|
|
|
149
149
|
loads them, resolves agent wallets, and runs each step through either an inline
|
|
150
150
|
ethers dispatcher or the dexe-mcp stdio bridge.
|
|
151
151
|
|
|
152
|
-
**
|
|
152
|
+
**57 scenarios shipped** covering:
|
|
153
153
|
|
|
154
154
|
- Reset + delegation chains (S00, S01, S06, S14)
|
|
155
155
|
- Validator chamber pass / veto / full lifecycle (S02, S03, S07)
|
|
@@ -163,6 +163,12 @@ ethers dispatcher or the dexe-mcp stdio bridge.
|
|
|
163
163
|
delegate/revoke from expert, reward multiplier (4 modes), change voting
|
|
164
164
|
settings, new proposal type, change math model, custom ABI, manual calldata,
|
|
165
165
|
create staking tier, off-chain validator + for/against + settings) (S16–S40)
|
|
166
|
+
- OTC multi-tier sale flows: open sale, buyer buy native + merkle (S41–S46)
|
|
167
|
+
- Simulator + inbox + per-DAO reads (S47, S48, S50, S51)
|
|
168
|
+
- **Broadcast lifecycle for the v0.5.6 builder rewrites: `withdraw_treasury`,
|
|
169
|
+
`apply_to_dao`, `reward_multiplier mint` (S52–S54)**
|
|
170
|
+
- **Broadcast lifecycle for the most-used proposal types: `token_transfer`,
|
|
171
|
+
`blacklist`, `add_expert` (S55–S57)**
|
|
166
172
|
|
|
167
173
|
```bash
|
|
168
174
|
# 1) generate 9 wallets (8 agents + funder), fund the funder from your wallet
|
|
@@ -174,8 +180,8 @@ npm run swarm:run # full sweep, all scenarios
|
|
|
174
180
|
npm run swarm:run -- --scenarios=S00-reset,S01-delegation-chain-3hop --dry-run
|
|
175
181
|
```
|
|
176
182
|
|
|
177
|
-
Setup runbook: [`tests/swarm/README.md`](tests/swarm/README.md).
|
|
178
|
-
Scenario schema: [`tests/swarm/scenarios/_schema.md`](tests/swarm/scenarios/_schema.md).
|
|
183
|
+
Setup runbook: [`tests/swarm/README.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/tests/swarm/README.md).
|
|
184
|
+
Scenario schema: [`tests/swarm/scenarios/_schema.md`](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/tests/swarm/scenarios/_schema.md).
|
|
179
185
|
Per-role agent prompts: `tests/swarm/prompts/`.
|
|
180
186
|
|
|
181
187
|
## Contributing
|
|
@@ -191,4 +197,4 @@ npm run dev # watch mode
|
|
|
191
197
|
|
|
192
198
|
## License
|
|
193
199
|
|
|
194
|
-
MIT. See [LICENSE](
|
|
200
|
+
MIT. See [LICENSE](https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/LICENSE).
|
package/dist/config.d.ts
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
|
+
export interface ChainConfig {
|
|
2
|
+
chainId: number;
|
|
3
|
+
rpcUrl: string;
|
|
4
|
+
/** Optional `ContractsRegistry` override scoped to this chain. */
|
|
5
|
+
registryOverride?: string;
|
|
6
|
+
}
|
|
1
7
|
export interface DexeConfig {
|
|
2
8
|
/** Absolute, normalized path to the DeXe-Protocol checkout (may not exist yet). */
|
|
3
9
|
protocolPath: string;
|
|
4
|
-
/**
|
|
10
|
+
/** All chains configured via env. Empty when no RPC is set. Frozen. */
|
|
11
|
+
chains: ReadonlyMap<number, ChainConfig>;
|
|
12
|
+
/**
|
|
13
|
+
* Default chain id used when a tool call omits `chainId`. Always resolves to
|
|
14
|
+
* a configured chain when `chains` is non-empty. When `chains` is empty,
|
|
15
|
+
* defaults to 56 for legacy single-chain code paths that don't need an RPC.
|
|
16
|
+
*/
|
|
17
|
+
defaultChainId: number;
|
|
18
|
+
/**
|
|
19
|
+
* Back-compat alias for `chains.get(defaultChainId)?.rpcUrl`. Always reflects
|
|
20
|
+
* the default chain's RPC. New code should call `getProvider(chainId)` instead.
|
|
21
|
+
*/
|
|
5
22
|
rpcUrl?: string;
|
|
6
|
-
/**
|
|
23
|
+
/** Back-compat alias for `defaultChainId`. */
|
|
7
24
|
chainId: number;
|
|
8
|
-
/**
|
|
25
|
+
/** Back-compat: registry override resolved against the default chain. */
|
|
9
26
|
registryOverride?: string;
|
|
10
27
|
/** Pinata JWT for IPFS uploads (reads work without it via gateway). */
|
|
11
28
|
pinataJwt?: string;
|
|
12
|
-
/** GraphQL endpoint URLs for The Graph subgraphs. */
|
|
29
|
+
/** GraphQL endpoint URLs for The Graph subgraphs (chain-agnostic in env). */
|
|
13
30
|
subgraphPoolsUrl?: string;
|
|
14
31
|
subgraphValidatorsUrl?: string;
|
|
15
32
|
subgraphInteractionsUrl?: string;
|
|
@@ -25,4 +42,10 @@ export interface DexeConfig {
|
|
|
25
42
|
* that lazily from inside build/test tools.
|
|
26
43
|
*/
|
|
27
44
|
export declare function loadConfig(): Promise<DexeConfig>;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a chain config given an optional `chainId`. When omitted, returns
|
|
47
|
+
* the default chain. Throws with a clear message when the requested chain is
|
|
48
|
+
* not configured.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveChain(config: DexeConfig, chainId?: number): ChainConfig;
|
|
28
51
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;
|
|
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"}
|
package/dist/config.js
CHANGED
|
@@ -18,23 +18,88 @@ export async function loadConfig() {
|
|
|
18
18
|
else if (!isBuildReady(protocolPath)) {
|
|
19
19
|
process.stderr.write(`[dexe-mcp] DeXe-Protocol checkout at ${protocolPath} is incomplete (missing node_modules or hardhat.config) — will be prepared on first dexe_compile call.\n`);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// ---- collect every configured chain ------------------------------------
|
|
22
|
+
// Priority:
|
|
23
|
+
// 1) DEXE_RPC_URL_TESTNET → chain 97
|
|
24
|
+
// 2) DEXE_RPC_URL_MAINNET → chain 56
|
|
25
|
+
// 3) Legacy DEXE_RPC_URL + DEXE_CHAIN_ID → register that chain
|
|
26
|
+
// All three may coexist; later entries with the same chainId override earlier.
|
|
27
|
+
const chains = new Map();
|
|
28
|
+
const registryOverride = process.env.DEXE_CONTRACTS_REGISTRY?.trim() || undefined;
|
|
29
|
+
const rpcTestnet = process.env.DEXE_RPC_URL_TESTNET?.trim() || undefined;
|
|
30
|
+
if (rpcTestnet) {
|
|
31
|
+
chains.set(97, { chainId: 97, rpcUrl: rpcTestnet });
|
|
32
|
+
}
|
|
33
|
+
const rpcMainnet = process.env.DEXE_RPC_URL_MAINNET?.trim() || undefined;
|
|
34
|
+
if (rpcMainnet) {
|
|
35
|
+
chains.set(56, { chainId: 56, rpcUrl: rpcMainnet });
|
|
36
|
+
}
|
|
37
|
+
// Legacy single-chain env (still supported)
|
|
38
|
+
const legacyRpc = process.env.DEXE_RPC_URL?.trim() || undefined;
|
|
39
|
+
let legacyChainId;
|
|
23
40
|
if (process.env.DEXE_CHAIN_ID) {
|
|
24
41
|
const n = Number(process.env.DEXE_CHAIN_ID);
|
|
25
42
|
if (!Number.isFinite(n) || n <= 0) {
|
|
26
43
|
fatal(`DEXE_CHAIN_ID must be a positive integer, got: ${process.env.DEXE_CHAIN_ID}`);
|
|
27
44
|
}
|
|
28
|
-
|
|
45
|
+
legacyChainId = n;
|
|
46
|
+
}
|
|
47
|
+
if (legacyRpc) {
|
|
48
|
+
// Resolve legacy chainId. If unset, infer from URL hostname; fall back to 56.
|
|
49
|
+
const inferred = legacyChainId ?? inferChainIdFromRpcUrl(legacyRpc) ?? 56;
|
|
50
|
+
// Apply registryOverride only when this is the legacy chain (per-chain
|
|
51
|
+
// override via DEXE_CONTRACTS_REGISTRY has always been single-chain).
|
|
52
|
+
chains.set(inferred, {
|
|
53
|
+
chainId: inferred,
|
|
54
|
+
rpcUrl: legacyRpc,
|
|
55
|
+
registryOverride,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// ---- resolve default chain ---------------------------------------------
|
|
59
|
+
let defaultChainId;
|
|
60
|
+
const explicitDefault = process.env.DEXE_DEFAULT_CHAIN_ID?.trim();
|
|
61
|
+
if (explicitDefault) {
|
|
62
|
+
const n = Number(explicitDefault);
|
|
63
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
64
|
+
fatal(`DEXE_DEFAULT_CHAIN_ID must be a positive integer, got: ${explicitDefault}`);
|
|
65
|
+
}
|
|
66
|
+
if (!chains.has(n)) {
|
|
67
|
+
const configured = [...chains.keys()].sort().join(", ") || "none";
|
|
68
|
+
fatal(`DEXE_DEFAULT_CHAIN_ID=${n} but no RPC configured for that chain. Configured: [${configured}]. Set DEXE_RPC_URL_${n === 97 ? "TESTNET" : n === 56 ? "MAINNET" : "<chain>"} or legacy DEXE_RPC_URL.`);
|
|
69
|
+
}
|
|
70
|
+
defaultChainId = n;
|
|
71
|
+
}
|
|
72
|
+
else if (chains.size === 1) {
|
|
73
|
+
defaultChainId = [...chains.keys()][0];
|
|
74
|
+
}
|
|
75
|
+
else if (chains.size > 1) {
|
|
76
|
+
// Multi-chain without explicit default → prefer testnet for safety, else lowest chainId.
|
|
77
|
+
const sorted = [...chains.keys()].sort((a, b) => a - b);
|
|
78
|
+
defaultChainId = chains.has(97) ? 97 : sorted[0];
|
|
79
|
+
process.stderr.write(`[dexe-mcp] multiple chains configured without DEXE_DEFAULT_CHAIN_ID; defaulting to ${defaultChainId === 97 ? "testnet (97)" : `chain ${defaultChainId}`} for safety. Set DEXE_DEFAULT_CHAIN_ID to override.\n`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// No chains configured — keep legacy fallback so non-RPC tools still load.
|
|
83
|
+
defaultChainId = legacyChainId ?? 56;
|
|
84
|
+
}
|
|
85
|
+
// ---- emit one-line summary of the resolved chain set --------------------
|
|
86
|
+
if (chains.size > 0) {
|
|
87
|
+
const summary = [...chains.values()]
|
|
88
|
+
.sort((a, b) => a.chainId - b.chainId)
|
|
89
|
+
.map(c => `${c.chainId}${c.chainId === defaultChainId ? "*" : ""}`)
|
|
90
|
+
.join(", ");
|
|
91
|
+
process.stderr.write(`[dexe-mcp] chains: [${summary}] (default marked with *)\n`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
process.stderr.write("[dexe-mcp] no RPC configured — read/write tools that touch a chain will fail with a clear error.\n");
|
|
29
95
|
}
|
|
30
|
-
const registryOverride = process.env.DEXE_CONTRACTS_REGISTRY?.trim() || undefined;
|
|
31
96
|
const pinataJwt = process.env.DEXE_PINATA_JWT?.trim() || undefined;
|
|
32
97
|
const subgraphPoolsUrl = process.env.DEXE_SUBGRAPH_POOLS_URL?.trim() || undefined;
|
|
33
98
|
const subgraphValidatorsUrl = process.env.DEXE_SUBGRAPH_VALIDATORS_URL?.trim() || undefined;
|
|
34
99
|
const subgraphInteractionsUrl = process.env.DEXE_SUBGRAPH_INTERACTIONS_URL?.trim() || undefined;
|
|
35
100
|
const privateKey = process.env.DEXE_PRIVATE_KEY?.trim() || undefined;
|
|
36
|
-
if (privateKey &&
|
|
37
|
-
fatal("DEXE_PRIVATE_KEY requires DEXE_RPC_URL to be set (signing needs an RPC endpoint).");
|
|
101
|
+
if (privateKey && chains.size === 0) {
|
|
102
|
+
fatal("DEXE_PRIVATE_KEY requires at least one of DEXE_RPC_URL / DEXE_RPC_URL_TESTNET / DEXE_RPC_URL_MAINNET to be set (signing needs an RPC endpoint).");
|
|
38
103
|
}
|
|
39
104
|
if (privateKey) {
|
|
40
105
|
const { Wallet } = await import("ethers");
|
|
@@ -49,11 +114,14 @@ export async function loadConfig() {
|
|
|
49
114
|
}
|
|
50
115
|
forkBlock = n;
|
|
51
116
|
}
|
|
117
|
+
const defaultChain = chains.get(defaultChainId);
|
|
52
118
|
return Object.freeze({
|
|
53
119
|
protocolPath,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
120
|
+
chains: Object.freeze(new Map(chains)),
|
|
121
|
+
defaultChainId,
|
|
122
|
+
chainId: defaultChainId,
|
|
123
|
+
rpcUrl: defaultChain?.rpcUrl,
|
|
124
|
+
registryOverride: defaultChain?.registryOverride ?? registryOverride,
|
|
57
125
|
pinataJwt,
|
|
58
126
|
subgraphPoolsUrl,
|
|
59
127
|
subgraphValidatorsUrl,
|
|
@@ -62,6 +130,34 @@ export async function loadConfig() {
|
|
|
62
130
|
privateKey,
|
|
63
131
|
});
|
|
64
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Best-effort chain-id inference from a JSON-RPC URL. Used only when legacy
|
|
135
|
+
* `DEXE_RPC_URL` is set without `DEXE_CHAIN_ID`. Returns undefined when
|
|
136
|
+
* unknown — caller falls back to 56.
|
|
137
|
+
*/
|
|
138
|
+
function inferChainIdFromRpcUrl(url) {
|
|
139
|
+
const u = url.toLowerCase();
|
|
140
|
+
if (u.includes("prebsc") || u.includes("testnet"))
|
|
141
|
+
return 97;
|
|
142
|
+
if (u.includes("bsc") || u.includes("binance"))
|
|
143
|
+
return 56;
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolve a chain config given an optional `chainId`. When omitted, returns
|
|
148
|
+
* the default chain. Throws with a clear message when the requested chain is
|
|
149
|
+
* not configured.
|
|
150
|
+
*/
|
|
151
|
+
export function resolveChain(config, chainId) {
|
|
152
|
+
const target = chainId ?? config.defaultChainId;
|
|
153
|
+
const chain = config.chains.get(target);
|
|
154
|
+
if (!chain) {
|
|
155
|
+
const configured = [...config.chains.keys()].sort().join(", ") || "none";
|
|
156
|
+
throw new Error(`No RPC configured for chainId=${target}. Configured chains: [${configured}]. ` +
|
|
157
|
+
`Set DEXE_RPC_URL_${target === 97 ? "TESTNET" : target === 56 ? "MAINNET" : "<chain>"} in the MCP env block.`);
|
|
158
|
+
}
|
|
159
|
+
return chain;
|
|
160
|
+
}
|
|
65
161
|
function fatal(msg) {
|
|
66
162
|
// stderr only — stdout is the MCP protocol channel.
|
|
67
163
|
process.stderr.write(`[dexe-mcp] fatal: ${msg}\n`);
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DexeConfig } from "../config.js";
|
|
2
|
+
export type BlacklistCheck = {
|
|
3
|
+
status: "blacklisted";
|
|
4
|
+
token: string;
|
|
5
|
+
account: string;
|
|
6
|
+
} | {
|
|
7
|
+
status: "clean";
|
|
8
|
+
token: string;
|
|
9
|
+
account: string;
|
|
10
|
+
} | {
|
|
11
|
+
status: "skipped";
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort `isBlacklisted(account)` lookup. Returns `skipped` when the RPC
|
|
16
|
+
* is unset or the call reverts (e.g. token isn't ERC20Gov). Build steps that
|
|
17
|
+
* use this should treat `skipped` as "go ahead" and only block on
|
|
18
|
+
* `blacklisted`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkBlacklist(config: DexeConfig, token: string, account: string): Promise<BlacklistCheck>;
|
|
21
|
+
export declare function blacklistError(token: string, account: string): string;
|
|
22
|
+
//# sourceMappingURL=blacklist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blacklist.d.ts","sourceRoot":"","sources":["../../src/lib/blacklist.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAwBzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAOrE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Contract } from "ethers";
|
|
2
|
+
import { RpcProvider } from "../rpc.js";
|
|
3
|
+
const ERC20_GOV_BLACKLIST_ABI = [
|
|
4
|
+
"function isBlacklisted(address account) view returns (bool)",
|
|
5
|
+
];
|
|
6
|
+
/**
|
|
7
|
+
* Best-effort `isBlacklisted(account)` lookup. Returns `skipped` when the RPC
|
|
8
|
+
* is unset or the call reverts (e.g. token isn't ERC20Gov). Build steps that
|
|
9
|
+
* use this should treat `skipped` as "go ahead" and only block on
|
|
10
|
+
* `blacklisted`.
|
|
11
|
+
*/
|
|
12
|
+
export async function checkBlacklist(config, token, account) {
|
|
13
|
+
if (!config.rpcUrl) {
|
|
14
|
+
return { status: "skipped", reason: "DEXE_RPC_URL not set — skipping blacklist precheck" };
|
|
15
|
+
}
|
|
16
|
+
let provider;
|
|
17
|
+
try {
|
|
18
|
+
provider = new RpcProvider(config).requireProvider();
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
return { status: "skipped", reason: err instanceof Error ? err.message : String(err) };
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const contract = new Contract(token, ERC20_GOV_BLACKLIST_ABI, provider);
|
|
25
|
+
const flag = await contract.isBlacklisted(account);
|
|
26
|
+
return flag
|
|
27
|
+
? { status: "blacklisted", token, account }
|
|
28
|
+
: { status: "clean", token, account };
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
return {
|
|
32
|
+
status: "skipped",
|
|
33
|
+
reason: `isBlacklisted() unavailable on ${token} (${err instanceof Error ? err.message : String(err)})`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function blacklistError(token, account) {
|
|
38
|
+
return (`Refusing to build: recipient ${account} is blacklisted on ERC20Gov ${token}. ` +
|
|
39
|
+
`If broadcast, GovPool.execute would revert with "ERC20Gov: account is blacklisted" ` +
|
|
40
|
+
`and the proposal would sit in SucceededFor permanently. Un-blacklist first ` +
|
|
41
|
+
`(dexe_proposal_build_blacklist with isBlacklisted=false) or pick a different recipient.`);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=blacklist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blacklist.js","sourceRoot":"","sources":["../../src/lib/blacklist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,MAAM,uBAAuB,GAAG;IAC9B,6DAA6D;CACrD,CAAC;AAOX;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAkB,EAClB,KAAa,EACb,OAAe;IAEf,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,oDAAoD,EAAE,CAAC;IAC7F,CAAC;IACD,IAAI,QAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;IACvD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACzF,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,KAAK,EAAE,uBAA8C,EAAE,QAAQ,CAE5F,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI;YACT,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE;YAC3C,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,kCAAkC,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG;SACxG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,OAAe;IAC3D,OAAO,CACL,gCAAgC,OAAO,+BAA+B,KAAK,IAAI;QAC/E,qFAAqF;QACrF,6EAA6E;QAC7E,yFAAyF,CAC1F,CAAC;AACJ,CAAC"}
|
package/dist/lib/signer.d.ts
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { Wallet } from "ethers";
|
|
2
|
-
import type
|
|
2
|
+
import { type DexeConfig } from "../config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Per-chain signer cache. The private key is chain-agnostic; only the
|
|
5
|
+
* provider differs per chain.
|
|
6
|
+
*/
|
|
3
7
|
export declare class SignerManager {
|
|
4
|
-
private
|
|
8
|
+
private readonly cache;
|
|
5
9
|
private readonly key;
|
|
6
|
-
private readonly
|
|
10
|
+
private readonly config;
|
|
7
11
|
constructor(config: DexeConfig);
|
|
8
12
|
hasSigner(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Address of the configured signer (chain-agnostic — same EOA across chains).
|
|
15
|
+
* Throws if no `DEXE_PRIVATE_KEY` is set.
|
|
16
|
+
*/
|
|
9
17
|
getAddress(): string;
|
|
10
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Return a signer bound to the requested chain's RPC. When `chainId` is
|
|
20
|
+
* omitted the default chain is used.
|
|
21
|
+
*/
|
|
22
|
+
requireSigner(chainId?: number): Wallet;
|
|
23
|
+
private failNoKey;
|
|
11
24
|
}
|
|
12
25
|
//# sourceMappingURL=signer.d.ts.map
|
package/dist/lib/signer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/lib/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../../src/lib/signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE7D;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;gBAExB,MAAM,EAAE,UAAU;IAK9B,SAAS,IAAI,OAAO;IAIpB;;;OAGG;IACH,UAAU,IAAI,MAAM;IAKpB;;;OAGG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAYvC,OAAO,CAAC,SAAS;CAMlB"}
|