@guiie/buda-mcp 1.5.0 → 1.5.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.
Files changed (59) hide show
  1. package/.cursor/rules/marketplace-docs-sync.mdc +32 -0
  2. package/CHANGELOG.md +40 -0
  3. package/PUBLISH_CHECKLIST.md +40 -88
  4. package/README.md +446 -78
  5. package/dist/client.d.ts +1 -0
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +2 -1
  8. package/dist/http.js +42 -6
  9. package/dist/index.js +12 -3
  10. package/dist/tools/batch_orders.d.ts +5 -0
  11. package/dist/tools/batch_orders.d.ts.map +1 -1
  12. package/dist/tools/batch_orders.js +35 -1
  13. package/dist/tools/cancel_order.js +1 -1
  14. package/dist/tools/dead_mans_switch.d.ts +1 -1
  15. package/dist/tools/dead_mans_switch.d.ts.map +1 -1
  16. package/dist/tools/dead_mans_switch.js +33 -3
  17. package/dist/tools/lightning.d.ts.map +1 -1
  18. package/dist/tools/lightning.js +15 -1
  19. package/dist/tools/place_order.d.ts.map +1 -1
  20. package/dist/tools/place_order.js +31 -0
  21. package/dist/tools/receive_addresses.d.ts +5 -0
  22. package/dist/tools/receive_addresses.d.ts.map +1 -1
  23. package/dist/tools/receive_addresses.js +26 -2
  24. package/dist/tools/remittances.d.ts +5 -0
  25. package/dist/tools/remittances.d.ts.map +1 -1
  26. package/dist/tools/remittances.js +27 -3
  27. package/dist/tools/technical_indicators.d.ts.map +1 -1
  28. package/dist/tools/technical_indicators.js +2 -1
  29. package/dist/tools/withdrawals.d.ts.map +1 -1
  30. package/dist/tools/withdrawals.js +11 -1
  31. package/dist/utils.d.ts.map +1 -1
  32. package/dist/utils.js +4 -1
  33. package/dist/validation.d.ts +6 -0
  34. package/dist/validation.d.ts.map +1 -1
  35. package/dist/validation.js +26 -0
  36. package/dist/version.d.ts.map +1 -1
  37. package/dist/version.js +8 -1
  38. package/marketplace/README.md +1 -1
  39. package/marketplace/claude-listing.md +75 -4
  40. package/marketplace/gemini-tools.json +325 -2
  41. package/marketplace/openapi.yaml +160 -1
  42. package/package.json +2 -1
  43. package/server.json +2 -2
  44. package/src/client.ts +3 -1
  45. package/src/http.ts +50 -6
  46. package/src/index.ts +10 -3
  47. package/src/tools/batch_orders.ts +40 -1
  48. package/src/tools/cancel_order.ts +1 -1
  49. package/src/tools/dead_mans_switch.ts +39 -3
  50. package/src/tools/lightning.ts +17 -1
  51. package/src/tools/place_order.ts +32 -0
  52. package/src/tools/receive_addresses.ts +29 -3
  53. package/src/tools/remittances.ts +30 -4
  54. package/src/tools/technical_indicators.ts +2 -1
  55. package/src/tools/withdrawals.ts +12 -1
  56. package/src/utils.ts +3 -1
  57. package/src/validation.ts +29 -0
  58. package/src/version.ts +11 -3
  59. package/test/unit.ts +261 -18
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;aAEnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAHrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAG7C,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM;IAOpB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;YACW,cAAc;YA2Bd,cAAc;IActB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoB1E,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBnD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmBpF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;aAEnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAHrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAG7C,OAAO,GAAE,MAAiB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM;IAOpB,OAAO,IAAI,OAAO;IAIlB,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAWnB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;;OAIG;YACW,cAAc;YA2Bd,cAAc;IActB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoB1E,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBnD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmBpF"}
package/dist/client.js CHANGED
@@ -25,8 +25,9 @@ export class BudaClient {
25
25
  hasAuth() {
26
26
  return Boolean(this.apiKey && this.apiSecret);
27
27
  }
28
+ _nonceCounter = 0;
28
29
  nonce() {
29
- return String(Math.floor(Date.now() * 1000));
30
+ return String(Date.now() * 1000 + (this._nonceCounter++ % 1000));
30
31
  }
31
32
  sign(method, pathWithQuery, body, nonce) {
32
33
  const encodedBody = body ? Buffer.from(body).toString("base64") : "";
package/dist/http.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import express from "express";
2
+ import rateLimit from "express-rate-limit";
2
3
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
5
  import { BudaClient } from "./client.js";
5
6
  import { MemoryCache, CACHE_TTL } from "./cache.js";
6
7
  import { VERSION } from "./version.js";
8
+ import { validateMarketId } from "./validation.js";
7
9
  import * as markets from "./tools/markets.js";
8
10
  import * as ticker from "./tools/ticker.js";
9
11
  import * as orderbook from "./tools/orderbook.js";
@@ -119,7 +121,7 @@ function createServer() {
119
121
  orders.register(server, client);
120
122
  placeOrder.register(server, client);
121
123
  cancelOrder.register(server, client);
122
- deadMansSwitch.register(server, client);
124
+ deadMansSwitch.register(server, client, "http");
123
125
  account.register(server, client);
124
126
  balance.register(server, client);
125
127
  orderLookup.register(server, client);
@@ -148,7 +150,11 @@ function createServer() {
148
150
  };
149
151
  });
150
152
  server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", { list: undefined }), async (uri, params) => {
151
- const marketId = params.market.toLowerCase();
153
+ const raw = params.market;
154
+ const validationError = validateMarketId(raw);
155
+ if (validationError)
156
+ throw new Error(validationError);
157
+ const marketId = raw.toLowerCase();
152
158
  const data = await reqCache.getOrFetch(`ticker:${marketId}`, CACHE_TTL.TICKER, () => client.get(`/markets/${marketId}/ticker`));
153
159
  return {
154
160
  contents: [
@@ -161,9 +167,13 @@ function createServer() {
161
167
  };
162
168
  });
163
169
  server.resource("buda-summary", new ResourceTemplate("buda://summary/{market}", { list: undefined }), async (uri, params) => {
164
- const marketId = params.market.toUpperCase();
170
+ const raw = params.market;
171
+ const validationError = validateMarketId(raw);
172
+ if (validationError)
173
+ throw new Error(validationError);
174
+ const marketId = raw.toUpperCase();
165
175
  const result = await handleMarketSummary({ market_id: marketId }, client, reqCache);
166
- const text = result.content[0].text;
176
+ const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
167
177
  return {
168
178
  contents: [
169
179
  {
@@ -178,6 +188,32 @@ function createServer() {
178
188
  }
179
189
  const app = express();
180
190
  app.use(express.json());
191
+ const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
192
+ if (authEnabled && !MCP_AUTH_TOKEN) {
193
+ console.error("[buda-mcp] FATAL: BUDA_API_KEY/BUDA_API_SECRET are set but MCP_AUTH_TOKEN is not.\n" +
194
+ " The /mcp endpoint would be publicly accessible with full account access.\n" +
195
+ " Set MCP_AUTH_TOKEN to a long random secret, or run in stdio mode instead.");
196
+ process.exit(1);
197
+ }
198
+ const mcpRateLimiter = rateLimit({
199
+ windowMs: 60_000,
200
+ max: parseInt(process.env.MCP_RATE_LIMIT ?? "120", 10),
201
+ standardHeaders: true,
202
+ legacyHeaders: false,
203
+ message: { error: "Too many requests. Retry after 60 seconds.", code: "RATE_LIMITED" },
204
+ });
205
+ function mcpAuthMiddleware(req, res, next) {
206
+ if (!MCP_AUTH_TOKEN) {
207
+ next();
208
+ return;
209
+ }
210
+ const auth = req.headers.authorization ?? "";
211
+ if (auth !== `Bearer ${MCP_AUTH_TOKEN}`) {
212
+ res.status(401).json({ error: "Unauthorized" });
213
+ return;
214
+ }
215
+ next();
216
+ }
181
217
  // Health check for Railway / uptime monitors
182
218
  app.get("/health", (_req, res) => {
183
219
  res.json({
@@ -203,7 +239,7 @@ app.get("/.well-known/mcp/server-card.json", (_req, res) => {
203
239
  });
204
240
  });
205
241
  // Stateless StreamableHTTP — new server instance per request (no session state needed)
206
- app.post("/mcp", async (req, res) => {
242
+ app.post("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
207
243
  const transport = new StreamableHTTPServerTransport({
208
244
  sessionIdGenerator: undefined,
209
245
  });
@@ -215,7 +251,7 @@ app.post("/mcp", async (req, res) => {
215
251
  await transport.handleRequest(req, res, req.body);
216
252
  });
217
253
  // SSE upgrade for clients that prefer streaming
218
- app.get("/mcp", async (req, res) => {
254
+ app.get("/mcp", mcpRateLimiter, mcpAuthMiddleware, async (req, res) => {
219
255
  const transport = new StreamableHTTPServerTransport({
220
256
  sessionIdGenerator: undefined,
221
257
  });
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { BudaClient } from "./client.js";
6
6
  import { cache, CACHE_TTL } from "./cache.js";
7
7
  import { VERSION } from "./version.js";
8
+ import { validateMarketId } from "./validation.js";
8
9
  import * as markets from "./tools/markets.js";
9
10
  import * as ticker from "./tools/ticker.js";
10
11
  import * as orderbook from "./tools/orderbook.js";
@@ -97,7 +98,11 @@ server.resource("buda-markets", "buda://markets", async (uri) => {
97
98
  };
98
99
  });
99
100
  server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", { list: undefined }), async (uri, params) => {
100
- const marketId = params.market.toLowerCase();
101
+ const raw = params.market;
102
+ const validationError = validateMarketId(raw);
103
+ if (validationError)
104
+ throw new Error(validationError);
105
+ const marketId = raw.toLowerCase();
101
106
  const data = await cache.getOrFetch(`ticker:${marketId}`, CACHE_TTL.TICKER, () => client.get(`/markets/${marketId}/ticker`));
102
107
  return {
103
108
  contents: [
@@ -110,9 +115,13 @@ server.resource("buda-ticker", new ResourceTemplate("buda://ticker/{market}", {
110
115
  };
111
116
  });
112
117
  server.resource("buda-summary", new ResourceTemplate("buda://summary/{market}", { list: undefined }), async (uri, params) => {
113
- const marketId = params.market.toUpperCase();
118
+ const raw = params.market;
119
+ const validationError = validateMarketId(raw);
120
+ if (validationError)
121
+ throw new Error(validationError);
122
+ const marketId = raw.toUpperCase();
114
123
  const result = await handleMarketSummary({ market_id: marketId }, client, cache);
115
- const text = result.content[0].text;
124
+ const text = result.content[0]?.text ?? JSON.stringify({ error: "No content returned" });
116
125
  return {
117
126
  contents: [
118
127
  {
@@ -39,6 +39,10 @@ export declare const toolSchema: {
39
39
  required: string[];
40
40
  };
41
41
  };
42
+ max_notional: {
43
+ type: string;
44
+ description: string;
45
+ };
42
46
  confirmation_token: {
43
47
  type: string;
44
48
  description: string;
@@ -63,6 +67,7 @@ declare const orderShape: z.ZodObject<{
63
67
  type SingleOrderInput = z.infer<typeof orderShape>;
64
68
  type BatchOrdersArgs = {
65
69
  orders: SingleOrderInput[];
70
+ max_notional?: number;
66
71
  confirmation_token: string;
67
72
  };
68
73
  export declare function handlePlaceBatchOrders(args: BatchOrdersArgs, client: BudaClient): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"batch_orders.d.ts","sourceRoot":"","sources":["../../src/tools/batch_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCtB,CAAC;AAEF,QAAA,MAAM,UAAU;;;;;;;;;;;;iBAMd,CAAC;AAEH,KAAK,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAWnD,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA6GhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkBpE"}
1
+ {"version":3,"file":"batch_orders.d.ts","sourceRoot":"","sources":["../../src/tools/batch_orders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CtB,CAAC;AAEF,QAAA,MAAM,UAAU;;;;;;;;;;;;iBAMd,CAAC;AAEH,KAAK,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAWnD,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAkIhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2BpE"}
@@ -6,6 +6,7 @@ export const toolSchema = {
6
6
  description: "Place multiple orders sequentially on Buda.com (up to 20). " +
7
7
  "All orders are pre-validated before any API call — a validation failure stops execution with zero orders placed. " +
8
8
  "Partial API failures do NOT roll back already-placed orders. " +
9
+ "Use max_notional to cap total exposure (computed as sum of amount × limit_price for limit orders; market orders contribute 0). " +
9
10
  "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
10
11
  "Requires BUDA_API_KEY and BUDA_API_SECRET.",
11
12
  inputSchema: {
@@ -26,6 +27,12 @@ export const toolSchema = {
26
27
  required: ["market_id", "type", "price_type", "amount"],
27
28
  },
28
29
  },
30
+ max_notional: {
31
+ type: "number",
32
+ description: "Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
33
+ "Batch is rejected before any API call if the sum exceeds this value. " +
34
+ "Market orders contribute 0 to the notional since their execution price is unknown.",
35
+ },
29
36
  confirmation_token: {
30
37
  type: "string",
31
38
  description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute.",
@@ -42,7 +49,7 @@ const orderShape = z.object({
42
49
  limit_price: z.number().positive().optional(),
43
50
  });
44
51
  export async function handlePlaceBatchOrders(args, client) {
45
- const { orders, confirmation_token } = args;
52
+ const { orders, max_notional, confirmation_token } = args;
46
53
  if (confirmation_token !== "CONFIRM") {
47
54
  return {
48
55
  content: [
@@ -94,6 +101,26 @@ export async function handlePlaceBatchOrders(args, client) {
94
101
  };
95
102
  }
96
103
  }
104
+ // Notional cap check (limit orders only; market orders have unknown execution price)
105
+ if (max_notional !== undefined) {
106
+ const totalNotional = orders.reduce((sum, o) => {
107
+ return sum + (o.price_type === "limit" && o.limit_price ? o.amount * o.limit_price : 0);
108
+ }, 0);
109
+ if (totalNotional > max_notional) {
110
+ return {
111
+ content: [{
112
+ type: "text",
113
+ text: JSON.stringify({
114
+ error: `Total notional ${totalNotional} exceeds max_notional cap of ${max_notional}. No orders were placed.`,
115
+ code: "NOTIONAL_CAP_EXCEEDED",
116
+ total_notional: totalNotional,
117
+ max_notional,
118
+ }),
119
+ }],
120
+ isError: true,
121
+ };
122
+ }
123
+ }
97
124
  // Execute sequentially
98
125
  const results = [];
99
126
  for (let i = 0; i < orders.length; i++) {
@@ -146,6 +173,13 @@ export function register(server, client) {
146
173
  .min(1)
147
174
  .max(20)
148
175
  .describe("Array of 1–20 orders to place."),
176
+ max_notional: z
177
+ .number()
178
+ .positive()
179
+ .optional()
180
+ .describe("Optional spending cap: total notional (sum of amount × limit_price for limit orders). " +
181
+ "Batch is rejected before any API call if the sum exceeds this value. " +
182
+ "Market orders contribute 0 to the notional since their execution price is unknown."),
149
183
  confirmation_token: z
150
184
  .string()
151
185
  .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to execute."),
@@ -42,7 +42,7 @@ export async function handleCancelOrder(args, client) {
42
42
  }
43
43
  try {
44
44
  const data = await client.put(`/orders/${order_id}`, {
45
- state: "canceling",
45
+ order: { state: "canceling" },
46
46
  });
47
47
  return {
48
48
  content: [{ type: "text", text: JSON.stringify(data.order, null, 2) }],
@@ -79,6 +79,6 @@ export declare function handleDisarmCancelTimer({ market_id }: MarketOnlyArgs):
79
79
  }>;
80
80
  isError?: boolean;
81
81
  };
82
- export declare function register(server: McpServer, client: BudaClient): void;
82
+ export declare function register(server: McpServer, client: BudaClient, transport?: "stdio" | "http"): void;
83
83
  export {};
84
84
  //# sourceMappingURL=dead_mans_switch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dead_mans_switch.d.ts","sourceRoot":"","sources":["../../src/tools/dead_mans_switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAiDxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAgB3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAgB5B,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+ChF;AAED,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,wBAAgB,sBAAsB,CACpC,EAAE,SAAS,EAAE,EAAE,cAAc,EAC7B,MAAM,EAAE,UAAU,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CA0CvE;AAED,wBAAgB,uBAAuB,CACrC,EAAE,SAAS,EAAE,EAAE,cAAc,GAC5B;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAwCvE;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA0CpE"}
1
+ {"version":3,"file":"dead_mans_switch.d.ts","sourceRoot":"","sources":["../../src/tools/dead_mans_switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAiDxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAgB3B,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;CAgB5B,CAAC;AAIF,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA8DhF;AAED,KAAK,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C,wBAAgB,sBAAsB,CACpC,EAAE,SAAS,EAAE,EAAE,cAAc,EAC7B,MAAM,EAAE,UAAU,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CA0CvE;AAED,wBAAgB,uBAAuB,CACrC,EAAE,SAAS,EAAE,EAAE,cAAc,GAC5B;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAwCvE;AAID,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,GAAE,OAAO,GAAG,MAAgB,GACpC,IAAI,CA2DN"}
@@ -5,7 +5,7 @@ async function cancelAllOrdersForMarket(marketId, client) {
5
5
  try {
6
6
  const data = await client.get(`/markets/${marketId}/orders`, { state: "pending", per: 300 });
7
7
  const orders = data.orders ?? [];
8
- await Promise.allSettled(orders.map((order) => client.put(`/orders/${order.id}`, { state: "canceling" })));
8
+ await Promise.allSettled(orders.map((order) => client.put(`/orders/${order.id}`, { order: { state: "canceling" } })));
9
9
  timers.delete(marketId);
10
10
  }
11
11
  catch {
@@ -111,6 +111,20 @@ export async function handleScheduleCancelAll(args, client) {
111
111
  isError: true,
112
112
  };
113
113
  }
114
+ if (!Number.isInteger(ttl_seconds) || ttl_seconds < 10 || ttl_seconds > 300) {
115
+ return {
116
+ content: [
117
+ {
118
+ type: "text",
119
+ text: JSON.stringify({
120
+ error: "ttl_seconds must be an integer between 10 and 300.",
121
+ code: "VALIDATION_ERROR",
122
+ }),
123
+ },
124
+ ],
125
+ isError: true,
126
+ };
127
+ }
114
128
  const id = market_id.toLowerCase();
115
129
  const entry = armTimer(id, ttl_seconds, client);
116
130
  return {
@@ -207,7 +221,7 @@ export function handleDisarmCancelTimer({ market_id }) {
207
221
  };
208
222
  }
209
223
  // ---- Registration ----
210
- export function register(server, client) {
224
+ export function register(server, client, transport = "stdio") {
211
225
  server.tool(toolSchema.name, toolSchema.description, {
212
226
  market_id: z
213
227
  .string()
@@ -221,7 +235,23 @@ export function register(server, client) {
221
235
  confirmation_token: z
222
236
  .string()
223
237
  .describe("Must equal exactly 'CONFIRM' (case-sensitive) to arm the switch."),
224
- }, (args) => handleScheduleCancelAll(args, client));
238
+ }, (args) => {
239
+ if (transport === "http") {
240
+ return Promise.resolve({
241
+ content: [{
242
+ type: "text",
243
+ text: JSON.stringify({
244
+ error: "schedule_cancel_all is not available on the HTTP transport. " +
245
+ "Timer state is lost on every server restart or deploy. " +
246
+ "Run buda-mcp in stdio mode on a persistent local process to use this feature.",
247
+ code: "TRANSPORT_NOT_SUPPORTED",
248
+ }),
249
+ }],
250
+ isError: true,
251
+ });
252
+ }
253
+ return handleScheduleCancelAll(args, client);
254
+ });
225
255
  server.tool(renewToolSchema.name, renewToolSchema.description, {
226
256
  market_id: z
227
257
  .string()
@@ -1 +1 @@
1
- {"version":3,"file":"lightning.d.ts","sourceRoot":"","sources":["../../src/tools/lightning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;CAuBzC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;CAwB5C,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+DhF;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,0BAA0B,EAChC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA8ChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2CpE"}
1
+ {"version":3,"file":"lightning.d.ts","sourceRoot":"","sources":["../../src/tools/lightning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;CAuBzC,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;CAwB5C,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+EhF;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,0BAA0B,EAChC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA8ChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2CpE"}
@@ -66,6 +66,20 @@ export async function handleLightningWithdrawal(args, client) {
66
66
  isError: true,
67
67
  };
68
68
  }
69
+ const BOLT11_RE = /^ln(bc|tb|bcrt)\d/i;
70
+ if (!BOLT11_RE.test(invoice)) {
71
+ return {
72
+ content: [{
73
+ type: "text",
74
+ text: JSON.stringify({
75
+ error: "Invalid Lightning invoice format. " +
76
+ "Expected a BOLT-11 string starting with 'lnbc', 'lntb', or 'lnbcrt'.",
77
+ code: "INVALID_INVOICE",
78
+ }),
79
+ }],
80
+ isError: true,
81
+ };
82
+ }
69
83
  try {
70
84
  const data = await client.post(`/reserves/ln-btc/withdrawals`, { invoice });
71
85
  const lw = data.lightning_withdrawal;
@@ -141,7 +155,7 @@ export function register(server, client) {
141
155
  server.tool(lightningWithdrawalToolSchema.name, lightningWithdrawalToolSchema.description, {
142
156
  invoice: z
143
157
  .string()
144
- .min(1)
158
+ .min(50)
145
159
  .describe("BOLT-11 Lightning invoice string (starts with 'lnbc', 'lntb', etc.)."),
146
160
  confirmation_token: z
147
161
  .string()
@@ -1 +1 @@
1
- {"version":3,"file":"place_order.d.ts","sourceRoot":"","sources":["../../src/tools/place_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEtB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqIhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA4DpE"}
1
+ {"version":3,"file":"place_order.d.ts","sourceRoot":"","sources":["../../src/tools/place_order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEtB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqKhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA4DpE"}
@@ -145,6 +145,37 @@ export async function handlePlaceOrder(args, client) {
145
145
  isError: true,
146
146
  };
147
147
  }
148
+ if (gtd_timestamp !== undefined) {
149
+ const ts = new Date(gtd_timestamp).getTime();
150
+ if (isNaN(ts)) {
151
+ return {
152
+ content: [
153
+ {
154
+ type: "text",
155
+ text: JSON.stringify({
156
+ error: "gtd_timestamp must be a valid ISO 8601 datetime string.",
157
+ code: "VALIDATION_ERROR",
158
+ }),
159
+ },
160
+ ],
161
+ isError: true,
162
+ };
163
+ }
164
+ if (ts <= Date.now()) {
165
+ return {
166
+ content: [
167
+ {
168
+ type: "text",
169
+ text: JSON.stringify({
170
+ error: "gtd_timestamp must be a future datetime.",
171
+ code: "VALIDATION_ERROR",
172
+ }),
173
+ },
174
+ ],
175
+ isError: true,
176
+ };
177
+ }
178
+ }
148
179
  let limitType = "gtc";
149
180
  if (ioc)
150
181
  limitType = "ioc";
@@ -10,6 +10,10 @@ export declare const createReceiveAddressToolSchema: {
10
10
  type: string;
11
11
  description: string;
12
12
  };
13
+ confirmation_token: {
14
+ type: string;
15
+ description: string;
16
+ };
13
17
  };
14
18
  required: string[];
15
19
  };
@@ -67,6 +71,7 @@ export declare function handleGetReceiveAddress(args: {
67
71
  }>;
68
72
  export declare function handleCreateReceiveAddress(args: {
69
73
  currency: string;
74
+ confirmation_token: string;
70
75
  }, client: BudaClient): Promise<{
71
76
  content: Array<{
72
77
  type: "text";
@@ -1 +1 @@
1
- {"version":3,"file":"receive_addresses.d.ts","sourceRoot":"","sources":["../../src/tools/receive_addresses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;CAmB1C,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;CAiB1C,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;CAoBvC,CAAC;AAYF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqChF;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACtC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA4BhF;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA6BhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA4BpE"}
1
+ {"version":3,"file":"receive_addresses.d.ts","sourceRoot":"","sources":["../../src/tools/receive_addresses.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAIxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;CAwB1C,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;CAiB1C,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;CAoBvC,CAAC;AAYF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqChF;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACtC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA4BhF;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EACtD,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+ChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA+BpE"}
@@ -6,6 +6,7 @@ export const createReceiveAddressToolSchema = {
6
6
  description: "Generates a new receive address for a crypto currency. " +
7
7
  "Creates a new blockchain deposit address for the given currency. " +
8
8
  "Each call generates a distinct address. Not idempotent. " +
9
+ "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
9
10
  "Only applicable to crypto currencies (BTC, ETH, etc.). " +
10
11
  "Requires BUDA_API_KEY and BUDA_API_SECRET. " +
11
12
  "Example: 'Give me a fresh Bitcoin deposit address.'",
@@ -16,8 +17,12 @@ export const createReceiveAddressToolSchema = {
16
17
  type: "string",
17
18
  description: "Currency code (e.g. 'BTC', 'ETH').",
18
19
  },
20
+ confirmation_token: {
21
+ type: "string",
22
+ description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to generate a new address.",
23
+ },
19
24
  },
20
- required: ["currency"],
25
+ required: ["currency", "confirmation_token"],
21
26
  },
22
27
  };
23
28
  export const listReceiveAddressesToolSchema = {
@@ -122,7 +127,23 @@ export async function handleGetReceiveAddress(args, client) {
122
127
  }
123
128
  }
124
129
  export async function handleCreateReceiveAddress(args, client) {
125
- const { currency } = args;
130
+ const { currency, confirmation_token } = args;
131
+ if (confirmation_token !== "CONFIRM") {
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: JSON.stringify({
137
+ error: "Address not generated. confirmation_token must equal 'CONFIRM' to execute. " +
138
+ "Each call creates a distinct address — review and set confirmation_token='CONFIRM' to proceed.",
139
+ code: "CONFIRMATION_REQUIRED",
140
+ preview: { currency },
141
+ }),
142
+ },
143
+ ],
144
+ isError: true,
145
+ };
146
+ }
126
147
  const validationError = validateCurrency(currency);
127
148
  if (validationError) {
128
149
  return {
@@ -156,6 +177,9 @@ export function register(server, client) {
156
177
  }, (args) => handleGetReceiveAddress(args, client));
157
178
  server.tool(createReceiveAddressToolSchema.name, createReceiveAddressToolSchema.description, {
158
179
  currency: z.string().min(2).max(10).describe("Currency code (e.g. 'BTC', 'ETH')."),
180
+ confirmation_token: z
181
+ .string()
182
+ .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to generate a new address."),
159
183
  }, (args) => handleCreateReceiveAddress(args, client));
160
184
  }
161
185
  //# sourceMappingURL=receive_addresses.js.map
@@ -35,6 +35,10 @@ export declare const quoteRemittanceToolSchema: {
35
35
  type: string;
36
36
  description: string;
37
37
  };
38
+ confirmation_token: {
39
+ type: string;
40
+ description: string;
41
+ };
38
42
  };
39
43
  required: string[];
40
44
  };
@@ -94,6 +98,7 @@ export declare function handleQuoteRemittance(args: {
94
98
  currency: string;
95
99
  amount: number;
96
100
  recipient_id: number;
101
+ confirmation_token: string;
97
102
  }, client: BudaClient): Promise<{
98
103
  content: Array<{
99
104
  type: "text";
@@ -1 +1 @@
1
- {"version":3,"file":"remittances.d.ts","sourceRoot":"","sources":["../../src/tools/remittances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;CAoBrC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;CA4BrC,CAAC;AAEF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;CAuB3C,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;CAiBnC,CAAC;AAgBF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACrC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAoChF;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAgBhF;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EAChE,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAgChF;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EAChD,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAwCpE"}
1
+ {"version":3,"file":"remittances.d.ts","sourceRoot":"","sources":["../../src/tools/remittances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;CAoBrC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;CAiCrC,CAAC;AAEF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;CAuB3C,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;CAiBnC,CAAC;AAgBF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACrC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAoChF;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAgBhF;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EAC5F,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAkDhF;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,EAChD,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAqChF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA2CpE"}
@@ -28,7 +28,8 @@ export const quoteRemittanceToolSchema = {
28
28
  "Requests a price quote for a fiat remittance to a saved recipient. " +
29
29
  "Returns a remittance object in 'quoted' state with an expiry timestamp. " +
30
30
  "NOT idempotent — creates a new remittance record each call. " +
31
- "To execute, call accept_remittance_quote with the returned ID before it expires. " +
31
+ "IMPORTANT: Pass confirmation_token='CONFIRM' to execute. " +
32
+ "To execute the transfer, call accept_remittance_quote with the returned ID before it expires. " +
32
33
  "Requires BUDA_API_KEY and BUDA_API_SECRET. " +
33
34
  "Example: 'Get a remittance quote to send 100000 CLP to recipient 5.'",
34
35
  inputSchema: {
@@ -46,8 +47,12 @@ export const quoteRemittanceToolSchema = {
46
47
  type: "number",
47
48
  description: "ID of the saved remittance recipient.",
48
49
  },
50
+ confirmation_token: {
51
+ type: "string",
52
+ description: "Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to create the quote.",
53
+ },
49
54
  },
50
- required: ["currency", "amount", "recipient_id"],
55
+ required: ["currency", "amount", "recipient_id", "confirmation_token"],
51
56
  },
52
57
  };
53
58
  export const acceptRemittanceQuoteToolSchema = {
@@ -151,7 +156,23 @@ export async function handleGetRemittance(args, client) {
151
156
  }
152
157
  }
153
158
  export async function handleQuoteRemittance(args, client) {
154
- const { currency, amount, recipient_id } = args;
159
+ const { currency, amount, recipient_id, confirmation_token } = args;
160
+ if (confirmation_token !== "CONFIRM") {
161
+ return {
162
+ content: [
163
+ {
164
+ type: "text",
165
+ text: JSON.stringify({
166
+ error: "Remittance quote not created. confirmation_token must equal 'CONFIRM' to execute. " +
167
+ "Review the details and set confirmation_token='CONFIRM' to proceed.",
168
+ code: "CONFIRMATION_REQUIRED",
169
+ preview: { currency, amount, recipient_id },
170
+ }),
171
+ },
172
+ ],
173
+ isError: true,
174
+ };
175
+ }
155
176
  const validationError = validateCurrency(currency);
156
177
  if (validationError) {
157
178
  return {
@@ -228,6 +249,9 @@ export function register(server, client) {
228
249
  currency: z.string().min(2).max(10).describe("Fiat currency code (e.g. 'CLP', 'COP')."),
229
250
  amount: z.number().positive().describe("Amount to remit (positive number)."),
230
251
  recipient_id: z.number().int().positive().describe("ID of the saved remittance recipient."),
252
+ confirmation_token: z
253
+ .string()
254
+ .describe("Safety confirmation. Must equal exactly 'CONFIRM' (case-sensitive) to create the quote."),
231
255
  }, (args) => handleQuoteRemittance(args, client));
232
256
  server.tool(acceptRemittanceQuoteToolSchema.name, acceptRemittanceQuoteToolSchema.description, {
233
257
  id: z.number().int().positive().describe("The numeric ID of the remittance quote to accept."),
@@ -1 +1 @@
1
- {"version":3,"file":"technical_indicators.d.ts","sourceRoot":"","sources":["../../src/tools/technical_indicators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA8BtB,CAAC;AAsGF,KAAK,uBAAuB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA2GhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAyBpE"}
1
+ {"version":3,"file":"technical_indicators.d.ts","sourceRoot":"","sources":["../../src/tools/technical_indicators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;CA8BtB,CAAC;AAsGF,KAAK,uBAAuB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA4GhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAyBpE"}
@@ -146,7 +146,7 @@ export async function handleTechnicalIndicators(args, client) {
146
146
  const macdResult = macd(closes, 12, 26, 9);
147
147
  const bbResult = bollingerBands(closes, 20, 2);
148
148
  const sma20 = parseFloat(sma(closes, 20).toFixed(2));
149
- const sma50 = parseFloat(sma(closes, 50).toFixed(2));
149
+ const sma50 = closes.length >= 50 ? parseFloat(sma(closes, 50).toFixed(2)) : null;
150
150
  const lastClose = closes[closes.length - 1];
151
151
  // Signal interpretations
152
152
  const rsiSignal = rsiValue !== null && rsiValue > 70
@@ -180,6 +180,7 @@ export async function handleTechnicalIndicators(args, client) {
180
180
  bollinger_bands: bbResult,
181
181
  sma_20: sma20,
182
182
  sma_50: sma50,
183
+ sma_50_warning: sma50 === null ? `insufficient data (need 50 candles, have ${closes.length})` : undefined,
183
184
  },
184
185
  signals: {
185
186
  rsi_signal: rsiSignal,
@@ -1 +1 @@
1
- {"version":3,"file":"withdrawals.d.ts","sourceRoot":"","sources":["../../src/tools/withdrawals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAqBF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,wBAAwB,EAC9B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+ChF;AAED,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsBtC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAyFhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA+BpE"}
1
+ {"version":3,"file":"withdrawals.d.ts","sourceRoot":"","sources":["../../src/tools/withdrawals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAC;AAKxD,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;CA8B1C,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAqBF,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,wBAAwB,EAC9B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA+ChF;AAED,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBtC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAmGhF;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA+BpE"}