@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.
@@ -1,3 +1,4 @@
1
1
  export { executeSwap, resolveToken, getTokenInfo } from './swap.js';
2
2
  export { snipeToken, watchSnipe } from './snipe.js';
3
3
  export { createDCA, listDCA, cancelDCA, runDCA } from './dca.js';
4
+ export { executeLifiSwap, executeLifiBridge, checkBridgeStatus, showSupportedChains } from '../services/lifi.js';
@@ -223,7 +223,7 @@ export async function handleMenuSelect(id, value, item, ws) {
223
223
 
224
224
  case 'trade_action':
225
225
  if (value === 'swap') {
226
- ws.sendMenu('trade_swap_pair', '◆ Swap Pair', [
226
+ ws.sendMenu('trade_swap_pair', '◆ Swap Pair (via LI.FI — best route across 31 DEXs)', [
227
227
  { value: 'ETH->USDC', label: 'ETH → USDC', desc: 'Most common' },
228
228
  { value: 'USDC->ETH', label: 'USDC → ETH', desc: 'Reverse' },
229
229
  { value: 'ETH->AERO', label: 'ETH → AERO', desc: 'Base ecosystem' },
@@ -233,6 +233,16 @@ export async function handleMenuSelect(id, value, item, ws) {
233
233
  ]);
234
234
  return {};
235
235
  }
236
+ if (value === 'bridge') {
237
+ const currentChain = getConfig('chain') || 'base';
238
+ const chains = ['base', 'ethereum', 'arbitrum', 'optimism', 'polygon', 'avalanche', 'bsc', 'zksync', 'scroll', 'linea'];
239
+ ws.sendMenu('bridge_from_chain', '◆ Bridge From Chain', chains.map(c => ({
240
+ value: c,
241
+ label: c === currentChain ? `★ ${c}` : c,
242
+ desc: c === currentChain ? 'current' : '',
243
+ })));
244
+ return {};
245
+ }
236
246
  if (value === 'snipe') {
237
247
  ws.sendPrompt('trade_snipe_token', 'Token contract (0x...):', {});
238
248
  return {};
@@ -280,6 +290,63 @@ export async function handleMenuSelect(id, value, item, ws) {
280
290
  });
281
291
  return {};
282
292
 
293
+ case 'bridge_from_chain': {
294
+ if (value === 'back') return {};
295
+ const chains = ['base', 'ethereum', 'arbitrum', 'optimism', 'polygon', 'avalanche', 'bsc', 'zksync', 'scroll', 'linea'];
296
+ const destChains = chains.filter(c => c !== value);
297
+ ws.sendMenu('bridge_to_chain', `◆ Bridge To Chain (from ${value})`, destChains.map(c => ({
298
+ value: c,
299
+ label: c,
300
+ desc: '',
301
+ meta: { fromChain: value },
302
+ })));
303
+ return {};
304
+ }
305
+
306
+ case 'bridge_to_chain': {
307
+ if (value === 'back') return {};
308
+ const fromChain = item?.meta?.fromChain || 'base';
309
+ ws.sendMenu('bridge_token', `◆ Token to Bridge (${fromChain} → ${value})`, [
310
+ { value: 'ETH', label: 'ETH', desc: 'Native token', meta: { fromChain, toChain: value } },
311
+ { value: 'USDC', label: 'USDC', desc: 'Stablecoin', meta: { fromChain, toChain: value } },
312
+ { value: 'USDT', label: 'USDT', desc: 'Tether', meta: { fromChain, toChain: value } },
313
+ { value: 'custom', label: 'Custom token', desc: 'Enter symbol', meta: { fromChain, toChain: value } },
314
+ { value: 'back', label: '← Back', desc: '' },
315
+ ]);
316
+ return {};
317
+ }
318
+
319
+ case 'bridge_token': {
320
+ if (value === 'back') return {};
321
+ if (value === 'custom') {
322
+ ws.sendPrompt('bridge_custom_token', 'Token symbol or address:', item?.meta || {});
323
+ return {};
324
+ }
325
+ const m = item?.meta || {};
326
+ ws.sendMenu('bridge_amount', `◆ Amount (${value} · ${m.fromChain} → ${m.toChain})`, [
327
+ { value: '0.01', label: `0.01 ${value}`, desc: 'small', meta: { ...m, token: value } },
328
+ { value: '0.05', label: `0.05 ${value}`, desc: 'standard', meta: { ...m, token: value } },
329
+ { value: '0.1', label: `0.1 ${value}`, desc: 'medium', meta: { ...m, token: value } },
330
+ { value: '0.5', label: `0.5 ${value}`, desc: 'large', meta: { ...m, token: value } },
331
+ { value: '1', label: `1 ${value}`, desc: 'large', meta: { ...m, token: value } },
332
+ { value: 'custom', label: 'Custom amount', desc: '', meta: { ...m, token: value } },
333
+ ]);
334
+ return {};
335
+ }
336
+
337
+ case 'bridge_amount': {
338
+ if (value === 'custom') {
339
+ ws.sendPrompt('bridge_custom_amount', `Amount (${item?.meta?.token || 'token'}):`, item?.meta || {});
340
+ return {};
341
+ }
342
+ ws.sendPrompt('bridge_password', `Wallet password (bridge ${value} ${item?.meta?.token || ''} · ${item?.meta?.fromChain || ''} → ${item?.meta?.toChain || ''}):`, {
343
+ ...(item?.meta || {}),
344
+ amount: value,
345
+ mask: true,
346
+ });
347
+ return {};
348
+ }
349
+
283
350
  case 'send_token':
284
351
  if (value === 'back') return {};
285
352
  if (value === 'custom') {
@@ -536,6 +603,66 @@ export async function handlePromptResponse(id, value, meta, ws) {
536
603
  return {};
537
604
  }
538
605
 
606
+ if (id === 'bridge_custom_token') {
607
+ if (!value) { ws.sendLine(` ${ANSI.red}✗ Cancelled${ANSI.reset}`); ws.sendLine(''); return {}; }
608
+ const m = meta || {};
609
+ ws.sendMenu('bridge_amount', `◆ Amount (${value} · ${m.fromChain} → ${m.toChain})`, [
610
+ { value: '0.01', label: `0.01 ${value}`, desc: 'small', meta: { ...m, token: value.trim() } },
611
+ { value: '0.05', label: `0.05 ${value}`, desc: 'standard', meta: { ...m, token: value.trim() } },
612
+ { value: '0.1', label: `0.1 ${value}`, desc: 'medium', meta: { ...m, token: value.trim() } },
613
+ { value: '0.5', label: `0.5 ${value}`, desc: 'large', meta: { ...m, token: value.trim() } },
614
+ { value: '1', label: `1 ${value}`, desc: 'large', meta: { ...m, token: value.trim() } },
615
+ { value: 'custom', label: 'Custom amount', desc: '', meta: { ...m, token: value.trim() } },
616
+ ]);
617
+ return {};
618
+ }
619
+
620
+ if (id === 'bridge_custom_amount') {
621
+ const n = Number(value);
622
+ if (!Number.isFinite(n) || n <= 0) {
623
+ ws.sendLine(` ${ANSI.red}✗ Invalid amount${ANSI.reset}`);
624
+ ws.sendLine('');
625
+ return {};
626
+ }
627
+ ws.sendPrompt('bridge_password', `Wallet password (bridge ${value} ${meta?.token || ''} · ${meta?.fromChain || ''} → ${meta?.toChain || ''}):`, {
628
+ ...meta,
629
+ amount: String(value),
630
+ mask: true,
631
+ });
632
+ return {};
633
+ }
634
+
635
+ if (id === 'bridge_password') {
636
+ if (!meta?.fromChain || !meta?.toChain || !meta?.token || !meta?.amount || !value) {
637
+ ws.sendLine(` ${ANSI.red}✗ Missing bridge details${ANSI.reset}`);
638
+ ws.sendLine('');
639
+ return {};
640
+ }
641
+
642
+ ws.sendLine('');
643
+ ws.sendLine(` ${ANSI.dim}Bridging ${meta.amount} ${meta.token} from ${meta.fromChain} → ${meta.toChain} via LI.FI...${ANSI.reset}`);
644
+ ws.sendLine('');
645
+
646
+ try {
647
+ const { executeLifiBridge } = await import('../services/lifi.js');
648
+ await executeLifiBridge({
649
+ fromChain: meta.fromChain,
650
+ toChain: meta.toChain,
651
+ token: meta.token,
652
+ amount: meta.amount,
653
+ slippage: parseFloat(getConfig('slippage') || 0.5),
654
+ wallet: getConfig('activeWallet'),
655
+ password: value,
656
+ confirm: true,
657
+ });
658
+ ws.sendLine(` ${ANSI.green}✓ Bridge flow completed (check terminal output for receipt)${ANSI.reset}`);
659
+ } catch (err) {
660
+ ws.sendLine(` ${ANSI.red}✗ Bridge failed: ${err.message}${ANSI.reset}`);
661
+ }
662
+ ws.sendLine('');
663
+ return {};
664
+ }
665
+
539
666
  if (id === 'trade_swap_password') {
540
667
  if (!meta?.tokenIn || !meta?.tokenOut || !meta?.amount || !value) {
541
668
  ws.sendLine(` ${ANSI.red}✗ Missing swap details${ANSI.reset}`);
@@ -543,12 +670,13 @@ export async function handlePromptResponse(id, value, meta, ws) {
543
670
  return {};
544
671
  }
545
672
 
546
- ws.sendLine(` ${ANSI.dim}Executing swap ${meta.amount} ${meta.tokenIn} → ${meta.tokenOut}...${ANSI.reset}`);
673
+ ws.sendLine(` ${ANSI.dim}Executing swap ${meta.amount} ${meta.tokenIn} → ${meta.tokenOut} via LI.FI...${ANSI.reset}`);
547
674
  ws.sendLine('');
548
675
 
549
676
  try {
550
- const { executeSwap } = await import('../trading/swap.js');
551
- await executeSwap({
677
+ // Try LI.FI first, fall back to direct Uniswap
678
+ const { executeLifiSwap } = await import('../services/lifi.js');
679
+ const swapOpts = {
552
680
  tokenIn: meta.tokenIn,
553
681
  tokenOut: meta.tokenOut,
554
682
  amount: meta.amount,
@@ -556,8 +684,18 @@ export async function handlePromptResponse(id, value, meta, ws) {
556
684
  wallet: getConfig('activeWallet'),
557
685
  password: value,
558
686
  confirm: true,
559
- });
560
- ws.sendLine(` ${ANSI.green}✓ Swap flow completed (check terminal output for receipt)${ANSI.reset}`);
687
+ };
688
+
689
+ const result = await executeLifiSwap(swapOpts);
690
+ if (result?.success) {
691
+ ws.sendLine(` ${ANSI.green}✓ Swap completed via LI.FI${ANSI.reset}`);
692
+ } else if (result?.error !== 'cancelled') {
693
+ // Fallback to direct Uniswap
694
+ ws.sendLine(` ${ANSI.darkGold}LI.FI route unavailable — trying direct Uniswap V3...${ANSI.reset}`);
695
+ const { executeSwap } = await import('../trading/swap.js');
696
+ await executeSwap(swapOpts);
697
+ ws.sendLine(` ${ANSI.green}✓ Swap completed via Uniswap V3${ANSI.reset}`);
698
+ }
561
699
  } catch (err) {
562
700
  ws.sendLine(` ${ANSI.red}✗ Swap failed: ${err.message}${ANSI.reset}`);
563
701
  }
@@ -686,6 +824,8 @@ export async function handleCommand(cmd, ws) {
686
824
  return await cmdMarket(args, ws);
687
825
  case 'trade':
688
826
  return await cmdTrade(args, ws);
827
+ case 'bridge':
828
+ return await cmdBridge(args, ws);
689
829
  case 'wallet':
690
830
  return await cmdWallet(args, ws);
691
831
  case 'mail':
@@ -719,7 +859,7 @@ export async function handleCommand(cmd, ws) {
719
859
  return await cmdChatLogs(args, ws);
720
860
  default: {
721
861
  // Fuzzy: if it looks like natural language, route to AI
722
- const nlKeywords = /\b(swap|buy|sell|send|transfer|price|what|how|should|analyze|check|balance|gas|dca|order|card|prepaid|visa|mastercard|bet|coinflip|flip|dice|slots|hilo|gamble|play|casino)\b/i;
862
+ const nlKeywords = /\b(swap|buy|sell|send|transfer|price|what|how|should|analyze|check|balance|gas|dca|order|card|prepaid|visa|mastercard|bet|coinflip|flip|dice|slots|hilo|gamble|play|casino|bridge|cross-chain|crosschain)\b/i;
723
863
  if (nlKeywords.test(cmd)) {
724
864
  return await cmdAI(cmd.split(/\s+/), ws);
725
865
  }
@@ -986,7 +1126,8 @@ async function cmdTrade(args, ws) {
986
1126
  ws.sendLine('');
987
1127
 
988
1128
  ws.sendMenu('trade_action', '◆ Trade Actions', [
989
- { value: 'swap', label: '🔄 Swap', desc: 'Interactive token swap (password prompt)' },
1129
+ { value: 'swap', label: '🔄 Swap', desc: 'Token swap via LI.FI (best route across 31 DEXs)' },
1130
+ { value: 'bridge', label: '🌉 Bridge', desc: 'Cross-chain transfer via LI.FI (60 chains)' },
990
1131
  { value: 'snipe', label: '⚡ Snipe', desc: 'Fast buy by token contract' },
991
1132
  { value: 'watch', label: '👀 Watch Pairs', desc: 'Monitor new pairs (CLI guidance)' },
992
1133
  { value: 'back', label: '← Back', desc: '' },
@@ -995,6 +1136,79 @@ async function cmdTrade(args, ws) {
995
1136
  return {};
996
1137
  }
997
1138
 
1139
+ // ══════════════════════════════════════════════════
1140
+ // BRIDGE (LI.FI cross-chain)
1141
+ // ══════════════════════════════════════════════════
1142
+ async function cmdBridge(args, ws) {
1143
+ const sub = (args[0] || '').toLowerCase();
1144
+
1145
+ if (sub === 'status' && args[1]) {
1146
+ // Check bridge transfer status
1147
+ ws.sendLine(` ${ANSI.dim}Checking bridge status...${ANSI.reset}`);
1148
+ try {
1149
+ const { checkBridgeStatus } = await import('../services/lifi.js');
1150
+ await checkBridgeStatus(args[1], {
1151
+ fromChain: args.find((a, i) => args[i - 1] === '--from'),
1152
+ toChain: args.find((a, i) => args[i - 1] === '--to'),
1153
+ });
1154
+ } catch (err) {
1155
+ ws.sendLine(` ${ANSI.red}✗ ${err.message}${ANSI.reset}`);
1156
+ }
1157
+ ws.sendLine('');
1158
+ return {};
1159
+ }
1160
+
1161
+ if (sub === 'chains') {
1162
+ ws.sendLine(` ${ANSI.dim}Fetching supported chains...${ANSI.reset}`);
1163
+ try {
1164
+ const { getChains } = await import('../services/lifi.js');
1165
+ const chains = await getChains();
1166
+ ws.sendLine('');
1167
+ ws.sendLine(`${ANSI.gold} ◆ LI.FI SUPPORTED CHAINS (${chains.length})${ANSI.reset}`);
1168
+ ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
1169
+
1170
+ const evm = chains.filter(c => c.chainType === 'EVM').sort((a, b) => a.name.localeCompare(b.name));
1171
+ const other = chains.filter(c => c.chainType !== 'EVM');
1172
+
1173
+ for (const c of evm.slice(0, 30)) {
1174
+ ws.sendLine(` ${ANSI.green}●${ANSI.reset} ${ANSI.white}${c.name.padEnd(22)}${ANSI.reset} ${ANSI.dim}id:${c.id}${ANSI.reset}`);
1175
+ }
1176
+ if (evm.length > 30) {
1177
+ ws.sendLine(` ${ANSI.dim}...and ${evm.length - 30} more EVM chains${ANSI.reset}`);
1178
+ }
1179
+ if (other.length) {
1180
+ ws.sendLine('');
1181
+ for (const c of other) {
1182
+ ws.sendLine(` ${ANSI.blue}●${ANSI.reset} ${ANSI.white}${c.name.padEnd(22)}${ANSI.reset} ${ANSI.dim}${c.chainType}${ANSI.reset}`);
1183
+ }
1184
+ }
1185
+ ws.sendLine('');
1186
+ } catch (err) {
1187
+ ws.sendLine(` ${ANSI.red}✗ ${err.message}${ANSI.reset}`);
1188
+ ws.sendLine('');
1189
+ }
1190
+ return {};
1191
+ }
1192
+
1193
+ // Default: show bridge menu
1194
+ const currentChain = getConfig('chain') || 'base';
1195
+
1196
+ ws.sendLine(`${ANSI.gold} ◆ CROSS-CHAIN BRIDGE (LI.FI)${ANSI.reset}`);
1197
+ ws.sendLine(`${ANSI.dim} ${'─'.repeat(50)}${ANSI.reset}`);
1198
+ ws.sendLine(` ${ANSI.white}Move tokens between 60+ chains with optimal routing.${ANSI.reset}`);
1199
+ ws.sendLine(` ${ANSI.dim}Aggregates 27 bridges for best rates.${ANSI.reset}`);
1200
+ ws.sendLine('');
1201
+
1202
+ const chains = ['base', 'ethereum', 'arbitrum', 'optimism', 'polygon', 'avalanche', 'bsc', 'zksync', 'scroll', 'linea'];
1203
+ ws.sendMenu('bridge_from_chain', '◆ Bridge From Chain', chains.map(c => ({
1204
+ value: c,
1205
+ label: c === currentChain ? `★ ${c}` : c,
1206
+ desc: c === currentChain ? 'current chain' : '',
1207
+ })));
1208
+
1209
+ return {};
1210
+ }
1211
+
998
1212
  // ══════════════════════════════════════════════════
999
1213
  // WALLET
1000
1214
  // ══════════════════════════════════════════════════