dexe-mcp 0.5.8 → 0.6.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.
- package/CHANGELOG.md +641 -536
- package/README.md +289 -270
- package/SECURITY.md +96 -46
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -1
- package/dist/governor/adapter.d.ts +90 -0
- package/dist/governor/adapter.d.ts.map +1 -0
- package/dist/governor/adapter.js +169 -0
- package/dist/governor/adapter.js.map +1 -0
- package/dist/governor/configs/compound.json +32 -0
- package/dist/governor/configs/optimism.json +28 -0
- package/dist/governor/configs/uniswap.json +32 -0
- package/dist/governor/encoder.d.ts +59 -0
- package/dist/governor/encoder.d.ts.map +1 -0
- package/dist/governor/encoder.js +290 -0
- package/dist/governor/encoder.js.map +1 -0
- package/dist/governor/index.d.ts +11 -0
- package/dist/governor/index.d.ts.map +1 -0
- package/dist/governor/index.js +20 -0
- package/dist/governor/index.js.map +1 -0
- package/dist/governor/loader.d.ts +42 -0
- package/dist/governor/loader.d.ts.map +1 -0
- package/dist/governor/loader.js +103 -0
- package/dist/governor/loader.js.map +1 -0
- package/dist/governor/tally.d.ts +48 -0
- package/dist/governor/tally.d.ts.map +1 -0
- package/dist/governor/tally.js +103 -0
- package/dist/governor/tally.js.map +1 -0
- package/dist/governor/tools/build.d.ts +3 -0
- package/dist/governor/tools/build.d.ts.map +1 -0
- package/dist/governor/tools/build.js +137 -0
- package/dist/governor/tools/build.js.map +1 -0
- package/dist/governor/tools/extras.d.ts +4 -0
- package/dist/governor/tools/extras.d.ts.map +1 -0
- package/dist/governor/tools/extras.js +197 -0
- package/dist/governor/tools/extras.js.map +1 -0
- package/dist/governor/tools/read.d.ts +4 -0
- package/dist/governor/tools/read.d.ts.map +1 -0
- package/dist/governor/tools/read.js +174 -0
- package/dist/governor/tools/read.js.map +1 -0
- package/dist/governor/tools/simulate.d.ts +6 -0
- package/dist/governor/tools/simulate.d.ts.map +1 -0
- package/dist/governor/tools/simulate.js +191 -0
- package/dist/governor/tools/simulate.js.map +1 -0
- package/dist/lib/broadcastGuards.d.ts +41 -0
- package/dist/lib/broadcastGuards.d.ts.map +1 -0
- package/dist/lib/broadcastGuards.js +85 -0
- package/dist/lib/broadcastGuards.js.map +1 -0
- package/dist/lib/ethersProvider.d.ts +96 -0
- package/dist/lib/ethersProvider.d.ts.map +1 -0
- package/dist/lib/ethersProvider.js +170 -0
- package/dist/lib/ethersProvider.js.map +1 -0
- package/dist/lib/signer.d.ts +2 -0
- package/dist/lib/signer.d.ts.map +1 -1
- package/dist/lib/signer.js +4 -0
- package/dist/lib/signer.js.map +1 -1
- package/dist/tools/flow.d.ts.map +1 -1
- package/dist/tools/flow.js +13 -0
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/getConfig.d.ts.map +1 -1
- package/dist/tools/getConfig.js +17 -0
- package/dist/tools/getConfig.js.map +1 -1
- package/dist/tools/inbox.js +8 -8
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/predict.js +17 -17
- package/dist/tools/safe.d.ts +5 -0
- package/dist/tools/safe.d.ts.map +1 -0
- package/dist/tools/safe.js +264 -0
- package/dist/tools/safe.js.map +1 -0
- package/dist/tools/simulate.d.ts +7 -0
- package/dist/tools/simulate.d.ts.map +1 -1
- package/dist/tools/simulate.js +8 -0
- package/dist/tools/simulate.js.map +1 -1
- package/dist/tools/subgraph.js +162 -162
- package/dist/tools/txSend.d.ts.map +1 -1
- package/dist/tools/txSend.js +25 -0
- package/dist/tools/txSend.js.map +1 -1
- package/package.json +95 -92
package/CHANGELOG.md
CHANGED
|
@@ -1,536 +1,641 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- **
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- **
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
## 0.5.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
###
|
|
113
|
-
|
|
114
|
-
- **
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
###
|
|
159
|
-
|
|
160
|
-
- **`
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
`
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
`
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
`
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
the
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
`
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
-
|
|
273
|
-
`
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
###
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
- `
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
- `
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
- `dexe_user_inbox` —
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
-
|
|
412
|
-
- `
|
|
413
|
-
- `
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
- `
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
- `
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
-
|
|
437
|
-
|
|
438
|
-
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
-
|
|
445
|
-
|
|
446
|
-
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
**
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
- `
|
|
466
|
-
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
-
|
|
470
|
-
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
**
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
- `
|
|
480
|
-
- `
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
-
|
|
485
|
-
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
- `
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
-
|
|
516
|
-
-
|
|
517
|
-
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
- `
|
|
521
|
-
-
|
|
522
|
-
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.6.0 — 2026-05-26
|
|
4
|
+
|
|
5
|
+
### `gov` track
|
|
6
|
+
|
|
7
|
+
External OpenZeppelin Governor + Compound Bravo surface. **+18 tools, total 131 → 149. 17 → 18 groups.** Targets Uniswap, Compound, Optimism. Independent from the DeXe Protocol — no DeXe contract needs to be deployed on the target chain. Source plan: `research/06-execution-plan.md` (Option 1).
|
|
8
|
+
|
|
9
|
+
### New tools — `dexe_gov_*` (18)
|
|
10
|
+
|
|
11
|
+
**Read (5)** — `dexe_gov_list_governors`, `dexe_gov_get_proposal`, `dexe_gov_get_voting_power`, `dexe_gov_get_quorum`, `dexe_gov_get_proposal_threshold`. Family-agnostic readouts: Bravo's `proposals(uint256)` flat struct is mapped onto the OZ `{snapshot, deadline, votes}` shape; `bravoExtra` (`proposer`, `eta`, `canceled`, `executed`) surfaced when applicable. Voting-power routes by token type — `ERC20VotesComp` (UNI, COMP) hits `getPriorVotes` / `getCurrentVotes`; `ERC20Votes` (OP) hits `getPastVotes` / `getVotes`.
|
|
12
|
+
|
|
13
|
+
**Build (5)** — `dexe_gov_build_propose`, `dexe_gov_build_vote_cast`, `dexe_gov_build_queue`, `dexe_gov_build_execute`, `dexe_gov_build_delegate`. Version-branched encoders:
|
|
14
|
+
- OZ v4+ propose: `(targets, values, calldatas, description)`; queue/execute: `(…, descriptionHash)` — accepts raw description (auto-keccak'd) or pre-computed hash.
|
|
15
|
+
- Bravo propose: `(targets, values, signatures, calldatas, description)`; queue/execute: `(proposalId)` only.
|
|
16
|
+
- `castVote` / `castVoteWithReason` identical both families; `support`: 0=Against, 1=For, 2=Abstain.
|
|
17
|
+
- `delegate` is on the voting token, not the governor.
|
|
18
|
+
|
|
19
|
+
**Simulate (2)** — `dexe_gov_simulate_proposal` (single-block `eth_call` dry-run with `Error(string)` + `Panic(uint256)` decoding) and `dexe_gov_simulate_vote_impact` (pure projection: current tallies + quorum, project the post-vote state, report `{quorumMet, willPass}` with family-aware quorum semantics — Bravo counts `forVotes` only, OZ counts `for + abstain`).
|
|
20
|
+
|
|
21
|
+
**Extras (6)** — `dexe_gov_get_state` (single-call state lookup), `dexe_gov_has_voted` (per-account vote receipt), `dexe_gov_build_cancel` (family-aware cancel encoder), `dexe_gov_decode_calldata` (round-trip any Governor write calldata), `dexe_gov_hash_description` (pure keccak256 utility), `dexe_gov_hash_proposal` (OZ-only `hashProposal` preview — errors clearly on Bravo). Closes plan §2 metric #2 (`≥18 dexe_gov_* tools shipped`).
|
|
22
|
+
|
|
23
|
+
### New configs / fixtures
|
|
24
|
+
|
|
25
|
+
`src/governor/configs/` — Uniswap, Compound, Optimism. Each is one JSON. Adding a DAO is a config-only change.
|
|
26
|
+
|
|
27
|
+
### Tally parity harness
|
|
28
|
+
|
|
29
|
+
`tests/governor/parity.test.ts` — pulls the 10 most-recent proposals per Tier-1 DAO via Tally GraphQL, asserts on-chain `state()` matches the canonical-indexed Tally status. Live mode gated by `TALLY_API_KEY`; unit cases for the comparator run without network.
|
|
30
|
+
|
|
31
|
+
### Tests (gov)
|
|
32
|
+
|
|
33
|
+
60 governor unit tests green (encoder selector + roundtrip, family detection, isolation guard, fixture validity, Tally mapper). Plan §4.1 selector targets verified: OZ propose `0x7d5e81e2`, castVote `0x56781388`, delegate `0x5c19a95c`. Bravo propose selector derived from canonical 5-arg signature.
|
|
34
|
+
|
|
35
|
+
### Docs (gov)
|
|
36
|
+
|
|
37
|
+
`docs/GOVERNOR.md` (new). `docs/GOVERNOR_LAUNCH.md` (launch runbook). `docs/TOOLS.md` §17. README catalog row + tool count.
|
|
38
|
+
|
|
39
|
+
### Hardening (gov, post-audit)
|
|
40
|
+
|
|
41
|
+
Multi-agent audit pass before merge. No correctness or security blockers found; the following were tightened:
|
|
42
|
+
- **Generic per-chain RPC** — `config.ts` now registers any `DEXE_RPC_URL_<chainId>` env var, so the live Governor read/simulate tools can reach Ethereum (1) and Optimism (10) where the Tier-1 DAOs actually live. Documented in `docs/GOVERNOR.md` + `docs/ENVIRONMENT.md`.
|
|
43
|
+
- **Read-side input validation** — `dexe_gov_get_proposal` / `_get_voting_power` / `_get_state` / `_has_voted` now reject malformed `account` / `proposalId` at the schema layer instead of forwarding a cryptic RPC error.
|
|
44
|
+
- **Encoder guards** — OZ `queue`/`execute`/`cancel` now enforce target/value/calldata length parity (previously only `propose` did); all builders reject empty action sets and cap at `MAX_ACTIONS` (50).
|
|
45
|
+
- **Revert decoding** — `simulate_proposal` decodes `Panic(uint256)` codes to a human hint (overflow, div-by-zero, …) instead of raw bytes.
|
|
46
|
+
- **Testability** — vote-impact projection extracted to a pure `projectVoteImpact()`; `validateGovernorConfig` exported. New offline tests cover voting-power routing, Bravo/OZ proposal-struct mapping, family-branched quorum projection, encoder guards, `hashProposal` Bravo invariant, and the real config validator. Governor suite now 70+ unit tests.
|
|
47
|
+
|
|
48
|
+
## 0.5.9 — 2026-05-26
|
|
49
|
+
|
|
50
|
+
Security-hardening release: supply-chain CI, signer broadcast guards, and Safe{Wallet} multisig signing.
|
|
51
|
+
|
|
52
|
+
### Signer broadcast guards
|
|
53
|
+
|
|
54
|
+
`dexe_tx_send` **and every composite signer flow** (`dexe_proposal_create`,
|
|
55
|
+
`dexe_proposal_vote_and_execute`, and the OTC composites — all broadcast through
|
|
56
|
+
the shared `sendOrCollect` loop) now run `runBroadcastGuards()` (new
|
|
57
|
+
`src/lib/broadcastGuards.ts`) before `wallet.sendTransaction()`. Four opt-in
|
|
58
|
+
checks, chained in order; each is a no-op unless its env var is set, so calldata
|
|
59
|
+
mode and the default signer posture are unchanged. In every case the broadcast is
|
|
60
|
+
aborted **before any gas is spent** and the result carries `isError: true`.
|
|
61
|
+
`dexe_tx_send` returns the structured `{ status: "rejected", guard, reason }`
|
|
62
|
+
shape; composite flows abort with the guard's reason as error text. Closes
|
|
63
|
+
security-hardening roadmap B6/B7/B9/B10.
|
|
64
|
+
|
|
65
|
+
- **B6 — destination allowlist (`DEXE_SIGNER_ALLOWLIST`).** Comma-separated `to`
|
|
66
|
+
addresses; broadcasts to anything off-list are rejected. Validated and
|
|
67
|
+
lowercased at startup — an invalid address aborts startup.
|
|
68
|
+
- **B7 — value cap (`DEXE_SIGNER_MAX_VALUE_WEI`).** Rejects any broadcast whose
|
|
69
|
+
`value` (wei) exceeds the cap.
|
|
70
|
+
- **B9 — auto-simulation (always on in single-shot signer mode).** Reuses
|
|
71
|
+
`simulateCalldata` to `eth_call` the tx against live state; aborts with the
|
|
72
|
+
decoded revert reason instead of paying gas for a doomed tx. Only a genuine
|
|
73
|
+
contract revert (`CALL_EXCEPTION` / decodable returndata) aborts — a transport
|
|
74
|
+
failure (timeout, 429) fails **open** so a flaky RPC can't wedge a valid
|
|
75
|
+
broadcast. Skipped inside composite flows, whose steps are an ordered
|
|
76
|
+
*dependent* sequence that can't be simulated against pre-sequence state
|
|
77
|
+
(B6/B7/B10 still apply there).
|
|
78
|
+
- **B10 — rate limit (`DEXE_SIGNER_MAX_BROADCASTS_PER_MIN`).** Sliding 60s window,
|
|
79
|
+
serialized with `p-limit(1)`; rejects with a retry hint once the cap is hit.
|
|
80
|
+
|
|
81
|
+
See `docs/ENVIRONMENT.md` §4 and `SECURITY.md` for the full config block.
|
|
82
|
+
|
|
83
|
+
### Safe{Wallet} multisig signing (Track C)
|
|
84
|
+
|
|
85
|
+
- **New `dexe_safe_*` tool family (+2, total 129 → 131; new "Safe multisig" group → 15 groups).** Adds a signer mode that **queues** a transaction in the [Safe Transaction Service](https://docs.safe.global/) for owners to co-sign and execute, instead of broadcasting it from a single EOA. Designed for clients who custody the DAO/treasury operator key in a Gnosis Safe.
|
|
86
|
+
- **`dexe_safe_propose_tx`** — takes a `TxPayload` (`to`/`value`/`data`/`operation`) as produced by any `dexe_*_build_*` tool, reads the Safe's next `nonce()` on-chain (unless supplied), computes the EIP-712 `safeTxHash`, signs it with `DEXE_PRIVATE_KEY` (which must be a Safe owner), and assembles the create-multisig-transaction body. **`dryRun` defaults to `true`** — returns the full signed payload and the resolved POST target without sending. `dryRun=false` POSTs to the service (api.safe.global requires `DEXE_SAFE_API_KEY`). *Live POST validation is deferred pending a test Safe; build + dry-run paths are verified.*
|
|
87
|
+
- **`dexe_safe_info`** — read-only: live Safe nonce / threshold / owners / singleton version, whether the configured signer is an owner, and which Safe Transaction Service endpoint this chain resolves to.
|
|
88
|
+
- **`src/lib/ethersProvider.ts`** — new Safe ethers layer: `SAFE_ABI` + `readSafeState`, the `SafeTx` EIP-712 type set + `computeSafeTxHash`, and the `chainId → api.safe.global/tx-service/<shortname>/api/v2` endpoint resolver (override via `DEXE_SAFE_TX_SERVICE_URL`).
|
|
89
|
+
- **`dexe_get_config`** now reports `signerMode` (`"readonly"` | `"eoa"` | `"safe"`) plus a `safe` block (service URL + API-key configured flags), so an agent can tell at session start whether writes broadcast directly or queue to a multisig.
|
|
90
|
+
- **New env vars** — `DEXE_SAFE_TX_SERVICE_URL` (override / required for chains without a hosted service, e.g. BSC testnet) and `DEXE_SAFE_API_KEY` (Bearer token for api.safe.global). See [`docs/SAFE.md`](docs/SAFE.md) and [`docs/ENVIRONMENT.md`](docs/ENVIRONMENT.md). Closes security-hardening roadmap C13.
|
|
91
|
+
|
|
92
|
+
### Supply-chain hardening
|
|
93
|
+
|
|
94
|
+
- **npm provenance enabled.** New `.github/workflows/release.yml` triggered by `v*.*.*` tag push: runs typecheck + build + tests, verifies tag matches `package.json` version, then `npm publish --provenance --access public`. OIDC-signed attestation links every future tarball to the exact git commit and workflow run. Visible as a "Provenance" badge on npmjs.com. `publishConfig.provenance: true` is now baked into `package.json` so even manual `npm publish` (in an OIDC-enabled env) attaches an attestation. Requires repo secret `NPM_TOKEN`. Closes security-hardening roadmap A1.
|
|
95
|
+
- **OSSF Scorecard analysis.** New `.github/workflows/scorecard.yml` runs weekly (Sundays 04:00 UTC) and on push to `main`. Audits branch protection, token permissions, dependency hygiene, signed releases, and 15+ other checks. Publishes SARIF to GitHub code-scanning and a public score via OIDC to `api.securityscorecards.dev`. Badge usable at `https://api.securityscorecards.dev/projects/github.com/edward-arinin-web-dev/dexe-mcp/badge`.
|
|
96
|
+
- **Dependency Review on PRs.** New `.github/workflows/dependency-review.yml` runs on every PR touching deps. Fails the check on `high`-or-`critical` CVEs from GitHub Advisory Database, denies copyleft licenses (GPL/AGPL), and posts a PR comment when issues found. Blocks unsafe dep updates before merge.
|
|
97
|
+
- **`ci.yml` least-privilege.** Tightened top-level + job `permissions: contents: read` per Scorecard Token-Permissions check. Added `npm test` to PR/main pipeline (previously typecheck+build only). Closes security-hardening roadmap A4.
|
|
98
|
+
- **CodeQL static analysis.** New `.github/workflows/codeql.yml` runs the `security-extended` query suite against the `javascript-typescript` source on every PR/main push and weekly (Sundays 05:00 UTC). Catches prototype pollution, command injection, ReDoS, unsafe deserialization, path traversal, and other CWE patterns. Findings upload to GitHub code-scanning. Closes security-hardening roadmap A5.
|
|
99
|
+
- **CVE sweep after Dependabot activation.** Three new moderate CVEs surfaced when Dependency Graph was enabled on the repo. Resolved in this PR:
|
|
100
|
+
- `esbuild >=0.25.0` added to `overrides` (GHSA-67mh-4wv8-2f99 — dev server SSRF; transitive through vite/vitest/tsx).
|
|
101
|
+
- `ws >=8.20.1` added to `overrides` (GHSA-58qx-3vcg-4xpx — uninitialized memory disclosure; transitive through ethers).
|
|
102
|
+
- `vitest` bumped from `^2.1.0` to `^3.0.0` in devDependencies — pulls in vite ≥6.4.2 which patches the path-traversal CVE (GHSA-4w7w-66w2-5vf9).
|
|
103
|
+
- `npm audit` now reports **0 vulnerabilities** (both prod and dev).
|
|
104
|
+
- **`npm test` no-test-files tolerance.** Added `--passWithNoTests` to the `test` script so the CI/release pipeline doesn't fail on branches that don't yet have tests under their tree (e.g. this one — tests live on `governor-adapter`).
|
|
105
|
+
- **Lockfile integrity job.** New `verify-lockfile` job in `ci.yml` installs strictly from the committed `package-lock.json` via `npm ci` (which aborts if `package.json` and the lockfile are out of sync and never rewrites the lockfile), asserts the lockfile was not mutated (`git diff --exit-code package-lock.json`), and validates the full resolved tree with `npm ls --all`. Any drift — stale lockfile, hand-edit, or inconsistent override/peer resolution — fails the build before merge. Closes security-hardening roadmap A3.
|
|
106
|
+
- **Signed-tag enforcement on release.** `release.yml` now imports the maintainer's public key (repo secret `MAINTAINER_GPG_PUBLIC_KEY`) and runs `git verify-tag "$GITHUB_REF_NAME"` **before** the publish step. An unsigned tag, an invalid signature, or a tag from an unknown key aborts the release, so nothing reaches npm without a valid maintainer signature. Checkout switched to `fetch-depth: 0` + `fetch-tags: true` so the annotated tag object and its signature are available. Documented `git verify-tag` / `git tag -v` for consumers in `SECURITY.md` and `README.md`. Closes security-hardening roadmap A2. (GPG key generation is a separate maintainer step.)
|
|
107
|
+
|
|
108
|
+
## 0.5.8
|
|
109
|
+
|
|
110
|
+
DAO avatar pipeline — root-cause fix + three new composites.
|
|
111
|
+
|
|
112
|
+
### Avatar bug fixes (frontend rendering)
|
|
113
|
+
|
|
114
|
+
- **`dexe_ipfs_upload_file` now returns a CID v1 base32 string** (`bafy…`) as the primary `cid` field, with the original Pinata response preserved as `cidV0`. The DeXe frontend stores avatar URLs as `https://<cid>.ipfs.4everland.io/<file>`, and that subdomain gateway only resolves v1 — so the pre-0.5.8 server produced dead links every time an agent uploaded an avatar.
|
|
115
|
+
- **Image filenames are normalized to `.jpeg` for any `image/*` content type** (configurable via `normalizeImageExt: false`). Matches what `useCreateDAO` does in the frontend and what `parseAvatarFromIpfsResponse` expects when reading the profile back.
|
|
116
|
+
- **`dexe_ipfs_upload_dao_metadata` auto-converts any incoming `avatarCID` to v1 base32** before composing `avatarUrl`. Callers that previously passed in a v0 `Qm…` (which silently produced a dead link) now get a working URL.
|
|
117
|
+
|
|
118
|
+
### New tools (+3, total 126 → 129)
|
|
119
|
+
|
|
120
|
+
- **`dexe_ipfs_upload_avatar`** — one-shot composite. Takes base64 image bytes, normalizes the filename to `.jpeg`, pins, converts the CID to v1, and returns the exact `{avatarCID, avatarFileName, avatarUrl}` triple that `dexe_ipfs_upload_dao_metadata` and `dexe_ipfs_update_dao_metadata` accept. Removes a three-step manual chain.
|
|
121
|
+
- **`dexe_dao_generate_avatar`** — generates a deterministic placeholder. Initials of the DAO name over a hash-coloured gradient, emitted as plain SVG (no `<foreignObject>`, no JS) and pinned through Pinata. Same input always produces the same colours, so re-deploys keep the brand. No external image-generation provider involved.
|
|
122
|
+
- **`dexe_ipfs_update_dao_metadata`** — smart "modify DAO profile" helper. Fetches the current DAO descriptionURL JSON, applies only the fields you pass in `overrides` (avatar / name / website / description / socialLinks / documents), re-pins the merged result, and returns the new CID ready to feed into `dexe_proposal_build_modify_dao_profile.newDescriptionURL`. Eliminates the previous footgun where re-uploading metadata meant manually re-specifying every unchanged field — any forgotten field silently disappeared from the profile.
|
|
123
|
+
|
|
124
|
+
### Recommended modify-profile flow
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
1. dexe_ipfs_upload_avatar → {avatarCID, avatarFileName, avatarUrl}
|
|
128
|
+
(or dexe_dao_generate_avatar)
|
|
129
|
+
2. dexe_ipfs_update_dao_metadata → newDescriptionURL
|
|
130
|
+
3. dexe_proposal_build_modify_dao_profile → TxPayload
|
|
131
|
+
4. dexe_proposal_create → broadcast
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Supply-chain hygiene
|
|
135
|
+
|
|
136
|
+
- **Closes 4 transitive `npm audit` findings** under `@modelcontextprotocol/sdk@1.29.0`:
|
|
137
|
+
- `fast-uri` <=3.1.0 (high) — path-traversal + host-confusion (GHSA-q3j6-qgpj-74h6, GHSA-v39h-62p7-jpjc)
|
|
138
|
+
- `hono` <4.12.18 (moderate) — six advisories, incl. JSX HTML/CSS injection, JWT validation, cache-key leakage
|
|
139
|
+
- `ip-address` <=10.1.0 (moderate) — XSS in `Address6` HTML-emitting methods (GHSA-v2v4-37r5-5v8g)
|
|
140
|
+
- `express-rate-limit` (moderate)
|
|
141
|
+
- Resolved via `package.json` `overrides`. `@modelcontextprotocol/sdk` pin bumped from `^1.0.0` → `^1.29.0`. No public-API change.
|
|
142
|
+
- **`SECURITY.md`** added — vuln-disclosure policy, scoped threat model, contact email. Now ships in the tarball alongside `LICENSE`.
|
|
143
|
+
- **`.github/FUNDING.yml`** added (GitHub sponsors link).
|
|
144
|
+
|
|
145
|
+
`npm audit --omit=dev` now reports **0 vulnerabilities**.
|
|
146
|
+
|
|
147
|
+
## 0.5.7
|
|
148
|
+
|
|
149
|
+
Last broadcast sweep: **57 / 57 green** on Polaris (BSC testnet 97), 2026-05-12.
|
|
150
|
+
|
|
151
|
+
### Swarm coverage — 41 → 57 scenarios
|
|
152
|
+
|
|
153
|
+
- 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.
|
|
154
|
+
- 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.
|
|
155
|
+
- 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.
|
|
156
|
+
- Replaced retired Glacier fixture with fresh **Polaris** testnet DAO (LINEAR, 50% quorum, deployed 2026-05-12). Sentinel (validator chamber) unchanged. README updated.
|
|
157
|
+
|
|
158
|
+
### Swarm tooling
|
|
159
|
+
|
|
160
|
+
- **`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.
|
|
161
|
+
- **`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).
|
|
162
|
+
|
|
163
|
+
### Multi-chain config (chain-mixup guard)
|
|
164
|
+
|
|
165
|
+
- 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.
|
|
166
|
+
- 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.
|
|
167
|
+
- 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.
|
|
168
|
+
- 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.
|
|
169
|
+
- Provider and signer are now per-chain caches (`RpcProvider`, `SignerManager`) so multi-chain usage doesn't churn through new connections.
|
|
170
|
+
|
|
171
|
+
## 0.5.6
|
|
172
|
+
|
|
173
|
+
Three Stage A mainnet bug fixes — all surfaced on `DexeClientDemo`
|
|
174
|
+
(BSC `0xCAe3…5B41`) and tracked as bugs #29 / #30 / #31.
|
|
175
|
+
|
|
176
|
+
### Fixed
|
|
177
|
+
|
|
178
|
+
- **Bug #30 — `dexe_proposal_build_withdraw_treasury` emitted wrong
|
|
179
|
+
selector.** Builder targeted `GovPool.withdraw(address,uint256,uint256[])`
|
|
180
|
+
(selector `0xfb8c5ef0`), which is the user-deposit-withdraw function on
|
|
181
|
+
GovPool, not a treasury transfer. `proposal_create` rejected it with
|
|
182
|
+
`Gov: invalid internal data`. Rewritten to emit one external
|
|
183
|
+
`ERC20.transfer(receiver, amount)` action per token and/or one
|
|
184
|
+
`ERC721.transferFrom(govPool, receiver, tokenId)` action per NFT —
|
|
185
|
+
treasury sits in the GovPool address as a regular ERC20/721 balance, so
|
|
186
|
+
withdrawal is just a plain external token call. New schema: drop the
|
|
187
|
+
single `(amount, nftIds)` shape; supply `token`+`amount` and/or
|
|
188
|
+
`nftAddress`+`nftIds`. At least one must be non-empty.
|
|
189
|
+
|
|
190
|
+
- **Bug #29 — `apply_to_dao` / `token_transfer` / `withdraw_treasury` had
|
|
191
|
+
no blacklist precheck.** `ERC20Gov.transfer` reverts on a blacklisted
|
|
192
|
+
recipient, and a proposal that passes voting then fails `execute()` sits
|
|
193
|
+
in `SucceededFor` permanently with no recovery. When `DEXE_RPC_URL` is
|
|
194
|
+
set, the three builders now `isBlacklisted(receiver)` against the token
|
|
195
|
+
before encoding and refuse to build with a clear error if the recipient
|
|
196
|
+
is blacklisted. When the token isn't ERC20Gov (call reverts) or RPC is
|
|
197
|
+
absent, the precheck soft-skips with a note in the result detail —
|
|
198
|
+
build always proceeds. New helper: `src/lib/blacklist.ts`.
|
|
199
|
+
|
|
200
|
+
- **Bug #31 — `dexe_proposal_build_reward_multiplier` mint/change_token
|
|
201
|
+
reverted silently.** `ERC721_MULTIPLIER_ABI` declared `duration` as
|
|
202
|
+
`uint256`, but `ERC721Multiplier.mint(address,uint256,uint64,string)`
|
|
203
|
+
uses `uint64`. ethers derives the selector from the canonical signature,
|
|
204
|
+
so the wrong-typed arg produced a different selector → no-match →
|
|
205
|
+
silent revert with no returndata when GovPool.execute called into the
|
|
206
|
+
multiplier (the contract has no `MAX_MULTIPLIER` check, so the original
|
|
207
|
+
scale-mismatch hypothesis was wrong). Fixed the ABI to `uint64
|
|
208
|
+
duration`. Builder now also rejects `multiplier=0`, multiplier values
|
|
209
|
+
below `PRECISION/100` (likely forgot the 1e25 scale), `duration > 2^64
|
|
210
|
+
− 1`, and `duration=0` for mint. Tool description spells out
|
|
211
|
+
`PRECISION = 1e25` and `duration = seconds (uint64)`.
|
|
212
|
+
|
|
213
|
+
## 0.5.5
|
|
214
|
+
|
|
215
|
+
Doc + RPC hygiene. Two issues surfaced after publishing 0.5.4:
|
|
216
|
+
|
|
217
|
+
### Fixed
|
|
218
|
+
|
|
219
|
+
- **Internal RPC URL leaked into examples.** Three files referenced
|
|
220
|
+
`https://mbsc1.dexe.io/rpc`, an internal DeXe endpoint not intended for
|
|
221
|
+
public traffic. Replaced with the canonical public BSC RPC
|
|
222
|
+
`https://bsc-dataseed.binance.org` in:
|
|
223
|
+
- `docs/ENVIRONMENT.md` (3 occurrences — quick-start block, env table
|
|
224
|
+
example, BSC mainnet chain config)
|
|
225
|
+
- `tests/swarm/README.md` (`SWARM_RPC_URL_MAINNET` example)
|
|
226
|
+
- `tests/compat/FORM-GUIDE.md` (network-capture hint)
|
|
227
|
+
- `.env.example` (2 occurrences — `DEXE_RPC_URL` core block,
|
|
228
|
+
`SWARM_RPC_URL_MAINNET` swarm block)
|
|
229
|
+
- `scripts/swarm/test-mainnet-deploy.mjs` + `test-offchain-mainnet.mjs`
|
|
230
|
+
(now read `process.env.DEXE_RPC_URL` first, fall back to public BSC RPC)
|
|
231
|
+
Existing installs that copy-pasted the snippet still work — both URLs
|
|
232
|
+
serve BSC mainnet — but the public one carries no internal-infra hint.
|
|
233
|
+
- **README links broken on npmjs.com.** Relative links like
|
|
234
|
+
`./docs/TOOLS.md` work on GitHub but npm does NOT resolve them against the
|
|
235
|
+
repo URL — npm renders the README at the package home and a relative link
|
|
236
|
+
resolves to a non-existent path on `npmjs.com`. Converted all in-README
|
|
237
|
+
links to absolute GitHub URLs:
|
|
238
|
+
`./docs/X.md` → `https://github.com/edward-arinin-web-dev/dexe-mcp/blob/main/docs/X.md`
|
|
239
|
+
Same pattern applied to the swarm-runbook + LICENSE links.
|
|
240
|
+
|
|
241
|
+
### Scope of exposure
|
|
242
|
+
|
|
243
|
+
Verified via `npm pack --dry-run`: the internal URL was **never shipped in
|
|
244
|
+
any npm tarball**. `package.json`'s `files` array only includes `dist/`,
|
|
245
|
+
`README.md`, `CHANGELOG.md`, `FUTURE.md`, and `.mcp.example.json` — all of
|
|
246
|
+
which used the public BSC RPC. The leak was confined to GitHub-only
|
|
247
|
+
artifacts (`docs/`, `tests/`, gitignored `.env.example` + swarm probe
|
|
248
|
+
scripts). No npm-deprecation needed.
|
|
249
|
+
|
|
250
|
+
### Notes
|
|
251
|
+
|
|
252
|
+
- Git history retains the original URL — full history rewrite via
|
|
253
|
+
`git filter-repo` was considered and declined: rewrites every commit SHA,
|
|
254
|
+
breaks PR refs and external clones, and the URL is an endpoint, not a
|
|
255
|
+
credential. Forward-fix is sufficient.
|
|
256
|
+
|
|
257
|
+
## 0.5.4
|
|
258
|
+
|
|
259
|
+
Off-chain backend + DAO deploy hardening. Two latent bugs surfaced during
|
|
260
|
+
mainnet client-demo lifecycle on `0xCAe32Fa6e6D1C223Ed1047caA58F7fC0b2D65B41`
|
|
261
|
+
(BSC) — both fixed at the boundary so callers don't have to know.
|
|
262
|
+
|
|
263
|
+
### Fixed
|
|
264
|
+
|
|
265
|
+
- **`dexe_dao_build_deploy`** (`src/tools/daoDeploy.ts`) — pre-flight reject
|
|
266
|
+
when `tokenParams.cap == mintedTotal` while creating a new gov token.
|
|
267
|
+
ERC20Gov init reverted silently inside `_initGovPool` with the generic
|
|
268
|
+
`Address: low-level delegate call failed`, hiding the real cause behind a
|
|
269
|
+
10M-gas wasted tx. The validator now throws a clear message:
|
|
270
|
+
`cap must be strictly greater than mintedTotal; pass cap=0 for uncapped, or
|
|
271
|
+
cap > mintedTotal`. Tool description updated.
|
|
272
|
+
- **`dexe_proposal_build_offchain_single_option` / `_multi_option` /
|
|
273
|
+
`_for_against`** (`src/tools/proposalBuildOffchain.ts`) — backend rejected
|
|
274
|
+
every off-chain proposal with HTTP 400 `proposal type was not found` because
|
|
275
|
+
the builders sent `attributes.type = String(Math.floor(Date.now()/1000))`
|
|
276
|
+
(unix timestamp) instead of a registered template name. Constants now wired
|
|
277
|
+
per voting type:
|
|
278
|
+
- `default_single_option_type` for `voting_type=one_of`
|
|
279
|
+
- `default_multi_option_type` for `voting_type=multiple_of`
|
|
280
|
+
- `default_for_against_type` for `voting_type=for_against`
|
|
281
|
+
- **Off-chain quorum percentages** — same three builders. The backend stores
|
|
282
|
+
`*_percent` as fractions (`0.5` = 50%), but the inputs accept whole-number
|
|
283
|
+
percentages (`50` = 50%) for ergonomic parity with the frontend form.
|
|
284
|
+
Boundary now divides by 100 once, via a new `pctToFraction` helper.
|
|
285
|
+
|
|
286
|
+
### Verified
|
|
287
|
+
|
|
288
|
+
- Smoke-tested all three off-chain builders: `outer.type` and
|
|
289
|
+
`custom_parameters.type` carry the correct constants; quorum fractions match
|
|
290
|
+
backend examples (live proposal #58 created end-to-end against
|
|
291
|
+
`https://api.dexe.io`).
|
|
292
|
+
- DAO deploy: `cap == mintedTotal` rejected pre-flight with the new message;
|
|
293
|
+
`cap > mintedTotal` and `cap == 0` (uncapped) pass the check.
|
|
294
|
+
- `tsc` clean, no project-test regressions.
|
|
295
|
+
|
|
296
|
+
## 0.5.3
|
|
297
|
+
|
|
298
|
+
`getProposals` ABI fix for the post-upgrade GovPool layout. On-chain
|
|
299
|
+
`GovPool.getProposals(offset, limit)` now returns a single `ProposalView[]`
|
|
300
|
+
array — not the legacy 5-tuple `(Proposal[], ValidatorProposal[], uint8[],
|
|
301
|
+
uint256[], uint256[])`. Every multicall-backed reader was decoding against
|
|
302
|
+
the old shape and surfacing as `getProposals reverted` on every live mainnet
|
|
303
|
+
DAO (DeXe Protocol, BOXY, Carib, HackenDAO, …). Verified live decode on 4
|
|
304
|
+
DAOs after the patch.
|
|
305
|
+
|
|
306
|
+
### Fixed
|
|
307
|
+
|
|
308
|
+
- `dexe_proposal_list` (`src/tools/proposal.ts`) — ABI string + decoder
|
|
309
|
+
rewritten for the `ProposalView[]` shape. `requiredQuorum` now read
|
|
310
|
+
per-view instead of from a parallel array.
|
|
311
|
+
- `dexe_user_inbox` (`src/tools/inbox.ts`) — same ABI swap; voting-state
|
|
312
|
+
scan now indexes `views[i].proposal.core` / `views[i].proposalState`.
|
|
313
|
+
- `dexe_proposal_forecast` (`src/tools/predict.ts`) — same ABI swap;
|
|
314
|
+
history mapping reads `views[i].proposal.core.{executed,votesFor,
|
|
315
|
+
votesAgainst}`.
|
|
316
|
+
- `dexe_decode_proposal` (`src/tools/gov.ts`) — already correct (uses the
|
|
317
|
+
artifact ABI loaded by `dexe_compile`), no change.
|
|
318
|
+
|
|
319
|
+
### Notes
|
|
320
|
+
|
|
321
|
+
- Validators' `ProposalCore` differs from gov `ProposalCore`:
|
|
322
|
+
`(bool executed, uint56 snapshotId, uint64 voteEnd, uint64 executeAfter,
|
|
323
|
+
uint128 quorum, uint256 votesFor, uint256 votesAgainst)`. Don't reuse the
|
|
324
|
+
gov fragment when decoding `ExternalProposal`.
|
|
325
|
+
|
|
326
|
+
## 0.5.2
|
|
327
|
+
|
|
328
|
+
Subgraph auth fix. The Graph decentralized gateway now rejects requests
|
|
329
|
+
without `Authorization: Bearer <api-key>` — every subgraph-backed tool
|
|
330
|
+
(`dexe_read_dao_list`, `dexe_proposal_voters`, `dexe_user_inbox`, etc.) was
|
|
331
|
+
silently failing with HTTP 401 / "missing authorization header".
|
|
332
|
+
|
|
333
|
+
### Fixed
|
|
334
|
+
|
|
335
|
+
- `gqlRequest` (`src/lib/subgraph.ts`) now sends a Bearer token derived from
|
|
336
|
+
(in priority order): explicit `apiKey` arg → `DEXE_GRAPH_API_KEY` env →
|
|
337
|
+
auto-extracted from URL path (`/api/<key>/subgraphs/...`). Backward-compatible
|
|
338
|
+
with the legacy URL shape — no env or call-site changes required for users
|
|
339
|
+
whose key is already embedded in `DEXE_SUBGRAPH_*_URL`.
|
|
340
|
+
- HTTP error path now includes the gateway's response body (truncated to 200
|
|
341
|
+
chars) so 401/403 reasons surface in the thrown message.
|
|
342
|
+
|
|
343
|
+
### Added
|
|
344
|
+
|
|
345
|
+
- New optional env var `DEXE_GRAPH_API_KEY` for the Bearer-only URL shape
|
|
346
|
+
(`https://gateway.thegraph.com/api/subgraphs/id/<id>`). Documented in
|
|
347
|
+
`.env.example`.
|
|
348
|
+
- Exported helper `extractGraphApiKey(endpoint)` for reuse.
|
|
349
|
+
|
|
350
|
+
## 0.5.1
|
|
351
|
+
|
|
352
|
+
OTC tier rate-scaling guardrails. Production incident on 2026-05-04: a sale
|
|
353
|
+
proposal shipped with `exchangeRates: ["1e17"]` for "0.10 USDT/HELIO" — the
|
|
354
|
+
on-chain formula is `saleAmount = purchaseAmount * PRECISION / rate` with
|
|
355
|
+
`PRECISION = 10^25` (see `contracts/core/Globals.sol`), so the tier promised
|
|
356
|
+
buyers `10^7` more sale tokens than the tier could provide. Buys reverted
|
|
357
|
+
with `TSP: insufficient sale token amount` and the tiers had to be
|
|
358
|
+
recovered via `offTiers + recover`.
|
|
359
|
+
|
|
360
|
+
### Added
|
|
361
|
+
|
|
362
|
+
- New optional tier field `purchaseRatios: string[]` — human decimal ratios
|
|
363
|
+
(`"0.10"` = 0.10 purchase tokens per 1 sale token), auto-scaled with
|
|
364
|
+
`parseUnits(r, 25)`. Mutually exclusive with `exchangeRates`.
|
|
365
|
+
- Exported `PRECISION_DECIMALS = 25` constant from `proposalBuildComplex`.
|
|
366
|
+
|
|
367
|
+
### Changed
|
|
368
|
+
|
|
369
|
+
- `tierSchema.exchangeRates` is now optional. The schema enforces via
|
|
370
|
+
`.refine()` that exactly one of `exchangeRates` (raw 25-precision wei)
|
|
371
|
+
or `purchaseRatios` (decimals) is provided.
|
|
372
|
+
- `buildTierTuple` normalizes both shapes into raw 25-precision
|
|
373
|
+
`bigint[]` before encoding.
|
|
374
|
+
|
|
375
|
+
### Validation
|
|
376
|
+
|
|
377
|
+
- Raw `exchangeRates[i] < 10^18` now throws with a hint citing
|
|
378
|
+
`PRECISION = 10^25` — catches the unscaled-ratio mistake at build time
|
|
379
|
+
instead of on-chain. Existing fixtures (rates ≥ 1e18) remain
|
|
380
|
+
byte-identical (verified via `npm run test:compat`).
|
|
381
|
+
|
|
382
|
+
## 0.5.0
|
|
383
|
+
|
|
384
|
+
Transaction simulator gate, multi-DAO inbox + forecast + OTC discovery, and
|
|
385
|
+
frontend byte-diff harness. Adds preflight tools (catch reverts before
|
|
386
|
+
broadcast), the read-side "what needs my attention" loop (inbox +
|
|
387
|
+
forecast), OTC tier discovery, and a fixture-driven calldata-equivalence
|
|
388
|
+
test against the production DeXe frontend. **125 tools** total
|
|
389
|
+
(119 → 125).
|
|
390
|
+
|
|
391
|
+
### Added
|
|
392
|
+
|
|
393
|
+
**Simulator tools (3)**
|
|
394
|
+
- `dexe_sim_calldata` — generic preflight. Returns `{ success, revertReason?, returnData?, gasEstimate? }`. Decodes `Error(string)` (selector `0x08c379a0`) and `Panic(uint256)` revert payloads. Optional `from`/`value`/`blockTag` overrides.
|
|
395
|
+
- `dexe_sim_proposal` — preflight `GovPool.execute(proposalId)`. Reads proposal state first; refuses to sim unless `SucceededFor` (idx 4). Surfaces `proposalState` + `proposalStateIndex` for diagnostics.
|
|
396
|
+
- `dexe_sim_buy` — preflight `TokenSaleProposal.buy(...)`. Native path (paymentToken = `0x0`) sets `value=amount`. ERC20 path also reads current allowance and reports `willNeedApprove: true` when allowance < amount.
|
|
397
|
+
|
|
398
|
+
**Integration**
|
|
399
|
+
- `dexe_otc_buyer_buy` — new `simulateFirst?: boolean` flag. When true, runs `dexe_sim_calldata` on the encoded `buy()` payload before the broadcast/return path; aborts with the revert reason on failure. Ignored when `dryRun: true`.
|
|
400
|
+
|
|
401
|
+
**Frontend ↔ MCP byte-diff harness**
|
|
402
|
+
- `tests/compat/diff-otc.mjs` — fixture-driven runner. For each `tests/compat/fixtures/otc-frontend-*.json` it calls `buildTokenSaleMultiActions(input)` from compiled `dist/`, byte-compares every `actions[i].data` against the fixture, and on mismatch prints an ABI-decoded field-level diff via `Interface.parseTransaction`. Exit 0 = all green, 1 = at least one diverged. Wired as `npm run test:compat`.
|
|
403
|
+
- `tests/compat/gen-otc-fixtures.mjs` — fixture generator. Runs an *independent* synthesizer that mirrors the frontend hook's pipeline (lines 33-130 of `useGovPoolCreateTokenSaleProposal.ts`) **and** the MCP helper, asserts byte-identical calldata, then writes the fixture using the helper's output. Refuses to write on synth/helper divergence. Re-run after any helper refactor or frontend ABI bump.
|
|
404
|
+
- Three fixtures covering the canonical OTC shapes:
|
|
405
|
+
- `otc-frontend-1tier-open.json` — single open tier (no participation gating).
|
|
406
|
+
- `otc-frontend-2tier-merkle.json` — open + `MerkleWhitelist` (auto-derived root, no `addToWhitelist`).
|
|
407
|
+
- `otc-frontend-2tier-plain-whitelist.json` — open + plain `Whitelist` (auto-appended `addToWhitelist` action).
|
|
408
|
+
- `tests/compat/CAPTURE.md` — runbook documenting both capture methods (synthesizer + live WalletConnect intercept) and the form-field → TierSpec field map for re-capture.
|
|
409
|
+
|
|
410
|
+
**Docs + scenarios**
|
|
411
|
+
- `docs/SIMULATOR.md` — explains the three sim tools, response shapes, revert decoding, integration with `dexe_otc_buyer_buy`, and the limits of `eth_call`-based simulation (pending state, reorg risk, L2 divergence).
|
|
412
|
+
- `S47-sim-calldata-balance` — exercises `dexe_sim_calldata` calling `balanceOf` on the active chain's first allowlisted token; verifies `success: true` and a 32-byte return.
|
|
413
|
+
- `S48-sim-buy-no-tier` — exercises `dexe_sim_buy` against Glacier's TokenSaleProposal on BSC testnet with `tierId=999`; verifies `success: false` + revert reason set.
|
|
414
|
+
|
|
415
|
+
**Subgraph trio — read-side "what needs my attention" tools (3)**
|
|
416
|
+
- `dexe_user_inbox` — multi-DAO attention aggregator. Per DAO, surfaces
|
|
417
|
+
`unvotedProposal` items (Voting state + zero personal vote), `claimableRewards`
|
|
418
|
+
(non-zero pending rewards across the scanned window), and `lockedDeposit`
|
|
419
|
+
(UserKeeper.tokenBalance > 0). Mainnet auto-discovers DAOs via the pools
|
|
420
|
+
subgraph (`voterInPools` for the user, limit 50). Testnet requires explicit
|
|
421
|
+
`daos[]` since chain 97 has no subgraph. Read-only. See `docs/INBOX.md`.
|
|
422
|
+
- `dexe_proposal_forecast` — predictive pass-rate. Reads latest 10 proposals via
|
|
423
|
+
`getProposals(0, 10)` + their final states, computes historical pass-rate +
|
|
424
|
+
average For-vote weight, and returns `{ quorum, historicalPassRate, risks,
|
|
425
|
+
recommendation }`. `recommendation` is `likelyPass` / `borderline` /
|
|
426
|
+
`likelyFail` based on `hitProbability = clamp(projectedFor / required, 0, 1)`.
|
|
427
|
+
Mainnet only by default; pass `forceRpcOnly: true` to run on testnet.
|
|
428
|
+
- `dexe_otc_list_sales_for_dao` — OTC tier discovery. Reads `latestTierId()`
|
|
429
|
+
then `getTierViews(0, latestTierId)` on a DAO's TokenSaleProposal helper.
|
|
430
|
+
Returns tiers tagged with `status` (`upcoming` / `active` / `ended`)
|
|
431
|
+
computed against `block.timestamp`, plus aggregate counts. Works on both
|
|
432
|
+
chain 56 and chain 97 — no subgraph required. `totalSold` returns `null`
|
|
433
|
+
in v1 (not exposed via `getTierViews`).
|
|
434
|
+
|
|
435
|
+
**Tests**
|
|
436
|
+
- `S50-otc-list-for-dao.json` — chain 97, validates tier-list shape on
|
|
437
|
+
Glacier (zero tiers expected).
|
|
438
|
+
- `S51-inbox-with-supplied-daos.json` — chain 97/56, exercises
|
|
439
|
+
`dexe_user_inbox` with explicit `daos[]`.
|
|
440
|
+
|
|
441
|
+
### Notes
|
|
442
|
+
|
|
443
|
+
- Compat fixtures are **synthesized** for v1: the synthesizer encodes via the same canonical `TokenSaleProposal` ABI signature both the frontend artifact and `TOKEN_SALE_PROPOSAL_ABI` regenerate from (post-Bug #25 fix). Live WalletConnect-intercept re-cert is documented in `CAPTURE.md` and remains the ground-truth check after frontend major bumps.
|
|
444
|
+
- All three fixtures round-trip cleanly through `Interface.decodeFunctionData`.
|
|
445
|
+
|
|
446
|
+
### Follow-ups (v0.5.1+)
|
|
447
|
+
|
|
448
|
+
- `dexe_otc_list_active_sales` — cross-DAO global live-sale list. Requires a subgraph entity that doesn't exist yet.
|
|
449
|
+
- Per-DAO TokenSaleProposal helper auto-discovery from registry / deploy receipt so callers don't need to thread the address.
|
|
450
|
+
- State-override allowance for ERC20 sim path (currently flags `willNeedApprove`).
|
|
451
|
+
|
|
452
|
+
## 0.4.0
|
|
453
|
+
|
|
454
|
+
OTC DAO support. Adds the calldata builders, merkle utilities, and four
|
|
455
|
+
composite tools needed to launch and operate an over-the-counter token sale
|
|
456
|
+
end-to-end through one MCP surface. **119 tools** total. Lifecycle proven
|
|
457
|
+
on BSC testnet (deploy → open_sale → vote → execute → buy → claim →
|
|
458
|
+
balance delta verified).
|
|
459
|
+
|
|
460
|
+
### Added
|
|
461
|
+
|
|
462
|
+
**Phase A — calldata builders (4 tools)**
|
|
463
|
+
- `dexe_proposal_build_token_sale_multi` — N-tier sale envelope. Sums and dedupes ERC20 approves per sale token, auto-derives merkle roots for `MerkleWhitelist` tiers when only `users[]` is supplied, auto-appends `addToWhitelist` for plain `Whitelist` tiers.
|
|
464
|
+
- `dexe_proposal_build_token_sale_whitelist` — standalone external proposal that calls `addToWhitelist([{tierId, users[], uri}, …])` on a live tier.
|
|
465
|
+
- `dexe_proposal_build_token_sale` — kept as back-compat shim forwarding `[tier]` to `_multi`. Gains optional `participation` field.
|
|
466
|
+
- `dexe_merkle_build` / `dexe_merkle_proof` — OZ `StandardMerkleTree`-compatible: sorted-pair commutative keccak, double-hash leaf `keccak256(keccak256(abi.encode(...)))`. Default leaf shape `["address"]`; advanced shapes via `entries` + `leafEncoding`.
|
|
467
|
+
|
|
468
|
+
**Phase B — composite tools (4 tools)**
|
|
469
|
+
- `dexe_otc_dao_open_sale` — orchestrates `_multi` + `runProposalCreate` (balance/threshold check, approve, deposit, IPFS metadata, `createProposalAndVote`). `buildOnly: true` short-circuits the proposal flow and just returns the envelope. `dryRun: true` returns ordered TxPayloads even when `DEXE_PRIVATE_KEY` is set.
|
|
470
|
+
- `dexe_otc_buyer_status` — read-only aggregator. Multicalls `getTierViews` + `getUserViews(user, tierIds, proofs)`, surfaces participation requirements + pre-computed `claimable` (`canClaim && !isClaimed ? claimTotalAmount : 0`) and `vestingWithdrawable` (`amountToWithdraw`). Optional per-tier `whitelists[]` triggers merkle-tree build + proof + verify check for the user.
|
|
471
|
+
- `dexe_otc_buyer_buy` — preflights ERC20 balance + allowance (skipped on native sentinel `ZeroAddress`), prepends `approve(spender=TokenSaleProposal, MAX_UINT256)` when needed, builds `buy(tierId, paymentToken, amount, proof)`. Auto-derives the merkle proof when `whitelistUsers[]` is supplied without a precomputed `proof`. Native path sets `value=amount`.
|
|
472
|
+
- `dexe_otc_buyer_claim_all` — picks tiers with `canClaim && !isClaimed` → `claim`, tiers with `amountToWithdraw > 0` → `vestingWithdraw`. Skips silently when nothing pending (`mode='noop'`).
|
|
473
|
+
|
|
474
|
+
**Refactors**
|
|
475
|
+
- `proposalBuildComplex.ts` — extracted `buildTokenSaleMultiActions(input)` pure helper; `tierSchema`, `TierSpec`, `buildTierTuple`, `buildSaleApprovals`, `TOKEN_SALE_PROPOSAL_ABI` now exported. The `dexe_proposal_build_token_sale_multi` registrar is a thin shim around the helper.
|
|
476
|
+
- `flow.ts` — extracted `runProposalCreate(input, deps)` + `sendOrCollect` exported. `dexe_proposal_create` gains a `dryRun` flag. `sendOrCollect` distinguishes `mode='dryRun'` (caller-requested) from `mode='payloads'` (no signer); the swarm orchestrator's `mcpFallbackDispatcher` only auto-broadcasts on `'payloads'`.
|
|
477
|
+
|
|
478
|
+
**Docs + scripts**
|
|
479
|
+
- `docs/OTC.md` — project-owner + buyer flows with paste-ready examples. Documents every gotcha that bit during integration: PRECISION 1e25 (not 1e18) on `exchangeRates`; `canClaim` requires `block.timestamp >= saleEndTime + claimLockDuration` so buyers must wait for the sale window to close even with `claimLockDuration: 0`; `maxAllocationPerUser == 0` means unlimited (not zero); newly-passed proposals briefly land in `Locked` (idx 6) before `SucceededFor` (idx 4); treasury must be seeded with sale token (mint via `tokenParams.users[]` + predicted `govPool` address).
|
|
480
|
+
- `scripts/lifecycle-otc.mjs` — runnable end-to-end proof on BSC testnet (chain 97). Single command. Deploys a fresh DAO, opens a 1-tier sale, votes+executes, buys, claims, verifies balance delta.
|
|
481
|
+
|
|
482
|
+
**Swarm scenarios**
|
|
483
|
+
- `S41-otc-multi-merkle-build` — 2 tiers Open + MerkleWhitelist, auto-derived root.
|
|
484
|
+
- `S42-otc-multi-whitelist-build` — 2 tiers Open + plain Whitelist, auto-appended `addToWhitelist`.
|
|
485
|
+
- `S43-otc-whitelist-extend-build` — standalone `_whitelist` proposal extending an existing tier.
|
|
486
|
+
- `S44-otc-open-sale-build` — `buildOnly` envelope sanity.
|
|
487
|
+
- `S45-otc-buyer-buy-native-build` — `dryRun` + native sentinel.
|
|
488
|
+
- `S46-otc-buyer-buy-merkle-build` — `dryRun` + auto-merkle proof.
|
|
489
|
+
|
|
490
|
+
### Fixed
|
|
491
|
+
|
|
492
|
+
- **Bug #25** — `TOKEN_SALE_PROPOSAL_ABI` had two field-order transpositions vs the contract: `TierInitParams` swapped `saleTokenAddress` <-> `claimLockDuration`, and `VestingSettings` was declared `(cliff, step, duration, percentage)` instead of canonical `(percentage, duration, cliff, step)`. Selector matched (`0x6a6effda`) but calldata was silently misdecoded — every prior single-tier sale proposal built via dexe-mcp landed with vesting + claim-lock fields scrambled.
|
|
493
|
+
- **Bug #26** — `getUserViews` ABI in `read.ts` (and copied into `otc.ts`) declared `UserView` as a flat 7-field struct (`canParticipate, isWhitelisted, purchasedAmount, owedAmount, lockedAmount, claimableAmount, vestingWithdrawAmount`). Actual contract returns `tuple(bool canParticipate, PurchaseView purchaseView, VestingUserView vestingUserView)` with nested structs. Both files now match the contract; affected callers (`dexe_read_token_sale_user`, `dexe_otc_buyer_status`, `dexe_otc_buyer_claim_all`) updated to read fields via the correct paths.
|
|
494
|
+
- **Bug #27** — `getUserViews` is a 3-arg function (`address user, uint256[] tierIds, bytes32[][] proofs`); ABI was missing the third parameter, causing every call to revert with `require(false)` at the abicoder layer. Fixed in both `read.ts` and `otc.ts`; non-merkle tiers pass `tierIds.map(() => [])`.
|
|
495
|
+
- **`flow.ts` `vote_and_execute` Locked state.** When `open_sale`'s `createProposalAndVote` clears quorum + earlyCompletion, the proposal lands directly in state 6 (`Locked`) before transitioning to `SucceededFor`. The skip-vote-and-execute branch only matched 4/5; now also matches 6.
|
|
496
|
+
- **`otc.ts` multicall double-unwrap.** Single-return-value functions are already unwrapped by `src/lib/multicall.ts`; the OTC composites were treating the result as one extra layer deep and indexing `[0]`. Fixed.
|
|
497
|
+
|
|
498
|
+
### Lifecycle proof
|
|
499
|
+
|
|
500
|
+
Live run on BSC testnet (chain 97) on 2026-05-01:
|
|
501
|
+
- govPool: `0x028C447c72A6Fd1955f0937bb3C5926E8EAC297c`
|
|
502
|
+
- deploy tx: `0x3e17ff4e46a6840bf4945e15a9c3af620be276b7de0e1efe807e08ec8a097dbe`
|
|
503
|
+
- execute proposal 1: `0x17b677e3fb0b078ca670d3a16c3a776cc36dac97e4497446b19d6490633873df`
|
|
504
|
+
- buyer balance: `400000.0` → `399999.0` (buy) → `400000.0` (claim) — delta verified
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## 0.3.0
|
|
509
|
+
|
|
510
|
+
End-to-end testnet validation. Every proposal-builder tool is now exercised by an automated swarm scenario on BSC testnet, and the harness itself ships in-repo so external integrators can run it. **111 tools** total, **41 swarm scenarios**, full sweep green.
|
|
511
|
+
|
|
512
|
+
### Added
|
|
513
|
+
|
|
514
|
+
**Swarm test harness (`tests/swarm/` + `scripts/swarm/`)**
|
|
515
|
+
- `scripts/swarm/orchestrator.ts` — scenario loader + dispatcher. Inline ethers dispatchers for the no-IPFS toolset (vote_user_power, read_delegation_map, build_undelegate, build_withdraw, build_withdraw_all, build_erc20_approve, build_deposit, build_delegate, build_vote). Generic MCP-stdio fallback (`mcpFallbackDispatcher`) routes anything else through the dexe-mcp child server, so adding a scenario for a new tool is JSON-only — no code changes.
|
|
516
|
+
- Loop expansion (`spec.loop.over` × `appliesToSteps`), template engine (`{{dao}}`, `{{firstAllowlistedToken}}`, `{{firstAllowlistedDao}}`, `{{secondAllowlistedDao}}`, `{{dao.<helper>}}`, `{{agent:X:address}}`, `{{capture.path}}`, `{{capture.0.field}}`), `skipIf` evaluator with limited expressions, deferred-cascade for chained captures, wallet semaphore for parallel-safe broadcasts, per-scenario `prefund` hook that tops up agents from `AGENT_FUNDER_PK` before each scenario runs.
|
|
517
|
+
- `scripts/swarm/preflight.ts` + `scripts/swarm/fund-pool.ts` — wallet-readiness check + token allowlist–enforced top-up. Hard-refuses to send to any non-pool address or any token not on the allowlist.
|
|
518
|
+
- `scripts/swarm/nightly.sh` — Phase 5 cron runner. Pulls main, runs preflight + full sweep, tails the run report, posts the one-line summary to `SWARM_SUMMARY_WEBHOOK` and/or `SWARM_SUMMARY_ISSUE` (gh CLI), runs a triage stub on failure (with `SWARM_FIXER=1` opt-in for auto-fix), and rotates run-report dirs older than 30 days while keeping the latest 50.
|
|
519
|
+
- `scripts/swarm/orchestrator.ts` emits a single greppable summary line after `writeReport`: `SWARM <runId> <pass>/<total> <mode> <chainTag> <reportPath>` — consumed by nightly.sh and any external poster.
|
|
520
|
+
- `scripts/swarm/one-shot-execute.mjs` — closes a proposal lifecycle once it reaches `SucceededFor`. Polls + caps `wait()` at 90 s to avoid sandbox hangs.
|
|
521
|
+
- 41 scenario JSONs covering: reset, delegation chain, validator pass / veto / full lifecycle, expert / participation / staking / validator / catalog / cross-DAO / multi-proposal-state read snapshots, cancel-vote, decode-and-introspect, build-only sanity for every external + internal proposal type from `dexe_proposal_catalog`.
|
|
522
|
+
- Role prompts: `proposer`, `voter`, `delegator`, `reporter`, `triage`, `validator`, `expert`, `fixer`, plus `_shared.md` and the dao-personas fixture. Fixer prompt encodes the CLAUDE.md auto-fix loop verbatim — branch `swarm-fix/<YYYY-MM-DD>`, never push to main, diff scope hard-bounded to `src/tools/`, `src/lib/`, `tests/swarm/`.
|
|
523
|
+
|
|
524
|
+
**Composite + signing tools**
|
|
525
|
+
- `dexe_proposal_create` — full prerequisite handling: balance check, ERC20 approve, deposit, IPFS metadata upload, `createProposalAndVote`. When `DEXE_PRIVATE_KEY` is set the tool signs and broadcasts; otherwise returns the ordered `TxPayload` list. Supports `proposalType: 'modify_dao_profile' | 'custom'`.
|
|
526
|
+
- `dexe_proposal_vote_and_execute` — vote-then-execute composite with `autoExecute` + `depositFirst` flags.
|
|
527
|
+
- `dexe_tx_send` + `dexe_tx_status` — opt-in signer surface that uses the configured `DEXE_PRIVATE_KEY` when present. Calls remain calldata-by-default; users opt in by setting the env var.
|
|
528
|
+
- `dexe_dao_build_deploy` predicted-address auto-wiring: `govToken` flowed into `userKeeperParams.tokenAddress` and `distributionProposal` + `govTokenSale` into `additionalProposalExecutors` automatically. LINEAR / POLYNOMIAL `votePower` initData auto-encoded.
|
|
529
|
+
|
|
530
|
+
**Reads + introspection**
|
|
531
|
+
- `dexe_read_dao_list`, `_dao_members`, `_dao_experts`, `_user_activity`, `_distribution_status`, `_token_sale_tiers`, `_token_sale_user`, `_staking_info`, `_validator_list`, `_privacy_policy_status`, `_delegation_map` — fill out the DAO read surface.
|
|
532
|
+
- `dexe_get_methods` returns structured per-function metadata (4-byte selectors, mutability, full structured inputs/outputs with `internalType` preserved for tuples).
|
|
533
|
+
- `dexe_proposal_voters` switched to the `pools` subgraph and the proposalInteractions composite ID format (poolAddr + uint32LE(proposalId), no separator).
|
|
534
|
+
- `dexe_decode_proposal` understands every external + internal proposal action shape.
|
|
535
|
+
|
|
536
|
+
### Fixed
|
|
537
|
+
|
|
538
|
+
- **Proposal metadata format**: builders now emit `proposalName` / `proposalDescription` (not `name` / `description`), wrap diffs inside `changes: { proposedChanges, currentChanges }`, set `isMeta: false`, and round-trip identical to the frontend reference. 17 builders touched.
|
|
539
|
+
- **Approve target for deposits** is `UserKeeper`, not `GovPool`. Both flow tools (`proposal_create`, `vote_and_execute`) now approve the right address.
|
|
540
|
+
- **Personal voting power** = `tokenBalance.balance − ownedBalance` (deposited only). Without this, `withdraw` on freshly-funded agents reverts `GovUK: can't withdraw this`.
|
|
541
|
+
- **VotePower initData** uses `__LinearPower_init()` selector `0x892aea1f` (not empty `0x`) so newly-deployed DAOs initialize their LINEAR vote-power proxy correctly.
|
|
542
|
+
- **`STATE_NAMES` enum order** corrected (Defeated / Locked positions were swapped).
|
|
543
|
+
- **Custom-proposal IPFS metadata** now includes `category`, `isMeta`, `proposedChanges`, `currentChanges`.
|
|
544
|
+
- **Subgraph migration**: Studio URLs deprecated; switched to The Graph decentralized network with API key. Per-chain endpoints documented.
|
|
545
|
+
- **IPFS gateway path normalization**: dedicated gateways configured with a trailing `/ipfs` (e.g. `https://<sub>.mypinata.cloud/ipfs`) no longer produce `/ipfs/ipfs/<cid>` 404s.
|
|
546
|
+
|
|
547
|
+
### Changed
|
|
548
|
+
|
|
549
|
+
- README updated: tool count `83 → 111`, new "Swarm test harness" section.
|
|
550
|
+
- `process.loadEnvFile()` is invoked from `index.ts` so the MCP server loads `.env` itself; users no longer have to plumb env-var changes through their MCP client config (which often doesn't reload).
|
|
551
|
+
- Repo now ships `.claude/skills/swarm-test/SKILL.md` for users running Claude Code; lets them invoke the swarm with `/swarm-test`.
|
|
552
|
+
|
|
553
|
+
### Notes
|
|
554
|
+
|
|
555
|
+
- **Validated network**: BSC testnet (chain 97). Two fixture DAOs deployed for the harness — Glacier (50% quorum, no validators) and Sentinel (5% quorum, 2 validators with 1k SVT each).
|
|
556
|
+
- **Mainnet status**: a separate run pass is staged (Stage B per `tests/swarm/README.md`) but blocked on a previously-observed `PoolFactory.deployGovPool` revert. Re-validate when the protocol team confirms a fix.
|
|
557
|
+
- **Off-chain backend tools** require `DEXE_BACKEND_API_URL` and only run on chains where DeXe operates a backend. The corresponding swarm scenarios declare `requiresChain: [56]` so they auto-skip on testnet.
|
|
558
|
+
|
|
559
|
+
## 0.2.0
|
|
560
|
+
|
|
561
|
+
The big one — dexe-mcp expands from 15 dev-tooling tools to **83 tools** covering the full DeXe DAO lifecycle. AI agents can now create DAOs, build any of the 33 proposal types the DeXe frontend exposes, upload metadata to IPFS, stake/delegate/vote/execute/claim — all end-to-end.
|
|
562
|
+
|
|
563
|
+
### Added
|
|
564
|
+
|
|
565
|
+
**Foundations + reads (13 tools)** — `dexe_dao_info`, `dexe_dao_predict_addresses`, `dexe_dao_registry_lookup`, `dexe_proposal_state`, `dexe_proposal_list`, `dexe_proposal_voters`, `dexe_vote_user_power`, `dexe_vote_get_votes`, `dexe_read_multicall`, `dexe_read_treasury`, `dexe_read_validators`, `dexe_read_settings`, `dexe_read_expert_status`. Backed by an `AddressBook` that resolves contracts via `ContractsRegistry`, a Multicall3 batch helper, a canonical `TxPayload` shape, enum mirrors for `ProposalState` / `VoteType`, and a minimal subgraph GraphQL client.
|
|
566
|
+
|
|
567
|
+
**IPFS (6 tools)** — `dexe_ipfs_upload_proposal_metadata`, `_upload_dao_metadata`, `_upload_file`, `_fetch`, `_cid_info`, `_cid_for_json`. Backed by a Pinata client and local CID computation via `multiformats`. Public gateways (dweb.link, ipfs.io, cf-ipfs, 4everland) are unreliable and NOT defaulted. Users must set `DEXE_IPFS_GATEWAY` to a dedicated gateway (the one Pinata provides alongside the JWT is recommended). Public gateways are opt-in via `DEXE_IPFS_GATEWAYS_FALLBACK` (comma-separated, tried sequentially — no parallel races).
|
|
568
|
+
|
|
569
|
+
**Proposals — all 33 types (35 tools)**
|
|
570
|
+
- `dexe_proposal_catalog` — enumerate every proposal type the DeXe UI exposes (24 external, 4 internal, 5 off-chain), with metadata shape, gating, and linked MCP builder.
|
|
571
|
+
- Primitives: `dexe_proposal_build_external` (+ `createProposalAndVote`), `dexe_proposal_build_internal`, `dexe_proposal_build_custom_abi`, `dexe_proposal_build_offchain`.
|
|
572
|
+
- External wrappers (each returns `{ metadata, actions: Action[] }`): `token_transfer`, `token_distribution`, `token_sale`, `token_sale_recover`, `change_voting_settings`, `manage_validators`, `add_expert`, `remove_expert`, `withdraw_treasury`, `delegate_to_expert`, `revoke_from_expert`, `create_staking_tier`, `change_math_model`, `modify_dao_profile`, `blacklist`, `reward_multiplier`, `apply_to_dao`, `new_proposal_type` (also covers *Enable Staking*).
|
|
573
|
+
- Internal validator wrappers (each returns `{ metadata, proposalType, data }`): `change_validator_balances` (type 0), `change_validator_settings` (type 1), `monthly_withdraw` (type 2), `offchain_internal_proposal` (type 3).
|
|
574
|
+
- Off-chain backend proposals: `offchain_single_option`, `offchain_multi_option`, `offchain_for_against`, `offchain_settings`. Plus `dexe_auth_request_nonce` + `dexe_auth_login_request` for the 2-step Bearer flow, and `dexe_offchain_build_vote` / `dexe_offchain_build_cancel_vote`.
|
|
575
|
+
- **Write model is calldata-only.** No signer, no private keys. Every write tool emits a signable payload the agent's wallet submits.
|
|
576
|
+
|
|
577
|
+
**Vote / stake / execute / claim writes (14 tools)** — `erc20_approve`, `deposit` (payable for native-staking DAOs), `withdraw`, `delegate`, `undelegate`, `vote`, `cancel_vote`, `validator_vote`, `validator_cancel_vote`, `move_to_validators`, `execute`, `claim_rewards`, `claim_micropool_rewards`, plus `multicall` to batch any of the above into one atomic tx. Arg-order gotchas captured in code comments (e.g. `GovPool.vote(pid, isFor, amount, nftIds)` vs `GovValidators.voteInternalProposal(pid, amount, isFor)`).
|
|
578
|
+
|
|
579
|
+
**DAO deploy (1 tool)** — `dexe_dao_build_deploy` encodes `PoolFactory.deployGovPool(GovPoolDeployParams)` with the full nested struct (settings / validators / userKeeper / token / votePower / verifier / BABT flag / descriptionURL / name). Auto-resolves PoolFactory via `ContractsRegistry` if omitted. When `deployer` + RPC are available, also returns the predicted GovPool address so agents can wire follow-up txs before the DAO exists. Encodes against the compiled `PoolFactory.json` artifact when present (strict parity); falls back to a hand-rolled tuple signature derived from `IPoolFactory.sol` otherwise.
|
|
580
|
+
|
|
581
|
+
### Changed
|
|
582
|
+
|
|
583
|
+
- `src/config.ts` adds `DEXE_CHAIN_ID` (default 56), `DEXE_CONTRACTS_REGISTRY` override, `DEXE_PINATA_JWT`, three subgraph URL overrides, `DEXE_BACKEND_API_URL`.
|
|
584
|
+
- `package.json` description rewritten to reflect full DAO-ops scope. New dep: `multiformats` (Protocol Labs, for local CID computation).
|
|
585
|
+
- `README.md` reorganized around the eight tool groups; added the full env-var matrix.
|
|
586
|
+
|
|
587
|
+
### Notes
|
|
588
|
+
|
|
589
|
+
- **No breaking changes.** All v0.1.x tools remain. The write contract is new-world: `TxPayload` for single-tx builders, `Action[]` for proposal wrappers — never a singular `action` field.
|
|
590
|
+
- **Deferred to future work** (`FUTURE.md`): Hardhat-fork simulation (`dexe_simulate_vote`), signer-aware send mode, additional IPFS pinning providers (Storacha, Lighthouse), and alternate subgraphs.
|
|
591
|
+
|
|
592
|
+
## 0.1.5
|
|
593
|
+
|
|
594
|
+
### Fixed
|
|
595
|
+
- **`'npx' is not recognized`** from inside `npm run compile` (and other npm scripts that internally call `npx hardhat …`) on stripped-Node Windows installs. v0.1.4 got `npm` itself spawning cleanly, but DeXe-Protocol's `compile` script is literally `npx hardhat compile --force`, and when npm spawned that child, `cmd.exe` couldn't find `npx.cmd` on PATH — the stripped `C:\Program Files\nodejs\` has `node.exe` only. Root cause: we weren't propagating the resolved Node's shim directory into the child's `PATH`.
|
|
596
|
+
- New `deriveNodeBinDir()` + `envWithNodeBinDir()` helpers in `src/runtime.ts` derive the directory containing `npm.cmd`/`npx.cmd` (Windows) or `bin/npm`/`bin/npx` (Unix) from the resolved `npm-cli.js` path, and prepend it to `PATH` on every child spawn (`bootstrap` npm install, `runNpmScript`, `runHardhat`). Child shells launched by npm scripts can now resolve `npx` / `npm` / any locally-installed binary as expected.
|
|
597
|
+
- `npmCommand()` now returns a `binDir` field alongside `command` / `prefixArgs` / `needsShell`. Bootstrap logs the prepended directory on first run so it's visible which Node install is contributing the shims.
|
|
598
|
+
|
|
599
|
+
## 0.1.4
|
|
600
|
+
|
|
601
|
+
### Fixed
|
|
602
|
+
- **`spawn EINVAL` during first-run `npm install`** on Windows hosts where `process.execPath` points at a Node install that does not bundle npm (e.g. a bare `node.exe` dropped under `C:\Program Files\nodejs\` without the rest of the toolchain). Two root causes addressed:
|
|
603
|
+
1. `resolveNpmCli()` now searches a broader set of locations for a usable `npm-cli.js` — including `%APPDATA%\nvm\v*\node_modules\npm\bin\npm-cli.js` (nvm-windows), `%APPDATA%\npm\node_modules\npm\bin\npm-cli.js` (per-user npm prefix), `C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js` (stock Windows installer), `~/.nvm/versions/node/v*/lib/node_modules/npm/bin/npm-cli.js` (nvm Unix), and Homebrew paths. Because `npm-cli.js` is plain JavaScript, *any* modern `node` can execute any of these, so the MCP process's own Node is free to "borrow" npm from a completely different Node install.
|
|
604
|
+
2. When no `npm-cli.js` is found anywhere and we fall back to spawning `npm.cmd` directly, `execFile` / `execa` now pass `{ shell: true }` — without it, Node refuses to spawn `.cmd` / `.bat` files (CVE-2024-27980 mitigation) and throws `spawn EINVAL`.
|
|
605
|
+
- Progress logging on first bootstrap now prints the resolved `npm-cli.js` path (or "shell-resolved" fallback), so "which npm is about to run" is visible in stderr.
|
|
606
|
+
|
|
607
|
+
## 0.1.3
|
|
608
|
+
|
|
609
|
+
### Docs
|
|
610
|
+
- **Windows install section rewritten** to lead with the absolute-path recipe (`node <abs path to dist/index.js>`) instead of `cmd /c dexe-mcp`. End-to-end testing against Claude Code on Windows showed the `cmd /c` wrapper, while standalone functional, did not reliably complete the MCP handshake when spawned by Claude Code — the absolute-path recipe has zero shim resolution and is known-working.
|
|
611
|
+
- **New prereq step**: verify `npm --version` actually runs in your shell *before* attempting `npm install -g dexe-mcp`. Users with a stripped `node.exe`-only install (common on Windows) will hit a silent `npm i -g` no-op otherwise, with no visible error.
|
|
612
|
+
- Added a "Verify the install" section showing how to smoke-test `dexe-mcp` over stdio without involving Claude Code, so users can distinguish "MCP server broken" from "client registration broken".
|
|
613
|
+
|
|
614
|
+
No code changes — 0.1.3 is a docs-only patch on top of 0.1.2's behavior.
|
|
615
|
+
|
|
616
|
+
## 0.1.2
|
|
617
|
+
|
|
618
|
+
### Fixed
|
|
619
|
+
- **Server no longer hangs / fails on first launch.** The heavy `git clone` + `npm install` bootstrap is now lazy — it runs only when a build tool (`dexe_compile`, `dexe_test`, `dexe_coverage`, `dexe_lint`) is first invoked, not inside MCP `initialize()`. Previously the MCP handshake would block for minutes or time out, and crash outright on hosts where `npm` / `git` were not on the spawned process's PATH.
|
|
620
|
+
- **PATH-independent spawning of `npm` and `hardhat`.** The runner now invokes `node <npm-cli.js>` and `node <protocol>/node_modules/hardhat/internal/cli/cli.js` directly via `process.execPath`, so it works on Windows installs where `npm.cmd` / `npx.cmd` aren't on the MCP client's spawn PATH (common with nvm-windows and with stripped `node.exe`-only installs).
|
|
621
|
+
- **Actionable error messages** when `git` is not installed, when `DEXE_PROTOCOL_PATH` points at a non-Hardhat directory, or when the user-managed checkout is missing `node_modules`.
|
|
622
|
+
- Concurrent build-tool calls now coalesce into a single bootstrap instead of racing `git clone` / `npm install`.
|
|
623
|
+
|
|
624
|
+
### Changed
|
|
625
|
+
- `loadConfig()` no longer hard-fails when the DeXe-Protocol checkout is missing or incomplete at startup — it logs a soft warning to stderr and defers preparation to the first build-tool invocation.
|
|
626
|
+
- `src/bootstrap.ts` split into `resolveProtocolPath()` (cheap, startup-safe) and `ensureBuildReady()` (lazy, idempotent).
|
|
627
|
+
- New `src/runtime.ts` with portable `npmCommand()` / `hardhatCommand()` / `hasGit()` helpers.
|
|
628
|
+
|
|
629
|
+
### Docs
|
|
630
|
+
- README now has an OS-specific install matrix (Mac/Linux vs. Windows) and a "dev / local checkout" recipe. Troubleshooting section updated for the new lazy-bootstrap behavior and the `process.execPath` npm resolution.
|
|
631
|
+
|
|
632
|
+
## 0.1.1
|
|
633
|
+
|
|
634
|
+
### Added
|
|
635
|
+
- `dexe_get_methods` introspection tool — returns per-contract methods partitioned into `read` (view/pure) and `write` (nonpayable/payable). Each entry includes `name`, canonical `signature`, 4-byte `selector`, `stateMutability`, and structured `inputs`/`outputs` with `internalType` preserved (so tuple-typed args like `IGovPool.ProposalView[]` survive intact). Designed for generating TypeScript interfaces or ethers wrappers without re-parsing raw ABIs. Supports `kind` filter (`read`/`write`/`all`) and optional `includeEvents`/`includeErrors`.
|
|
636
|
+
|
|
637
|
+
Tool count: 14 → 15.
|
|
638
|
+
|
|
639
|
+
## 0.1.0
|
|
640
|
+
|
|
641
|
+
Initial public release (Phase A): build/test, contract introspection, read-only governance tools. 14 tools.
|