agentic-wallet-mcp 0.4.2 → 0.6.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.
- package/CHANGELOG.md +138 -0
- package/README.md +88 -6
- package/dist/server-bundle.cjs +789 -56
- package/package.json +11 -2
package/dist/server-bundle.cjs
CHANGED
|
@@ -2233,8 +2233,8 @@ var require_resolve = __commonJS({
|
|
|
2233
2233
|
}
|
|
2234
2234
|
return count;
|
|
2235
2235
|
}
|
|
2236
|
-
function getFullPath(resolver, id = "",
|
|
2237
|
-
if (
|
|
2236
|
+
function getFullPath(resolver, id = "", normalize3) {
|
|
2237
|
+
if (normalize3 !== false)
|
|
2238
2238
|
id = normalizeId(id);
|
|
2239
2239
|
const p = resolver.parse(id);
|
|
2240
2240
|
return _getFullPath(resolver, p);
|
|
@@ -3630,7 +3630,7 @@ var require_fast_uri = __commonJS({
|
|
|
3630
3630
|
"use strict";
|
|
3631
3631
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3632
3632
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3633
|
-
function
|
|
3633
|
+
function normalize3(uri, options) {
|
|
3634
3634
|
if (typeof uri === "string") {
|
|
3635
3635
|
uri = /** @type {T} */
|
|
3636
3636
|
normalizeString(uri, options);
|
|
@@ -3897,7 +3897,7 @@ var require_fast_uri = __commonJS({
|
|
|
3897
3897
|
}
|
|
3898
3898
|
var fastUri = {
|
|
3899
3899
|
SCHEMES,
|
|
3900
|
-
normalize:
|
|
3900
|
+
normalize: normalize3,
|
|
3901
3901
|
resolve,
|
|
3902
3902
|
resolveComponent,
|
|
3903
3903
|
equal,
|
|
@@ -8541,13 +8541,13 @@ var require_path = __commonJS({
|
|
|
8541
8541
|
return /^(?:\/|\w+:)/.test(path2);
|
|
8542
8542
|
}
|
|
8543
8543
|
);
|
|
8544
|
-
var
|
|
8544
|
+
var normalize3 = (
|
|
8545
8545
|
/**
|
|
8546
8546
|
* Normalizes the specified path.
|
|
8547
8547
|
* @param {string} path Path to normalize
|
|
8548
8548
|
* @returns {string} Normalized path
|
|
8549
8549
|
*/
|
|
8550
|
-
path.normalize = function
|
|
8550
|
+
path.normalize = function normalize4(path2) {
|
|
8551
8551
|
path2 = path2.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
8552
8552
|
var parts = path2.split("/"), absolute = isAbsolute(path2), prefix = "";
|
|
8553
8553
|
if (absolute)
|
|
@@ -8570,12 +8570,12 @@ var require_path = __commonJS({
|
|
|
8570
8570
|
);
|
|
8571
8571
|
path.resolve = function resolve(originPath, includePath, alreadyNormalized) {
|
|
8572
8572
|
if (!alreadyNormalized)
|
|
8573
|
-
includePath =
|
|
8573
|
+
includePath = normalize3(includePath);
|
|
8574
8574
|
if (isAbsolute(includePath))
|
|
8575
8575
|
return includePath;
|
|
8576
8576
|
if (!alreadyNormalized)
|
|
8577
|
-
originPath =
|
|
8578
|
-
return (originPath = originPath.replace(/(?:\/|^)[^/]+$/, "")).length ?
|
|
8577
|
+
originPath = normalize3(originPath);
|
|
8578
|
+
return (originPath = originPath.replace(/(?:\/|^)[^/]+$/, "")).length ? normalize3(originPath + "/" + includePath) : includePath;
|
|
8579
8579
|
};
|
|
8580
8580
|
}
|
|
8581
8581
|
});
|
|
@@ -12192,7 +12192,7 @@ var require_payment_engine = __commonJS({
|
|
|
12192
12192
|
var blob_decoder_1 = require_blob_decoder();
|
|
12193
12193
|
var prepare_client_1 = require_prepare_client();
|
|
12194
12194
|
var _sdkCtor = require("zetrix-sdk-nodejs");
|
|
12195
|
-
var
|
|
12195
|
+
var InsufficientBalanceError2 = class _InsufficientBalanceError extends Error {
|
|
12196
12196
|
constructor(message, required2, available, asset) {
|
|
12197
12197
|
super(message);
|
|
12198
12198
|
this.required = required2;
|
|
@@ -12202,7 +12202,7 @@ var require_payment_engine = __commonJS({
|
|
|
12202
12202
|
Object.setPrototypeOf(this, _InsufficientBalanceError.prototype);
|
|
12203
12203
|
}
|
|
12204
12204
|
};
|
|
12205
|
-
exports2.InsufficientBalanceError =
|
|
12205
|
+
exports2.InsufficientBalanceError = InsufficientBalanceError2;
|
|
12206
12206
|
exports2.PaymentEngine = {
|
|
12207
12207
|
/**
|
|
12208
12208
|
* Create a Zetrix SDK instance for the given node config.
|
|
@@ -12295,20 +12295,20 @@ var require_payment_engine = __commonJS({
|
|
|
12295
12295
|
const { balance } = await exports2.PaymentEngine.fetchAccountInfo(wallet.address, node);
|
|
12296
12296
|
const required2 = amount + fee;
|
|
12297
12297
|
if (BigInt(balance) < required2) {
|
|
12298
|
-
throw new
|
|
12298
|
+
throw new InsufficientBalanceError2(`Insufficient ZTX: required ${required2}, available ${balance}`, String(required2), balance, "ZTX");
|
|
12299
12299
|
}
|
|
12300
12300
|
return;
|
|
12301
12301
|
}
|
|
12302
12302
|
if (!opts.skipTokenCheck) {
|
|
12303
12303
|
const { balance: tokenBal } = await exports2.PaymentEngine.fetchZTP20Balance(req.asset, wallet.address, node);
|
|
12304
12304
|
if (BigInt(tokenBal) < amount) {
|
|
12305
|
-
throw new
|
|
12305
|
+
throw new InsufficientBalanceError2(`Insufficient ${req.asset}: required ${req.maxAmountRequired}, available ${tokenBal}`, req.maxAmountRequired, tokenBal, req.asset);
|
|
12306
12306
|
}
|
|
12307
12307
|
}
|
|
12308
12308
|
if (fee > 0n) {
|
|
12309
12309
|
const { balance: ztxBal } = await exports2.PaymentEngine.fetchAccountInfo(wallet.address, node);
|
|
12310
12310
|
if (BigInt(ztxBal) < fee) {
|
|
12311
|
-
throw new
|
|
12311
|
+
throw new InsufficientBalanceError2(`Insufficient ZTX for gas: required ${feeLimit}, available ${ztxBal}`, feeLimit, ztxBal, "ZTX");
|
|
12312
12312
|
}
|
|
12313
12313
|
}
|
|
12314
12314
|
},
|
|
@@ -12547,9 +12547,17 @@ var import_node_path3 = require("node:path");
|
|
|
12547
12547
|
// package.json
|
|
12548
12548
|
var package_default = {
|
|
12549
12549
|
name: "agentic-wallet-mcp",
|
|
12550
|
-
version: "0.
|
|
12550
|
+
version: "0.6.0",
|
|
12551
12551
|
description: "Agent-facing MCP wallet for Zetrix \u2014 orchestrates x401 identity proof, x402 payment, and MBI VC issuance",
|
|
12552
|
-
keywords: [
|
|
12552
|
+
keywords: [
|
|
12553
|
+
"mcp",
|
|
12554
|
+
"model-context-protocol",
|
|
12555
|
+
"zetrix",
|
|
12556
|
+
"wallet",
|
|
12557
|
+
"x401",
|
|
12558
|
+
"x402",
|
|
12559
|
+
"blockchain"
|
|
12560
|
+
],
|
|
12553
12561
|
license: "MIT",
|
|
12554
12562
|
author: "MyEG Services Berhad",
|
|
12555
12563
|
homepage: "https://github.com/Zetrix-Chain/zetrix-agentic-wallet",
|
|
@@ -12570,6 +12578,7 @@ var package_default = {
|
|
|
12570
12578
|
files: [
|
|
12571
12579
|
"dist/server-bundle.cjs",
|
|
12572
12580
|
"README.md",
|
|
12581
|
+
"CHANGELOG.md",
|
|
12573
12582
|
"LICENSE"
|
|
12574
12583
|
],
|
|
12575
12584
|
scripts: {
|
|
@@ -21159,7 +21168,7 @@ var StdioServerTransport = class {
|
|
|
21159
21168
|
};
|
|
21160
21169
|
|
|
21161
21170
|
// src/index.ts
|
|
21162
|
-
var
|
|
21171
|
+
var import_x402_zetrix_client2 = __toESM(require_dist2(), 1);
|
|
21163
21172
|
|
|
21164
21173
|
// node_modules/x401-zetrix-client/dist/config.js
|
|
21165
21174
|
var ZETRIX_OID4VP_URLS = {
|
|
@@ -21547,6 +21556,14 @@ function deriveMbiBaseUrl(network) {
|
|
|
21547
21556
|
function deriveTemplateRegistryAddress(network) {
|
|
21548
21557
|
return network.includes("testnet") ? "ZTX3JszqPgRUx743SAp7q7zURfjvkWuH2FMEz" : "ZTX3GqJM1U6ifMPonwD4fGvrgoTKJua7b2cKX";
|
|
21549
21558
|
}
|
|
21559
|
+
var TOKEN_REGISTRY = {
|
|
21560
|
+
JMYR: { testnet: "ZTX3WeinXtt28YMyr4vUZ14ddTgEMGeuc1e6b", mainnet: "ZTX3NCkXBqbyJWjZZxciQez945Lu6tGAcjNJr" }
|
|
21561
|
+
};
|
|
21562
|
+
function resolveTokenAddress(symbol, network) {
|
|
21563
|
+
const entry = TOKEN_REGISTRY[symbol.toUpperCase()];
|
|
21564
|
+
if (!entry) return void 0;
|
|
21565
|
+
return network.includes("testnet") ? entry.testnet : entry.mainnet;
|
|
21566
|
+
}
|
|
21550
21567
|
function loadConfig(env) {
|
|
21551
21568
|
const req = (key, hint) => {
|
|
21552
21569
|
const v = env[key];
|
|
@@ -21609,6 +21626,75 @@ async function resolveAssetSymbol(asset, query) {
|
|
|
21609
21626
|
return info?.symbol ?? asset;
|
|
21610
21627
|
}
|
|
21611
21628
|
|
|
21629
|
+
// src/clients/contract-query-client.ts
|
|
21630
|
+
async function queryContract(input, query) {
|
|
21631
|
+
let response;
|
|
21632
|
+
try {
|
|
21633
|
+
response = await query({
|
|
21634
|
+
contractAddress: input.contractAddress,
|
|
21635
|
+
input: JSON.stringify({ method: input.method, params: input.params ?? {} }),
|
|
21636
|
+
optType: 2
|
|
21637
|
+
});
|
|
21638
|
+
} catch (e) {
|
|
21639
|
+
return { ok: false, error: `query_contract: RPC call failed \u2014 ${e.message}` };
|
|
21640
|
+
}
|
|
21641
|
+
if (response.errorCode !== 0) {
|
|
21642
|
+
return { ok: false, error: `query_contract: contract call failed with errorCode ${response.errorCode}` };
|
|
21643
|
+
}
|
|
21644
|
+
const raw = response.result?.query_rets?.[0]?.result?.value;
|
|
21645
|
+
if (raw === void 0) {
|
|
21646
|
+
return { ok: false, error: "query_contract: no result value returned" };
|
|
21647
|
+
}
|
|
21648
|
+
try {
|
|
21649
|
+
return { ok: true, result: JSON.parse(raw) };
|
|
21650
|
+
} catch {
|
|
21651
|
+
return { ok: true, result: raw };
|
|
21652
|
+
}
|
|
21653
|
+
}
|
|
21654
|
+
|
|
21655
|
+
// src/clients/token-balance-client.ts
|
|
21656
|
+
var ZTX_DECIMALS = 6;
|
|
21657
|
+
async function fetchZTP20BalanceStrict(contractAddress, address, query) {
|
|
21658
|
+
const result = await query({
|
|
21659
|
+
contractAddress,
|
|
21660
|
+
input: JSON.stringify({ method: "balanceOf", params: { address } }),
|
|
21661
|
+
optType: 2
|
|
21662
|
+
});
|
|
21663
|
+
if (result?.errorCode !== 0) {
|
|
21664
|
+
throw new Error(`balanceOf failed with errorCode ${result?.errorCode}`);
|
|
21665
|
+
}
|
|
21666
|
+
const raw = result.result?.query_rets?.[0]?.result?.value;
|
|
21667
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
21668
|
+
throw new Error("balanceOf returned no value");
|
|
21669
|
+
}
|
|
21670
|
+
const parsed = JSON.parse(raw);
|
|
21671
|
+
const balance = parsed?.balance;
|
|
21672
|
+
if (typeof balance !== "string") {
|
|
21673
|
+
throw new Error("balanceOf returned no balance field");
|
|
21674
|
+
}
|
|
21675
|
+
return balance;
|
|
21676
|
+
}
|
|
21677
|
+
async function queryTokenBalance(deps, token) {
|
|
21678
|
+
const symbol = token.toUpperCase();
|
|
21679
|
+
if (symbol === "ZTX") {
|
|
21680
|
+
try {
|
|
21681
|
+
return { token: symbol, balance: await deps.fetchNativeBalance(deps.address), decimals: ZTX_DECIMALS };
|
|
21682
|
+
} catch {
|
|
21683
|
+
return { token: symbol, error: "query_failed" };
|
|
21684
|
+
}
|
|
21685
|
+
}
|
|
21686
|
+
const contractAddress = deps.resolveTokenAddress(symbol);
|
|
21687
|
+
if (!contractAddress) return { token: symbol, error: "unknown_token" };
|
|
21688
|
+
let balance;
|
|
21689
|
+
try {
|
|
21690
|
+
balance = await fetchZTP20BalanceStrict(contractAddress, deps.address, deps.query);
|
|
21691
|
+
} catch {
|
|
21692
|
+
return { token: symbol, error: "query_failed" };
|
|
21693
|
+
}
|
|
21694
|
+
const info = await fetchTokenInfo(contractAddress, deps.query);
|
|
21695
|
+
return { token: symbol, balance, decimals: info?.decimals ?? null };
|
|
21696
|
+
}
|
|
21697
|
+
|
|
21612
21698
|
// src/clients/template-info-client.ts
|
|
21613
21699
|
async function fetchTemplateFields(templateId, registryAddress, nodeBaseUrl, query) {
|
|
21614
21700
|
const key = `template__${templateId}`;
|
|
@@ -21667,6 +21753,10 @@ var WalletBeClient = class {
|
|
|
21667
21753
|
createAccount(password, label, purpose) {
|
|
21668
21754
|
return this.post("/wallet/hsm/account/create", { password, label, purpose });
|
|
21669
21755
|
}
|
|
21756
|
+
/** GET /wallet/hsm/account/activate/status — ground-truth on-chain activation check (no local state). */
|
|
21757
|
+
checkActivationStatus(address) {
|
|
21758
|
+
return this.get("/wallet/hsm/account/activate/status", { address });
|
|
21759
|
+
}
|
|
21670
21760
|
async post(path, body) {
|
|
21671
21761
|
const url = `${this.baseUrl}${path}`;
|
|
21672
21762
|
let res;
|
|
@@ -21694,6 +21784,25 @@ var WalletBeClient = class {
|
|
|
21694
21784
|
}
|
|
21695
21785
|
return env.data;
|
|
21696
21786
|
}
|
|
21787
|
+
async get(path, query) {
|
|
21788
|
+
const url = `${this.baseUrl}${path}?${new URLSearchParams(query).toString()}`;
|
|
21789
|
+
let res;
|
|
21790
|
+
try {
|
|
21791
|
+
res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
21792
|
+
} catch (e) {
|
|
21793
|
+
throw new WalletBeError(`Wallet BE ${path} request failed`, void 0, e);
|
|
21794
|
+
}
|
|
21795
|
+
if (!res.ok) {
|
|
21796
|
+
const text = await res.text().catch(() => "");
|
|
21797
|
+
throw new WalletBeError(`Wallet BE ${path} HTTP ${res.status}: ${text}`);
|
|
21798
|
+
}
|
|
21799
|
+
const env = await res.json();
|
|
21800
|
+
if (env.errorCode !== 0) {
|
|
21801
|
+
const detail = env.data?.errorList?.length ? ` \u2014 ${env.data.errorList.join("; ")}` : "";
|
|
21802
|
+
throw new WalletBeError(`Wallet BE ${path} errorCode ${env.errorCode}: ${env.message ?? "error"}${detail}`, env.errorCode);
|
|
21803
|
+
}
|
|
21804
|
+
return env.data;
|
|
21805
|
+
}
|
|
21697
21806
|
};
|
|
21698
21807
|
|
|
21699
21808
|
// src/signer.ts
|
|
@@ -21803,16 +21912,35 @@ var MbiVpAdapter = class {
|
|
|
21803
21912
|
// src/clients/mbi-client.ts
|
|
21804
21913
|
var MbiError = class extends Error {
|
|
21805
21914
|
httpStatus;
|
|
21806
|
-
|
|
21915
|
+
/**
|
|
21916
|
+
* MBI's own numeric code from the ResponseWrapper body — finer-grained than the HTTP status
|
|
21917
|
+
* and the only reliable way to tell a *definitive* post-payment failure from an indeterminate
|
|
21918
|
+
* one. Undefined when the body carries no numeric `status`.
|
|
21919
|
+
*/
|
|
21920
|
+
mbiStatus;
|
|
21921
|
+
constructor(message, httpStatus, mbiStatus) {
|
|
21807
21922
|
super(message);
|
|
21808
21923
|
this.name = "MbiError";
|
|
21809
21924
|
this.httpStatus = httpStatus;
|
|
21925
|
+
this.mbiStatus = mbiStatus;
|
|
21810
21926
|
}
|
|
21811
21927
|
};
|
|
21928
|
+
var MBI_SETTLEMENT_INDETERMINATE = 4012;
|
|
21812
21929
|
var MbiClient = class _MbiClient {
|
|
21813
21930
|
baseUrl;
|
|
21814
|
-
|
|
21931
|
+
/** Per-request deadline in ms. See {@link MbiClient.DEFAULT_TIMEOUT_MS}. */
|
|
21932
|
+
timeoutMs;
|
|
21933
|
+
/**
|
|
21934
|
+
* MBI's own facilitator read timeout is 60s, and `/settle` submits
|
|
21935
|
+
* a transaction on chain. A client deadline at or below that would abort a settle MBI is
|
|
21936
|
+
* still legitimately waiting on — manufacturing exactly the indeterminate outcome that MR
|
|
21937
|
+
* exists to prevent, except on our side where nothing records it. Sits above 60s so MBI
|
|
21938
|
+
* always gets to answer first; raise it in step if MBI's own timeout is ever raised.
|
|
21939
|
+
*/
|
|
21940
|
+
static DEFAULT_TIMEOUT_MS = 9e4;
|
|
21941
|
+
constructor(baseUrl, opts) {
|
|
21815
21942
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
21943
|
+
this.timeoutMs = opts?.timeoutMs ?? _MbiClient.DEFAULT_TIMEOUT_MS;
|
|
21816
21944
|
}
|
|
21817
21945
|
/**
|
|
21818
21946
|
* Phase 1 — POST /v1/vc/pay/apply without X-PAYMENT; expects the 402 challenge.
|
|
@@ -21862,6 +21990,7 @@ var MbiClient = class _MbiClient {
|
|
|
21862
21990
|
return fetch(`${this.baseUrl}${path}`, {
|
|
21863
21991
|
method,
|
|
21864
21992
|
headers,
|
|
21993
|
+
signal: AbortSignal.timeout(this.timeoutMs),
|
|
21865
21994
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
21866
21995
|
}).catch((e) => {
|
|
21867
21996
|
throw new MbiError(`MBI ${path} request failed: ${e.message}`);
|
|
@@ -21876,13 +22005,15 @@ var MbiClient = class _MbiClient {
|
|
|
21876
22005
|
async error(res, context) {
|
|
21877
22006
|
const text = await res.text().catch(() => "");
|
|
21878
22007
|
let msg = text;
|
|
22008
|
+
let mbiStatus;
|
|
21879
22009
|
try {
|
|
21880
22010
|
const j = JSON.parse(text);
|
|
22011
|
+
if (typeof j.status === "number") mbiStatus = j.status;
|
|
21881
22012
|
const truncated = text.length > _MbiClient.ERROR_BODY_MAX_LEN ? `${text.slice(0, _MbiClient.ERROR_BODY_MAX_LEN)}\u2026 (truncated, ${text.length} bytes total)` : text;
|
|
21882
22013
|
msg = `${j.message ?? j.error ?? text} | full body: ${truncated}`;
|
|
21883
22014
|
} catch {
|
|
21884
22015
|
}
|
|
21885
|
-
return new MbiError(`MBI ${context} \u2014 HTTP ${res.status}: ${msg}`, res.status);
|
|
22016
|
+
return new MbiError(`MBI ${context} \u2014 HTTP ${res.status}: ${msg}`, res.status, mbiStatus);
|
|
21886
22017
|
}
|
|
21887
22018
|
};
|
|
21888
22019
|
|
|
@@ -22027,6 +22158,19 @@ function isVcValid(entry, now = /* @__PURE__ */ new Date()) {
|
|
|
22027
22158
|
if (Number.isNaN(expiry.getTime())) return false;
|
|
22028
22159
|
return expiry.getTime() > now.getTime();
|
|
22029
22160
|
}
|
|
22161
|
+
function extractAttributeKeys(vc) {
|
|
22162
|
+
if (typeof vc !== "object" || vc === null) return [];
|
|
22163
|
+
const subject = vc.credentialSubject;
|
|
22164
|
+
if (typeof subject !== "object" || subject === null) return [];
|
|
22165
|
+
const keys = /* @__PURE__ */ new Set();
|
|
22166
|
+
for (const [key, value] of Object.entries(subject)) {
|
|
22167
|
+
if (key === "id") continue;
|
|
22168
|
+
if (typeof value === "object" && value !== null) {
|
|
22169
|
+
for (const inner of Object.keys(value)) keys.add(inner);
|
|
22170
|
+
}
|
|
22171
|
+
}
|
|
22172
|
+
return [...keys];
|
|
22173
|
+
}
|
|
22030
22174
|
function extractValidUntil(vc, fallback) {
|
|
22031
22175
|
if (typeof vc === "object" && vc !== null && "validUntil" in vc) {
|
|
22032
22176
|
const v = vc.validUntil;
|
|
@@ -22035,36 +22179,99 @@ function extractValidUntil(vc, fallback) {
|
|
|
22035
22179
|
return fallback;
|
|
22036
22180
|
}
|
|
22037
22181
|
|
|
22182
|
+
// src/payment-readiness.ts
|
|
22183
|
+
var import_x402_zetrix_client = __toESM(require_dist2(), 1);
|
|
22184
|
+
var PaymentReadinessError = class extends Error {
|
|
22185
|
+
shortfall;
|
|
22186
|
+
constructor(message, shortfall) {
|
|
22187
|
+
super(message);
|
|
22188
|
+
this.name = "PaymentReadinessError";
|
|
22189
|
+
this.shortfall = shortfall;
|
|
22190
|
+
}
|
|
22191
|
+
};
|
|
22192
|
+
function toPaymentReadinessError(err, requestedAsset) {
|
|
22193
|
+
if (!(err instanceof import_x402_zetrix_client.InsufficientBalanceError)) return null;
|
|
22194
|
+
const reason = err.asset === "ZTX" && requestedAsset !== "ZTX" ? "gas" : "resource_payment";
|
|
22195
|
+
return new PaymentReadinessError(err.message, {
|
|
22196
|
+
asset: err.asset,
|
|
22197
|
+
required: err.required,
|
|
22198
|
+
available: err.available,
|
|
22199
|
+
reason
|
|
22200
|
+
});
|
|
22201
|
+
}
|
|
22202
|
+
async function payWithReadinessCheck(requestedAsset, rawPay) {
|
|
22203
|
+
try {
|
|
22204
|
+
return await rawPay();
|
|
22205
|
+
} catch (err) {
|
|
22206
|
+
const readinessError = toPaymentReadinessError(err, requestedAsset);
|
|
22207
|
+
if (readinessError) throw readinessError;
|
|
22208
|
+
throw err;
|
|
22209
|
+
}
|
|
22210
|
+
}
|
|
22211
|
+
|
|
22038
22212
|
// src/orchestrator/subscribe.ts
|
|
22213
|
+
function diffAgainstTemplate(vc, fields) {
|
|
22214
|
+
const held = new Set(extractAttributeKeys(vc));
|
|
22215
|
+
const missing = fields.required.filter((k) => !held.has(k));
|
|
22216
|
+
const dropped = [...held].filter((k) => !fields.allKeys.includes(k));
|
|
22217
|
+
return missing.length > 0 || dropped.length > 0 ? { missing, dropped } : void 0;
|
|
22218
|
+
}
|
|
22219
|
+
var TERMINAL_SETTLEMENT_STATUSES = /* @__PURE__ */ new Set(["ISSUED", "FAILED"]);
|
|
22220
|
+
var RECOVERY_MAX_POLLS = 5;
|
|
22221
|
+
var RECOVERY_POLL_DELAY_MS = 2e3;
|
|
22222
|
+
async function pollSettlementOutcome(deps, paymentId) {
|
|
22223
|
+
if (!deps.mbi.getStatus) return void 0;
|
|
22224
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
22225
|
+
let last;
|
|
22226
|
+
for (let polls = 1; polls <= RECOVERY_MAX_POLLS; polls++) {
|
|
22227
|
+
let status;
|
|
22228
|
+
try {
|
|
22229
|
+
status = await deps.mbi.getStatus(paymentId);
|
|
22230
|
+
} catch {
|
|
22231
|
+
return { status: "UNKNOWN", ...last ? { txHash: last.txHash, vcId: last.vcId } : {}, polls };
|
|
22232
|
+
}
|
|
22233
|
+
last = { status: status.status, txHash: status.txHash, vcId: status.vcId };
|
|
22234
|
+
if (TERMINAL_SETTLEMENT_STATUSES.has(status.status)) {
|
|
22235
|
+
return { status: status.status, txHash: status.txHash, vcId: status.vcId, polls };
|
|
22236
|
+
}
|
|
22237
|
+
if (polls < RECOVERY_MAX_POLLS) await sleep(RECOVERY_POLL_DELAY_MS);
|
|
22238
|
+
}
|
|
22239
|
+
return { ...last, polls: RECOVERY_MAX_POLLS };
|
|
22240
|
+
}
|
|
22039
22241
|
async function subscribeAndIssue(deps, opts) {
|
|
22040
22242
|
if (!/^did:zid:/.test(opts.templateId)) {
|
|
22041
22243
|
return { issued: false, reason: `templateId must be a did:zid:... credential-definition id, got "${opts.templateId}"` };
|
|
22042
22244
|
}
|
|
22245
|
+
const fields = deps.resolveTemplateFields ? await deps.resolveTemplateFields(opts.templateId) : null;
|
|
22246
|
+
const schema = fields ? { required: fields.required, optional: fields.allKeys.filter((k) => !fields.required.includes(k)) } : void 0;
|
|
22043
22247
|
if (deps.cache && !opts.forceReissue && !opts.dryRun) {
|
|
22044
22248
|
const cached2 = await deps.cache.get(opts.templateId);
|
|
22045
22249
|
if (cached2 && isVcValid(cached2)) {
|
|
22250
|
+
const originalPayment = { txHash: cached2.txHash, asset: cached2.paidAsset, amount: cached2.amountPaid };
|
|
22251
|
+
const paidOriginally = cached2.amountPaid !== void 0 && cached2.amountPaid !== "0";
|
|
22252
|
+
const staleAttributes = fields ? diffAgainstTemplate(cached2.vc, fields) : void 0;
|
|
22046
22253
|
return {
|
|
22047
22254
|
issued: true,
|
|
22048
22255
|
vcId: cached2.vcId,
|
|
22049
22256
|
vc: cached2.vc,
|
|
22050
|
-
|
|
22051
|
-
|
|
22052
|
-
|
|
22053
|
-
|
|
22257
|
+
fromCache: true,
|
|
22258
|
+
...paidOriginally ? { originalPayment } : {},
|
|
22259
|
+
...schema ? { schema } : {},
|
|
22260
|
+
...staleAttributes ? { staleAttributes } : {}
|
|
22054
22261
|
};
|
|
22055
22262
|
}
|
|
22056
22263
|
}
|
|
22057
|
-
const fields = deps.resolveTemplateFields ? await deps.resolveTemplateFields(opts.templateId) : null;
|
|
22058
22264
|
const { agentDid, ...rest } = opts.attributes ?? {};
|
|
22059
22265
|
const shouldAutoFillAgentDid = !agentDid && fields !== null && fields.allKeys.includes("agentDid");
|
|
22060
22266
|
const attributes = shouldAutoFillAgentDid ? { agentDid: deps.holderDid, ...rest } : opts.attributes ?? {};
|
|
22061
|
-
if (
|
|
22267
|
+
if (fields) {
|
|
22062
22268
|
const attrs = attributes;
|
|
22063
22269
|
const missing = fields.required.filter((k) => attrs[k] === void 0 || attrs[k] === null || attrs[k] === "");
|
|
22064
22270
|
if (missing.length > 0) {
|
|
22065
22271
|
return {
|
|
22066
22272
|
issued: false,
|
|
22067
|
-
reason: `template requires attribute(s) not supplied: ${missing.join(", ")} \u2014 no payment made
|
|
22273
|
+
reason: `template requires attribute(s) not supplied: ${missing.join(", ")} \u2014 no payment made`,
|
|
22274
|
+
...schema ? { schema } : {}
|
|
22068
22275
|
};
|
|
22069
22276
|
}
|
|
22070
22277
|
}
|
|
@@ -22073,7 +22280,15 @@ async function subscribeAndIssue(deps, opts) {
|
|
|
22073
22280
|
const { signBlob: signData, publicKey } = await deps.sign(blob);
|
|
22074
22281
|
const body = { data, signData, publicKey };
|
|
22075
22282
|
if (opts.expirationDate) body.expirationDate = opts.expirationDate;
|
|
22076
|
-
|
|
22283
|
+
let challenge;
|
|
22284
|
+
try {
|
|
22285
|
+
challenge = await deps.mbi.applyChallenge(body);
|
|
22286
|
+
} catch (err) {
|
|
22287
|
+
if (err instanceof MbiError) {
|
|
22288
|
+
return { issued: false, reason: err.message, httpStatus: err.httpStatus, ...schema ? { schema } : {} };
|
|
22289
|
+
}
|
|
22290
|
+
throw err;
|
|
22291
|
+
}
|
|
22077
22292
|
if (challenge.issued) {
|
|
22078
22293
|
const issued2 = challenge.issued;
|
|
22079
22294
|
if (deps.cache) {
|
|
@@ -22095,11 +22310,12 @@ async function subscribeAndIssue(deps, opts) {
|
|
|
22095
22310
|
txHash: issued2.txHash,
|
|
22096
22311
|
paidAsset: "none",
|
|
22097
22312
|
amountPaid: "0",
|
|
22313
|
+
...schema ? { schema } : {},
|
|
22098
22314
|
...opts.dryRun ? { reason: "this template requires no payment \u2014 MBI issues synchronously at phase 1, so dryRun could not prevent this issuance" } : {}
|
|
22099
22315
|
};
|
|
22100
22316
|
}
|
|
22101
22317
|
const accept = challenge.accepts[0];
|
|
22102
|
-
if (!accept) return { issued: false, reason: "MBI 402 returned no payment options" };
|
|
22318
|
+
if (!accept) return { issued: false, reason: "MBI 402 returned no payment options", ...schema ? { schema } : {} };
|
|
22103
22319
|
if (opts.dryRun) {
|
|
22104
22320
|
const quotedRaw = String(accept.asset ?? "");
|
|
22105
22321
|
const quotedAsset = deps.resolveSymbol ? await deps.resolveSymbol(quotedRaw) : quotedRaw;
|
|
@@ -22109,16 +22325,41 @@ async function subscribeAndIssue(deps, opts) {
|
|
|
22109
22325
|
quote: {
|
|
22110
22326
|
asset: quotedAsset,
|
|
22111
22327
|
maxAmountRequired: accept.maxAmountRequired,
|
|
22112
|
-
payTo: accept.payTo
|
|
22113
|
-
|
|
22114
|
-
}
|
|
22328
|
+
payTo: accept.payTo
|
|
22329
|
+
},
|
|
22330
|
+
...schema ? { schema } : {}
|
|
22115
22331
|
};
|
|
22116
22332
|
}
|
|
22117
|
-
|
|
22118
|
-
|
|
22333
|
+
let xPayment;
|
|
22334
|
+
try {
|
|
22335
|
+
xPayment = await deps.pay(accept);
|
|
22336
|
+
} catch (err) {
|
|
22337
|
+
if (err instanceof PaymentReadinessError) {
|
|
22338
|
+
return { issued: false, reason: `insufficient funds: ${err.message}`, insufficientFunds: err.shortfall };
|
|
22339
|
+
}
|
|
22340
|
+
throw err;
|
|
22341
|
+
}
|
|
22119
22342
|
const rawAsset = String(accept.asset ?? "");
|
|
22120
22343
|
const paidAsset = deps.resolveSymbol ? await deps.resolveSymbol(rawAsset) : rawAsset;
|
|
22121
22344
|
const amountPaid = String(accept.maxAmountRequired ?? "");
|
|
22345
|
+
let issued;
|
|
22346
|
+
try {
|
|
22347
|
+
issued = await deps.mbi.applySettle({ ...body, paymentId: challenge.paymentId }, xPayment);
|
|
22348
|
+
} catch (err) {
|
|
22349
|
+
if (err instanceof MbiError) {
|
|
22350
|
+
const paymentAttempted = { asset: paidAsset, amount: amountPaid, paymentId: challenge.paymentId };
|
|
22351
|
+
const recovery = err.mbiStatus === MBI_SETTLEMENT_INDETERMINATE && challenge.paymentId ? await pollSettlementOutcome(deps, challenge.paymentId) : void 0;
|
|
22352
|
+
return {
|
|
22353
|
+
issued: false,
|
|
22354
|
+
reason: err.message,
|
|
22355
|
+
httpStatus: err.httpStatus,
|
|
22356
|
+
...schema ? { schema } : {},
|
|
22357
|
+
paymentAttempted,
|
|
22358
|
+
...recovery ? { recovery } : {}
|
|
22359
|
+
};
|
|
22360
|
+
}
|
|
22361
|
+
throw err;
|
|
22362
|
+
}
|
|
22122
22363
|
if (deps.cache) {
|
|
22123
22364
|
await deps.cache.set(opts.templateId, {
|
|
22124
22365
|
templateId: opts.templateId,
|
|
@@ -22137,10 +22378,23 @@ async function subscribeAndIssue(deps, opts) {
|
|
|
22137
22378
|
vc: issued.verifiableCredential,
|
|
22138
22379
|
txHash: issued.txHash,
|
|
22139
22380
|
paidAsset,
|
|
22140
|
-
amountPaid
|
|
22381
|
+
amountPaid,
|
|
22382
|
+
...schema ? { schema } : {}
|
|
22141
22383
|
};
|
|
22142
22384
|
}
|
|
22143
22385
|
|
|
22386
|
+
// src/orchestrator/wait-for-activation.ts
|
|
22387
|
+
async function waitForActivation(check, address, sleep, opts = {}) {
|
|
22388
|
+
const attempts = opts.attempts ?? 3;
|
|
22389
|
+
const delayMs = opts.delayMs ?? 3e3;
|
|
22390
|
+
for (let i = 0; i < attempts; i++) {
|
|
22391
|
+
await sleep(delayMs);
|
|
22392
|
+
const { activated } = await check(address);
|
|
22393
|
+
if (activated) return true;
|
|
22394
|
+
}
|
|
22395
|
+
return false;
|
|
22396
|
+
}
|
|
22397
|
+
|
|
22144
22398
|
// src/orchestrator/onboard.ts
|
|
22145
22399
|
function deriveHolderDid(publicKeyHex) {
|
|
22146
22400
|
const hex = publicKeyHex.trim();
|
|
@@ -22158,31 +22412,383 @@ async function createHolderAccount(deps, input) {
|
|
|
22158
22412
|
message: `An account already exists for this wallet (zetrixAddress=${existing.zetrixAddress}, holderDid=${existing.holderDid}). Ask the user whether to keep using it or create a brand-new one \u2014 call create_holder_account again with confirmNew:true to mint a new account.`
|
|
22159
22413
|
};
|
|
22160
22414
|
}
|
|
22161
|
-
const { zetrixAddress, publicKeyHex } = await deps.create(input.password, input.label, input.purpose);
|
|
22415
|
+
const { zetrixAddress, publicKeyHex, activated } = await deps.create(input.password, input.label, input.purpose);
|
|
22162
22416
|
const holderDid = deriveHolderDid(publicKeyHex);
|
|
22163
22417
|
await deps.saveAccount({ zetrixAddress, holderDid, hsmPassword: input.password, label: input.label, purpose: input.purpose });
|
|
22164
|
-
const
|
|
22165
|
-
|
|
22418
|
+
const finalActivated = activated || await waitForActivation(deps.checkActivationStatus, zetrixAddress, deps.sleep);
|
|
22419
|
+
const message = `New holder HSM account created \u2014 address, DID, and password saved to the wallet's local account store. Both will be used automatically on the next server restart; no manual config edit needed. If your MCP config also sets ZETRIX_ADDRESS/HSM_PASSWORD via environment variables, update or remove those too: an explicit env ZETRIX_ADDRESS/HSM_PASSWORD always takes precedence over the saved account. ZETRIX_ADDRESS=${zetrixAddress} (HOLDER_DID=${holderDid} is optional \u2014 it re-derives automatically).` + (finalActivated ? "" : ` Note: on-chain activation has not completed yet \u2014 balance/on-chain calls for this address may fail until it does; check again later.`);
|
|
22420
|
+
return { created: true, alreadyExists: Boolean(existing), zetrixAddress, holderDid, publicKeyHex, activated: finalActivated, message };
|
|
22421
|
+
}
|
|
22422
|
+
|
|
22423
|
+
// src/iso3166.ts
|
|
22424
|
+
var COUNTRIES = [
|
|
22425
|
+
{ alpha2: "AD", alpha3: "AND", name: "Andorra" },
|
|
22426
|
+
{ alpha2: "AE", alpha3: "ARE", name: "United Arab Emirates" },
|
|
22427
|
+
{ alpha2: "AF", alpha3: "AFG", name: "Afghanistan" },
|
|
22428
|
+
{ alpha2: "AG", alpha3: "ATG", name: "Antigua and Barbuda" },
|
|
22429
|
+
{ alpha2: "AI", alpha3: "AIA", name: "Anguilla" },
|
|
22430
|
+
{ alpha2: "AL", alpha3: "ALB", name: "Albania" },
|
|
22431
|
+
{ alpha2: "AM", alpha3: "ARM", name: "Armenia" },
|
|
22432
|
+
{ alpha2: "AO", alpha3: "AGO", name: "Angola" },
|
|
22433
|
+
{ alpha2: "AQ", alpha3: "ATA", name: "Antarctica" },
|
|
22434
|
+
{ alpha2: "AR", alpha3: "ARG", name: "Argentina" },
|
|
22435
|
+
{ alpha2: "AS", alpha3: "ASM", name: "American Samoa" },
|
|
22436
|
+
{ alpha2: "AT", alpha3: "AUT", name: "Austria" },
|
|
22437
|
+
{ alpha2: "AU", alpha3: "AUS", name: "Australia" },
|
|
22438
|
+
{ alpha2: "AW", alpha3: "ABW", name: "Aruba" },
|
|
22439
|
+
{ alpha2: "AX", alpha3: "ALA", name: "\xC5land Islands" },
|
|
22440
|
+
{ alpha2: "AZ", alpha3: "AZE", name: "Azerbaijan" },
|
|
22441
|
+
{ alpha2: "BA", alpha3: "BIH", name: "Bosnia and Herzegovina" },
|
|
22442
|
+
{ alpha2: "BB", alpha3: "BRB", name: "Barbados" },
|
|
22443
|
+
{ alpha2: "BD", alpha3: "BGD", name: "Bangladesh" },
|
|
22444
|
+
{ alpha2: "BE", alpha3: "BEL", name: "Belgium" },
|
|
22445
|
+
{ alpha2: "BF", alpha3: "BFA", name: "Burkina Faso" },
|
|
22446
|
+
{ alpha2: "BG", alpha3: "BGR", name: "Bulgaria" },
|
|
22447
|
+
{ alpha2: "BH", alpha3: "BHR", name: "Bahrain" },
|
|
22448
|
+
{ alpha2: "BI", alpha3: "BDI", name: "Burundi" },
|
|
22449
|
+
{ alpha2: "BJ", alpha3: "BEN", name: "Benin" },
|
|
22450
|
+
{ alpha2: "BL", alpha3: "BLM", name: "Saint Barth\xE9lemy" },
|
|
22451
|
+
{ alpha2: "BM", alpha3: "BMU", name: "Bermuda" },
|
|
22452
|
+
{ alpha2: "BN", alpha3: "BRN", name: "Brunei Darussalam" },
|
|
22453
|
+
{ alpha2: "BO", alpha3: "BOL", name: "Bolivia (Plurinational State of)" },
|
|
22454
|
+
{ alpha2: "BQ", alpha3: "BES", name: "Bonaire, Sint Eustatius and Saba" },
|
|
22455
|
+
{ alpha2: "BR", alpha3: "BRA", name: "Brazil" },
|
|
22456
|
+
{ alpha2: "BS", alpha3: "BHS", name: "Bahamas" },
|
|
22457
|
+
{ alpha2: "BT", alpha3: "BTN", name: "Bhutan" },
|
|
22458
|
+
{ alpha2: "BV", alpha3: "BVT", name: "Bouvet Island" },
|
|
22459
|
+
{ alpha2: "BW", alpha3: "BWA", name: "Botswana" },
|
|
22460
|
+
{ alpha2: "BY", alpha3: "BLR", name: "Belarus" },
|
|
22461
|
+
{ alpha2: "BZ", alpha3: "BLZ", name: "Belize" },
|
|
22462
|
+
{ alpha2: "CA", alpha3: "CAN", name: "Canada" },
|
|
22463
|
+
{ alpha2: "CC", alpha3: "CCK", name: "Cocos (Keeling) Islands" },
|
|
22464
|
+
{ alpha2: "CD", alpha3: "COD", name: "Congo, Democratic Republic of the" },
|
|
22465
|
+
{ alpha2: "CF", alpha3: "CAF", name: "Central African Republic" },
|
|
22466
|
+
{ alpha2: "CG", alpha3: "COG", name: "Congo" },
|
|
22467
|
+
{ alpha2: "CH", alpha3: "CHE", name: "Switzerland" },
|
|
22468
|
+
{ alpha2: "CI", alpha3: "CIV", name: "C\xF4te d'Ivoire" },
|
|
22469
|
+
{ alpha2: "CK", alpha3: "COK", name: "Cook Islands" },
|
|
22470
|
+
{ alpha2: "CL", alpha3: "CHL", name: "Chile" },
|
|
22471
|
+
{ alpha2: "CM", alpha3: "CMR", name: "Cameroon" },
|
|
22472
|
+
{ alpha2: "CN", alpha3: "CHN", name: "China" },
|
|
22473
|
+
{ alpha2: "CO", alpha3: "COL", name: "Colombia" },
|
|
22474
|
+
{ alpha2: "CR", alpha3: "CRI", name: "Costa Rica" },
|
|
22475
|
+
{ alpha2: "CU", alpha3: "CUB", name: "Cuba" },
|
|
22476
|
+
{ alpha2: "CV", alpha3: "CPV", name: "Cabo Verde" },
|
|
22477
|
+
{ alpha2: "CW", alpha3: "CUW", name: "Cura\xE7ao" },
|
|
22478
|
+
{ alpha2: "CX", alpha3: "CXR", name: "Christmas Island" },
|
|
22479
|
+
{ alpha2: "CY", alpha3: "CYP", name: "Cyprus" },
|
|
22480
|
+
{ alpha2: "CZ", alpha3: "CZE", name: "Czechia" },
|
|
22481
|
+
{ alpha2: "DE", alpha3: "DEU", name: "Germany" },
|
|
22482
|
+
{ alpha2: "DJ", alpha3: "DJI", name: "Djibouti" },
|
|
22483
|
+
{ alpha2: "DK", alpha3: "DNK", name: "Denmark" },
|
|
22484
|
+
{ alpha2: "DM", alpha3: "DMA", name: "Dominica" },
|
|
22485
|
+
{ alpha2: "DO", alpha3: "DOM", name: "Dominican Republic" },
|
|
22486
|
+
{ alpha2: "DZ", alpha3: "DZA", name: "Algeria" },
|
|
22487
|
+
{ alpha2: "EC", alpha3: "ECU", name: "Ecuador" },
|
|
22488
|
+
{ alpha2: "EE", alpha3: "EST", name: "Estonia" },
|
|
22489
|
+
{ alpha2: "EG", alpha3: "EGY", name: "Egypt" },
|
|
22490
|
+
{ alpha2: "EH", alpha3: "ESH", name: "Western Sahara" },
|
|
22491
|
+
{ alpha2: "ER", alpha3: "ERI", name: "Eritrea" },
|
|
22492
|
+
{ alpha2: "ES", alpha3: "ESP", name: "Spain" },
|
|
22493
|
+
{ alpha2: "ET", alpha3: "ETH", name: "Ethiopia" },
|
|
22494
|
+
{ alpha2: "FI", alpha3: "FIN", name: "Finland" },
|
|
22495
|
+
{ alpha2: "FJ", alpha3: "FJI", name: "Fiji" },
|
|
22496
|
+
{ alpha2: "FK", alpha3: "FLK", name: "Falkland Islands (Malvinas)" },
|
|
22497
|
+
{ alpha2: "FM", alpha3: "FSM", name: "Micronesia (Federated States of)" },
|
|
22498
|
+
{ alpha2: "FO", alpha3: "FRO", name: "Faroe Islands" },
|
|
22499
|
+
{ alpha2: "FR", alpha3: "FRA", name: "France" },
|
|
22500
|
+
{ alpha2: "GA", alpha3: "GAB", name: "Gabon" },
|
|
22501
|
+
{ alpha2: "GB", alpha3: "GBR", name: "United Kingdom of Great Britain and Northern Ireland" },
|
|
22502
|
+
{ alpha2: "GD", alpha3: "GRD", name: "Grenada" },
|
|
22503
|
+
{ alpha2: "GE", alpha3: "GEO", name: "Georgia" },
|
|
22504
|
+
{ alpha2: "GF", alpha3: "GUF", name: "French Guiana" },
|
|
22505
|
+
{ alpha2: "GG", alpha3: "GGY", name: "Guernsey" },
|
|
22506
|
+
{ alpha2: "GH", alpha3: "GHA", name: "Ghana" },
|
|
22507
|
+
{ alpha2: "GI", alpha3: "GIB", name: "Gibraltar" },
|
|
22508
|
+
{ alpha2: "GL", alpha3: "GRL", name: "Greenland" },
|
|
22509
|
+
{ alpha2: "GM", alpha3: "GMB", name: "Gambia" },
|
|
22510
|
+
{ alpha2: "GN", alpha3: "GIN", name: "Guinea" },
|
|
22511
|
+
{ alpha2: "GP", alpha3: "GLP", name: "Guadeloupe" },
|
|
22512
|
+
{ alpha2: "GQ", alpha3: "GNQ", name: "Equatorial Guinea" },
|
|
22513
|
+
{ alpha2: "GR", alpha3: "GRC", name: "Greece" },
|
|
22514
|
+
{ alpha2: "GS", alpha3: "SGS", name: "South Georgia and the South Sandwich Islands" },
|
|
22515
|
+
{ alpha2: "GT", alpha3: "GTM", name: "Guatemala" },
|
|
22516
|
+
{ alpha2: "GU", alpha3: "GUM", name: "Guam" },
|
|
22517
|
+
{ alpha2: "GW", alpha3: "GNB", name: "Guinea-Bissau" },
|
|
22518
|
+
{ alpha2: "GY", alpha3: "GUY", name: "Guyana" },
|
|
22519
|
+
{ alpha2: "HK", alpha3: "HKG", name: "Hong Kong" },
|
|
22520
|
+
{ alpha2: "HM", alpha3: "HMD", name: "Heard Island and McDonald Islands" },
|
|
22521
|
+
{ alpha2: "HN", alpha3: "HND", name: "Honduras" },
|
|
22522
|
+
{ alpha2: "HR", alpha3: "HRV", name: "Croatia" },
|
|
22523
|
+
{ alpha2: "HT", alpha3: "HTI", name: "Haiti" },
|
|
22524
|
+
{ alpha2: "HU", alpha3: "HUN", name: "Hungary" },
|
|
22525
|
+
{ alpha2: "ID", alpha3: "IDN", name: "Indonesia" },
|
|
22526
|
+
{ alpha2: "IE", alpha3: "IRL", name: "Ireland" },
|
|
22527
|
+
{ alpha2: "IL", alpha3: "ISR", name: "Israel" },
|
|
22528
|
+
{ alpha2: "IM", alpha3: "IMN", name: "Isle of Man" },
|
|
22529
|
+
{ alpha2: "IN", alpha3: "IND", name: "India" },
|
|
22530
|
+
{ alpha2: "IO", alpha3: "IOT", name: "British Indian Ocean Territory" },
|
|
22531
|
+
{ alpha2: "IQ", alpha3: "IRQ", name: "Iraq" },
|
|
22532
|
+
{ alpha2: "IR", alpha3: "IRN", name: "Iran (Islamic Republic of)" },
|
|
22533
|
+
{ alpha2: "IS", alpha3: "ISL", name: "Iceland" },
|
|
22534
|
+
{ alpha2: "IT", alpha3: "ITA", name: "Italy" },
|
|
22535
|
+
{ alpha2: "JE", alpha3: "JEY", name: "Jersey" },
|
|
22536
|
+
{ alpha2: "JM", alpha3: "JAM", name: "Jamaica" },
|
|
22537
|
+
{ alpha2: "JO", alpha3: "JOR", name: "Jordan" },
|
|
22538
|
+
{ alpha2: "JP", alpha3: "JPN", name: "Japan" },
|
|
22539
|
+
{ alpha2: "KE", alpha3: "KEN", name: "Kenya" },
|
|
22540
|
+
{ alpha2: "KG", alpha3: "KGZ", name: "Kyrgyzstan" },
|
|
22541
|
+
{ alpha2: "KH", alpha3: "KHM", name: "Cambodia" },
|
|
22542
|
+
{ alpha2: "KI", alpha3: "KIR", name: "Kiribati" },
|
|
22543
|
+
{ alpha2: "KM", alpha3: "COM", name: "Comoros" },
|
|
22544
|
+
{ alpha2: "KN", alpha3: "KNA", name: "Saint Kitts and Nevis" },
|
|
22545
|
+
{ alpha2: "KP", alpha3: "PRK", name: "Korea (Democratic People's Republic of)" },
|
|
22546
|
+
{ alpha2: "KR", alpha3: "KOR", name: "Korea, Republic of" },
|
|
22547
|
+
{ alpha2: "KW", alpha3: "KWT", name: "Kuwait" },
|
|
22548
|
+
{ alpha2: "KY", alpha3: "CYM", name: "Cayman Islands" },
|
|
22549
|
+
{ alpha2: "KZ", alpha3: "KAZ", name: "Kazakhstan" },
|
|
22550
|
+
{ alpha2: "LA", alpha3: "LAO", name: "Lao People's Democratic Republic" },
|
|
22551
|
+
{ alpha2: "LB", alpha3: "LBN", name: "Lebanon" },
|
|
22552
|
+
{ alpha2: "LC", alpha3: "LCA", name: "Saint Lucia" },
|
|
22553
|
+
{ alpha2: "LI", alpha3: "LIE", name: "Liechtenstein" },
|
|
22554
|
+
{ alpha2: "LK", alpha3: "LKA", name: "Sri Lanka" },
|
|
22555
|
+
{ alpha2: "LR", alpha3: "LBR", name: "Liberia" },
|
|
22556
|
+
{ alpha2: "LS", alpha3: "LSO", name: "Lesotho" },
|
|
22557
|
+
{ alpha2: "LT", alpha3: "LTU", name: "Lithuania" },
|
|
22558
|
+
{ alpha2: "LU", alpha3: "LUX", name: "Luxembourg" },
|
|
22559
|
+
{ alpha2: "LV", alpha3: "LVA", name: "Latvia" },
|
|
22560
|
+
{ alpha2: "LY", alpha3: "LBY", name: "Libya" },
|
|
22561
|
+
{ alpha2: "MA", alpha3: "MAR", name: "Morocco" },
|
|
22562
|
+
{ alpha2: "MC", alpha3: "MCO", name: "Monaco" },
|
|
22563
|
+
{ alpha2: "MD", alpha3: "MDA", name: "Moldova, Republic of" },
|
|
22564
|
+
{ alpha2: "ME", alpha3: "MNE", name: "Montenegro" },
|
|
22565
|
+
{ alpha2: "MF", alpha3: "MAF", name: "Saint Martin (French part)" },
|
|
22566
|
+
{ alpha2: "MG", alpha3: "MDG", name: "Madagascar" },
|
|
22567
|
+
{ alpha2: "MH", alpha3: "MHL", name: "Marshall Islands" },
|
|
22568
|
+
{ alpha2: "MK", alpha3: "MKD", name: "North Macedonia" },
|
|
22569
|
+
{ alpha2: "ML", alpha3: "MLI", name: "Mali" },
|
|
22570
|
+
{ alpha2: "MM", alpha3: "MMR", name: "Myanmar" },
|
|
22571
|
+
{ alpha2: "MN", alpha3: "MNG", name: "Mongolia" },
|
|
22572
|
+
{ alpha2: "MO", alpha3: "MAC", name: "Macao" },
|
|
22573
|
+
{ alpha2: "MP", alpha3: "MNP", name: "Northern Mariana Islands" },
|
|
22574
|
+
{ alpha2: "MQ", alpha3: "MTQ", name: "Martinique" },
|
|
22575
|
+
{ alpha2: "MR", alpha3: "MRT", name: "Mauritania" },
|
|
22576
|
+
{ alpha2: "MS", alpha3: "MSR", name: "Montserrat" },
|
|
22577
|
+
{ alpha2: "MT", alpha3: "MLT", name: "Malta" },
|
|
22578
|
+
{ alpha2: "MU", alpha3: "MUS", name: "Mauritius" },
|
|
22579
|
+
{ alpha2: "MV", alpha3: "MDV", name: "Maldives" },
|
|
22580
|
+
{ alpha2: "MW", alpha3: "MWI", name: "Malawi" },
|
|
22581
|
+
{ alpha2: "MX", alpha3: "MEX", name: "Mexico" },
|
|
22582
|
+
{ alpha2: "MY", alpha3: "MYS", name: "Malaysia" },
|
|
22583
|
+
{ alpha2: "MZ", alpha3: "MOZ", name: "Mozambique" },
|
|
22584
|
+
{ alpha2: "NA", alpha3: "NAM", name: "Namibia" },
|
|
22585
|
+
{ alpha2: "NC", alpha3: "NCL", name: "New Caledonia" },
|
|
22586
|
+
{ alpha2: "NE", alpha3: "NER", name: "Niger" },
|
|
22587
|
+
{ alpha2: "NF", alpha3: "NFK", name: "Norfolk Island" },
|
|
22588
|
+
{ alpha2: "NG", alpha3: "NGA", name: "Nigeria" },
|
|
22589
|
+
{ alpha2: "NI", alpha3: "NIC", name: "Nicaragua" },
|
|
22590
|
+
{ alpha2: "NL", alpha3: "NLD", name: "Netherlands" },
|
|
22591
|
+
{ alpha2: "NO", alpha3: "NOR", name: "Norway" },
|
|
22592
|
+
{ alpha2: "NP", alpha3: "NPL", name: "Nepal" },
|
|
22593
|
+
{ alpha2: "NR", alpha3: "NRU", name: "Nauru" },
|
|
22594
|
+
{ alpha2: "NU", alpha3: "NIU", name: "Niue" },
|
|
22595
|
+
{ alpha2: "NZ", alpha3: "NZL", name: "New Zealand" },
|
|
22596
|
+
{ alpha2: "OM", alpha3: "OMN", name: "Oman" },
|
|
22597
|
+
{ alpha2: "PA", alpha3: "PAN", name: "Panama" },
|
|
22598
|
+
{ alpha2: "PE", alpha3: "PER", name: "Peru" },
|
|
22599
|
+
{ alpha2: "PF", alpha3: "PYF", name: "French Polynesia" },
|
|
22600
|
+
{ alpha2: "PG", alpha3: "PNG", name: "Papua New Guinea" },
|
|
22601
|
+
{ alpha2: "PH", alpha3: "PHL", name: "Philippines" },
|
|
22602
|
+
{ alpha2: "PK", alpha3: "PAK", name: "Pakistan" },
|
|
22603
|
+
{ alpha2: "PL", alpha3: "POL", name: "Poland" },
|
|
22604
|
+
{ alpha2: "PM", alpha3: "SPM", name: "Saint Pierre and Miquelon" },
|
|
22605
|
+
{ alpha2: "PN", alpha3: "PCN", name: "Pitcairn" },
|
|
22606
|
+
{ alpha2: "PR", alpha3: "PRI", name: "Puerto Rico" },
|
|
22607
|
+
{ alpha2: "PS", alpha3: "PSE", name: "Palestine, State of" },
|
|
22608
|
+
{ alpha2: "PT", alpha3: "PRT", name: "Portugal" },
|
|
22609
|
+
{ alpha2: "PW", alpha3: "PLW", name: "Palau" },
|
|
22610
|
+
{ alpha2: "PY", alpha3: "PRY", name: "Paraguay" },
|
|
22611
|
+
{ alpha2: "QA", alpha3: "QAT", name: "Qatar" },
|
|
22612
|
+
{ alpha2: "RE", alpha3: "REU", name: "R\xE9union" },
|
|
22613
|
+
{ alpha2: "RO", alpha3: "ROU", name: "Romania" },
|
|
22614
|
+
{ alpha2: "RS", alpha3: "SRB", name: "Serbia" },
|
|
22615
|
+
{ alpha2: "RU", alpha3: "RUS", name: "Russian Federation" },
|
|
22616
|
+
{ alpha2: "RW", alpha3: "RWA", name: "Rwanda" },
|
|
22617
|
+
{ alpha2: "SA", alpha3: "SAU", name: "Saudi Arabia" },
|
|
22618
|
+
{ alpha2: "SB", alpha3: "SLB", name: "Solomon Islands" },
|
|
22619
|
+
{ alpha2: "SC", alpha3: "SYC", name: "Seychelles" },
|
|
22620
|
+
{ alpha2: "SD", alpha3: "SDN", name: "Sudan" },
|
|
22621
|
+
{ alpha2: "SE", alpha3: "SWE", name: "Sweden" },
|
|
22622
|
+
{ alpha2: "SG", alpha3: "SGP", name: "Singapore" },
|
|
22623
|
+
{ alpha2: "SH", alpha3: "SHN", name: "Saint Helena, Ascension and Tristan da Cunha" },
|
|
22624
|
+
{ alpha2: "SI", alpha3: "SVN", name: "Slovenia" },
|
|
22625
|
+
{ alpha2: "SJ", alpha3: "SJM", name: "Svalbard and Jan Mayen" },
|
|
22626
|
+
{ alpha2: "SK", alpha3: "SVK", name: "Slovakia" },
|
|
22627
|
+
{ alpha2: "SL", alpha3: "SLE", name: "Sierra Leone" },
|
|
22628
|
+
{ alpha2: "SM", alpha3: "SMR", name: "San Marino" },
|
|
22629
|
+
{ alpha2: "SN", alpha3: "SEN", name: "Senegal" },
|
|
22630
|
+
{ alpha2: "SO", alpha3: "SOM", name: "Somalia" },
|
|
22631
|
+
{ alpha2: "SR", alpha3: "SUR", name: "Suriname" },
|
|
22632
|
+
{ alpha2: "SS", alpha3: "SSD", name: "South Sudan" },
|
|
22633
|
+
{ alpha2: "ST", alpha3: "STP", name: "Sao Tome and Principe" },
|
|
22634
|
+
{ alpha2: "SV", alpha3: "SLV", name: "El Salvador" },
|
|
22635
|
+
{ alpha2: "SX", alpha3: "SXM", name: "Sint Maarten (Dutch part)" },
|
|
22636
|
+
{ alpha2: "SY", alpha3: "SYR", name: "Syrian Arab Republic" },
|
|
22637
|
+
{ alpha2: "SZ", alpha3: "SWZ", name: "Eswatini" },
|
|
22638
|
+
{ alpha2: "TC", alpha3: "TCA", name: "Turks and Caicos Islands" },
|
|
22639
|
+
{ alpha2: "TD", alpha3: "TCD", name: "Chad" },
|
|
22640
|
+
{ alpha2: "TF", alpha3: "ATF", name: "French Southern Territories" },
|
|
22641
|
+
{ alpha2: "TG", alpha3: "TGO", name: "Togo" },
|
|
22642
|
+
{ alpha2: "TH", alpha3: "THA", name: "Thailand" },
|
|
22643
|
+
{ alpha2: "TJ", alpha3: "TJK", name: "Tajikistan" },
|
|
22644
|
+
{ alpha2: "TK", alpha3: "TKL", name: "Tokelau" },
|
|
22645
|
+
{ alpha2: "TL", alpha3: "TLS", name: "Timor-Leste" },
|
|
22646
|
+
{ alpha2: "TM", alpha3: "TKM", name: "Turkmenistan" },
|
|
22647
|
+
{ alpha2: "TN", alpha3: "TUN", name: "Tunisia" },
|
|
22648
|
+
{ alpha2: "TO", alpha3: "TON", name: "Tonga" },
|
|
22649
|
+
{ alpha2: "TR", alpha3: "TUR", name: "T\xFCrkiye" },
|
|
22650
|
+
{ alpha2: "TT", alpha3: "TTO", name: "Trinidad and Tobago" },
|
|
22651
|
+
{ alpha2: "TV", alpha3: "TUV", name: "Tuvalu" },
|
|
22652
|
+
{ alpha2: "TW", alpha3: "TWN", name: "Taiwan, Province of China" },
|
|
22653
|
+
{ alpha2: "TZ", alpha3: "TZA", name: "Tanzania, United Republic of" },
|
|
22654
|
+
{ alpha2: "UA", alpha3: "UKR", name: "Ukraine" },
|
|
22655
|
+
{ alpha2: "UG", alpha3: "UGA", name: "Uganda" },
|
|
22656
|
+
{ alpha2: "UM", alpha3: "UMI", name: "United States Minor Outlying Islands" },
|
|
22657
|
+
{ alpha2: "US", alpha3: "USA", name: "United States of America" },
|
|
22658
|
+
{ alpha2: "UY", alpha3: "URY", name: "Uruguay" },
|
|
22659
|
+
{ alpha2: "UZ", alpha3: "UZB", name: "Uzbekistan" },
|
|
22660
|
+
{ alpha2: "VA", alpha3: "VAT", name: "Holy See" },
|
|
22661
|
+
{ alpha2: "VC", alpha3: "VCT", name: "Saint Vincent and the Grenadines" },
|
|
22662
|
+
{ alpha2: "VE", alpha3: "VEN", name: "Venezuela (Bolivarian Republic of)" },
|
|
22663
|
+
{ alpha2: "VG", alpha3: "VGB", name: "Virgin Islands (British)" },
|
|
22664
|
+
{ alpha2: "VI", alpha3: "VIR", name: "Virgin Islands (U.S.)" },
|
|
22665
|
+
{ alpha2: "VN", alpha3: "VNM", name: "Viet Nam" },
|
|
22666
|
+
{ alpha2: "VU", alpha3: "VUT", name: "Vanuatu" },
|
|
22667
|
+
{ alpha2: "WF", alpha3: "WLF", name: "Wallis and Futuna" },
|
|
22668
|
+
{ alpha2: "WS", alpha3: "WSM", name: "Samoa" },
|
|
22669
|
+
{ alpha2: "YE", alpha3: "YEM", name: "Yemen" },
|
|
22670
|
+
{ alpha2: "YT", alpha3: "MYT", name: "Mayotte" },
|
|
22671
|
+
{ alpha2: "ZA", alpha3: "ZAF", name: "South Africa" },
|
|
22672
|
+
{ alpha2: "ZM", alpha3: "ZMB", name: "Zambia" },
|
|
22673
|
+
{ alpha2: "ZW", alpha3: "ZWE", name: "Zimbabwe" }
|
|
22674
|
+
];
|
|
22675
|
+
var COMMON_ALIASES = {
|
|
22676
|
+
usa: "US",
|
|
22677
|
+
america: "US",
|
|
22678
|
+
unitedstates: "US",
|
|
22679
|
+
uk: "GB",
|
|
22680
|
+
unitedkingdom: "GB",
|
|
22681
|
+
britain: "GB",
|
|
22682
|
+
greatbritain: "GB",
|
|
22683
|
+
southkorea: "KR",
|
|
22684
|
+
northkorea: "KP",
|
|
22685
|
+
russia: "RU",
|
|
22686
|
+
vietnam: "VN",
|
|
22687
|
+
laos: "LA",
|
|
22688
|
+
syria: "SY",
|
|
22689
|
+
iran: "IR",
|
|
22690
|
+
ivorycoast: "CI",
|
|
22691
|
+
czechrepublic: "CZ",
|
|
22692
|
+
swaziland: "SZ",
|
|
22693
|
+
burma: "MM",
|
|
22694
|
+
capeverde: "CV",
|
|
22695
|
+
easttimor: "TL",
|
|
22696
|
+
taiwan: "TW",
|
|
22697
|
+
macedonia: "MK",
|
|
22698
|
+
vatican: "VA",
|
|
22699
|
+
vaticancity: "VA",
|
|
22700
|
+
holland: "NL",
|
|
22701
|
+
moldova: "MD",
|
|
22702
|
+
bolivia: "BO",
|
|
22703
|
+
tanzania: "TZ",
|
|
22704
|
+
venezuela: "VE",
|
|
22705
|
+
palestine: "PS",
|
|
22706
|
+
brunei: "BN"
|
|
22707
|
+
};
|
|
22708
|
+
function normalize(s) {
|
|
22709
|
+
return s.toLowerCase().trim().replace(/[^a-z0-9]/g, "");
|
|
22710
|
+
}
|
|
22711
|
+
function isValidCountry(input) {
|
|
22712
|
+
const trimmed = input.trim();
|
|
22713
|
+
if (/^[A-Za-z]{2}$/.test(trimmed)) {
|
|
22714
|
+
return COUNTRIES.some((c) => c.alpha2 === trimmed.toUpperCase());
|
|
22715
|
+
}
|
|
22716
|
+
if (/^[A-Za-z]{3}$/.test(trimmed)) {
|
|
22717
|
+
return COUNTRIES.some((c) => c.alpha3 === trimmed.toUpperCase());
|
|
22718
|
+
}
|
|
22719
|
+
const normalized = normalize(trimmed);
|
|
22720
|
+
if (COMMON_ALIASES[normalized]) return true;
|
|
22721
|
+
return COUNTRIES.some((c) => normalize(c.name) === normalized);
|
|
22166
22722
|
}
|
|
22167
22723
|
|
|
22168
22724
|
// src/template-aliases.ts
|
|
22725
|
+
function validateDob(value) {
|
|
22726
|
+
if (typeof value !== "string") return "dob must be a string in YYYY-MM-DD format";
|
|
22727
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return `dob must match the format YYYY-MM-DD, got "${value}"`;
|
|
22728
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
22729
|
+
const date3 = new Date(Date.UTC(year, month - 1, day));
|
|
22730
|
+
const isRealCalendarDate = date3.getUTCFullYear() === year && date3.getUTCMonth() === month - 1 && date3.getUTCDate() === day;
|
|
22731
|
+
if (!isRealCalendarDate) return `dob is not a valid calendar date: "${value}"`;
|
|
22732
|
+
return void 0;
|
|
22733
|
+
}
|
|
22734
|
+
function validateCountryOfOrigin(value) {
|
|
22735
|
+
if (typeof value !== "string" || !value.trim()) return "countryOfOrigin must be a non-empty string";
|
|
22736
|
+
if (!isValidCountry(value)) return `countryOfOrigin must be an ISO 3166 country code or name, got "${value}"`;
|
|
22737
|
+
return void 0;
|
|
22738
|
+
}
|
|
22169
22739
|
var TEMPLATE_ALIASES = [
|
|
22170
22740
|
{
|
|
22171
22741
|
match: "birthcert",
|
|
22172
|
-
testnet: "did:zid:
|
|
22173
|
-
mainnet: "did:zid:
|
|
22742
|
+
testnet: "did:zid:3c0fb79adff08e14e06dcd6e3243205010dd65f533434a3d96c55575d1d3d959",
|
|
22743
|
+
mainnet: "did:zid:19091d19049abb8869b4b8e2f4a887bd1d1d86e5f5ebd0c8297000255f67765b",
|
|
22744
|
+
deriveAttributes: { id: "agentUsername" },
|
|
22745
|
+
validateAttributes: { dob: validateDob, countryOfOrigin: validateCountryOfOrigin }
|
|
22174
22746
|
}
|
|
22175
22747
|
];
|
|
22176
|
-
function
|
|
22748
|
+
function normalize2(s) {
|
|
22177
22749
|
return s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
22178
22750
|
}
|
|
22751
|
+
function findEntry(templateId, network) {
|
|
22752
|
+
if (/^did:zid:/.test(templateId)) {
|
|
22753
|
+
const key = network.includes("testnet") ? "testnet" : "mainnet";
|
|
22754
|
+
return TEMPLATE_ALIASES.find((e) => e[key] === templateId);
|
|
22755
|
+
}
|
|
22756
|
+
const normalized = normalize2(templateId);
|
|
22757
|
+
return TEMPLATE_ALIASES.find((e) => normalized.includes(e.match));
|
|
22758
|
+
}
|
|
22179
22759
|
function resolveTemplateAlias(input, network) {
|
|
22180
22760
|
if (/^did:zid:/.test(input)) return void 0;
|
|
22181
|
-
const
|
|
22182
|
-
const entry = TEMPLATE_ALIASES.find((e) => normalized.includes(e.match));
|
|
22761
|
+
const entry = findEntry(input, network);
|
|
22183
22762
|
if (!entry) return void 0;
|
|
22184
22763
|
return network.includes("testnet") ? entry.testnet : entry.mainnet;
|
|
22185
22764
|
}
|
|
22765
|
+
function deriveTemplateAttributes(templateId, network, attributes) {
|
|
22766
|
+
const entry = findEntry(templateId, network);
|
|
22767
|
+
if (!entry?.deriveAttributes) return attributes;
|
|
22768
|
+
const result = { ...attributes };
|
|
22769
|
+
for (const [target, source] of Object.entries(entry.deriveAttributes)) {
|
|
22770
|
+
if ((result[target] === void 0 || result[target] === null || result[target] === "") && result[source] !== void 0) {
|
|
22771
|
+
result[target] = result[source];
|
|
22772
|
+
}
|
|
22773
|
+
}
|
|
22774
|
+
return result;
|
|
22775
|
+
}
|
|
22776
|
+
function derivedAttributeKeys(templateId, network) {
|
|
22777
|
+
const entry = findEntry(templateId, network);
|
|
22778
|
+
return entry?.deriveAttributes ? Object.keys(entry.deriveAttributes) : [];
|
|
22779
|
+
}
|
|
22780
|
+
function validateTemplateAttributes(templateId, network, attributes) {
|
|
22781
|
+
const entry = findEntry(templateId, network);
|
|
22782
|
+
if (!entry?.validateAttributes) return [];
|
|
22783
|
+
const errors = [];
|
|
22784
|
+
for (const [key, validate] of Object.entries(entry.validateAttributes)) {
|
|
22785
|
+
const value = attributes[key];
|
|
22786
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
22787
|
+
const error2 = validate(value);
|
|
22788
|
+
if (error2) errors.push(error2);
|
|
22789
|
+
}
|
|
22790
|
+
return errors;
|
|
22791
|
+
}
|
|
22186
22792
|
|
|
22187
22793
|
// src/mcp-tools.ts
|
|
22188
22794
|
async function loadValidCachedCredentials(cache) {
|
|
@@ -22194,13 +22800,15 @@ function createTools(deps) {
|
|
|
22194
22800
|
return {
|
|
22195
22801
|
async wallet_status(input = {}) {
|
|
22196
22802
|
const balances = deps.getBalances ? await deps.getBalances() : void 0;
|
|
22803
|
+
const tokenBalance = input.token && deps.queryTokenBalance ? await deps.queryTokenBalance(input.token) : void 0;
|
|
22197
22804
|
const credentials = input.heldCredentials ?? (await loadValidCachedCredentials(deps.cache)).map((entry) => entry.vc);
|
|
22198
22805
|
return {
|
|
22199
22806
|
holderDid: deps.config.holderDid,
|
|
22200
22807
|
zetrixAddress: deps.config.zetrixAddress,
|
|
22201
22808
|
network: deps.config.network,
|
|
22202
22809
|
credentials,
|
|
22203
|
-
...balances !== void 0 ? { balances } : {}
|
|
22810
|
+
...balances !== void 0 ? { balances } : {},
|
|
22811
|
+
...tokenBalance !== void 0 ? { tokenBalance } : {}
|
|
22204
22812
|
};
|
|
22205
22813
|
},
|
|
22206
22814
|
async prove_identity(input) {
|
|
@@ -22226,16 +22834,67 @@ function createTools(deps) {
|
|
|
22226
22834
|
pay_and_fetch(input) {
|
|
22227
22835
|
return payAndFetch(deps.payer, input);
|
|
22228
22836
|
},
|
|
22229
|
-
subscribe_and_issue(input) {
|
|
22837
|
+
async subscribe_and_issue(input) {
|
|
22230
22838
|
const resolved = resolveTemplateAlias(input.templateId, deps.config.network);
|
|
22231
|
-
|
|
22839
|
+
const templateId = resolved ?? input.templateId;
|
|
22840
|
+
const attributes = deriveTemplateAttributes(templateId, deps.config.network, input.attributes ?? {});
|
|
22841
|
+
const errors = validateTemplateAttributes(templateId, deps.config.network, attributes);
|
|
22842
|
+
if (errors.length > 0) {
|
|
22843
|
+
return { issued: false, reason: errors.join("; ") };
|
|
22844
|
+
}
|
|
22845
|
+
const result = await subscribeAndIssue(deps.subscribeDeps, { ...input, templateId, attributes });
|
|
22846
|
+
if (!result.schema) return result;
|
|
22847
|
+
const hidden = /* @__PURE__ */ new Set(["agentDid", ...derivedAttributeKeys(templateId, deps.config.network)]);
|
|
22848
|
+
return {
|
|
22849
|
+
...result,
|
|
22850
|
+
schema: {
|
|
22851
|
+
required: result.schema.required.filter((k) => !hidden.has(k)),
|
|
22852
|
+
optional: result.schema.optional.filter((k) => !hidden.has(k))
|
|
22853
|
+
}
|
|
22854
|
+
};
|
|
22855
|
+
},
|
|
22856
|
+
/**
|
|
22857
|
+
* Free schema lookup. Previously the only way to ask "what does this template need?" was
|
|
22858
|
+
* subscribe_and_issue({ dryRun: true }) — a tool whose name reads as "this charges money", so
|
|
22859
|
+
* an agent reasoning about required fields had no obvious reason to reach for it. Reported
|
|
22860
|
+
* live: an agent discovered a newly-required attribute only by failing an issuance first.
|
|
22861
|
+
*/
|
|
22862
|
+
async get_template_schema(input) {
|
|
22863
|
+
const resolved = resolveTemplateAlias(input.templateId, deps.config.network);
|
|
22864
|
+
const templateId = resolved ?? input.templateId;
|
|
22865
|
+
if (!/^did:zid:/.test(templateId)) {
|
|
22866
|
+
return {
|
|
22867
|
+
templateId,
|
|
22868
|
+
error: `templateId must be a did:zid:... credential-definition id or a known template name, got "${input.templateId}"`
|
|
22869
|
+
};
|
|
22870
|
+
}
|
|
22871
|
+
const fields = deps.subscribeDeps.resolveTemplateFields ? await deps.subscribeDeps.resolveTemplateFields(templateId) : null;
|
|
22872
|
+
if (!fields) {
|
|
22873
|
+
return {
|
|
22874
|
+
templateId,
|
|
22875
|
+
error: `template schema could not be read from chain for ${templateId} (unknown/inactive template, or node unavailable)`
|
|
22876
|
+
};
|
|
22877
|
+
}
|
|
22878
|
+
const hidden = /* @__PURE__ */ new Set(["agentDid", ...derivedAttributeKeys(templateId, deps.config.network)]);
|
|
22879
|
+
return {
|
|
22880
|
+
templateId,
|
|
22881
|
+
schema: {
|
|
22882
|
+
required: fields.required.filter((k) => !hidden.has(k)),
|
|
22883
|
+
optional: fields.allKeys.filter((k) => !fields.required.includes(k) && !hidden.has(k))
|
|
22884
|
+
}
|
|
22885
|
+
};
|
|
22886
|
+
},
|
|
22887
|
+
query_contract(input) {
|
|
22888
|
+
return deps.queryContract(input);
|
|
22232
22889
|
},
|
|
22233
22890
|
create_holder_account(input) {
|
|
22234
22891
|
return createHolderAccount(
|
|
22235
22892
|
{
|
|
22236
22893
|
create: deps.createAccount,
|
|
22237
22894
|
getExistingAccount: () => Promise.resolve(deps.config.zetrixAddress ? { zetrixAddress: deps.config.zetrixAddress, holderDid: deps.config.holderDid } : null),
|
|
22238
|
-
saveAccount: deps.saveAccount
|
|
22895
|
+
saveAccount: deps.saveAccount,
|
|
22896
|
+
checkActivationStatus: deps.checkActivationStatus,
|
|
22897
|
+
sleep: deps.sleep
|
|
22239
22898
|
},
|
|
22240
22899
|
input
|
|
22241
22900
|
);
|
|
@@ -22246,8 +22905,16 @@ function createTools(deps) {
|
|
|
22246
22905
|
// src/orchestrator/resolve-holder.ts
|
|
22247
22906
|
async function resolveHolder(deps, input) {
|
|
22248
22907
|
if (!input.zetrixAddress) {
|
|
22249
|
-
const { zetrixAddress, publicKeyHex } = await deps.createAccount(input.hsmPassword);
|
|
22250
|
-
|
|
22908
|
+
const { zetrixAddress, publicKeyHex, activated } = await deps.createAccount(input.hsmPassword);
|
|
22909
|
+
let finalActivated = activated;
|
|
22910
|
+
if (!finalActivated) {
|
|
22911
|
+
try {
|
|
22912
|
+
finalActivated = await waitForActivation(deps.checkActivationStatus, zetrixAddress, deps.sleep);
|
|
22913
|
+
} catch {
|
|
22914
|
+
finalActivated = false;
|
|
22915
|
+
}
|
|
22916
|
+
}
|
|
22917
|
+
return { zetrixAddress, holderDid: deriveHolderDid(publicKeyHex), created: true, didMismatch: false, activated: finalActivated };
|
|
22251
22918
|
}
|
|
22252
22919
|
const { publicKey } = await deps.signMessage(input.zetrixAddress, input.zetrixAddress, input.hsmPassword);
|
|
22253
22920
|
const derivedDid = deriveHolderDid(publicKey);
|
|
@@ -22289,7 +22956,8 @@ function buildToolList() {
|
|
|
22289
22956
|
inputSchema: {
|
|
22290
22957
|
type: "object",
|
|
22291
22958
|
properties: {
|
|
22292
|
-
heldCredentials: { type: "array", items: { type: "object" }, description: "VCs the client holds. Omit to report whatever the wallet has cached locally from prior subscribe_and_issue calls instead." }
|
|
22959
|
+
heldCredentials: { type: "array", items: { type: "object" }, description: "VCs the client holds. Omit to report whatever the wallet has cached locally from prior subscribe_and_issue calls instead." },
|
|
22960
|
+
token: { type: "string", description: `Optional token symbol (e.g. "ZTX", "JMYR") to check its balance for the active network, alongside the usual status fields. Returns { balance, decimals } where balance is in the asset's raw base units \u2014 divide by 10^decimals for the human amount (e.g. balance "473999900" with decimals 6 is 473.9999 JMYR). A failed lookup reports { error: "query_failed" } rather than a zero balance.` }
|
|
22293
22961
|
}
|
|
22294
22962
|
}
|
|
22295
22963
|
},
|
|
@@ -22328,9 +22996,36 @@ function buildToolList() {
|
|
|
22328
22996
|
required: ["url"]
|
|
22329
22997
|
}
|
|
22330
22998
|
},
|
|
22999
|
+
{
|
|
23000
|
+
name: "get_template_schema",
|
|
23001
|
+
description: `Read a VC template's declared attribute schema from chain \u2014 FREE, no payment, no signing, no MBI issuance. Call this BEFORE subscribe_and_issue to find out which attributes a template requires, rather than discovering a missing one by attempting an issuance and being rejected. Accepts a did:zid:... credential-definition id or a known template name (e.g. "AI Birthcert"). Returns { templateId, schema: { required, optional } }; attributes the wallet fills in itself (agentDid, alias-derived keys) are omitted since you never supply them. A template that cannot be read reports { error } rather than an empty schema, so "needs nothing" is never confused with "could not look it up".`,
|
|
23002
|
+
inputSchema: {
|
|
23003
|
+
type: "object",
|
|
23004
|
+
properties: {
|
|
23005
|
+
templateId: {
|
|
23006
|
+
type: "string",
|
|
23007
|
+
description: 'The MBI credential-definition id (did:zid:...) or a known template name, e.g. "AI Birthcert".'
|
|
23008
|
+
}
|
|
23009
|
+
},
|
|
23010
|
+
required: ["templateId"]
|
|
23011
|
+
}
|
|
23012
|
+
},
|
|
23013
|
+
{
|
|
23014
|
+
name: "query_contract",
|
|
23015
|
+
description: 'Read-only query against a Zetrix contract or account \u2014 call an arbitrary contract method (e.g. "balanceOf", "contractInfo") and return its raw result. No signing, no state change.',
|
|
23016
|
+
inputSchema: {
|
|
23017
|
+
type: "object",
|
|
23018
|
+
properties: {
|
|
23019
|
+
contractAddress: { type: "string", description: "Zetrix contract address to query." },
|
|
23020
|
+
method: { type: "string", description: 'Contract method name, e.g. "balanceOf", "contractInfo".' },
|
|
23021
|
+
params: { type: "object", description: 'Method parameters, e.g. { "address": "ZTX..." } for balanceOf.' }
|
|
23022
|
+
},
|
|
23023
|
+
required: ["contractAddress", "method"]
|
|
23024
|
+
}
|
|
23025
|
+
},
|
|
22331
23026
|
{
|
|
22332
23027
|
name: "subscribe_and_issue",
|
|
22333
|
-
description: "Obtain a VC from MBI: build the signed payload, pay x402, and return the issued credential. If a still-valid credential for this templateId is already cached locally, it is returned directly with no payment (fromCache: true) \u2014 pass forceReissue:true to pay and issue fresh regardless. Payment is asset-agnostic \u2014 MBI's 402 challenge may quote the native ZETRIX token or a ZTP20 token (e.g. JMYR); pass dryRun:true first to see the quoted asset/amount for free before committing to pay.",
|
|
23028
|
+
description: "Obtain a VC from MBI: build the signed payload, pay x402, and return the issued credential. If a still-valid credential for this templateId is already cached locally, it is returned directly with no payment (fromCache: true) \u2014 pass forceReissue:true to pay and issue fresh regardless. Payment is asset-agnostic \u2014 MBI's 402 challenge may quote the native ZETRIX token or a ZTP20 token (e.g. JMYR); pass dryRun:true first to see the quoted asset/amount for free before committing to pay. What a call actually cost is reported precisely: paidAsset/amountPaid are set ONLY when this call paid, a cache hit reports the earlier charge under originalPayment instead (never as amountPaid, so summing spend cannot double-count), and any failure after the payment has settled on chain reports paymentAttempted: { asset, amount, paymentId }. Two such failures exist and mean different things: MBI 4006 is a definitive facilitator rejection, while 4012 (HTTP 502) means the outcome is INDETERMINATE \u2014 the payment may well have landed. On 4012 the wallet automatically polls MBI's recovery endpoint and reports recovery: { status, txHash?, vcId?, polls }, where status is ISSUED (the credential exists after all \u2014 fetch it by vcId, since recovery returns no VC body), FAILED, or REQUIRED/SETTLED (still unresolved) / UNKNOWN (recovery itself unreachable). NEVER retry a payment after either failure: the funds may already be gone, and a retry charges the full amount again \u2014 look the paymentId up instead. Every response except a cache hit also includes { schema: { required, optional } } \u2014 the template's full declared attribute schema read from chain \u2014 so you see the complete field list, not just what went wrong; a cache hit skips the chain lookup and omits it.",
|
|
22334
23029
|
inputSchema: {
|
|
22335
23030
|
type: "object",
|
|
22336
23031
|
properties: {
|
|
@@ -22345,7 +23040,7 @@ function buildToolList() {
|
|
|
22345
23040
|
expirationDate: { type: "string" },
|
|
22346
23041
|
dryRun: {
|
|
22347
23042
|
type: "boolean",
|
|
22348
|
-
description: "Stop after MBI's free phase-1 quote and return { quote: { asset, maxAmountRequired, payTo,
|
|
23043
|
+
description: "Stop after MBI's free phase-1 quote and return { quote: { asset, maxAmountRequired, payTo }, schema: { required, optional } } without paying or issuing \u2014 use this to check the payment requirement AND the template's full attribute schema (read from chain) before spending funds. Still validates required attributes locally first \u2014 a missing one blocks before any MBI call."
|
|
22349
23044
|
},
|
|
22350
23045
|
forceReissue: {
|
|
22351
23046
|
type: "boolean",
|
|
@@ -22388,10 +23083,13 @@ async function main() {
|
|
|
22388
23083
|
const config2 = loadConfig(env);
|
|
22389
23084
|
const hsmPassword = config2.hsmPassword;
|
|
22390
23085
|
const be = new WalletBeClient(config2.walletBeUrl);
|
|
22391
|
-
const
|
|
23086
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
23087
|
+
const { zetrixAddress, holderDid, created, didMismatch, activated } = await resolveHolder(
|
|
22392
23088
|
{
|
|
22393
23089
|
createAccount: (password) => be.createAccount(password),
|
|
22394
|
-
signMessage: (message, address, password) => be.signMessage(message, address, password)
|
|
23090
|
+
signMessage: (message, address, password) => be.signMessage(message, address, password),
|
|
23091
|
+
checkActivationStatus: (address) => be.checkActivationStatus(address),
|
|
23092
|
+
sleep
|
|
22395
23093
|
},
|
|
22396
23094
|
{ zetrixAddress: config2.zetrixAddress, holderDid: config2.holderDid, hsmPassword }
|
|
22397
23095
|
);
|
|
@@ -22410,6 +23108,12 @@ async function main() {
|
|
|
22410
23108
|
if (didMismatch) {
|
|
22411
23109
|
process.stderr.write(
|
|
22412
23110
|
`agentic-wallet-mcp: configured HOLDER_DID=${config2.holderDid} does not match the account's actual public key \u2014 using the derived HOLDER_DID=${holderDid} instead. Update your MCP config.
|
|
23111
|
+
`
|
|
23112
|
+
);
|
|
23113
|
+
}
|
|
23114
|
+
if (created && !activated) {
|
|
23115
|
+
process.stderr.write(
|
|
23116
|
+
`agentic-wallet-mcp: the newly created HSM account (ZETRIX_ADDRESS=${zetrixAddress}) has not completed on-chain activation yet \u2014 balance/on-chain calls for this address may fail until it does.
|
|
22413
23117
|
`
|
|
22414
23118
|
);
|
|
22415
23119
|
}
|
|
@@ -22420,6 +23124,20 @@ async function main() {
|
|
|
22420
23124
|
const sdk = new import_zetrix_sdk_nodejs.default({ host: config2.nodeHost, port: config2.nodePort });
|
|
22421
23125
|
const contractQuery = (a) => sdk.contract.call(a);
|
|
22422
23126
|
const resolveSymbol = (asset) => resolveAssetSymbol(asset, contractQuery);
|
|
23127
|
+
const fetchNativeBalance = async (address) => {
|
|
23128
|
+
const res = await sdk.account.getInfo(address);
|
|
23129
|
+
if (res.errorCode !== 0) throw new Error(`getInfo failed with errorCode ${res.errorCode}`);
|
|
23130
|
+
const balance = res.result?.balance;
|
|
23131
|
+
if (typeof balance !== "string") throw new Error("getInfo returned no balance");
|
|
23132
|
+
return balance;
|
|
23133
|
+
};
|
|
23134
|
+
const tokenBalanceDeps = {
|
|
23135
|
+
address: zetrixAddress,
|
|
23136
|
+
fetchNativeBalance,
|
|
23137
|
+
resolveTokenAddress: (symbol) => resolveTokenAddress(symbol, config2.network) ?? null,
|
|
23138
|
+
query: contractQuery
|
|
23139
|
+
};
|
|
23140
|
+
const queryTokenBalance2 = (token) => queryTokenBalance(tokenBalanceDeps, token);
|
|
22423
23141
|
const nodeBaseUrl = `https://${config2.nodeHost}${config2.nodePort ? `:${config2.nodePort}` : ""}`;
|
|
22424
23142
|
const nodeMetaQuery = (url) => fetch(url, { headers: { Accept: "application/json" } }).then((r) => r.json());
|
|
22425
23143
|
const resolveTemplateFields = (templateId) => fetchTemplateFields(templateId, config2.templateRegistryAddress, nodeBaseUrl, nodeMetaQuery);
|
|
@@ -22427,7 +23145,10 @@ async function main() {
|
|
|
22427
23145
|
const vcCache = createFsVcCache((0, import_node_path3.join)((0, import_node_os.homedir)(), ".agentic-wallet-mcp", "vc-cache", cacheScope));
|
|
22428
23146
|
const pay = (accept) => {
|
|
22429
23147
|
assertWithinPaymentCap(accept, config2.maxPaymentAmount);
|
|
22430
|
-
return
|
|
23148
|
+
return payWithReadinessCheck(
|
|
23149
|
+
String(accept.asset ?? ""),
|
|
23150
|
+
() => import_x402_zetrix_client2.PaymentEngine.pay(asPayRequest(accept), walletCfg, node, {}, walletBeSignerFn)
|
|
23151
|
+
);
|
|
22431
23152
|
};
|
|
22432
23153
|
const payer = async (req) => {
|
|
22433
23154
|
const init = { method: req.method ?? "GET", headers: req.headers, body: req.body };
|
|
@@ -22438,7 +23159,15 @@ async function main() {
|
|
|
22438
23159
|
const parsed = await res.json();
|
|
22439
23160
|
const accept = parsed.accepts?.[0];
|
|
22440
23161
|
if (!accept) throw new Error("pay_and_fetch: 402 had no accepts[]");
|
|
22441
|
-
|
|
23162
|
+
let xPayment;
|
|
23163
|
+
try {
|
|
23164
|
+
xPayment = await pay(accept);
|
|
23165
|
+
} catch (err) {
|
|
23166
|
+
if (err instanceof PaymentReadinessError) {
|
|
23167
|
+
return { status: 402, body: "", paymentMade: false, amountPaid: "", amountPaidHuman: "", asset: "", insufficientFunds: err.shortfall };
|
|
23168
|
+
}
|
|
23169
|
+
throw err;
|
|
23170
|
+
}
|
|
22442
23171
|
const retry = await fetch(req.url, { ...init, headers: { ...req.headers ?? {}, "x-payment": xPayment } });
|
|
22443
23172
|
const asset = await resolveSymbol(String(accept.asset ?? ""));
|
|
22444
23173
|
return {
|
|
@@ -22468,8 +23197,12 @@ async function main() {
|
|
|
22468
23197
|
makeWallet,
|
|
22469
23198
|
payer,
|
|
22470
23199
|
subscribeDeps: { mbi, sign: subscribeSign, pay, resolveSymbol, holderDid, resolveTemplateFields, cache: vcCache },
|
|
23200
|
+
queryContract: (input) => queryContract(input, contractQuery),
|
|
23201
|
+
queryTokenBalance: queryTokenBalance2,
|
|
22471
23202
|
createAccount: (password, label, purpose) => be.createAccount(password, label, purpose),
|
|
22472
23203
|
saveAccount: (account) => accountStore.set({ ...account, createdAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
23204
|
+
checkActivationStatus: (address) => be.checkActivationStatus(address),
|
|
23205
|
+
sleep,
|
|
22473
23206
|
cache: vcCache
|
|
22474
23207
|
};
|
|
22475
23208
|
const tools = createTools(deps);
|