@haven_ai/sdk 0.1.22-alpha.0 → 0.1.23-alpha.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/README.md +11 -7
- package/dist/index.cjs +137 -550
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -158
- package/dist/index.d.ts +110 -158
- package/dist/index.js +137 -547
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -102,7 +102,23 @@ var AgentPaymentFailureCode = {
|
|
|
102
102
|
* mechanical: re-send merchant_url, tool_name, arguments, and
|
|
103
103
|
* mcp_transport explicitly (the version-skew path).
|
|
104
104
|
*/
|
|
105
|
-
MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE"
|
|
105
|
+
MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE",
|
|
106
|
+
/**
|
|
107
|
+
* #1351: the caller supplied BOTH the atomic `max_amount` and the
|
|
108
|
+
* human-denominated `max_amount_human` cap for one purchase. Haven refuses
|
|
109
|
+
* to guess which the user meant — the two differ by a factor of 10^decimals,
|
|
110
|
+
* so picking wrong is exactly the silent-overspend this cap exists to
|
|
111
|
+
* prevent. Rejected before any merchant probe, funding intent, or signature.
|
|
112
|
+
*/
|
|
113
|
+
AmbiguousMaxAmount: "AMBIGUOUS_MAX_AMOUNT",
|
|
114
|
+
/**
|
|
115
|
+
* #1351: a human-denominated cap was supplied, but it cannot be converted to
|
|
116
|
+
* atomic units against THIS quote — either the quote's asset has no known
|
|
117
|
+
* decimals on its network, or the cap carries more fraction digits than the
|
|
118
|
+
* asset can represent (truncating it would silently change the user's cap).
|
|
119
|
+
* The fallback is the exact atomic `max_amount`.
|
|
120
|
+
*/
|
|
121
|
+
MaxAmountUnconvertible: "MAX_AMOUNT_UNCONVERTIBLE"
|
|
106
122
|
};
|
|
107
123
|
var AgentPaymentRail = {
|
|
108
124
|
/** Standard Haven payment from the user's Safe through an approved delegate allowance. */
|
|
@@ -157,7 +173,9 @@ var AgentPaymentFailureCodeDescriptions = {
|
|
|
157
173
|
[AgentPaymentFailureCode.PaymentWindowExpired]: "The x402 funding/quote window expired before the signer or hosted settle step could finish. Re-quote via haven_pay_mcp_tool with the same idempotency key to avoid duplicate funding.",
|
|
158
174
|
[AgentPaymentFailureCode.MerchantRejectedAfterFunding]: "The Haven funding leg succeeded, but the merchant rejected the paid retry. Stop retrying the merchant and reconcile stranded delegate funds with haven_sweep_delegate.",
|
|
159
175
|
[AgentPaymentFailureCode.MerchantUnresponsiveAfterFunding]: "The Haven funding leg succeeded, but the merchant did not answer the paid retry before the timeout. The merchant may still settle late \u2014 check haven_get_payment_status (and retry haven_complete_mcp_tool once) BEFORE sweeping; sweep only if no settlement appears.",
|
|
160
|
-
[AgentPaymentFailureCode.MerchantCallContextUnavailable]: "merchant_url/tool_name were omitted and no stored merchant call context is available for this payment_id. Re-send merchant_url, tool_name, arguments, and mcp_transport explicitly."
|
|
176
|
+
[AgentPaymentFailureCode.MerchantCallContextUnavailable]: "merchant_url/tool_name were omitted and no stored merchant call context is available for this payment_id. Re-send merchant_url, tool_name, arguments, and mcp_transport explicitly.",
|
|
177
|
+
[AgentPaymentFailureCode.AmbiguousMaxAmount]: "Both max_amount (atomic units) and max_amount_human (whole tokens) were supplied for one purchase. Nothing was contacted and nothing was spent. Re-send with exactly ONE: max_amount_human for a cap the user stated in tokens, max_amount for an exact atomic figure.",
|
|
178
|
+
[AgentPaymentFailureCode.MaxAmountUnconvertible]: "max_amount_human could not be converted to atomic units against this quote's asset \u2014 either its decimals are unknown to Haven or the cap has more decimal places than the asset supports. Nothing was spent. Round the cap, or re-send it as an exact atomic max_amount."
|
|
161
179
|
};
|
|
162
180
|
var AgentPaymentWarningCode = {
|
|
163
181
|
/** No max_amount cap was supplied — the live quoted price was accepted as-is. */
|
|
@@ -683,73 +701,6 @@ function stableStringify(value) {
|
|
|
683
701
|
const object = value;
|
|
684
702
|
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
|
|
685
703
|
}
|
|
686
|
-
function normalizeChallenge(value) {
|
|
687
|
-
const candidate = value;
|
|
688
|
-
if (!candidate || typeof candidate !== "object" || candidate.rail !== "mpp_demo" || typeof candidate.version !== "string" || typeof candidate.challengeId !== "string" || typeof candidate.resource !== "string" || typeof candidate.description !== "string" || // TODO: relax these checks when non-demo machine payment rails are added.
|
|
689
|
-
candidate.network?.chainId !== 8453 || candidate.network?.name !== "base" || candidate.asset?.symbol !== "USDC" || typeof candidate.asset?.address !== "string" || candidate.asset.decimals !== 6 || typeof candidate.amount?.display !== "string" || typeof candidate.amount?.atomic !== "string" || typeof candidate.recipient !== "string" || typeof candidate.expiresAt !== "string") {
|
|
690
|
-
return null;
|
|
691
|
-
}
|
|
692
|
-
return {
|
|
693
|
-
rail: candidate.rail,
|
|
694
|
-
version: candidate.version,
|
|
695
|
-
challengeId: candidate.challengeId,
|
|
696
|
-
resource: candidate.resource,
|
|
697
|
-
description: candidate.description,
|
|
698
|
-
network: candidate.network,
|
|
699
|
-
asset: candidate.asset,
|
|
700
|
-
amount: candidate.amount,
|
|
701
|
-
recipient: candidate.recipient,
|
|
702
|
-
expiresAt: candidate.expiresAt,
|
|
703
|
-
metadata: candidate.metadata
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
function parseMachinePaymentChallenge(response) {
|
|
707
|
-
const header = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
|
|
708
|
-
if (!header) {
|
|
709
|
-
throw new Error("No MACHINE-PAYMENT-CHALLENGE header found in 402 response.");
|
|
710
|
-
}
|
|
711
|
-
const parsed = normalizeChallenge(
|
|
712
|
-
decodeBase64Json(header, "MACHINE-PAYMENT-CHALLENGE header")
|
|
713
|
-
);
|
|
714
|
-
if (!parsed) throw new Error("Invalid machine payment challenge");
|
|
715
|
-
return parsed;
|
|
716
|
-
}
|
|
717
|
-
async function parseMachinePaymentChallengeResponse(response) {
|
|
718
|
-
try {
|
|
719
|
-
return parseMachinePaymentChallenge(response);
|
|
720
|
-
} catch (headerErr) {
|
|
721
|
-
try {
|
|
722
|
-
const body = await response.clone().json();
|
|
723
|
-
const parsed = normalizeChallenge(body.challenge);
|
|
724
|
-
if (parsed) return parsed;
|
|
725
|
-
} catch {
|
|
726
|
-
}
|
|
727
|
-
throw headerErr;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
function buildMachinePaymentIdempotencyKey(challenge) {
|
|
731
|
-
const material = [
|
|
732
|
-
challenge.rail,
|
|
733
|
-
challenge.challengeId,
|
|
734
|
-
challenge.resource,
|
|
735
|
-
challenge.recipient.toLowerCase(),
|
|
736
|
-
challenge.asset.address.toLowerCase(),
|
|
737
|
-
challenge.amount.atomic,
|
|
738
|
-
challenge.network.chainId
|
|
739
|
-
].join("|");
|
|
740
|
-
return `${challenge.rail}:${createHash("sha256").update(material).digest("hex").slice(0, 16)}`;
|
|
741
|
-
}
|
|
742
|
-
function encodeMachinePaymentProof(receipt) {
|
|
743
|
-
return encodeBase64Json({
|
|
744
|
-
rail: receipt.rail,
|
|
745
|
-
challengeId: receipt.challengeId,
|
|
746
|
-
paymentId: receipt.paymentId,
|
|
747
|
-
txHash: receipt.txHash,
|
|
748
|
-
settledVia: "haven",
|
|
749
|
-
payer: receipt.payer,
|
|
750
|
-
chainId: receipt.chainId
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
704
|
function createJsonRpcProvider(url) {
|
|
754
705
|
return new ethers.JsonRpcProvider(url);
|
|
755
706
|
}
|
|
@@ -870,9 +821,6 @@ function messageForState(label, status, paymentId, nextAction) {
|
|
|
870
821
|
function sameAddress(a, b) {
|
|
871
822
|
return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
|
|
872
823
|
}
|
|
873
|
-
function isMppRail(rail) {
|
|
874
|
-
return rail === "mpp" || Boolean(rail?.startsWith("mpp_"));
|
|
875
|
-
}
|
|
876
824
|
function decimalFromUsdcAtomic(value) {
|
|
877
825
|
const amount = BigInt(value);
|
|
878
826
|
const whole = amount / 1000000n;
|
|
@@ -974,7 +922,6 @@ var HavenClient = class {
|
|
|
974
922
|
chainRpcs;
|
|
975
923
|
inFlightX402 = /* @__PURE__ */ new Map();
|
|
976
924
|
x402ReceiptCache = /* @__PURE__ */ new Map();
|
|
977
|
-
inFlightMachinePayments = /* @__PURE__ */ new Map();
|
|
978
925
|
/**
|
|
979
926
|
* Setup-time headers configured via `HavenClientConfig.defaultHeaders`.
|
|
980
927
|
* Read-only after construction — use `withRequestContext` for per-call
|
|
@@ -1092,8 +1039,7 @@ var HavenClient = class {
|
|
|
1092
1039
|
400
|
|
1093
1040
|
);
|
|
1094
1041
|
}
|
|
1095
|
-
const
|
|
1096
|
-
const fundingTo = agent.delegateAddress;
|
|
1042
|
+
const fundingTo = options.delegateAddress ?? (await this.getAgent()).delegateAddress;
|
|
1097
1043
|
if (!fundingTo) {
|
|
1098
1044
|
throw new HavenApiError("Authenticated agent has no delegate address registered.", 502);
|
|
1099
1045
|
}
|
|
@@ -1102,13 +1048,25 @@ var HavenClient = class {
|
|
|
1102
1048
|
url: paymentRequired.resource.url,
|
|
1103
1049
|
payTo: fundingTo,
|
|
1104
1050
|
merchantPayTo: option.payTo,
|
|
1051
|
+
// #1360: this path ALWAYS means the EIP-3009 funding leg (payTo is the
|
|
1052
|
+
// agent's own delegate EOA). Saying so explicitly turns a stale/rotated
|
|
1053
|
+
// delegate address into the backend's LOUD shape-mismatch 400 instead
|
|
1054
|
+
// of a silent reroute to the erc7710 settlement branch (the #1358
|
|
1055
|
+
// review's open-budget misroute). Legacy-rail backends ignore the field.
|
|
1056
|
+
settlementScheme: "eip3009",
|
|
1105
1057
|
amount: x402AuthorizationAmount(option),
|
|
1106
1058
|
asset: option.asset,
|
|
1107
1059
|
network: option.network,
|
|
1108
1060
|
description: paymentRequired.resource.description,
|
|
1109
1061
|
idempotencyKey,
|
|
1110
1062
|
// #1307: persisted so the settle leg can rehydrate it by payment_id.
|
|
1111
|
-
...options.mcpCallContext ? { mcpCallContext: options.mcpCallContext } : {}
|
|
1063
|
+
...options.mcpCallContext ? { mcpCallContext: options.mcpCallContext } : {},
|
|
1064
|
+
// #1355: persisted so the SIGN leg can rehydrate it by payment_id — the
|
|
1065
|
+
// local signer's context fetch then carries the 402 PaymentRequired and
|
|
1066
|
+
// the agent passes only payment_id. Bounded: the backend rejects >64KB,
|
|
1067
|
+
// so an oversized blob is omitted here (signer falls back to the
|
|
1068
|
+
// caller-supplied copy) rather than failing the intent.
|
|
1069
|
+
...new TextEncoder().encode(JSON.stringify(paymentRequired)).length <= 65536 ? { paymentRequired } : {}
|
|
1112
1070
|
});
|
|
1113
1071
|
if (raw.status !== "pending_signature") {
|
|
1114
1072
|
this.throwPaymentStateError("x402 payment", raw);
|
|
@@ -1240,6 +1198,17 @@ var HavenClient = class {
|
|
|
1240
1198
|
* Get the agent identity tied to this API key.
|
|
1241
1199
|
*/
|
|
1242
1200
|
async getAgent() {
|
|
1201
|
+
if (this.agentInFlight) return this.agentInFlight;
|
|
1202
|
+
const request = this.fetchAgent();
|
|
1203
|
+
this.agentInFlight = request;
|
|
1204
|
+
request.finally(() => {
|
|
1205
|
+
this.agentInFlight = null;
|
|
1206
|
+
}).catch(() => {
|
|
1207
|
+
});
|
|
1208
|
+
return request;
|
|
1209
|
+
}
|
|
1210
|
+
agentInFlight = null;
|
|
1211
|
+
async fetchAgent() {
|
|
1243
1212
|
const raw = await this.get("/machine-payments/agent");
|
|
1244
1213
|
return {
|
|
1245
1214
|
id: raw.id,
|
|
@@ -1438,6 +1407,7 @@ var HavenClient = class {
|
|
|
1438
1407
|
*/
|
|
1439
1408
|
async getPostPurchaseAllowanceSummary(paymentId) {
|
|
1440
1409
|
const unavailable = (detail) => ({
|
|
1410
|
+
payment: null,
|
|
1441
1411
|
allowance: null,
|
|
1442
1412
|
warnings: [
|
|
1443
1413
|
{
|
|
@@ -1446,27 +1416,38 @@ var HavenClient = class {
|
|
|
1446
1416
|
}
|
|
1447
1417
|
]
|
|
1448
1418
|
});
|
|
1419
|
+
const [statusResult, agentResult, allowanceResult] = await Promise.allSettled([
|
|
1420
|
+
this.getPaymentStatus(paymentId),
|
|
1421
|
+
this.getAgent(),
|
|
1422
|
+
this.getAllowances()
|
|
1423
|
+
]);
|
|
1424
|
+
if (statusResult.status === "rejected") {
|
|
1425
|
+
return unavailable(statusResult.reason instanceof Error ? statusResult.reason.message : String(statusResult.reason));
|
|
1426
|
+
}
|
|
1427
|
+
const status = statusResult.value;
|
|
1428
|
+
if (agentResult.status === "rejected") {
|
|
1429
|
+
return { ...unavailable(agentResult.reason instanceof Error ? agentResult.reason.message : String(agentResult.reason)), payment: status };
|
|
1430
|
+
}
|
|
1431
|
+
if (allowanceResult.status === "rejected") {
|
|
1432
|
+
return { ...unavailable(allowanceResult.reason instanceof Error ? allowanceResult.reason.message : String(allowanceResult.reason)), payment: status };
|
|
1433
|
+
}
|
|
1449
1434
|
try {
|
|
1450
|
-
const [status, agent, allowanceSummary] = await Promise.all([
|
|
1451
|
-
this.getPaymentStatus(paymentId),
|
|
1452
|
-
this.getAgent(),
|
|
1453
|
-
this.getAllowances()
|
|
1454
|
-
]);
|
|
1455
1435
|
const tokenAddress = status.asset ?? status.x402?.asset ?? null;
|
|
1456
1436
|
if (!tokenAddress) {
|
|
1457
|
-
return unavailable("the settled payment does not carry a resolvable token address");
|
|
1437
|
+
return { ...unavailable("the settled payment does not carry a resolvable token address"), payment: status };
|
|
1458
1438
|
}
|
|
1459
|
-
const rail =
|
|
1439
|
+
const rail = agentResult.value.executionRail;
|
|
1460
1440
|
const source = rail === "delegation" ? "active_delegations" : "allowance_module";
|
|
1461
|
-
const match =
|
|
1441
|
+
const match = allowanceResult.value.allowances.find(
|
|
1462
1442
|
(a) => a.tokenAddress.toLowerCase() === tokenAddress.toLowerCase()
|
|
1463
1443
|
);
|
|
1464
1444
|
if (!match) {
|
|
1465
|
-
return unavailable("no allowance/budget row matches the settled token");
|
|
1445
|
+
return { ...unavailable("no allowance/budget row matches the settled token"), payment: status };
|
|
1466
1446
|
}
|
|
1467
1447
|
const token = resolveTokenFromAddress(match.tokenAddress);
|
|
1468
1448
|
const remainingDisplay = token ? `${formatAtomicAmount(safeBigInt(match.onchain.remaining), token.decimals)} ${match.tokenSymbol}` : void 0;
|
|
1469
1449
|
return {
|
|
1450
|
+
payment: status,
|
|
1470
1451
|
allowance: {
|
|
1471
1452
|
rail,
|
|
1472
1453
|
remaining_atomic: match.onchain.remaining,
|
|
@@ -1514,6 +1495,7 @@ var HavenClient = class {
|
|
|
1514
1495
|
async discoverTools(options = {}) {
|
|
1515
1496
|
const params = new URLSearchParams();
|
|
1516
1497
|
if (options.category) params.set("category", options.category);
|
|
1498
|
+
if (options.search !== void 0) params.set("search", options.search);
|
|
1517
1499
|
if (options.rail) params.set("rail", options.rail);
|
|
1518
1500
|
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1519
1501
|
const raw = await this.get(`/catalog${query}`);
|
|
@@ -1553,10 +1535,11 @@ var HavenClient = class {
|
|
|
1553
1535
|
return { receipt, verification: verifyPaymentReceipt(receipt) };
|
|
1554
1536
|
}
|
|
1555
1537
|
/**
|
|
1556
|
-
* Rehydrate the x402
|
|
1538
|
+
* Rehydrate the x402 resume-state bundle for a payment id (#1328: the MPP
|
|
1539
|
+
* resume-state variant retired along with the rest of the mpp_demo surface).
|
|
1557
1540
|
*
|
|
1558
1541
|
* The server returns stored protocol context only. The client still signs the
|
|
1559
|
-
* merchant proof locally when resumeX402Payment()
|
|
1542
|
+
* merchant proof locally when resumeX402Payment() runs.
|
|
1560
1543
|
*/
|
|
1561
1544
|
async getResumeState(paymentId) {
|
|
1562
1545
|
return this.get(`/payments/${paymentId}/resume_state`);
|
|
@@ -1705,7 +1688,11 @@ var HavenClient = class {
|
|
|
1705
1688
|
asset: option.asset,
|
|
1706
1689
|
network: option.network,
|
|
1707
1690
|
description: paymentRequired.resource.description,
|
|
1708
|
-
idempotencyKey
|
|
1691
|
+
idempotencyKey,
|
|
1692
|
+
// #1360: same explicit funding-leg declaration as createX402Intent —
|
|
1693
|
+
// this local-key path derives payTo from the key (never stale), but the
|
|
1694
|
+
// declaration keeps both writers of the 3009 shape loud-by-default.
|
|
1695
|
+
settlementScheme: "eip3009"
|
|
1709
1696
|
});
|
|
1710
1697
|
if (raw.success && raw.tx_hash) {
|
|
1711
1698
|
const receipt2 = this.mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw);
|
|
@@ -1823,22 +1810,11 @@ var HavenClient = class {
|
|
|
1823
1810
|
if (response.status !== 402) {
|
|
1824
1811
|
return mcpSessionId ? this.surfaceMcpResult(response) : response;
|
|
1825
1812
|
}
|
|
1826
|
-
const machineChallengeHeader = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
|
|
1827
|
-
if (machineChallengeHeader) {
|
|
1828
|
-
const challenge = await parseMachinePaymentChallengeResponse(response);
|
|
1829
|
-
return this.fetchWithMachinePayment(url, requestInit, challenge);
|
|
1830
|
-
}
|
|
1831
1813
|
let paymentRequired;
|
|
1832
1814
|
try {
|
|
1833
1815
|
paymentRequired = await parsePaymentRequiredResponse(response);
|
|
1834
1816
|
} catch {
|
|
1835
|
-
|
|
1836
|
-
try {
|
|
1837
|
-
challenge = await parseMachinePaymentChallengeResponse(response);
|
|
1838
|
-
} catch {
|
|
1839
|
-
return response;
|
|
1840
|
-
}
|
|
1841
|
-
return this.fetchWithMachinePayment(url, requestInit, challenge);
|
|
1817
|
+
return response;
|
|
1842
1818
|
}
|
|
1843
1819
|
if (!mcpSessionId && await responseHasBazaarExtension(response)) {
|
|
1844
1820
|
mcpSessionId = await this.mcpInitialize(url, init);
|
|
@@ -1981,49 +1957,6 @@ var HavenClient = class {
|
|
|
1981
1957
|
headers
|
|
1982
1958
|
});
|
|
1983
1959
|
}
|
|
1984
|
-
/**
|
|
1985
|
-
* Probe a paid MPP endpoint or inspect an existing challenge without creating
|
|
1986
|
-
* a Haven payment or approval request.
|
|
1987
|
-
*/
|
|
1988
|
-
async quoteMpp(challengeOrUrl, init, options = {}) {
|
|
1989
|
-
if (typeof challengeOrUrl !== "string") {
|
|
1990
|
-
const request2 = this.snapshotX402Request(challengeOrUrl.resource, init);
|
|
1991
|
-
return this.buildMppQuote(challengeOrUrl, request2, options.idempotencyKey);
|
|
1992
|
-
}
|
|
1993
|
-
const request = this.snapshotX402Request(challengeOrUrl, init);
|
|
1994
|
-
const response = await this.merchantFetch(challengeOrUrl, init);
|
|
1995
|
-
if (response.status !== 402) {
|
|
1996
|
-
throw new HavenApiError(
|
|
1997
|
-
`Expected an MPP quote response with HTTP 402, got HTTP ${response.status}.`,
|
|
1998
|
-
response.status || 400
|
|
1999
|
-
);
|
|
2000
|
-
}
|
|
2001
|
-
const challenge = await parseMachinePaymentChallengeResponse(response);
|
|
2002
|
-
return this.buildMppQuote(challenge, request, options.idempotencyKey);
|
|
2003
|
-
}
|
|
2004
|
-
/**
|
|
2005
|
-
* Pay a previously inspected MPP quote and retry the exact captured request.
|
|
2006
|
-
*/
|
|
2007
|
-
async payMppChallenge(quote, options = {}) {
|
|
2008
|
-
const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
|
|
2009
|
-
try {
|
|
2010
|
-
const receipt = await this.authorizeMachinePayment(quote.challenge, { idempotencyKey });
|
|
2011
|
-
return this.retryMppRequest(
|
|
2012
|
-
quote.request.url,
|
|
2013
|
-
this.requestInitFromSnapshot(quote.request),
|
|
2014
|
-
quote.challenge,
|
|
2015
|
-
receipt
|
|
2016
|
-
);
|
|
2017
|
-
} catch (err) {
|
|
2018
|
-
this.attachResumeState(err, {
|
|
2019
|
-
rail: "mpp",
|
|
2020
|
-
challenge: quote.challenge,
|
|
2021
|
-
idempotencyKey,
|
|
2022
|
-
request: quote.request
|
|
2023
|
-
});
|
|
2024
|
-
throw err;
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
1960
|
async retryX402Request(url, initialInit, paymentRequired, receipt) {
|
|
2028
1961
|
if (!receipt.accepted) {
|
|
2029
1962
|
throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
|
|
@@ -2288,151 +2221,13 @@ var HavenClient = class {
|
|
|
2288
2221
|
return void 0;
|
|
2289
2222
|
}
|
|
2290
2223
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
throw new HavenApiError(`Unsupported machine payment rail: ${challenge.rail}`, 400);
|
|
2299
|
-
}
|
|
2300
|
-
const idempotencyKey = options.idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge);
|
|
2301
|
-
const inFlight = this.inFlightMachinePayments.get(idempotencyKey);
|
|
2302
|
-
if (inFlight) return inFlight;
|
|
2303
|
-
const promise = this.authorizeMppDemoPayment(challenge, idempotencyKey);
|
|
2304
|
-
this.inFlightMachinePayments.set(idempotencyKey, promise);
|
|
2305
|
-
try {
|
|
2306
|
-
return await promise;
|
|
2307
|
-
} catch (err) {
|
|
2308
|
-
this.attachResumeState(err, {
|
|
2309
|
-
rail: "mpp",
|
|
2310
|
-
challenge,
|
|
2311
|
-
idempotencyKey
|
|
2312
|
-
});
|
|
2313
|
-
throw err;
|
|
2314
|
-
} finally {
|
|
2315
|
-
this.inFlightMachinePayments.delete(idempotencyKey);
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
async authorizeMppDemoPayment(challenge, idempotencyKey) {
|
|
2319
|
-
const raw = await this.post(
|
|
2320
|
-
"/machine-payments/authorize",
|
|
2321
|
-
{ challenge, idempotencyKey }
|
|
2322
|
-
);
|
|
2323
|
-
if (raw.success && raw.tx_hash) {
|
|
2324
|
-
return this.mapMachinePaymentReceipt(challenge, raw, raw.tx_hash);
|
|
2325
|
-
}
|
|
2326
|
-
this.throwIfNonSignableAuthorizationState("Machine payment", raw);
|
|
2327
|
-
if (!raw.sign_data?.hash) {
|
|
2328
|
-
throw new HavenApiError("No sign_hash returned from machine payment authorization", 500, raw);
|
|
2329
|
-
}
|
|
2330
|
-
const sig = await this.signForData(raw.sign_data);
|
|
2331
|
-
const execResult = await this.post(
|
|
2332
|
-
`/payments/${raw.payment_id}/sign`,
|
|
2333
|
-
{ signature: sig }
|
|
2334
|
-
);
|
|
2335
|
-
if (execResult.status !== "confirmed" || !execResult.tx_hash) {
|
|
2336
|
-
this.throwPaymentStateError("Machine payment", execResult);
|
|
2337
|
-
}
|
|
2338
|
-
return this.mapMachinePaymentReceipt(challenge, raw, execResult.tx_hash, execResult);
|
|
2339
|
-
}
|
|
2340
|
-
async resumeAuthorizedMpp(input) {
|
|
2341
|
-
if (!this.delegateKey) {
|
|
2342
|
-
throw new HavenSigningError(
|
|
2343
|
-
"delegateKey is required for machine payments. Pass it in the HavenClient config."
|
|
2344
|
-
);
|
|
2345
|
-
}
|
|
2346
|
-
const status = await this.getPaymentStatus(input.paymentId);
|
|
2347
|
-
this.assertCanResumeMpp(status, input.challenge);
|
|
2348
|
-
return this.mapMachinePaymentReceiptFromStatus(input.challenge, status);
|
|
2349
|
-
}
|
|
2350
|
-
async resumeMppPayment(input) {
|
|
2351
|
-
const inputInit = "init" in input ? input.init : void 0;
|
|
2352
|
-
const initialInit = inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0);
|
|
2353
|
-
let challenge = input.challenge;
|
|
2354
|
-
const url = input.url ?? input.request?.url;
|
|
2355
|
-
if (!challenge) {
|
|
2356
|
-
if (!url) {
|
|
2357
|
-
throw new HavenApiError("MPP resume requires the original URL or a captured request snapshot.", 400);
|
|
2358
|
-
}
|
|
2359
|
-
const response = await this.merchantFetch(url, initialInit);
|
|
2360
|
-
if (response.status !== 402) {
|
|
2361
|
-
throw new HavenApiError("Expected the original MPP request to return HTTP 402 before resuming.", 400);
|
|
2362
|
-
}
|
|
2363
|
-
challenge = await parseMachinePaymentChallengeResponse(response);
|
|
2364
|
-
}
|
|
2365
|
-
const receipt = await this.resumeAuthorizedMpp({
|
|
2366
|
-
paymentId: input.paymentId,
|
|
2367
|
-
challenge,
|
|
2368
|
-
idempotencyKey: input.idempotencyKey
|
|
2369
|
-
});
|
|
2370
|
-
return this.retryMppRequest(url ?? challenge.resource, initialInit, challenge, receipt);
|
|
2371
|
-
}
|
|
2372
|
-
async fetchWithMachinePayment(url, initialInit, challenge) {
|
|
2373
|
-
const request = this.snapshotX402Request(url, initialInit);
|
|
2374
|
-
const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
|
|
2375
|
-
let receipt;
|
|
2376
|
-
try {
|
|
2377
|
-
receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
|
|
2378
|
-
} catch (err) {
|
|
2379
|
-
this.attachResumeState(err, {
|
|
2380
|
-
rail: "mpp",
|
|
2381
|
-
challenge,
|
|
2382
|
-
idempotencyKey,
|
|
2383
|
-
request
|
|
2384
|
-
});
|
|
2385
|
-
throw err;
|
|
2386
|
-
}
|
|
2387
|
-
return this.retryMppRequest(url, initialInit, challenge, receipt);
|
|
2388
|
-
}
|
|
2389
|
-
async retryMppRequest(url, initialInit, challenge, receipt) {
|
|
2390
|
-
const retryHeaders = new Headers(initialInit?.headers);
|
|
2391
|
-
retryHeaders.set("MACHINE-PAYMENT-PROOF", receipt.proofHeader);
|
|
2392
|
-
const retryResponse = await this.merchantFetch(url, {
|
|
2393
|
-
...initialInit,
|
|
2394
|
-
headers: retryHeaders
|
|
2395
|
-
});
|
|
2396
|
-
if (!retryResponse.ok) {
|
|
2397
|
-
const merchant = await captureMerchantResponse(retryResponse);
|
|
2398
|
-
await this.recordMerchantRetryRejected({
|
|
2399
|
-
rail: receipt.rail,
|
|
2400
|
-
paymentId: receipt.paymentId,
|
|
2401
|
-
txHash: receipt.txHash,
|
|
2402
|
-
resourceUrl: receipt.resourceUrl,
|
|
2403
|
-
merchant,
|
|
2404
|
-
details: {
|
|
2405
|
-
challenge_id: receipt.challengeId
|
|
2406
|
-
}
|
|
2407
|
-
});
|
|
2408
|
-
throw new HavenApiError(
|
|
2409
|
-
"Machine payment retry failed after Haven sent the payment.",
|
|
2410
|
-
merchant.merchant_status,
|
|
2411
|
-
{
|
|
2412
|
-
marker: "machine_payment_retry_rejected_after_payment",
|
|
2413
|
-
payment_id: receipt.paymentId,
|
|
2414
|
-
tx_hash: receipt.txHash,
|
|
2415
|
-
resource_url: receipt.resourceUrl,
|
|
2416
|
-
rail: receipt.rail,
|
|
2417
|
-
...merchant
|
|
2418
|
-
}
|
|
2419
|
-
);
|
|
2420
|
-
}
|
|
2421
|
-
await this.reportMachinePaymentEvidence({
|
|
2422
|
-
paymentId: receipt.paymentId,
|
|
2423
|
-
rail: receipt.rail,
|
|
2424
|
-
txHash: receipt.txHash,
|
|
2425
|
-
resourceUrl: receipt.resourceUrl,
|
|
2426
|
-
merchantStatus: retryResponse.status,
|
|
2427
|
-
challengePayload: challenge,
|
|
2428
|
-
paymentProofHeaderName: "MACHINE-PAYMENT-PROOF",
|
|
2429
|
-
paymentProofHeader: receipt.proofHeader,
|
|
2430
|
-
protocolReceiptHeaderName: retryResponse.headers.has("Payment-Receipt") ? "Payment-Receipt" : retryResponse.headers.has("MACHINE-PAYMENT-RESPONSE") ? "MACHINE-PAYMENT-RESPONSE" : void 0,
|
|
2431
|
-
protocolReceiptHeader: retryResponse.headers.get("Payment-Receipt") ?? retryResponse.headers.get("MACHINE-PAYMENT-RESPONSE") ?? void 0
|
|
2432
|
-
});
|
|
2433
|
-
await this.reportMerchantReceipt(receipt.paymentId, retryResponse);
|
|
2434
|
-
return retryResponse;
|
|
2435
|
-
}
|
|
2224
|
+
// #1328: authorizeMachinePayment / authorizeMppDemoPayment / resumeAuthorizedMpp
|
|
2225
|
+
// / resumeMppPayment / fetchWithMachinePayment / retryMppRequest (the
|
|
2226
|
+
// MACHINE-PAYMENT-CHALLENGE / mpp_demo client surface) are retired — the
|
|
2227
|
+
// backend's POST /machine-payments/authorize refuses unconditionally now,
|
|
2228
|
+
// and MACHINE-PAYMENT-CHALLENGE was never produced by any other Haven
|
|
2229
|
+
// surface. Use the x402 flow (authorizeX402 / fetch / quoteX402 / payX402Quote)
|
|
2230
|
+
// for agent-to-merchant payments.
|
|
2436
2231
|
assertCanResumeX402(status, paymentRequired, option) {
|
|
2437
2232
|
if (status.rail !== "x402") {
|
|
2438
2233
|
throw new HavenPaymentStateError(
|
|
@@ -2496,68 +2291,6 @@ var HavenClient = class {
|
|
|
2496
2291
|
);
|
|
2497
2292
|
}
|
|
2498
2293
|
}
|
|
2499
|
-
assertCanResumeMpp(status, challenge) {
|
|
2500
|
-
if (!isMppRail(status.rail)) {
|
|
2501
|
-
throw new HavenPaymentStateError(
|
|
2502
|
-
`Payment ${status.paymentId} is ${status.rail}, not MPP.`,
|
|
2503
|
-
409,
|
|
2504
|
-
status
|
|
2505
|
-
);
|
|
2506
|
-
}
|
|
2507
|
-
if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
|
|
2508
|
-
throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
|
|
2509
|
-
}
|
|
2510
|
-
if (!status.txHash) {
|
|
2511
|
-
throw new HavenApiError(
|
|
2512
|
-
`MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
|
|
2513
|
-
502,
|
|
2514
|
-
status,
|
|
2515
|
-
status.paymentId
|
|
2516
|
-
);
|
|
2517
|
-
}
|
|
2518
|
-
if (status.resourceUrl && status.resourceUrl !== challenge.resource) {
|
|
2519
|
-
throw new HavenApiError(
|
|
2520
|
-
"MPP resume request does not match the approved resource URL.",
|
|
2521
|
-
409,
|
|
2522
|
-
{ status, challenge },
|
|
2523
|
-
status.paymentId
|
|
2524
|
-
);
|
|
2525
|
-
}
|
|
2526
|
-
if (status.merchantAddress && !sameAddress(status.merchantAddress, challenge.recipient)) {
|
|
2527
|
-
throw new HavenApiError(
|
|
2528
|
-
"MPP resume request does not match the approved merchant.",
|
|
2529
|
-
409,
|
|
2530
|
-
{ status, challenge },
|
|
2531
|
-
status.paymentId
|
|
2532
|
-
);
|
|
2533
|
-
}
|
|
2534
|
-
if (status.chainId && status.chainId !== challenge.network.chainId) {
|
|
2535
|
-
throw new HavenApiError(
|
|
2536
|
-
"MPP resume request does not match the approved network.",
|
|
2537
|
-
409,
|
|
2538
|
-
{ status, challenge },
|
|
2539
|
-
status.paymentId
|
|
2540
|
-
);
|
|
2541
|
-
}
|
|
2542
|
-
if (status.token && status.token !== challenge.asset.symbol) {
|
|
2543
|
-
throw new HavenApiError(
|
|
2544
|
-
"MPP resume request does not match the approved token.",
|
|
2545
|
-
409,
|
|
2546
|
-
{ status, challenge },
|
|
2547
|
-
status.paymentId
|
|
2548
|
-
);
|
|
2549
|
-
}
|
|
2550
|
-
const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
|
|
2551
|
-
const requestedAmount = normalizeDecimal(challenge.amount.display);
|
|
2552
|
-
if (approvedAmount && approvedAmount !== requestedAmount) {
|
|
2553
|
-
throw new HavenApiError(
|
|
2554
|
-
"MPP resume request does not match the approved amount.",
|
|
2555
|
-
409,
|
|
2556
|
-
{ status, challenge },
|
|
2557
|
-
status.paymentId
|
|
2558
|
-
);
|
|
2559
|
-
}
|
|
2560
|
-
}
|
|
2561
2294
|
mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
|
|
2562
2295
|
const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
|
|
2563
2296
|
const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
|
|
@@ -2664,53 +2397,6 @@ var HavenClient = class {
|
|
|
2664
2397
|
this.x402ReceiptCache.set(idempotencyKey, { expiresAt, receipt });
|
|
2665
2398
|
}
|
|
2666
2399
|
}
|
|
2667
|
-
mapMachinePaymentReceipt(challenge, raw, txHash, execResult) {
|
|
2668
|
-
const receiptWithoutHeader = {
|
|
2669
|
-
success: true,
|
|
2670
|
-
rail: challenge.rail,
|
|
2671
|
-
paymentId: raw.payment_id,
|
|
2672
|
-
challengeId: challenge.challengeId,
|
|
2673
|
-
txHash,
|
|
2674
|
-
token: execResult?.token ?? raw.token ?? challenge.asset.symbol,
|
|
2675
|
-
amount: execResult?.amount ?? raw.amount ?? challenge.amount.display,
|
|
2676
|
-
to: execResult?.to ?? raw.to ?? challenge.recipient,
|
|
2677
|
-
resourceUrl: raw.resource_url ?? challenge.resource,
|
|
2678
|
-
explorerUrl: execResult?.explorer_url ?? raw.explorer_url ?? buildExplorerUrl(execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId, txHash),
|
|
2679
|
-
payer: raw.payer ?? raw.safe_address,
|
|
2680
|
-
chainId: execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId
|
|
2681
|
-
};
|
|
2682
|
-
return {
|
|
2683
|
-
...receiptWithoutHeader,
|
|
2684
|
-
proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
|
|
2685
|
-
};
|
|
2686
|
-
}
|
|
2687
|
-
mapMachinePaymentReceiptFromStatus(challenge, status) {
|
|
2688
|
-
if (!status.txHash) {
|
|
2689
|
-
throw new HavenApiError(
|
|
2690
|
-
`MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
|
|
2691
|
-
502,
|
|
2692
|
-
status,
|
|
2693
|
-
status.paymentId
|
|
2694
|
-
);
|
|
2695
|
-
}
|
|
2696
|
-
const receiptWithoutHeader = {
|
|
2697
|
-
success: true,
|
|
2698
|
-
rail: challenge.rail,
|
|
2699
|
-
paymentId: status.paymentId,
|
|
2700
|
-
challengeId: challenge.challengeId,
|
|
2701
|
-
txHash: status.txHash,
|
|
2702
|
-
token: status.token || challenge.asset.symbol,
|
|
2703
|
-
amount: status.amount || challenge.amount.display,
|
|
2704
|
-
to: status.merchantAddress ?? challenge.recipient,
|
|
2705
|
-
resourceUrl: status.resourceUrl ?? challenge.resource,
|
|
2706
|
-
explorerUrl: explorerUrlOrEmpty(status.chainId || challenge.network.chainId, status.txHash),
|
|
2707
|
-
chainId: status.chainId || challenge.network.chainId
|
|
2708
|
-
};
|
|
2709
|
-
return {
|
|
2710
|
-
...receiptWithoutHeader,
|
|
2711
|
-
proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
|
|
2712
|
-
};
|
|
2713
|
-
}
|
|
2714
2400
|
async recordMerchantRetryRejected(input) {
|
|
2715
2401
|
try {
|
|
2716
2402
|
await this.post("/machine-payments/reconciliation-events", {
|
|
@@ -2908,6 +2594,11 @@ var HavenClient = class {
|
|
|
2908
2594
|
amountAtomic: x402AuthorizationAmount(option),
|
|
2909
2595
|
amount: decimalFromUsdcAtomic(x402AuthorizationAmount(option)),
|
|
2910
2596
|
token: token?.symbol ?? "USDC",
|
|
2597
|
+
// #1351: null when the asset is unrecognised on this network — the
|
|
2598
|
+
// `token` fallback above is a LABEL, not evidence of 6 decimals, and a
|
|
2599
|
+
// human-denominated cap must fail closed rather than convert against a
|
|
2600
|
+
// guess. Same resolution as `token`, so the two never disagree.
|
|
2601
|
+
decimals: token?.decimals ?? null,
|
|
2911
2602
|
asset: option.asset,
|
|
2912
2603
|
network: option.network,
|
|
2913
2604
|
chainId: chainIdOrNull(option.network),
|
|
@@ -2948,63 +2639,18 @@ var HavenClient = class {
|
|
|
2948
2639
|
merchantAddress: input.accepted.payTo
|
|
2949
2640
|
};
|
|
2950
2641
|
}
|
|
2951
|
-
buildMppQuote
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
idempotencyKey: idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge),
|
|
2956
|
-
challenge,
|
|
2957
|
-
request,
|
|
2958
|
-
resourceUrl: challenge.resource,
|
|
2959
|
-
description: challenge.description ?? null,
|
|
2960
|
-
amountAtomic: challenge.amount.atomic,
|
|
2961
|
-
amount: challenge.amount.display,
|
|
2962
|
-
token: challenge.asset.symbol,
|
|
2963
|
-
asset: challenge.asset.address,
|
|
2964
|
-
network: challenge.network.name,
|
|
2965
|
-
chainId: challenge.network.chainId,
|
|
2966
|
-
merchantAddress: challenge.recipient,
|
|
2967
|
-
expiresAt: challenge.expiresAt
|
|
2968
|
-
};
|
|
2969
|
-
}
|
|
2970
|
-
buildMppResumeState(input) {
|
|
2971
|
-
const quote = this.buildMppQuote(
|
|
2972
|
-
input.challenge,
|
|
2973
|
-
input.request ?? this.snapshotX402Request(input.challenge.resource),
|
|
2974
|
-
input.idempotencyKey
|
|
2975
|
-
);
|
|
2976
|
-
return {
|
|
2977
|
-
rail: "mpp",
|
|
2978
|
-
paymentRail: quote.paymentRail,
|
|
2979
|
-
paymentId: input.paymentId,
|
|
2980
|
-
idempotencyKey: quote.idempotencyKey,
|
|
2981
|
-
challenge: input.challenge,
|
|
2982
|
-
url: input.request?.url ?? input.challenge.resource,
|
|
2983
|
-
request: input.request,
|
|
2984
|
-
resourceUrl: quote.resourceUrl,
|
|
2985
|
-
description: quote.description,
|
|
2986
|
-
amountAtomic: quote.amountAtomic,
|
|
2987
|
-
amount: quote.amount,
|
|
2988
|
-
token: quote.token,
|
|
2989
|
-
asset: quote.asset,
|
|
2990
|
-
network: quote.network,
|
|
2991
|
-
chainId: quote.chainId,
|
|
2992
|
-
merchantAddress: quote.merchantAddress,
|
|
2993
|
-
expiresAt: quote.expiresAt
|
|
2994
|
-
};
|
|
2995
|
-
}
|
|
2642
|
+
// #1328: attachResumeState's 'mpp' branch (buildMppQuote / buildMppResumeState
|
|
2643
|
+
// / attachMppResumeState) is retired along with the rest of the MPP-demo
|
|
2644
|
+
// client surface — every remaining caller passes rail: 'x402' only, so this
|
|
2645
|
+
// is now a direct alias for attachX402ResumeState rather than a dispatcher.
|
|
2996
2646
|
attachResumeState(err, input) {
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
);
|
|
3005
|
-
return;
|
|
3006
|
-
}
|
|
3007
|
-
this.attachMppResumeState(err, input.challenge, input.idempotencyKey, input.request);
|
|
2647
|
+
this.attachX402ResumeState(
|
|
2648
|
+
err,
|
|
2649
|
+
input.paymentRequired,
|
|
2650
|
+
input.accepted,
|
|
2651
|
+
input.idempotencyKey,
|
|
2652
|
+
input.request
|
|
2653
|
+
);
|
|
3008
2654
|
}
|
|
3009
2655
|
attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
|
|
3010
2656
|
if (!(err instanceof HavenPaymentStateError)) return;
|
|
@@ -3017,16 +2663,6 @@ var HavenClient = class {
|
|
|
3017
2663
|
request
|
|
3018
2664
|
});
|
|
3019
2665
|
}
|
|
3020
|
-
attachMppResumeState(err, challenge, idempotencyKey, request) {
|
|
3021
|
-
if (!(err instanceof HavenPaymentStateError)) return;
|
|
3022
|
-
if (!isMppRail(err.state.rail)) return;
|
|
3023
|
-
err.resumeState = this.buildMppResumeState({
|
|
3024
|
-
paymentId: err.state.paymentId,
|
|
3025
|
-
challenge,
|
|
3026
|
-
idempotencyKey,
|
|
3027
|
-
request
|
|
3028
|
-
});
|
|
3029
|
-
}
|
|
3030
2666
|
// ── Tool Execution (for agent frameworks) ────────────────────────
|
|
3031
2667
|
/**
|
|
3032
2668
|
* Execute a tool call by name and input.
|
|
@@ -3085,29 +2721,6 @@ var HavenClient = class {
|
|
|
3085
2721
|
return this.toolError(err);
|
|
3086
2722
|
}
|
|
3087
2723
|
}
|
|
3088
|
-
if (toolName === "authorize_machine_payment") {
|
|
3089
|
-
const { challenge, idempotencyKey } = input;
|
|
3090
|
-
try {
|
|
3091
|
-
const receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
|
|
3092
|
-
return {
|
|
3093
|
-
success: true,
|
|
3094
|
-
payment_id: receipt.paymentId,
|
|
3095
|
-
tx_hash: receipt.txHash,
|
|
3096
|
-
token: receipt.token,
|
|
3097
|
-
amount: receipt.amount,
|
|
3098
|
-
to: receipt.to,
|
|
3099
|
-
resource_url: receipt.resourceUrl,
|
|
3100
|
-
explorer_url: receipt.explorerUrl,
|
|
3101
|
-
proof_header: receipt.proofHeader,
|
|
3102
|
-
rail: receipt.rail,
|
|
3103
|
-
challenge_id: receipt.challengeId,
|
|
3104
|
-
payer: receipt.payer,
|
|
3105
|
-
chain_id: receipt.chainId
|
|
3106
|
-
};
|
|
3107
|
-
} catch (err) {
|
|
3108
|
-
return this.toolError(err);
|
|
3109
|
-
}
|
|
3110
|
-
}
|
|
3111
2724
|
if (toolName === "get_payment_status") {
|
|
3112
2725
|
const { payment_id } = input;
|
|
3113
2726
|
const result = await this.getPaymentStatus(payment_id);
|
|
@@ -3455,7 +3068,7 @@ var toolDescriptions = {
|
|
|
3455
3068
|
payX402OneShot: {
|
|
3456
3069
|
summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.",
|
|
3457
3070
|
selectionGuidance: "Prefer this over the quote+pay split when the agent just wants the paid resource and does not need to inspect the price first. If you already have a quote from haven_quote_x402, use haven_pay_x402_quote instead. Do not use for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.",
|
|
3458
|
-
behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the EIP-3009 payment from the delegate wallet, asks Haven for a Safe AllowanceModule top-up if needed, then retries the original request with the X-PAYMENT header and returns the merchant response. If the resource returns
|
|
3071
|
+
behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the EIP-3009 payment from the delegate wallet, asks Haven for a Safe AllowanceModule top-up if needed, then retries the original request with the X-PAYMENT header and returns the merchant response. If the resource returns a non-402 status, returns it unchanged without contacting Haven.",
|
|
3459
3072
|
nextActionGuidance: "If approval is needed, preserve the returned resume_state or paymentId and call the resume tool once nextAction=retry_original_x402_request. If the response carries phase=insufficient_funds and nextAction=fund_safe_or_raise_allowance, the payment cannot be retried until the originating Safe is funded or the agent allowance raised \u2014 stop and tell the user the shortfall reported on the response."
|
|
3460
3073
|
},
|
|
3461
3074
|
resumeX402: {
|
|
@@ -3463,29 +3076,17 @@ var toolDescriptions = {
|
|
|
3463
3076
|
behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the approved Haven funding, and retries the merchant request with the X-PAYMENT header. No new Haven approval is created.",
|
|
3464
3077
|
nextActionGuidance: "Only use when get_payment_status returns nextAction=retry_original_x402_request; do not start a new merchant session."
|
|
3465
3078
|
},
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
},
|
|
3471
|
-
payMpp: {
|
|
3472
|
-
summary: "Pay an inspected MPP challenge. The delegate key signs locally; Haven only validates and relays signed, on-chain-constrained payment transactions.",
|
|
3473
|
-
selectionGuidance: "Do not use this for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.",
|
|
3474
|
-
behavior: "Authorizes the payment through Haven within the on-chain allowance, signs the challenge proof, and returns the proof header for retrying the original paid resource.",
|
|
3475
|
-
nextActionGuidance: "If approval is needed, preserve resume_state or payment_id and wait for nextAction=retry_original_x402_request before resuming."
|
|
3476
|
-
},
|
|
3477
|
-
resumeMpp: {
|
|
3478
|
-
summary: "Resume an MPP payment after the Haven wallet owner approved the funding step.",
|
|
3479
|
-
behavior: "Accepts either resume_state or payment_id and retries the original paid resource with the MPP proof header. No new Haven approval is created.",
|
|
3480
|
-
nextActionGuidance: ""
|
|
3481
|
-
},
|
|
3079
|
+
// #1328: quoteMpp / payMpp / resumeMpp (the mpp_demo challenge/quote/resume
|
|
3080
|
+
// fragments) are retired along with the client surface they described —
|
|
3081
|
+
// MACHINE-PAYMENT-CHALLENGE was never produced by anything besides the now
|
|
3082
|
+
// deleted `/demo/mpp/*` route. Use the x402 fragments above instead.
|
|
3482
3083
|
getPaymentStatus: {
|
|
3483
3084
|
summary: "Fetch structured Haven payment status, including phase and nextAction taxonomy for agent recovery.",
|
|
3484
3085
|
behavior: "Accepts a payment intent or approval request id and returns the full state taxonomy (phase, nextAction, rail, amount, merchant, resource url, idempotency key, message).",
|
|
3485
3086
|
nextActionGuidance: ""
|
|
3486
3087
|
},
|
|
3487
3088
|
getResumeState: {
|
|
3488
|
-
summary: "Rehydrate stored x402
|
|
3089
|
+
summary: "Rehydrate stored x402 resume_state by payment_id.",
|
|
3489
3090
|
behavior: "Returns the context that the agent originally received in a pending-approval response, reconstructed from Haven's database. This is context only; signing still happens locally when a resume tool is called.",
|
|
3490
3091
|
nextActionGuidance: ""
|
|
3491
3092
|
},
|
|
@@ -3522,18 +3123,18 @@ var toolDescriptions = {
|
|
|
3522
3123
|
discoverTools: {
|
|
3523
3124
|
summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices, and which pay tool to use next.",
|
|
3524
3125
|
selectionGuidance: "Use this when the user asks what the agent can buy, pay for, or which paid services exist \u2014 or when you need a resource URL for a service the user described. Do NOT use for balance, budget, or spend-limit questions \u2014 use haven_get_allowances. Do NOT use to pay \u2014 each returned entry names the pay tool to use next.",
|
|
3525
|
-
behavior: "Use each entry's suggested_tool field first \u2014 it names the exact next call. Read-only lookup against Haven's curated catalog; entries are periodically re-verified against the live merchant and degraded entries are flagged. Returns name, description, price, rail, resource URL, tool_name, tool_arguments, and suggested_tool. The catalog price (price_display/price_atomic, marked price_is_indicative) is a last-verified hint, NOT authoritative \u2014 the real price comes from the merchant's live 402 at pay time. Never creates a payment, signature, or approval.",
|
|
3526
|
-
nextActionGuidance:
|
|
3126
|
+
behavior: "Use each entry's suggested_tool field first \u2014 it names the exact next call. Read-only lookup against Haven's curated catalog; entries are periodically re-verified against the live merchant and degraded entries are flagged. Use category for a case-insensitive category filter (for example, VPN or vpn), or search for a product name, category, or description term. Returns name, description, price, rail, resource URL, tool_name, tool_arguments, and suggested_tool. The catalog price (price_display/price_atomic, marked price_is_indicative) is a last-verified hint, NOT authoritative \u2014 the real price comes from the merchant's live 402 at pay time. Never creates a payment, signature, or approval.",
|
|
3127
|
+
nextActionGuidance: `Pick an entry and pay it with the tool named in suggested_tool, passing the entry's resource_url, tool_name, and tool_arguments for MCP merchants. Confirm the price from the live pay-tool result (not the catalog), and pass the user's cap as max_amount_human in whole tokens ("no more than 1 USDC" \u2192 max_amount_human: "1") \u2014 never convert it to atomic units by hand (#1351).`
|
|
3527
3128
|
},
|
|
3528
3129
|
sweep_delegate: {
|
|
3529
3130
|
summary: "Sweep stranded USDC and/or ETH from the delegate wallet back to the originating Safe.",
|
|
3530
|
-
selectionGuidance: "Use this when the user instructs you to recover stranded funds on the delegate wallet, or when a payment status returns nextAction=sweep_stranded_funds. Do NOT use for normal payments \u2014 use haven_pay_x402
|
|
3131
|
+
selectionGuidance: "Use this when the user instructs you to recover stranded funds on the delegate wallet, or when a payment status returns nextAction=sweep_stranded_funds. Do NOT use for normal payments \u2014 use haven_pay_x402. Do NOT use to read balances only \u2014 use haven_get_allowances.",
|
|
3531
3132
|
behavior: "Reads the delegate EOA's on-chain USDC and ETH balances. For each non-zero balance, signs and submits a transfer from the delegate EOA to the originating Safe (hardcoded destination). The delegate key signs locally \u2014 Haven never sees it and the backend never constructs signed transactions (CASP/MiCA Red Line #2). Returns tx hashes and recovered amounts. Returns an empty transfers list when nothing is stranded.",
|
|
3532
3133
|
nextActionGuidance: "If transfers is non-empty, confirm the amounts with the user. No further action required \u2014 funds are on their way back to the Safe."
|
|
3533
3134
|
},
|
|
3534
3135
|
send: {
|
|
3535
3136
|
summary: "Send ETH or USDC directly from the agent's Haven wallet to a recipient address.",
|
|
3536
|
-
selectionGuidance: "Use this for plain transfers \u2014 refunding a user, paying a freelancer, topping up a co-agent's wallet, or moving funds between addresses. Do NOT use for x402 paid endpoints
|
|
3137
|
+
selectionGuidance: "Use this for plain transfers \u2014 refunding a user, paying a freelancer, topping up a co-agent's wallet, or moving funds between addresses. Do NOT use for x402 paid endpoints \u2014 use haven_pay_x402 instead. Do NOT use for read-only allowance, budget, or what-can-I-spend questions \u2014 use haven_get_allowances.",
|
|
3537
3138
|
behavior: "Sends the requested amount through the Safe AllowanceModule. Amounts within the remaining on-chain allowance for the asset execute automatically; amounts that exceed the allowance are queued as pending_approval for the wallet owner to approve in Haven. The agent's signing key signs the AllowanceModule transfer hash; Haven never receives the key.",
|
|
3538
3139
|
nextActionGuidance: "If pending_approval is returned, preserve the payment_id and wait for the wallet owner to approve in Haven. Poll haven_get_payment_status until nextAction=none."
|
|
3539
3140
|
}
|
|
@@ -3649,22 +3250,11 @@ var resumeX402Schema = {
|
|
|
3649
3250
|
},
|
|
3650
3251
|
required: ["payment_id", "url", "payTo", "amount", "asset", "network"]
|
|
3651
3252
|
};
|
|
3652
|
-
var authorizeMachinePaymentSchema = {
|
|
3653
|
-
type: "object",
|
|
3654
|
-
properties: {
|
|
3655
|
-
challenge: {
|
|
3656
|
-
type: "object",
|
|
3657
|
-
description: "Machine payment challenge returned by a Haven demo endpoint"
|
|
3658
|
-
}
|
|
3659
|
-
},
|
|
3660
|
-
required: ["challenge"]
|
|
3661
|
-
};
|
|
3662
3253
|
var MAKE_PAYMENT_DESCRIPTION = "Request and sign a payment from the user-controlled Safe within approved on-chain limits. For read-only allowance, budget, spend-limit, remaining-amount, or reset-period questions, use get_allowances instead of making a payment. Haven authenticates the agent, validates the signed intent, and relays the Safe AllowanceModule transaction; it does not hold keys or control funds. Gnosis Chain tokens: EURe, USDC.e, xDAI. Base tokens: USDC, ETH.";
|
|
3663
3254
|
var GET_STATUS_DESCRIPTION = toolDescriptions.getPaymentStatus.summary + " Accepts payment intent IDs and approval request IDs. Returns the current status, phase, next_action, transaction hash if available, and payment details.";
|
|
3664
3255
|
var GET_ALLOWANCES_DESCRIPTION = composeDescription(toolDescriptions.getAllowances);
|
|
3665
3256
|
var AUTHORIZE_X402_DESCRIPTION = composeDescription(toolDescriptions.payX402) + " In this SDK tool set, the allowance lookup tool is get_allowances. When a paid API returns x402 payment requirements, use this tool to sign with the agent-owned delegate key and request a policy-limited Safe AllowanceModule top-up when needed. Haven relays signed transactions only; the agent key authorizes payment and on-chain limits enforce spend. If this returns pending_approval, tell the user it is waiting in Haven, preserve the original merchant/MCP session and x402 details, call get_payment_status later, and use resume_x402_payment only when next_action is retry_original_x402_request. Do not start a new merchant session or loop retries while approval is pending. Use the returned payment_header as the X-PAYMENT header on the retry request when doing a manual HTTP retry.";
|
|
3666
3257
|
var RESUME_X402_DESCRIPTION = toolDescriptions.resumeX402.summary + " Use this only after get_payment_status returns next_action=retry_original_x402_request. It checks the approved payment, validates the original x402 details, and returns a merchant X-PAYMENT header without creating a new approval request or merchant session.";
|
|
3667
|
-
var AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION = composeDescription(toolDescriptions.payMpp) + " In this SDK tool set, the allowance lookup tool is get_allowances. Currently scoped to the internal MPP demo rail. The agent signs the payment, Haven relays it within the on-chain allowance, and the tool returns a proof header for the retry request.";
|
|
3668
3258
|
var SWEEP_DELEGATE_DESCRIPTION = composeDescription(toolDescriptions.sweep_delegate);
|
|
3669
3259
|
var sweepDelegateSchema = {
|
|
3670
3260
|
type: "object",
|
|
@@ -3698,11 +3288,6 @@ function claudeTools() {
|
|
|
3698
3288
|
description: RESUME_X402_DESCRIPTION,
|
|
3699
3289
|
input_schema: resumeX402Schema
|
|
3700
3290
|
},
|
|
3701
|
-
{
|
|
3702
|
-
name: "authorize_machine_payment",
|
|
3703
|
-
description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
|
|
3704
|
-
input_schema: authorizeMachinePaymentSchema
|
|
3705
|
-
},
|
|
3706
3291
|
{
|
|
3707
3292
|
name: "haven_sweep_delegate",
|
|
3708
3293
|
description: SWEEP_DELEGATE_DESCRIPTION,
|
|
@@ -3752,14 +3337,6 @@ function openaiTools() {
|
|
|
3752
3337
|
parameters: resumeX402Schema
|
|
3753
3338
|
}
|
|
3754
3339
|
},
|
|
3755
|
-
{
|
|
3756
|
-
type: "function",
|
|
3757
|
-
function: {
|
|
3758
|
-
name: "authorize_machine_payment",
|
|
3759
|
-
description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
|
|
3760
|
-
parameters: authorizeMachinePaymentSchema
|
|
3761
|
-
}
|
|
3762
|
-
},
|
|
3763
3340
|
{
|
|
3764
3341
|
type: "function",
|
|
3765
3342
|
function: {
|
|
@@ -3835,10 +3412,13 @@ normal, not an error.
|
|
|
3835
3412
|
|
|
3836
3413
|
1. \`mcp__haven__haven_discover_tools\` to find a payable service and its
|
|
3837
3414
|
\`catalog_id\`.
|
|
3838
|
-
2. \`mcp__haven__haven_prepare_catalog_purchase\` with \`catalog_id\` and
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3415
|
+
2. \`mcp__haven__haven_prepare_catalog_purchase\` with \`catalog_id\` and a
|
|
3416
|
+
spending cap. A cap is REQUIRED on this tool and is best practice on every
|
|
3417
|
+
paid call below too \u2014 it caps what the LIVE merchant quote may charge,
|
|
3418
|
+
checked before any funding intent is created. Write it the way the user
|
|
3419
|
+
said it: \`max_amount_human\` is whole tokens, so "no more than 1 USDC" is
|
|
3420
|
+
\`max_amount_human: "1"\`. (\`max_amount\` is the atomic-unit form, where
|
|
3421
|
+
"1" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)
|
|
3842
3422
|
3. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: \`next_action\`, \`next_tool\`,
|
|
3843
3423
|
and \`next_arguments\` name the exact next call \u2014 act on those first; the
|
|
3844
3424
|
prose in this section is fallback and debugging detail. If the catalog
|
|
@@ -3846,9 +3426,11 @@ normal, not an error.
|
|
|
3846
3426
|
\`mcp__haven__haven_pay_mcp_tool\` (merchant URL, tool name, arguments) as
|
|
3847
3427
|
the manual fallback.
|
|
3848
3428
|
|
|
3849
|
-
**Signing:** \`mcp__haven-signer__haven_sign_x402\` with \`payment_id\`
|
|
3850
|
-
|
|
3851
|
-
itself, so never relay \`typed_data\` yourself.
|
|
3429
|
+
**Signing:** \`mcp__haven-signer__haven_sign_x402\` with \`payment_id\` ONLY \u2014
|
|
3430
|
+
the local signer fetches the exact signing bytes AND \`payment_required\`
|
|
3431
|
+
itself, so never relay \`typed_data\` or the 402 blob yourself. If the signer
|
|
3432
|
+
reports its fetched context carried no \`payment_required\` (older backend),
|
|
3433
|
+
re-call with \`payment_required\` added verbatim. Fallback for an older signer
|
|
3852
3434
|
or backend: re-run the quote/prepare tool with the SAME \`idempotency_key\`
|
|
3853
3435
|
plus \`include_signing_payload=true\`, then pass \`payload_hash\`,
|
|
3854
3436
|
\`x402_expected\` (the nested \`x402.expected\` object), and
|
|
@@ -3918,8 +3500,14 @@ present and surface \`message\` or \`error\` verbatim. Common cases:
|
|
|
3918
3500
|
- \`pending_approval\`: queued for the user's approval (see above).
|
|
3919
3501
|
- \`insufficient_funds\`: the Haven wallet doesn't hold enough of that token.
|
|
3920
3502
|
Suggest the user add funds in the Haven dashboard.
|
|
3921
|
-
- \`PRICE_EXCEEDS_MAX\`: the live merchant price exceeded your
|
|
3922
|
-
|
|
3503
|
+
- \`PRICE_EXCEEDS_MAX\`: the live merchant price exceeded your cap. No funds
|
|
3504
|
+
moved; ask the user before retrying with a higher one.
|
|
3505
|
+
- \`AMBIGUOUS_MAX_AMOUNT\`: you sent both \`max_amount\` and
|
|
3506
|
+
\`max_amount_human\`. Nothing was contacted or spent \u2014 re-send with exactly
|
|
3507
|
+
one (\`max_amount_human\` for a cap the user stated in tokens).
|
|
3508
|
+
- \`MAX_AMOUNT_UNCONVERTIBLE\`: \`max_amount_human\` does not fit this quote's
|
|
3509
|
+
asset \u2014 unknown decimals, or more decimal places than the asset supports.
|
|
3510
|
+
Round the cap, or send an exact atomic \`max_amount\`.
|
|
3923
3511
|
- \`PAYMENT_WINDOW_EXPIRED\`: re-run the quote/prepare tool with the same
|
|
3924
3512
|
\`idempotency_key\`, then sign the fresh payload.
|
|
3925
3513
|
- \`MERCHANT_REJECTED_AFTER_FUNDING\`: the merchant refused the paid retry.
|
|
@@ -3938,10 +3526,12 @@ present and surface \`message\` or \`error\` verbatim. Common cases:
|
|
|
3938
3526
|
## Reporting after a purchase
|
|
3939
3527
|
|
|
3940
3528
|
A settled \`mcp__haven__haven_settle_mcp_tool\` response carries
|
|
3941
|
-
\`agent_summary\` and the remaining post-purchase allowance
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
purchase
|
|
3529
|
+
\`agent_summary.purchase_summary\` and the remaining post-purchase allowance
|
|
3530
|
+
in \`allowance\` \u2014 report the product, Haven-derived payment/transaction
|
|
3531
|
+
fields, and what is left from those fields directly. \`result\` is optional
|
|
3532
|
+
raw merchant evidence; never use it to decide whether the purchase was paid.
|
|
3533
|
+
Do not call \`haven_get_agent\` or \`haven_get_allowances\` again just to
|
|
3534
|
+
report a purchase you already made.
|
|
3945
3535
|
|
|
3946
3536
|
## Revoke
|
|
3947
3537
|
|
|
@@ -3952,7 +3542,7 @@ for that credential.
|
|
|
3952
3542
|
var SKILL_FOLDER_NAME = "haven-pay";
|
|
3953
3543
|
|
|
3954
3544
|
// src/node-version.ts
|
|
3955
|
-
var HAVEN_MINIMUM_NODE_VERSION = "
|
|
3545
|
+
var HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
|
|
3956
3546
|
function parseNodeVersion(value) {
|
|
3957
3547
|
const match = value.trim().match(/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
3958
3548
|
if (!match) return [0, 0, 0];
|
|
@@ -4139,6 +3729,6 @@ function sameUrl(a, b) {
|
|
|
4139
3729
|
}
|
|
4140
3730
|
}
|
|
4141
3731
|
|
|
4142
|
-
export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, AgentPaymentWarningCode, DISCOVERY_MAX_BYTES, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_MD, HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, MerchantTimeoutError, RECEIPT_VERSION, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, SignerRefusalCode, TRANSFER_WITH_AUTHORIZATION_TYPES, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey,
|
|
3732
|
+
export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, AgentPaymentWarningCode, DISCOVERY_MAX_BYTES, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_MD, HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, MerchantTimeoutError, RECEIPT_VERSION, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, SignerRefusalCode, TRANSFER_WITH_AUTHORIZATION_TYPES, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isSupportedNodeVersion, isSweepableChain, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectPaymentOption, selectStandardPaymentOption, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, verifyPaymentReceipt, verifySignature, x402AuthorizationAmount };
|
|
4143
3733
|
//# sourceMappingURL=index.js.map
|
|
4144
3734
|
//# sourceMappingURL=index.js.map
|