@aibtc/mcp-server 1.58.0 → 1.60.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 (265) hide show
  1. package/README.md +41 -0
  2. package/dist/bridge/index.d.ts +31 -0
  3. package/dist/bridge/index.js +285 -0
  4. package/dist/index.js +28 -5
  5. package/dist/services/credentials.js +7 -2
  6. package/dist/services/defi.service.js +23 -11
  7. package/dist/services/hiro-api.d.ts +10 -0
  8. package/dist/services/hiro-api.js +30 -8
  9. package/dist/services/nft.service.js +14 -5
  10. package/dist/services/pillar-api.service.d.ts +8 -0
  11. package/dist/services/pillar-api.service.js +13 -1
  12. package/dist/services/spend-limiter.d.ts +45 -0
  13. package/dist/services/spend-limiter.js +218 -0
  14. package/dist/services/wallet-manager.js +5 -0
  15. package/dist/services/x402.service.js +63 -13
  16. package/dist/tools/bitcoin.tools.js +19 -0
  17. package/dist/tools/endpoint.tools.js +3 -1
  18. package/dist/tools/inbox.tools.js +9 -12
  19. package/dist/tools/news.tools.js +14 -16
  20. package/dist/tools/pillar-direct.tools.js +29 -22
  21. package/dist/tools/sbtc.tools.js +2 -9
  22. package/dist/tools/scaffold.tools.js +9 -14
  23. package/dist/tools/stacking-lottery.tools.js +8 -5
  24. package/dist/tools/yield-dashboard.tools.js +10 -14
  25. package/dist/transactions/builder.js +5 -0
  26. package/dist/utils/encryption.js +2 -0
  27. package/package.json +11 -5
  28. package/skill/SKILL.md +1 -1
  29. package/skill/references/genesis-lifecycle.md +105 -92
  30. package/dist/config/bitcoin-constants.d.ts.map +0 -1
  31. package/dist/config/bitcoin-constants.js.map +0 -1
  32. package/dist/config/caip.d.ts.map +0 -1
  33. package/dist/config/caip.js.map +0 -1
  34. package/dist/config/competition.d.ts.map +0 -1
  35. package/dist/config/competition.js.map +0 -1
  36. package/dist/config/contracts.d.ts.map +0 -1
  37. package/dist/config/contracts.js.map +0 -1
  38. package/dist/config/index.d.ts.map +0 -1
  39. package/dist/config/index.js.map +0 -1
  40. package/dist/config/networks.d.ts.map +0 -1
  41. package/dist/config/networks.js.map +0 -1
  42. package/dist/config/pillar.d.ts.map +0 -1
  43. package/dist/config/pillar.js.map +0 -1
  44. package/dist/config/sponsor.d.ts.map +0 -1
  45. package/dist/config/sponsor.js.map +0 -1
  46. package/dist/endpoints/index.d.ts.map +0 -1
  47. package/dist/endpoints/index.js.map +0 -1
  48. package/dist/endpoints/registry.d.ts.map +0 -1
  49. package/dist/endpoints/registry.js.map +0 -1
  50. package/dist/index.d.ts.map +0 -1
  51. package/dist/index.js.map +0 -1
  52. package/dist/services/bitflow.service.d.ts.map +0 -1
  53. package/dist/services/bitflow.service.js.map +0 -1
  54. package/dist/services/bns.service.d.ts.map +0 -1
  55. package/dist/services/bns.service.js.map +0 -1
  56. package/dist/services/credentials.d.ts.map +0 -1
  57. package/dist/services/credentials.js.map +0 -1
  58. package/dist/services/defi.service.d.ts.map +0 -1
  59. package/dist/services/defi.service.js.map +0 -1
  60. package/dist/services/erc8004.service.d.ts.map +0 -1
  61. package/dist/services/erc8004.service.js.map +0 -1
  62. package/dist/services/hiro-api.d.ts.map +0 -1
  63. package/dist/services/hiro-api.js.map +0 -1
  64. package/dist/services/inscription-parser.d.ts.map +0 -1
  65. package/dist/services/inscription-parser.js.map +0 -1
  66. package/dist/services/lightning/provider.d.ts.map +0 -1
  67. package/dist/services/lightning/provider.js.map +0 -1
  68. package/dist/services/lightning/spark-provider.d.ts.map +0 -1
  69. package/dist/services/lightning/spark-provider.js.map +0 -1
  70. package/dist/services/lightning-manager.d.ts.map +0 -1
  71. package/dist/services/lightning-manager.js.map +0 -1
  72. package/dist/services/mempool-api.d.ts.map +0 -1
  73. package/dist/services/mempool-api.js.map +0 -1
  74. package/dist/services/nft.service.d.ts.map +0 -1
  75. package/dist/services/nft.service.js.map +0 -1
  76. package/dist/services/nonce-tracker.d.ts.map +0 -1
  77. package/dist/services/nonce-tracker.js.map +0 -1
  78. package/dist/services/pillar-api.service.d.ts.map +0 -1
  79. package/dist/services/pillar-api.service.js.map +0 -1
  80. package/dist/services/sbtc-deposit.service.d.ts.map +0 -1
  81. package/dist/services/sbtc-deposit.service.js.map +0 -1
  82. package/dist/services/sbtc.service.d.ts.map +0 -1
  83. package/dist/services/sbtc.service.js.map +0 -1
  84. package/dist/services/scaffold.service.d.ts.map +0 -1
  85. package/dist/services/scaffold.service.js.map +0 -1
  86. package/dist/services/signing-key.service.d.ts.map +0 -1
  87. package/dist/services/signing-key.service.js.map +0 -1
  88. package/dist/services/stacking.service.d.ts.map +0 -1
  89. package/dist/services/stacking.service.js.map +0 -1
  90. package/dist/services/tenero-api.d.ts.map +0 -1
  91. package/dist/services/tenero-api.js.map +0 -1
  92. package/dist/services/tokens.service.d.ts.map +0 -1
  93. package/dist/services/tokens.service.js.map +0 -1
  94. package/dist/services/unisat-indexer.d.ts.map +0 -1
  95. package/dist/services/unisat-indexer.js.map +0 -1
  96. package/dist/services/wallet-manager.d.ts.map +0 -1
  97. package/dist/services/wallet-manager.js.map +0 -1
  98. package/dist/services/x402.service.d.ts.map +0 -1
  99. package/dist/services/x402.service.js.map +0 -1
  100. package/dist/tools/arxiv-research.tools.d.ts.map +0 -1
  101. package/dist/tools/arxiv-research.tools.js.map +0 -1
  102. package/dist/tools/bitcoin.tools.d.ts.map +0 -1
  103. package/dist/tools/bitcoin.tools.js.map +0 -1
  104. package/dist/tools/bitflow.tools.d.ts.map +0 -1
  105. package/dist/tools/bitflow.tools.js.map +0 -1
  106. package/dist/tools/bns.tools.d.ts.map +0 -1
  107. package/dist/tools/bns.tools.js.map +0 -1
  108. package/dist/tools/bounty-scanner.tools.d.ts.map +0 -1
  109. package/dist/tools/bounty-scanner.tools.js.map +0 -1
  110. package/dist/tools/child-inscription.tools.d.ts.map +0 -1
  111. package/dist/tools/child-inscription.tools.js.map +0 -1
  112. package/dist/tools/competition.tools.d.ts.map +0 -1
  113. package/dist/tools/competition.tools.js.map +0 -1
  114. package/dist/tools/contract.tools.d.ts.map +0 -1
  115. package/dist/tools/contract.tools.js.map +0 -1
  116. package/dist/tools/credentials.tools.d.ts.map +0 -1
  117. package/dist/tools/credentials.tools.js.map +0 -1
  118. package/dist/tools/defi.tools.d.ts.map +0 -1
  119. package/dist/tools/defi.tools.js.map +0 -1
  120. package/dist/tools/dual-stacking.tools.d.ts.map +0 -1
  121. package/dist/tools/dual-stacking.tools.js.map +0 -1
  122. package/dist/tools/earning.tools.d.ts.map +0 -1
  123. package/dist/tools/earning.tools.js.map +0 -1
  124. package/dist/tools/endpoint.tools.d.ts.map +0 -1
  125. package/dist/tools/endpoint.tools.js.map +0 -1
  126. package/dist/tools/erc8004.tools.d.ts.map +0 -1
  127. package/dist/tools/erc8004.tools.js.map +0 -1
  128. package/dist/tools/identity.tools.d.ts.map +0 -1
  129. package/dist/tools/identity.tools.js.map +0 -1
  130. package/dist/tools/inbox-x402.tools.d.ts.map +0 -1
  131. package/dist/tools/inbox-x402.tools.js.map +0 -1
  132. package/dist/tools/inbox.tools.d.ts.map +0 -1
  133. package/dist/tools/inbox.tools.js.map +0 -1
  134. package/dist/tools/index.d.ts.map +0 -1
  135. package/dist/tools/index.js.map +0 -1
  136. package/dist/tools/jingswap.tools.d.ts.map +0 -1
  137. package/dist/tools/jingswap.tools.js.map +0 -1
  138. package/dist/tools/lightning.tools.d.ts.map +0 -1
  139. package/dist/tools/lightning.tools.js.map +0 -1
  140. package/dist/tools/mempool.tools.d.ts.map +0 -1
  141. package/dist/tools/mempool.tools.js.map +0 -1
  142. package/dist/tools/news.tools.d.ts.map +0 -1
  143. package/dist/tools/news.tools.js.map +0 -1
  144. package/dist/tools/nft.tools.d.ts.map +0 -1
  145. package/dist/tools/nft.tools.js.map +0 -1
  146. package/dist/tools/nonce.tools.d.ts.map +0 -1
  147. package/dist/tools/nonce.tools.js.map +0 -1
  148. package/dist/tools/nostr.tools.d.ts.map +0 -1
  149. package/dist/tools/nostr.tools.js.map +0 -1
  150. package/dist/tools/openrouter.tools.d.ts.map +0 -1
  151. package/dist/tools/openrouter.tools.js.map +0 -1
  152. package/dist/tools/ordinals-marketplace.tools.d.ts.map +0 -1
  153. package/dist/tools/ordinals-marketplace.tools.js.map +0 -1
  154. package/dist/tools/ordinals-p2p.tools.d.ts.map +0 -1
  155. package/dist/tools/ordinals-p2p.tools.js.map +0 -1
  156. package/dist/tools/ordinals.tools.d.ts.map +0 -1
  157. package/dist/tools/ordinals.tools.js.map +0 -1
  158. package/dist/tools/pillar-direct.tools.d.ts.map +0 -1
  159. package/dist/tools/pillar-direct.tools.js.map +0 -1
  160. package/dist/tools/pillar.tools.d.ts.map +0 -1
  161. package/dist/tools/pillar.tools.js.map +0 -1
  162. package/dist/tools/psbt.helpers.d.ts.map +0 -1
  163. package/dist/tools/psbt.helpers.js.map +0 -1
  164. package/dist/tools/psbt.tools.d.ts.map +0 -1
  165. package/dist/tools/psbt.tools.js.map +0 -1
  166. package/dist/tools/query.tools.d.ts.map +0 -1
  167. package/dist/tools/query.tools.js.map +0 -1
  168. package/dist/tools/relay-diagnostic.tools.d.ts.map +0 -1
  169. package/dist/tools/relay-diagnostic.tools.js.map +0 -1
  170. package/dist/tools/reputation.tools.d.ts.map +0 -1
  171. package/dist/tools/reputation.tools.js.map +0 -1
  172. package/dist/tools/runes.tools.d.ts.map +0 -1
  173. package/dist/tools/runes.tools.js.map +0 -1
  174. package/dist/tools/sbtc.tools.d.ts.map +0 -1
  175. package/dist/tools/sbtc.tools.js.map +0 -1
  176. package/dist/tools/scaffold.tools.d.ts.map +0 -1
  177. package/dist/tools/scaffold.tools.js.map +0 -1
  178. package/dist/tools/schemas.d.ts.map +0 -1
  179. package/dist/tools/schemas.js.map +0 -1
  180. package/dist/tools/settings.tools.d.ts.map +0 -1
  181. package/dist/tools/settings.tools.js.map +0 -1
  182. package/dist/tools/signing.tools.d.ts.map +0 -1
  183. package/dist/tools/signing.tools.js.map +0 -1
  184. package/dist/tools/skill-mappings.d.ts.map +0 -1
  185. package/dist/tools/skill-mappings.js.map +0 -1
  186. package/dist/tools/souldinals.tools.d.ts.map +0 -1
  187. package/dist/tools/souldinals.tools.js.map +0 -1
  188. package/dist/tools/stacking-lottery.tools.d.ts.map +0 -1
  189. package/dist/tools/stacking-lottery.tools.js.map +0 -1
  190. package/dist/tools/stacking.tools.d.ts.map +0 -1
  191. package/dist/tools/stacking.tools.js.map +0 -1
  192. package/dist/tools/stacks-market.tools.d.ts.map +0 -1
  193. package/dist/tools/stacks-market.tools.js.map +0 -1
  194. package/dist/tools/styx.tools.d.ts.map +0 -1
  195. package/dist/tools/styx.tools.js.map +0 -1
  196. package/dist/tools/taproot-multisig.tools.d.ts.map +0 -1
  197. package/dist/tools/taproot-multisig.tools.js.map +0 -1
  198. package/dist/tools/tenero.tools.d.ts.map +0 -1
  199. package/dist/tools/tenero.tools.js.map +0 -1
  200. package/dist/tools/tokens.tools.d.ts.map +0 -1
  201. package/dist/tools/tokens.tools.js.map +0 -1
  202. package/dist/tools/transfer.tools.d.ts.map +0 -1
  203. package/dist/tools/transfer.tools.js.map +0 -1
  204. package/dist/tools/wallet-management.tools.d.ts.map +0 -1
  205. package/dist/tools/wallet-management.tools.js.map +0 -1
  206. package/dist/tools/wallet.tools.d.ts.map +0 -1
  207. package/dist/tools/wallet.tools.js.map +0 -1
  208. package/dist/tools/yield-dashboard.tools.d.ts.map +0 -1
  209. package/dist/tools/yield-dashboard.tools.js.map +0 -1
  210. package/dist/tools/yield-hunter.tools.d.ts.map +0 -1
  211. package/dist/tools/yield-hunter.tools.js.map +0 -1
  212. package/dist/transactions/bitcoin-builder.d.ts.map +0 -1
  213. package/dist/transactions/bitcoin-builder.js.map +0 -1
  214. package/dist/transactions/builder.d.ts.map +0 -1
  215. package/dist/transactions/builder.js.map +0 -1
  216. package/dist/transactions/child-inscription-builder.d.ts.map +0 -1
  217. package/dist/transactions/child-inscription-builder.js.map +0 -1
  218. package/dist/transactions/clarity-values.d.ts.map +0 -1
  219. package/dist/transactions/clarity-values.js.map +0 -1
  220. package/dist/transactions/inscription-builder.d.ts.map +0 -1
  221. package/dist/transactions/inscription-builder.js.map +0 -1
  222. package/dist/transactions/post-conditions.d.ts.map +0 -1
  223. package/dist/transactions/post-conditions.js.map +0 -1
  224. package/dist/transactions/rune-transfer-builder.d.ts.map +0 -1
  225. package/dist/transactions/rune-transfer-builder.js.map +0 -1
  226. package/dist/transactions/runestone-builder.d.ts.map +0 -1
  227. package/dist/transactions/runestone-builder.js.map +0 -1
  228. package/dist/transactions/sponsor-builder.d.ts.map +0 -1
  229. package/dist/transactions/sponsor-builder.js.map +0 -1
  230. package/dist/utils/bip322.d.ts.map +0 -1
  231. package/dist/utils/bip322.js.map +0 -1
  232. package/dist/utils/bitcoin.d.ts.map +0 -1
  233. package/dist/utils/bitcoin.js.map +0 -1
  234. package/dist/utils/encryption.d.ts.map +0 -1
  235. package/dist/utils/encryption.js.map +0 -1
  236. package/dist/utils/erc8004-helpers.d.ts.map +0 -1
  237. package/dist/utils/erc8004-helpers.js.map +0 -1
  238. package/dist/utils/errors.d.ts.map +0 -1
  239. package/dist/utils/errors.js.map +0 -1
  240. package/dist/utils/fee.d.ts.map +0 -1
  241. package/dist/utils/fee.js.map +0 -1
  242. package/dist/utils/formatting.d.ts.map +0 -1
  243. package/dist/utils/formatting.js.map +0 -1
  244. package/dist/utils/index.d.ts.map +0 -1
  245. package/dist/utils/index.js.map +0 -1
  246. package/dist/utils/l402-protocol.d.ts.map +0 -1
  247. package/dist/utils/l402-protocol.js.map +0 -1
  248. package/dist/utils/redact.d.ts.map +0 -1
  249. package/dist/utils/redact.js.map +0 -1
  250. package/dist/utils/relay-health.d.ts.map +0 -1
  251. package/dist/utils/relay-health.js.map +0 -1
  252. package/dist/utils/storage.d.ts.map +0 -1
  253. package/dist/utils/storage.js.map +0 -1
  254. package/dist/utils/tokens.d.ts.map +0 -1
  255. package/dist/utils/tokens.js.map +0 -1
  256. package/dist/utils/x402-payment-logging.d.ts.map +0 -1
  257. package/dist/utils/x402-payment-logging.js.map +0 -1
  258. package/dist/utils/x402-payment-state.d.ts.map +0 -1
  259. package/dist/utils/x402-payment-state.js.map +0 -1
  260. package/dist/utils/x402-protocol.d.ts.map +0 -1
  261. package/dist/utils/x402-protocol.js.map +0 -1
  262. package/dist/utils/x402-recovery.d.ts.map +0 -1
  263. package/dist/utils/x402-recovery.js.map +0 -1
  264. package/dist/yield-hunter/index.d.ts.map +0 -1
  265. package/dist/yield-hunter/index.js.map +0 -1
