@lombard.finance/sdk-agent 0.1.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/dist/tools.js ADDED
@@ -0,0 +1,1641 @@
1
+ import { BTCE_VAULT_CONTRACTS as xe, getLbtcContractAddresses as R, Env as m, ChainId as T, MIN_STAKE_AMOUNT_BTC as re, MIN_REDEEM_AMOUNT_BTC as C, BTC_DECIMALS as pe, makePublicClient as X, Token as _, getExchangeRatio as Ee, getLBTCExchangeRate as Me, fromSatoshi as oe, getDepositsByAddress as he, getDepositStatus as me, getDepositStatusDisplay as fe, getUnstakesByAddress as Re, getEarnApy as Pe, getEarnTVL as De, getDepositBtcAddress as Fe, requiresAutoMintFee as Ue, getNetworkFeeSignature as Ne, getEarnWithdrawals as be, getApy as qe, getEarnPosition as Oe, getTokenContractInfo as Ve } from "@lombard.finance/sdk";
2
+ import { parseUnits as Q, encodeFunctionData as A, erc20Abi as ye, formatUnits as v } from "viem";
3
+ import { baseSepolia as ne, base as ie, sepolia as ce, mainnet as de } from "viem/chains";
4
+ import { z as c } from "zod";
5
+ import { zodToJsonSchema as je } from "zod-to-json-schema";
6
+ function He() {
7
+ return {
8
+ ...R(m.testnet),
9
+ ...R(m.prod)
10
+ };
11
+ }
12
+ const L = [
13
+ {
14
+ symbol: "LBTC",
15
+ aliases: ["Lombard BTC", "Lombard staked Bitcoin", "lbtc"],
16
+ name: "Lombard BTC",
17
+ description: "Yield-bearing receipt token for native BTC staked via Babylon. 1 LBTC is always worth slightly more than 1 BTC and grows over time as Babylon yield accrues. The exchange rate is never 1:1 — always fetch with get_exchange_rate.",
18
+ isLombardIssued: !0,
19
+ isYieldBearing: !0,
20
+ decimals: 8,
21
+ addresses: He()
22
+ },
23
+ {
24
+ symbol: "BTC.b",
25
+ aliases: ["BTCb", "BTC dot b", "btc.b", "Lombard cross-chain BTC"],
26
+ name: "BTC.b",
27
+ description: "Lombard's cross-chain wrapped Bitcoin token. Bridged BTC, NOT yield-bearing. Use BTC.b when the user wants wrapped BTC on an EVM chain without yield exposure.",
28
+ isLombardIssued: !0,
29
+ isYieldBearing: !1,
30
+ decimals: 8,
31
+ addresses: {},
32
+ notes: "Per-chain BTC.b contract addresses are resolved on demand via the SDK's getTokenContractInfo(Token.BTCb, chainId, env). Call get_token_info with chainId+address for verification."
33
+ },
34
+ {
35
+ symbol: "BTCe",
36
+ aliases: ["Bitcoin Earn token", "Bitcoin Earn vault share", "BTCE", "btce"],
37
+ name: "Bitcoin Earn vault share (BTCe)",
38
+ description: "ERC4626 wrapper share token for the Bitcoin Earn vault. Holding BTCe is how users participate in Bitcoin Earn yield; deposits via prepare_deploy_to_vault mint BTCe, withdrawals via prepare_vault_withdrawal burn it.",
39
+ isLombardIssued: !0,
40
+ isYieldBearing: !0,
41
+ decimals: 8,
42
+ addresses: { ...xe },
43
+ notes: "BTCe wraps the underlying Veda share (LBTCv) 1:1 today; convertToAssets() is the authoritative conversion if the ratio ever changes."
44
+ }
45
+ ];
46
+ function ze(t) {
47
+ if (!t) return;
48
+ const e = t.trim().toLowerCase();
49
+ for (const a of L)
50
+ if (a.symbol.toLowerCase() === e || a.aliases.some((s) => s.toLowerCase() === e)) return a;
51
+ }
52
+ function Ye(t, e) {
53
+ if (!e) return;
54
+ const a = e.toLowerCase();
55
+ for (const s of L) {
56
+ const r = s.addresses[t];
57
+ if (r && r.toLowerCase() === a) return s;
58
+ }
59
+ }
60
+ function Ze() {
61
+ return [
62
+ "# Lombard asset glossary",
63
+ "",
64
+ "These are the canonical Lombard-related assets. Use these names verbatim. If a user asks about an asset not listed here, call get_token_info to look it up before saying you don't know.",
65
+ "",
66
+ ...L.map((e) => {
67
+ const a = [
68
+ e.isLombardIssued ? "Lombard-issued" : "third-party",
69
+ e.isYieldBearing ? "yield-bearing" : "not yield-bearing"
70
+ ].join(", ");
71
+ return `- **${e.symbol}** (${e.name}; ${a}; ${e.decimals} decimals) — ${e.description}`;
72
+ })
73
+ ].join(`
74
+ `);
75
+ }
76
+ const ba = Ze(), le = {
77
+ [de.id]: { chain: de, chainId: T.ethereum, env: m.prod, name: "Ethereum" },
78
+ [ce.id]: { chain: ce, chainId: T.sepolia, env: m.testnet, name: "Sepolia" },
79
+ [ie.id]: { chain: ie, chainId: T.base, env: m.prod, name: "Base" },
80
+ [ne.id]: { chain: ne, chainId: T.baseSepoliaTestnet, env: m.testnet, name: "Base Sepolia" }
81
+ };
82
+ function u(t) {
83
+ const e = le[t];
84
+ if (!e) {
85
+ const a = Object.keys(le).join(", ");
86
+ throw new Error(`Unsupported chain ID: ${t}. Supported: ${a}`);
87
+ }
88
+ return e;
89
+ }
90
+ const f = c.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid EVM address"), y = c.string().regex(/^\d+(\.\d+)?$/, "Must be a numeric string").refine(
91
+ (t) => parseFloat(t) > 0 && parseFloat(t) < 1e3,
92
+ "Amount must be positive and under 1000"
93
+ ), We = "Chain ID. Default to the user's connected chain (provided in your wallet context) unless they specify a different one. Supported: 1=Ethereum, 11155111=Sepolia, 8453=Base, 84532=Base Sepolia.", b = c.number().describe(We), p = c.object({
94
+ address: f.describe("EVM wallet address (0x...)"),
95
+ chainId: b
96
+ }), P = c.object({
97
+ chainId: c.number().optional().describe("Chain ID for environment resolution (optional)")
98
+ }), D = c.object({
99
+ amount: y.describe("Amount of BTC.b to stake (e.g. '0.1')"),
100
+ chainId: b
101
+ }), F = c.object({
102
+ amount: y.describe("Amount of LBTC to unstake"),
103
+ outputAsset: c.enum(["BTC", "BTCb"]).describe("Output: BTC (cross-chain) or BTCb (same chain)"),
104
+ recipient: c.string().optional().describe("Destination address (required for BTC output)"),
105
+ chainId: b
106
+ }), U = p, N = c.object({
107
+ chainId: c.number().optional().describe(
108
+ "Chain ID to filter strategies (optional, returns all if omitted)"
109
+ )
110
+ }), q = p, O = c.object({
111
+ amount: y.describe("Amount of LBTC to deploy"),
112
+ chainId: b
113
+ }), ge = c.object({}), V = c.object({
114
+ amount: y.describe("Amount of vault shares to withdraw"),
115
+ address: f.describe(
116
+ "EVM wallet address requesting the withdrawal. Used to check for an existing active withdrawal (only one is allowed per user per vault)."
117
+ ),
118
+ chainId: b
119
+ }), j = c.object({
120
+ depositTxHash: c.string().min(1).describe("The BTC deposit transaction hash to claim"),
121
+ address: f.describe("EVM wallet address that owns the deposit"),
122
+ chainId: b
123
+ }), H = c.object({
124
+ amount: y.describe("Amount of BTC.b to redeem for native BTC"),
125
+ recipient: c.string().describe(
126
+ "Bitcoin destination address for the redeemed BTC. MUST be a valid Bitcoin address for the network (bc1.../1.../3... mainnet; tb1.../m.../n.../2... testnet). Ask the user for this explicitly — never infer from prior context."
127
+ ),
128
+ chainId: b
129
+ }), we = c.object({
130
+ query: c.string().optional().describe(
131
+ "Free-text token name or symbol (e.g. 'BTCe', 'LBTC', 'Bitcoin Earn vault share')."
132
+ ),
133
+ address: c.string().optional().describe(
134
+ "Optional contract address (0x...). When provided, chainId is required too."
135
+ ),
136
+ chainId: c.number().optional().describe("Chain ID for an address-based lookup.")
137
+ }), z = c.object({
138
+ address: f.describe(
139
+ "EVM wallet address that owns the active withdrawal being cancelled."
140
+ ),
141
+ chainId: b
142
+ }), Ke = c.object({
143
+ address: f.describe("EVM wallet address (0x...)")
144
+ }), Y = c.object({
145
+ category: c.string().optional().describe(
146
+ "Filter by category: automated-strategy, borrow-stables, looping, dex-lp, other"
147
+ ),
148
+ chain: c.string().optional().describe("Filter by chain (e.g. Ethereum, Base, Solana)"),
149
+ protocol: c.string().optional().describe("Filter by protocol (e.g. Morpho, Aave, Uniswap)")
150
+ }), Z = c.object({
151
+ tokenAddress: f.describe(
152
+ "ERC-20 token contract address (0x...). Get this from tool results like get_morpho_lbtc_markets, not from memory."
153
+ ),
154
+ address: f.describe("EVM wallet address to check balance for"),
155
+ chainId: b
156
+ }), Be = c.object({}), $ = c.string().regex(
157
+ /^0x[a-fA-F0-9]{64}$/,
158
+ "Invalid Morpho market ID (must be 0x + 64 hex chars)"
159
+ ).describe("Morpho Blue market ID (from get_morpho_lbtc_markets)"), W = c.object({
160
+ marketId: $,
161
+ amount: y.describe(
162
+ "Amount of LBTC to supply as collateral (e.g. '0.1')"
163
+ ),
164
+ address: f.describe("EVM wallet address supplying the collateral")
165
+ }), K = c.object({
166
+ marketId: $,
167
+ amount: y.describe(
168
+ "Amount of loan asset to borrow (e.g. '100' for 100 USDC)"
169
+ ),
170
+ address: f.describe("EVM wallet address borrowing the asset")
171
+ }), G = c.object({
172
+ marketId: $,
173
+ amount: y.describe(
174
+ "Amount of loan asset to repay (e.g. '1' for 1 USDC)"
175
+ ),
176
+ address: f.describe("EVM wallet address repaying the debt")
177
+ }), J = c.object({
178
+ marketId: $,
179
+ address: f.describe("EVM wallet address to check position for")
180
+ });
181
+ function l(t) {
182
+ return je(t, { target: "openAi" });
183
+ }
184
+ const Ge = l(z);
185
+ l(Ke);
186
+ const g = l(p), Je = l(P), Xe = l(D), Qe = l(F), et = l(U), tt = l(N), at = l(q), st = l(O), rt = l(ge), ot = l(V), nt = l(j), it = l(Y), ct = l(Z), dt = l(we), lt = l(H), ut = l(Be), pt = l(
187
+ W
188
+ ), ht = l(K), mt = l(G), ft = l(J), bt = /* @__PURE__ */ new Set([
189
+ 11155111,
190
+ // ethereum sepolia
191
+ 84532
192
+ // base sepolia
193
+ ]), yt = /^(bc1[a-z0-9]{39,87}|[13][a-km-zA-HJ-NP-Z1-9]{25,34})$/, gt = /^(tb1[a-z0-9]{39,87}|[mn2][a-km-zA-HJ-NP-Z1-9]{25,34})$/;
194
+ function ve(t, e) {
195
+ if (typeof t != "string") return !1;
196
+ const a = t.trim();
197
+ return a.length === 0 ? !1 : bt.has(e) ? gt.test(a) : yt.test(a);
198
+ }
199
+ function x(t) {
200
+ if (typeof t != "string" || !/^\d+(\.\d+)?$/.test(t)) return !1;
201
+ const e = Number(t);
202
+ return Number.isFinite(e) && e > 0;
203
+ }
204
+ function wt(t) {
205
+ const e = [], a = [];
206
+ if (x(t.amount) ? Number(t.amount) < C && a.push(
207
+ `amount ${t.amount} is below the protocol minimum of ${C} LBTC. Network fees may push the practical minimum higher; ask the user to confirm a value at or above ${C}.`
208
+ ) : a.push(
209
+ "amount must be a positive numeric string (e.g. '0.5')"
210
+ ), t.outputAsset !== "BTC" && t.outputAsset !== "BTCb" && a.push("outputAsset must be either 'BTC' or 'BTCb'"), t.outputAsset === "BTC" && (typeof t.recipient != "string" || t.recipient.length === 0 ? e.push("recipient") : ve(t.recipient, t.chainId) || a.push(
211
+ "recipient is not a valid Bitcoin address for this network. Mainnet: bc1.../1.../3...; Sepolia/testnet: tb1.../m.../n.../2..."
212
+ )), e.length === 0 && a.length === 0)
213
+ return { valid: !0 };
214
+ const s = [];
215
+ return e.length > 0 && s.push(
216
+ `Ask the user for: ${e.join(", ")}. Do not infer these values from prior context.`
217
+ ), a.length > 0 && s.push(
218
+ "Surface the listed errors to the user and re-prompt; do not retry the tool with the same arguments."
219
+ ), {
220
+ valid: !1,
221
+ missing: e,
222
+ errors: a,
223
+ note: s.join(" ")
224
+ };
225
+ }
226
+ function Bt(t) {
227
+ const e = [];
228
+ return x(t.amount) ? Number(t.amount) < re && e.push(
229
+ `amount ${t.amount} is below the protocol minimum of ${re} BTC.`
230
+ ) : e.push("amount must be a positive numeric string (e.g. '0.5')"), e.length === 0 ? { valid: !0 } : {
231
+ valid: !1,
232
+ missing: [],
233
+ errors: e,
234
+ note: "Surface the listed errors to the user and re-prompt; do not retry the tool with the same arguments."
235
+ };
236
+ }
237
+ function vt(t) {
238
+ const e = [], a = [];
239
+ if (x(t.amount) ? Number(t.amount) < C && a.push(
240
+ `amount ${t.amount} is below the protocol minimum of ${C} BTC. Network fees may push the practical minimum higher.`
241
+ ) : a.push("amount must be a positive numeric string (e.g. '0.001')"), typeof t.recipient != "string" || t.recipient.length === 0 ? e.push("recipient") : ve(t.recipient, t.chainId) || a.push(
242
+ "recipient is not a valid Bitcoin address for this network. Mainnet: bc1.../1.../3...; Sepolia/testnet: tb1.../m.../n.../2..."
243
+ ), e.length === 0 && a.length === 0) return { valid: !0 };
244
+ const s = [];
245
+ return e.length > 0 && s.push(
246
+ `Ask the user for: ${e.join(", ")}. Do not infer these values from prior context.`
247
+ ), a.length > 0 && s.push(
248
+ "Surface the listed errors to the user and re-prompt; do not retry the tool with the same arguments."
249
+ ), {
250
+ valid: !1,
251
+ missing: e,
252
+ errors: a,
253
+ note: s.join(" ")
254
+ };
255
+ }
256
+ function Te(t) {
257
+ return x(t.amount) ? { valid: !0 } : {
258
+ valid: !1,
259
+ missing: [],
260
+ errors: ["amount must be a positive numeric string (e.g. '0.5')"],
261
+ note: "Surface the listed errors to the user and re-prompt; do not retry the tool with the same arguments."
262
+ };
263
+ }
264
+ function Tt(t, e) {
265
+ const a = (e == null ? void 0 : e.mainnet) ?? process.env.LOMBARD_PARTNER_ID ?? "lombardtest1", s = (e == null ? void 0 : e.testnet) ?? process.env.LOMBARD_TESTNET_PARTNER_ID ?? "test1";
266
+ return t === m.testnet ? s : a;
267
+ }
268
+ const w = "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", I = R(m.prod)[T.ethereum], Ct = "https://api.morpho.org/graphql", At = 1e4, ee = {
269
+ name: "marketParams",
270
+ type: "tuple",
271
+ components: [
272
+ { name: "loanToken", type: "address" },
273
+ { name: "collateralToken", type: "address" },
274
+ { name: "oracle", type: "address" },
275
+ { name: "irm", type: "address" },
276
+ { name: "lltv", type: "uint256" }
277
+ ]
278
+ }, kt = [
279
+ {
280
+ name: "supplyCollateral",
281
+ type: "function",
282
+ stateMutability: "nonpayable",
283
+ inputs: [
284
+ ee,
285
+ { name: "assets", type: "uint256" },
286
+ { name: "onBehalf", type: "address" },
287
+ { name: "data", type: "bytes" }
288
+ ],
289
+ outputs: []
290
+ }
291
+ ], _t = [
292
+ {
293
+ name: "borrow",
294
+ type: "function",
295
+ stateMutability: "nonpayable",
296
+ inputs: [
297
+ ee,
298
+ { name: "assets", type: "uint256" },
299
+ { name: "shares", type: "uint256" },
300
+ { name: "onBehalf", type: "address" },
301
+ { name: "receiver", type: "address" }
302
+ ],
303
+ outputs: [
304
+ { name: "assetsBorrowed", type: "uint256" },
305
+ { name: "sharesBorrowed", type: "uint256" }
306
+ ]
307
+ }
308
+ ], ue = [
309
+ {
310
+ name: "position",
311
+ type: "function",
312
+ stateMutability: "view",
313
+ inputs: [
314
+ { name: "id", type: "bytes32" },
315
+ { name: "user", type: "address" }
316
+ ],
317
+ outputs: [
318
+ { name: "supplyShares", type: "uint256" },
319
+ { name: "borrowShares", type: "uint128" },
320
+ { name: "collateral", type: "uint128" }
321
+ ]
322
+ },
323
+ {
324
+ name: "market",
325
+ type: "function",
326
+ stateMutability: "view",
327
+ inputs: [{ name: "id", type: "bytes32" }],
328
+ outputs: [
329
+ { name: "totalSupplyAssets", type: "uint128" },
330
+ { name: "totalSupplyShares", type: "uint128" },
331
+ { name: "totalBorrowAssets", type: "uint128" },
332
+ { name: "totalBorrowShares", type: "uint128" },
333
+ { name: "lastUpdate", type: "uint128" },
334
+ { name: "fee", type: "uint128" }
335
+ ]
336
+ }
337
+ ], It = [
338
+ {
339
+ name: "repay",
340
+ type: "function",
341
+ stateMutability: "nonpayable",
342
+ inputs: [
343
+ ee,
344
+ { name: "assets", type: "uint256" },
345
+ { name: "shares", type: "uint256" },
346
+ { name: "onBehalf", type: "address" },
347
+ { name: "data", type: "bytes" }
348
+ ],
349
+ outputs: [
350
+ { name: "assetsRepaid", type: "uint256" },
351
+ { name: "sharesRepaid", type: "uint256" }
352
+ ]
353
+ }
354
+ ], St = [
355
+ {
356
+ name: "price",
357
+ type: "function",
358
+ stateMutability: "view",
359
+ inputs: [],
360
+ outputs: [{ name: "", type: "uint256" }]
361
+ }
362
+ ], Lt = 10n ** 36n, $t = 10n ** 18n, xt = 0.8;
363
+ function Et({
364
+ collateralRaw: t,
365
+ borrowAssetsRaw: e,
366
+ oraclePrice: a,
367
+ lltvRaw: s
368
+ }) {
369
+ const r = Number(v(s, 18));
370
+ if (t === 0n)
371
+ return {
372
+ currentLtv: 0,
373
+ lltv: r,
374
+ healthStatus: e > 0n ? "Bad debt" : "Empty"
375
+ };
376
+ if (e === 0n)
377
+ return {
378
+ currentLtv: 0,
379
+ lltv: r,
380
+ healthStatus: "Collateral only (no borrows)"
381
+ };
382
+ if (a === 0n)
383
+ return {
384
+ currentLtv: 0,
385
+ lltv: r,
386
+ healthStatus: "Unknown (oracle unavailable)"
387
+ };
388
+ const o = t * a / Lt, n = e * $t / o, i = Number(v(n, 18)), d = r * xt;
389
+ let h;
390
+ return i < d ? h = "Healthy" : i < r ? h = "At risk" : h = "Liquidatable", { currentLtv: i, lltv: r, healthStatus: h };
391
+ }
392
+ const Mt = `{
393
+ markets(where: {
394
+ collateralAssetAddress_in: ["${I}"],
395
+ chainId_in: [1]
396
+ }) {
397
+ items {
398
+ marketId: uniqueKey
399
+ loanAsset { symbol address decimals }
400
+ collateralAsset { symbol address decimals }
401
+ oracleAddress
402
+ irmAddress
403
+ lltv
404
+ state {
405
+ supplyApy
406
+ borrowApy
407
+ supplyAssetsUsd
408
+ borrowAssetsUsd
409
+ utilization
410
+ }
411
+ }
412
+ }
413
+ }`;
414
+ function E(t) {
415
+ return `{
416
+ marketByUniqueKey(uniqueKey: "${t}", chainId: 1) {
417
+ marketId: uniqueKey
418
+ loanAsset { symbol address decimals }
419
+ collateralAsset { symbol address decimals }
420
+ oracleAddress
421
+ irmAddress
422
+ lltv
423
+ state {
424
+ supplyApy
425
+ borrowApy
426
+ supplyAssetsUsd
427
+ borrowAssetsUsd
428
+ utilization
429
+ }
430
+ }
431
+ }`;
432
+ }
433
+ async function k(t) {
434
+ var s;
435
+ const e = await fetch(Ct, {
436
+ method: "POST",
437
+ headers: { "Content-Type": "application/json" },
438
+ body: JSON.stringify({ query: t })
439
+ });
440
+ if (!e.ok)
441
+ throw new Error(`Morpho API returned ${e.status}`);
442
+ const a = await e.json();
443
+ if ((s = a.errors) != null && s.length)
444
+ throw new Error(`Morpho API error: ${a.errors[0].message}`);
445
+ return a.data;
446
+ }
447
+ function Rt(t) {
448
+ const e = t.state.supplyAssetsUsd;
449
+ return {
450
+ marketId: t.marketId,
451
+ loanAsset: t.loanAsset.symbol,
452
+ loanAssetAddress: t.loanAsset.address,
453
+ collateralAsset: t.collateralAsset.symbol,
454
+ collateralAssetAddress: t.collateralAsset.address,
455
+ supplyApy: `${(t.state.supplyApy * 100).toFixed(2)}%`,
456
+ borrowApy: `${(t.state.borrowApy * 100).toFixed(2)}%`,
457
+ tvlUsd: `$${e >= 1e6 ? `${(e / 1e6).toFixed(2)}M` : e >= 1e3 ? `${(e / 1e3).toFixed(1)}K` : e.toFixed(0)}`,
458
+ utilization: `${(t.state.utilization * 100).toFixed(1)}%`,
459
+ lltv: `${(Number(t.lltv) / 1e18 * 100).toFixed(0)}%`,
460
+ description: `Borrow ${t.loanAsset.symbol} against LBTC collateral (${(t.state.supplyApy * 100).toFixed(2)}% supply APY, ${(Number(t.lltv) / 1e18 * 100).toFixed(0)}% LLTV)`
461
+ };
462
+ }
463
+ const Pt = {
464
+ name: "get_morpho_lbtc_markets",
465
+ description: "List Morpho Blue lending markets where LBTC is used as collateral. Returns market IDs, loan assets, supply/borrow APYs, TVL, and utilization. Use this to find markets where users can supply LBTC as collateral to borrow other assets.",
466
+ parameters: ut,
467
+ schema: Be,
468
+ execute: async (t) => {
469
+ try {
470
+ const a = (await k(Mt)).markets.items.filter((s) => s.state.supplyAssetsUsd >= At).sort((s, r) => r.state.supplyAssetsUsd - s.state.supplyAssetsUsd).map(Rt);
471
+ return {
472
+ markets: a,
473
+ note: a.length > 0 ? `Found ${a.length} active Morpho markets with LBTC collateral on Ethereum mainnet. Supply LBTC as collateral to borrow the loan asset.` : "No active Morpho markets found for LBTC."
474
+ };
475
+ } catch (e) {
476
+ return {
477
+ markets: [],
478
+ note: "",
479
+ error: e instanceof Error ? e.message : "Failed to fetch Morpho markets"
480
+ };
481
+ }
482
+ }
483
+ }, Dt = {
484
+ name: "prepare_morpho_supply_collateral",
485
+ description: "Prepare transactions to supply LBTC as collateral to a Morpho Blue market. Returns two unsigned transactions: (1) ERC-20 approve for the Morpho contract, and (2) supplyCollateral call. The user's wallet signs both.",
486
+ parameters: pt,
487
+ schema: W,
488
+ execute: async (t) => {
489
+ const { marketId: e, amount: a, address: s } = W.parse(t);
490
+ try {
491
+ const o = (await k(E(e))).marketByUniqueKey;
492
+ if (!o)
493
+ return {
494
+ action: "error",
495
+ marketId: e,
496
+ description: "",
497
+ error: `Market ${e} not found on Morpho.`
498
+ };
499
+ if (o.collateralAsset.address.toLowerCase() !== I.toLowerCase())
500
+ return {
501
+ action: "error",
502
+ marketId: e,
503
+ description: "",
504
+ error: `This market uses ${o.collateralAsset.symbol} as collateral, not LBTC.`
505
+ };
506
+ const n = Q(a, pe), i = A({
507
+ abi: ye,
508
+ functionName: "approve",
509
+ args: [w, n]
510
+ }), d = {
511
+ loanToken: o.loanAsset.address,
512
+ collateralToken: o.collateralAsset.address,
513
+ oracle: o.oracleAddress,
514
+ irm: o.irmAddress,
515
+ lltv: BigInt(o.lltv)
516
+ }, h = A({
517
+ abi: kt,
518
+ functionName: "supplyCollateral",
519
+ args: [
520
+ d,
521
+ n,
522
+ s,
523
+ "0x"
524
+ ]
525
+ });
526
+ return {
527
+ action: "sdk_execute",
528
+ method: "morpho.supplyCollateral",
529
+ params: {
530
+ chainId: 1,
531
+ // Morpho Blue is Ethereum mainnet only
532
+ transactions: [
533
+ {
534
+ to: I,
535
+ data: i,
536
+ label: `Approve Morpho to spend ${a} LBTC`
537
+ },
538
+ {
539
+ to: w,
540
+ data: h,
541
+ label: `Supply ${a} LBTC as collateral to ${o.loanAsset.symbol}/LBTC market`
542
+ }
543
+ ]
544
+ },
545
+ marketId: e,
546
+ description: `Supply ${a} LBTC as collateral to the ${o.loanAsset.symbol}/LBTC Morpho market (${(Number(o.lltv) / 1e18 * 100).toFixed(0)}% LLTV, ${(o.state.supplyApy * 100).toFixed(2)}% supply APY). This requires two transactions: approve + supply.`
547
+ };
548
+ } catch (r) {
549
+ return {
550
+ action: "error",
551
+ marketId: e,
552
+ description: "",
553
+ error: r instanceof Error ? r.message : "Failed to prepare Morpho supply"
554
+ };
555
+ }
556
+ }
557
+ }, Ft = {
558
+ name: "prepare_morpho_borrow",
559
+ description: "Prepare a transaction to borrow from a Morpho Blue market where the user has LBTC collateral. The user must have already supplied LBTC as collateral to this market. Returns an unsigned borrow transaction for the user's wallet to sign.",
560
+ parameters: ht,
561
+ schema: K,
562
+ execute: async (t) => {
563
+ const { marketId: e, amount: a, address: s } = K.parse(t);
564
+ try {
565
+ const o = (await k(E(e))).marketByUniqueKey;
566
+ if (!o)
567
+ return {
568
+ action: "error",
569
+ marketId: e,
570
+ description: "",
571
+ error: `Market ${e} not found on Morpho.`
572
+ };
573
+ const n = Q(a, o.loanAsset.decimals), i = {
574
+ loanToken: o.loanAsset.address,
575
+ collateralToken: o.collateralAsset.address,
576
+ oracle: o.oracleAddress,
577
+ irm: o.irmAddress,
578
+ lltv: BigInt(o.lltv)
579
+ }, d = A({
580
+ abi: _t,
581
+ functionName: "borrow",
582
+ args: [
583
+ i,
584
+ n,
585
+ 0n,
586
+ // shares = 0 means borrow by asset amount
587
+ s,
588
+ // onBehalf
589
+ s
590
+ // receiver
591
+ ]
592
+ });
593
+ return {
594
+ action: "sdk_execute",
595
+ method: "morpho.borrow",
596
+ params: {
597
+ chainId: 1,
598
+ transactions: [
599
+ {
600
+ to: w,
601
+ data: d,
602
+ label: `Borrow ${a} ${o.loanAsset.symbol} from ${o.loanAsset.symbol}/LBTC market`
603
+ }
604
+ ]
605
+ },
606
+ marketId: e,
607
+ description: `Borrow ${a} ${o.loanAsset.symbol} against your LBTC collateral on the ${o.loanAsset.symbol}/LBTC Morpho market (${(o.state.borrowApy * 100).toFixed(2)}% borrow APY).`
608
+ };
609
+ } catch (r) {
610
+ return {
611
+ action: "error",
612
+ marketId: e,
613
+ description: "",
614
+ error: r instanceof Error ? r.message : "Failed to prepare Morpho borrow"
615
+ };
616
+ }
617
+ }
618
+ }, Ut = {
619
+ name: "prepare_morpho_repay",
620
+ description: "Prepare transactions to repay borrowed assets on a Morpho Blue market. Returns two unsigned transactions: (1) ERC-20 approve for the Morpho contract, and (2) repay call. The user must have the loan asset in their wallet.",
621
+ parameters: mt,
622
+ schema: G,
623
+ execute: async (t) => {
624
+ const { marketId: e, amount: a, address: s } = G.parse(t);
625
+ try {
626
+ const o = (await k(E(e))).marketByUniqueKey;
627
+ if (!o)
628
+ return {
629
+ action: "error",
630
+ marketId: e,
631
+ description: "",
632
+ error: `Market ${e} not found on Morpho.`
633
+ };
634
+ const n = Q(a, o.loanAsset.decimals), i = A({
635
+ abi: ye,
636
+ functionName: "approve",
637
+ args: [w, n]
638
+ }), d = {
639
+ loanToken: o.loanAsset.address,
640
+ collateralToken: o.collateralAsset.address,
641
+ oracle: o.oracleAddress,
642
+ irm: o.irmAddress,
643
+ lltv: BigInt(o.lltv)
644
+ }, h = A({
645
+ abi: It,
646
+ functionName: "repay",
647
+ args: [
648
+ d,
649
+ n,
650
+ 0n,
651
+ // shares = 0 means repay by asset amount
652
+ s,
653
+ // onBehalf
654
+ "0x"
655
+ // data (no callback)
656
+ ]
657
+ });
658
+ return {
659
+ action: "sdk_execute",
660
+ method: "morpho.repay",
661
+ params: {
662
+ chainId: 1,
663
+ transactions: [
664
+ {
665
+ to: o.loanAsset.address,
666
+ data: i,
667
+ label: `Approve Morpho to spend ${a} ${o.loanAsset.symbol}`
668
+ },
669
+ {
670
+ to: w,
671
+ data: h,
672
+ label: `Repay ${a} ${o.loanAsset.symbol} on ${o.loanAsset.symbol}/LBTC market`
673
+ }
674
+ ]
675
+ },
676
+ marketId: e,
677
+ description: `Repay ${a} ${o.loanAsset.symbol} on the ${o.loanAsset.symbol}/${o.collateralAsset.symbol} Morpho market. This requires two transactions: approve + repay.`
678
+ };
679
+ } catch (r) {
680
+ return {
681
+ action: "error",
682
+ marketId: e,
683
+ description: "",
684
+ error: r instanceof Error ? r.message : "Failed to prepare Morpho repay"
685
+ };
686
+ }
687
+ }
688
+ }, Nt = {
689
+ name: "get_morpho_position",
690
+ description: "Get the user's position in a Morpho Blue market: collateral deposited, amount borrowed, current LTV, and health status. Returns token addresses for use with get_token_balance.",
691
+ parameters: ft,
692
+ schema: J,
693
+ execute: async (t) => {
694
+ const { marketId: e, address: a } = J.parse(t), s = {
695
+ collateral: "0",
696
+ borrowAssets: "0",
697
+ loanAsset: "",
698
+ loanAssetAddress: "",
699
+ collateralAsset: "LBTC",
700
+ collateralAssetAddress: I,
701
+ lltv: "",
702
+ currentLtv: "0%",
703
+ healthStatus: "No position"
704
+ };
705
+ try {
706
+ const o = (await k(E(e))).marketByUniqueKey;
707
+ if (!o)
708
+ return { ...s, error: `Market ${e} not found.` };
709
+ const n = u(1), i = X({
710
+ chainId: n.chainId,
711
+ env: n.env
712
+ }), [d, h, Ce] = await Promise.all([
713
+ i.readContract({
714
+ address: w,
715
+ abi: ue,
716
+ functionName: "position",
717
+ args: [e, a]
718
+ }),
719
+ i.readContract({
720
+ address: w,
721
+ abi: ue,
722
+ functionName: "market",
723
+ args: [e]
724
+ }),
725
+ i.readContract({
726
+ address: o.oracleAddress,
727
+ abi: St,
728
+ functionName: "price"
729
+ })
730
+ ]), te = d[2], Ae = d[1], ke = h[2], ae = h[3], se = ae > 0n ? Ae * ke / ae : 0n, _e = v(te, pe), Ie = v(
731
+ se,
732
+ o.loanAsset.decimals
733
+ ), { currentLtv: Se, lltv: Le, healthStatus: $e } = Et({
734
+ collateralRaw: te,
735
+ borrowAssetsRaw: se,
736
+ oraclePrice: Ce,
737
+ lltvRaw: BigInt(o.lltv)
738
+ });
739
+ return {
740
+ collateral: _e,
741
+ borrowAssets: Ie,
742
+ loanAsset: o.loanAsset.symbol,
743
+ loanAssetAddress: o.loanAsset.address,
744
+ collateralAsset: o.collateralAsset.symbol,
745
+ collateralAssetAddress: o.collateralAsset.address,
746
+ lltv: `${(Le * 100).toFixed(0)}%`,
747
+ currentLtv: `${(Se * 100).toFixed(1)}%`,
748
+ healthStatus: $e
749
+ };
750
+ } catch (r) {
751
+ return {
752
+ ...s,
753
+ error: r instanceof Error ? r.message : "Failed to fetch Morpho position"
754
+ };
755
+ }
756
+ }
757
+ };
758
+ function B(t, e, a) {
759
+ return Promise.race([
760
+ t,
761
+ new Promise(
762
+ (s, r) => setTimeout(
763
+ () => r(new Error(`${a} timed out after ${e}ms`)),
764
+ e
765
+ )
766
+ )
767
+ ]);
768
+ }
769
+ async function S(t, e, a) {
770
+ const s = u(a), r = await B(
771
+ Ve(t, s.chainId, s.env),
772
+ 1e4,
773
+ "getTokenContractInfo"
774
+ ), o = X({
775
+ chainId: s.chainId,
776
+ env: s.env
777
+ }), n = await B(
778
+ o.readContract({
779
+ address: r.address,
780
+ abi: [
781
+ {
782
+ name: "balanceOf",
783
+ type: "function",
784
+ stateMutability: "view",
785
+ inputs: [{ name: "account", type: "address" }],
786
+ outputs: [{ name: "", type: "uint256" }]
787
+ }
788
+ ],
789
+ functionName: "balanceOf",
790
+ args: [e]
791
+ }),
792
+ 1e4,
793
+ `${t}.balanceOf on ${s.name}`
794
+ ), i = "decimals" in r && typeof r.decimals == "number" ? r.decimals : 8;
795
+ return v(n, i);
796
+ }
797
+ const qt = {
798
+ name: "get_lbtc_balance",
799
+ description: "Check the LBTC balance for a wallet address on a given chain.",
800
+ parameters: g,
801
+ schema: p,
802
+ execute: async (t) => {
803
+ const { address: e, chainId: a } = p.parse(t), { name: s } = u(a);
804
+ try {
805
+ return { balance: await S(_.LBTC, e, a), token: "LBTC", chain: s, address: e };
806
+ } catch (r) {
807
+ return {
808
+ balance: "",
809
+ token: "LBTC",
810
+ chain: s,
811
+ address: e,
812
+ error: r instanceof Error ? r.message : "Failed to fetch LBTC balance"
813
+ };
814
+ }
815
+ }
816
+ }, Ot = {
817
+ name: "get_btcb_balance",
818
+ description: "Check the BTC.b (cross-chain Bitcoin) balance for a wallet address on a given chain.",
819
+ parameters: g,
820
+ schema: p,
821
+ execute: async (t) => {
822
+ const { address: e, chainId: a } = p.parse(t), { name: s } = u(a);
823
+ try {
824
+ return { balance: await S(_.BTCb, e, a), token: "BTC.b", chain: s, address: e };
825
+ } catch (r) {
826
+ return {
827
+ balance: "",
828
+ token: "BTC.b",
829
+ chain: s,
830
+ address: e,
831
+ error: r instanceof Error ? r.message : "Failed to fetch BTC.b balance"
832
+ };
833
+ }
834
+ }
835
+ }, Vt = {
836
+ name: "get_exchange_rate",
837
+ description: "Get the current LBTC/BTC exchange rate and minimum stake amount. LBTC accrues staking yield over time, so 1 LBTC is worth slightly more than 1 BTC.",
838
+ parameters: Je,
839
+ schema: P,
840
+ execute: async (t) => {
841
+ const { chainId: e } = P.parse(t);
842
+ try {
843
+ const a = m.prod, [s, r] = await Promise.all([
844
+ Ee({ env: a }),
845
+ Me({ env: a })
846
+ ]), o = s.LBTC;
847
+ if (!(o != null && o.BTCTokenRatio) || !(o != null && o.tokenBTCRatio))
848
+ throw new Error("Exchange ratio data unavailable");
849
+ const n = String(o.BTCTokenRatio), i = String(o.tokenBTCRatio);
850
+ return {
851
+ lbtcToBtc: n,
852
+ btcToLbtc: i,
853
+ minStakeAmountBtc: oe(r.minAmount).toString(),
854
+ description: `1 LBTC = ${n} BTC. 1 BTC = ${i} LBTC. Min stake: ${oe(r.minAmount)} BTC.`
855
+ };
856
+ } catch (a) {
857
+ return {
858
+ lbtcToBtc: "",
859
+ btcToLbtc: "",
860
+ minStakeAmountBtc: "",
861
+ description: "",
862
+ error: a instanceof Error ? a.message : "Failed to fetch exchange rate"
863
+ };
864
+ }
865
+ }
866
+ }, jt = {
867
+ name: "get_deposit_status",
868
+ description: "Check the status of all deposits for an address. Shows pending, claimable, and claimed deposits.",
869
+ parameters: g,
870
+ schema: p,
871
+ execute: async (t) => {
872
+ const { address: e, chainId: a } = p.parse(t), { env: s } = u(a), r = await he({
873
+ address: e,
874
+ env: s
875
+ });
876
+ return r.length === 0 ? { deposits: [], message: "No deposits found" } : {
877
+ totalDeposits: r.length,
878
+ deposits: r.map((o) => {
879
+ var d;
880
+ const n = me(o), i = fe(n);
881
+ return {
882
+ txHash: o.txHash,
883
+ amount: (d = o.amount) == null ? void 0 : d.toString(),
884
+ status: n,
885
+ statusLabel: i.label,
886
+ description: i.description,
887
+ requiresAction: i.requiresAction,
888
+ rawPayload: o.rawPayload || null,
889
+ proofSignature: o.proof || null
890
+ };
891
+ })
892
+ };
893
+ }
894
+ }, Ht = {
895
+ name: "get_unstake_status",
896
+ description: "Check the status of all unstake/redeem operations for an address.",
897
+ parameters: g,
898
+ schema: p,
899
+ execute: async (t) => {
900
+ const { address: e, chainId: a } = p.parse(t), { env: s } = u(a), r = await Re({
901
+ address: e,
902
+ env: s
903
+ });
904
+ return r.length === 0 ? { unstakes: [], message: "No unstakes found" } : {
905
+ totalUnstakes: r.length,
906
+ unstakes: r.map((o) => {
907
+ var n;
908
+ return {
909
+ txHash: o.txHash,
910
+ amount: (n = o.amount) == null ? void 0 : n.toString(),
911
+ payoutStatus: o.payoutTxStatus,
912
+ payoutTxHash: o.payoutTxHash || null
913
+ };
914
+ })
915
+ };
916
+ }
917
+ }, zt = {
918
+ name: "get_balance",
919
+ description: "Check both LBTC and BTC.b balances for a wallet on a given chain in a single call.",
920
+ parameters: et,
921
+ schema: U,
922
+ execute: async (t) => {
923
+ const { address: e, chainId: a } = U.parse(t), s = u(a), [r, o] = await Promise.all([
924
+ S(_.LBTC, e, a).catch(
925
+ (n) => n instanceof Error ? `error: ${n.message}` : "error"
926
+ ),
927
+ S(_.BTCb, e, a).catch(
928
+ (n) => n instanceof Error ? `error: ${n.message}` : "error"
929
+ )
930
+ ]);
931
+ return { lbtc: r, btcb: o, chain: s.name, address: e };
932
+ }
933
+ }, M = [
934
+ {
935
+ name: "balanceOf",
936
+ type: "function",
937
+ stateMutability: "view",
938
+ inputs: [{ name: "account", type: "address" }],
939
+ outputs: [{ name: "", type: "uint256" }]
940
+ },
941
+ {
942
+ name: "decimals",
943
+ type: "function",
944
+ stateMutability: "view",
945
+ inputs: [],
946
+ outputs: [{ name: "", type: "uint8" }]
947
+ },
948
+ {
949
+ name: "symbol",
950
+ type: "function",
951
+ stateMutability: "view",
952
+ inputs: [],
953
+ outputs: [{ name: "", type: "string" }]
954
+ }
955
+ ], Yt = {
956
+ name: "get_token_info",
957
+ description: "Look up a Lombard-related asset by symbol, alias, or contract address. Returns the canonical name, description, decimals, and per-chain contract addresses. Use this whenever the user mentions a token you're not sure about (BTCe, LBTCv, etc.) before telling them you don't recognize it.",
958
+ parameters: dt,
959
+ schema: we,
960
+ execute: async (t) => {
961
+ const e = L.map((s) => s.symbol), a = (s) => {
962
+ const r = {};
963
+ for (const [o, n] of Object.entries(s.addresses))
964
+ n && (r[o] = n);
965
+ return {
966
+ symbol: s.symbol,
967
+ name: s.name,
968
+ description: s.description,
969
+ decimals: s.decimals,
970
+ isLombardIssued: s.isLombardIssued,
971
+ isYieldBearing: s.isYieldBearing,
972
+ addresses: r,
973
+ ...s.notes ? { notes: s.notes } : {}
974
+ };
975
+ };
976
+ if (t.address && typeof t.chainId == "number") {
977
+ const s = Ye(t.chainId, t.address);
978
+ return s ? {
979
+ found: !0,
980
+ asset: a(s),
981
+ note: `Address ${t.address} on chainId ${t.chainId} is ${s.symbol}.`
982
+ } : {
983
+ found: !1,
984
+ suggestions: e,
985
+ note: `Address ${t.address} on chainId ${t.chainId} is not a Lombard-issued asset.`
986
+ };
987
+ }
988
+ if (t.query) {
989
+ const s = ze(t.query);
990
+ return s ? {
991
+ found: !0,
992
+ asset: a(s),
993
+ note: `Resolved "${t.query}" to ${s.symbol}.`
994
+ } : {
995
+ found: !1,
996
+ suggestions: e,
997
+ note: `"${t.query}" is not a known Lombard asset. Known symbols: ${e.join(", ")}.`
998
+ };
999
+ }
1000
+ return {
1001
+ found: !1,
1002
+ suggestions: e,
1003
+ note: "Provide a `query` (symbol/name) or both `address` and `chainId`."
1004
+ };
1005
+ }
1006
+ }, Zt = {
1007
+ name: "get_token_balance",
1008
+ description: "Check the balance of any ERC-20 token for a wallet address. Requires the token contract address (0x...). Get addresses from other tool results (e.g. loanAsset.address from get_morpho_lbtc_markets). Reads symbol and decimals directly from the contract. Use this for tokens beyond LBTC and BTC.b.",
1009
+ parameters: ct,
1010
+ schema: Z,
1011
+ execute: async (t) => {
1012
+ const { tokenAddress: e, address: a, chainId: s } = Z.parse(t), r = u(s), o = X({
1013
+ chainId: r.chainId,
1014
+ env: r.env
1015
+ });
1016
+ try {
1017
+ const [n, i, d] = await Promise.all([
1018
+ o.readContract({
1019
+ address: e,
1020
+ abi: M,
1021
+ functionName: "balanceOf",
1022
+ args: [a]
1023
+ }),
1024
+ o.readContract({
1025
+ address: e,
1026
+ abi: M,
1027
+ functionName: "decimals"
1028
+ }),
1029
+ o.readContract({
1030
+ address: e,
1031
+ abi: M,
1032
+ functionName: "symbol"
1033
+ })
1034
+ ]);
1035
+ return {
1036
+ balance: v(n, i),
1037
+ symbol: d,
1038
+ tokenAddress: e,
1039
+ chain: r.name
1040
+ };
1041
+ } catch (n) {
1042
+ return {
1043
+ balance: "",
1044
+ symbol: "",
1045
+ tokenAddress: e,
1046
+ chain: r.name,
1047
+ error: n instanceof Error ? n.message : "Failed to read token balance"
1048
+ };
1049
+ }
1050
+ }
1051
+ }, Wt = {
1052
+ name: "get_strategies",
1053
+ description: "List available yield strategies where LBTC can be deployed for additional yield. Currently includes Bitcoin Earn (passive vault yield). Returns name, chain, APY, and TVL.",
1054
+ parameters: tt,
1055
+ schema: N,
1056
+ // Vault data is mainnet-only regardless of chainId
1057
+ execute: async (t) => {
1058
+ const { chainId: e } = N.parse(t), a = m.prod;
1059
+ try {
1060
+ const [s, r] = await Promise.all([
1061
+ Pe({ env: a }),
1062
+ De({ env: a })
1063
+ ]), o = s.length > 0 ? s[s.length - 1] : null;
1064
+ return {
1065
+ strategies: [
1066
+ {
1067
+ vault: "Bitcoin Earn",
1068
+ chain: "Ethereum",
1069
+ apy: o ? `${(parseFloat(String(o.apy)) * 100).toFixed(2)}%` : "N/A",
1070
+ tvlBtc: r.btcBalance.toFixed(4)
1071
+ }
1072
+ ]
1073
+ };
1074
+ } catch {
1075
+ return { strategies: [], error: "Unable to fetch vault data" };
1076
+ }
1077
+ }
1078
+ }, Kt = process.env.LOMBARD_BFF_URL || "https://bff.prod.lombard-fi.com", Gt = {
1079
+ name: "get_opportunities",
1080
+ description: "List LBTC and BTC.b DeFi opportunities across protocols and chains. Includes borrow-stables, looping, DEX LP, automated strategies, and more. Filter by category (borrow-stables, looping, dex-lp, automated-strategy, other), chain, or protocol.",
1081
+ parameters: it,
1082
+ schema: Y,
1083
+ execute: async (t) => {
1084
+ const { category: e, chain: a, protocol: s } = Y.parse(t);
1085
+ try {
1086
+ const r = [];
1087
+ e && r.push(`category=${encodeURIComponent(e)}`), a && r.push(`chain=${encodeURIComponent(a)}`), s && r.push(`protocol=${encodeURIComponent(s)}`);
1088
+ const o = r.length > 0 ? `?${r.join("&")}` : "", n = await fetch(`${Kt}/opportunities-api${o}`);
1089
+ if (!n.ok)
1090
+ throw new Error(`BFF returned ${n.status}`);
1091
+ return {
1092
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1093
+ opportunities: (await n.json()).opportunities
1094
+ };
1095
+ } catch (r) {
1096
+ return {
1097
+ opportunities: [],
1098
+ error: r instanceof Error ? r.message : "Failed to fetch opportunities"
1099
+ };
1100
+ }
1101
+ }
1102
+ }, Jt = {
1103
+ name: "get_deposit_btc_address",
1104
+ description: "Get or generate a BTC deposit address for a wallet. Users send native BTC to this address to receive LBTC on the specified EVM chain. If no address exists yet, returns instructions to generate one (requires a wallet signature).",
1105
+ parameters: at,
1106
+ schema: q,
1107
+ execute: async (t) => {
1108
+ const { address: e, chainId: a } = q.parse(t), s = u(a);
1109
+ try {
1110
+ return {
1111
+ btcAddress: await Fe({
1112
+ address: e,
1113
+ chainId: s.chainId,
1114
+ env: s.env,
1115
+ partnerId: Tt(s.env)
1116
+ }),
1117
+ chain: s.name,
1118
+ note: "Send BTC to this address. Once confirmed and notarized, use get_deposit_status to track progress and claim your LBTC."
1119
+ };
1120
+ } catch {
1121
+ return {
1122
+ btcAddress: null,
1123
+ chain: s.name,
1124
+ action: "generate_deposit_address",
1125
+ note: "No deposit address exists yet. To generate one, a wallet signature is required. Click the button below to sign and generate your BTC deposit address."
1126
+ };
1127
+ }
1128
+ }
1129
+ }, Xt = {
1130
+ name: "check_fee_authorization",
1131
+ description: "Check if a valid fee authorization signature exists for staking. On Ethereum/Sepolia, fee auth (EIP-712) is required before generating a BTC deposit address. On other chains, an address confirmation is required instead.",
1132
+ parameters: g,
1133
+ schema: p,
1134
+ execute: async (t) => {
1135
+ const { address: e, chainId: a } = p.parse(t), s = u(a);
1136
+ if (Ue(s.chainId))
1137
+ try {
1138
+ const o = await B(
1139
+ Ne({
1140
+ address: e,
1141
+ chainId: s.chainId,
1142
+ env: s.env
1143
+ }),
1144
+ 1e4,
1145
+ "getNetworkFeeSignature"
1146
+ ), n = o.hasSignature && new Date(o.expirationDate).getTime() > Date.now();
1147
+ return {
1148
+ chain: s.name,
1149
+ requiresFeeAuth: !0,
1150
+ hasValidSignature: n,
1151
+ expirationDate: o.hasSignature ? o.expirationDate : null,
1152
+ note: n ? "Fee authorization is valid. Ready to generate deposit address." : "Fee authorization is needed before generating a deposit address."
1153
+ };
1154
+ } catch {
1155
+ return {
1156
+ chain: s.name,
1157
+ requiresFeeAuth: !0,
1158
+ hasValidSignature: !1,
1159
+ expirationDate: null,
1160
+ note: "Fee authorization is needed before generating a deposit address."
1161
+ };
1162
+ }
1163
+ return {
1164
+ chain: s.name,
1165
+ requiresFeeAuth: !1,
1166
+ hasValidSignature: !1,
1167
+ expirationDate: null,
1168
+ note: "This chain requires an address confirmation signature (not fee auth). The signing will happen when generating the deposit address."
1169
+ };
1170
+ }
1171
+ }, Qt = {
1172
+ name: "prepare_btc_deposit",
1173
+ description: "Prepare a native BTC -> LBTC deposit address. Use this when the user wants LBTC (yield-bearing). The wallet will prompt for fee authorization (Ethereum/Sepolia) or an address confirmation (other chains), then a unique BTC deposit address is generated.",
1174
+ parameters: g,
1175
+ schema: p,
1176
+ execute: async (t) => {
1177
+ const { address: e, chainId: a } = p.parse(t), s = u(a);
1178
+ return {
1179
+ action: "sdk_execute",
1180
+ method: "btc.generateDepositAddress",
1181
+ params: { address: e, chainId: s.chainId },
1182
+ description: `Generate a BTC deposit address for ${e} on ${s.name}. The deposit will mint LBTC. Your wallet will prompt you to sign an authorization.`
1183
+ };
1184
+ }
1185
+ }, ea = {
1186
+ name: "prepare_btc_to_btcb_deposit",
1187
+ description: "Prepare a native BTC -> BTC.b deposit address. Use this when the user wants BTC.b (cross-chain wrapped Bitcoin, NOT yield-bearing). Distinct flow from prepare_btc_deposit (which produces LBTC). The wallet will prompt for the required authorization, then a unique BTC deposit address is generated that mints BTC.b on the destination EVM chain.",
1188
+ parameters: g,
1189
+ schema: p,
1190
+ execute: async (t) => {
1191
+ const { address: e, chainId: a } = p.parse(t), s = u(a);
1192
+ return {
1193
+ action: "sdk_execute",
1194
+ method: "btc.generateBtcbDepositAddress",
1195
+ params: { address: e, chainId: s.chainId },
1196
+ description: `Generate a BTC -> BTC.b deposit address for ${e} on ${s.name}. The deposit will mint BTC.b on the destination EVM chain. Your wallet will prompt you to sign an authorization.`
1197
+ };
1198
+ }
1199
+ }, ta = {
1200
+ name: "prepare_stake",
1201
+ description: "Prepare a BTC.b → LBTC stake. Returns transaction parameters for the user's wallet to sign, or a validation failure listing what to ask the user for.",
1202
+ parameters: Xe,
1203
+ schema: D,
1204
+ execute: async (t) => {
1205
+ const e = D.safeParse(t);
1206
+ if (!e.success)
1207
+ return {
1208
+ valid: !1,
1209
+ missing: [],
1210
+ errors: e.error.issues.map((n) => n.message),
1211
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1212
+ };
1213
+ const a = Bt(e.data);
1214
+ if (!a.valid) return a;
1215
+ const { amount: s, chainId: r } = e.data, o = u(r);
1216
+ return {
1217
+ valid: !0,
1218
+ action: "sdk_execute",
1219
+ method: "evm.stake",
1220
+ params: {
1221
+ amount: s,
1222
+ chainId: o.chainId,
1223
+ assetIn: "BTCb",
1224
+ assetOut: "LBTC"
1225
+ },
1226
+ description: `Stake ${s} BTC.b to receive LBTC on ${o.name}`
1227
+ };
1228
+ }
1229
+ }, aa = {
1230
+ name: "prepare_unstake",
1231
+ description: "Prepare an LBTC unstake. When outputAsset is 'BTC', the user MUST supply a Bitcoin destination address — do not infer or fill it from prior context. Returns either prepared transaction parameters or a validation failure listing what to ask the user for.",
1232
+ parameters: Qe,
1233
+ schema: F,
1234
+ execute: async (t) => {
1235
+ const e = F.safeParse(t);
1236
+ if (!e.success)
1237
+ return {
1238
+ valid: !1,
1239
+ missing: [],
1240
+ errors: e.error.issues.map((d) => d.message),
1241
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1242
+ };
1243
+ const a = wt(e.data);
1244
+ if (!a.valid) return a;
1245
+ const { amount: s, outputAsset: r, recipient: o, chainId: n } = e.data, i = u(n);
1246
+ return {
1247
+ valid: !0,
1248
+ action: "sdk_execute",
1249
+ method: "evm.unstake",
1250
+ params: {
1251
+ amount: s,
1252
+ outputAsset: r,
1253
+ recipient: o,
1254
+ chainId: i.chainId
1255
+ },
1256
+ description: `Unstake ${s} LBTC to ${r} on ${i.name}`
1257
+ };
1258
+ }
1259
+ }, sa = {
1260
+ name: "prepare_redeem_btcb",
1261
+ description: "Prepare a redemption of BTC.b for native BTC. Distinct from prepare_unstake (which operates on LBTC). The user MUST supply a Bitcoin destination address — do not infer or fill it from prior context. Returns either prepared transaction parameters or a validation failure listing what to ask the user for.",
1262
+ parameters: lt,
1263
+ schema: H,
1264
+ execute: async (t) => {
1265
+ const e = H.safeParse(t);
1266
+ if (!e.success)
1267
+ return {
1268
+ valid: !1,
1269
+ missing: [],
1270
+ errors: e.error.issues.map((i) => i.message),
1271
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1272
+ };
1273
+ const a = vt(e.data);
1274
+ if (!a.valid) return a;
1275
+ const { amount: s, recipient: r, chainId: o } = e.data, n = u(o);
1276
+ return {
1277
+ valid: !0,
1278
+ action: "sdk_execute",
1279
+ method: "evm.redeemBtcb",
1280
+ params: {
1281
+ amount: s,
1282
+ recipient: r,
1283
+ chainId: n.chainId
1284
+ },
1285
+ description: `Redeem ${s} BTC.b to native BTC on ${n.name}. Destination: ${r}.`
1286
+ };
1287
+ }
1288
+ }, ra = {
1289
+ name: "prepare_deploy_to_vault",
1290
+ description: "Prepare a transaction to deploy LBTC into Bitcoin Earn. Returns prepared transaction parameters or a validation failure.",
1291
+ parameters: st,
1292
+ schema: O,
1293
+ execute: async (t) => {
1294
+ const e = O.safeParse(t);
1295
+ if (!e.success)
1296
+ return {
1297
+ valid: !1,
1298
+ missing: [],
1299
+ errors: e.error.issues.map((n) => n.message),
1300
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1301
+ };
1302
+ const a = Te(e.data);
1303
+ if (!a.valid) return a;
1304
+ const { amount: s, chainId: r } = e.data, o = u(r);
1305
+ return {
1306
+ valid: !0,
1307
+ action: "sdk_execute",
1308
+ method: "evm.deploy",
1309
+ params: { amount: s, chainId: o.chainId, token: "LBTC" },
1310
+ description: `Deploy ${s} LBTC to Bitcoin Earn on ${o.name}`
1311
+ };
1312
+ }
1313
+ }, oa = {
1314
+ name: "prepare_vault_withdrawal",
1315
+ description: "Prepare a withdrawal from Bitcoin Earn. Only one active withdrawal is allowed per user per vault — this tool checks first and refuses if one is already queued, returning its details so you can offer the user prepare_cancel_withdrawal. On success, returns prepared transaction parameters.",
1316
+ parameters: ot,
1317
+ schema: V,
1318
+ execute: async (t) => {
1319
+ const e = V.safeParse(t);
1320
+ if (!e.success)
1321
+ return {
1322
+ valid: !1,
1323
+ missing: [],
1324
+ errors: e.error.issues.map((i) => i.message),
1325
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1326
+ };
1327
+ const a = Te(e.data);
1328
+ if (!a.valid) return a;
1329
+ const { amount: s, address: r, chainId: o } = e.data, n = u(o);
1330
+ try {
1331
+ const d = (await B(
1332
+ be({
1333
+ account: r,
1334
+ chainId: n.chainId,
1335
+ env: n.env
1336
+ }),
1337
+ 15e3,
1338
+ "getEarnWithdrawals"
1339
+ )).open[0];
1340
+ if (d)
1341
+ return {
1342
+ valid: !1,
1343
+ missing: [],
1344
+ errors: [
1345
+ `An active withdrawal already exists for ${r} on ${n.name}: ${d.shareAmount.toString()} shares queued (request tx ${d.txHash}). Only one active withdrawal is allowed per vault.`
1346
+ ],
1347
+ note: `Tell the user about the existing withdrawal (shareAmount=${d.shareAmount.toString()}, txHash=${d.txHash}, deadline=${d.deadline}) and ask whether they want to cancel it via prepare_cancel_withdrawal before queuing a new one. Do not retry prepare_vault_withdrawal until they confirm.`
1348
+ };
1349
+ } catch (i) {
1350
+ return {
1351
+ valid: !1,
1352
+ missing: [],
1353
+ errors: [
1354
+ i instanceof Error ? `Could not verify active withdrawals: ${i.message}` : "Could not verify active withdrawals."
1355
+ ],
1356
+ note: "The active-withdrawal check failed. Tell the user this is a backend issue, suggest they run get_vault_withdrawals manually to confirm no active withdrawal exists, and only proceed with prepare_vault_withdrawal after they confirm."
1357
+ };
1358
+ }
1359
+ return {
1360
+ valid: !0,
1361
+ action: "sdk_execute",
1362
+ method: "evm.withdrawFromVault",
1363
+ params: { amount: s, chainId: n.chainId },
1364
+ description: `Withdraw ${s} shares from Bitcoin Earn on ${n.name}. Withdrawals are queued and may take time to process.`
1365
+ };
1366
+ }
1367
+ }, na = {
1368
+ name: "get_lbtc_apy",
1369
+ description: "Get the current LBTC base staking APY (annual percentage yield). Returns both the base and effective APY for LBTC staking.",
1370
+ parameters: rt,
1371
+ schema: ge,
1372
+ execute: async () => {
1373
+ try {
1374
+ const t = await B(
1375
+ qe({ env: m.prod }),
1376
+ 1e4,
1377
+ "getApy"
1378
+ ), e = t.baseApy.multipliedBy(100).toFixed(2), a = t.effectiveApy.multipliedBy(100).toFixed(2);
1379
+ return {
1380
+ baseApy: t.baseApy.toString(),
1381
+ effectiveApy: t.effectiveApy.toString(),
1382
+ description: `LBTC base staking APY: ${e}%. Effective APY (with compounding/incentives): ${a}%.`
1383
+ };
1384
+ } catch (t) {
1385
+ return {
1386
+ baseApy: "",
1387
+ effectiveApy: "",
1388
+ description: "",
1389
+ error: t instanceof Error ? t.message : "Failed to fetch LBTC APY"
1390
+ };
1391
+ }
1392
+ }
1393
+ }, ia = {
1394
+ name: "get_vault_positions",
1395
+ description: "Get a user's Bitcoin Earn positions including shares held and their estimated LBTC value. Currently supports Bitcoin Earn on Ethereum mainnet.",
1396
+ parameters: g,
1397
+ schema: p,
1398
+ execute: async (t) => {
1399
+ const { address: e, chainId: a } = p.parse(t), s = u(a);
1400
+ try {
1401
+ const r = await B(
1402
+ Oe({ address: e, chainId: s.chainId }),
1403
+ 1e4,
1404
+ "getEarnPosition"
1405
+ );
1406
+ return {
1407
+ shares: r.totalShares.toString(),
1408
+ shareValue: r.exchangeRate.toString(),
1409
+ estimatedLbtcValue: r.position.toString(),
1410
+ vault: "Bitcoin Earn",
1411
+ chain: s.name
1412
+ };
1413
+ } catch (r) {
1414
+ return {
1415
+ shares: "",
1416
+ shareValue: "",
1417
+ estimatedLbtcValue: "",
1418
+ vault: "Bitcoin Earn",
1419
+ chain: s.name,
1420
+ error: r instanceof Error ? r.message : "Failed to fetch vault positions"
1421
+ };
1422
+ }
1423
+ }
1424
+ }, ca = {
1425
+ name: "prepare_claim_deposit",
1426
+ description: "Prepare a transaction to claim (mint) LBTC from a notarized BTC deposit. Checks if the deposit is claimable and returns the transaction parameters for wallet signing.",
1427
+ parameters: nt,
1428
+ schema: j,
1429
+ execute: async (t) => {
1430
+ const { depositTxHash: e, address: a, chainId: s } = j.parse(t), r = u(s), n = (await he({
1431
+ address: a,
1432
+ env: r.env
1433
+ })).find((d) => d.txHash === e);
1434
+ if (!n)
1435
+ return {
1436
+ action: "error",
1437
+ method: "",
1438
+ params: {
1439
+ depositTxHash: e,
1440
+ rawPayload: "",
1441
+ proofSignature: "",
1442
+ chainId: r.chainId
1443
+ },
1444
+ description: "",
1445
+ error: "Could not find a deposit with this transaction hash for the given address. Use get_deposit_status to verify the transaction hash."
1446
+ };
1447
+ const i = me(n);
1448
+ if (i !== "claimable") {
1449
+ const d = fe(i);
1450
+ return {
1451
+ action: "error",
1452
+ method: "",
1453
+ params: {
1454
+ depositTxHash: e,
1455
+ rawPayload: "",
1456
+ proofSignature: "",
1457
+ chainId: r.chainId
1458
+ },
1459
+ description: "",
1460
+ error: `Deposit is not claimable. Current status: ${d.label}. ${d.description}`
1461
+ };
1462
+ }
1463
+ return {
1464
+ action: "sdk_execute",
1465
+ method: "evm.claimDeposit",
1466
+ params: {
1467
+ depositTxHash: e,
1468
+ rawPayload: n.rawPayload,
1469
+ proofSignature: n.proof,
1470
+ chainId: r.chainId
1471
+ },
1472
+ description: `Claim LBTC from deposit ${e.slice(0, 10)}... on ${r.name}. Your wallet will prompt you to sign the mint transaction.`
1473
+ };
1474
+ }
1475
+ }, da = {
1476
+ name: "prepare_cancel_withdrawal",
1477
+ description: "Cancel an active Bitcoin Earn withdrawal that has not yet been processed. Looks up the user's active withdrawal first; refuses if none exists, includes its details in the description if one does, then returns the cancel transaction parameters.",
1478
+ parameters: Ge,
1479
+ schema: z,
1480
+ execute: async (t) => {
1481
+ const e = z.safeParse(t);
1482
+ if (!e.success)
1483
+ return {
1484
+ valid: !1,
1485
+ missing: [],
1486
+ errors: e.error.issues.map((n) => n.message),
1487
+ note: "Surface the listed errors to the user and re-prompt with valid input."
1488
+ };
1489
+ const { address: a, chainId: s } = e.data, r = u(s);
1490
+ let o = "";
1491
+ try {
1492
+ const i = (await B(
1493
+ be({
1494
+ account: a,
1495
+ chainId: r.chainId,
1496
+ env: r.env
1497
+ }),
1498
+ 15e3,
1499
+ "getEarnWithdrawals"
1500
+ )).open[0];
1501
+ if (!i)
1502
+ return {
1503
+ valid: !1,
1504
+ missing: [],
1505
+ errors: [
1506
+ `No active withdrawal found for ${a} on ${r.name}. There is nothing to cancel.`
1507
+ ],
1508
+ note: "Tell the user there is no active withdrawal to cancel. If they think there should be, suggest get_vault_withdrawals to inspect their full withdrawal history."
1509
+ };
1510
+ o = ` Active withdrawal: ${i.shareAmount.toString()} shares (request tx ${i.txHash}, deadline ${i.deadline}).`;
1511
+ } catch (n) {
1512
+ return {
1513
+ valid: !1,
1514
+ missing: [],
1515
+ errors: [
1516
+ n instanceof Error ? `Could not verify active withdrawals before cancelling: ${n.message}` : "Could not verify active withdrawals before cancelling."
1517
+ ],
1518
+ note: "Backend issue. Ask the user to retry in a moment, or to verify via get_vault_withdrawals first."
1519
+ };
1520
+ }
1521
+ return {
1522
+ valid: !0,
1523
+ action: "sdk_execute",
1524
+ method: "evm.cancelWithdrawal",
1525
+ params: { chainId: r.chainId },
1526
+ description: `Cancel pending Bitcoin Earn withdrawal on ${r.name}.${o} Your wallet will prompt you to sign the cancellation transaction.`
1527
+ };
1528
+ }
1529
+ }, la = [
1530
+ qt,
1531
+ Ot,
1532
+ zt,
1533
+ Zt,
1534
+ Yt,
1535
+ Vt,
1536
+ jt,
1537
+ Ht,
1538
+ Wt,
1539
+ Gt,
1540
+ Jt,
1541
+ Xt,
1542
+ Qt,
1543
+ ea,
1544
+ ta,
1545
+ aa,
1546
+ sa,
1547
+ ra,
1548
+ oa,
1549
+ da,
1550
+ na,
1551
+ ia,
1552
+ ca,
1553
+ Pt,
1554
+ Dt,
1555
+ Ft,
1556
+ Ut,
1557
+ Nt
1558
+ ], ya = Object.fromEntries(la.map((t) => [t.name, t]));
1559
+ export {
1560
+ Jt as $,
1561
+ g as A,
1562
+ et as B,
1563
+ We as C,
1564
+ st as D,
1565
+ Je as E,
1566
+ Z as F,
1567
+ dt as G,
1568
+ we as H,
1569
+ F as I,
1570
+ V as J,
1571
+ la as K,
1572
+ ba as L,
1573
+ ht as M,
1574
+ y as N,
1575
+ it as O,
1576
+ Ze as P,
1577
+ b as Q,
1578
+ lt as R,
1579
+ le as S,
1580
+ ct as T,
1581
+ Qe as U,
1582
+ ot as V,
1583
+ Xt as W,
1584
+ f as X,
1585
+ zt as Y,
1586
+ Ot as Z,
1587
+ u as _,
1588
+ p as a,
1589
+ jt as a0,
1590
+ Vt as a1,
1591
+ na as a2,
1592
+ qt as a3,
1593
+ Pt as a4,
1594
+ Nt as a5,
1595
+ Gt as a6,
1596
+ Wt as a7,
1597
+ Zt as a8,
1598
+ Yt as a9,
1599
+ Ht as aa,
1600
+ ia as ab,
1601
+ Qt as ac,
1602
+ ea as ad,
1603
+ da as ae,
1604
+ ca as af,
1605
+ ra as ag,
1606
+ Ft as ah,
1607
+ Ut as ai,
1608
+ Dt as aj,
1609
+ sa as ak,
1610
+ ta as al,
1611
+ aa as am,
1612
+ oa as an,
1613
+ Ye as ao,
1614
+ ze as ap,
1615
+ ya as aq,
1616
+ U as b,
1617
+ nt as c,
1618
+ j as d,
1619
+ O as e,
1620
+ at as f,
1621
+ q as g,
1622
+ P as h,
1623
+ L as i,
1624
+ rt as j,
1625
+ ge as k,
1626
+ K as l,
1627
+ ut as m,
1628
+ Be as n,
1629
+ ft as o,
1630
+ J as p,
1631
+ mt as q,
1632
+ G as r,
1633
+ pt as s,
1634
+ W as t,
1635
+ Y as u,
1636
+ H as v,
1637
+ Xe as w,
1638
+ D as x,
1639
+ tt as y,
1640
+ N as z
1641
+ };