@secondlayer/stacks 5.1.3 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -8
- package/package.json +3 -23
- package/dist/src/tools/btc/index.cjs +0 -131
- package/dist/src/tools/btc/index.cjs.map +0 -10
- package/dist/src/tools/btc/index.d.cts +0 -10
- package/dist/src/tools/btc/index.d.ts +0 -10
- package/dist/src/tools/btc/index.js +0 -90
- package/dist/src/tools/btc/index.js.map +0 -10
- package/dist/src/tools/index.cjs +0 -3865
- package/dist/src/tools/index.cjs.map +0 -80
- package/dist/src/tools/index.d.cts +0 -206
- package/dist/src/tools/index.d.ts +0 -206
- package/dist/src/tools/index.js +0 -3827
- package/dist/src/tools/index.js.map +0 -80
package/README.md
CHANGED
|
@@ -64,14 +64,7 @@ multi-broadcast gap, which is why it lives here rather than being deferred to
|
|
|
64
64
|
| `@secondlayer/stacks/pox` | PoX stacking — solo and delegated |
|
|
65
65
|
| `@secondlayer/stacks/stackingdao` | StackingDAO liquid staking (STX/stSTX) |
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Give your agent Stacks reads through [`@secondlayer/mcp`](https://www.npmjs.com/package/@secondlayer/mcp) instead. The two AI SDK tool entries below still import, and stay until the next major, but they get no new tools. The tradeoff of keeping them: `ai` and `zod` are now optional peer dependencies, so a project that imports either entry installs both itself; a project that only reads contracts installs neither.
|
|
70
|
-
|
|
71
|
-
| Module | Description |
|
|
72
|
-
|---|---|
|
|
73
|
-
| `@secondlayer/stacks/tools` | **Deprecated.** AI SDK `tool()` set for Stacks reads. Bare exports read `STACKS_NETWORK` (or `STACKS_CHAIN`) and `STACKS_NODE_RPC_URL`, `SL_API_URL` or `STACKS_RPC_URL`; `createStacksTools(client)` binds your own client |
|
|
74
|
-
| `@secondlayer/stacks/tools/btc` | **Deprecated.** AI SDK `tool()` set for Bitcoin reads via mempool.space (`BTC_MEMPOOL_URL` overrides the host) |
|
|
67
|
+
Agent Stacks reads go through [`@secondlayer/mcp`](https://www.npmjs.com/package/@secondlayer/mcp).
|
|
75
68
|
|
|
76
69
|
## Guides
|
|
77
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@secondlayer/stacks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Typed Stacks client for TypeScript: read contracts, decode Clarity, build and send transactions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -99,16 +99,6 @@
|
|
|
99
99
|
"import": "./dist/src/connect/walletconnect/index.js",
|
|
100
100
|
"require": "./dist/src/connect/walletconnect/index.cjs"
|
|
101
101
|
},
|
|
102
|
-
"./tools": {
|
|
103
|
-
"types": "./dist/src/tools/index.d.ts",
|
|
104
|
-
"import": "./dist/src/tools/index.js",
|
|
105
|
-
"require": "./dist/src/tools/index.cjs"
|
|
106
|
-
},
|
|
107
|
-
"./tools/btc": {
|
|
108
|
-
"types": "./dist/src/tools/btc/index.d.ts",
|
|
109
|
-
"import": "./dist/src/tools/btc/index.js",
|
|
110
|
-
"require": "./dist/src/tools/btc/index.cjs"
|
|
111
|
-
},
|
|
112
102
|
"./filters": {
|
|
113
103
|
"types": "./dist/src/filters/index.d.ts",
|
|
114
104
|
"import": "./dist/src/filters/index.js",
|
|
@@ -133,16 +123,12 @@
|
|
|
133
123
|
"devDependencies": {
|
|
134
124
|
"@stacks/clarinet-sdk": "3.21.1",
|
|
135
125
|
"@stacks/transactions": "7.0.6",
|
|
136
|
-
"@types/bun": "latest"
|
|
137
|
-
"ai": "6.0.167",
|
|
138
|
-
"zod": "^4.3.6"
|
|
126
|
+
"@types/bun": "latest"
|
|
139
127
|
},
|
|
140
128
|
"peerDependencies": {
|
|
141
129
|
"@stacks/clarinet-sdk": "^3",
|
|
142
130
|
"@stacks/transactions": "^7",
|
|
143
|
-
"
|
|
144
|
-
"typescript": "^5",
|
|
145
|
-
"zod": "^4"
|
|
131
|
+
"typescript": "^5"
|
|
146
132
|
},
|
|
147
133
|
"peerDependenciesMeta": {
|
|
148
134
|
"@stacks/clarinet-sdk": {
|
|
@@ -150,12 +136,6 @@
|
|
|
150
136
|
},
|
|
151
137
|
"@stacks/transactions": {
|
|
152
138
|
"optional": true
|
|
153
|
-
},
|
|
154
|
-
"ai": {
|
|
155
|
-
"optional": true
|
|
156
|
-
},
|
|
157
|
-
"zod": {
|
|
158
|
-
"optional": true
|
|
159
139
|
}
|
|
160
140
|
},
|
|
161
141
|
"dependencies": {
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
var import_node_module = require("node:module");
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
function __accessProp(key) {
|
|
7
|
-
return this[key];
|
|
8
|
-
}
|
|
9
|
-
var __toCommonJS = (from) => {
|
|
10
|
-
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
11
|
-
if (entry)
|
|
12
|
-
return entry;
|
|
13
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
14
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
-
for (var key of __getOwnPropNames(from))
|
|
16
|
-
if (!__hasOwnProp.call(entry, key))
|
|
17
|
-
__defProp(entry, key, {
|
|
18
|
-
get: __accessProp.bind(from, key),
|
|
19
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
__moduleCache.set(from, entry);
|
|
23
|
-
return entry;
|
|
24
|
-
};
|
|
25
|
-
var __moduleCache;
|
|
26
|
-
var __returnValue = (v) => v;
|
|
27
|
-
function __exportSetter(name, newValue) {
|
|
28
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
-
}
|
|
30
|
-
var __export = (target, all) => {
|
|
31
|
-
for (var name in all)
|
|
32
|
-
__defProp(target, name, {
|
|
33
|
-
get: all[name],
|
|
34
|
-
enumerable: true,
|
|
35
|
-
configurable: true,
|
|
36
|
-
set: __exportSetter.bind(all, name)
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// src/tools/btc/index.ts
|
|
41
|
-
var exports_btc = {};
|
|
42
|
-
__export(exports_btc, {
|
|
43
|
-
btcUtxos: () => btcUtxos,
|
|
44
|
-
btcFeeEstimate: () => btcFeeEstimate,
|
|
45
|
-
btcConfirmations: () => btcConfirmations,
|
|
46
|
-
btcBlockHeight: () => btcBlockHeight,
|
|
47
|
-
btcBalance: () => btcBalance,
|
|
48
|
-
BTC_ADDRESS: () => BTC_ADDRESS
|
|
49
|
-
});
|
|
50
|
-
module.exports = __toCommonJS(exports_btc);
|
|
51
|
-
var import_ai = require("ai");
|
|
52
|
-
var import_zod = require("zod");
|
|
53
|
-
function baseUrl() {
|
|
54
|
-
return (process.env.BTC_MEMPOOL_URL ?? "https://mempool.space").replace(/\/$/, "");
|
|
55
|
-
}
|
|
56
|
-
async function get(path) {
|
|
57
|
-
const res = await fetch(`${baseUrl()}${path}`, {
|
|
58
|
-
headers: { Accept: "application/json" }
|
|
59
|
-
});
|
|
60
|
-
if (!res.ok) {
|
|
61
|
-
throw new Error(`BTC mempool.space ${path} → ${res.status} ${res.statusText}`);
|
|
62
|
-
}
|
|
63
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
64
|
-
if (contentType.includes("application/json"))
|
|
65
|
-
return res.json();
|
|
66
|
-
return res.text();
|
|
67
|
-
}
|
|
68
|
-
var BTC_TXID = import_zod.z.string().regex(/^[0-9a-fA-F]{64}$/, "64-character hex BTC txid");
|
|
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" });
|
|
70
|
-
var btcConfirmations = import_ai.tool({
|
|
71
|
-
description: "Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.",
|
|
72
|
-
inputSchema: import_zod.z.object({ txid: BTC_TXID }),
|
|
73
|
-
execute: async ({ txid }) => {
|
|
74
|
-
const tx = await get(`/api/tx/${txid}`);
|
|
75
|
-
if (!tx.status.confirmed || tx.status.block_height == null) {
|
|
76
|
-
return { confirmed: false, confirmations: 0 };
|
|
77
|
-
}
|
|
78
|
-
const tip = await get("/api/blocks/tip/height");
|
|
79
|
-
return {
|
|
80
|
-
confirmed: true,
|
|
81
|
-
confirmations: Math.max(0, tip - tx.status.block_height + 1),
|
|
82
|
-
blockHeight: tx.status.block_height
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
var btcBalance = import_ai.tool({
|
|
87
|
-
description: "Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.",
|
|
88
|
-
inputSchema: import_zod.z.object({ address: BTC_ADDRESS }),
|
|
89
|
-
execute: async ({ address }) => {
|
|
90
|
-
const info = await get(`/api/address/${encodeURIComponent(address)}`);
|
|
91
|
-
return {
|
|
92
|
-
confirmedSat: info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,
|
|
93
|
-
unconfirmedSat: info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
var btcUtxos = import_ai.tool({
|
|
98
|
-
description: "List of unspent outputs for a Bitcoin address (truncated to `limit`).",
|
|
99
|
-
inputSchema: import_zod.z.object({
|
|
100
|
-
address: BTC_ADDRESS,
|
|
101
|
-
limit: import_zod.z.number().int().min(1).max(50).default(25)
|
|
102
|
-
}),
|
|
103
|
-
execute: async ({ address, limit }) => {
|
|
104
|
-
const utxos = await get(`/api/address/${encodeURIComponent(address)}/utxo`);
|
|
105
|
-
return { utxos: utxos.slice(0, limit) };
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
var btcFeeEstimate = import_ai.tool({
|
|
109
|
-
description: "Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).",
|
|
110
|
-
inputSchema: import_zod.z.object({}),
|
|
111
|
-
execute: async () => {
|
|
112
|
-
const fees = await get("/api/v1/fees/recommended");
|
|
113
|
-
return {
|
|
114
|
-
fastestSatVb: fees.fastestFee ?? 0,
|
|
115
|
-
halfHourSatVb: fees.halfHourFee ?? 0,
|
|
116
|
-
hourSatVb: fees.hourFee ?? 0,
|
|
117
|
-
economySatVb: fees.economyFee ?? 0,
|
|
118
|
-
minimumSatVb: fees.minimumFee ?? 0
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
var btcBlockHeight = import_ai.tool({
|
|
123
|
-
description: "Current Bitcoin chain tip height.",
|
|
124
|
-
inputSchema: import_zod.z.object({}),
|
|
125
|
-
execute: async () => ({
|
|
126
|
-
height: await get("/api/blocks/tip/height")
|
|
127
|
-
})
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
//# debugId=A9918581E436E21F64756E2164756E21
|
|
131
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/tools/btc/index.ts"],
|
|
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 * @deprecated Point your agent at `@secondlayer/mcp` instead; this entry\n * stays importable until the next major but gets no new tools. Installing\n * it means installing `ai` and `zod` yourself: both are optional peers of\n * the package, not dependencies.\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
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "A9918581E436E21F64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Tool } from "ai";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
type LooseTool = Tool<any, any>;
|
|
4
|
-
declare const BTC_ADDRESS: z.ZodString;
|
|
5
|
-
declare const btcConfirmations: LooseTool;
|
|
6
|
-
declare const btcBalance: LooseTool;
|
|
7
|
-
declare const btcUtxos: LooseTool;
|
|
8
|
-
declare const btcFeeEstimate: LooseTool;
|
|
9
|
-
declare const btcBlockHeight: LooseTool;
|
|
10
|
-
export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance, BTC_ADDRESS };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Tool } from "ai";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
type LooseTool = Tool<any, any>;
|
|
4
|
-
declare const BTC_ADDRESS: z.ZodString;
|
|
5
|
-
declare const btcConfirmations: LooseTool;
|
|
6
|
-
declare const btcBalance: LooseTool;
|
|
7
|
-
declare const btcUtxos: LooseTool;
|
|
8
|
-
declare const btcFeeEstimate: LooseTool;
|
|
9
|
-
declare const btcBlockHeight: LooseTool;
|
|
10
|
-
export { btcUtxos, btcFeeEstimate, btcConfirmations, btcBlockHeight, btcBalance, BTC_ADDRESS };
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// src/tools/btc/index.ts
|
|
2
|
-
import { tool } from "ai";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
function baseUrl() {
|
|
5
|
-
return (process.env.BTC_MEMPOOL_URL ?? "https://mempool.space").replace(/\/$/, "");
|
|
6
|
-
}
|
|
7
|
-
async function get(path) {
|
|
8
|
-
const res = await fetch(`${baseUrl()}${path}`, {
|
|
9
|
-
headers: { Accept: "application/json" }
|
|
10
|
-
});
|
|
11
|
-
if (!res.ok) {
|
|
12
|
-
throw new Error(`BTC mempool.space ${path} → ${res.status} ${res.statusText}`);
|
|
13
|
-
}
|
|
14
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
15
|
-
if (contentType.includes("application/json"))
|
|
16
|
-
return res.json();
|
|
17
|
-
return res.text();
|
|
18
|
-
}
|
|
19
|
-
var BTC_TXID = z.string().regex(/^[0-9a-fA-F]{64}$/, "64-character hex BTC txid");
|
|
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
|
-
var btcConfirmations = tool({
|
|
22
|
-
description: "Number of confirmations for a Bitcoin transaction. Returns { confirmations, confirmed }.",
|
|
23
|
-
inputSchema: z.object({ txid: BTC_TXID }),
|
|
24
|
-
execute: async ({ txid }) => {
|
|
25
|
-
const tx = await get(`/api/tx/${txid}`);
|
|
26
|
-
if (!tx.status.confirmed || tx.status.block_height == null) {
|
|
27
|
-
return { confirmed: false, confirmations: 0 };
|
|
28
|
-
}
|
|
29
|
-
const tip = await get("/api/blocks/tip/height");
|
|
30
|
-
return {
|
|
31
|
-
confirmed: true,
|
|
32
|
-
confirmations: Math.max(0, tip - tx.status.block_height + 1),
|
|
33
|
-
blockHeight: tx.status.block_height
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
var btcBalance = tool({
|
|
38
|
-
description: "Bitcoin balance for an address, in satoshis. Returns { confirmedSat, unconfirmedSat }.",
|
|
39
|
-
inputSchema: z.object({ address: BTC_ADDRESS }),
|
|
40
|
-
execute: async ({ address }) => {
|
|
41
|
-
const info = await get(`/api/address/${encodeURIComponent(address)}`);
|
|
42
|
-
return {
|
|
43
|
-
confirmedSat: info.chain_stats.funded_txo_sum - info.chain_stats.spent_txo_sum,
|
|
44
|
-
unconfirmedSat: info.mempool_stats.funded_txo_sum - info.mempool_stats.spent_txo_sum
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
var btcUtxos = tool({
|
|
49
|
-
description: "List of unspent outputs for a Bitcoin address (truncated to `limit`).",
|
|
50
|
-
inputSchema: z.object({
|
|
51
|
-
address: BTC_ADDRESS,
|
|
52
|
-
limit: z.number().int().min(1).max(50).default(25)
|
|
53
|
-
}),
|
|
54
|
-
execute: async ({ address, limit }) => {
|
|
55
|
-
const utxos = await get(`/api/address/${encodeURIComponent(address)}/utxo`);
|
|
56
|
-
return { utxos: utxos.slice(0, limit) };
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
var btcFeeEstimate = tool({
|
|
60
|
-
description: "Current Bitcoin fee estimates in sat/vB across priority tiers (fastest, 30-min, hour, economy).",
|
|
61
|
-
inputSchema: z.object({}),
|
|
62
|
-
execute: async () => {
|
|
63
|
-
const fees = await get("/api/v1/fees/recommended");
|
|
64
|
-
return {
|
|
65
|
-
fastestSatVb: fees.fastestFee ?? 0,
|
|
66
|
-
halfHourSatVb: fees.halfHourFee ?? 0,
|
|
67
|
-
hourSatVb: fees.hourFee ?? 0,
|
|
68
|
-
economySatVb: fees.economyFee ?? 0,
|
|
69
|
-
minimumSatVb: fees.minimumFee ?? 0
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
var btcBlockHeight = tool({
|
|
74
|
-
description: "Current Bitcoin chain tip height.",
|
|
75
|
-
inputSchema: z.object({}),
|
|
76
|
-
execute: async () => ({
|
|
77
|
-
height: await get("/api/blocks/tip/height")
|
|
78
|
-
})
|
|
79
|
-
});
|
|
80
|
-
export {
|
|
81
|
-
btcUtxos,
|
|
82
|
-
btcFeeEstimate,
|
|
83
|
-
btcConfirmations,
|
|
84
|
-
btcBlockHeight,
|
|
85
|
-
btcBalance,
|
|
86
|
-
BTC_ADDRESS
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
//# debugId=E811F99F534F2FE364756E2164756E21
|
|
90
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/tools/btc/index.ts"],
|
|
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 * @deprecated Point your agent at `@secondlayer/mcp` instead; this entry\n * stays importable until the next major but gets no new tools. Installing\n * it means installing `ai` and `zod` yourself: both are optional peers of\n * the package, not dependencies.\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
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "E811F99F534F2FE364756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|