@darksol/terminal 0.12.0 → 0.13.1

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.
@@ -0,0 +1,241 @@
1
+ # @darksol/terminal — Full Audit Report
2
+ **Version:** 0.12.0 | **Test run:** 130 pass / 0 fail | **Files reviewed:** 47
3
+ **Date:** 2026-03-14
4
+
5
+ ---
6
+
7
+ ## 1. Architecture Overview
8
+
9
+ **Entry point:** `bin/darksol.js` → `src/cli.js` (Commander.js, ESM, Node ≥18)
10
+
11
+ ```
12
+ src/
13
+ ├── cli.js ← 1500+ line monolith; all commands wired here
14
+ ├── agent/ ← LLM tool-calling loop (OpenAI/Anthropic function-calling)
15
+ │ ├── index.js, loop.js, autonomous.js, strategy-evaluator.js, tools.js
16
+ ├── config/
17
+ │ ├── store.js ← conf-backed typed config
18
+ │ └── keys.js ← AES-256-GCM encrypted API key vault
19
+ ├── daemon/ ← generic service registry (start/stop/status/PID)
20
+ ├── llm/
21
+ │ ├── engine.js ← multi-provider (OpenAI/Anthropic/OpenRouter/Ollama)
22
+ │ ├── intent.js ← NL → structured intent parser
23
+ │ └── models.js ← model catalog + capability metadata
24
+ ├── memory/index.js ← JSON append-log memory
25
+ ├── scripts/engine.js ← user script CRUD + new Function() executor
26
+ ├── services/ ← 14 service modules (casino, oracle, cards, facilitator,
27
+ │ gas, lifi, market, mail, builders, telegram, watch,
28
+ │ whale, whale-monitor, skills, browser)
29
+ ├── soul/index.js ← agent personality/tone
30
+ ├── trading/ ← swap.js, snipe.js, dca.js
31
+ ├── ui/ ← chalk, ora, cli-table3 wrappers
32
+ ├── utils/ ← fetch.js, helpers.js, x402.js
33
+ ├── wallet/ ← keystore, manager, agent-signer, portfolio, history
34
+ └── web/ ← embedded web terminal (http.createServer)
35
+ ```
36
+
37
+ **Dep graph:** cli.js imports from virtually every layer. Services are leaf nodes. x402.js is depended on by poker, oracle, casino. whale-monitor.js has a side-effect import (calls registerService at load).
38
+
39
+ ---
40
+
41
+ ## 2. Code Quality
42
+
43
+ ### ✅ Positives
44
+ - Consistent spinner → success/fail pattern across all services
45
+ - Good JSDoc on public functions
46
+ - Clean separation: config/store vs config/keys vs wallet/keystore
47
+ - Dependency injection on poker.js and whale.js makes them genuinely testable
48
+ - 130 tests passing, zero failures
49
+
50
+ ### ❌ Issues
51
+ - **`warn` not imported in cards.js** — will crash with ReferenceError on invalid denomination/provider
52
+ - **`formatCompact()` duplicated** in market.js (already exists in utils/helpers.js)
53
+ - **`topMovers()` makes unused HTTP call** — fetches trending endpoint, discards result
54
+ - **ERC-20 ABI fragments duplicated** across swap.js, portfolio.js, whale.js, scripts/engine.js
55
+ - **Explorer API URLs duplicated** between wallet/history.js and services/whale.js
56
+ - **ora + nanospinner both in deps** — redundant spinner libraries
57
+ - **cli.js is 1500+ lines** — should split into command modules
58
+ - **Error handling inconsistent** — most use spin.fail(), but watch.js and market.js use raw console.log
59
+
60
+ ---
61
+
62
+ ## 3. Security Review
63
+
64
+ ### 🔴 CRITICAL — x402 nonce uses Math.random()
65
+
66
+ **File:** `src/utils/x402.js`
67
+
68
+ EIP-3009 nonce is generated with Math.random() — NOT cryptographically secure. This nonce authorizes USDC transfers on mainnet. A compromised PRNG seed allows replay attacks.
69
+
70
+ **Fix:** `import { randomBytes } from 'crypto'; const nonce = '0x' + randomBytes(32).toString('hex');`
71
+
72
+ ### 🟠 HIGH — Key vault uses machine-derived password
73
+
74
+ **File:** `src/config/keys.js`
75
+
76
+ API keys stored via wizard are encrypted with `darksol-vault-${hostname()}-${username}` — predictable, derivable by any process running as the same user. Users aren't warned.
77
+
78
+ **Fix:** Document weak vs strong protection clearly. Better: OS keychain or prompted master password.
79
+
80
+ ### 🟠 HIGH — Script execution is not sandboxed
81
+
82
+ **File:** `src/scripts/engine.js`
83
+
84
+ `new Function()` executes in global scope with full Node.js access. The unlocked private key signer is passed into script context. This is correct for user scripts, but needs a bold warning before execution.
85
+
86
+ ### 🟡 MEDIUM — node-fetch `timeout` silently ignored
87
+
88
+ **Files:** `src/utils/x402.js`, `src/services/browser.js`
89
+
90
+ node-fetch v3 dropped the timeout option. Calls with `{ timeout: 2000 }` will block indefinitely on hung connections.
91
+
92
+ **Fix:** Use `AbortSignal.timeout(2000)` or manual AbortController.
93
+
94
+ ### 🟡 MEDIUM — Etherscan API key not applied in history.js
95
+
96
+ `wallet/history.js` builds URLs without auth, unlike `services/whale.js` which uses `getApiKey('etherscan')`. Rate limited to 5 req/s unauthenticated.
97
+
98
+ ### 🟢 LOW — ETH price hardcoded fallback $3000
99
+
100
+ `gas.js` and `portfolio.js` silently fall back to $3000 if CoinGecko is unreachable. No warning shown.
101
+
102
+ ### 🟢 LOW — Web server binds 0.0.0.0
103
+
104
+ `src/web/server.js` binds all interfaces. Anyone on LAN can interact with the web terminal. Should default to 127.0.0.1.
105
+
106
+ ---
107
+
108
+ ## 4. Bug Hunt
109
+
110
+ ### 🔴 BUG — `warn` not imported in cards.js
111
+ Any call to `cardsOrder()` with invalid denomination/provider throws `ReferenceError: warn is not defined`. Quick fix: add `warn` to the import.
112
+
113
+ ### 🔴 BUG — DCA `runDCA()` never executes actual swaps
114
+ `src/trading/dca.js` — the executor marks orders as complete without calling `executeSwap`. Users see "DCA execution complete" for orders that were never traded. No "simulation mode" warning.
115
+
116
+ ### 🟠 BUG — `watchSnipe` auto-snipe logic is absent
117
+ `src/trading/snipe.js` — subscribes to newBlockHeaders and logs block numbers, but never calls `snipeToken()`. The feature is a skeleton.
118
+
119
+ ### 🟠 BUG — Race condition in autonomous strategy loop
120
+ `src/agent/autonomous.js` — `setInterval(runStrategyCycle, interval)` can fire overlapping cycles if one takes longer than the interval, risking duplicate trades. Should use setTimeout with re-scheduling.
121
+
122
+ ### 🟡 BUG — Silent error swallowing in whale monitor
123
+ `src/services/whale-monitor.js` — `pollTrackedWallets().catch(() => {})` swallows all errors silently. No visibility into whether monitoring is working or failing.
124
+
125
+ ### 🟡 BUG — topMovers() wasted HTTP call
126
+ `src/services/market.js` — fetches trending endpoint, result is completely discarded.
127
+
128
+ ### 🟡 BUG — Snipe slippage BigInt conversion
129
+ `src/trading/snipe.js` — potential precision issues in slippage math with BigInt conversions.
130
+
131
+ ---
132
+
133
+ ## 5. Test Coverage
134
+
135
+ ### ✅ Well-tested
136
+ - CLI command structure (cli.test.js)
137
+ - Config store (config.test.js)
138
+ - Keystore encryption (keystore.test.js)
139
+ - Agent loop + tools (agent-loop.test.js, agent-tools.test.js)
140
+ - Autonomous strategy (autonomous.test.js)
141
+ - DCA CRUD (dca.test.js)
142
+ - Trading validation (trading.test.js)
143
+ - Poker logic (poker.test.js)
144
+ - Script engine (scripts.test.js)
145
+ - LLM providers (llm-providers.test.js)
146
+ - Telegram bot (telegram.test.js)
147
+ - UI components (ui.test.js)
148
+ - Daemon management (daemon.test.js)
149
+ - Helpers (helpers.test.js)
150
+
151
+ ### ❌ Not tested
152
+ - x402 payment flow (critical path, no tests)
153
+ - Casino service (real payment flow, no tests)
154
+ - Oracle service (no tests)
155
+ - Cards service (no tests — has the warn bug)
156
+ - LI.FI bridge integration (no tests)
157
+ - Web server/terminal (no tests)
158
+ - Wallet portfolio scanning (no tests)
159
+ - Whale monitor polling (no tests)
160
+ - Agent signer HTTP daemon (no tests)
161
+ - Facilitator service (no tests)
162
+
163
+ ### Assessment
164
+ 130 tests at 0 failures is solid. But the most dangerous code paths (x402 payments, casino bets, agent signer) have zero coverage. The things that move money are untested.
165
+
166
+ ---
167
+
168
+ ## 6. Dependency Health
169
+
170
+ **19 runtime deps** — reasonable for scope, but:
171
+ - **ora + nanospinner** — duplicate spinners, pick one
172
+ - **blessed + blessed-contrib** — only used in dashboard.js, heavyweight for optional UI
173
+ - **node-fetch** — Node 18+ has native fetch; could eliminate this dep entirely
174
+ - **agentmail** — external dependency for mail service, review update frequency
175
+ - **ethers v6** — correct and current
176
+ - **ws** — needed for WebSocket (snipe block watcher, web terminal)
177
+
178
+ No known CVEs in current dep tree. Supply chain risk is low — all deps are well-maintained mainstream packages.
179
+
180
+ ---
181
+
182
+ ## 7. UX Issues
183
+
184
+ - **DCA "complete" messages are lies** — users think trades executed when they didn't
185
+ - **Snipe watcher gives false confidence** — shows "watching..." but never snipes
186
+ - **Key vault setup doesn't warn about protection level** — users assume their keys are safe
187
+ - **Web terminal on 0.0.0.0 with no auth** — anyone on LAN gets full CLI access
188
+ - **`hasSoul()` OLLAMA_HOST validation** — rejects bare hostnames without telling user to add http://
189
+ - **cli.js is massive** — `darksol --help` works but finding specific subcommand help requires digging
190
+
191
+ ---
192
+
193
+ ## 8. Performance
194
+
195
+ - **Startup:** Importing all 14 services on CLI boot regardless of which command runs. Lazy imports would cut cold start significantly.
196
+ - **whale-monitor processed Set:** Grows unbounded, trims at 1000→500 but could accumulate over days
197
+ - **node-fetch timeouts broken** — hung connections block indefinitely (see security section)
198
+ - **topMovers double fetch** — wasted HTTP request on every call
199
+
200
+ ---
201
+
202
+ ## 9. Missing Features / Incomplete Code
203
+
204
+ - **DCA execution** — CRUD works, execution is a stub
205
+ - **Snipe auto-buy** — block watcher works, token detection is absent
206
+ - **Whale mirror trading** — detected but not acted on
207
+ - **Desktop app** — Electron scaffold at desktop/, not packaged
208
+ - **MCP integration** — referenced in memory but not in current source
209
+
210
+ ---
211
+
212
+ ## 10. Prioritized Recommendations
213
+
214
+ ### 🔴 Critical (fix before next release)
215
+ 1. **x402 nonce: replace Math.random() with crypto.randomBytes()** — replay attack vector on mainnet USDC
216
+ 2. **cards.js: add `warn` to import** — crashes on invalid input
217
+ 3. **DCA: add clear "SIMULATION ONLY" warning or wire up real swaps** — users think trades execute
218
+
219
+ ### 🟠 High (fix soon)
220
+ 4. **node-fetch timeout: use AbortController** — prevents indefinite hangs
221
+ 5. **Web server: default to 127.0.0.1** — close LAN exposure
222
+ 6. **Autonomous strategy: replace setInterval with setTimeout chain** — prevent duplicate trades
223
+ 7. **Add tests for x402, casino, agent-signer** — the money-moving code needs coverage
224
+
225
+ ### 🟡 Medium (next sprint)
226
+ 8. **Deduplicate ERC-20 ABI, Explorer URLs, formatCompact** — DRY cleanup
227
+ 9. **Remove unused topMovers trending fetch**
228
+ 10. **Etherscan API key in history.js**
229
+ 11. **Lazy-load service imports in cli.js**
230
+ 12. **Split cli.js into command modules**
231
+
232
+ ### 🟢 Nice-to-have
233
+ 13. Remove ora (keep nanospinner) or vice versa
234
+ 14. Drop node-fetch, use native fetch
235
+ 15. ETH price fallback warning
236
+ 16. Script execution safety warning UI
237
+ 17. Key vault protection level documentation
238
+
239
+ ---
240
+
241
+ **Bottom line:** The architecture is solid and well-organized for its scope. 130 passing tests is strong. The critical issues are concentrated in the financial paths — x402 nonce security, DCA phantom execution, and untested payment flows. Fix those three and this is a genuinely impressive CLI platform.
package/README.md CHANGED
@@ -56,6 +56,21 @@ darksol bridge send --from base --to arbitrum --token ETH -a 0.1
56
56
  darksol bridge status 0xTxHash...
