chain-insights 0.70.0 → 0.71.2

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/cli.cjs CHANGED
@@ -522,7 +522,7 @@ program.command("mcp").description("Low-level access to the Chain Insights MCP e
522
522
  }
523
523
  }
524
524
  console.log(formatToolsTable(visibleRemoteTools(tools)));
525
- const { META_DEX_LOOKUP_DESCRIPTION, META_DEX_LOOKUP_TITLE, META_DEX_LOOKUP_TOOL } = await Promise.resolve().then(() => require("./dex-tool-DIKN4dXB.cjs")).then((n) => n.dex_tool_exports);
525
+ const { META_DEX_LOOKUP_DESCRIPTION, META_DEX_LOOKUP_TITLE, META_DEX_LOOKUP_TOOL } = await Promise.resolve().then(() => require("./dex-tool-B4T8Czhm.cjs")).then((n) => n.dex_tool_exports);
526
526
  console.log("");
527
527
  console.log(formatToolsTable([{
528
528
  name: META_DEX_LOOKUP_TOOL,
@@ -556,7 +556,7 @@ program.command("mcp").description("Low-level access to the Chain Insights MCP e
556
556
  return;
557
557
  }
558
558
  if (tool === "meta_dex_lookup") {
559
- const { handleMetaDexLookup } = await Promise.resolve().then(() => require("./dex-tool-DIKN4dXB.cjs")).then((n) => n.dex_tool_exports);
559
+ const { handleMetaDexLookup } = await Promise.resolve().then(() => require("./dex-tool-B4T8Czhm.cjs")).then((n) => n.dex_tool_exports);
560
560
  const { loadRegistry } = await Promise.resolve().then(() => require("./dex-registry-KOTJhAQf.cjs")).then((n) => n.dex_registry_exports);
561
561
  const pools = args["pools"] === void 0 ? void 0 : String(args["pools"]).toLowerCase() !== "false";
562
562
  const result = await withGraphMcpClient("chain-insights-cli-dex-lookup", (client) => handleMetaDexLookup({
package/dist/cli.mjs CHANGED
@@ -520,7 +520,7 @@ program.command("mcp").description("Low-level access to the Chain Insights MCP e
520
520
  }
521
521
  }
522
522
  console.log(formatToolsTable(visibleRemoteTools(tools)));
523
- const { META_DEX_LOOKUP_DESCRIPTION, META_DEX_LOOKUP_TITLE, META_DEX_LOOKUP_TOOL } = await import("./dex-tool-DpQKS7Te.mjs").then((n) => n.a);
523
+ const { META_DEX_LOOKUP_DESCRIPTION, META_DEX_LOOKUP_TITLE, META_DEX_LOOKUP_TOOL } = await import("./dex-tool-B5Qwz1Zd.mjs").then((n) => n.a);
524
524
  console.log("");
525
525
  console.log(formatToolsTable([{
526
526
  name: META_DEX_LOOKUP_TOOL,
@@ -554,7 +554,7 @@ program.command("mcp").description("Low-level access to the Chain Insights MCP e
554
554
  return;
555
555
  }
556
556
  if (tool === "meta_dex_lookup") {
557
- const { handleMetaDexLookup } = await import("./dex-tool-DpQKS7Te.mjs").then((n) => n.a);
557
+ const { handleMetaDexLookup } = await import("./dex-tool-B5Qwz1Zd.mjs").then((n) => n.a);
558
558
  const { loadRegistry } = await import("./dex-registry-05wAhSa0.mjs").then((n) => n.n);
559
559
  const pools = args["pools"] === void 0 ? void 0 : String(args["pools"]).toLowerCase() !== "false";
560
560
  const result = await withGraphMcpClient("chain-insights-cli-dex-lookup", (client) => handleMetaDexLookup({
@@ -233,8 +233,8 @@ var dex_tool_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
233
233
  });
234
234
  const META_DEX_LOOKUP_TOOL = "meta_dex_lookup";
235
235
  const META_DEX_LOOKUP_SCHEMA = "chain-insights.meta-dex-lookup.v1";
236
- const META_DEX_LOOKUP_TITLE = "Exchange by name";
237
- const META_DEX_LOOKUP_DESCRIPTION = "Call this first when a question names a decentralized exchange, a launchpad or a vault (Aero, Aerodrome, Velodrome, up., Raphael, Topaz, Uniswap, PancakeSwap, Balancer, Curve, Penguin, Virtuals, ...) and gives no address. It turns the name into the exchange's factories, routers or pool manager, its biggest pools, and the first reads to send, with every address in full. A misspelling within two letters is taken and named in took_for. When matched is null the name is not covered: say so, list covered, and send no graph query for the name. Never ask the user for a pool, factory or router address.";
236
+ const META_DEX_LOOKUP_TITLE = "Exchange by name or address";
237
+ const META_DEX_LOOKUP_DESCRIPTION = "Call this first when a question names a decentralized exchange, a launchpad or a vault (Aero, Aerodrome, Velodrome, up., Raphael, Topaz, Uniswap, PancakeSwap, Balancer, Curve, Penguin, Virtuals, ...) and gives no address. It turns the name into the exchange's factories, routers or pool manager, its biggest pools, and the first reads to send, with every address in full. A misspelling within two letters is taken and named in took_for. When matched is null the name is not covered: say so, list covered, and send no graph query for the name. Never ask the user for a pool, factory or router address. When the user gives a contract address instead of a name, send it as address (0x plus 40 hex, any case, with no name): the answer is the exchange whose factory, router or manager it is, and took_for names the role it holds. When matched is null no exchange row holds the address: send no read for it. Give a name or an address, not both.";
238
238
  const META_DEX_LOOKUP_ANNOTATIONS = {
239
239
  readOnlyHint: true,
240
240
  idempotentHint: true,
@@ -358,7 +358,13 @@ function readMatch(entry, members, read) {
358
358
  notes
359
359
  };
360
360
  }
361
- function hintFor(result, name) {
361
+ const ADDRESS_FORM = /^0x[0-9a-fA-F]{40}$/;
362
+ function hintFor(result, name, address = null) {
363
+ if (address !== null && !result.matched) return `${ANSWER_HINT} No exchange row holds ${address}: it is not a registered exchange contract. Send no exchange read for it; read the graph for what the address did.`;
364
+ if (address !== null && result.matched) {
365
+ const { matched } = result;
366
+ return `${ANSWER_HINT} Say in one line: "${address} is a ${result.took_for} row of ${matched.display}." Ask nothing. Exchange ${matched.display}, trail ${matched.trail_type}: send the first reads of recipe, anchored on the addresses above, and load ${matched.skill} when this host has skills. Read families before a SWAPPED search: it is sent when behind_dex is at most 100000. Never ask the user for an address.`;
367
+ }
362
368
  if (name === null) return `${ANSWER_HINT} These are the exchanges the registry covers. Call meta_dex_lookup with a name for its addresses and first reads.`;
363
369
  if (result.matched) {
364
370
  const { matched } = result;
@@ -381,7 +387,7 @@ function textResult(structured) {
381
387
  isError: false
382
388
  };
383
389
  }
384
- /** meta_dex_lookup, {network, name?, pools?}. Every argument is checked before the registry is read. */
390
+ /** meta_dex_lookup, {network, name?, address?, pools?}. Every argument is checked before the registry is read. */
385
391
  async function handleMetaDexLookup(args, deps) {
386
392
  const record = isRecord(args) ? args : {};
387
393
  let network;
@@ -393,6 +399,12 @@ async function handleMetaDexLookup(args, deps) {
393
399
  const rawName = record.name;
394
400
  if (rawName !== void 0 && rawName !== null && typeof rawName !== "string") return errorResult("invalid_name: name must be the exchange name as text");
395
401
  const name = typeof rawName === "string" && rawName.trim() !== "" ? rawName.trim() : null;
402
+ const rawAddress = record.address;
403
+ if (rawAddress !== void 0 && rawAddress !== null && typeof rawAddress !== "string") return errorResult("invalid_address: address must be 0x plus 40 hex characters");
404
+ const addressText = typeof rawAddress === "string" && rawAddress.trim() !== "" ? rawAddress.trim() : null;
405
+ if (name !== null && addressText !== null) return errorResult("Give a name or an address, not both.");
406
+ if (addressText !== null && !ADDRESS_FORM.test(addressText)) return errorResult("invalid_address: address must be 0x plus 40 hex characters");
407
+ const address = addressText === null ? null : addressText.toLowerCase();
396
408
  const rawPools = record.pools;
397
409
  if (rawPools !== void 0 && rawPools !== null && typeof rawPools !== "boolean") return errorResult("invalid_pools: pools must be true or false");
398
410
  const pools = rawPools !== false;
@@ -409,7 +421,7 @@ async function handleMetaDexLookup(args, deps) {
409
421
  registry_version: document.registry_version,
410
422
  registry_source: loaded.source
411
423
  };
412
- if (name === null) {
424
+ if (name === null && address === null) {
413
425
  const result = {
414
426
  ...base,
415
427
  matched: null,
@@ -429,7 +441,16 @@ async function handleMetaDexLookup(args, deps) {
429
441
  hint: hintFor(result, null)
430
442
  });
431
443
  }
432
- const match = require_dex_registry.matchDex(name, document.rows);
444
+ let match;
445
+ if (address !== null) {
446
+ const holder = document.rows.find((row) => address in row.roles);
447
+ match = {
448
+ matched: holder ?? null,
449
+ ...holder ? { took_for: `${holder.roles[address]}, served` } : {},
450
+ candidates: [],
451
+ covered: document.rows.map((row) => row.display)
452
+ };
453
+ } else match = require_dex_registry.matchDex(name, document.rows);
433
454
  if (!match.matched) {
434
455
  const result = {
435
456
  ...base,
@@ -440,7 +461,7 @@ async function handleMetaDexLookup(args, deps) {
440
461
  };
441
462
  return textResult({
442
463
  ...result,
443
- hint: hintFor(result, name)
464
+ hint: hintFor(result, name, address)
444
465
  });
445
466
  }
446
467
  const entry = match.matched;
@@ -488,7 +509,7 @@ async function handleMetaDexLookup(args, deps) {
488
509
  };
489
510
  return textResult({
490
511
  ...result,
491
- hint: hintFor(result, name)
512
+ hint: hintFor(result, name, address)
492
513
  });
493
514
  }
494
515
  //#endregion
@@ -233,8 +233,8 @@ var dex_tool_exports = /* @__PURE__ */ __exportAll({
233
233
  });
234
234
  const META_DEX_LOOKUP_TOOL = "meta_dex_lookup";
235
235
  const META_DEX_LOOKUP_SCHEMA = "chain-insights.meta-dex-lookup.v1";
236
- const META_DEX_LOOKUP_TITLE = "Exchange by name";
237
- const META_DEX_LOOKUP_DESCRIPTION = "Call this first when a question names a decentralized exchange, a launchpad or a vault (Aero, Aerodrome, Velodrome, up., Raphael, Topaz, Uniswap, PancakeSwap, Balancer, Curve, Penguin, Virtuals, ...) and gives no address. It turns the name into the exchange's factories, routers or pool manager, its biggest pools, and the first reads to send, with every address in full. A misspelling within two letters is taken and named in took_for. When matched is null the name is not covered: say so, list covered, and send no graph query for the name. Never ask the user for a pool, factory or router address.";
236
+ const META_DEX_LOOKUP_TITLE = "Exchange by name or address";
237
+ const META_DEX_LOOKUP_DESCRIPTION = "Call this first when a question names a decentralized exchange, a launchpad or a vault (Aero, Aerodrome, Velodrome, up., Raphael, Topaz, Uniswap, PancakeSwap, Balancer, Curve, Penguin, Virtuals, ...) and gives no address. It turns the name into the exchange's factories, routers or pool manager, its biggest pools, and the first reads to send, with every address in full. A misspelling within two letters is taken and named in took_for. When matched is null the name is not covered: say so, list covered, and send no graph query for the name. Never ask the user for a pool, factory or router address. When the user gives a contract address instead of a name, send it as address (0x plus 40 hex, any case, with no name): the answer is the exchange whose factory, router or manager it is, and took_for names the role it holds. When matched is null no exchange row holds the address: send no read for it. Give a name or an address, not both.";
238
238
  const META_DEX_LOOKUP_ANNOTATIONS = {
239
239
  readOnlyHint: true,
240
240
  idempotentHint: true,
@@ -358,7 +358,13 @@ function readMatch(entry, members, read) {
358
358
  notes
359
359
  };
360
360
  }
361
- function hintFor(result, name) {
361
+ const ADDRESS_FORM = /^0x[0-9a-fA-F]{40}$/;
362
+ function hintFor(result, name, address = null) {
363
+ if (address !== null && !result.matched) return `${ANSWER_HINT} No exchange row holds ${address}: it is not a registered exchange contract. Send no exchange read for it; read the graph for what the address did.`;
364
+ if (address !== null && result.matched) {
365
+ const { matched } = result;
366
+ return `${ANSWER_HINT} Say in one line: "${address} is a ${result.took_for} row of ${matched.display}." Ask nothing. Exchange ${matched.display}, trail ${matched.trail_type}: send the first reads of recipe, anchored on the addresses above, and load ${matched.skill} when this host has skills. Read families before a SWAPPED search: it is sent when behind_dex is at most 100000. Never ask the user for an address.`;
367
+ }
362
368
  if (name === null) return `${ANSWER_HINT} These are the exchanges the registry covers. Call meta_dex_lookup with a name for its addresses and first reads.`;
363
369
  if (result.matched) {
364
370
  const { matched } = result;
@@ -381,7 +387,7 @@ function textResult(structured) {
381
387
  isError: false
382
388
  };
383
389
  }
384
- /** meta_dex_lookup, {network, name?, pools?}. Every argument is checked before the registry is read. */
390
+ /** meta_dex_lookup, {network, name?, address?, pools?}. Every argument is checked before the registry is read. */
385
391
  async function handleMetaDexLookup(args, deps) {
386
392
  const record = isRecord(args) ? args : {};
387
393
  let network;
@@ -393,6 +399,12 @@ async function handleMetaDexLookup(args, deps) {
393
399
  const rawName = record.name;
394
400
  if (rawName !== void 0 && rawName !== null && typeof rawName !== "string") return errorResult("invalid_name: name must be the exchange name as text");
395
401
  const name = typeof rawName === "string" && rawName.trim() !== "" ? rawName.trim() : null;
402
+ const rawAddress = record.address;
403
+ if (rawAddress !== void 0 && rawAddress !== null && typeof rawAddress !== "string") return errorResult("invalid_address: address must be 0x plus 40 hex characters");
404
+ const addressText = typeof rawAddress === "string" && rawAddress.trim() !== "" ? rawAddress.trim() : null;
405
+ if (name !== null && addressText !== null) return errorResult("Give a name or an address, not both.");
406
+ if (addressText !== null && !ADDRESS_FORM.test(addressText)) return errorResult("invalid_address: address must be 0x plus 40 hex characters");
407
+ const address = addressText === null ? null : addressText.toLowerCase();
396
408
  const rawPools = record.pools;
397
409
  if (rawPools !== void 0 && rawPools !== null && typeof rawPools !== "boolean") return errorResult("invalid_pools: pools must be true or false");
398
410
  const pools = rawPools !== false;
@@ -409,7 +421,7 @@ async function handleMetaDexLookup(args, deps) {
409
421
  registry_version: document.registry_version,
410
422
  registry_source: loaded.source
411
423
  };
412
- if (name === null) {
424
+ if (name === null && address === null) {
413
425
  const result = {
414
426
  ...base,
415
427
  matched: null,
@@ -429,7 +441,16 @@ async function handleMetaDexLookup(args, deps) {
429
441
  hint: hintFor(result, null)
430
442
  });
431
443
  }
432
- const match = matchDex(name, document.rows);
444
+ let match;
445
+ if (address !== null) {
446
+ const holder = document.rows.find((row) => address in row.roles);
447
+ match = {
448
+ matched: holder ?? null,
449
+ ...holder ? { took_for: `${holder.roles[address]}, served` } : {},
450
+ candidates: [],
451
+ covered: document.rows.map((row) => row.display)
452
+ };
453
+ } else match = matchDex(name, document.rows);
433
454
  if (!match.matched) {
434
455
  const result = {
435
456
  ...base,
@@ -440,7 +461,7 @@ async function handleMetaDexLookup(args, deps) {
440
461
  };
441
462
  return textResult({
442
463
  ...result,
443
- hint: hintFor(result, name)
464
+ hint: hintFor(result, name, address)
444
465
  });
445
466
  }
446
467
  const entry = match.matched;
@@ -488,10 +509,10 @@ async function handleMetaDexLookup(args, deps) {
488
509
  };
489
510
  return textResult({
490
511
  ...result,
491
- hint: hintFor(result, name)
512
+ hint: hintFor(result, name, address)
492
513
  });
493
514
  }
494
515
  //#endregion
495
516
  export { dex_tool_exports as a, META_DEX_LOOKUP_TOOL as i, META_DEX_LOOKUP_DESCRIPTION as n, handleMetaDexLookup as o, META_DEX_LOOKUP_TITLE as r, withAnswerHintResult as s, META_DEX_LOOKUP_ANNOTATIONS as t };
496
517
 
497
- //# sourceMappingURL=dex-tool-DpQKS7Te.mjs.map
518
+ //# sourceMappingURL=dex-tool-B5Qwz1Zd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dex-tool-B5Qwz1Zd.mjs","names":["isRecord"],"sources":["../src/mcp/answer-hint.ts","../src/mcp/dex-recipes.ts","../src/mcp/dex-tool.ts"],"sourcesContent":["/**\n * The two answer rules that still slip in long answers, carried on every\n * graph reply in the result's `hint` field. Claude Code has a Stop hook that\n * reads the answer; Codex and Claude Desktop have no such hook, and in the\n * loop's third prompt set they broke one of these two rules in three of\n * thirteen conversations. The reply is the one thing every host hands the\n * model right before it writes, so the rules ride on it. A `hint` the\n * server already set is kept.\n */\n\nexport const ANSWER_HINT =\n 'Answer: write every address in full (0x plus 40 characters), also when it repeats one named earlier and also when the user asks for shorter ones (name them instead); ' +\n 'a transfer moves tokens, so write \"tokens worth about N USD\", never \"sent N USD\" or a $ figure; ' +\n 'never draw the flows in text, ASCII or Mermaid, the host draws them.'\n\ntype TextBlock = { type: string; text?: string }\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** The structured content with the hint set when the server left it empty. */\nexport function withAnswerHint(structuredContent: unknown): unknown {\n if (!isRecord(structuredContent) || !isRecord(structuredContent.facts)) return structuredContent\n if (typeof structuredContent.hint === 'string' && structuredContent.hint.trim()) return structuredContent\n return { ...structuredContent, hint: ANSWER_HINT }\n}\n\n/** A graph tool result whose structured content and single JSON text block both carry the hint. */\nexport function withAnswerHintResult<T extends { content?: TextBlock[]; structuredContent?: unknown }>(result: T): T {\n const structured = withAnswerHint(result.structuredContent)\n if (structured === result.structuredContent) return result\n const content = result.content ?? []\n const only = content.length === 1 && content[0]?.type === 'text' ? content[0] : null\n let parsed: unknown = undefined\n try {\n parsed = only?.text ? JSON.parse(only.text) : undefined\n } catch {\n parsed = undefined\n }\n const textIsStructured = parsed !== undefined && JSON.stringify(parsed) === JSON.stringify(result.structuredContent)\n return { ...result, structuredContent: structured, content: textIsStructured ? [{ ...only, text: JSON.stringify(structured) }] : content }\n}\n","/**\n * The first reads of each trail type, filled with the addresses of one\n * exchange. meta_dex_lookup returns them, so a host that loads no skill\n * (Claude Desktop chat) still gets the tested reads of\n * skills/chain-insights-dex*. The shapes are the skills' own: R3 and R4 of\n * chain-insights-dex, G1, G4 and G5 of the gauge trail, V1, V3 and V4 of the\n * vault trail, L1 to L3 of the launchpad trail.\n *\n * A value the lookup cannot know (a seller, a day, a transaction) is written\n * as a placeholder in angle brackets, and the step's `why` says where it comes\n * from. Every address the lookup knows is written in full.\n */\n\nimport type { DexEntry, TrailType } from './dex-registry.js'\n\nexport interface RecipeStep {\n step: string\n why: string\n query: string\n}\n\n/** The trail-type skill of each trail, for hosts that load skills. */\nexport const TRAIL_SKILLS: Record<TrailType, string> = {\n plain: 'chain-insights-dex',\n gauge: 'chain-insights-dex-gauge',\n vault: 'chain-insights-dex-vault',\n launchpad: 'chain-insights-dex-launchpad',\n}\n\nconst SELLER = '<seller address>'\nconst DAY = '<YYYY-MM-DD>'\nconst TX = '<tx_id>'\nconst TOKEN = '<launched token address>'\n\n/** The pools one factory deployed, by lifetime volume (R3). */\nexport function poolsByFactoryQuery(factory: string, limit = 10): string {\n return (\n `USE topology MATCH (f:Address {address: \"${factory}\"})-[:DEPLOYED_CONTRACT]->(p:Pool) WHERE p.total_volume_usd IS NOT NULL ` +\n 'RETURN f.address AS from_address, p.address AS to_address, p.labels AS to_labels, p.total_volume_usd AS total_volume_usd, p.tx_total_count AS tx_total_count ' +\n `ORDER BY p.total_volume_usd DESC LIMIT ${limit}`\n )\n}\n\n/** The senders of one pool on FLOWS_TO, by lifetime volume (R4, G1). */\nfunction sellersIntoPoolQuery(pool: string): string {\n return (\n `USE topology MATCH (s:Address)-[f:FLOWS_TO]->(p:Address {address: \"${pool}\"}) WHERE NOT s:Pool ` +\n 'RETURN s.address AS from_address, p.address AS to_address, labels(s) AS from_node_labels, f.amount_usd_sum AS amount_usd_sum, f.tx_count AS tx_count, f.first_seen_timestamp AS first_seen_timestamp, f.last_seen_timestamp AS last_seen_timestamp, s.labels AS from_labels, p.labels AS to_labels, s.is_exchange AS from_is_exchange, p.is_exchange AS to_is_exchange ' +\n 'ORDER BY f.amount_usd_sum DESC LIMIT 25'\n )\n}\n\n/** The payers whose swaps name one contract as the recipient, by sold volume (V4 shape). */\nfunction sellersIntoContractQuery(contract: string): string {\n return (\n `USE topology MATCH (s:Address)-[sw:SWAPPED]->(r:Address {address: \"${contract}\"}) WHERE NOT s:Pool ` +\n 'RETURN s.address AS from_address, r.address AS to_address, labels(s) AS from_node_labels, sw.sold_asset AS sold_asset, sw.bought_asset AS bought_asset, sw.sold_usd AS sold_usd, sw.bought_usd AS bought_usd, sw.swap_count AS swap_count, sw.pools AS pools, sw.last_seen_height AS last_seen_height ' +\n 'ORDER BY sw.sold_usd DESC LIMIT 25'\n )\n}\n\n/** One seller's swaps (R5, G2, V1). */\nfunction sellerSwapsQuery(): string {\n return (\n `USE topology MATCH (s:Address {address: \"${SELLER}\"})-[sw:SWAPPED]->(r:Address) ` +\n 'RETURN s.address AS from_address, r.address AS to_address, labels(r) AS to_node_labels, sw.sold_asset AS sold_asset, sw.bought_asset AS bought_asset, sw.sold_usd AS sold_usd, sw.bought_usd AS bought_usd, sw.swap_count AS swap_count, sw.pools AS pools, sw.last_seen_height AS last_seen_height ' +\n 'ORDER BY sw.swap_count DESC LIMIT 25'\n )\n}\n\n/** The facts SWAP rows of a seller and one recipient on one day (R6, G4, V3). */\nfunction swapRowsQuery(recipient: string): string {\n return (\n `USE facts MATCH (s:Address {address: \"${SELLER}\"})-[x:SWAP]->(r:Address {address: \"${recipient}\"}) WHERE x.block_date = \"${DAY}\" ` +\n 'RETURN x.tx_id AS tx_id, x.block_timestamp AS block_timestamp, x.payer AS payer, x.recipient AS recipient, x.sold_asset_symbol AS sold_asset_symbol, x.sold_usd AS sold_usd, x.bought_asset_symbol AS bought_asset_symbol, x.bought_usd AS bought_usd LIMIT 50'\n )\n}\n\n/** The transfers one router made in one transaction (G5). */\nfunction routerPayoutQuery(router: string): string {\n return (\n `USE facts MATCH (r:Address {address: \"${router}\"})-[t:TRANSFER]->(b:Address) WHERE t.block_date = \"${DAY}\" AND t.tx_id = \"${TX}\" ` +\n 'RETURN r.address AS from_address, b.address AS to_address, t.amount_usd AS amount_usd, t.asset_symbol AS asset_symbol, t.kind AS kind, t.tx_id AS tx_id LIMIT 10'\n )\n}\n\nconst dayStep: RecipeStep = {\n step: 'The day of a swap link',\n why: 'A SWAPPED link carries heights, not times: read the block of its last_seen_height for the day the facts reads need.',\n query:\n 'USE chain MATCH (b:Block {block_height: <last_seen_height>}) RETURN b.block_date, b.block_timestamp',\n}\n\n/**\n * The pool a trail starts from: the busiest pool read, else the registry's\n * example pool, else none.\n */\nfunction startPool(entry: DexEntry, topPool: string | null): string | null {\n return topPool ?? entry.example_pool ?? null\n}\n\nfunction poolsStep(entry: DexEntry): RecipeStep | null {\n const factory = entry.factories.find((address) => entry.roles[address] === 'factory')\n if (!factory) return null\n return {\n step: 'Pools of the exchange, by factory',\n why: `The pools ${entry.display} deployed, by lifetime volume. One batch member per factory: ${entry.factories.filter((a) => entry.roles[a] === 'factory').join(', ')}.`,\n query: poolsByFactoryQuery(factory),\n }\n}\n\n/** The first reads of the exchange's trail type, with its addresses filled in. */\nexport function recipeFor(entry: DexEntry, topPool: string | null): RecipeStep[] {\n const pool = startPool(entry, topPool)\n const steps: RecipeStep[] = []\n switch (entry.trail_type) {\n case 'gauge': {\n const router = entry.routers[0]\n if (router) {\n steps.push({\n step: 'Sellers into the router',\n why: `On ${entry.display} a swap pays the router, and the router pays on. These are the payers whose swaps name the router ${router}; the router is never the buyer.`,\n query: sellersIntoContractQuery(router),\n })\n }\n if (pool) {\n steps.push({\n step: 'Sellers into the busiest pool',\n why: `The senders of ${pool} on FLOWS_TO. A sender that also adds liquidity is a liquidity provider, not a seller.`,\n query: sellersIntoPoolQuery(pool),\n })\n } else {\n const pools = poolsStep(entry)\n if (pools) steps.push(pools)\n }\n if (router) {\n steps.push(dayStep)\n steps.push({\n step: \"A seller's swaps through the router on one day\",\n why: 'Fill the seller from the first step and the day from the block read: each row gives the tx_id of one swap.',\n query: swapRowsQuery(router),\n })\n steps.push({\n step: 'Who the router paid in that transaction',\n why: 'Fill the day and the tx_id: the receiver of the bought asset is the buyer. A pool or a pool manager there is the next leg, not the buyer.',\n query: routerPayoutQuery(router),\n })\n }\n break\n }\n case 'vault': {\n const manager = entry.factories[0]!\n steps.push({\n step: 'The swaps the pool manager settles',\n why: `${entry.display} keeps every pool in one manager, ${manager}. A manager deploys nothing: its pools are the pools of the swaps it settles.`,\n query: sellersIntoContractQuery(manager),\n })\n steps.push({\n step: \"One seller's swaps\",\n why: 'Fill a seller from the first step. A recipient that is the manager is never the buyer: read the facts row past it.',\n query: sellerSwapsQuery(),\n })\n steps.push(dayStep)\n steps.push({\n step: 'The facts SWAP row past the manager',\n why: 'Fill the seller and the day: the recipient column names who the manager paid.',\n query: swapRowsQuery(manager),\n })\n break\n }\n case 'launchpad': {\n const factory = entry.factories[0]!\n steps.push({\n step: 'Launches of the launchpad, newest first',\n why: `The contracts ${factory} created, with the creator of each.`,\n query:\n `USE topology MATCH (f:Address {address: \"${factory}\"})-[d:DEPLOYED_CONTRACT]->(t:Address) ` +\n 'RETURN f.address AS from_address, t.address AS to_address, labels(t) AS to_node_labels, t.labels AS to_labels, d.tx_origin AS creator, d.tx_id AS tx_id, d.block_height AS block_height, d.block_timestamp AS created_timestamp ORDER BY d.block_height DESC LIMIT 25',\n })\n steps.push({\n step: 'Traders on the curve of one launched token',\n why: 'Fill a launched token from the first step.',\n query:\n `USE topology MATCH (t:Address {address: \"${TOKEN}\"})-[f:FLOWS_TO]-(b:Address) WHERE NOT t:Pool ` +\n 'RETURN startNode(f).address AS from_address, endNode(f).address AS to_address, labels(b) AS node_labels, f.tx_count AS tx_count, f.amount_usd_sum AS amount_usd_sum, f.first_seen_timestamp AS first_seen_timestamp, f.last_seen_timestamp AS last_seen_timestamp ORDER BY f.tx_count DESC LIMIT 25',\n })\n steps.push({\n step: 'The first pool of one launched token',\n why: 'The oldest ADDED_LIQUIDITY into a :Pool is the graduation. None means it has not graduated in the graph yet.',\n query:\n `USE topology MATCH (t:Address {address: \"${TOKEN}\"})-[l:ADDED_LIQUIDITY]->(p:Pool) ` +\n 'RETURN t.address AS from_address, p.address AS to_address, p.labels AS to_labels, l.asset AS asset, l.usd AS usd, l.first_seen_height AS first_seen_height ORDER BY l.first_seen_height ASC LIMIT 5',\n })\n break\n }\n case 'plain': {\n if (pool) {\n steps.push({\n step: 'Sellers into the busiest pool',\n why: `The senders of ${pool} on FLOWS_TO, by lifetime volume. A seller that is a contract is often an aggregator or a router: say \"a contract\".`,\n query: sellersIntoPoolQuery(pool),\n })\n } else {\n const pools = poolsStep(entry)\n if (pools) steps.push(pools)\n }\n steps.push({\n step: \"Who a seller's swaps paid\",\n why: 'Fill a seller from the first step. Keep the rows whose pools hold the pool: the recipient is the buyer.',\n query: sellerSwapsQuery(),\n })\n steps.push(dayStep)\n steps.push({\n step: 'The swaps of a seller and a recipient on one day',\n why: 'Fill the seller, the recipient and the day.',\n query: swapRowsQuery('<recipient address>'),\n })\n break\n }\n }\n return steps\n}\n","/**\n * meta_dex_lookup: an exchange's name becomes its addresses.\n *\n * A local tool of the proxy. It matches the name against the exchange registry\n * (src/mcp/dex-registry.ts) at no cost, then sends one graph_query_batch of\n * anchored reads: Head for the family lag, each factory, manager and router by\n * its address, and the pools each factory deployed. Nothing is read by name and\n * nothing is gated on a family lag: a factory deployed months ago is not stale\n * because the swap family is behind. A name that is not covered sends no read.\n *\n * The description below is the contract with every host, Claude Desktop chat\n * included, which reads no skill: it carries the rule the exchange skills open\n * with. tests/host-parity.test.ts holds it to the skills' trigger words.\n */\n\nimport { ANSWER_HINT } from './answer-hint.js'\nimport { recipeFor, TRAIL_SKILLS, type RecipeStep, poolsByFactoryQuery } from './dex-recipes.js'\nimport {\n DexRegistryError,\n matchDex,\n normalizeDexNetwork,\n type DexCandidate,\n type DexEntry,\n type DexMatchResult,\n type LoadedRegistry,\n type RegistrySource,\n type Role,\n type TrailType,\n} from './dex-registry.js'\n\nexport const META_DEX_LOOKUP_TOOL = 'meta_dex_lookup'\nexport const META_DEX_LOOKUP_SCHEMA = 'chain-insights.meta-dex-lookup.v1' as const\nexport const META_DEX_LOOKUP_TITLE = 'Exchange by name or address'\nexport const META_DEX_LOOKUP_DESCRIPTION =\n 'Call this first when a question names a decentralized exchange, a launchpad or a vault ' +\n '(Aero, Aerodrome, Velodrome, up., Raphael, Topaz, Uniswap, PancakeSwap, Balancer, Curve, ' +\n \"Penguin, Virtuals, ...) and gives no address. It turns the name into the exchange's \" +\n 'factories, routers or pool manager, its biggest pools, and the first reads to send, ' +\n 'with every address in full. A misspelling within two letters is taken and named in ' +\n 'took_for. When matched is null the name is not covered: say so, list covered, and send ' +\n 'no graph query for the name. Never ask the user for a pool, factory or router address. ' +\n 'When the user gives a contract address instead of a name, send it as address (0x plus 40 hex, ' +\n 'any case, with no name): the answer is the exchange whose factory, router or manager it is, ' +\n 'and took_for names the role it holds. When matched is null no exchange row holds the address: ' +\n 'send no read for it. Give a name or an address, not both.'\nexport const META_DEX_LOOKUP_ANNOTATIONS = {\n readOnlyHint: true,\n idempotentHint: true,\n openWorldHint: false,\n} as const\nexport const META_DEX_LOOKUP_ARGS = ['network', 'name', 'address', 'pools'] as const\n\n/** The pools returned per exchange, and per factory read. */\nexport const POOLS_LIMIT = 10\n/** A batch holds at most 20 members; Head and the pool reads take their share. */\nconst CONTRACT_MEMBERS_MAX = 12\n\nexport interface ContractRow {\n address: string\n role: Role\n confirmed: boolean\n confirmed_by?: string\n}\n\nexport interface PoolRow {\n address: string\n labels: string[]\n total_volume_usd: number\n tx_total_count: number\n}\n\nexport interface FamilyLag {\n behind_money: number | null\n behind_dex: number | null\n behind_transfers: number | null\n}\n\nexport interface DexMatch {\n dex: string\n display: string\n trail_type: TrailType\n /** The skill a host with skills loads next. */\n skill: string\n factories: ContractRow[]\n routers: ContractRow[]\n manager: ContractRow | null\n pools: PoolRow[]\n recipe: RecipeStep[]\n}\n\nexport interface CoveredExchange {\n dex: string\n display: string\n trail_type: TrailType\n factories: string[]\n routers: string[]\n}\n\nexport interface MetaDexLookupResult {\n schema: typeof META_DEX_LOOKUP_SCHEMA\n network: string\n registry_version: number\n registry_source: RegistrySource\n matched: DexMatch | null\n /** A near name hit: the name as typed. An address hit: the role it holds and the verification cell. */\n took_for?: string\n candidates: DexCandidate[]\n covered: string[]\n /** With no name: every covered exchange, with its key, trail type and contracts. */\n exchanges?: CoveredExchange[]\n families: FamilyLag | null\n /** What a read could not do: a lane that is not reachable, a member that was refused. */\n notes?: string[]\n hint: string\n}\n\n/** The batch reply as the remote client returns it. */\nexport type BatchAnswer = {\n content?: unknown[]\n structuredContent?: unknown\n isError?: boolean\n}\n\nexport interface DexToolDependencies {\n loadRegistry: (network: string) => Promise<LoadedRegistry>\n /** One graph_query_batch through the proxy's remote client, billed as any read. */\n graphQueryBatch: (args: {\n network: string\n queries: Array<{ id: string; query: string }>\n }) => Promise<BatchAnswer>\n /** The reason no read can be sent now, or undefined when the graph is reachable. */\n unavailable?: () => Promise<string | undefined> | string | undefined\n /** The text of a call that threw: payment required, transport. */\n describeFailure: (err: unknown) => string\n}\n\nexport type MetaDexLookupToolResult = {\n content: Array<{ type: 'text'; text: string }>\n structuredContent?: Record<string, unknown>\n isError: boolean\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction errorResult(text: string): MetaDexLookupToolResult {\n return { content: [{ type: 'text', text }], isError: true }\n}\n\ntype Member = { id?: unknown; ok?: unknown; results?: unknown; error?: unknown }\n\nfunction membersOf(answer: BatchAnswer): Map<string, Member> {\n const facts = isRecord(answer.structuredContent) ? answer.structuredContent.facts : undefined\n const queries = isRecord(facts) ? facts.queries : undefined\n const members = new Map<string, Member>()\n if (Array.isArray(queries)) {\n for (const member of queries)\n if (isRecord(member) && typeof member.id === 'string') members.set(member.id, member)\n }\n return members\n}\n\nconst rowsOf = (member: Member | undefined): Array<Record<string, unknown>> =>\n member?.ok === true && Array.isArray(member.results) ? member.results.filter(isRecord) : []\n\nconst numberOrNull = (value: unknown): number | null => {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value)))\n return Number(value)\n return null\n}\n\nconst stringList = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : []\n\n/** A column of a row, read under its alias or as the query wrote it (h.behind_dex). */\nfunction column(row: Record<string, unknown>, name: string, variable: string): unknown {\n return name in row ? row[name] : row[`${variable}.${name}`]\n}\n\nexport const HEAD_QUERY =\n 'USE chain MATCH (h:Head) RETURN h.behind_money, h.behind_dex, h.behind_transfers'\n\nexport function contractQuery(address: string): string {\n return (\n `USE topology MATCH (a:Address {address: \"${address}\"}) ` +\n 'RETURN a.address AS address, labels(a) AS node_labels, a.labels AS labels, a.is_contract AS is_contract LIMIT 1'\n )\n}\n\nexport function contractListQuery(addresses: string[]): string {\n return (\n `USE topology MATCH (a:Address) WHERE a.address IN [${addresses.map((a) => `\"${a}\"`).join(', ')}] ` +\n `RETURN a.address AS address, labels(a) AS node_labels, a.labels AS labels, a.is_contract AS is_contract LIMIT ${addresses.length}`\n )\n}\n\n/** The anchored reads of one exchange: Head, each contract, and the pools of each factory. */\nexport function lookupQueries(\n entry: DexEntry,\n pools: boolean\n): Array<{ id: string; query: string }> {\n const contracts = Object.keys(entry.roles)\n const queries: Array<{ id: string; query: string }> = [{ id: 'head', query: HEAD_QUERY }]\n if (contracts.length <= CONTRACT_MEMBERS_MAX) {\n for (const address of contracts)\n queries.push({ id: `contract:${address}`, query: contractQuery(address) })\n } else {\n queries.push({ id: 'contracts', query: contractListQuery(contracts) })\n }\n if (pools) {\n for (const factory of entry.factories.filter((address) => entry.roles[address] === 'factory')) {\n queries.push({ id: `pools:${factory}`, query: poolsByFactoryQuery(factory, POOLS_LIMIT) })\n }\n }\n return queries\n}\n\nfunction confirmation(\n row: Record<string, unknown> | undefined\n): Pick<ContractRow, 'confirmed' | 'confirmed_by'> {\n if (!row) return { confirmed: false }\n if (row.is_contract === true) return { confirmed: true, confirmed_by: 'is_contract' }\n if (stringList(row.node_labels).includes('Contract'))\n return { confirmed: true, confirmed_by: ':Contract' }\n return { confirmed: false }\n}\n\nfunction readMatch(\n entry: DexEntry,\n members: Map<string, Member>,\n read: boolean\n): {\n contracts: Map<string, ContractRow>\n pools: PoolRow[]\n families: FamilyLag | null\n notes: string[]\n} {\n const notes: string[] = []\n const contracts = new Map<string, ContractRow>()\n const listed = new Map(rowsOf(members.get('contracts')).map((row) => [String(row.address), row]))\n for (const [address, role] of Object.entries(entry.roles)) {\n const row = members.has(`contract:${address}`)\n ? rowsOf(members.get(`contract:${address}`))[0]\n : listed.get(address)\n contracts.set(address, { address, role, ...confirmation(row) })\n }\n const byAddress = new Map<string, PoolRow>()\n for (const [id, member] of members) {\n if (!id.startsWith('pools:')) continue\n for (const row of rowsOf(member)) {\n const address = typeof row.to_address === 'string' ? row.to_address : null\n const volume = numberOrNull(row.total_volume_usd)\n if (!address || volume === null || byAddress.has(address)) continue\n byAddress.set(address, {\n address,\n labels: stringList(row.to_labels),\n total_volume_usd: volume,\n tx_total_count: numberOrNull(row.tx_total_count) ?? 0,\n })\n }\n }\n const pools = [...byAddress.values()]\n .sort((a, b) => b.total_volume_usd - a.total_volume_usd)\n .slice(0, POOLS_LIMIT)\n const head = rowsOf(members.get('head'))[0]\n const families: FamilyLag | null = head\n ? {\n behind_money: numberOrNull(column(head, 'behind_money', 'h')),\n behind_dex: numberOrNull(column(head, 'behind_dex', 'h')),\n behind_transfers: numberOrNull(column(head, 'behind_transfers', 'h')),\n }\n : null\n if (read) {\n for (const [id, member] of members) {\n if (member.ok !== true)\n notes.push(\n `${id}: ${typeof member.error === 'string' ? member.error : 'the read was not served'}`\n )\n }\n }\n return { contracts, pools, families, notes }\n}\n\nconst ADDRESS_FORM = /^0x[0-9a-fA-F]{40}$/\n\nfunction hintFor(\n result: Omit<MetaDexLookupResult, 'hint'>,\n name: string | null,\n address: string | null = null\n): string {\n if (address !== null && !result.matched) {\n return `${ANSWER_HINT} No exchange row holds ${address}: it is not a registered exchange contract. Send no exchange read for it; read the graph for what the address did.`\n }\n if (address !== null && result.matched) {\n const { matched } = result\n return (\n `${ANSWER_HINT} Say in one line: \"${address} is a ${result.took_for} row of ${matched.display}.\" Ask nothing. ` +\n `Exchange ${matched.display}, trail ${matched.trail_type}: send the first reads of recipe, ` +\n `anchored on the addresses above, and load ${matched.skill} when this host has skills. ` +\n 'Read families before a SWAPPED search: it is sent when behind_dex is at most 100000. Never ask the user for an address.'\n )\n }\n if (name === null) {\n return `${ANSWER_HINT} These are the exchanges the registry covers. Call meta_dex_lookup with a name for its addresses and first reads.`\n }\n if (result.matched) {\n const { matched } = result\n const took = result.took_for\n ? `Say in one line: \"I took ${matched.display} for ${result.took_for}.\" Ask nothing. `\n : ''\n return (\n `${ANSWER_HINT} ${took}Exchange ${matched.display}, trail ${matched.trail_type}: send the first reads of recipe, ` +\n `anchored on the addresses above, and load ${matched.skill} when this host has skills. ` +\n 'Read families before a SWAPPED search: it is sent when behind_dex is at most 100000. Never ask the user for an address.'\n )\n }\n if (result.candidates.length > 0) {\n const names = result.candidates\n .map((candidate) => `${candidate.display} (${candidate.dex})`)\n .join(', ')\n return `${ANSWER_HINT} ${result.candidates.length} rows fit \"${name}\": ${names}. Name both or pick one: call meta_dex_lookup with each key. Never guess one, never ask the user for an address.`\n }\n return `${ANSWER_HINT} ${name} is not covered. Send no query for the name: say so in one line and list the covered exchanges by name.`\n}\n\nfunction textResult(structured: MetaDexLookupResult): MetaDexLookupToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(structured, null, 2) }],\n structuredContent: structured as unknown as Record<string, unknown>,\n isError: false,\n }\n}\n\n/** meta_dex_lookup, {network, name?, address?, pools?}. Every argument is checked before the registry is read. */\nexport async function handleMetaDexLookup(\n args: unknown,\n deps: DexToolDependencies\n): Promise<MetaDexLookupToolResult> {\n const record = isRecord(args) ? args : {}\n let network: string\n try {\n network = normalizeDexNetwork(record.network)\n } catch (err) {\n return errorResult((err as Error).message)\n }\n const rawName = record.name\n if (rawName !== undefined && rawName !== null && typeof rawName !== 'string') {\n return errorResult('invalid_name: name must be the exchange name as text')\n }\n const name = typeof rawName === 'string' && rawName.trim() !== '' ? rawName.trim() : null\n const rawAddress = record.address\n if (rawAddress !== undefined && rawAddress !== null && typeof rawAddress !== 'string') {\n return errorResult('invalid_address: address must be 0x plus 40 hex characters')\n }\n const addressText = typeof rawAddress === 'string' && rawAddress.trim() !== '' ? rawAddress.trim() : null\n if (name !== null && addressText !== null) return errorResult('Give a name or an address, not both.')\n if (addressText !== null && !ADDRESS_FORM.test(addressText)) {\n return errorResult('invalid_address: address must be 0x plus 40 hex characters')\n }\n const address = addressText === null ? null : addressText.toLowerCase()\n const rawPools = record.pools\n if (rawPools !== undefined && rawPools !== null && typeof rawPools !== 'boolean') {\n return errorResult('invalid_pools: pools must be true or false')\n }\n const pools = rawPools !== false\n\n let loaded: LoadedRegistry\n try {\n loaded = await deps.loadRegistry(network)\n } catch (err) {\n return errorResult(\n err instanceof DexRegistryError\n ? err.message\n : `exchange registry unavailable: ${(err as Error).message}`\n )\n }\n const { document } = loaded\n const base = {\n schema: META_DEX_LOOKUP_SCHEMA,\n network,\n registry_version: document.registry_version,\n registry_source: loaded.source,\n }\n\n if (name === null && address === null) {\n const result = {\n ...base,\n matched: null,\n candidates: [],\n covered: document.rows.map((row) => row.display),\n exchanges: document.rows.map((row) => ({\n dex: row.dex,\n display: row.display,\n trail_type: row.trail_type,\n factories: row.factories,\n routers: row.routers,\n })),\n families: null,\n }\n return textResult({ ...result, hint: hintFor(result, null) })\n }\n\n let match: DexMatchResult\n if (address !== null) {\n const holder = document.rows.find((row) => address in row.roles)\n match = {\n matched: holder ?? null,\n ...(holder ? { took_for: `${holder.roles[address]}, served` } : {}),\n candidates: [],\n covered: document.rows.map((row) => row.display),\n }\n } else {\n match = matchDex(name as string, document.rows)\n }\n if (!match.matched) {\n const result = {\n ...base,\n matched: null,\n candidates: match.candidates,\n covered: match.covered,\n families: null,\n }\n return textResult({ ...result, hint: hintFor(result, name, address) })\n }\n\n const entry = match.matched\n const queries = lookupQueries(entry, pools)\n let members = new Map<string, Member>()\n const notes: string[] = []\n const unavailable = await deps.unavailable?.()\n if (unavailable) {\n notes.push(\n `No graph read was sent: ${unavailable} The contracts are the reviewed registry rows, not yet confirmed on the graph.`\n )\n } else {\n try {\n const answer = await deps.graphQueryBatch({ network, queries })\n members = membersOf(answer)\n if (answer.isError === true && members.size === 0) {\n const first = Array.isArray(answer.content) ? answer.content[0] : undefined\n notes.push(\n `The graph refused the reads: ${isRecord(first) && typeof first.text === 'string' ? first.text : 'no reason given'}`\n )\n }\n } catch (err) {\n notes.push(`The graph reads failed: ${deps.describeFailure(err)}`)\n }\n }\n const read = readMatch(entry, members, members.size > 0)\n notes.push(...read.notes)\n const contractsOf = (role: Role): ContractRow[] =>\n [...read.contracts.values()].filter((contract) => contract.role === role)\n const topPool = read.pools[0]?.address ?? null\n const matched: DexMatch = {\n dex: entry.dex,\n display: entry.display,\n trail_type: entry.trail_type,\n skill: TRAIL_SKILLS[entry.trail_type],\n factories: contractsOf('factory'),\n routers: contractsOf('router'),\n manager: contractsOf('manager')[0] ?? null,\n pools: read.pools,\n recipe: recipeFor(entry, topPool),\n }\n const result = {\n ...base,\n matched,\n ...(match.took_for ? { took_for: match.took_for } : {}),\n candidates: [],\n covered: match.covered,\n families: read.families,\n ...(notes.length > 0 ? { notes } : {}),\n }\n return textResult({ ...result, hint: hintFor(result, name, address) })\n}\n"],"mappings":";;;;;;;;;;;;AAUA,MAAa,cACX;AAMF,SAASA,WAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;AAGA,SAAgB,eAAe,mBAAqC;CAClE,IAAI,CAACA,WAAS,iBAAiB,KAAK,CAACA,WAAS,kBAAkB,KAAK,GAAG,OAAO;CAC/E,IAAI,OAAO,kBAAkB,SAAS,YAAY,kBAAkB,KAAK,KAAK,GAAG,OAAO;CACxF,OAAO;EAAE,GAAG;EAAmB,MAAM;CAAY;AACnD;;AAGA,SAAgB,qBAAuF,QAAc;CACnH,MAAM,aAAa,eAAe,OAAO,iBAAiB;CAC1D,IAAI,eAAe,OAAO,mBAAmB,OAAO;CACpD,MAAM,UAAU,OAAO,WAAW,CAAC;CACnC,MAAM,OAAO,QAAQ,WAAW,KAAK,QAAQ,EAAE,EAAE,SAAS,SAAS,QAAQ,KAAK;CAChF,IAAI,SAAkB,KAAA;CACtB,IAAI;EACF,SAAS,MAAM,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,KAAA;CAChD,QAAQ;EACN,SAAS,KAAA;CACX;CACA,MAAM,mBAAmB,WAAW,KAAA,KAAa,KAAK,UAAU,MAAM,MAAM,KAAK,UAAU,OAAO,iBAAiB;CACnH,OAAO;EAAE,GAAG;EAAQ,mBAAmB;EAAY,SAAS,mBAAmB,CAAC;GAAE,GAAG;GAAM,MAAM,KAAK,UAAU,UAAU;EAAE,CAAC,IAAI;CAAQ;AAC3I;;;;ACpBA,MAAa,eAA0C;CACrD,OAAO;CACP,OAAO;CACP,OAAO;CACP,WAAW;AACb;AAEA,MAAM,SAAS;AACf,MAAM,MAAM;AACZ,MAAM,KAAK;AACX,MAAM,QAAQ;;AAGd,SAAgB,oBAAoB,SAAiB,QAAQ,IAAY;CACvE,OACE,4CAA4C,QAAQ,8QAEV;AAE9C;;AAGA,SAAS,qBAAqB,MAAsB;CAClD,OACE,sEAAsE,KAAK;AAI/E;;AAGA,SAAS,yBAAyB,UAA0B;CAC1D,OACE,sEAAsE,SAAS;AAInF;;AAGA,SAAS,mBAA2B;CAClC,OACE,4CAA4C,OAAO;AAIvD;;AAGA,SAAS,cAAc,WAA2B;CAChD,OACE,yCAAyC,OAAO,sCAAsC,UAAU,4BAA4B,IAAI;AAGpI;;AAGA,SAAS,kBAAkB,QAAwB;CACjD,OACE,yCAAyC,OAAO,sDAAsD,IAAI,mBAAmB,GAAG;AAGpI;AAEA,MAAM,UAAsB;CAC1B,MAAM;CACN,KAAK;CACL,OACE;AACJ;;;;;AAMA,SAAS,UAAU,OAAiB,SAAuC;CACzE,OAAO,WAAW,MAAM,gBAAgB;AAC1C;AAEA,SAAS,UAAU,OAAoC;CACrD,MAAM,UAAU,MAAM,UAAU,MAAM,YAAY,MAAM,MAAM,aAAa,SAAS;CACpF,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO;EACL,MAAM;EACN,KAAK,aAAa,MAAM,QAAQ,+DAA+D,MAAM,UAAU,QAAQ,MAAM,MAAM,MAAM,OAAO,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE;EACtK,OAAO,oBAAoB,OAAO;CACpC;AACF;;AAGA,SAAgB,UAAU,OAAiB,SAAsC;CAC/E,MAAM,OAAO,UAAU,OAAO,OAAO;CACrC,MAAM,QAAsB,CAAC;CAC7B,QAAQ,MAAM,YAAd;EACE,KAAK,SAAS;GACZ,MAAM,SAAS,MAAM,QAAQ;GAC7B,IAAI,QACF,MAAM,KAAK;IACT,MAAM;IACN,KAAK,MAAM,MAAM,QAAQ,oGAAoG,OAAO;IACpI,OAAO,yBAAyB,MAAM;GACxC,CAAC;GAEH,IAAI,MACF,MAAM,KAAK;IACT,MAAM;IACN,KAAK,kBAAkB,KAAK;IAC5B,OAAO,qBAAqB,IAAI;GAClC,CAAC;QACI;IACL,MAAM,QAAQ,UAAU,KAAK;IAC7B,IAAI,OAAO,MAAM,KAAK,KAAK;GAC7B;GACA,IAAI,QAAQ;IACV,MAAM,KAAK,OAAO;IAClB,MAAM,KAAK;KACT,MAAM;KACN,KAAK;KACL,OAAO,cAAc,MAAM;IAC7B,CAAC;IACD,MAAM,KAAK;KACT,MAAM;KACN,KAAK;KACL,OAAO,kBAAkB,MAAM;IACjC,CAAC;GACH;GACA;EACF;EACA,KAAK,SAAS;GACZ,MAAM,UAAU,MAAM,UAAU;GAChC,MAAM,KAAK;IACT,MAAM;IACN,KAAK,GAAG,MAAM,QAAQ,oCAAoC,QAAQ;IAClE,OAAO,yBAAyB,OAAO;GACzC,CAAC;GACD,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OAAO,iBAAiB;GAC1B,CAAC;GACD,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OAAO,cAAc,OAAO;GAC9B,CAAC;GACD;EACF;EACA,KAAK,aAAa;GAChB,MAAM,UAAU,MAAM,UAAU;GAChC,MAAM,KAAK;IACT,MAAM;IACN,KAAK,iBAAiB,QAAQ;IAC9B,OACE,4CAA4C,QAAQ;GAExD,CAAC;GACD,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OACE,4CAA4C,MAAM;GAEtD,CAAC;GACD,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OACE,4CAA4C,MAAM;GAEtD,CAAC;GACD;EACF;EACA,KAAK;GACH,IAAI,MACF,MAAM,KAAK;IACT,MAAM;IACN,KAAK,kBAAkB,KAAK;IAC5B,OAAO,qBAAqB,IAAI;GAClC,CAAC;QACI;IACL,MAAM,QAAQ,UAAU,KAAK;IAC7B,IAAI,OAAO,MAAM,KAAK,KAAK;GAC7B;GACA,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OAAO,iBAAiB;GAC1B,CAAC;GACD,MAAM,KAAK,OAAO;GAClB,MAAM,KAAK;IACT,MAAM;IACN,KAAK;IACL,OAAO,cAAc,qBAAqB;GAC5C,CAAC;CAGL;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/LA,MAAa,uBAAuB;AACpC,MAAa,yBAAyB;AACtC,MAAa,wBAAwB;AACrC,MAAa,8BACX;AAWF,MAAa,8BAA8B;CACzC,cAAc;CACd,gBAAgB;CAChB,eAAe;AACjB;;AAMA,MAAM,uBAAuB;AAuF7B,SAAS,SAAS,OAAkD;CAClE,OAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AACrE;AAEA,SAAS,YAAY,MAAuC;CAC1D,OAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAQ;EAAK,CAAC;EAAG,SAAS;CAAK;AAC5D;AAIA,SAAS,UAAU,QAA0C;CAC3D,MAAM,QAAQ,SAAS,OAAO,iBAAiB,IAAI,OAAO,kBAAkB,QAAQ,KAAA;CACpF,MAAM,UAAU,SAAS,KAAK,IAAI,MAAM,UAAU,KAAA;CAClD,MAAM,0BAAU,IAAI,IAAoB;CACxC,IAAI,MAAM,QAAQ,OAAO,GAClB;OAAA,MAAM,UAAU,SACnB,IAAI,SAAS,MAAM,KAAK,OAAO,OAAO,OAAO,UAAU,QAAQ,IAAI,OAAO,IAAI,MAAM;CAAA;CAExF,OAAO;AACT;AAEA,MAAM,UAAU,WACd,QAAQ,OAAO,QAAQ,MAAM,QAAQ,OAAO,OAAO,IAAI,OAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAE5F,MAAM,gBAAgB,UAAkC;CACtD,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG,OAAO;CAChE,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,KAAK,CAAC,GACnF,OAAO,OAAO,KAAK;CACrB,OAAO;AACT;AAEA,MAAM,cAAc,UAClB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,UAA2B,OAAO,UAAU,QAAQ,IAAI,CAAC;;AAGhG,SAAS,OAAO,KAA8B,MAAc,UAA2B;CACrF,OAAO,QAAQ,MAAM,IAAI,QAAQ,IAAI,GAAG,SAAS,GAAG;AACtD;AAEA,MAAa,aACX;AAEF,SAAgB,cAAc,SAAyB;CACrD,OACE,4CAA4C,QAAQ;AAGxD;AAEA,SAAgB,kBAAkB,WAA6B;CAC7D,OACE,sDAAsD,UAAU,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,kHACiB,UAAU;AAE/H;;AAGA,SAAgB,cACd,OACA,OACsC;CACtC,MAAM,YAAY,OAAO,KAAK,MAAM,KAAK;CACzC,MAAM,UAAgD,CAAC;EAAE,IAAI;EAAQ,OAAO;CAAW,CAAC;CACxF,IAAI,UAAU,UAAU,sBACtB,KAAK,MAAM,WAAW,WACpB,QAAQ,KAAK;EAAE,IAAI,YAAY;EAAW,OAAO,cAAc,OAAO;CAAE,CAAC;MAE3E,QAAQ,KAAK;EAAE,IAAI;EAAa,OAAO,kBAAkB,SAAS;CAAE,CAAC;CAEvE,IAAI,OACF,KAAK,MAAM,WAAW,MAAM,UAAU,QAAQ,YAAY,MAAM,MAAM,aAAa,SAAS,GAC1F,QAAQ,KAAK;EAAE,IAAI,SAAS;EAAW,OAAO,oBAAoB,SAAA,EAAoB;CAAE,CAAC;CAG7F,OAAO;AACT;AAEA,SAAS,aACP,KACiD;CACjD,IAAI,CAAC,KAAK,OAAO,EAAE,WAAW,MAAM;CACpC,IAAI,IAAI,gBAAgB,MAAM,OAAO;EAAE,WAAW;EAAM,cAAc;CAAc;CACpF,IAAI,WAAW,IAAI,WAAW,CAAC,CAAC,SAAS,UAAU,GACjD,OAAO;EAAE,WAAW;EAAM,cAAc;CAAY;CACtD,OAAO,EAAE,WAAW,MAAM;AAC5B;AAEA,SAAS,UACP,OACA,SACA,MAMA;CACA,MAAM,QAAkB,CAAC;CACzB,MAAM,4BAAY,IAAI,IAAyB;CAC/C,MAAM,SAAS,IAAI,IAAI,OAAO,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,OAAO,GAAG,GAAG,CAAC,CAAC;CAChG,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,MAAM,KAAK,GAAG;EACzD,MAAM,MAAM,QAAQ,IAAI,YAAY,SAAS,IACzC,OAAO,QAAQ,IAAI,YAAY,SAAS,CAAC,CAAC,CAAC,KAC3C,OAAO,IAAI,OAAO;EACtB,UAAU,IAAI,SAAS;GAAE;GAAS;GAAM,GAAG,aAAa,GAAG;EAAE,CAAC;CAChE;CACA,MAAM,4BAAY,IAAI,IAAqB;CAC3C,KAAK,MAAM,CAAC,IAAI,WAAW,SAAS;EAClC,IAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;EAC9B,KAAK,MAAM,OAAO,OAAO,MAAM,GAAG;GAChC,MAAM,UAAU,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;GACtE,MAAM,SAAS,aAAa,IAAI,gBAAgB;GAChD,IAAI,CAAC,WAAW,WAAW,QAAQ,UAAU,IAAI,OAAO,GAAG;GAC3D,UAAU,IAAI,SAAS;IACrB;IACA,QAAQ,WAAW,IAAI,SAAS;IAChC,kBAAkB;IAClB,gBAAgB,aAAa,IAAI,cAAc,KAAK;GACtD,CAAC;EACH;CACF;CACA,MAAM,QAAQ,CAAC,GAAG,UAAU,OAAO,CAAC,CAAC,CAClC,MAAM,GAAG,MAAM,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,CACvD,MAAM,GAAA,EAAc;CACvB,MAAM,OAAO,OAAO,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC;CACzC,MAAM,WAA6B,OAC/B;EACE,cAAc,aAAa,OAAO,MAAM,gBAAgB,GAAG,CAAC;EAC5D,YAAY,aAAa,OAAO,MAAM,cAAc,GAAG,CAAC;EACxD,kBAAkB,aAAa,OAAO,MAAM,oBAAoB,GAAG,CAAC;CACtE,IACA;CACJ,IAAI,MACG;OAAA,MAAM,CAAC,IAAI,WAAW,SACzB,IAAI,OAAO,OAAO,MAChB,MAAM,KACJ,GAAG,GAAG,IAAI,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,2BAC9D;CAAA;CAGN,OAAO;EAAE;EAAW;EAAO;EAAU;CAAM;AAC7C;AAEA,MAAM,eAAe;AAErB,SAAS,QACP,QACA,MACA,UAAyB,MACjB;CACR,IAAI,YAAY,QAAQ,CAAC,OAAO,SAC9B,OAAO,GAAG,YAAY,yBAAyB,QAAQ;CAEzD,IAAI,YAAY,QAAQ,OAAO,SAAS;EACtC,MAAM,EAAE,YAAY;EACpB,OACE,GAAG,YAAY,qBAAqB,QAAQ,QAAQ,OAAO,SAAS,UAAU,QAAQ,QAAQ,2BAClF,QAAQ,QAAQ,UAAU,QAAQ,WAAW,8EACZ,QAAQ,MAAM;CAG/D;CACA,IAAI,SAAS,MACX,OAAO,GAAG,YAAY;CAExB,IAAI,OAAO,SAAS;EAClB,MAAM,EAAE,YAAY;EACpB,MAAM,OAAO,OAAO,WAChB,4BAA4B,QAAQ,QAAQ,OAAO,OAAO,SAAS,oBACnE;EACJ,OACE,GAAG,YAAY,GAAG,KAAK,WAAW,QAAQ,QAAQ,UAAU,QAAQ,WAAW,8EAClC,QAAQ,MAAM;CAG/D;CACA,IAAI,OAAO,WAAW,SAAS,GAAG;EAChC,MAAM,QAAQ,OAAO,WAClB,KAAK,cAAc,GAAG,UAAU,QAAQ,IAAI,UAAU,IAAI,EAAE,CAAC,CAC7D,KAAK,IAAI;EACZ,OAAO,GAAG,YAAY,GAAG,OAAO,WAAW,OAAO,aAAa,KAAK,KAAK,MAAM;CACjF;CACA,OAAO,GAAG,YAAY,GAAG,KAAK;AAChC;AAEA,SAAS,WAAW,YAA0D;CAC5E,OAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,KAAK,UAAU,YAAY,MAAM,CAAC;EAAE,CAAC;EACrE,mBAAmB;EACnB,SAAS;CACX;AACF;;AAGA,eAAsB,oBACpB,MACA,MACkC;CAClC,MAAM,SAAS,SAAS,IAAI,IAAI,OAAO,CAAC;CACxC,IAAI;CACJ,IAAI;EACF,UAAU,oBAAoB,OAAO,OAAO;CAC9C,SAAS,KAAK;EACZ,OAAO,YAAa,IAAc,OAAO;CAC3C;CACA,MAAM,UAAU,OAAO;CACvB,IAAI,YAAY,KAAA,KAAa,YAAY,QAAQ,OAAO,YAAY,UAClE,OAAO,YAAY,sDAAsD;CAE3E,MAAM,OAAO,OAAO,YAAY,YAAY,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK,IAAI;CACrF,MAAM,aAAa,OAAO;CAC1B,IAAI,eAAe,KAAA,KAAa,eAAe,QAAQ,OAAO,eAAe,UAC3E,OAAO,YAAY,4DAA4D;CAEjF,MAAM,cAAc,OAAO,eAAe,YAAY,WAAW,KAAK,MAAM,KAAK,WAAW,KAAK,IAAI;CACrG,IAAI,SAAS,QAAQ,gBAAgB,MAAM,OAAO,YAAY,sCAAsC;CACpG,IAAI,gBAAgB,QAAQ,CAAC,aAAa,KAAK,WAAW,GACxD,OAAO,YAAY,4DAA4D;CAEjF,MAAM,UAAU,gBAAgB,OAAO,OAAO,YAAY,YAAY;CACtE,MAAM,WAAW,OAAO;CACxB,IAAI,aAAa,KAAA,KAAa,aAAa,QAAQ,OAAO,aAAa,WACrE,OAAO,YAAY,4CAA4C;CAEjE,MAAM,QAAQ,aAAa;CAE3B,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,KAAK,aAAa,OAAO;CAC1C,SAAS,KAAK;EACZ,OAAO,YACL,eAAe,mBACX,IAAI,UACJ,kCAAmC,IAAc,SACvD;CACF;CACA,MAAM,EAAE,aAAa;CACrB,MAAM,OAAO;EACX,QAAQ;EACR;EACA,kBAAkB,SAAS;EAC3B,iBAAiB,OAAO;CAC1B;CAEA,IAAI,SAAS,QAAQ,YAAY,MAAM;EACrC,MAAM,SAAS;GACb,GAAG;GACH,SAAS;GACT,YAAY,CAAC;GACb,SAAS,SAAS,KAAK,KAAK,QAAQ,IAAI,OAAO;GAC/C,WAAW,SAAS,KAAK,KAAK,SAAS;IACrC,KAAK,IAAI;IACT,SAAS,IAAI;IACb,YAAY,IAAI;IAChB,WAAW,IAAI;IACf,SAAS,IAAI;GACf,EAAE;GACF,UAAU;EACZ;EACA,OAAO,WAAW;GAAE,GAAG;GAAQ,MAAM,QAAQ,QAAQ,IAAI;EAAE,CAAC;CAC9D;CAEA,IAAI;CACJ,IAAI,YAAY,MAAM;EACpB,MAAM,SAAS,SAAS,KAAK,MAAM,QAAQ,WAAW,IAAI,KAAK;EAC/D,QAAQ;GACN,SAAS,UAAU;GACnB,GAAI,SAAS,EAAE,UAAU,GAAG,OAAO,MAAM,SAAS,UAAU,IAAI,CAAC;GACjE,YAAY,CAAC;GACb,SAAS,SAAS,KAAK,KAAK,QAAQ,IAAI,OAAO;EACjD;CACF,OACE,QAAQ,SAAS,MAAgB,SAAS,IAAI;CAEhD,IAAI,CAAC,MAAM,SAAS;EAClB,MAAM,SAAS;GACb,GAAG;GACH,SAAS;GACT,YAAY,MAAM;GAClB,SAAS,MAAM;GACf,UAAU;EACZ;EACA,OAAO,WAAW;GAAE,GAAG;GAAQ,MAAM,QAAQ,QAAQ,MAAM,OAAO;EAAE,CAAC;CACvE;CAEA,MAAM,QAAQ,MAAM;CACpB,MAAM,UAAU,cAAc,OAAO,KAAK;CAC1C,IAAI,0BAAU,IAAI,IAAoB;CACtC,MAAM,QAAkB,CAAC;CACzB,MAAM,cAAc,MAAM,KAAK,cAAc;CAC7C,IAAI,aACF,MAAM,KACJ,2BAA2B,YAAY,+EACzC;MAEA,IAAI;EACF,MAAM,SAAS,MAAM,KAAK,gBAAgB;GAAE;GAAS;EAAQ,CAAC;EAC9D,UAAU,UAAU,MAAM;EAC1B,IAAI,OAAO,YAAY,QAAQ,QAAQ,SAAS,GAAG;GACjD,MAAM,QAAQ,MAAM,QAAQ,OAAO,OAAO,IAAI,OAAO,QAAQ,KAAK,KAAA;GAClE,MAAM,KACJ,gCAAgC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,mBACnG;EACF;CACF,SAAS,KAAK;EACZ,MAAM,KAAK,2BAA2B,KAAK,gBAAgB,GAAG,GAAG;CACnE;CAEF,MAAM,OAAO,UAAU,OAAO,SAAS,QAAQ,OAAO,CAAC;CACvD,MAAM,KAAK,GAAG,KAAK,KAAK;CACxB,MAAM,eAAe,SACnB,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,CAAC,CAAC,QAAQ,aAAa,SAAS,SAAS,IAAI;CAC1E,MAAM,UAAU,KAAK,MAAM,EAAE,EAAE,WAAW;CAC1C,MAAM,UAAoB;EACxB,KAAK,MAAM;EACX,SAAS,MAAM;EACf,YAAY,MAAM;EAClB,OAAO,aAAa,MAAM;EAC1B,WAAW,YAAY,SAAS;EAChC,SAAS,YAAY,QAAQ;EAC7B,SAAS,YAAY,SAAS,CAAC,CAAC,MAAM;EACtC,OAAO,KAAK;EACZ,QAAQ,UAAU,OAAO,OAAO;CAClC;CACA,MAAM,SAAS;EACb,GAAG;EACH;EACA,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;EACrD,YAAY,CAAC;EACb,SAAS,MAAM;EACf,UAAU,KAAK;EACf,GAAI,MAAM,SAAS,IAAI,EAAE,MAAM,IAAI,CAAC;CACtC;CACA,OAAO,WAAW;EAAE,GAAG;EAAQ,MAAM,QAAQ,QAAQ,MAAM,OAAO;CAAE,CAAC;AACvE"}
@@ -8,7 +8,7 @@ const require_subscription_status = require("./subscription-status-ru99UCPZ.cjs"
8
8
  const require_capabilities = require("./capabilities-DGavTSoW.cjs");
9
9
  const require_graph_schema = require("./graph-schema-BoUMa03H.cjs");
10
10
  const require_action_log = require("./action-log-HniMMF7f.cjs");
11
- const require_dex_tool = require("./dex-tool-DIKN4dXB.cjs");
11
+ const require_dex_tool = require("./dex-tool-B4T8Czhm.cjs");
12
12
  const require_dex_registry = require("./dex-registry-KOTJhAQf.cjs");
13
13
  let node_url = require("node:url");
14
14
  let node_path = require("node:path");
@@ -1442,7 +1442,8 @@ async function createProxy() {
1442
1442
  description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS[require_dex_tool.META_DEX_LOOKUP_TOOL],
1443
1443
  inputSchema: {
1444
1444
  network: NETWORK_SCHEMA,
1445
- name: zod.string().optional().describe("The exchange as the user wrote it: Aero, Aerodrome, uni v4. With no name, every covered exchange is listed."),
1445
+ name: zod.string().optional().describe("The exchange as the user wrote it: Aero, Aerodrome, uni v4. With no name and no address, every covered exchange is listed."),
1446
+ address: zod.string().optional().describe("A contract address (0x plus 40 hex, any case) instead of a name: the exchange whose factory, router or manager it is, with took_for naming the role. Not with name."),
1446
1447
  pools: zod.boolean().optional().describe("Read the biggest pools of the exchange (default true). false sends only Head and the contract reads.")
1447
1448
  },
1448
1449
  annotations: require_dex_tool.META_DEX_LOOKUP_ANNOTATIONS
@@ -6,7 +6,7 @@ import { n as unavailableSubscriptionStatus } from "./subscription-status-DA9DCF
6
6
  import { r as mirrorGraphNetworkCapabilities } from "./capabilities-BBVDIECk.mjs";
7
7
  import { a as handleMetaSchema, c as GRAPH_EXPAND_TITLE, l as GRAPH_EXPAND_TOOL, n as META_SCHEMA_DESCRIPTION, o as FLOWS_MAX_OFFSET, r as META_SCHEMA_TITLE, s as GRAPH_EXPAND_DESCRIPTION, t as GraphSchemaError, u as handleGraphExpand } from "./graph-schema-DqZUTnP0.mjs";
8
8
  import { r as appendActionLog, t as actionLogSignalsFromResult } from "./action-log-D49Par9P.mjs";
9
- import { i as META_DEX_LOOKUP_TOOL, n as META_DEX_LOOKUP_DESCRIPTION, o as handleMetaDexLookup, r as META_DEX_LOOKUP_TITLE, s as withAnswerHintResult, t as META_DEX_LOOKUP_ANNOTATIONS } from "./dex-tool-DpQKS7Te.mjs";
9
+ import { i as META_DEX_LOOKUP_TOOL, n as META_DEX_LOOKUP_DESCRIPTION, o as handleMetaDexLookup, r as META_DEX_LOOKUP_TITLE, s as withAnswerHintResult, t as META_DEX_LOOKUP_ANNOTATIONS } from "./dex-tool-B5Qwz1Zd.mjs";
10
10
  import { r as loadRegistry } from "./dex-registry-05wAhSa0.mjs";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import path from "node:path";
@@ -1438,7 +1438,8 @@ async function createProxy() {
1438
1438
  description: KNOWN_PUBLIC_TOOL_DESCRIPTIONS[META_DEX_LOOKUP_TOOL],
1439
1439
  inputSchema: {
1440
1440
  network: NETWORK_SCHEMA,
1441
- name: z.string().optional().describe("The exchange as the user wrote it: Aero, Aerodrome, uni v4. With no name, every covered exchange is listed."),
1441
+ name: z.string().optional().describe("The exchange as the user wrote it: Aero, Aerodrome, uni v4. With no name and no address, every covered exchange is listed."),
1442
+ address: z.string().optional().describe("A contract address (0x plus 40 hex, any case) instead of a name: the exchange whose factory, router or manager it is, with took_for naming the role. Not with name."),
1442
1443
  pools: z.boolean().optional().describe("Read the biggest pools of the exchange (default true). false sends only Head and the contract reads.")
1443
1444
  },
1444
1445
  annotations: META_DEX_LOOKUP_ANNOTATIONS