From cec06173732915724f9a77659df4923293231f53 Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Fri, 22 May 2026 08:00:52 -0700 Subject: [PATCH 1/2] fix(aibtc-news): align file-signal and claim-beat with current API contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes discovered while filing signals against the live API: 1. file-signal: add btc_address to POST body — API now requires it in the body in addition to the X-BTC-Address auth header. 2. file-signal: stringify disclosure object before sending — API expects a string; the CLI was sending a parsed JSON object, causing 400 errors. 3. file-signal (x402 flow): fix getAccount import path — getAccount moved from wallet-manager.ts to x402.service.ts; stale import caused the x402 payment flow to crash after a successful payment was deducted. 4. claim-beat: add slug and created_by fields to POST body — API requires slug (not just beat_slug) and created_by (BTC address from auth header). Co-Authored-By: Claude Sonnet 4.6 --- aibtc-news/aibtc-news.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aibtc-news/aibtc-news.ts b/aibtc-news/aibtc-news.ts index a9f78b2e..500357b8 100644 --- a/aibtc-news/aibtc-news.ts +++ b/aibtc-news/aibtc-news.ts @@ -354,13 +354,14 @@ program const body: Record = { beat_slug: opts.beatId, + btc_address: headers["X-BTC-Address"], content: opts.content, }; if (opts.headline) body.headline = opts.headline; if (sources.length > 0) body.sources = sources; if (tags.length > 0) body.tags = tags; - if (disclosure !== undefined) body.disclosure = disclosure; + if (disclosure !== undefined) body.disclosure = typeof disclosure === "string" ? disclosure : JSON.stringify(disclosure); // Step 1: POST with auth headers — may return 200 (free) or 402 (x402 payment required) const signalsUrl = `${NEWS_API_BASE}/signals`; @@ -413,7 +414,7 @@ program const { getStacksNetwork } = await import("../src/lib/config/networks.js"); const { createFungiblePostCondition } = await import("../src/lib/transactions/post-conditions.js"); const { getHiroApi } = await import("../src/lib/services/hiro-api.js"); - const { getAccount } = await import("../src/lib/services/wallet-manager.js"); + const { getAccount } = await import("../src/lib/services/x402.service.js"); const paymentRequired = decodePaymentRequired(paymentHeader); if (!paymentRequired?.accepts?.length) { @@ -645,6 +646,8 @@ program const body: Record = { beat_slug: opts.beatId, + slug: opts.beatId, + created_by: headers["X-BTC-Address"], }; if (opts.name) body.name = opts.name; From 52bc92337b41d9234c0ac3d0f08fddafb0cb98ed Mon Sep 17 00:00:00 2001 From: 369SunRay <369sunray@aibtc> Date: Thu, 28 May 2026 08:04:05 -0700 Subject: [PATCH 2/2] fix(tests): restore fetch correctly after hodlmm-flow mock + add tiny-secp256k1 hodlmm-flow.test.ts captured `fetch` at afterEach call time rather than module load time, so `globalThis.fetch = fetch` was a no-op (both sides were the mock). The orphaned mock returned 429 for all non-Bitflow URLs, causing x402.service tests to fail cross-file. Also adds tiny-secp256k1 as an explicit dependency; stacks-alpha-engine imports it at the top level and the missing package made its test file fail to load. Co-Authored-By: Claude Sonnet 4.6 --- bun.lock | 6 ++++++ hodlmm-flow/hodlmm-flow.test.ts | 5 +++-- package.json | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bun.lock b/bun.lock index 16aee9f6..ea2d1ed9 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "@aibtc/skills", @@ -23,6 +24,7 @@ "dotenv": "^17.2.3", "micro-ordinals": "^0.3.0", "sbtc": "^0.3.2", + "tiny-secp256k1": "^2.2.4", "tslib": "^2.8.1", "yaml": "^2.8.2", "zod": "^4.3.5", @@ -207,12 +209,16 @@ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "tiny-secp256k1": ["tiny-secp256k1@2.2.4", "", { "dependencies": { "uint8array-tools": "0.0.7" } }, "sha512-FoDTcToPqZE454Q04hH9o2EhxWsm7pOSpicyHkgTwKhdKWdsTUuqfP5MLq3g+VjAtl2vSx6JpXGdwA2qpYkI0Q=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "uint8array-tools": ["uint8array-tools@0.0.7", "", {}, "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "varuint-bitcoin": ["varuint-bitcoin@1.1.2", "", { "dependencies": { "safe-buffer": "^5.1.1" } }, "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw=="], diff --git a/hodlmm-flow/hodlmm-flow.test.ts b/hodlmm-flow/hodlmm-flow.test.ts index 491b7ee6..69159327 100644 --- a/hodlmm-flow/hodlmm-flow.test.ts +++ b/hodlmm-flow/hodlmm-flow.test.ts @@ -69,9 +69,10 @@ const MOCK_POOL_DETAIL = { }, }; +const originalFetch = globalThis.fetch; + afterEach(() => { - // Reset to real fetch after each test - globalThis.fetch = fetch; + globalThis.fetch = originalFetch; }); test("analyzePool returns partial result with hiro_rate_limited when fetch throws 429", async () => { diff --git a/package.json b/package.json index 01c66c7e..16078cdb 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "dotenv": "^17.2.3", "micro-ordinals": "^0.3.0", "sbtc": "^0.3.2", + "tiny-secp256k1": "^2.2.4", "tslib": "^2.8.1", "yaml": "^2.8.2", "zod": "^4.3.5"