@secondlayer/stacks 2.15.0 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/shared/{stacks-tfpspzwd.js → stacks-1x9b2k5y.js} +16 -11
  2. package/dist/shared/{stacks-tfpspzwd.js.map → stacks-1x9b2k5y.js.map} +5 -5
  3. package/dist/shared/{stacks-pperea7f.js → stacks-58e4vbaw.js} +3 -3
  4. package/dist/shared/{stacks-jbmcwky5.js → stacks-905052xe.js} +33 -3
  5. package/dist/shared/{stacks-jbmcwky5.js.map → stacks-905052xe.js.map} +3 -3
  6. package/dist/shared/{stacks-shn9zw99.cjs → stacks-9mqveyjv.cjs} +3 -3
  7. package/dist/shared/stacks-9mqveyjv.cjs.map +10 -0
  8. package/dist/shared/{stacks-1xhz0fbf.cjs → stacks-fvnxj77s.cjs} +13 -8
  9. package/dist/shared/{stacks-1xhz0fbf.cjs.map → stacks-fvnxj77s.cjs.map} +5 -5
  10. package/dist/shared/{stacks-wamwv8q8.cjs → stacks-g2qnr5qn.cjs} +12 -3
  11. package/dist/shared/{stacks-wamwv8q8.cjs.map → stacks-g2qnr5qn.cjs.map} +5 -5
  12. package/dist/shared/{stacks-dmrvk1mz.js → stacks-mbnfwekf.js} +34 -8
  13. package/dist/shared/{stacks-dmrvk1mz.js.map → stacks-mbnfwekf.js.map} +5 -5
  14. package/dist/shared/{stacks-f66v961k.js → stacks-p2c0w0sq.js} +3 -3
  15. package/dist/shared/{stacks-g11v9a35.js → stacks-qchg7s2m.js} +9 -5
  16. package/dist/shared/{stacks-g11v9a35.js.map → stacks-qchg7s2m.js.map} +3 -3
  17. package/dist/shared/{stacks-5nskdw7w.cjs → stacks-qjgh6pqr.cjs} +8 -4
  18. package/dist/shared/{stacks-5nskdw7w.cjs.map → stacks-qjgh6pqr.cjs.map} +3 -3
  19. package/dist/shared/{stacks-jcgvn5v5.cjs → stacks-s361pmzs.cjs} +32 -7
  20. package/dist/shared/{stacks-jcgvn5v5.cjs.map → stacks-s361pmzs.cjs.map} +5 -5
  21. package/dist/shared/{stacks-ssndnbbd.js → stacks-sd9sc71n.js} +13 -4
  22. package/dist/shared/{stacks-ssndnbbd.js.map → stacks-sd9sc71n.js.map} +5 -5
  23. package/dist/shared/{stacks-0tp2dk00.js → stacks-srvk63qq.js} +8 -7
  24. package/dist/shared/stacks-srvk63qq.js.map +10 -0
  25. package/dist/shared/{stacks-b9904rc2.cjs → stacks-v889ttgp.cjs} +37 -2
  26. package/dist/shared/{stacks-b9904rc2.cjs.map → stacks-v889ttgp.cjs.map} +3 -3
  27. package/dist/src/actions/index.d.cts +5 -0
  28. package/dist/src/actions/index.d.ts +5 -0
  29. package/dist/src/actions/index.js +7 -7
  30. package/dist/src/bitcoin/index.js +1 -1
  31. package/dist/src/bns/index.js +5 -5
  32. package/dist/src/clarity/index.d.cts +11 -1
  33. package/dist/src/clarity/index.d.ts +11 -1
  34. package/dist/src/clarity/index.js +12 -2
  35. package/dist/src/clarity/index.js.map +1 -1
  36. package/dist/src/connect/index.cjs +47 -6
  37. package/dist/src/connect/index.cjs.map +8 -4
  38. package/dist/src/connect/index.js +47 -6
  39. package/dist/src/connect/index.js.map +8 -4
  40. package/dist/src/index.cjs +4 -4
  41. package/dist/src/index.cjs.map +3 -3
  42. package/dist/src/index.d.cts +11 -0
  43. package/dist/src/index.d.ts +11 -0
  44. package/dist/src/index.js +11 -10
  45. package/dist/src/index.js.map +3 -3
  46. package/dist/src/pox/index.js +4 -4
  47. package/dist/src/pox5/index.js +3 -3
  48. package/dist/src/sbtc/index.js +4 -4
  49. package/dist/src/stackingdao/index.js +4 -4
  50. package/dist/src/tools/btc/index.cjs +6 -5
  51. package/dist/src/tools/btc/index.cjs.map +3 -3
  52. package/dist/src/tools/btc/index.d.cts +3 -1
  53. package/dist/src/tools/btc/index.d.ts +3 -1
  54. package/dist/src/tools/btc/index.js +6 -5
  55. package/dist/src/tools/btc/index.js.map +3 -3
  56. package/dist/src/tools/index.cjs +339 -45
  57. package/dist/src/tools/index.cjs.map +16 -15
  58. package/dist/src/tools/index.js +339 -48
  59. package/dist/src/tools/index.js.map +16 -15
  60. package/dist/src/transactions/index.d.cts +10 -1
  61. package/dist/src/transactions/index.d.ts +10 -1
  62. package/dist/src/transactions/index.js +2 -2
  63. package/dist/src/x402/index.d.cts +5 -0
  64. package/dist/src/x402/index.d.ts +5 -0
  65. package/dist/src/x402/index.js +4 -4
  66. package/package.json +4 -2
  67. package/dist/shared/stacks-0tp2dk00.js.map +0 -10
  68. package/dist/shared/stacks-shn9zw99.cjs.map +0 -10
  69. /package/dist/shared/{stacks-pperea7f.js.map → stacks-58e4vbaw.js.map} +0 -0
  70. /package/dist/shared/{stacks-f66v961k.js.map → stacks-p2c0w0sq.js.map} +0 -0
@@ -44,7 +44,8 @@ __export(exports_btc, {
44
44
  btcFeeEstimate: () => btcFeeEstimate,
45
45
  btcConfirmations: () => btcConfirmations,
46
46
  btcBlockHeight: () => btcBlockHeight,
47
- btcBalance: () => btcBalance
47
+ btcBalance: () => btcBalance,
48
+ BTC_ADDRESS: () => BTC_ADDRESS
48
49
  });
49
50
  module.exports = __toCommonJS(exports_btc);
50
51
  var import_ai = require("ai");
@@ -65,7 +66,7 @@ async function get(path) {
65
66
  return res.text();
66
67
  }
67
68
  var BTC_TXID = import_zod.z.string().regex(/^[0-9a-fA-F]{64}$/, "64-character hex BTC txid");
68
- var BTC_ADDRESS = import_zod.z.string().describe("Bitcoin address (legacy, segwit, or taproot)");
69
+ var BTC_ADDRESS = import_zod.z.string().regex(/^(1[a-zA-HJ-NP-Z0-9]{25,34}|3[a-zA-HJ-NP-Z0-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{11,71}|tb1[a-zA-HJ-NP-Z0-9]{11,71})$/, { message: "Invalid Bitcoin address" });
69
70
  var btcConfirmations = import_ai.tool({
70
71
  description: "Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.",
71
72
  inputSchema: import_zod.z.object({ txid: BTC_TXID }),
@@ -86,7 +87,7 @@ var btcBalance = import_ai.tool({
86
87
  description: "Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.",
87
88
  inputSchema: import_zod.z.object({ address: BTC_ADDRESS }),
88
89
  execute: async ({ address }) => {
89
- const info = await get(`/api/address/${address}`);
90
+ const info = await get(`/api/address/${encodeURIComponent(address)}`);
90
91
  return {
91
92
  confirmedSat: info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,
92
93
  unconfirmedSat: info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum
@@ -100,7 +101,7 @@ var btcUtxos = import_ai.tool({
100
101
  limit: import_zod.z.number().int().min(1).max(50).default(25)
101
102
  }),
102
103
  execute: async ({ address, limit }) => {
103
- const utxos = await get(`/api/address/${address}/utxo`);
104
+ const utxos = await get(`/api/address/${encodeURIComponent(address)}/utxo`);
104
105
  return { utxos: utxos.slice(0, limit) };
105
106
  }
106
107
  });
@@ -126,5 +127,5 @@ var btcBlockHeight = import_ai.tool({
126
127
  })
127
128
  });
128
129
 
129
- //# debugId=E9A41C992B04F9FD64756E2164756E21
130
+ //# debugId=A9918581E436E21F64756E2164756E21
130
131
  //# sourceMappingURL=index.cjs.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/btc/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Bitcoin read tools for AI SDK tool calls. Useful for sBTC peg-in/peg-out\n * flows, BTC-collateralized lending, and anywhere a Stacks contract's\n * behaviour depends on BTC state.\n *\n * Backed by mempool.space by default. Swap endpoints by setting\n * `BTC_MEMPOOL_URL` in the caller's env. Reads only — no BTC writes.\n *\n * import { generateText } from \"ai\"\n * import { btcConfirmations, btcBalance } from \"@secondlayer/stacks/tools/btc\"\n * await generateText({\n * model: anthropic(\"claude-sonnet-4-6\"),\n * tools: { btcConfirmations, btcBalance },\n * prompt: \"…\",\n * })\n */\n\nimport { type Tool, tool } from \"ai\";\nimport { z } from \"zod\";\n\n// biome-ignore lint/suspicious/noExplicitAny: Tool's input-schema generic too precise for isolated-declarations; AI SDK validates at runtime\ntype LooseTool = Tool<any, any>;\n\nfunction baseUrl(): string {\n\treturn (process.env.BTC_MEMPOOL_URL ?? \"https://mempool.space\").replace(\n\t\t/\\/$/,\n\t\t\"\",\n\t);\n}\n\nasync function get<T>(path: string): Promise<T> {\n\tconst res = await fetch(`${baseUrl()}${path}`, {\n\t\theaders: { Accept: \"application/json\" },\n\t});\n\tif (!res.ok) {\n\t\tthrow new Error(\n\t\t\t`BTC mempool.space ${path} → ${res.status} ${res.statusText}`,\n\t\t);\n\t}\n\tconst contentType = res.headers.get(\"content-type\") ?? \"\";\n\tif (contentType.includes(\"application/json\")) return res.json() as Promise<T>;\n\treturn res.text() as unknown as Promise<T>;\n}\n\nconst BTC_TXID = z\n\t.string()\n\t.regex(/^[0-9a-fA-F]{64}$/, \"64-character hex BTC txid\");\nconst BTC_ADDRESS = z\n\t.string()\n\t.describe(\"Bitcoin address (legacy, segwit, or taproot)\");\n\nexport const btcConfirmations: LooseTool = tool({\n\tdescription:\n\t\t\"Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.\",\n\tinputSchema: z.object({ txid: BTC_TXID }),\n\texecute: async ({ txid }) => {\n\t\tconst tx = await get<{\n\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t}>(`/api/tx/${txid}`);\n\t\tif (!tx.status.confirmed || tx.status.block_height == null) {\n\t\t\treturn { confirmed: false, confirmations: 0 };\n\t\t}\n\t\tconst tip = await get<number>(\"/api/blocks/tip/height\");\n\t\treturn {\n\t\t\tconfirmed: true,\n\t\t\tconfirmations: Math.max(0, tip - tx.status.block_height + 1),\n\t\t\tblockHeight: tx.status.block_height,\n\t\t};\n\t},\n});\n\nexport const btcBalance: LooseTool = tool({\n\tdescription:\n\t\t\"Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.\",\n\tinputSchema: z.object({ address: BTC_ADDRESS }),\n\texecute: async ({ address }) => {\n\t\tconst info = await get<{\n\t\t\tchain_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t\tmempool_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t}>(`/api/address/${address}`);\n\t\treturn {\n\t\t\tconfirmedSat:\n\t\t\t\tinfo.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,\n\t\t\tunconfirmedSat:\n\t\t\t\tinfo.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum,\n\t\t};\n\t},\n});\n\nexport const btcUtxos: LooseTool = tool({\n\tdescription:\n\t\t\"List of unspent outputs for a Bitcoin address (truncated to `limit`).\",\n\tinputSchema: z.object({\n\t\taddress: BTC_ADDRESS,\n\t\tlimit: z.number().int().min(1).max(50).default(25),\n\t}),\n\texecute: async ({ address, limit }) => {\n\t\tconst utxos = await get<\n\t\t\tArray<{\n\t\t\t\ttxid: string;\n\t\t\t\tvout: number;\n\t\t\t\tvalue: number;\n\t\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t\t}>\n\t\t>(`/api/address/${address}/utxo`);\n\t\treturn { utxos: utxos.slice(0, limit) };\n\t},\n});\n\nexport const btcFeeEstimate: LooseTool = tool({\n\tdescription:\n\t\t\"Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).\",\n\tinputSchema: z.object({}),\n\texecute: async () => {\n\t\tconst fees = await get<Record<string, number>>(\"/api/v1/fees/recommended\");\n\t\treturn {\n\t\t\tfastestSatVb: fees.fastestFee ?? 0,\n\t\t\thalfHourSatVb: fees.halfHourFee ?? 0,\n\t\t\thourSatVb: fees.hourFee ?? 0,\n\t\t\teconomySatVb: fees.economyFee ?? 0,\n\t\t\tminimumSatVb: fees.minimumFee ?? 0,\n\t\t};\n\t},\n});\n\nexport const btcBlockHeight: LooseTool = tool({\n\tdescription: \"Current Bitcoin chain tip height.\",\n\tinputSchema: z.object({}),\n\texecute: async () => ({\n\t\theight: await get<number>(\"/api/blocks/tip/height\"),\n\t}),\n});\n"
5
+ "/**\n * Bitcoin read tools for AI SDK tool calls. Useful for sBTC peg-in/peg-out\n * flows, BTC-collateralized lending, and anywhere a Stacks contract's\n * behaviour depends on BTC state.\n *\n * Backed by mempool.space by default. Swap endpoints by setting\n * `BTC_MEMPOOL_URL` in the caller's env. Reads only — no BTC writes.\n *\n * import { generateText } from \"ai\"\n * import { btcConfirmations, btcBalance } from \"@secondlayer/stacks/tools/btc\"\n * await generateText({\n * model: anthropic(\"claude-sonnet-4-6\"),\n * tools: { btcConfirmations, btcBalance },\n * prompt: \"…\",\n * })\n */\n\nimport { type Tool, tool } from \"ai\";\nimport { z } from \"zod\";\n\n// biome-ignore lint/suspicious/noExplicitAny: Tool's input-schema generic too precise for isolated-declarations; AI SDK validates at runtime\ntype LooseTool = Tool<any, any>;\n\nfunction baseUrl(): string {\n\treturn (process.env.BTC_MEMPOOL_URL ?? \"https://mempool.space\").replace(\n\t\t/\\/$/,\n\t\t\"\",\n\t);\n}\n\nasync function get<T>(path: string): Promise<T> {\n\tconst res = await fetch(`${baseUrl()}${path}`, {\n\t\theaders: { Accept: \"application/json\" },\n\t});\n\tif (!res.ok) {\n\t\tthrow new Error(\n\t\t\t`BTC mempool.space ${path} → ${res.status} ${res.statusText}`,\n\t\t);\n\t}\n\tconst contentType = res.headers.get(\"content-type\") ?? \"\";\n\tif (contentType.includes(\"application/json\")) return res.json() as Promise<T>;\n\treturn res.text() as unknown as Promise<T>;\n}\n\nconst BTC_TXID = z\n\t.string()\n\t.regex(/^[0-9a-fA-F]{64}$/, \"64-character hex BTC txid\");\nexport const BTC_ADDRESS: z.ZodString = z\n\t.string()\n\t.regex(\n\t\t/^(1[a-zA-HJ-NP-Z0-9]{25,34}|3[a-zA-HJ-NP-Z0-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{11,71}|tb1[a-zA-HJ-NP-Z0-9]{11,71})$/,\n\t\t{ message: \"Invalid Bitcoin address\" },\n\t);\n\nexport const btcConfirmations: LooseTool = tool({\n\tdescription:\n\t\t\"Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.\",\n\tinputSchema: z.object({ txid: BTC_TXID }),\n\texecute: async ({ txid }) => {\n\t\tconst tx = await get<{\n\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t}>(`/api/tx/${txid}`);\n\t\tif (!tx.status.confirmed || tx.status.block_height == null) {\n\t\t\treturn { confirmed: false, confirmations: 0 };\n\t\t}\n\t\tconst tip = await get<number>(\"/api/blocks/tip/height\");\n\t\treturn {\n\t\t\tconfirmed: true,\n\t\t\tconfirmations: Math.max(0, tip - tx.status.block_height + 1),\n\t\t\tblockHeight: tx.status.block_height,\n\t\t};\n\t},\n});\n\nexport const btcBalance: LooseTool = tool({\n\tdescription:\n\t\t\"Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.\",\n\tinputSchema: z.object({ address: BTC_ADDRESS }),\n\texecute: async ({ address }) => {\n\t\tconst info = await get<{\n\t\t\tchain_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t\tmempool_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t}>(`/api/address/${encodeURIComponent(address)}`);\n\t\treturn {\n\t\t\tconfirmedSat:\n\t\t\t\tinfo.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,\n\t\t\tunconfirmedSat:\n\t\t\t\tinfo.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum,\n\t\t};\n\t},\n});\n\nexport const btcUtxos: LooseTool = tool({\n\tdescription:\n\t\t\"List of unspent outputs for a Bitcoin address (truncated to `limit`).\",\n\tinputSchema: z.object({\n\t\taddress: BTC_ADDRESS,\n\t\tlimit: z.number().int().min(1).max(50).default(25),\n\t}),\n\texecute: async ({ address, limit }) => {\n\t\tconst utxos = await get<\n\t\t\tArray<{\n\t\t\t\ttxid: string;\n\t\t\t\tvout: number;\n\t\t\t\tvalue: number;\n\t\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t\t}>\n\t\t>(`/api/address/${encodeURIComponent(address)}/utxo`);\n\t\treturn { utxos: utxos.slice(0, limit) };\n\t},\n});\n\nexport const btcFeeEstimate: LooseTool = tool({\n\tdescription:\n\t\t\"Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).\",\n\tinputSchema: z.object({}),\n\texecute: async () => {\n\t\tconst fees = await get<Record<string, number>>(\"/api/v1/fees/recommended\");\n\t\treturn {\n\t\t\tfastestSatVb: fees.fastestFee ?? 0,\n\t\t\thalfHourSatVb: fees.halfHourFee ?? 0,\n\t\t\thourSatVb: fees.hourFee ?? 0,\n\t\t\teconomySatVb: fees.economyFee ?? 0,\n\t\t\tminimumSatVb: fees.minimumFee ?? 0,\n\t\t};\n\t},\n});\n\nexport const btcBlockHeight: LooseTool = tool({\n\tdescription: \"Current Bitcoin chain tip height.\",\n\tinputSchema: z.object({}),\n\texecute: async () => ({\n\t\theight: await get<number>(\"/api/blocks/tip/height\"),\n\t}),\n});\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "E9A41C992B04F9FD64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "A9918581E436E21F64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,8 +1,10 @@
1
1
  import { Tool } from "ai";
2
+ import { z } from "zod";
2
3
  type LooseTool = Tool<any, any>;
4
+ declare const BTC_ADDRESS: z.ZodString;
3
5
  declare const btcConfirmations: LooseTool;
4
6
  declare const btcBalance: LooseTool;
5
7
  declare const btcUtxos: LooseTool;
6
8
  declare const btcFeeEstimate: LooseTool;
7
9
  declare const btcBlockHeight: LooseTool;
8
- export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance };
10
+ export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance, BTC_ADDRESS };
@@ -1,8 +1,10 @@
1
1
  import { Tool } from "ai";
2
+ import { z } from "zod";
2
3
  type LooseTool = Tool<any, any>;
4
+ declare const BTC_ADDRESS: z.ZodString;
3
5
  declare const btcConfirmations: LooseTool;
4
6
  declare const btcBalance: LooseTool;
5
7
  declare const btcUtxos: LooseTool;
6
8
  declare const btcFeeEstimate: LooseTool;
7
9
  declare const btcBlockHeight: LooseTool;
8
- export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance };
10
+ export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance, BTC_ADDRESS };
@@ -17,7 +17,7 @@ async function get(path) {
17
17
  return res.text();
18
18
  }
19
19
  var BTC_TXID = z.string().regex(/^[0-9a-fA-F]{64}$/, "64-character hex BTC txid");
20
- var BTC_ADDRESS = z.string().describe("Bitcoin address (legacy, segwit, or taproot)");
20
+ var BTC_ADDRESS = z.string().regex(/^(1[a-zA-HJ-NP-Z0-9]{25,34}|3[a-zA-HJ-NP-Z0-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{11,71}|tb1[a-zA-HJ-NP-Z0-9]{11,71})$/, { message: "Invalid Bitcoin address" });
21
21
  var btcConfirmations = tool({
22
22
  description: "Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.",
23
23
  inputSchema: z.object({ txid: BTC_TXID }),
@@ -38,7 +38,7 @@ var btcBalance = tool({
38
38
  description: "Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.",
39
39
  inputSchema: z.object({ address: BTC_ADDRESS }),
40
40
  execute: async ({ address }) => {
41
- const info = await get(`/api/address/${address}`);
41
+ const info = await get(`/api/address/${encodeURIComponent(address)}`);
42
42
  return {
43
43
  confirmedSat: info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,
44
44
  unconfirmedSat: info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum
@@ -52,7 +52,7 @@ var btcUtxos = tool({
52
52
  limit: z.number().int().min(1).max(50).default(25)
53
53
  }),
54
54
  execute: async ({ address, limit }) => {
55
- const utxos = await get(`/api/address/${address}/utxo`);
55
+ const utxos = await get(`/api/address/${encodeURIComponent(address)}/utxo`);
56
56
  return { utxos: utxos.slice(0, limit) };
57
57
  }
58
58
  });
@@ -82,8 +82,9 @@ export {
82
82
  btcFeeEstimate,
83
83
  btcConfirmations,
84
84
  btcBlockHeight,
85
- btcBalance
85
+ btcBalance,
86
+ BTC_ADDRESS
86
87
  };
87
88
 
88
- //# debugId=F2DF8EAD15141CD864756E2164756E21
89
+ //# debugId=E811F99F534F2FE364756E2164756E21
89
90
  //# sourceMappingURL=index.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/btc/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Bitcoin read tools for AI SDK tool calls. Useful for sBTC peg-in/peg-out\n * flows, BTC-collateralized lending, and anywhere a Stacks contract's\n * behaviour depends on BTC state.\n *\n * Backed by mempool.space by default. Swap endpoints by setting\n * `BTC_MEMPOOL_URL` in the caller's env. Reads only — no BTC writes.\n *\n * import { generateText } from \"ai\"\n * import { btcConfirmations, btcBalance } from \"@secondlayer/stacks/tools/btc\"\n * await generateText({\n * model: anthropic(\"claude-sonnet-4-6\"),\n * tools: { btcConfirmations, btcBalance },\n * prompt: \"…\",\n * })\n */\n\nimport { type Tool, tool } from \"ai\";\nimport { z } from \"zod\";\n\n// biome-ignore lint/suspicious/noExplicitAny: Tool's input-schema generic too precise for isolated-declarations; AI SDK validates at runtime\ntype LooseTool = Tool<any, any>;\n\nfunction baseUrl(): string {\n\treturn (process.env.BTC_MEMPOOL_URL ?? \"https://mempool.space\").replace(\n\t\t/\\/$/,\n\t\t\"\",\n\t);\n}\n\nasync function get<T>(path: string): Promise<T> {\n\tconst res = await fetch(`${baseUrl()}${path}`, {\n\t\theaders: { Accept: \"application/json\" },\n\t});\n\tif (!res.ok) {\n\t\tthrow new Error(\n\t\t\t`BTC mempool.space ${path} → ${res.status} ${res.statusText}`,\n\t\t);\n\t}\n\tconst contentType = res.headers.get(\"content-type\") ?? \"\";\n\tif (contentType.includes(\"application/json\")) return res.json() as Promise<T>;\n\treturn res.text() as unknown as Promise<T>;\n}\n\nconst BTC_TXID = z\n\t.string()\n\t.regex(/^[0-9a-fA-F]{64}$/, \"64-character hex BTC txid\");\nconst BTC_ADDRESS = z\n\t.string()\n\t.describe(\"Bitcoin address (legacy, segwit, or taproot)\");\n\nexport const btcConfirmations: LooseTool = tool({\n\tdescription:\n\t\t\"Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.\",\n\tinputSchema: z.object({ txid: BTC_TXID }),\n\texecute: async ({ txid }) => {\n\t\tconst tx = await get<{\n\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t}>(`/api/tx/${txid}`);\n\t\tif (!tx.status.confirmed || tx.status.block_height == null) {\n\t\t\treturn { confirmed: false, confirmations: 0 };\n\t\t}\n\t\tconst tip = await get<number>(\"/api/blocks/tip/height\");\n\t\treturn {\n\t\t\tconfirmed: true,\n\t\t\tconfirmations: Math.max(0, tip - tx.status.block_height + 1),\n\t\t\tblockHeight: tx.status.block_height,\n\t\t};\n\t},\n});\n\nexport const btcBalance: LooseTool = tool({\n\tdescription:\n\t\t\"Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.\",\n\tinputSchema: z.object({ address: BTC_ADDRESS }),\n\texecute: async ({ address }) => {\n\t\tconst info = await get<{\n\t\t\tchain_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t\tmempool_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t}>(`/api/address/${address}`);\n\t\treturn {\n\t\t\tconfirmedSat:\n\t\t\t\tinfo.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,\n\t\t\tunconfirmedSat:\n\t\t\t\tinfo.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum,\n\t\t};\n\t},\n});\n\nexport const btcUtxos: LooseTool = tool({\n\tdescription:\n\t\t\"List of unspent outputs for a Bitcoin address (truncated to `limit`).\",\n\tinputSchema: z.object({\n\t\taddress: BTC_ADDRESS,\n\t\tlimit: z.number().int().min(1).max(50).default(25),\n\t}),\n\texecute: async ({ address, limit }) => {\n\t\tconst utxos = await get<\n\t\t\tArray<{\n\t\t\t\ttxid: string;\n\t\t\t\tvout: number;\n\t\t\t\tvalue: number;\n\t\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t\t}>\n\t\t>(`/api/address/${address}/utxo`);\n\t\treturn { utxos: utxos.slice(0, limit) };\n\t},\n});\n\nexport const btcFeeEstimate: LooseTool = tool({\n\tdescription:\n\t\t\"Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).\",\n\tinputSchema: z.object({}),\n\texecute: async () => {\n\t\tconst fees = await get<Record<string, number>>(\"/api/v1/fees/recommended\");\n\t\treturn {\n\t\t\tfastestSatVb: fees.fastestFee ?? 0,\n\t\t\thalfHourSatVb: fees.halfHourFee ?? 0,\n\t\t\thourSatVb: fees.hourFee ?? 0,\n\t\t\teconomySatVb: fees.economyFee ?? 0,\n\t\t\tminimumSatVb: fees.minimumFee ?? 0,\n\t\t};\n\t},\n});\n\nexport const btcBlockHeight: LooseTool = tool({\n\tdescription: \"Current Bitcoin chain tip height.\",\n\tinputSchema: z.object({}),\n\texecute: async () => ({\n\t\theight: await get<number>(\"/api/blocks/tip/height\"),\n\t}),\n});\n"
5
+ "/**\n * Bitcoin read tools for AI SDK tool calls. Useful for sBTC peg-in/peg-out\n * flows, BTC-collateralized lending, and anywhere a Stacks contract's\n * behaviour depends on BTC state.\n *\n * Backed by mempool.space by default. Swap endpoints by setting\n * `BTC_MEMPOOL_URL` in the caller's env. Reads only — no BTC writes.\n *\n * import { generateText } from \"ai\"\n * import { btcConfirmations, btcBalance } from \"@secondlayer/stacks/tools/btc\"\n * await generateText({\n * model: anthropic(\"claude-sonnet-4-6\"),\n * tools: { btcConfirmations, btcBalance },\n * prompt: \"…\",\n * })\n */\n\nimport { type Tool, tool } from \"ai\";\nimport { z } from \"zod\";\n\n// biome-ignore lint/suspicious/noExplicitAny: Tool's input-schema generic too precise for isolated-declarations; AI SDK validates at runtime\ntype LooseTool = Tool<any, any>;\n\nfunction baseUrl(): string {\n\treturn (process.env.BTC_MEMPOOL_URL ?? \"https://mempool.space\").replace(\n\t\t/\\/$/,\n\t\t\"\",\n\t);\n}\n\nasync function get<T>(path: string): Promise<T> {\n\tconst res = await fetch(`${baseUrl()}${path}`, {\n\t\theaders: { Accept: \"application/json\" },\n\t});\n\tif (!res.ok) {\n\t\tthrow new Error(\n\t\t\t`BTC mempool.space ${path} → ${res.status} ${res.statusText}`,\n\t\t);\n\t}\n\tconst contentType = res.headers.get(\"content-type\") ?? \"\";\n\tif (contentType.includes(\"application/json\")) return res.json() as Promise<T>;\n\treturn res.text() as unknown as Promise<T>;\n}\n\nconst BTC_TXID = z\n\t.string()\n\t.regex(/^[0-9a-fA-F]{64}$/, \"64-character hex BTC txid\");\nexport const BTC_ADDRESS: z.ZodString = z\n\t.string()\n\t.regex(\n\t\t/^(1[a-zA-HJ-NP-Z0-9]{25,34}|3[a-zA-HJ-NP-Z0-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{11,71}|tb1[a-zA-HJ-NP-Z0-9]{11,71})$/,\n\t\t{ message: \"Invalid Bitcoin address\" },\n\t);\n\nexport const btcConfirmations: LooseTool = tool({\n\tdescription:\n\t\t\"Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.\",\n\tinputSchema: z.object({ txid: BTC_TXID }),\n\texecute: async ({ txid }) => {\n\t\tconst tx = await get<{\n\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t}>(`/api/tx/${txid}`);\n\t\tif (!tx.status.confirmed || tx.status.block_height == null) {\n\t\t\treturn { confirmed: false, confirmations: 0 };\n\t\t}\n\t\tconst tip = await get<number>(\"/api/blocks/tip/height\");\n\t\treturn {\n\t\t\tconfirmed: true,\n\t\t\tconfirmations: Math.max(0, tip - tx.status.block_height + 1),\n\t\t\tblockHeight: tx.status.block_height,\n\t\t};\n\t},\n});\n\nexport const btcBalance: LooseTool = tool({\n\tdescription:\n\t\t\"Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.\",\n\tinputSchema: z.object({ address: BTC_ADDRESS }),\n\texecute: async ({ address }) => {\n\t\tconst info = await get<{\n\t\t\tchain_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t\tmempool_stats: { funded_txo_sum: number; spent_txo_sum: number };\n\t\t}>(`/api/address/${encodeURIComponent(address)}`);\n\t\treturn {\n\t\t\tconfirmedSat:\n\t\t\t\tinfo.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,\n\t\t\tunconfirmedSat:\n\t\t\t\tinfo.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum,\n\t\t};\n\t},\n});\n\nexport const btcUtxos: LooseTool = tool({\n\tdescription:\n\t\t\"List of unspent outputs for a Bitcoin address (truncated to `limit`).\",\n\tinputSchema: z.object({\n\t\taddress: BTC_ADDRESS,\n\t\tlimit: z.number().int().min(1).max(50).default(25),\n\t}),\n\texecute: async ({ address, limit }) => {\n\t\tconst utxos = await get<\n\t\t\tArray<{\n\t\t\t\ttxid: string;\n\t\t\t\tvout: number;\n\t\t\t\tvalue: number;\n\t\t\t\tstatus: { confirmed: boolean; block_height?: number };\n\t\t\t}>\n\t\t>(`/api/address/${encodeURIComponent(address)}/utxo`);\n\t\treturn { utxos: utxos.slice(0, limit) };\n\t},\n});\n\nexport const btcFeeEstimate: LooseTool = tool({\n\tdescription:\n\t\t\"Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).\",\n\tinputSchema: z.object({}),\n\texecute: async () => {\n\t\tconst fees = await get<Record<string, number>>(\"/api/v1/fees/recommended\");\n\t\treturn {\n\t\t\tfastestSatVb: fees.fastestFee ?? 0,\n\t\t\thalfHourSatVb: fees.halfHourFee ?? 0,\n\t\t\thourSatVb: fees.hourFee ?? 0,\n\t\t\teconomySatVb: fees.economyFee ?? 0,\n\t\t\tminimumSatVb: fees.minimumFee ?? 0,\n\t\t};\n\t},\n});\n\nexport const btcBlockHeight: LooseTool = tool({\n\tdescription: \"Current Bitcoin chain tip height.\",\n\tinputSchema: z.object({}),\n\texecute: async () => ({\n\t\theight: await get<number>(\"/api/blocks/tip/height\"),\n\t}),\n});\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "F2DF8EAD15141CD864756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "E811F99F534F2FE364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -58,6 +58,37 @@ module.exports = __toCommonJS(exports_tools);
58
58
  var import_ai = require("ai");
59
59
  var import_zod = require("zod");
60
60
 
61
+ // src/errors/base.ts
62
+ class BaseError extends Error {
63
+ name = "StacksError";
64
+ shortMessage;
65
+ details;
66
+ constructor(shortMessage, options) {
67
+ const message = [
68
+ shortMessage,
69
+ options?.details ? `
70
+ ${options.details}` : ""
71
+ ].join("");
72
+ super(message, { cause: options?.cause });
73
+ this.shortMessage = shortMessage;
74
+ this.details = options?.details;
75
+ }
76
+ toJSON() {
77
+ return {
78
+ name: this.name,
79
+ message: this.message,
80
+ shortMessage: this.shortMessage,
81
+ details: this.details,
82
+ cause: this.cause instanceof Error ? this.cause.message : undefined
83
+ };
84
+ }
85
+ }
86
+
87
+ // src/errors/response.ts
88
+ class MalformedResponseError extends BaseError {
89
+ name = "MalformedResponseError";
90
+ }
91
+
61
92
  // src/utils/c32.ts
62
93
  var import_sha2 = require("@noble/hashes/sha2.js");
63
94
 
@@ -471,6 +502,9 @@ var AssetType = {
471
502
  };
472
503
  var RECOVERABLE_ECDSA_SIG_LENGTH_BYTES = 65;
473
504
  var MEMO_MAX_LENGTH_BYTES = 34;
505
+ var COINBASE_BYTES_LENGTH = 32;
506
+ var VRF_PROOF_BYTES_LENGTH = 80;
507
+ var MICROBLOCK_HEADER_BYTES_LENGTH = 132;
474
508
 
475
509
  // src/transactions/wire/serialize.ts
476
510
  function serializeAddress2(c32Address) {
@@ -651,11 +685,23 @@ function serializePayload(payload) {
651
685
  }
652
686
  return concatBytes(...parts);
653
687
  }
688
+ var _txCache = new WeakMap;
689
+ function clearTxCache(tx) {
690
+ _txCache.delete(tx);
691
+ }
654
692
  function serializeTransaction(tx) {
655
- return concatBytes(writeUInt8(tx.version), writeUInt32BE(tx.chainId), serializeAuthorization(tx.auth), writeUInt8(tx.anchorMode), writeUInt8(tx.postConditionMode), serializePostConditions(tx.postConditions), serializePayload(tx.payload));
693
+ const cached = _txCache.get(tx);
694
+ if (cached)
695
+ return cached;
696
+ const bytes = concatBytes(writeUInt8(tx.version), writeUInt32BE(tx.chainId), serializeAuthorization(tx.auth), writeUInt8(tx.anchorMode), writeUInt8(tx.postConditionMode), serializePostConditions(tx.postConditions), serializePayload(tx.payload));
697
+ _txCache.set(tx, bytes);
698
+ return bytes;
656
699
  }
657
700
 
658
701
  // src/actions/public/estimateFee.ts
702
+ function isValidEstimation(e) {
703
+ return typeof e === "object" && e !== null && "fee_rate" in e && "fee" in e && (typeof e.fee_rate === "number" || typeof e.fee_rate === "string") && (typeof e.fee === "number" || typeof e.fee === "string");
704
+ }
659
705
  async function estimateFee(client, params) {
660
706
  const payloadHex = bytesToHex(serializePayload(params.transaction.payload));
661
707
  const txHex = bytesToHex(serializeTransaction(params.transaction));
@@ -666,10 +712,16 @@ async function estimateFee(client, params) {
666
712
  transaction_payload: `0x${payloadHex}`
667
713
  }
668
714
  });
669
- return (data.estimations ?? []).map((e) => ({
670
- feeRate: e.fee_rate,
671
- fee: e.fee
672
- }));
715
+ const raw = data?.estimations ?? [];
716
+ return raw.map((e) => {
717
+ if (!isValidEstimation(e)) {
718
+ throw new MalformedResponseError("estimateFee: node response contains invalid fee estimation entry");
719
+ }
720
+ return {
721
+ feeRate: Number(e.fee_rate),
722
+ fee: Number(e.fee)
723
+ };
724
+ });
673
725
  }
674
726
 
675
727
  // src/actions/public/getAccountHistory.ts
@@ -678,48 +730,19 @@ async function getAccountHistory(client, params) {
678
730
  return client.request(`/extended/v2/addresses/${params.address}/transactions?limit=${limit}`, { method: "GET" });
679
731
  }
680
732
 
681
- // src/errors/base.ts
682
- class BaseError extends Error {
683
- name = "StacksError";
684
- shortMessage;
685
- details;
686
- constructor(shortMessage, options) {
687
- const message = [
688
- shortMessage,
689
- options?.details ? `
690
- ${options.details}` : ""
691
- ].join("");
692
- super(message, { cause: options?.cause });
693
- this.shortMessage = shortMessage;
694
- this.details = options?.details;
695
- }
696
- toJSON() {
697
- return {
698
- name: this.name,
699
- message: this.message,
700
- shortMessage: this.shortMessage,
701
- details: this.details,
702
- cause: this.cause instanceof Error ? this.cause.message : undefined
703
- };
704
- }
705
- }
706
-
707
- // src/errors/response.ts
708
- class MalformedResponseError extends BaseError {
709
- name = "MalformedResponseError";
710
- }
711
-
712
733
  // src/actions/public/getAccountInfo.ts
713
734
  async function getAccountInfo(client, params) {
714
735
  const data = await client.request(`/v2/accounts/${params.address}?proof=1`, {
715
736
  method: "GET"
716
737
  });
717
- if (data?.balance === undefined || data?.nonce === undefined) {
738
+ const balance = data?.balance;
739
+ const nonce = data?.nonce;
740
+ if (typeof balance !== "string" && typeof balance !== "number" || typeof nonce !== "string" && typeof nonce !== "number") {
718
741
  throw new MalformedResponseError(`getAccountInfo: /v2/accounts/${params.address} response is missing "balance" or "nonce"`);
719
742
  }
720
743
  return {
721
- balance: BigInt(data.balance),
722
- nonce: BigInt(data.nonce),
744
+ balance: BigInt(balance),
745
+ nonce: BigInt(nonce),
723
746
  balanceProof: data.balance_proof ?? "",
724
747
  nonceProof: data.nonce_proof ?? ""
725
748
  };
@@ -730,10 +753,11 @@ async function getBalance(client, params) {
730
753
  const data = await client.request(`/v2/accounts/${params.address}`, {
731
754
  method: "GET"
732
755
  });
733
- if (data?.balance === undefined) {
756
+ const balance = data?.balance;
757
+ if (typeof balance !== "string" && typeof balance !== "number") {
734
758
  throw new MalformedResponseError(`getBalance: /v2/accounts/${params.address} response is missing "balance"`);
735
759
  }
736
- return BigInt(data.balance);
760
+ return BigInt(balance);
737
761
  }
738
762
 
739
763
  // src/actions/public/getBlock.ts
@@ -1797,6 +1821,7 @@ async function resolveFee(client, transaction, fee) {
1797
1821
  }
1798
1822
  function setUnsignedFee(transaction, fee) {
1799
1823
  transaction.auth.spendingCondition.fee = fee;
1824
+ clearTxCache(transaction);
1800
1825
  }
1801
1826
  function assertNoFeeTierForProvider(fee) {
1802
1827
  if (isFeeTier(fee)) {
@@ -1940,7 +1965,7 @@ function getContract(params) {
1940
1965
  });
1941
1966
  const mid = estimates[1] ?? estimates[0];
1942
1967
  if (mid) {
1943
- unsigned.auth.spendingCondition.fee = BigInt(mid.fee);
1968
+ setUnsignedFee(unsigned, BigInt(mid.fee));
1944
1969
  }
1945
1970
  }
1946
1971
  return unsigned;
@@ -2543,6 +2568,262 @@ async function getPrimaryName(client, address) {
2543
2568
  }
2544
2569
  }
2545
2570
 
2571
+ // src/transactions/wire/deserialize.ts
2572
+ function readSpendingCondition(r) {
2573
+ const hashMode = r.readUInt8();
2574
+ const signer = bytesToHex(r.readBytes(20));
2575
+ const nonce = r.readBigUInt64BE();
2576
+ const fee = r.readBigUInt64BE();
2577
+ if (hashMode === AddressHashMode.P2PKH || hashMode === AddressHashMode.P2WPKH) {
2578
+ const keyEncoding = r.readUInt8();
2579
+ const signature = bytesToHex(r.readBytes(RECOVERABLE_ECDSA_SIG_LENGTH_BYTES));
2580
+ return {
2581
+ hashMode,
2582
+ signer,
2583
+ nonce,
2584
+ fee,
2585
+ keyEncoding,
2586
+ signature
2587
+ };
2588
+ }
2589
+ const fieldCount = r.readUInt32BE();
2590
+ const fields = [];
2591
+ for (let i = 0;i < fieldCount; i++) {
2592
+ const fieldType = r.readUInt8();
2593
+ if (fieldType <= 1) {
2594
+ const keyLen = fieldType === 0 ? 33 : 65;
2595
+ fields.push({
2596
+ type: "publicKey",
2597
+ pubKeyEncoding: fieldType,
2598
+ data: bytesToHex(r.readBytes(keyLen))
2599
+ });
2600
+ } else {
2601
+ fields.push({
2602
+ type: "signature",
2603
+ pubKeyEncoding: fieldType === 2 ? 0 : 1,
2604
+ data: bytesToHex(r.readBytes(RECOVERABLE_ECDSA_SIG_LENGTH_BYTES))
2605
+ });
2606
+ }
2607
+ }
2608
+ const signaturesRequired = r.readUInt16BE();
2609
+ return {
2610
+ hashMode,
2611
+ signer,
2612
+ nonce,
2613
+ fee,
2614
+ fields,
2615
+ signaturesRequired
2616
+ };
2617
+ }
2618
+ function readAuthorization(r) {
2619
+ const authType = r.readUInt8();
2620
+ const spendingCondition = readSpendingCondition(r);
2621
+ if (authType === AuthType.Standard) {
2622
+ return { authType: AuthType.Standard, spendingCondition };
2623
+ }
2624
+ const sponsorSpendingCondition = readSpendingCondition(r);
2625
+ return {
2626
+ authType: AuthType.Sponsored,
2627
+ spendingCondition,
2628
+ sponsorSpendingCondition
2629
+ };
2630
+ }
2631
+ function readAssetInfo(r) {
2632
+ return {
2633
+ address: readAddress(r),
2634
+ contractName: readLPString(r),
2635
+ assetName: readLPString(r)
2636
+ };
2637
+ }
2638
+ function readPostConditionPrincipal(r) {
2639
+ const type = r.readUInt8();
2640
+ switch (type) {
2641
+ case PostConditionPrincipalId.Origin:
2642
+ return { type: "origin" };
2643
+ case PostConditionPrincipalId.Standard:
2644
+ return { type: "standard", address: readAddress(r) };
2645
+ case PostConditionPrincipalId.Contract:
2646
+ return {
2647
+ type: "contract",
2648
+ address: readAddress(r),
2649
+ contractName: readLPString(r)
2650
+ };
2651
+ default:
2652
+ return { type: "origin" };
2653
+ }
2654
+ }
2655
+ function readPostConditions(r) {
2656
+ const count = r.readUInt32BE();
2657
+ const pcs = [];
2658
+ for (let i = 0;i < count; i++) {
2659
+ const assetType = r.readUInt8();
2660
+ const principal = readPostConditionPrincipal(r);
2661
+ switch (assetType) {
2662
+ case AssetType.STX:
2663
+ pcs.push({
2664
+ type: "stx",
2665
+ principal,
2666
+ conditionCode: r.readUInt8(),
2667
+ amount: r.readBigUInt64BE()
2668
+ });
2669
+ break;
2670
+ case AssetType.Fungible:
2671
+ pcs.push({
2672
+ type: "ft",
2673
+ principal,
2674
+ asset: readAssetInfo(r),
2675
+ conditionCode: r.readUInt8(),
2676
+ amount: r.readBigUInt64BE()
2677
+ });
2678
+ break;
2679
+ case AssetType.NonFungible:
2680
+ pcs.push({
2681
+ type: "nft",
2682
+ principal,
2683
+ asset: readAssetInfo(r),
2684
+ assetId: readCV(r),
2685
+ conditionCode: r.readUInt8()
2686
+ });
2687
+ break;
2688
+ case AssetType.Staking:
2689
+ pcs.push({
2690
+ type: "staking",
2691
+ principal,
2692
+ conditionCode: r.readUInt8(),
2693
+ amount: r.readBigUInt64BE()
2694
+ });
2695
+ break;
2696
+ case AssetType.Pox:
2697
+ pcs.push({
2698
+ type: "pox",
2699
+ principal,
2700
+ conditionCode: r.readUInt8()
2701
+ });
2702
+ break;
2703
+ default:
2704
+ throw new Error(`Unknown post-condition asset type: 0x${assetType.toString(16).padStart(2, "0")} (post-condition ${i + 1}/${count})`);
2705
+ }
2706
+ }
2707
+ return pcs;
2708
+ }
2709
+ function readPayload(r) {
2710
+ const payloadType = r.readUInt8();
2711
+ switch (payloadType) {
2712
+ case PayloadType.TokenTransfer: {
2713
+ const recipient = readCV(r);
2714
+ const amount = r.readBigUInt64BE();
2715
+ const memoBytes = r.readBytes(MEMO_MAX_LENGTH_BYTES);
2716
+ const memo = bytesToAscii(memoBytes).replace(/\0+$/, "");
2717
+ return {
2718
+ payloadType: PayloadType.TokenTransfer,
2719
+ recipient,
2720
+ amount,
2721
+ memo
2722
+ };
2723
+ }
2724
+ case PayloadType.ContractCall: {
2725
+ const contractAddress = readAddress(r);
2726
+ const contractName = readLPString(r);
2727
+ const functionName = readLPString(r);
2728
+ const numArgs = r.readUInt32BE();
2729
+ const functionArgs = [];
2730
+ for (let i = 0;i < numArgs; i++)
2731
+ functionArgs.push(readCV(r));
2732
+ return {
2733
+ payloadType: PayloadType.ContractCall,
2734
+ contractAddress,
2735
+ contractName,
2736
+ functionName,
2737
+ functionArgs
2738
+ };
2739
+ }
2740
+ case PayloadType.SmartContract: {
2741
+ const contractName = readLPString(r);
2742
+ const codeBody = readLPString(r, 4);
2743
+ return { payloadType: PayloadType.SmartContract, contractName, codeBody };
2744
+ }
2745
+ case PayloadType.VersionedSmartContract: {
2746
+ const clarityVersion = r.readUInt8();
2747
+ const contractName = readLPString(r);
2748
+ const codeBody = readLPString(r, 4);
2749
+ return {
2750
+ payloadType: PayloadType.VersionedSmartContract,
2751
+ clarityVersion,
2752
+ contractName,
2753
+ codeBody
2754
+ };
2755
+ }
2756
+ case PayloadType.Coinbase: {
2757
+ const coinbaseBuffer = bytesToHex(r.readBytes(COINBASE_BYTES_LENGTH));
2758
+ return { payloadType: PayloadType.Coinbase, coinbaseBuffer };
2759
+ }
2760
+ case PayloadType.CoinbaseToAltRecipient: {
2761
+ const coinbaseBuffer = bytesToHex(r.readBytes(COINBASE_BYTES_LENGTH));
2762
+ const recipient = readCV(r);
2763
+ return {
2764
+ payloadType: PayloadType.CoinbaseToAltRecipient,
2765
+ coinbaseBuffer,
2766
+ recipient
2767
+ };
2768
+ }
2769
+ case PayloadType.PoisonMicroblock: {
2770
+ const header1 = bytesToHex(r.readBytes(MICROBLOCK_HEADER_BYTES_LENGTH));
2771
+ const header2 = bytesToHex(r.readBytes(MICROBLOCK_HEADER_BYTES_LENGTH));
2772
+ return { payloadType: PayloadType.PoisonMicroblock, header1, header2 };
2773
+ }
2774
+ case PayloadType.TenureChange: {
2775
+ const tenureConsensusHash = bytesToHex(r.readBytes(20));
2776
+ const prevTenureConsensusHash = bytesToHex(r.readBytes(20));
2777
+ const burnViewConsensusHash = bytesToHex(r.readBytes(20));
2778
+ const previousTenureEnd = bytesToHex(r.readBytes(32));
2779
+ const previousTenureBlocks = r.readUInt32BE();
2780
+ const cause = r.readUInt8();
2781
+ const pubkeyHash = bytesToHex(r.readBytes(20));
2782
+ return {
2783
+ payloadType: PayloadType.TenureChange,
2784
+ tenureConsensusHash,
2785
+ prevTenureConsensusHash,
2786
+ burnViewConsensusHash,
2787
+ previousTenureEnd,
2788
+ previousTenureBlocks,
2789
+ cause,
2790
+ pubkeyHash
2791
+ };
2792
+ }
2793
+ case PayloadType.NakamotoCoinbase: {
2794
+ const coinbaseBuffer = bytesToHex(r.readBytes(COINBASE_BYTES_LENGTH));
2795
+ const optionalCV = readCV(r);
2796
+ const recipient = optionalCV.type === "none" ? null : optionalCV.type === "some" ? optionalCV.value : optionalCV;
2797
+ const vrfProof = bytesToHex(r.readBytes(VRF_PROOF_BYTES_LENGTH));
2798
+ return {
2799
+ payloadType: PayloadType.NakamotoCoinbase,
2800
+ coinbaseBuffer,
2801
+ recipient,
2802
+ vrfProof
2803
+ };
2804
+ }
2805
+ default:
2806
+ throw new Error(`Unknown payload type: ${payloadType}`);
2807
+ }
2808
+ }
2809
+ function deserializeTransaction(input, meta) {
2810
+ const bytes = typeof input === "string" ? hexToBytes(without0x(input)) : input;
2811
+ const r = new BytesReader(bytes);
2812
+ const tx = {
2813
+ version: r.readUInt8(),
2814
+ chainId: r.readUInt32BE(),
2815
+ auth: readAuthorization(r),
2816
+ anchorMode: r.readUInt8(),
2817
+ postConditionMode: r.readUInt8(),
2818
+ postConditions: readPostConditions(r),
2819
+ payload: readPayload(r)
2820
+ };
2821
+ if (meta?._multisig) {
2822
+ tx._multisig = meta._multisig;
2823
+ }
2824
+ return tx;
2825
+ }
2826
+
2546
2827
  // src/chains/definitions.ts
2547
2828
  var mainnet = {
2548
2829
  id: 1,
@@ -2985,11 +3266,24 @@ async function contractRead(client, args) {
2985
3266
  const result = await readContract(client, args);
2986
3267
  return { result: JSON.stringify(result) };
2987
3268
  }
3269
+ function assertValidHex(raw) {
3270
+ if (raw.length % 2 !== 0) {
3271
+ throw new Error("serializedTxHex: odd-length hex string");
3272
+ }
3273
+ if (!/^[0-9a-fA-F]+$/.test(raw)) {
3274
+ throw new Error("serializedTxHex: contains non-hex characters");
3275
+ }
3276
+ }
2988
3277
  async function fee(client, serializedTxHex) {
2989
3278
  const raw = serializedTxHex.startsWith("0x") ? serializedTxHex.slice(2) : serializedTxHex;
3279
+ assertValidHex(raw);
2990
3280
  const txBytes = new Uint8Array(Buffer.from(raw, "hex"));
2991
- const { deserializeTransaction } = await import("@stacks/transactions");
2992
- const transaction = deserializeTransaction(txBytes);
3281
+ let transaction;
3282
+ try {
3283
+ transaction = deserializeTransaction(txBytes);
3284
+ } catch (e) {
3285
+ throw new Error(`serializedTxHex: deserialization failed — ${e instanceof Error ? e.message : String(e)}`);
3286
+ }
2993
3287
  const fees = await estimateFee(client, {
2994
3288
  transaction
2995
3289
  });
@@ -3174,5 +3468,5 @@ var getNftHoldings2 = import_ai.tool({
3174
3468
  execute: ({ principal, limit }) => nftHoldings(getDefaultPublicClient(), principal, limit)
3175
3469
  });
3176
3470
 
3177
- //# debugId=726789478731037064756E2164756E21
3471
+ //# debugId=0CE36B45A67DEB3C64756E2164756E21
3178
3472
  //# sourceMappingURL=index.cjs.map