@moly-mcp/lido 1.0.6 → 1.0.8

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,27 +1,57 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ getSettings,
4
+ stakeEth,
5
+ updateSettings
6
+ } from "./chunk-CQ6ZSCMZ.js";
2
7
  import {
3
8
  castVote,
4
9
  claimWithdrawals,
5
- getBalance,
6
- getConversionRate,
7
10
  getProposal,
8
11
  getProposals,
9
- getRewards,
10
- getSettings,
11
12
  getWithdrawalRequests,
12
13
  getWithdrawalStatus,
13
- requestWithdrawal,
14
- stakeEth,
14
+ requestWithdrawal
15
+ } from "./chunk-EQYEWCQO.js";
16
+ import {
17
+ configureAlertChannels,
18
+ listAlerts,
19
+ removeAlertById,
20
+ setAlert
21
+ } from "./chunk-6UIRFWG4.js";
22
+ import "./chunk-6F64RPQQ.js";
23
+ import {
24
+ bridgeToEthereum,
25
+ getBridgeQuote,
26
+ getBridgeStatus,
27
+ getL2Balance,
28
+ getTotalPosition
29
+ } from "./chunk-GL6TLHSF.js";
30
+ import {
31
+ getBalance,
32
+ getConversionRate,
33
+ getRewards,
15
34
  unwrapWsteth,
16
- updateSettings,
17
35
  wrapSteth
18
- } from "./chunk-RE3UIDLV.js";
19
- import "./chunk-PIFEXJ56.js";
36
+ } from "./chunk-EKZFGIVK.js";
37
+ import "./chunk-P6VFMSPM.js";
38
+ import {
39
+ loadBounds,
40
+ saveBounds
41
+ } from "./chunk-CH4MXPWS.js";
42
+ import {
43
+ initLedger,
44
+ ledgerStats,
45
+ logEntry,
46
+ queryLedger
47
+ } from "./chunk-RR74UAKD.js";
48
+ import "./chunk-PDX44BCA.js";
20
49
 
21
50
  // src/chat/session.ts
22
51
  import * as readline from "readline";
23
52
  import * as fs from "fs";
24
53
  import * as path from "path";
54
+ import { fileURLToPath } from "url";
25
55
 
26
56
  // src/chat/providers.ts