57
57
  darksol bridge chains
58
58
 
59
+ # Cross-DEX arbitrage
60
+ darksol arb scan --chain base # AI-scored DEX price comparison
61
+ darksol arb monitor --chain base --execute # real-time block-by-block scanning
62
+ darksol arb config # set thresholds, dry-run, DEXes
63
+ darksol arb add-endpoint base wss://your-quicknode # faster with WSS endpoints
64
+ darksol arb add-pair WETH AERO # add pairs to scan
65
+ darksol arb stats --days 7 # PnL history
66
+ darksol arb info # setup guide + risk warnings
67
+
68
+ # AI arbitrage intelligence
69
+ darksol arb ai # strategy briefing + recommendations
70
+ darksol arb discover --chain base # AI pair discovery
71
+ darksol arb tune --chain base # AI threshold optimization
72
+ darksol arb learn --chain base # learn from history patterns
73
+
59
74
  # Set up your agent identity
60
75
  darksol soul
61
76
 
@@ -128,6 +143,7 @@ Useful web-shell commands:
128
143
  ```bash
129
144
  help # clickable command menu (arrow keys + Enter)
130
145
  trade # interactive swap / snipe / bridge menu
146
+ arb # cross-DEX arbitrage scanner
131
147
  bridge # cross-chain bridge (LI.FI)
132
148
  send # interactive token transfer
133
149
  wallet # interactive wallet picker and actions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darksol/terminal",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "description": "DARKSOL Terminal — unified CLI for all DARKSOL services. Market intel, trading, oracle, casino, and more.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -16,6 +16,8 @@ import { startWebShell } from './web/server.js';
16
16
  import { executeSwap } from './trading/swap.js';
17
17
  import { snipeToken, watchSnipe } from './trading/snipe.js';
18
18
  import { createDCA, listDCA, cancelDCA, runDCA } from './trading/dca.js';
19
+ import { arbScan, arbMonitor, arbExecute, arbStats, arbConfig, arbAddEndpoint, arbAddPair, arbRemovePair, arbInfo } from './trading/arb.js';
20
+ import { aiDiscoverPairs, aiTuneThresholds, aiStrategyBriefing, aiLearn } from './trading/arb-ai.js';
19
21
  import { executeLifiSwap, executeLifiBridge, checkBridgeStatus, showSupportedChains } from './services/lifi.js';
20
22
  import { topMovers, tokenDetail, compareTokens } from './services/market.js';
21
23
  import { oracleFlip, oracleDice, oracleNumber, oracleShuffle, oracleHealth } from './services/oracle.js';
@@ -333,6 +335,96 @@ export function cli(argv) {
333
335
  .description('Execute pending DCA orders')
334
336
  .action(() => runDCA());
335
337
 
338
+ // ═══════════════════════════════════════
339
+ // ARBITRAGE COMMANDS
340
+ // ═══════════════════════════════════════
341
+ const arb = program
342
+ .command('arb')
343
+ .description('Cross-DEX arbitrage - scan, monitor, execute');
344
+
345
+ arb
346
+ .command('scan')
347
+ .description('One-shot scan across DEXs for price differences')
348
+ .option('-c, --chain <chain>', 'Target chain', 'base')
349
+ .option('-p, --pair <pair>', 'Token pair to scan (e.g. WETH/USDC)')
350
+ .option('-m, --min-profit <usd>', 'Minimum profit threshold in USD', '0.50')
351
+ .option('-s, --trade-size <eth>', 'Trade size in ETH', '0.1')
352
+ .action((opts) => arbScan({
353
+ chain: opts.chain,
354
+ pair: opts.pair,
355
+ minProfit: parseFloat(opts.minProfit),
356
+ tradeSize: parseFloat(opts.tradeSize),
357
+ }));
358
+
359
+ arb
360
+ .command('monitor')
361
+ .description('Real-time block-by-block arb monitoring (WSS recommended)')
362
+ .option('-c, --chain <chain>', 'Target chain', 'base')
363
+ .option('-e, --execute', 'Auto-execute profitable arbs')
364
+ .option('-d, --dry-run', 'Dry-run mode (no real transactions)')
365
+ .option('-m, --min-profit <usd>', 'Minimum profit threshold in USD', '0.50')
366
+ .action((opts) => arbMonitor({
367
+ chain: opts.chain,
368
+ execute: opts.execute,
369
+ dryRun: opts.dryRun !== undefined ? opts.dryRun : undefined,
370
+ minProfit: opts.minProfit,
371
+ }));
372
+
373
+ arb
374
+ .command('stats')
375
+ .description('View arb history and performance stats')
376
+ .option('-d, --days <days>', 'Number of days to show', '7')
377
+ .action((opts) => arbStats({ days: opts.days }));
378
+
379
+ arb
380
+ .command('config')
381
+ .description('Interactive arb configuration (thresholds, dry-run, DEXes)')
382
+ .action(() => arbConfig());
383
+
384
+ arb
385
+ .command('add-endpoint <chain> <url>')
386
+ .description('Add a custom WSS or RPC endpoint for faster arb detection')
387
+ .action((chain, url) => arbAddEndpoint({ chain, url }));
388
+
389
+ arb
390
+ .command('add-pair <tokenA> <tokenB>')
391
+ .description('Add a token pair to the arb scan list')
392
+ .action((tokenA, tokenB) => arbAddPair({ tokenA, tokenB }));
393
+
394
+ arb
395
+ .command('remove-pair <tokenA> <tokenB>')
396
+ .description('Remove a token pair from the arb scan list')
397
+ .action((tokenA, tokenB) => arbRemovePair({ tokenA, tokenB }));
398
+
399
+ arb
400
+ .command('info')
401
+ .description('How arbitrage works, setup guide, and risk warnings')
402
+ .action(() => arbInfo());
403
+
404
+ arb
405
+ .command('ai')
406
+ .description('AI strategy briefing — assessment, recommendations, next actions')
407
+ .option('-c, --chain <chain>', 'Target chain', 'base')
408
+ .action((opts) => aiStrategyBriefing({ chain: opts.chain }));
409
+
410
+ arb
411
+ .command('discover')
412
+ .description('AI-powered pair discovery — find new opportunities, drop dead pairs')
413
+ .option('-c, --chain <chain>', 'Target chain', 'base')
414
+ .action((opts) => aiDiscoverPairs({ chain: opts.chain }));
415
+
416
+ arb
417
+ .command('tune')
418
+ .description('AI threshold tuning — optimize min profit, trade size, gas ceiling')
419
+ .option('-c, --chain <chain>', 'Target chain', 'base')
420
+ .action((opts) => aiTuneThresholds({ chain: opts.chain }));
421
+
422
+ arb
423
+ .command('learn')
424
+ .description('Run AI learning cycle — analyze history and update patterns')
425
+ .option('-c, --chain <chain>', 'Target chain', 'base')
426
+ .action((opts) => aiLearn({ chain: opts.chain }));
427
+
336
428
  const auto = program
337
429
  .command('auto')
338
430
  .description('Autonomous trader mode - goal-based automated execution');
@@ -1933,6 +2025,7 @@ function showCommandList() {
1933
2025
  ['watch', 'Live price monitoring + alerts'],
1934
2026
  ['gas', 'Gas prices & cost estimates'],
1935
2027
  ['trade', 'Swap tokens, snipe, trading'],
2028
+ ['arb', 'Cross-DEX arbitrage scanner'],
1936
2029
  ['auto', 'Autonomous trader strategies'],
1937
2030
  ['bridge', 'Cross-chain bridge (LI.FI)'],
1938
2031
  ['dca', 'Dollar-cost averaging orders'],
@@ -57,6 +57,34 @@ const config = new Conf({
57
57
  strategies: [],
58
58
  },
59
59
  },
60
+ arb: {
61
+ type: 'object',
62
+ default: {
63
+ enabled: false,
64
+ minProfitUsd: 0.50,
65
+ maxTradeSize: 1.0,
66
+ gasCeiling: 0.01,
67
+ cooldownMs: 5000,
68
+ dryRun: true,
69
+ tokenAllowlist: [],
70
+ tokenDenylist: [],
71
+ endpoints: {
72
+ wss: {},
73
+ rpc: {},
74
+ },
75
+ dexes: {
76
+ base: ['uniswapV3', 'aerodrome', 'sushiswap'],
77
+ ethereum: ['uniswapV3', 'sushiswap'],
78
+ arbitrum: ['uniswapV3', 'sushiswap', 'camelot'],
79
+ optimism: ['uniswapV3', 'velodrome'],
80
+ polygon: ['uniswapV3', 'quickswap'],
81
+ },
82
+ pairs: [
83
+ { tokenA: 'WETH', tokenB: 'USDC' },
84
+ { tokenA: 'WETH', tokenB: 'USDT' },
85
+ ],
86
+ },
87
+ },
60
88
  services: {
61
89
  type: 'object',
62
90
  default: {
package/src/llm/intent.js CHANGED
@@ -66,6 +66,8 @@ ACTIONS (use the most specific one):
66
66
  - "gas" — gas price check
67
67
  - "cards" — order a prepaid Visa/Mastercard with crypto (e.g. "order a $50 card", "get me a prepaid card")
68
68
  - "casino" — play a casino game (coinflip, dice, hilo, slots). All bets are $1 USDC. (e.g. "flip a coin", "bet on heads", "play slots", "roll dice over 3")
69
+ - "arb_scan" — scan for cross-DEX arbitrage opportunities (e.g. "find arb opportunities", "scan for price differences", "check arb on base")
70
+ - "arb_monitor" — start real-time arbitrage monitoring (e.g. "monitor arb", "watch for arb opportunities")
69
71
  - "unknown" — can't determine what the user wants
70
72
 
71
73
  CASINO GAMES: