agentic-wallet-mcp 0.8.0 → 0.8.1
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 +21 -0
- package/dist/server-bundle.cjs +81 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ 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.8.1] — 19 August 2026
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **A payment blocked by the spending cap, or rejected for insufficient balance, now names the
|
|
16
|
+
real token and shows a human-readable amount** — e.g. `10000 (0.01 JMYR)` instead of a bare raw
|
|
17
|
+
integer that got mislabeled as ZTX once relayed. Affects `pay_and_fetch`, `subscribe_and_issue`,
|
|
18
|
+
and `request_ai_birthcert_verification`, since all three share the same payment step.
|
|
19
|
+
- **A wallet holding a ZTP20 token (e.g. JMYR) but zero ZTX no longer fails with a raw, opaque
|
|
20
|
+
error when trying to pay.** The wallet now checks its own ZTX gas balance before attempting the
|
|
21
|
+
payment and reports a clear "send some ZTX first" message — working around a bug in
|
|
22
|
+
`x402-zetrix-client` where its own gas check runs after an on-chain call that can itself fail
|
|
23
|
+
unhelpfully on a zero-gas account.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- The known-but-never-confirmed mainnet SSIVC host is now a named, exported constant
|
|
28
|
+
(`UNVERIFIED_MAINNET_SSIVC_BASE_URL`) instead of only living in a comment — still not wired in by
|
|
29
|
+
default (`SSIVC_BASE_URL` remains the way to enable it on mainnet), but easier to flip on once
|
|
30
|
+
confirmed reachable.
|
|
31
|
+
|
|
11
32
|
## [0.8.0] — 17 August 2026
|
|
12
33
|
|
|
13
34
|
### Added
|
package/dist/server-bundle.cjs
CHANGED
|
@@ -12548,7 +12548,7 @@ var import_node_path6 = require("node:path");
|
|
|
12548
12548
|
// package.json
|
|
12549
12549
|
var package_default = {
|
|
12550
12550
|
name: "agentic-wallet-mcp",
|
|
12551
|
-
version: "0.8.
|
|
12551
|
+
version: "0.8.1",
|
|
12552
12552
|
description: "Agent-facing MCP wallet for Zetrix \u2014 orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
|
|
12553
12553
|
keywords: [
|
|
12554
12554
|
"mcp",
|
|
@@ -21496,9 +21496,18 @@ var import_node_path = require("node:path");
|
|
|
21496
21496
|
|
|
21497
21497
|
// src/payment-guard.ts
|
|
21498
21498
|
var PaymentCapError = class extends Error {
|
|
21499
|
-
|
|
21499
|
+
/**
|
|
21500
|
+
* Set only when the failure is "requested amount exceeds the configured cap" — carries the raw
|
|
21501
|
+
* asset identifier and raw base-unit amounts so a caller with symbol/decimals resolution (e.g.
|
|
21502
|
+
* index.ts's `pay`) can rebuild a human-readable message without re-deriving these numbers.
|
|
21503
|
+
* Undefined for configuration-shaped failures (missing cap entry, malformed input), which have
|
|
21504
|
+
* no amount to render more legibly.
|
|
21505
|
+
*/
|
|
21506
|
+
detail;
|
|
21507
|
+
constructor(message, detail) {
|
|
21500
21508
|
super(message);
|
|
21501
21509
|
this.name = "PaymentCapError";
|
|
21510
|
+
this.detail = detail;
|
|
21502
21511
|
}
|
|
21503
21512
|
};
|
|
21504
21513
|
function isNonNegativeIntegerString(v) {
|
|
@@ -21538,7 +21547,10 @@ function assertWithinPaymentCap(accept, caps) {
|
|
|
21538
21547
|
const required2 = BigInt(requiredRaw);
|
|
21539
21548
|
const cap = BigInt(capRaw);
|
|
21540
21549
|
if (required2 > cap) {
|
|
21541
|
-
throw new PaymentCapError(
|
|
21550
|
+
throw new PaymentCapError(
|
|
21551
|
+
`payment blocked: requested ${required2} ${asset || "(unknown asset)"} exceeds configured MAX_PAYMENT_AMOUNT ${cap}`,
|
|
21552
|
+
{ asset, requiredRaw: required2.toString(), capRaw: cap.toString() }
|
|
21553
|
+
);
|
|
21542
21554
|
}
|
|
21543
21555
|
}
|
|
21544
21556
|
|
|
@@ -21645,6 +21657,23 @@ async function resolveAssetSymbol(asset, query) {
|
|
|
21645
21657
|
const info = await fetchTokenInfo(asset, query);
|
|
21646
21658
|
return info?.symbol ?? asset;
|
|
21647
21659
|
}
|
|
21660
|
+
var ZTX_DECIMALS = 6;
|
|
21661
|
+
async function resolveAssetInfo(asset, query) {
|
|
21662
|
+
if (asset === "ZTX") return { symbol: "ZTX", decimals: ZTX_DECIMALS };
|
|
21663
|
+
if (asset === "") return { symbol: "", decimals: 0 };
|
|
21664
|
+
const info = await fetchTokenInfo(asset, query);
|
|
21665
|
+
return info ?? { symbol: asset, decimals: 0 };
|
|
21666
|
+
}
|
|
21667
|
+
function formatHumanAmount(raw, decimals) {
|
|
21668
|
+
if (!/^\d+$/.test(raw) || decimals <= 0) return raw;
|
|
21669
|
+
const base = 10n ** BigInt(decimals);
|
|
21670
|
+
const value = BigInt(raw);
|
|
21671
|
+
const wholePart = value / base;
|
|
21672
|
+
const fracPart = value % base;
|
|
21673
|
+
if (fracPart === 0n) return wholePart.toString();
|
|
21674
|
+
const fracStr = fracPart.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
21675
|
+
return `${wholePart}.${fracStr}`;
|
|
21676
|
+
}
|
|
21648
21677
|
|
|
21649
21678
|
// src/clients/contract-query-client.ts
|
|
21650
21679
|
async function queryContract(input, query) {
|
|
@@ -21673,7 +21702,7 @@ async function queryContract(input, query) {
|
|
|
21673
21702
|
}
|
|
21674
21703
|
|
|
21675
21704
|
// src/clients/token-balance-client.ts
|
|
21676
|
-
var
|
|
21705
|
+
var ZTX_DECIMALS2 = 6;
|
|
21677
21706
|
function parseNativeBalance(res) {
|
|
21678
21707
|
if (res?.errorCode !== 0) throw new Error(`getInfo failed with errorCode ${res?.errorCode}`);
|
|
21679
21708
|
if (res.result === void 0 || res.result === null) throw new Error("getInfo returned no result");
|
|
@@ -21707,7 +21736,7 @@ async function queryTokenBalance(deps, token) {
|
|
|
21707
21736
|
const symbol = token.toUpperCase();
|
|
21708
21737
|
if (symbol === "ZTX") {
|
|
21709
21738
|
try {
|
|
21710
|
-
return { token: symbol, balance: await deps.fetchNativeBalance(deps.address), decimals:
|
|
21739
|
+
return { token: symbol, balance: await deps.fetchNativeBalance(deps.address), decimals: ZTX_DECIMALS2 };
|
|
21711
21740
|
} catch {
|
|
21712
21741
|
return { token: symbol, error: "query_failed" };
|
|
21713
21742
|
}
|
|
@@ -23705,13 +23734,53 @@ async function main() {
|
|
|
23705
23734
|
const vcCache = createFsVcCache((0, import_node_path6.join)(config2.stateDir, "vc-cache", cacheScope));
|
|
23706
23735
|
const mbi = new MbiClient(config2.mbiBaseUrl);
|
|
23707
23736
|
const messageSigner = (message) => be.signMessage(message, zetrixAddress, hsmPassword);
|
|
23708
|
-
const
|
|
23709
|
-
|
|
23710
|
-
|
|
23711
|
-
|
|
23712
|
-
|
|
23713
|
-
|
|
23714
|
-
|
|
23737
|
+
const formatAssetAmount = async (asset, raw) => {
|
|
23738
|
+
const { symbol, decimals } = await resolveAssetInfo(asset, contractQuery);
|
|
23739
|
+
const label = symbol || "(unknown asset)";
|
|
23740
|
+
const human = formatHumanAmount(raw, decimals);
|
|
23741
|
+
return human === raw ? `${raw} ${label}` : `${raw} (${human} ${label})`;
|
|
23742
|
+
};
|
|
23743
|
+
const pay = async (accept) => {
|
|
23744
|
+
const rawAsset = String(accept.asset ?? "");
|
|
23745
|
+
try {
|
|
23746
|
+
assertWithinPaymentCap(accept, config2.maxPaymentAmount);
|
|
23747
|
+
} catch (err) {
|
|
23748
|
+
if (err instanceof PaymentCapError && err.detail) {
|
|
23749
|
+
const { asset, requiredRaw, capRaw } = err.detail;
|
|
23750
|
+
throw new PaymentCapError(
|
|
23751
|
+
`payment blocked: requested ${await formatAssetAmount(asset, requiredRaw)} exceeds configured MAX_PAYMENT_AMOUNT ${await formatAssetAmount(asset, capRaw)}`,
|
|
23752
|
+
err.detail
|
|
23753
|
+
);
|
|
23754
|
+
}
|
|
23755
|
+
throw err;
|
|
23756
|
+
}
|
|
23757
|
+
if (rawAsset !== "" && rawAsset !== "ZTX") {
|
|
23758
|
+
const gasBalance = await fetchNativeBalance(zetrixAddress).catch(() => null);
|
|
23759
|
+
if (gasBalance === "0") {
|
|
23760
|
+
const { symbol } = await resolveAssetInfo(rawAsset, contractQuery);
|
|
23761
|
+
throw new PaymentReadinessError(
|
|
23762
|
+
`this wallet has 0 ZTX to pay network gas \u2014 the ${symbol || rawAsset} balance is separate from gas, and every transaction costs a small amount of ZTX regardless of which token is being paid. Send some ZTX to ${zetrixAddress} first, then retry.`,
|
|
23763
|
+
{ asset: "ZTX", required: "unknown", available: "0", reason: "gas" }
|
|
23764
|
+
);
|
|
23765
|
+
}
|
|
23766
|
+
}
|
|
23767
|
+
try {
|
|
23768
|
+
return await payWithReadinessCheck(
|
|
23769
|
+
rawAsset,
|
|
23770
|
+
() => import_x402_zetrix_client2.PaymentEngine.pay(asPayRequest(accept), walletCfg, node, {}, walletBeSignerFn),
|
|
23771
|
+
activated
|
|
23772
|
+
);
|
|
23773
|
+
} catch (err) {
|
|
23774
|
+
if (err instanceof PaymentReadinessError && err.shortfall.reason !== "not_activated") {
|
|
23775
|
+
const { asset, required: required2, available, reason } = err.shortfall;
|
|
23776
|
+
const label = reason === "gas" ? "ZTX for gas" : (await resolveAssetInfo(asset, contractQuery)).symbol || asset;
|
|
23777
|
+
throw new PaymentReadinessError(
|
|
23778
|
+
`insufficient ${label} \u2014 required ${await formatAssetAmount(asset, required2)}, available ${await formatAssetAmount(asset, available)}`,
|
|
23779
|
+
err.shortfall
|
|
23780
|
+
);
|
|
23781
|
+
}
|
|
23782
|
+
throw err;
|
|
23783
|
+
}
|
|
23715
23784
|
};
|
|
23716
23785
|
const verifyAiBirthcert = config2.ssivcBaseUrl ? (() => {
|
|
23717
23786
|
const ssivcSessionStore = createFsSsivcSessionStore((0, import_node_path6.join)(config2.stateDir, "ssivc-session.json"));
|