27
57
  async function callAnthropic(apiKey, model, messages, tools) {
@@ -325,14 +355,158 @@ var TOOL_DEFS = [
325
355
  },
326
356
  {
327
357
  name: "update_settings",
328
- description: "Change mode, network, or RPC.",
358
+ description: "Change mode, network, RPC, or chain scope.",
329
359
  parameters: {
330
360
  type: "object",
331
361
  properties: {
332
362
  network: { type: "string", enum: ["hoodi", "mainnet"] },
333
363
  mode: { type: "string", enum: ["simulation", "live"] },
334
364
  rpc: { type: "string", nullable: true },
335
- model: { type: "string" }
365
+ model: { type: "string" },
366
+ chain_scope: { type: "string", enum: ["ethereum", "all"], description: "ethereum = L1 only, all = L1 + Base/Arbitrum bridging" }
367
+ }
368
+ }
369
+ },
370
+ {
371
+ name: "get_l2_balance",
372
+ description: "Get ETH and wstETH balances on Base or Arbitrum L2. Mainnet only.",
373
+ parameters: {
374
+ type: "object",
375
+ required: ["source_chain"],
376
+ properties: {
377
+ source_chain: { type: "string", enum: ["base", "arbitrum"], description: "L2 chain to query" },
378
+ address: { type: "string", description: "Address to check (optional, defaults to wallet)" }
379
+ }
380
+ }
381
+ },
382
+ {
383
+ name: "get_bridge_quote",
384
+ description: "Get a quote for bridging ETH or wstETH from an L2 to Ethereum L1 via LI.FI. Mainnet only.",
385
+ parameters: {
386
+ type: "object",
387
+ required: ["source_chain", "token", "amount"],
388
+ properties: {
389
+ source_chain: { type: "string", enum: ["base", "arbitrum"] },
390
+ token: { type: "string", enum: ["ETH", "wstETH"], description: "Token to bridge" },
391
+ amount: { type: "string", description: 'Amount to bridge (e.g. "0.1")' },
392
+ to_token: { type: "string", enum: ["ETH", "wstETH"], description: "Token to receive on L1 (default ETH)" }
393
+ }
394
+ }
395
+ },
396
+ {
397
+ name: "bridge_to_ethereum",
398
+ description: "Bridge ETH or wstETH from Base/Arbitrum to Ethereum L1 via LI.FI. Mainnet only.",
399
+ parameters: {
400
+ type: "object",
401
+ required: ["source_chain", "token", "amount"],
402
+ properties: {
403
+ source_chain: { type: "string", enum: ["base", "arbitrum"] },
404
+ token: { type: "string", enum: ["ETH", "wstETH"] },
405
+ amount: { type: "string", description: "Amount to bridge" },
406
+ to_token: { type: "string", enum: ["ETH", "wstETH"] },
407
+ dry_run: { type: "boolean", description: "Simulate without broadcasting" }
408
+ }
409
+ }
410
+ },
411
+ {
412
+ name: "get_bridge_status",
413
+ description: "Check the status of an in-progress bridge transaction. Mainnet only.",
414
+ parameters: {
415
+ type: "object",
416
+ required: ["tx_hash", "source_chain"],
417
+ properties: {
418
+ tx_hash: { type: "string", description: "Bridge transaction hash on the L2" },
419
+ source_chain: { type: "string", enum: ["base", "arbitrum"] }
420
+ }
421
+ }
422
+ },
423
+ {
424
+ name: "set_alert",
425
+ description: "Create a new alert. Conditions: balance_below, balance_above, reward_rate_below, reward_rate_above, withdrawal_ready, proposal_new, conversion_rate_above, conversion_rate_below.",
426
+ parameters: {
427
+ type: "object",
428
+ required: ["condition"],
429
+ properties: {
430
+ condition: { type: "string", description: "Alert condition type" },
431
+ threshold: { type: "number", description: "Numeric threshold (required for _above/_below conditions)" },
432
+ channel: { type: "string", enum: ["telegram", "webhook"], description: "Notification channel (default: telegram)" }
433
+ }
434
+ }
435
+ },
436
+ {
437
+ name: "list_alerts",
438
+ description: "List all configured alerts.",
439
+ parameters: { type: "object", properties: {} }
440
+ },
441
+ {
442
+ name: "remove_alert",
443
+ description: "Remove an alert by ID.",
444
+ parameters: {
445
+ type: "object",
446
+ required: ["id"],
447
+ properties: { id: { type: "string", description: "Alert ID to remove" } }
448
+ }
449
+ },
450
+ {
451
+ name: "configure_alert_channels",
452
+ description: "Configure Telegram and/or webhook notification channels for alerts.",
453
+ parameters: {
454
+ type: "object",
455
+ properties: {
456
+ telegram_token: { type: "string", description: "Telegram bot token" },
457
+ telegram_chat_id: { type: "string", description: "Telegram chat ID" },
458
+ webhook_url: { type: "string", description: "Webhook URL for HTTP POST notifications" }
459
+ }
460
+ }
461
+ },
462
+ {
463
+ name: "get_total_position",
464
+ description: "Aggregated cross-chain position: ETH, stETH, wstETH across Ethereum + Base + Arbitrum, all converted to ETH equivalent.",
465
+ parameters: {
466
+ type: "object",
467
+ properties: {
468
+ address: { type: "string", description: "Ethereum address (optional)" }
469
+ }
470
+ }
471
+ },
472
+ {
473
+ name: "get_bounds",
474
+ description: "Get current policy bounds (max stake per tx, daily limit, min ETH reserve, governance auto-vote).",
475
+ parameters: { type: "object", properties: {} }
476
+ },
477
+ {
478
+ name: "set_bounds",
479
+ description: "Update policy bounds that gate write operations.",
480
+ parameters: {
481
+ type: "object",
482
+ properties: {
483
+ maxStakePerTx: { type: "number", description: "Max ETH per single stake" },
484
+ maxDailyStake: { type: "number", description: "Max ETH staked per day" },
485
+ minEthReserve: { type: "number", description: "Min ETH to keep unstaked for gas" },
486
+ autoRestakeThreshold: { type: "number", description: "Auto-restake rewards threshold in ETH" },
487
+ governanceAutoVote: { type: "boolean", description: "Allow agent to auto-vote on proposals" }
488
+ }
489
+ }
490
+ },
491
+ {
492
+ name: "get_trade_history",
493
+ description: "Query the activity ledger with filters.",
494
+ parameters: {
495
+ type: "object",
496
+ properties: {
497
+ tool: { type: "string", description: "Filter by tool name (e.g. stake_eth)" },
498
+ since: { type: "string", description: "ISO date to filter from (e.g. 2026-01-01)" },
499
+ limit: { type: "number", description: "Max results (default 50)" }
500
+ }
501
+ }
502
+ },
503
+ {
504
+ name: "get_staking_summary",
505
+ description: "Aggregate stats from the activity ledger: total operations, staked ETH, errors.",
506
+ parameters: {
507
+ type: "object",
508
+ properties: {
509
+ since: { type: "string", description: "ISO date to filter from (optional)" }
336
510
  }
337
511
  }
338
512
  }
@@ -386,6 +560,54 @@ async function executeTool(name, args) {
386
560
  case "update_settings":
387
561
  result = updateSettings(args);
388
562
  break;
563
+ case "get_l2_balance":
564
+ result = await getL2Balance(args.source_chain, args.address);
565
+ break;
566
+ case "get_bridge_quote":
567
+ result = await getBridgeQuote(args.source_chain, args.token, args.amount, args.to_token);
568
+ break;
569
+ case "bridge_to_ethereum":
570
+ result = await bridgeToEthereum(args.source_chain, args.token, args.amount, args.to_token, args.dry_run);
571
+ break;
572
+ case "get_bridge_status":
573
+ result = await getBridgeStatus(args.tx_hash, args.source_chain);
574
+ break;
575
+ case "set_alert":
576
+ result = setAlert(args);
577
+ break;
578
+ case "list_alerts":
579
+ result = listAlerts();
580
+ break;
581
+ case "remove_alert":
582
+ result = removeAlertById(args.id);
583
+ break;
584
+ case "configure_alert_channels":
585
+ result = configureAlertChannels(args);
586
+ break;
587
+ case "get_total_position":
588
+ result = await getTotalPosition(args.address);
589
+ break;
590
+ case "get_bounds":
591
+ result = loadBounds();
592
+ break;
593
+ case "set_bounds": {
594
+ const current = loadBounds();
595
+ const patch = args;
596
+ if (patch.maxStakePerTx !== void 0) current.maxStakePerTx = patch.maxStakePerTx;
597
+ if (patch.maxDailyStake !== void 0) current.maxDailyStake = patch.maxDailyStake;
598
+ if (patch.minEthReserve !== void 0) current.minEthReserve = patch.minEthReserve;
599
+ if (patch.autoRestakeThreshold !== void 0) current.autoRestakeThreshold = patch.autoRestakeThreshold;
600
+ if (patch.governanceAutoVote !== void 0) current.governanceAutoVote = patch.governanceAutoVote;
601
+ saveBounds(current);
602
+ result = current;
603
+ break;
604
+ }
605
+ case "get_trade_history":
606
+ result = queryLedger({ tool: args.tool, since: args.since, limit: args.limit });
607
+ break;
608
+ case "get_staking_summary":
609
+ result = ledgerStats(args.since);
610
+ break;
389
611
  default:
390
612
  return `Unknown tool: ${name}`;
391
613
  }
@@ -395,6 +617,50 @@ async function executeTool(name, args) {
395
617
  }
396
618
  }
