@bolloon/bolloon-agent 0.4.31 → 0.4.33
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/agents/chain/chain-config.js +504 -0
- package/dist/agents/chain/chain-index-query.js +135 -0
- package/dist/agents/chain/chain-indexer.js +1045 -0
- package/dist/agents/chain/chain-settlement.js +284 -0
- package/dist/agents/chain/chain-state-store.js +245 -0
- package/dist/agents/chain/chain-wallet.js +198 -0
- package/dist/agents/chain/escrow-client.js +433 -0
- package/dist/agents/chain/explorer.js +52 -0
- package/dist/agents/chain/index.js +22 -0
- package/dist/agents/chain/onchain-trade.js +705 -0
- package/dist/agents/network-pulse.js +676 -2
- package/dist/agents/task/task-onchain-runner.js +302 -0
- package/dist/agents/task/task-runner.js +27 -3
- package/dist/agents/task-board.js +702 -0
- package/dist/agents/task-group.js +567 -0
- package/dist/agents/x402/paid-info-store.js +75 -6
- package/dist/cli/commands/chain.js +926 -0
- package/dist/cli/commands/index.js +12 -2
- package/dist/cli/commands/tasks.js +627 -6
- package/dist/cli/mcp/server.js +4 -1
- package/dist/cli/mcp/tools.js +348 -5
- package/dist/cli/protocol-envelope.js +16 -0
- package/dist/cli-entry.js +6 -1
- package/dist/electron-build/agents/chain/chain-config.js +556 -0
- package/dist/electron-build/agents/chain/chain-config.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-index-query.js +145 -0
- package/dist/electron-build/agents/chain/chain-index-query.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-indexer.js +1095 -0
- package/dist/electron-build/agents/chain/chain-indexer.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-settlement.js +291 -0
- package/dist/electron-build/agents/chain/chain-settlement.js.map +1 -0
- package/dist/electron-build/agents/chain/escrow-client.js +443 -0
- package/dist/electron-build/agents/chain/escrow-client.js.map +1 -0
- package/dist/electron-build/agents/chain/explorer.js +59 -0
- package/dist/electron-build/agents/chain/explorer.js.map +1 -0
- package/dist/electron-build/agents/local-signer.js +101 -0
- package/dist/electron-build/agents/local-signer.js.map +1 -0
- package/dist/electron-build/agents/network-pulse.js +693 -3
- package/dist/electron-build/agents/network-pulse.js.map +1 -1
- package/dist/electron-build/agents/task/task-runner.js +27 -3
- package/dist/electron-build/agents/task/task-runner.js.map +1 -1
- package/dist/electron-build/agents/task-board.js +761 -0
- package/dist/electron-build/agents/task-board.js.map +1 -0
- package/dist/electron-build/agents/task-contract.js +382 -0
- package/dist/electron-build/agents/task-contract.js.map +1 -0
- package/dist/electron-build/agents/x402/paid-info-store.js +76 -6
- package/dist/electron-build/agents/x402/paid-info-store.js.map +1 -1
- package/dist/web/chain-explorer.js +617 -0
- package/dist/web/explorer.html +163 -0
- package/dist/web/index.html +5 -0
- package/dist/web/routes-chain-index.js +108 -0
- package/dist/web/routes-onchain-trade.js +99 -0
- package/dist/web/server.js +13 -0
- package/package.json +2 -1
- package/scripts/build-web.ts +20 -1
|
@@ -244,6 +244,42 @@ function makeTracker(onEvent) {
|
|
|
244
244
|
return async (e) => { if (onEvent)
|
|
245
245
|
await onEvent(e).catch(() => null); };
|
|
246
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* ★ F5 修复点。
|
|
249
|
+
* 老代码: `chainSettled = !!txHash` —— 拿到 txHash 就宣称链上已验证 (从不读 receipt/事件/确认数)。
|
|
250
|
+
* 新逻辑:
|
|
251
|
+
* · 没有 txHash → `not_attempted`, chainSettled=false (没发过链上交易)
|
|
252
|
+
* · 读不到 RPC / receipt → `unknown`, chainSettled=false (不确定 ≠ 没付)
|
|
253
|
+
* · receipt.status == 0 → `reverted`, chainSettled=false
|
|
254
|
+
* · 确认数 < 门槛 → `pending`, chainSettled=false
|
|
255
|
+
* · 事件(taskKey/resultHash)对不上 → `event_mismatch`, chainSettled=false
|
|
256
|
+
* · 全过 → `confirmed`/`finalized`, chainSettled=true
|
|
257
|
+
* 验证器本身抛错也**不会**炸付款路径: 一律降级成 `unknown` + chainSettled=false (fail-closed)。
|
|
258
|
+
*/
|
|
259
|
+
export async function verifyPaymentOnChain(args) {
|
|
260
|
+
const gate = args.chainSettlement?.gate || 'confirmed';
|
|
261
|
+
const txHash = String(args.txHash || '');
|
|
262
|
+
if (!txHash) {
|
|
263
|
+
return {
|
|
264
|
+
chainSettled: false, status: 'not_attempted',
|
|
265
|
+
reason: 'facilitator 说成功但没给 txHash: 没有链上交易可查, 不能认定链上结算完成',
|
|
266
|
+
confirmationsRequired: 0, requiredGate: gate, rpcAvailable: true, checkedAt: Date.now(), evidence: {},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const verifier = args.chainSettlement?.verifier
|
|
271
|
+
?? (await import('../chain/chain-settlement.js')).createDefaultChainSettlementVerifier({ gate });
|
|
272
|
+
return await verifier({ txHash, expect: args.chainSettlement?.expect, gate, recorded: args.chainSettlement?.recorded });
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
return {
|
|
276
|
+
chainSettled: false, status: 'unknown',
|
|
277
|
+
reason: `链上验证器抛错 → 不能判已结算: ${String(e?.message || e).slice(0, 200)}`,
|
|
278
|
+
txHash, confirmationsRequired: 0, requiredGate: gate, rpcAvailable: false,
|
|
279
|
+
checkedAt: Date.now(), evidence: { verifierError: String(e?.message || e).slice(0, 200) },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
247
283
|
export async function buyInfo(params) {
|
|
248
284
|
const { verifyEnvelope } = await import('./paid-info-protocol.js');
|
|
249
285
|
const doFetch = params.fetchImpl ?? fetch;
|
|
@@ -299,26 +335,59 @@ export async function buyInfo(params) {
|
|
|
299
335
|
const text = await retry.text();
|
|
300
336
|
const parsed = safeJson(text);
|
|
301
337
|
const receipt = retry.headers.get('x-payment-response') || parsed?.payment?.receipt || '';
|
|
338
|
+
// ★ 链上事实需要 txHash: facilitator 说成功但没有 txHash → 不能标 chainSettled (真跑抓到过这类"假结算")
|
|
339
|
+
const txHash = parsed?.payment?.txHash || retry.headers.get('x-payment-txhash') || parsed?.txHash || '';
|
|
302
340
|
if (retry.status < 200 || retry.status >= 300) {
|
|
303
341
|
// 付款这一步已经发出去了 (可能已上链), 只是拿资源失败 → 绝不许当"没付过钱"
|
|
342
|
+
// ★ F5: 有 txHash 就去链上真查一遍, 而不是"有 txHash 就算结算"
|
|
343
|
+
const v = await verifyPaymentOnChain({ txHash, chainSettlement: params.chainSettlement });
|
|
304
344
|
return {
|
|
305
345
|
ok: false, status: retry.status,
|
|
306
|
-
payment: {
|
|
346
|
+
payment: {
|
|
347
|
+
mode: 'facilitator', receipt: receipt || undefined, attempted: true, settled: true,
|
|
348
|
+
settlementUncertain: !receipt && !v.chainSettled,
|
|
349
|
+
chainSettled: v.chainSettled, chainSettlementStatus: v.status, chainSettlementReason: v.reason,
|
|
350
|
+
confirmations: v.confirmations, confirmationsRequired: v.confirmationsRequired, rpcAvailable: v.rpcAvailable,
|
|
351
|
+
...(txHash ? { txHash } : {}),
|
|
352
|
+
},
|
|
307
353
|
error: `付款后重试失败 ${retry.status}: ${text.slice(0, 200)}`,
|
|
308
354
|
};
|
|
309
355
|
}
|
|
310
356
|
mode = 'facilitator';
|
|
311
|
-
// ★
|
|
312
|
-
const
|
|
357
|
+
// ★ F5 修复: 拿到 txHash ≠ 链上已验证。真验证 = receipt(status==1) + 确认数 + 事件(taskKey/resultHash) + 合约 escrow 状态。
|
|
358
|
+
const verdict = await verifyPaymentOnChain({ txHash, chainSettlement: params.chainSettlement });
|
|
313
359
|
await trackEvent({
|
|
314
360
|
kind: 'settled',
|
|
315
|
-
detail: `mode=facilitator receipt=${receipt.slice(0, 24)}… txHash=${txHash ? `${String(txHash).slice(0, 16)}…` : '(缺失: 不能认定链上结算完成)'}
|
|
316
|
-
|
|
361
|
+
detail: `mode=facilitator receipt=${receipt.slice(0, 24)}… txHash=${txHash ? `${String(txHash).slice(0, 16)}…` : '(缺失: 不能认定链上结算完成)'} 链上判定=${verdict.status}` +
|
|
362
|
+
(verdict.confirmations != null ? ` 确认数=${verdict.confirmations}/${verdict.confirmationsRequired}` : ''),
|
|
363
|
+
patch: {
|
|
364
|
+
paymentMode: 'facilitator', paymentReceipt: receipt,
|
|
365
|
+
chainSettled: verdict.chainSettled,
|
|
366
|
+
chainSettlementStatus: verdict.status,
|
|
367
|
+
chainSettlementReason: verdict.reason,
|
|
368
|
+
...(verdict.confirmations != null ? { chainConfirmations: verdict.confirmations } : {}),
|
|
369
|
+
...(verdict.rpcAvailable ? {} : { chainRpcAvailable: false }),
|
|
370
|
+
...(txHash ? { txHash: String(txHash) } : {}),
|
|
371
|
+
},
|
|
317
372
|
});
|
|
318
373
|
const report = parsed?.proof ? await verifyEnvelope(parsed, { resolveDid: params.resolveDid, expectItemId: params.expectItemId }) : undefined;
|
|
319
374
|
if (report)
|
|
320
375
|
await trackEvent({ kind: 'delivered', detail: `trust=${report.trust}`, patch: { verificationTrust: report.trust, contentHash: parsed?.contentHash, protocolVerified: report.trust === 'verified' } });
|
|
321
|
-
return {
|
|
376
|
+
return {
|
|
377
|
+
ok: true, status: retry.status, envelope: parsed, verify: report, metadata, raw: text,
|
|
378
|
+
payment: {
|
|
379
|
+
mode, receipt,
|
|
380
|
+
...(txHash ? { txHash } : {}),
|
|
381
|
+
attempted: true, settled: true,
|
|
382
|
+
settlementUncertain: verdict.status === 'unknown' || verdict.status === 'config_unavailable' || !verdict.rpcAvailable,
|
|
383
|
+
chainSettled: verdict.chainSettled,
|
|
384
|
+
chainSettlementStatus: verdict.status,
|
|
385
|
+
chainSettlementReason: verdict.reason,
|
|
386
|
+
confirmations: verdict.confirmations,
|
|
387
|
+
confirmationsRequired: verdict.confirmationsRequired,
|
|
388
|
+
rpcAvailable: verdict.rpcAvailable,
|
|
389
|
+
},
|
|
390
|
+
};
|
|
322
391
|
}
|
|
323
392
|
if (!params.allowLocalDev) {
|
|
324
393
|
return { ok: false, status: 402, error: '需要钱包私钥才能支付 (未提供 privateKey; 本机联调请显式 allowLocalDev)' };
|