@darksol/terminal 0.7.2 → 0.8.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.
package/README.md CHANGED
@@ -15,7 +15,7 @@ A unified CLI for market intel, trading, AI-powered analysis, on-chain oracle, c
15
15
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-gold.svg)](https://www.gnu.org/licenses/gpl-3.0)
16
16
  [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-green.svg)](https://nodejs.org/)
17
17
 
18
- - Current release: **0.7.2**
18
+ - Current release: **0.8.1**
19
19
  - Changelog: `CHANGELOG.md`
20
20
 
21
21
  ## Install
@@ -48,9 +48,14 @@ darksol watch AERO --above 2.0
48
48
  # Gas estimates
49
49
  darksol gas base
50
50
 
51
- # Swap tokens (Uniswap V3 with slippage protection)
51
+ # Swap tokens (LI.FI — best route across 31 DEXs, Uniswap V3 fallback)
52
52
  darksol trade swap -i ETH -o USDC -a 0.1
53
53
 
54
+ # Cross-chain bridge (60+ chains via LI.FI)
55
+ darksol bridge send --from base --to arbitrum --token ETH -a 0.1
56
+ darksol bridge status 0xTxHash...
57
+ darksol bridge chains
58
+
54
59
  # AI trading assistant
55
60
  darksol ai chat
56
61
 
@@ -71,7 +76,8 @@ darksol agent start main
71
76
 
72
77
  - Arrow-key menus (`↑/↓` + `Enter`) for wallet/config/trade flows
73
78
  - **Interactive send** — token → recipient → amount → password → on-chain transfer
74
- - **Interactive swap** — pair picker (presets + custom) → amount → password → Uniswap V3 execution
79
+ - **Interactive swap** — pair picker (presets + custom) → amount → password → LI.FI execution (Uniswap V3 fallback)
80
+ - **Interactive bridge** — source chain → dest chain → token → amount → password → cross-chain via LI.FI
75
81
  - **Interactive snipe** — contract input → amount → password → fast buy
76
82
  - Wallet picker + wallet action menu (receive/send/portfolio/history/switch chain)
77
83
  - Agent signer control center (`agent`) with guided wallet selection + start/stop/status
@@ -87,7 +93,8 @@ Useful web-shell commands:
87
93
 
88
94
  ```bash
89
95
  help # clickable command menu (arrow keys + Enter)
90
- trade # interactive swap / snipe menu
96
+ trade # interactive swap / snipe / bridge menu
97
+ bridge # cross-chain bridge (LI.FI)
91
98
  send # interactive token transfer
92
99
  wallet # interactive wallet picker and actions
93
100
  keys # provider status + interactive add/update
@@ -104,7 +111,8 @@ ai <prompt> # chat with trading assistant
104
111
  | `wallet` | Create/import/manage encrypted EVM wallets | Free |
105
112
  | `send` | Send ETH or ERC-20 tokens | Gas only |
106
113
  | `receive` | Show receive address + chain safety hints | Free |
107
- | `trade` | Swap (Uniswap V3), snipe (V2), token trading | Gas only |
114
+ | `trade` | Swap via LI.FI (31 DEXs) + Uniswap V3 fallback, snipe | Gas only |
115
+ | `bridge` | Cross-chain bridge via LI.FI (60 chains, 27 bridges) | Gas only |
108
116
  | `dca` | Dollar-cost averaging engine | Gas only |
109
117
  | `ai` | LLM-powered trading assistant & intent execution | Provider dependent |
110
118
  | `agent` | Secure agent signer (PK-isolated proxy) | Free |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darksol/terminal",
3
- "version": "0.7.2",
3
+ "version": "0.8.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/skill/SKILL.md CHANGED
@@ -7,7 +7,7 @@ description: "DARKSOL Terminal — unified CLI + x402 platform for trading, wall
7
7
 
8
8
  **All DARKSOL services. One terminal. Zero trust required. 🌑**
9
9
 
10
- `@darksol/terminal` v0.7.1 | npm: `npm install -g @darksol/terminal`
10
+ `@darksol/terminal` v0.8.0 | npm: `npm install -g @darksol/terminal`
11
11
 
12
12
  ---
13
13
 
@@ -63,10 +63,11 @@ darksol wallet use <name> # Set active wallet
63
63
  darksol wallet export [name] # Export (password required for PK)
64
64
  ```
65
65
 
66
- ### 📊 Trading (5 chains)
66
+ ### 📊 Trading (60+ chains via LI.FI)
67
67
  ```bash
68
- darksol trade swap # Interactive swap (prompts for pair + amount)
69
- darksol trade swap -i ETH -o USDC -a 0.1 # Uniswap V3 swap with slippage protection
68
+ darksol trade swap # Interactive swap (LI.FI best route across 31 DEXs)
69
+ darksol trade swap -i ETH -o USDC -a 0.1 # LI.FI swap with Uniswap V3 fallback
70
+ darksol trade swap -i ETH -o USDC -a 0.1 --direct # Force direct Uniswap V3 (skip LI.FI)
70
71
  darksol trade swap -i ETH -o USDC -a 0.1 -p "pw" -y # Non-interactive (automation/cron)
71
72
  darksol trade pairs # Show common pairs for active chain
72
73
  darksol trade snipe <token> -a 0.05 # Fast buy with gas boost
@@ -76,8 +77,20 @@ darksol send # Interactive ETH/ERC-20 transfer
76
77
  darksol receive # Show your address for receiving
77
78
  ```
78
79
 
79
- **Supported chains:** Base (default), Ethereum, Polygon, Arbitrum, Optimism
80
- **Swap routers:** Base uses SwapRouter02 (V2), others use V1 SwapRouter. Handled automatically.
80
+ ### 🌉 Cross-Chain Bridge (LI.FI)
81
+ ```bash
82
+ darksol bridge send # Interactive bridge flow
83
+ darksol bridge send -f base -t arbitrum --token ETH -a 0.1 # Bridge ETH from Base to Arbitrum
84
+ darksol bridge send -f ethereum -t polygon --token USDC -a 100 -p "pw" -y # Non-interactive
85
+ darksol bridge status <txHash> # Track cross-chain transfer
86
+ darksol bridge status <txHash> -f base -t arbitrum # Faster status with chain hints
87
+ darksol bridge chains # Show all 60+ supported chains
88
+ ```
89
+
90
+ **LI.FI routing:** Aggregates 27 bridges and 31 DEXs across 60 chains. Finds optimal route automatically.
91
+ **Swap routing:** LI.FI primary, Uniswap V3 fallback. Use `--direct` to skip LI.FI.
92
+ **API key:** Free tier works without key (200 req/2hr). Higher limits: `darksol keys add lifi`
93
+ **Supported chains:** Base, Ethereum, Polygon, Arbitrum, Optimism, Avalanche, BSC, zkSync, Scroll, Linea, + 50 more
81
94
 
82
95
  ### 📈 DCA (Dollar-Cost Averaging)
83
96
  ```bash
package/src/cli.js CHANGED
@@ -13,6 +13,7 @@ import { startWebShell } from './web/server.js';
13
13
  import { executeSwap } from './trading/swap.js';
14
14
  import { snipeToken, watchSnipe } from './trading/snipe.js';
15
15
  import { createDCA, listDCA, cancelDCA, runDCA } from './trading/dca.js';
16
+ import { executeLifiSwap, executeLifiBridge, checkBridgeStatus, showSupportedChains } from './services/lifi.js';
16
17
  import { topMovers, tokenDetail, compareTokens } from './services/market.js';
17
18
  import { oracleFlip, oracleDice, oracleNumber, oracleShuffle, oracleHealth } from './services/oracle.js';
18
19
  import { casinoBet, casinoTables, casinoStats, casinoReceipt, casinoHealth, casinoVerify } from './services/casino.js';
@@ -113,7 +114,7 @@ export function cli(argv) {
113
114
 
114
115
  trade
115
116
  .command('swap')
116
- .description('Swap tokens via DEX (interactive if flags omitted)')
117
+ .description('Swap tokens via LI.FI (58 chains, 31 DEXs) with Uniswap fallback')
117
118
  .option('-i, --in <token>', 'Token to sell (symbol or address)')
118
119
  .option('-o, --out <token>', 'Token to buy (symbol or address)')
119
120
  .option('-a, --amount <amount>', 'Amount to swap')
@@ -121,6 +122,7 @@ export function cli(argv) {
121
122
  .option('-w, --wallet <name>', 'Wallet to use')
122
123
  .option('-p, --password <pw>', 'Wallet password (non-interactive)')
123
124
  .option('-y, --yes', 'Skip confirmation')
125
+ .option('--direct', 'Force direct Uniswap V3 (skip LI.FI)')
124
126
  .action(async (opts) => {
125
127
  let tokenIn = opts.in;
126
128
  let tokenOut = opts.out;
@@ -138,7 +140,7 @@ export function cli(argv) {
138
140
  amount = answers.amount;
139
141
  }
140
142
 
141
- return executeSwap({
143
+ const swapOpts = {
142
144
  tokenIn,
143
145
  tokenOut,
144
146
  amount,
@@ -146,7 +148,30 @@ export function cli(argv) {
146
148
  wallet: opts.wallet,
147
149
  password: opts.password,
148
150
  confirm: opts.yes ? true : undefined,
149
- });
151
+ };
152
+
153
+ // Try LI.FI first (unless --direct flag)
154
+ if (!opts.direct) {
155
+ try {
156
+ const result = await executeLifiSwap(swapOpts);
157
+ if (result?.success) return;
158
+ // If LI.FI failed (not cancelled), fall back to direct
159
+ if (result?.error !== 'cancelled') {
160
+ const { warn: showWarn, info: showInfo } = await import('./ui/components.js');
161
+ showWarn('LI.FI route failed — falling back to direct Uniswap V3...');
162
+ console.log('');
163
+ } else {
164
+ return; // User cancelled, don't fallback
165
+ }
166
+ } catch {
167
+ const { warn: showWarn } = await import('./ui/components.js');
168
+ showWarn('LI.FI unavailable — falling back to direct Uniswap V3...');
169
+ console.log('');
170
+ }
171
+ }
172
+
173
+ // Direct Uniswap V3 fallback
174
+ return executeSwap(swapOpts);
150
175
  });
151
176
 
152
177
  trade
@@ -193,6 +218,71 @@ export function cli(argv) {
193
218
  console.log('');
194
219
  });
195
220
 
221
+ // ═══════════════════════════════════════
222
+ // BRIDGE COMMANDS (LI.FI)
223
+ // ═══════════════════════════════════════
224
+ const bridge = program
225
+ .command('bridge')
226
+ .description('Cross-chain bridge — move tokens between chains via LI.FI');
227
+
228
+ bridge
229
+ .command('send')
230
+ .description('Bridge tokens to another chain')
231
+ .option('-f, --from <chain>', 'Source chain (e.g. base, ethereum)')
232
+ .option('-t, --to <chain>', 'Destination chain (e.g. arbitrum, optimism)')
233
+ .option('--token <symbol>', 'Token to bridge (e.g. ETH, USDC)', 'ETH')
234
+ .option('-a, --amount <amount>', 'Amount to bridge')
235
+ .option('-s, --slippage <percent>', 'Max slippage %', '0.5')
236
+ .option('-w, --wallet <name>', 'Wallet to use')
237
+ .option('-p, --password <pw>', 'Wallet password (non-interactive)')
238
+ .option('-y, --yes', 'Skip confirmation')
239
+ .action(async (opts) => {
240
+ let fromChain = opts.from;
241
+ let toChain = opts.to;
242
+ let token = opts.token;
243
+ let amount = opts.amount;
244
+
245
+ if (!fromChain || !toChain || !amount) {
246
+ const inquirer = (await import('inquirer')).default;
247
+ const answers = await inquirer.prompt([
248
+ { type: 'input', name: 'fromChain', message: 'Source chain:', default: fromChain || getConfig('chain') || 'base' },
249
+ { type: 'input', name: 'toChain', message: 'Destination chain:', default: toChain || 'arbitrum' },
250
+ { type: 'input', name: 'token', message: 'Token to bridge:', default: token || 'ETH' },
251
+ { type: 'input', name: 'amount', message: 'Amount:', default: amount || '0.1' },
252
+ ]);
253
+ fromChain = answers.fromChain;
254
+ toChain = answers.toChain;
255
+ token = answers.token;
256
+ amount = answers.amount;
257
+ }
258
+
259
+ return executeLifiBridge({
260
+ fromChain,
261
+ toChain,
262
+ token,
263
+ amount,
264
+ slippage: parseFloat(opts.slippage),
265
+ wallet: opts.wallet,
266
+ password: opts.password,
267
+ confirm: opts.yes ? true : undefined,
268
+ });
269
+ });
270
+
271
+ bridge
272
+ .command('status <txHash>')
273
+ .description('Check bridge transfer status')
274
+ .option('-f, --from <chain>', 'Source chain')
275
+ .option('-t, --to <chain>', 'Destination chain')
276
+ .action((txHash, opts) => checkBridgeStatus(txHash, {
277
+ fromChain: opts.from,
278
+ toChain: opts.to,
279
+ }));
280
+
281
+ bridge
282
+ .command('chains')
283
+ .description('Show all supported chains')
284
+ .action(() => showSupportedChains());
285
+
196
286
  // ═══════════════════════════════════════
197
287
  // DCA COMMANDS
198
288
  // ═══════════════════════════════════════
@@ -1109,6 +1199,7 @@ function showCommandList() {
1109
1199
  ['watch', 'Live price monitoring + alerts'],
1110
1200
  ['gas', 'Gas prices & cost estimates'],
1111
1201
  ['trade', 'Swap tokens, snipe, trading'],
1202
+ ['bridge', 'Cross-chain bridge (LI.FI)'],
1112
1203
  ['dca', 'Dollar-cost averaging orders'],
1113
1204
  ['ai chat', 'Standalone AI chat session'],
1114
1205
  ['ai execute', 'Parse + execute a trade via AI'],
@@ -178,6 +178,14 @@ export const SERVICES = {
178
178
  docsUrl: 'https://developers.paraswap.network',
179
179
  validate: (key) => key.length > 5,
180
180
  },
181
+ lifi: {
182
+ name: 'LI.FI',
183
+ category: 'trading',
184
+ description: 'Cross-chain swaps & bridges — 58 chains, 27 bridges, 31 DEXs',
185
+ envVar: 'LIFI_API_KEY',
186
+ docsUrl: 'https://docs.li.fi/api-reference/rate-limits',
187
+ validate: (key) => key.length > 20,
188
+ },
181
189
  };
182
190
 
183
191
  // ──────────────────────────────────────────────────
@@ -1,7 +1,5 @@
1
1
  import { fetchJSON } from '../utils/fetch.js';
2
- import fetch from 'node-fetch';
3
- import { ethers } from 'ethers';
4
- import { getServiceURL, getConfig, getRPC } from '../config/store.js';
2
+ import { getServiceURL, getConfig } from '../config/store.js';
5
3
  import { theme } from '../ui/theme.js';
6
4
  import { spinner, kvDisplay, success, error, warn, info, table } from '../ui/components.js';
7
5
  import { showSection } from '../ui/banner.js';
@@ -181,82 +179,36 @@ export async function casinoBet(gameType, betParams = {}, opts = {}) {
181
179
  return;
182
180
  }
183
181
 
184
- // ── Payment: Send 1 USDC to the house ──
185
- const HOUSE_WALLET = '0x7B0a6330121B26100D47BCcd5640cc6617F8adA7';
186
- const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
187
- const USDC_AMOUNT = '1000000'; // 1 USDC (6 decimals)
182
+ // ── Place bet via x402 (EIP-3009 auto-pay) ──
183
+ const signerToken = process.env.DARKSOL_SIGNER_TOKEN || getConfig('signerToken') || null;
184
+ const signerUp = await isSignerRunning(signerToken);
188
185
 
189
- const paymentSpin = spinner('Sending $1 USDC to the house...').start();
190
- let paymentTxHash;
191
-
192
- try {
193
- // Try agent signer first
194
- const signerToken = process.env.DARKSOL_SIGNER_TOKEN || getConfig('signerToken') || null;
195
- const signerUp = await isSignerRunning(signerToken);
196
-
197
- if (signerUp) {
198
- // Use agent signer to send USDC
199
- const headers = { 'Content-Type': 'application/json' };
200
- if (signerToken) headers.Authorization = `Bearer ${signerToken}`;
201
-
202
- // ERC-20 transfer calldata: transfer(address,uint256)
203
- const iface = new ethers.Interface(['function transfer(address to, uint256 amount) returns (bool)']);
204
- const txData = iface.encodeFunctionData('transfer', [HOUSE_WALLET, USDC_AMOUNT]);
205
-
206
- const resp = await fetch('http://127.0.0.1:18790/send', {
207
- method: 'POST',
208
- headers,
209
- body: JSON.stringify({ to: USDC_BASE, data: txData, value: '0' }),
210
- });
211
-
212
- if (!resp.ok) {
213
- const errText = await resp.text();
214
- throw new Error(`Signer refused: ${errText}`);
215
- }
216
-
217
- const result = await resp.json();
218
- paymentTxHash = result.txHash || result.hash;
219
- } else {
220
- // Try wallet directly (needs password)
221
- const activeWallet = getConfig('activeWallet');
222
- if (!activeWallet) throw new Error('No wallet configured. Set one: darksol wallet use <name>');
223
-
224
- const { decryptKey } = await import('../wallet/keystore.js');
225
- const password = process.env.DARKSOL_WALLET_PASSWORD;
226
- if (!password) {
227
- paymentSpin.fail('Payment requires agent signer or DARKSOL_WALLET_PASSWORD');
228
- info('Start agent signer: darksol signer start');
229
- info('Or set: export DARKSOL_WALLET_PASSWORD=<password>');
230
- return;
231
- }
232
-
233
- const pk = decryptKey(activeWallet, password);
234
- const provider = new ethers.JsonRpcProvider(getRPC('base'));
235
- const wallet = new ethers.Wallet(pk, provider);
236
- const usdc = new ethers.Contract(USDC_BASE, ['function transfer(address,uint256) returns (bool)'], wallet);
237
- const tx = await usdc.transfer(HOUSE_WALLET, USDC_AMOUNT);
238
- const receipt = await tx.wait();
239
- paymentTxHash = receipt.hash;
240
- }
241
-
242
- paymentSpin.succeed(`Payment sent: ${paymentTxHash.slice(0, 16)}...`);
243
- } catch (err) {
244
- paymentSpin.fail('Payment failed');
245
- error(err.message);
246
- if (err.message.includes('insufficient')) {
247
- info('You need at least 1 USDC on Base to play');
248
- }
186
+ if (!signerUp) {
187
+ error('Agent signer is required for casino bets (x402 payment).');
188
+ info('Start it: darksol agent start <wallet-name>');
249
189
  return;
250
190
  }
251
191
 
252
- // ── Place the bet with payment proof ──
253
192
  const spin = spinner(`Playing ${gameInfo.name}...`).start();
254
193
  try {
255
- const data = await fetchJSON(`${getURL()}/api/bet`, {
256
- method: 'POST',
257
- headers: { 'Content-Type': 'application/json' },
258
- body: JSON.stringify({ gameType, betParams, agentWallet, paymentTxHash }),
259
- });
194
+ const { fetchWithX402 } = await import('../utils/x402.js');
195
+ const result = await fetchWithX402(
196
+ `${getURL()}/api/bet`,
197
+ {
198
+ method: 'POST',
199
+ headers: { 'Content-Type': 'application/json' },
200
+ body: JSON.stringify({ gameType, betParams, agentWallet }),
201
+ },
202
+ { signerToken, autoSign: true },
203
+ );
204
+
205
+ if (result.error) {
206
+ spin.fail('Payment failed');
207
+ error(result.error);
208
+ return;
209
+ }
210
+
211
+ const data = result.data;
260
212
 
261
213
  if (data.won) {
262
214
  spin.succeed(theme.success(`YOU WON! $${data.payoutAmount} USDC`));
@@ -271,7 +223,7 @@ export async function casinoBet(gameType, betParams = {}, opts = {}) {
271
223
  ['Result', data.result || '-'],
272
224
  ['Won', data.won ? theme.success('YES! 🎉') : theme.error('No')],
273
225
  ['Payout', data.won ? `$${data.payoutAmount} USDC` : '$0'],
274
- ['Payment TX', paymentTxHash.slice(0, 20) + '...'],
226
+ ['Payment', result.paid ? theme.success('x402 ✓') : theme.dim('unpaid')],
275
227
  ['Oracle TX', data.oracleTxHash ? data.oracleTxHash.slice(0, 20) + '...' : '-'],
276
228
  ['Payout TX', data.payoutTxHash ? data.payoutTxHash.slice(0, 20) + '...' : '-'],
277
229
  ]);
@@ -286,8 +238,6 @@ export async function casinoBet(gameType, betParams = {}, opts = {}) {
286
238
  error(err.message);
287
239
  if (err.message.includes('not accepting') || err.message.includes('closed')) {
288
240
  info('The casino may be temporarily closed. Check: darksol casino status');
289
- } else if (err.message.includes('payment') || err.message.includes('Payment')) {
290
- info(`Your USDC was sent (${paymentTxHash.slice(0, 16)}...) — contact support if bet wasn't processed`);
291
241
  }
292
242
  }
293
243
  }