397
619
 
620
+ // src/bounds/enforce.ts
621
+ var STAKE_TOOLS = /* @__PURE__ */ new Set(["stake_eth", "bridge_to_ethereum"]);
622
+ async function checkBounds(toolName, args) {
623
+ const bounds = loadBounds();
624
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
625
+ if (bounds.lastResetDate !== today) {
626
+ bounds.dailyStaked = 0;
627
+ bounds.lastResetDate = today;
628
+ saveBounds(bounds);
629
+ }
630
+ if (toolName === "cast_vote" && !bounds.governanceAutoVote) {
631
+ return { allowed: false, reason: `Governance auto-vote is disabled. Set bounds: governanceAutoVote = true` };
632
+ }
633
+ if (STAKE_TOOLS.has(toolName)) {
634
+ const amount = parseFloat(args.amount_eth ?? args.amount ?? "0");
635
+ if (isNaN(amount) || amount <= 0) return { allowed: true };
636
+ if (amount > bounds.maxStakePerTx) {
637
+ return { allowed: false, reason: `Amount ${amount} ETH exceeds max per tx (${bounds.maxStakePerTx} ETH)` };
638
+ }
639
+ if (bounds.dailyStaked + amount > bounds.maxDailyStake) {
640
+ return { allowed: false, reason: `Would exceed daily limit: staked today ${bounds.dailyStaked.toFixed(4)} + ${amount} > ${bounds.maxDailyStake} ETH` };
641
+ }
642
+ try {
643
+ const bal = await getBalance();
644
+ const ethBal = parseFloat(bal.balances.eth);
645
+ if (ethBal - amount < bounds.minEthReserve) {
646
+ return { allowed: false, reason: `Would leave only ${(ethBal - amount).toFixed(4)} ETH, below reserve of ${bounds.minEthReserve} ETH` };
647
+ }
648
+ } catch {
649
+ }
650
+ }
651
+ return { allowed: true };
652
+ }
653
+ function recordStake(amount) {
654
+ const bounds = loadBounds();
655
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
656
+ if (bounds.lastResetDate !== today) {
657
+ bounds.dailyStaked = 0;
658
+ bounds.lastResetDate = today;
659
+ }
660
+ bounds.dailyStaked += amount;
661
+ saveBounds(bounds);
662
+ }
663
+
398
664
  // src/chat/session.ts
