@aibtc/mcp-server 1.67.0 → 1.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/legion.d.ts +53 -11
- package/dist/config/legion.js +77 -20
- package/dist/services/legion.service.d.ts +95 -43
- package/dist/services/legion.service.js +224 -104
- package/dist/services/spend-limiter.d.ts +53 -0
- package/dist/services/spend-limiter.js +55 -21
- package/dist/tools/index.js +1 -1
- package/dist/tools/legion.tools.d.ts +15 -6
- package/dist/tools/legion.tools.js +296 -288
- package/dist/tools/ordinals.tools.js +28 -2
- package/dist/transactions/builder.js +14 -1
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Uses micro-ordinals library to parse and create inscriptions.
|
|
12
12
|
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
13
14
|
import { z } from "zod";
|
|
14
15
|
import { NETWORK } from "../config/networks.js";
|
|
15
16
|
import { P2WPKH_INPUT_VBYTES, P2WPKH_OUTPUT_VBYTES, P2TR_OUTPUT_VBYTES, TX_OVERHEAD_VBYTES, DUST_THRESHOLD, P2TR_INPUT_BASE_VBYTES, WITNESS_OVERHEAD_VBYTES, } from "../config/bitcoin-constants.js";
|
|
@@ -223,8 +224,10 @@ export function registerOrdinalsTools(server) {
|
|
|
223
224
|
feeRate: actualFeeRate,
|
|
224
225
|
contentType,
|
|
225
226
|
contentSize: body.length,
|
|
227
|
+
contentSha256: createHash("sha256").update(body).digest("hex"),
|
|
226
228
|
nextStep: "After commit confirms, call inscribe_reveal with the same contentType, contentBase64, " +
|
|
227
|
-
"plus commitTxid and revealAmount from this response."
|
|
229
|
+
"plus commitTxid and revealAmount from this response. Pass contentSha256 back to inscribe_reveal " +
|
|
230
|
+
"to have the server abort before the reveal fee is spent if the decoded body differs by even one byte.",
|
|
228
231
|
});
|
|
229
232
|
}
|
|
230
233
|
catch (error) {
|
|
@@ -252,12 +255,20 @@ export function registerOrdinalsTools(server) {
|
|
|
252
255
|
contentBase64: z
|
|
253
256
|
.string()
|
|
254
257
|
.describe("Content as base64-encoded string (must match the commit step)"),
|
|
258
|
+
contentSha256: z
|
|
259
|
+
.string()
|
|
260
|
+
.regex(/^[0-9a-f]{64}$/i)
|
|
261
|
+
.optional()
|
|
262
|
+
.describe("Optional: sha256 hex digest of the decoded body from the inscribe commit response. " +
|
|
263
|
+
"If provided, the server computes sha256 over the locally-decoded body and aborts before " +
|
|
264
|
+
"broadcasting the reveal if they differ — prevents burning the reveal fee on a witness-hash " +
|
|
265
|
+
"mismatch when the base64 param drifts between the inscribe and inscribe_reveal calls."),
|
|
255
266
|
feeRate: z
|
|
256
267
|
.union([z.enum(["fast", "medium", "slow"]), z.number().positive()])
|
|
257
268
|
.optional()
|
|
258
269
|
.describe("Fee rate for reveal tx (default: medium)"),
|
|
259
270
|
},
|
|
260
|
-
}, async ({ commitTxid, revealAmount, contentType, contentBase64, feeRate }) => {
|
|
271
|
+
}, async ({ commitTxid, revealAmount, contentType, contentBase64, contentSha256, feeRate }) => {
|
|
261
272
|
try {
|
|
262
273
|
// Check wallet session
|
|
263
274
|
const walletManager = getWalletManager();
|
|
@@ -277,6 +288,21 @@ export function registerOrdinalsTools(server) {
|
|
|
277
288
|
const mempoolApi = new MempoolApi(NETWORK);
|
|
278
289
|
// Reconstruct the inscription and reveal script
|
|
279
290
|
const body = Buffer.from(contentBase64, "base64");
|
|
291
|
+
// If the caller supplied the sha256 digest from the commit response, verify the
|
|
292
|
+
// decoded body matches BEFORE we spend the reveal fee. Silent byte drift between
|
|
293
|
+
// the two calls would otherwise commit a tapscript hash that Bitcoin Core rejects
|
|
294
|
+
// as witness-hash-mismatch, burning the reveal-address sats permanently.
|
|
295
|
+
if (contentSha256) {
|
|
296
|
+
const localSha256 = createHash("sha256").update(body).digest("hex");
|
|
297
|
+
if (localSha256.toLowerCase() !== contentSha256.toLowerCase()) {
|
|
298
|
+
return createErrorResponse(new Error(`contentSha256 mismatch: the decoded body's sha256 (${localSha256}) does not match ` +
|
|
299
|
+
`the digest from the inscribe commit response (${contentSha256}). This means the ` +
|
|
300
|
+
`base64 payload passed to inscribe_reveal is not the exact bytes committed on-chain. ` +
|
|
301
|
+
`Aborting BEFORE broadcasting the reveal so the reveal-address sats are not burned. ` +
|
|
302
|
+
`Re-send the exact base64 from the successful inscribe call (or fix the transport / ` +
|
|
303
|
+
`serialization layer that mutated it).`));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
280
306
|
const inscription = {
|
|
281
307
|
contentType,
|
|
282
308
|
body,
|
|
@@ -3,7 +3,7 @@ import { hexToBytes } from "@stacks/common";
|
|
|
3
3
|
import { getStacksNetwork, getApiBaseUrl } from "../config/networks.js";
|
|
4
4
|
import { getHiroApi } from "../services/hiro-api.js";
|
|
5
5
|
import { resolveDefaultFee } from "../utils/fee.js";
|
|
6
|
-
import { getSpendLimiter } from "../services/spend-limiter.js";
|
|
6
|
+
import { getSpendLimiter, totalBoundedSpends } from "../services/spend-limiter.js";
|
|
7
7
|
import { getTrackedNonce, recordNonceUsed, resetTrackedNonce, reconcileWithChain, } from "../services/nonce-tracker.js";
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
9
|
// Pending nonce tracking (unified via SharedNonceTracker, issue #413)
|
|
@@ -117,6 +117,16 @@ export async function transferStx(account, recipient, amount, memo, fee) {
|
|
|
117
117
|
* Call a smart contract function
|
|
118
118
|
*/
|
|
119
119
|
export async function callContract(account, options) {
|
|
120
|
+
// Safety rail. Swaps, lending and pot entries all funnel through here, and
|
|
121
|
+
// their amounts are denominated in whatever token the call moves — there is no
|
|
122
|
+
// ledger to bill 1,000 ALEX against. The post conditions are the way in: they
|
|
123
|
+
// already bound, in native units, how much of each asset may leave this
|
|
124
|
+
// address. Meter the ones this rail has a ledger for and ignore the rest.
|
|
125
|
+
// Deliberately before makeContractCall, so an over-cap call never signs.
|
|
126
|
+
const meteredSpends = totalBoundedSpends(options.postConditions, account.address);
|
|
127
|
+
for (const spend of meteredSpends) {
|
|
128
|
+
await getSpendLimiter().check(spend.unit, spend.amount, account.address);
|
|
129
|
+
}
|
|
120
130
|
const networkName = getStacksNetwork(account.network);
|
|
121
131
|
const nonce = await getNextNonce(account.address, account.network);
|
|
122
132
|
// Always resolve a clamped fee — prevents @stacks/transactions from over-estimating.
|
|
@@ -141,6 +151,9 @@ export async function callContract(account, options) {
|
|
|
141
151
|
throw new Error(`Broadcast failed: ${broadcastResponse.error} - ${broadcastResponse.reason}`);
|
|
142
152
|
}
|
|
143
153
|
advancePendingNonce(account.address, nonce, broadcastResponse.txid);
|
|
154
|
+
for (const spend of meteredSpends) {
|
|
155
|
+
await getSpendLimiter().record(spend.unit, spend.amount, account.address);
|
|
156
|
+
}
|
|
144
157
|
return {
|
|
145
158
|
txid: broadcastResponse.txid,
|
|
146
159
|
rawTx: transaction.serialize(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aibtc/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.69.0",
|
|
4
4
|
"description": "Bitcoin-native MCP server for AI agents: BTC/STX wallets, DeFi yield, sBTC peg, NFTs, and x402 payments.",
|
|
5
5
|
"mcpName": "io.github.aibtcdev/mcp-server",
|
|
6
6
|
"type": "module",
|
package/skill/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Bitcoin L1 wallet for agents - check balances, send BTC, manage UTX
|
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
author: aibtcdev
|
|
7
|
-
version: 1.
|
|
7
|
+
version: 1.69.0 # x-release-please-version
|
|
8
8
|
npm: "@aibtc/mcp-server"
|
|
9
9
|
github: https://github.com/aibtcdev/aibtc-mcp-server
|
|
10
10
|
---
|