@@ -56,21 +56,18 @@ async function getNextNonce(address) {
56
56
  const hiroApi = getHiroApi(NETWORK);
57
57
  const accountInfo = await hiroApi.getAccountInfo(address);
58
58
  const confirmedNonce = accountInfo.nonce;
59
+ // The mempool scan is what makes the nonce safe against pending txs —
60
+ // silently skipping it on failure risks a nonce collision, so let it fail.
59
61
  let highestMempoolNonce = -1;
60
- try {
61
- const mempool = await hiroApi.getMempoolTransactions({
62
- sender_address: address,
63
- limit: 50,
64
- });
65
- for (const tx of mempool.results) {
66
- if (tx.nonce > highestMempoolNonce) {
67
- highestMempoolNonce = tx.nonce;
68
- }
62
+ const mempool = await hiroApi.getMempoolTransactions({
63
+ sender_address: address,
64
+ limit: 50,
65
+ });
66
+ for (const tx of mempool.results) {
67
+ if (tx.nonce > highestMempoolNonce) {
68
+ highestMempoolNonce = tx.nonce;
69
69
  }
70
70
  }
71
- catch {
72
- // Non-fatal
73
- }
74
71
  const chainNext = Math.max(confirmedNonce, highestMempoolNonce + 1);
75
72
  await reconcileWithChain(address, chainNext);
76
73
  return Math.max(chainNext, localNext ?? 0);
@@ -466,10 +463,11 @@ Fields:
466
463
  server.registerTool("news_file_signal", {
467
464
  description: `File a signal on a beat at aibtc.news.
468
465
 
469
- Requires an unlocked wallet with a P2WPKH (bc1q) BTC address and sBTC balance
470
- for the x402 payment. The tool handles the full payment flow:
471
- 1. POST with BIP-322 auth → receive 402 payment challenge
472
- 2. Build sponsored sBTC transfer (relay pays gas)
466
+ Filing is free — no payment required. Requires an unlocked wallet with a
467
+ P2WPKH (bc1q) BTC address for BIP-322 authentication. If the endpoint ever
468
+ returns a 402 payment challenge, the tool falls back to the x402 sBTC flow:
469
+ 1. POST with BIP-322 auth → signal filed (or receive 402 payment challenge)
470
+ 2. On 402: build sponsored sBTC transfer (relay pays gas)
473
471
  3. Retry with payment proof → signal filed
474
472
 
475
473
  Authentication: BIP-322 signed headers (X-BTC-Address, X-BTC-Signature, X-BTC-Timestamp).
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import crypto from "crypto";
3
3
  import { tupleCV, stringAsciiCV, uintCV, principalCV, noneCV, trueCV, falseCV, } from "@stacks/transactions";
4
4
  import { getSigningKeyService, generateAuthId, } from "../services/signing-key.service.js";
5
- import { getPillarApi } from "../services/pillar-api.service.js";
5
+ import { getPillarApi, PillarApiError } from "../services/pillar-api.service.js";
6
6
  import { getHiroApi } from "../services/hiro-api.js";
7
7
  import { NETWORK } from "../config/networks.js";
8
8
  import { PILLAR_API_KEY } from "../config/pillar.js";
@@ -497,8 +497,12 @@ export function registerPillarDirectTools(server) {
497
497
  const walletInfo = await api.get(`/api/smart-wallet/${walletName}`);
498
498
  walletStatus = walletInfo.data?.status || null;
499
499
  }
500
- catch {
501
- // Wallet not found in backend
500
+ catch (error) {
501
+ // 404 = wallet not registered in backend. Anything else (network,
502
+ // 5xx) must surface, or an initialized wallet gets misreported.
503
+ if (!(error instanceof PillarApiError && error.status === 404)) {
504
+ throw error;
505
+ }
502
506
  }
503
507
  if (!walletStatus || walletStatus === "pending_init") {
504
508
  return createJsonResponse({
@@ -554,8 +558,11 @@ export function registerPillarDirectTools(server) {
554
558
  });
555
559
  position = unwindQuote.data;
556
560
  }
557
- catch {
558
- // unwind-quote may fail for fresh wallets with no position
561
+ catch (error) {
562
+ // 4xx = fresh wallet with no position. Infra failures must surface.
563
+ if (!(error instanceof PillarApiError && error.status < 500)) {
564
+ throw error;
565
+ }
559
566
  }
560
567
  return createJsonResponse({
561
568
  success: true,
@@ -1146,21 +1153,16 @@ export function registerPillarDirectTools(server) {
1146
1153
  const frac = (micro % BigInt(1_000_000)).toString().padStart(6, "0");
1147
1154
  return `${whole}.${frac} STX`;
1148
1155
  };
1149
- // Fetch PoX cycle info
1150
- let poxInfo = null;
1151
- try {
1152
- const pox = await hiro.getPoxInfo();
1153
- poxInfo = {
1154
- currentCycleId: pox.current_cycle.id,
1155
- nextCycleId: pox.next_cycle.id,
1156
- blocksUntilNextCycle: pox.next_cycle.blocks_until_reward_phase,
1157
- minAmountUstx: pox.min_amount_ustx,
1158
- isPoxActive: pox.current_cycle.is_pox_active,
1159
- };
1160
- }
1161
- catch {
1162
- // PoX info fetch failed, continue without it
1163
- }
1156
+ // Fetch PoX cycle info — a global endpoint with no "not found" case,
1157
+ // so any failure is infrastructure and should surface.
1158
+ const pox = await hiro.getPoxInfo();
1159
+ const poxInfo = {
1160
+ currentCycleId: pox.current_cycle.id,
1161
+ nextCycleId: pox.next_cycle.id,
1162
+ blocksUntilNextCycle: pox.next_cycle.blocks_until_reward_phase,
1163
+ minAmountUstx: pox.min_amount_ustx,
1164
+ isPoxActive: pox.current_cycle.is_pox_active,
1165
+ };
1164
1166
  // Check enrollment status via backend
1165
1167
  const api = getPillarApi();
1166
1168
  const contractParts = session.smartWallet.split(".");
@@ -1175,8 +1177,13 @@ export function registerPillarDirectTools(server) {
1175
1177
  };
1176
1178
  }
1177
1179
  }
1178
- catch {
1179
- // Backend lookup failed, continue without enrollment info
1180
+ catch (error) {
1181
+ // 404 = wallet not registered, so not enrolled. Other failures
1182
+ // must surface — defaulting to enrolled:false on a backend outage
1183
+ // misreports an enrolled wallet and could prompt re-enrollment.
1184
+ if (!(error instanceof PillarApiError && error.status === 404)) {
1185
+ throw error;
1186
+ }
1180
1187
  }
1181
1188
  const isStacking = lockedMicro > BigInt(0);
1182
1189
  return createJsonResponse({
@@ -283,16 +283,9 @@ Signers later process the request and send BTC on L1.`,
283
283
  description: "Get information about how to deposit BTC to receive sBTC.",
284
284
  }, async () => {
285
285
  try {
286
- // Try to get wallet account (don't throw if not unlocked)
286
+ // getActiveAccount returns null when locked - generic instructions then
287
287
  const walletManager = getWalletManager();
288
- let account;
289
- try {
290
- account = walletManager.getActiveAccount();
291
- }
292
- catch {
293
- // Wallet not unlocked - return generic instructions
294
- account = null;
295
- }
288
+ const account = walletManager.getActiveAccount();
296
289
  // If wallet is unlocked and has Taproot keys, generate real deposit address
297
290
  if (account?.taprootPublicKey) {
298
291
  const depositService = getSbtcDepositService(NETWORK);
@@ -8,20 +8,15 @@ import { getWalletAddress } from "../services/x402.service.js";
8
8
  * Check if a directory contains an existing x402 project
9
9
  */
10
10
  async function isExistingX402Project(dir) {
11
- try {
12
- const indexPath = path.join(dir, "src", "index.ts");
13
- const middlewarePath = path.join(dir, "src", "x402-middleware.ts");
14
- const packagePath = path.join(dir, "package.json");
15
- const [hasIndex, hasMiddleware, hasPackage] = await Promise.all([
16
- fs.access(indexPath).then(() => true).catch(() => false),
17
- fs.access(middlewarePath).then(() => true).catch(() => false),
18
- fs.access(packagePath).then(() => true).catch(() => false),
19
- ]);
20
- return hasIndex && hasMiddleware && hasPackage;
21
- }
22
- catch {
23
- return false;
24
- }
11
+ const indexPath = path.join(dir, "src", "index.ts");
12
+ const middlewarePath = path.join(dir, "src", "x402-middleware.ts");
13
+ const packagePath = path.join(dir, "package.json");
14
+ const [hasIndex, hasMiddleware, hasPackage] = await Promise.all([
15
+ fs.access(indexPath).then(() => true).catch(() => false),
16
+ fs.access(middlewarePath).then(() => true).catch(() => false),
17
+ fs.access(packagePath).then(() => true).catch(() => false),
18
+ ]);
19
+ return hasIndex && hasMiddleware && hasPackage;
25
20
  }
26
21
  /**
27
22
  * Validate that a project directory does not already exist.
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { uintCV, contractPrincipalCV, PostConditionMode, deserializeCV, cvToJSON, } from "@stacks/transactions";
3
3
  import { getAccount, NETWORK } from "../services/x402.service.js";
4
- import { getHiroApi } from "../services/hiro-api.js";
4
+ import { getHiroApi, isNotFoundError } from "../services/hiro-api.js";
5
5
  import { callContract } from "../transactions/builder.js";
6
6
  import { getExplorerTxUrl } from "../config/networks.js";
7
7
  import { createJsonResponse, createErrorResponse } from "../utils/index.js";
@@ -100,14 +100,17 @@ Note: Stackspot is only available on mainnet.`,
100
100
  try {
101
101
  currentValueUstx = await callPotReadOnly(pot.contractName, "get-pot-value", []);
102
102
  }
103
- catch {
104
- // pot may not be deployed or reachable — skip gracefully
103
+ catch (error) {
104
+ // 404 = pot contract not deployed; other failures surface
105
+ if (!isNotFoundError(error))
106
+ throw error;
105
107
  }
106
108
  try {
107
109
  isLocked = await callPotReadOnly(pot.contractName, "is-locked", []);
108
110
  }
109
- catch {
110
- // same
111
+ catch (error) {
112
+ if (!isNotFoundError(error))
113
+ throw error;
111
114
  }
112
115
  return {
113
116
  name: pot.name,
@@ -251,21 +251,17 @@ async function readStackingPosition(walletAddress) {
251
251
  return pos;
252
252
  }
253
253
  async function getWalletBalances(walletAddress) {
254
- try {
255
- const res = await fetch(`${MAINNET_HIRO_API}/extended/v1/address/${walletAddress}/balances`);
256
- if (!res.ok)
257
- return { stxMicroStx: 0, sbtcSats: 0 };
258
- const data = (await res.json());
259
- const stxMicroStx = parseInt(data.stx?.balance ?? "0", 10);
260
- const sbtcKey = Object.keys(data.fungible_tokens ?? {}).find((k) => k.toLowerCase().includes("sbtc"));
261
- const sbtcSats = sbtcKey
262
- ? parseInt(data.fungible_tokens?.[sbtcKey]?.balance ?? "0", 10)
263
- : 0;
264
- return { stxMicroStx, sbtcSats };
265
- }
266
- catch {
267
- return { stxMicroStx: 0, sbtcSats: 0 };
254
+ const res = await fetch(`${MAINNET_HIRO_API}/extended/v1/address/${walletAddress}/balances`);
255
+ if (!res.ok) {
256
+ throw new Error(`Failed to fetch wallet balances for ${walletAddress}: HTTP ${res.status}`);
268
257
  }
258
+ const data = (await res.json());
259
+ const stxMicroStx = parseInt(data.stx?.balance ?? "0", 10);
260
+ const sbtcKey = Object.keys(data.fungible_tokens ?? {}).find((k) => k.toLowerCase().includes("sbtc"));
261
+ const sbtcSats = sbtcKey
262
+ ? parseInt(data.fungible_tokens?.[sbtcKey]?.balance ?? "0", 10)
263
+ : 0;
264
+ return { stxMicroStx, sbtcSats };
269
265
  }
270
266
  async function checkZestV2() {
271
267
  try {
@@ -3,6 +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
7
  import { getTrackedNonce, recordNonceUsed, resetTrackedNonce, reconcileWithChain, } from "../services/nonce-tracker.js";
7
8
  // ---------------------------------------------------------------------------
8
9
  // Pending nonce tracking (unified via SharedNonceTracker, issue #413)
@@ -82,6 +83,9 @@ export function advancePendingNonce(address, nonce, txid = "") {
82
83
  * @param fee Optional fee in micro-STX. If omitted, a medium-priority clamped fee is resolved.
83
84
  */
84
85
  export async function transferStx(account, recipient, amount, memo, fee) {
86
+ // Safety rail: block before signing if this would exceed the wallet's
87
+ // cumulative spending limit (per-session or per-day).
88
+ await getSpendLimiter().check("ustx", amount, account.address);
85
89
  const networkName = getStacksNetwork(account.network);
86
90
  const nonce = await getNextNonce(account.address, account.network);
87
91
  // Always resolve a clamped fee — prevents @stacks/transactions from over-estimating.
@@ -103,6 +107,7 @@ export async function transferStx(account, recipient, amount, memo, fee) {
103
107
  throw new Error(`Broadcast failed: ${broadcastResponse.error} - ${broadcastResponse.reason}`);
104
108
  }
105
109
  advancePendingNonce(account.address, nonce, broadcastResponse.txid);
110
+ await getSpendLimiter().record("ustx", amount, account.address);
106
111
  return {
107
112
  txid: broadcastResponse.txid,
108
113
  rawTx: transaction.serialize(),
@@ -37,6 +37,7 @@ export async function encrypt(plaintext, password) {
37
37
  const key = await deriveKey(password, salt);
38
38
  // Encrypt with AES-256-GCM
39
39
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
40
+ key.fill(0); // cipher holds its own copy
40
41
  const encrypted = Buffer.concat([
41
42
  cipher.update(plaintext, "utf8"),
42
43
  cipher.final(),
@@ -64,6 +65,7 @@ export async function decrypt(encrypted, password) {
64
65
  const key = await deriveKeyWithParams(password, salt, encrypted.scryptParams);
65
66
  // Decrypt with AES-256-GCM
66
67
  const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
68
+ key.fill(0); // decipher holds its own copy
67
69
  decipher.setAuthTag(authTag);
68
70
  try {
69
71
  const decrypted = Buffer.concat([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aibtc/mcp-server",
3
- "version": "1.58.0",
3
+ "version": "1.60.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",
@@ -14,13 +14,18 @@
14
14
  "dev": "tsx src/index.ts",
15
15
  "test": "vitest run",
16
16
  "test:watch": "vitest",
17
+ "prepare": "git config core.hooksPath >/dev/null 2>&1 || git config core.hooksPath .githooks 2>/dev/null || true",
17
18
  "prepublishOnly": "npm run build"
18
19
  },
19
20
  "files": [
20
21
  "dist",
22
+ "!dist/**/*.map",
21
23
  "README.md",
22
24
  "skill"
23
25
  ],
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
24
29
  "keywords": [
25
30
  "claude",
26
31
  "claude-code",
@@ -60,7 +65,7 @@
60
65
  "@stacks/transactions": "^7.3.1",
61
66
  "@stacks/wallet-sdk": "^7.2.0",
62
67
  "alex-sdk": "^3.2.1",
63
- "axios": "^1.15.0",
68
+ "axios": "^1.17.0",
64
69
  "dotenv": "^17.3.1",
65
70
  "light-bolt11-decoder": "^3.2.0",
66
71
  "micro-ordinals": "^0.3.0",
@@ -68,7 +73,7 @@
68
73
  "path-to-regexp": "^8.4.0",
69
74
  "sbtc": "^0.3.2",
70
75
  "tslib": "^2.8.1",
71
- "ws": "^8.19.0",
76
+ "ws": "^8.21.0",
72
77
  "x402-stacks": "^2.0.3",
73
78
  "zod": "^4.3.6"
74
79
  },
@@ -77,9 +82,10 @@
77
82
  "@types/ws": "^8.18.1",
78
83
  "tsx": "^4.21.0",
79
84
  "typescript": "^5.9.3",
80
- "vitest": "^4.0.18"
85
+ "vitest": "^4.1.8"
81
86
  },
82
87
  "overrides": {
83
- "lodash": "^4.18.0"
88
+ "lodash": "^4.18.0",
89
+ "axios": "^1.17.0"
84
90
  }
85
91
  }
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.58.0 # x-release-please-version
7
+ version: 1.60.0 # x-release-please-version
8
8
  npm: "@aibtc/mcp-server"
9
9
  github: https://github.com/aibtcdev/aibtc-mcp-server
10
10
  ---