399
665
  var R = "\x1B[0m";
400
666
  var B = "\x1B[1m";
@@ -412,30 +678,39 @@ ${CY}${B} \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2
412
678
  ${CY}${B} \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ${R}
413
679
  ${CY}${B} \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 ${R}
414
680
  ${CY}${B} \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D ${R}
415
- ${D} powered by Lido \u2B21${R}
681
+ ${D} powered by Lido${R}
416
682
  `;
417
683
  function ln(text = "") {
418
684
  process.stdout.write(text + "\n");
419
685
  }
686
+ function printResponse(text) {
687
+ const lines = text.split("\n");
688
+ const prefix = `${B}${GR}moly${R} \u203A `;
689
+ const indent = " ";
690
+ ln();
691
+ lines.forEach((line, i) => {
692
+ process.stdout.write((i === 0 ? prefix : indent) + line + "\n");
693
+ });
694
+ ln();
695
+ }
420
696
  function saveTrade(toolName, args, result) {
421
697
  try {
422
- const tradesDir = path.join(process.cwd(), "trades");
423
- if (!fs.existsSync(tradesDir)) fs.mkdirSync(tradesDir, { recursive: true });
424
- const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
425
- const file = path.join(tradesDir, `${today}.jsonl`);
426
- const record = JSON.stringify({
427
- ts: (/* @__PURE__ */ new Date()).toISOString(),
698
+ let txHash;
699
+ let amount;
700
+ try {
701
+ const parsed = JSON.parse(result);
702
+ txHash = parsed.txHash ?? parsed.tx_hash;
703
+ amount = args.amount_eth ?? args.amount_steth ?? args.amount;
704
+ } catch {
705
+ }
706
+ logEntry({
428
707
  tool: toolName,
429
708
  args,
430
- result: (() => {
431
- try {
432
- return JSON.parse(result);
433
- } catch {
434
- return result;
435
- }
436
- })()
709
+ result,
710
+ tx_hash: txHash,
711
+ amount,
712
+ status: "ok"
437
713
  });
438
- fs.appendFileSync(file, record + "\n");
439
714
  } catch {
440
715
  }
441
716
  }
@@ -453,18 +728,44 @@ var WRITE_TOOLS = /* @__PURE__ */ new Set([
453
728
  "claim_withdrawals",
454
729
  "wrap_steth",
455
730
  "unwrap_wsteth",
456
- "cast_vote"
731
+ "cast_vote",
732
+ "bridge_to_ethereum"
457
733
  ]);
458
734
  async function startChatSession(cfg) {
459
735
  if (!cfg.ai) {
460
736
  ln(`${RE}No AI provider configured. Run: moly setup${R}`);
461
737
  process.exit(1);
462
738
  }
739
+ try {
740
+ initLedger();
741
+ } catch {
742
+ }
463
743
  const { provider, apiKey, model } = cfg.ai;
744
+ let skillContext = "";
745
+ try {
746
+ const skillPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../lido.skill.md");
747
+ if (fs.existsSync(skillPath)) {
748
+ skillContext = fs.readFileSync(skillPath, "utf-8") + "\n\n";
749
+ }
750
+ } catch {
751
+ }
464
752
  const messages = [
465
753
  {
466
754
  role: "user",
467
- content: `You are Moly, a terminal assistant for Lido Finance on ${cfg.network}. Mode: ${cfg.mode} (${cfg.mode === "simulation" ? "dry-run, nothing broadcast" : "LIVE - real on-chain transactions"}). You can only do what your tools support: staking ETH, withdrawals, wrap/unwrap stETH/wstETH, balances, rewards, and Lido DAO governance. If asked about anything outside those tools (e.g. Lido Vaults, validators, node operators, DeFi integrations), say clearly and briefly that it is not supported. IMPORTANT: This is a terminal. Never use markdown. No **bold**, no bullet points, no headers, no backticks. Plain text only. Be concise. For live transactions always confirm first.`
755
+ content: skillContext + `You are Moly, a terminal assistant for Lido Finance on ${cfg.network}.
756
+ Mode: ${cfg.mode} (${cfg.mode === "simulation" ? "dry-run, nothing broadcast" : "LIVE - real on-chain transactions"}).
757
+ Chain scope: ${cfg.chainScope ?? "ethereum"}.
758
+
759
+ You can only do what your tools support: staking ETH, withdrawals, wrap/unwrap stETH/wstETH, balances, rewards, Lido DAO governance${cfg.chainScope === "all" ? ", and L2 bridging from Base/Arbitrum to Ethereum via LI.FI" : ""}.
760
+ ${cfg.chainScope === "all" ? "If the user wants to stake ETH from Base or Arbitrum, first check their L2 balance with get_l2_balance, then bridge to Ethereum with bridge_to_ethereum, then after bridging completes use stake_eth. Bridge takes 1-20 min, tell user to check with get_bridge_status.\n" : ""}If asked about anything outside those tools (e.g. Lido Vaults, validators, node operators, DeFi integrations), say clearly and briefly that it is not supported.
761
+
762
+ OUTPUT FORMAT RULES (terminal, no markdown):
763
+ - Never use **bold**, _italic_, # headers, or backtick code blocks.
764
+ - Use plain dashes (-) for lists, one item per line.
765
+ - Use blank lines to separate sections or groups of information.
766
+ - For key/value data (balances, settings, etc.) use " key: value" format, one per line.
767
+ - Keep prose concise. Lead with the answer, then details.
768
+ - For live transactions always confirm with the user first.`
468
769
  },
469
770
  {
470
771
  role: "assistant",
@@ -473,8 +774,8 @@ async function startChatSession(cfg) {
473
774
  ];
474
775
  printBanner(cfg);
475
776
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
476
- const prompt = () => new Promise((resolve, reject) => {
477
- rl.question(`${B}${BL}you${R} \u203A `, resolve);
777
+ const prompt = () => new Promise((resolve2, reject) => {
778
+ rl.question(`${B}${BL}you${R} \u203A `, resolve2);
478
779
  rl.once("close", () => reject(new Error("closed")));
479
780
  });
480
781
  while (true) {
@@ -500,25 +801,38 @@ async function startChatSession(cfg) {
500
801
  const toolResults = [];
501
802
  for (const tc of response.toolCalls) {
502
803
  ln(`${D} \u21B3 ${MA}${tc.name}${R}${D} ${JSON.stringify(tc.args)}${R}`);
804
+ if (WRITE_TOOLS.has(tc.name)) {
805
+ try {
806
+ const check = await checkBounds(tc.name, tc.args);
807
+ if (!check.allowed) {
808
+ ln(`${RE} \u2715 BLOCKED: ${check.reason}${R}`);
809
+ toolResults.push(makeToolResultMessage(provider, tc.id, tc.name, JSON.stringify({ blocked: true, reason: check.reason })));
810
+ continue;
811
+ }
812
+ } catch {
813
+ }
814
+ }
503
815
  const result = await executeTool(tc.name, tc.args);
504
816
  ln(`${D} ${result.slice(0, 300)}${result.length > 300 ? "\u2026" : ""}${R}`);
505
817
  if (WRITE_TOOLS.has(tc.name)) {
506
818
  saveTrade(tc.name, tc.args, result);
819
+ if (tc.name === "stake_eth" && tc.args.amount_eth) {
820
+ try {
821
+ recordStake(parseFloat(tc.args.amount_eth));
822
+ } catch {
823
+ }
824
+ }
507
825
  }
508
826
  toolResults.push(makeToolResultMessage(provider, tc.id, tc.name, result));
509
827
  }
510
828
  messages.push(...toolResults);
511
829
  if (response.text) {
512
- ln();
513
- ln(`${B}${GR}moly${R} \u203A ${response.text}`);
514
- ln();
830
+ printResponse(response.text);
515
831
  }
516
832
  continue;
517
833
  }
518
834
  if (response.text) {
519
- ln();
520
- ln(`${B}${GR}moly${R} \u203A ${response.text}`);
521
- ln();
835
+ printResponse(response.text);
522
836
  }
523
837
  break;
524
838
  }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_BOUNDS,
4
+ loadBounds,
5
+ resetBounds,
6
+ saveBounds
7
+ } from "./chunk-CH4MXPWS.js";
8
+ import "./chunk-PDX44BCA.js";
9
+ export {
10
+ DEFAULT_BOUNDS,
11
+ loadBounds,
12
+ resetBounds,
13
+ saveBounds
14
+ };
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addAlert,
4
+ loadAlerts,
5
+ loadChannelConfig,
6
+ removeAlert,
7
+ saveAlerts,
8
+ saveChannelConfig
9
+ } from "./chunk-6F64RPQQ.js";
10
+ import "./chunk-P6VFMSPM.js";
11
+ import "./chunk-PDX44BCA.js";
12
+ export {
13
+ addAlert,
14
+ loadAlerts,
15
+ loadChannelConfig,
16
+ removeAlert,
17
+ saveAlerts,
18
+ saveChannelConfig
19
+ };
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ exportLedger,
4
+ initLedger,
5
+ ledgerStats,
6
+ logEntry,
7
+ queryLedger
8
+ } from "./chunk-RR74UAKD.js";
9
+ import "./chunk-PDX44BCA.js";
10
+ export {
11
+ exportLedger,
12
+ initLedger,
13
+ ledgerStats,
14
+ logEntry,
15
+ queryLedger
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moly-mcp/lido",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Lido MCP Server — stake, unstake, wrap, govern. Works with Claude Desktop, Cursor, Windsurf, and any MCP client.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,10 +23,15 @@
23
23
  "@clack/prompts": "^0.9.1",
24
24
  "@lidofinance/lido-ethereum-sdk": "^4.7.0",
25
25
  "@modelcontextprotocol/sdk": "^1.27.1",
26
+ "better-sqlite3": "^11.7.0",
26
27
  "viem": "^2.47.4",
27
28
  "zod": "^3.24.0"
28
29
  },
30
+ "optionalDependencies": {
31
+ "@open-wallet-standard/core": "^0.1.0"
32
+ },
29
33
  "devDependencies": {
34
+ "@types/better-sqlite3": "^7.6.12",
30
35
  "@types/node": "^20",
31
36
  "tsup": "^8.4.0",
32
37
  "typescript": "^5"