agentic-wallet-mcp 0.9.0 → 0.9.2
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/CHANGELOG.md +31 -0
- package/dist/server-bundle.cjs +48 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
> Entries for 0.5.0 and earlier were reconstructed from commit history when this file was
|
|
9
9
|
> introduced in 0.6.0, so they summarise each release rather than being exhaustive.
|
|
10
10
|
|
|
11
|
+
## [0.9.2] — 3 September 2026
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`request_ai_birthcert_verification`'s sponsored-payment path no longer surfaces a facilitator
|
|
16
|
+
insufficient-funds rejection as an opaque, unhandled MCP tool error.** A `461407`
|
|
17
|
+
(`X402_INSUFFICIENT_FUNDS`) rejection from the facilitator's `/prepare` endpoint is now reshaped
|
|
18
|
+
into a clean `{ error }` result naming the asset and amount, instead of falling through every
|
|
19
|
+
error branch and throwing raw.
|
|
20
|
+
- **That message now renders amounts in human units, not raw base units.** A raw base-unit count
|
|
21
|
+
next to a token symbol (e.g. "requires 1,000,000 of JMYR") reads as a million *whole* tokens —
|
|
22
|
+
for a 6-decimal asset the actual requirement was 1 JMYR, a 1,000,000x misreading that could lead
|
|
23
|
+
to a drastically oversized top-up. Amounts are now resolved through the same symbol/decimals
|
|
24
|
+
formatter the rest of the wallet already uses.
|
|
25
|
+
- **The reported "current balance" is read from the facilitator's structured response field when
|
|
26
|
+
available**, falling back to parsing it out of the free-text error message only for an
|
|
27
|
+
older/unfixed facilitator — the free-text format was never a stable contract between the two
|
|
28
|
+
services.
|
|
29
|
+
|
|
30
|
+
## [0.9.1] — 28 August 2026
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **`request_ai_birthcert_verification` no longer blocks retrying an expired session.** If the
|
|
35
|
+
owner never completed MyDigital ID verification before a Verified AI Birthcert session's TTL
|
|
36
|
+
elapsed (`status: "expired"`), retrying previously threw an "unrecognized prior session status"
|
|
37
|
+
error and left the flow stuck — even though the settlement receipt was already safely persisted
|
|
38
|
+
locally and unconsumed. Any confirmed terminal session status other than `"issued"` (the only
|
|
39
|
+
status that consumes the receipt) is now treated the same as the existing 404/"gone" handling:
|
|
40
|
+
the receipt is replayed and a fresh verification session is opened, with no new payment made.
|
|
41
|
+
|
|
11
42
|
## [0.9.0] — 24 August 2026
|
|
12
43
|
|
|
13
44
|
### Added
|
package/dist/server-bundle.cjs
CHANGED
|
@@ -12549,7 +12549,7 @@ var import_node_path6 = require("node:path");
|
|
|
12549
12549
|
// package.json
|
|
12550
12550
|
var package_default = {
|
|
12551
12551
|
name: "agentic-wallet-mcp",
|
|
12552
|
-
version: "0.9.
|
|
12552
|
+
version: "0.9.2",
|
|
12553
12553
|
description: "Agent-facing MCP wallet for Zetrix \u2014 orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
|
|
12554
12554
|
keywords: [
|
|
12555
12555
|
"mcp",
|
|
@@ -23406,13 +23406,14 @@ async function decidePriorSession(deps, agentName) {
|
|
|
23406
23406
|
if (stored.agentName !== agentName) {
|
|
23407
23407
|
const otherStatus = await getConfirmedStatus(deps, stored.sessionId);
|
|
23408
23408
|
if (otherStatus === "gone") return { kind: "replay_receipt", receipt: stored.paymentReceipt };
|
|
23409
|
-
if (otherStatus.status
|
|
23409
|
+
if (otherStatus.status === "pending") {
|
|
23410
23410
|
return {
|
|
23411
23411
|
kind: "blocked",
|
|
23412
|
-
message: `a verification session for a different agent ("${stored.agentName}") is still in progress (status: "
|
|
23412
|
+
message: `a verification session for a different agent ("${stored.agentName}") is still in progress (status: "pending") and its payment has not been consumed yet \u2014 starting a new session for "${agentName}" would lose track of it. Call check_ai_birthcert_verification to resolve or confirm it first.`
|
|
23413
23413
|
};
|
|
23414
23414
|
}
|
|
23415
|
-
return { kind: "pay_fresh" };
|
|
23415
|
+
if (otherStatus.status === "issued") return { kind: "pay_fresh" };
|
|
23416
|
+
return { kind: "replay_receipt", receipt: stored.paymentReceipt };
|
|
23416
23417
|
}
|
|
23417
23418
|
const status = await getConfirmedStatus(deps, stored.sessionId);
|
|
23418
23419
|
if (status === "gone") return { kind: "replay_receipt", receipt: stored.paymentReceipt };
|
|
@@ -23423,9 +23424,7 @@ async function decidePriorSession(deps, agentName) {
|
|
|
23423
23424
|
};
|
|
23424
23425
|
}
|
|
23425
23426
|
if (status.status === "issued") return { kind: "pay_fresh" };
|
|
23426
|
-
|
|
23427
|
-
`requestAiBirthcertVerification: unrecognized prior session status "${status.status}" for session ${stored.sessionId} \u2014 refusing to guess whether its settlement receipt is safe to replay (see SPEC.md D8)`
|
|
23428
|
-
);
|
|
23427
|
+
return { kind: "replay_receipt", receipt: stored.paymentReceipt };
|
|
23429
23428
|
}
|
|
23430
23429
|
var requestQueue = Promise.resolve();
|
|
23431
23430
|
function withRequestLock(fn) {
|
|
@@ -23497,6 +23496,7 @@ var DEFINITIVE_PREPARE_REFUSALS = /* @__PURE__ */ new Set([
|
|
|
23497
23496
|
461415
|
|
23498
23497
|
// X402_UNSUPPORTED_ASSET — sponsorship is ZTP-20 only
|
|
23499
23498
|
]);
|
|
23499
|
+
var FACILITATOR_INSUFFICIENT_FUNDS_CODE = 461407;
|
|
23500
23500
|
function facilitatorErrorCode(err) {
|
|
23501
23501
|
const m = /"errorCode"\s*:\s*(\d{6})/.exec(err instanceof Error ? err.message : String(err));
|
|
23502
23502
|
return m ? Number(m[1]) : void 0;
|
|
@@ -23516,6 +23516,41 @@ function isDefinitiveSponsorshipFailure(err) {
|
|
|
23516
23516
|
if (code === void 0) return false;
|
|
23517
23517
|
return DEFINITIVE_PREPARE_REFUSALS.has(code);
|
|
23518
23518
|
}
|
|
23519
|
+
var FacilitatorInsufficientFundsError = class extends Error {
|
|
23520
|
+
constructor(requiredHuman, availableHuman, rawMessage) {
|
|
23521
|
+
super(
|
|
23522
|
+
`insufficient funds: the sponsored payment requires ${requiredHuman}` + (availableHuman !== void 0 ? ` \u2014 this wallet currently holds ${availableHuman}` : " and this wallet does not hold enough of it") + ` (facilitator: ${rawMessage})`
|
|
23523
|
+
);
|
|
23524
|
+
this.name = "FacilitatorInsufficientFundsError";
|
|
23525
|
+
}
|
|
23526
|
+
};
|
|
23527
|
+
function extractFacilitatorBalance(rawMessage) {
|
|
23528
|
+
const braceIdx = rawMessage.indexOf("{");
|
|
23529
|
+
if (braceIdx !== -1) {
|
|
23530
|
+
try {
|
|
23531
|
+
const body = JSON.parse(rawMessage.slice(braceIdx));
|
|
23532
|
+
const detail = body.messages?.[0]?.detail;
|
|
23533
|
+
if (Array.isArray(detail) && detail.length >= 3 && detail[2] !== null && detail[2] !== void 0) {
|
|
23534
|
+
return String(detail[2]);
|
|
23535
|
+
}
|
|
23536
|
+
} catch {
|
|
23537
|
+
}
|
|
23538
|
+
}
|
|
23539
|
+
const m = /insufficient_funds \[[^,]+,\s*[^,]+,\s*([^\]]+)\]/.exec(rawMessage);
|
|
23540
|
+
return m ? m[1].trim() : void 0;
|
|
23541
|
+
}
|
|
23542
|
+
async function toFacilitatorInsufficientFundsError(err, accept, formatAssetAmount) {
|
|
23543
|
+
if (!(err instanceof PrepareStageError)) return err;
|
|
23544
|
+
if (facilitatorErrorCode(err.cause) !== FACILITATOR_INSUFFICIENT_FUNDS_CODE) return err;
|
|
23545
|
+
const asset = accept.asset ?? "";
|
|
23546
|
+
const maxAmountRequired = accept.maxAmountRequired ?? "";
|
|
23547
|
+
if (!asset || !maxAmountRequired) return err;
|
|
23548
|
+
const rawMessage = err.cause instanceof Error ? err.cause.message : String(err.cause);
|
|
23549
|
+
const requiredHuman = formatAssetAmount ? await formatAssetAmount(asset, maxAmountRequired) : `${maxAmountRequired} of asset "${asset}"`;
|
|
23550
|
+
const availableRaw = extractFacilitatorBalance(rawMessage);
|
|
23551
|
+
const availableHuman = availableRaw !== void 0 && formatAssetAmount ? await formatAssetAmount(asset, availableRaw) : availableRaw;
|
|
23552
|
+
return new FacilitatorInsufficientFundsError(requiredHuman, availableHuman, rawMessage);
|
|
23553
|
+
}
|
|
23519
23554
|
async function attemptCandidate(deps, accept, buildBody, onQueued) {
|
|
23520
23555
|
let xPayment;
|
|
23521
23556
|
try {
|
|
@@ -23535,8 +23570,9 @@ async function payAndCreateSession(deps, buildBody, onQueued) {
|
|
|
23535
23570
|
return await attemptCandidate(deps, primary, buildBody, onQueued);
|
|
23536
23571
|
} catch (err) {
|
|
23537
23572
|
const fallback = candidates[1];
|
|
23538
|
-
if (!fallback || !isSponsored(primary) || isSponsored(fallback)
|
|
23539
|
-
|
|
23573
|
+
if (!fallback || !isSponsored(primary) || isSponsored(fallback) || !isDefinitiveSponsorshipFailure(err)) {
|
|
23574
|
+
throw await toFacilitatorInsufficientFundsError(err, primary, deps.formatAssetAmount);
|
|
23575
|
+
}
|
|
23540
23576
|
return await attemptCandidate(deps, fallback, buildBody, onQueued);
|
|
23541
23577
|
}
|
|
23542
23578
|
}
|
|
@@ -23606,6 +23642,7 @@ async function requestAiBirthcertVerificationLocked(deps, agentName, input) {
|
|
|
23606
23642
|
if (err instanceof PaymentReadinessError) return { error: `insufficient funds: ${err.message}` };
|
|
23607
23643
|
if (err instanceof PaymentCapError) return { error: err.message };
|
|
23608
23644
|
if (err instanceof NoPaymentOptionsError) return { error: err.message };
|
|
23645
|
+
if (err instanceof FacilitatorInsufficientFundsError) return { error: err.message };
|
|
23609
23646
|
if (err instanceof SettlementStillQueuedError) {
|
|
23610
23647
|
try {
|
|
23611
23648
|
await deps.sessionStore.set({
|
|
@@ -24016,7 +24053,8 @@ async function main() {
|
|
|
24016
24053
|
cache: vcCache,
|
|
24017
24054
|
quarantine: downloadQuarantine,
|
|
24018
24055
|
gasPreference: config2.gasPreference,
|
|
24019
|
-
maxSettlementAttempts: config2.maxSettlementAttempts
|
|
24056
|
+
maxSettlementAttempts: config2.maxSettlementAttempts,
|
|
24057
|
+
formatAssetAmount
|
|
24020
24058
|
};
|
|
24021
24059
|
return {
|
|
24022
24060
|
request: (input) => requestAiBirthcertVerification(verifyAiBirthcertDeps, input),
|