@haven_ai/sdk 0.3.0-alpha.0 → 0.5.0-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 +54 -3
- package/dist/base64-BUMXmruY.d.cts +2731 -0
- package/dist/base64-BUMXmruY.d.ts +2731 -0
- package/dist/chunk-GLNG2GF7.js +903 -0
- package/dist/chunk-GLNG2GF7.js.map +1 -0
- package/dist/chunk-JKUIE45B.cjs +964 -0
- package/dist/chunk-JKUIE45B.cjs.map +1 -0
- package/dist/chunk-KQ7JXKTV.js +902 -0
- package/dist/chunk-KQ7JXKTV.js.map +1 -0
- package/dist/chunk-QSSVOPWA.cjs +970 -0
- package/dist/chunk-QSSVOPWA.cjs.map +1 -0
- package/dist/edge.cjs +271 -0
- package/dist/edge.cjs.map +1 -0
- package/dist/edge.d.cts +105 -0
- package/dist/edge.d.ts +105 -0
- package/dist/edge.js +56 -0
- package/dist/edge.js.map +1 -0
- package/dist/index.cjs +1100 -1391
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -2091
- package/dist/index.d.ts +145 -2091
- package/dist/index.js +518 -1163
- package/dist/index.js.map +1 -1
- package/dist/test-support.cjs +215 -0
- package/dist/test-support.cjs.map +1 -0
- package/dist/test-support.d.cts +204 -0
- package/dist/test-support.d.ts +204 -0
- package/dist/test-support.js +200 -0
- package/dist/test-support.js.map +1 -0
- package/package.json +24 -1
package/dist/index.cjs
CHANGED
|
@@ -1,473 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunkQSSVOPWA_cjs = require('./chunk-QSSVOPWA.cjs');
|
|
4
|
+
var chunkJKUIE45B_cjs = require('./chunk-JKUIE45B.cjs');
|
|
3
5
|
var viem = require('viem');
|
|
4
6
|
var ethers = require('ethers');
|
|
5
|
-
var crypto = require('crypto');
|
|
6
7
|
var async_hooks = require('async_hooks');
|
|
7
8
|
var schemes = require('x402/schemes');
|
|
8
9
|
var accounts = require('viem/accounts');
|
|
9
10
|
|
|
10
|
-
// src/client.ts
|
|
11
|
-
|
|
12
|
-
// src/connector-channel.ts
|
|
13
|
-
var CONNECTOR_PACKAGE_NAME = "@haven_ai/connect";
|
|
14
|
-
var HAVEN_CONNECTOR_CHANNEL = "alpha";
|
|
15
|
-
var CHANNEL_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
16
|
-
function isConnectorChannel(value) {
|
|
17
|
-
return CHANNEL_PATTERN.test(value);
|
|
18
|
-
}
|
|
19
|
-
function resolveConnectorChannel(raw, fallback = HAVEN_CONNECTOR_CHANNEL) {
|
|
20
|
-
const trimmed = (raw ?? "").trim();
|
|
21
|
-
if (trimmed === "") return fallback;
|
|
22
|
-
if (!isConnectorChannel(trimmed)) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`HAVEN_CONNECTOR_CHANNEL is set to ${JSON.stringify(raw)}, which is not a valid npm dist-tag (lowercase letter first, then letters, digits or hyphens). Refusing to start rather than fall back to the default channel, because falling back would hand out the production connector while looking configured.`
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
return trimmed;
|
|
28
|
-
}
|
|
29
|
-
function connectorSpec(channel = HAVEN_CONNECTOR_CHANNEL) {
|
|
30
|
-
return `${CONNECTOR_PACKAGE_NAME}@${channel}`;
|
|
31
|
-
}
|
|
32
|
-
function connectorRerunCommand(args, options) {
|
|
33
|
-
const channel = options?.channel ?? HAVEN_CONNECTOR_CHANNEL;
|
|
34
|
-
const flags = options?.npxFlags ? `${options.npxFlags} ` : "";
|
|
35
|
-
const command = `npx ${flags}${connectorSpec(channel)}`;
|
|
36
|
-
return args ? `${command} ${args}` : command;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// src/types.ts
|
|
40
|
-
var DEFAULT_CONFIRMATION_TIMEOUT_MS = 9e4;
|
|
41
|
-
var AgentPaymentPhase = {
|
|
42
|
-
/** The agent must sign and submit the prepared payment before Haven can relay it. */
|
|
43
|
-
AgentSignatureRequired: "agent_signature_required",
|
|
44
|
-
/** Haven has received the signed payment and the agent should poll for confirmation. */
|
|
45
|
-
PaymentSubmitted: "payment_submitted",
|
|
46
|
-
/** The direct payment is confirmed; the agent does not need to do more for this payment id. */
|
|
47
|
-
PaymentConfirmed: "payment_confirmed",
|
|
48
|
-
/**
|
|
49
|
-
* #2115: RETIRED wire value — no live rail produces it. It described the
|
|
50
|
-
* Safe rail's approval queue, which no longer exists. Kept so a stored value
|
|
51
|
-
* still typechecks; see `AgentPaymentPhaseDescriptions` below for the
|
|
52
|
-
* agent-visible wording, which this comment used to contradict.
|
|
53
|
-
*/
|
|
54
|
-
UserApprovalRequired: "user_approval_required",
|
|
55
|
-
/** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
|
|
56
|
-
UserExecutionRequired: "user_execution_required",
|
|
57
|
-
/** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
|
|
58
|
-
WaitingForAdditionalApprovals: "waiting_for_additional_approvals",
|
|
59
|
-
/** The Haven funding leg was sent; the agent can continue the merchant/protocol leg. */
|
|
60
|
-
FundingSent: "funding_sent",
|
|
61
|
-
/** The payment was rejected and cannot proceed; the agent should stop and tell the user. */
|
|
62
|
-
Rejected: "rejected",
|
|
63
|
-
/** The payment expired before completion. */
|
|
64
|
-
Expired: "expired",
|
|
65
|
-
/** Haven could not complete the payment; the agent should stop and surface the failure. */
|
|
66
|
-
Failed: "failed",
|
|
67
|
-
/**
|
|
68
|
-
* Pre-flight check determined the delegate's existing balance plus the
|
|
69
|
-
* remaining on-chain budget cannot cover the requested amount, so no
|
|
70
|
-
* payment intent was created. The account must be funded or the agent's
|
|
71
|
-
* budget raised before retrying — #2115: the old wording contrasted this
|
|
72
|
-
* with `UserApprovalRequired` as if that were a live alternative, and named
|
|
73
|
-
* the retired rail's Safe and per-token allowance as the fix.
|
|
74
|
-
*/
|
|
75
|
-
InsufficientFunds: "insufficient_funds",
|
|
76
|
-
/**
|
|
77
|
-
* Haven's funding leg (account → delegate, the #946 EIP-3009 bridge)
|
|
78
|
-
* confirmed on-chain, but the merchant rejected the x402 retry. The delegate
|
|
79
|
-
* wallet may hold stranded USDC that was never settled to the merchant. The
|
|
80
|
-
* agent should stop, tell the user, and wait for the sweep flow to reclaim
|
|
81
|
-
* the funds.
|
|
82
|
-
*/
|
|
83
|
-
FundedButUnsettled: "funded_but_unsettled"
|
|
84
|
-
};
|
|
85
|
-
var AgentPaymentNextAction = {
|
|
86
|
-
/** Sign with the delegate key and submit the payment to Haven. */
|
|
87
|
-
SignAndSubmitPayment: "sign_and_submit_payment",
|
|
88
|
-
/** Poll getPaymentStatus later using this payment id. */
|
|
89
|
-
CheckStatusLater: "check_status_later",
|
|
90
|
-
/** No further agent action is required for this payment id. */
|
|
91
|
-
None: "none",
|
|
92
|
-
/**
|
|
93
|
-
* #2115: RETIRED wire value — no live rail produces it and nothing maps to
|
|
94
|
-
* it. Stop and tell the user rather than polling; no approval will arrive.
|
|
95
|
-
*/
|
|
96
|
-
WaitForUserApproval: "wait_for_user_approval",
|
|
97
|
-
/** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user rather than polling. */
|
|
98
|
-
WaitForUserToCompletePayment: "wait_for_user_to_complete_payment",
|
|
99
|
-
/** Resume this payment id and retry the original x402 request with the merchant payment header. */
|
|
100
|
-
RetryOriginalX402Request: "retry_original_x402_request",
|
|
101
|
-
/** Stop retrying this payment and tell the user what happened. */
|
|
102
|
-
StopAndTellUser: "stop_and_tell_user",
|
|
103
|
-
/** Ask again only if the user still wants the payment after expiry. */
|
|
104
|
-
RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it",
|
|
105
|
-
/** #1307: retry the SAME tool call, supplying the explicit context fields the server could not rehydrate. */
|
|
106
|
-
RetryWithExplicitContext: "retry_with_explicit_context",
|
|
107
|
-
/**
|
|
108
|
-
* The x402 funding/quote window expired. Re-quote the same logical merchant
|
|
109
|
-
* operation with the same idempotency key to stay double-charge-safe.
|
|
110
|
-
*/
|
|
111
|
-
PaymentWindowExpired: "payment_window_expired",
|
|
112
|
-
/**
|
|
113
|
-
* Stop and tell the user that the originating account needs to be funded or
|
|
114
|
-
* the agent's per-token allowance needs to be raised before the payment
|
|
115
|
-
* can succeed. A user approval will not fix this state on its own.
|
|
116
|
-
*
|
|
117
|
-
* #2914: the account-vocabulary spelling, and the only one — the
|
|
118
|
-
* pre-#2907 `fund_safe_or_raise_allowance` wire value (and the
|
|
119
|
-
* `AgentPaymentNextActionAccountAlias` seam #2908 added to bridge it) are
|
|
120
|
-
* retired along with the rest of the #2908 compatibility window.
|
|
121
|
-
*/
|
|
122
|
-
FundAccountOrRaiseAllowance: "fund_account_or_raise_allowance",
|
|
123
|
-
/**
|
|
124
|
-
* The delegate wallet may hold funds that were sent from the Safe but never
|
|
125
|
-
* settled to the merchant. The wallet owner should initiate a sweep to
|
|
126
|
-
* return those funds to the originating Safe.
|
|
127
|
-
*/
|
|
128
|
-
SweepStrandedFunds: "sweep_stranded_funds",
|
|
129
|
-
/**
|
|
130
|
-
* #2970: a `submitted` erc7710 x402 intent whose settlement window has
|
|
131
|
-
* passed with no on-chain settlement evidence Haven could verify. Distinct
|
|
132
|
-
* from {@link CheckStatusLater}, which this REPLACES once the window is
|
|
133
|
-
* past — but it is not futile: Haven's settlement sweep (120s tick) scans
|
|
134
|
-
* each candidate over its own window plus a 120s clock-skew allowance, so
|
|
135
|
-
* it can still attribute the settlement for a short while after this value
|
|
136
|
-
* first appears. Poll {@link CheckStatusLater}'s tool
|
|
137
|
-
* (`haven_get_payment_status`) once more, roughly two minutes later; if it
|
|
138
|
-
* still shows no evidence, tell the user the goods were delivered but
|
|
139
|
-
* Haven holds no verified settlement evidence for this payment. If the
|
|
140
|
-
* agent holds the merchant's real settlement transaction hash (from
|
|
141
|
-
* `PAYMENT-RESPONSE`'s `transaction` field, or a prior settle/complete
|
|
142
|
-
* result's `settlement_tx_hash`), report it with the hosted
|
|
143
|
-
* `haven_report_settlement_evidence` tool instead of waiting —
|
|
144
|
-
* `haven_report_x402_outcome` takes no hash and refuses a non-`confirmed`
|
|
145
|
-
* intent.
|
|
146
|
-
*/
|
|
147
|
-
AwaitingSettlementEvidence: "awaiting_settlement_evidence"
|
|
148
|
-
};
|
|
149
|
-
var AgentPaymentFailureCode = {
|
|
150
|
-
/** A merchant-authoritative x402 price exceeds the caller's pre-funding max_amount cap. */
|
|
151
|
-
PriceExceedsMax: "PRICE_EXCEEDS_MAX",
|
|
152
|
-
/** The x402 funding/quote window expired before the signer or hosted settle step could finish. */
|
|
153
|
-
PaymentWindowExpired: "PAYMENT_WINDOW_EXPIRED",
|
|
154
|
-
/** The merchant rejected the paid retry. On eip3009 the funding leg had succeeded (sweep);
|
|
155
|
-
* on erc7710 there is no funding leg — nothing to sweep, follow the message (#2983). */
|
|
156
|
-
MerchantRejectedAfterFunding: "MERCHANT_REJECTED_AFTER_FUNDING",
|
|
157
|
-
/** #1300 review: funding is on-chain but the merchant never ANSWERED the
|
|
158
|
-
* paid retry within the timeout. NOT proof of rejection — the merchant
|
|
159
|
-
* may still settle late, so the guidance is verify-then-act. On eip3009
|
|
160
|
-
* the funding leg had succeeded (verify-then-sweep); on erc7710 there is
|
|
161
|
-
* no funding leg — nothing to sweep, follow the message (#3000). */
|
|
162
|
-
MerchantUnresponsiveAfterFunding: "MERCHANT_UNRESPONSIVE_AFTER_FUNDING",
|
|
163
|
-
/**
|
|
164
|
-
* #1307: the caller omitted merchant_url/tool_name (asking Haven to
|
|
165
|
-
* rehydrate the stored MCP merchant-call context by payment_id), but no
|
|
166
|
-
* usable context was stored for this intent — either it was never an
|
|
167
|
-
* MCP-tool quote, or the stored context is incomplete. The fallback is
|
|
168
|
-
* mechanical: re-send merchant_url, tool_name, arguments, and
|
|
169
|
-
* mcp_transport explicitly (the version-skew path).
|
|
170
|
-
*/
|
|
171
|
-
MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE",
|
|
172
|
-
/**
|
|
173
|
-
* #1351: the caller supplied BOTH the atomic `max_amount` and the
|
|
174
|
-
* human-denominated `max_amount_human` cap for one purchase. Haven refuses
|
|
175
|
-
* to guess which the user meant — the two differ by a factor of 10^decimals,
|
|
176
|
-
* so picking wrong is exactly the silent-overspend this cap exists to
|
|
177
|
-
* prevent. Rejected before any merchant probe, funding intent, or signature.
|
|
178
|
-
*/
|
|
179
|
-
AmbiguousMaxAmount: "AMBIGUOUS_MAX_AMOUNT",
|
|
180
|
-
/**
|
|
181
|
-
* #1351: a human-denominated cap was supplied, but it cannot be converted to
|
|
182
|
-
* atomic units against THIS quote — either the quote's asset has no known
|
|
183
|
-
* decimals on its network, or the cap carries more fraction digits than the
|
|
184
|
-
* asset can represent (truncating it would silently change the user's cap).
|
|
185
|
-
* The fallback is the exact atomic `max_amount`.
|
|
186
|
-
*/
|
|
187
|
-
MaxAmountUnconvertible: "MAX_AMOUNT_UNCONVERTIBLE",
|
|
188
|
-
/**
|
|
189
|
-
* #2979: the merchant answered a `tools/call` probe with its own
|
|
190
|
-
* machine-readable "cannot settle right now" refusal (HTTP 503,
|
|
191
|
-
* `{ error: 'merchant_not_ready', reason_code, ... }`) instead of a 402
|
|
192
|
-
* challenge — e.g. its settlement wallet is out of gas. No 402 was ever
|
|
193
|
-
* issued and no payment was created; this is honest and (per
|
|
194
|
-
* `retry_after_s`, when present) usually transient, unlike a permanent
|
|
195
|
-
* endpoint miss.
|
|
196
|
-
*/
|
|
197
|
-
MerchantNotReady: "MERCHANT_NOT_READY"
|
|
198
|
-
};
|
|
199
|
-
var AgentPaymentRail = {
|
|
200
|
-
/** Standard Haven payment from the user's Safe through an approved delegate allowance. */
|
|
201
|
-
Direct: "direct",
|
|
202
|
-
/** x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg. */
|
|
203
|
-
X402: "x402",
|
|
204
|
-
/** Machine Payment Protocol family — categorical value used as a resume-state discriminator. */
|
|
205
|
-
Mpp: "mpp",
|
|
206
|
-
/** Haven internal MPP demo rail. Not for production traffic. */
|
|
207
|
-
MppDemo: "mpp_demo",
|
|
208
|
-
/** Crypto-settled MPP rail. */
|
|
209
|
-
MppCrypto: "mpp_crypto",
|
|
210
|
-
/** Stripe-deposit-backed MPP rail. */
|
|
211
|
-
StripeDeposit: "stripe_deposit",
|
|
212
|
-
/** Stripe Payment Token MPP rail. */
|
|
213
|
-
Spt: "spt"
|
|
214
|
-
};
|
|
215
|
-
var AGENT_PAYMENT_PHASE_VALUES = Object.values(AgentPaymentPhase);
|
|
216
|
-
var AGENT_PAYMENT_NEXT_ACTION_VALUES = Object.values(AgentPaymentNextAction);
|
|
217
|
-
var AGENT_PAYMENT_FAILURE_CODE_VALUES = Object.values(AgentPaymentFailureCode);
|
|
218
|
-
var AGENT_PAYMENT_RAIL_VALUES = Object.values(AgentPaymentRail);
|
|
219
|
-
var AgentPaymentPhaseDescriptions = {
|
|
220
|
-
[AgentPaymentPhase.AgentSignatureRequired]: "The agent must sign and submit the prepared payment before Haven can relay it.",
|
|
221
|
-
[AgentPaymentPhase.PaymentSubmitted]: "Haven has received the signed payment and the agent should poll for confirmation.",
|
|
222
|
-
[AgentPaymentPhase.PaymentConfirmed]: "The direct payment is confirmed; the agent does not need to do more for this payment id.",
|
|
223
|
-
[AgentPaymentPhase.UserApprovalRequired]: "Retired wire value: no live rail produces it. It described the Safe rail's approval queue, which no longer exists \u2014 an out-of-policy payment is declined before any money moves. If it is ever seen, stop and tell the user; no approval is pending.",
|
|
224
|
-
[AgentPaymentPhase.UserExecutionRequired]: "Retired wire value: no live rail produces it. Stop and tell the user.",
|
|
225
|
-
[AgentPaymentPhase.WaitingForAdditionalApprovals]: "Retired wire value: no live rail produces it. Stop and tell the user.",
|
|
226
|
-
[AgentPaymentPhase.FundingSent]: "The Haven funding leg was sent; the agent can continue the merchant/protocol leg.",
|
|
227
|
-
[AgentPaymentPhase.Rejected]: "The payment was rejected and cannot proceed; the agent should stop and tell the user.",
|
|
228
|
-
[AgentPaymentPhase.Expired]: "The payment expired before completion.",
|
|
229
|
-
[AgentPaymentPhase.Failed]: "Haven could not complete the payment; the agent should stop and surface the failure.",
|
|
230
|
-
[AgentPaymentPhase.InsufficientFunds]: "Pre-flight check determined the delegate balance plus the remaining on-chain budget cannot cover the requested amount, so no payment was created. The account must be funded or the agent budget raised before retrying.",
|
|
231
|
-
[AgentPaymentPhase.FundedButUnsettled]: "Haven's funding leg confirmed on-chain but the merchant rejected the x402 retry. The delegate wallet may hold stranded funds. The agent should stop and wait for the wallet owner to sweep the stranded funds back to the account."
|
|
232
|
-
};
|
|
233
|
-
var AgentPaymentNextActionDescriptions = {
|
|
234
|
-
[AgentPaymentNextAction.SignAndSubmitPayment]: "Sign with the delegate key and submit the payment to Haven.",
|
|
235
|
-
[AgentPaymentNextAction.CheckStatusLater]: "Poll getPaymentStatus later using this payment id.",
|
|
236
|
-
[AgentPaymentNextAction.None]: "No further agent action is required for this payment id.",
|
|
237
|
-
[AgentPaymentNextAction.WaitForUserApproval]: "Retired wire value: no live rail produces it, and nothing maps to it. It described a per-payment approval queue that no longer exists. If it is ever seen, stop and tell the user rather than polling \u2014 no approval will arrive.",
|
|
238
|
-
[AgentPaymentNextAction.WaitForUserToCompletePayment]: "Retired wire value: no live rail produces it. Stop and tell the user rather than polling.",
|
|
239
|
-
[AgentPaymentNextAction.RetryOriginalX402Request]: "Resume this payment id and retry the original x402 request with the merchant payment header.",
|
|
240
|
-
[AgentPaymentNextAction.StopAndTellUser]: "Stop retrying this payment and tell the user what happened.",
|
|
241
|
-
[AgentPaymentNextAction.RequestAgainIfUserStillWantsIt]: "Ask again only if the user still wants the payment after expiry.",
|
|
242
|
-
[AgentPaymentNextAction.PaymentWindowExpired]: "The x402 funding/quote window expired. Re-quote with the same idempotency key before asking the signer to build a merchant payment header again.",
|
|
243
|
-
[AgentPaymentNextAction.FundAccountOrRaiseAllowance]: "Stop and tell the user that the account needs to be funded or the agent budget raised before the payment can succeed.",
|
|
244
|
-
[AgentPaymentNextAction.RetryWithExplicitContext]: "Retry the same tool call, this time passing merchant_url, tool_name, arguments, and mcp_transport explicitly \u2014 the server had no stored context to rehydrate for this payment id.",
|
|
245
|
-
[AgentPaymentNextAction.SweepStrandedFunds]: "Tell the user that funds may be stranded in the delegate wallet and prompt them to initiate a sweep in Haven to return them to the originating account.",
|
|
246
|
-
[AgentPaymentNextAction.AwaitingSettlementEvidence]: "The settlement window passed with no verified on-chain evidence yet. If you hold the merchant's real settlement transaction hash, report it with haven_report_settlement_evidence. Otherwise, Haven's settlement sweep may still attribute it within about two minutes \u2014 poll getPaymentStatus once more, then tell the user the goods were delivered but unverified if it still shows nothing."
|
|
247
|
-
};
|
|
248
|
-
var AgentPaymentFailureCodeDescriptions = {
|
|
249
|
-
[AgentPaymentFailureCode.PriceExceedsMax]: "The merchant-authoritative x402 amount exceeds the caller's max_amount cap. No funding transfer was created; ask the user before retrying with a larger cap.",
|
|
250
|
-
[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.",
|
|
251
|
-
[AgentPaymentFailureCode.MerchantRejectedAfterFunding]: "The merchant rejected the paid retry. eip3009: the funding leg succeeded \u2014 stop retrying the merchant and reconcile stranded delegate funds with haven_sweep_delegate. erc7710: no funding leg, nothing to sweep \u2014 follow the message (re-quote later, or check haven_get_payment_status after the window first).",
|
|
252
|
-
[AgentPaymentFailureCode.MerchantUnresponsiveAfterFunding]: "The merchant did not answer the paid retry before the timeout. The merchant may still settle late. eip3009: the funding leg succeeded \u2014 check haven_get_payment_status, retry haven_complete_mcp_tool once, sweep only if no settlement appears. erc7710: no funding leg, nothing to sweep, and haven_complete_mcp_tool has no erc7710 branch \u2014 do not retry it; check haven_get_payment_status after the payment window and re-quote only if it shows no settlement.",
|
|
253
|
-
[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.",
|
|
254
|
-
[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.",
|
|
255
|
-
[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.",
|
|
256
|
-
[AgentPaymentFailureCode.MerchantNotReady]: 'The merchant refused the probe with its own "cannot settle right now" signal instead of a 402 challenge. No payment was created. Often transient \u2014 retry later (see retry_after_s in the message, if given) rather than treating this as a broken or wrong endpoint.'
|
|
257
|
-
};
|
|
258
|
-
var AgentPaymentWarningCode = {
|
|
259
|
-
/** No max_amount cap was supplied — the live quoted price was accepted as-is. */
|
|
260
|
-
MissingMaxAmount: "MISSING_MAX_AMOUNT",
|
|
261
|
-
/** The signing window closes soon; sign promptly or re-quote with the same idempotency key. */
|
|
262
|
-
QuoteExpiresSoon: "QUOTE_EXPIRES_SOON",
|
|
263
|
-
/** The merchant URL was resolved via discovery — pass the RESOLVED url forward. */
|
|
264
|
-
MerchantUrlDiscovered: "MERCHANT_URL_DISCOVERED",
|
|
265
|
-
/**
|
|
266
|
-
* #1306: the catalog's last-verified price_atomic differs from the LIVE
|
|
267
|
-
* merchant quote for a guided catalog purchase. The catalog price is only
|
|
268
|
-
* ever indicative; the live quote in the same response is authoritative.
|
|
269
|
-
*/
|
|
270
|
-
CatalogPriceDiffers: "CATALOG_PRICE_DIFFERS",
|
|
271
|
-
/**
|
|
272
|
-
* #1306: the rail-aware allowance/budget pre-check could not be read (RPC
|
|
273
|
-
* failure, etc). `sufficient` is reported as null rather than a fabricated
|
|
274
|
-
* true/false — the on-chain policy remains the actual gate either way.
|
|
275
|
-
*/
|
|
276
|
-
AllowanceCheckUnavailable: "ALLOWANCE_CHECK_UNAVAILABLE",
|
|
277
|
-
/**
|
|
278
|
-
* #1319: the delegation-rail read itself SUCCEEDED, but the remaining
|
|
279
|
-
* figure it returned is the #1145 fallback (the full configured budget)
|
|
280
|
-
* rather than a live ERC20PeriodTransferEnforcer read — `sufficient` is a
|
|
281
|
-
* real true/false, just computed from an optimistic number. Distinct from
|
|
282
|
-
* {@link AgentPaymentWarningCode.AllowanceCheckUnavailable}, which fires
|
|
283
|
-
* when the read failed outright and `sufficient` degrades to null. The
|
|
284
|
-
* on-chain policy re-checks at redemption either way; this only says the
|
|
285
|
-
* guidance shown here may be optimistic.
|
|
286
|
-
*/
|
|
287
|
-
AllowanceReadOptimistic: "ALLOWANCE_READ_OPTIMISTIC",
|
|
288
|
-
/**
|
|
289
|
-
* #2991: the quote tools' `expected_settlement_scheme` prediction of what
|
|
290
|
-
* `haven_prepare_catalog_purchase` / `haven_pay_mcp_tool` will actually
|
|
291
|
-
* select could not be computed — the agent's execution rail could not be
|
|
292
|
-
* read from Haven, so `expected_settlement_scheme` is `null` rather than a
|
|
293
|
-
* guess. `accepted_scheme` (the merchant's offer) is unaffected.
|
|
294
|
-
*/
|
|
295
|
-
X402SchemeUnknown: "X402_SCHEME_UNKNOWN",
|
|
296
|
-
/**
|
|
297
|
-
* #2968: the merchant answered 200 and handed over goods, but Haven holds NO
|
|
298
|
-
* on-chain evidence that the payment moved. `settled: false` beside this code
|
|
299
|
-
* is not a failure — it is the absence of proof, and the two must travel
|
|
300
|
-
* together so an agent can tell "the user has the goods" apart from "the
|
|
301
|
-
* money moved". Carries the intent's `expires_at`: after that instant the
|
|
302
|
-
* settlement can no longer land at all.
|
|
303
|
-
*/
|
|
304
|
-
SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED"
|
|
305
|
-
};
|
|
306
|
-
var AgentPaymentRailDescriptions = {
|
|
307
|
-
[AgentPaymentRail.Direct]: "Standard Haven payment from the user-controlled account, redeeming the agent's on-chain budget delegation.",
|
|
308
|
-
[AgentPaymentRail.X402]: "x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg.",
|
|
309
|
-
[AgentPaymentRail.Mpp]: "Categorical MPP rail value used as a resume-state discriminator. Response bodies carry a granular mpp_* value instead.",
|
|
310
|
-
[AgentPaymentRail.MppDemo]: "Haven internal MPP demo rail. Not for production traffic.",
|
|
311
|
-
[AgentPaymentRail.MppCrypto]: "Crypto-settled MPP rail.",
|
|
312
|
-
[AgentPaymentRail.StripeDeposit]: "Stripe-deposit-backed MPP rail.",
|
|
313
|
-
[AgentPaymentRail.Spt]: "Stripe Payment Token MPP rail."
|
|
314
|
-
};
|
|
315
|
-
var AgentPaymentPhaseSchema = {
|
|
316
|
-
type: "string",
|
|
317
|
-
enum: AGENT_PAYMENT_PHASE_VALUES,
|
|
318
|
-
description: "Stable Haven agent payment state phase.",
|
|
319
|
-
"x-enumDescriptions": AgentPaymentPhaseDescriptions
|
|
320
|
-
};
|
|
321
|
-
var AgentPaymentNextActionSchema = {
|
|
322
|
-
type: "string",
|
|
323
|
-
enum: AGENT_PAYMENT_NEXT_ACTION_VALUES,
|
|
324
|
-
description: "Stable next action an agent should take for a Haven payment state.",
|
|
325
|
-
"x-enumDescriptions": AgentPaymentNextActionDescriptions
|
|
326
|
-
};
|
|
327
|
-
var AgentPaymentFailureCodeSchema = {
|
|
328
|
-
type: "string",
|
|
329
|
-
enum: AGENT_PAYMENT_FAILURE_CODE_VALUES,
|
|
330
|
-
description: "Stable machine-readable failure codes for Haven agent payment recovery paths.",
|
|
331
|
-
"x-enumDescriptions": AgentPaymentFailureCodeDescriptions
|
|
332
|
-
};
|
|
333
|
-
var AgentPaymentRailSchema = {
|
|
334
|
-
type: "string",
|
|
335
|
-
enum: AGENT_PAYMENT_RAIL_VALUES,
|
|
336
|
-
description: "Stable rail identifier for Haven agent payment states.",
|
|
337
|
-
"x-enumDescriptions": AgentPaymentRailDescriptions
|
|
338
|
-
};
|
|
339
|
-
var HavenError = class extends Error {
|
|
340
|
-
constructor(message, code, statusCode, paymentId) {
|
|
341
|
-
super(message);
|
|
342
|
-
this.code = code;
|
|
343
|
-
this.statusCode = statusCode;
|
|
344
|
-
this.paymentId = paymentId;
|
|
345
|
-
this.name = "HavenError";
|
|
346
|
-
}
|
|
347
|
-
code;
|
|
348
|
-
statusCode;
|
|
349
|
-
paymentId;
|
|
350
|
-
};
|
|
351
|
-
var HavenApiError = class extends HavenError {
|
|
352
|
-
constructor(message, statusCode, body, paymentId) {
|
|
353
|
-
super(message, "API_ERROR", statusCode, paymentId);
|
|
354
|
-
this.body = body;
|
|
355
|
-
this.name = "HavenApiError";
|
|
356
|
-
}
|
|
357
|
-
body;
|
|
358
|
-
};
|
|
359
|
-
var MerchantTimeoutError = class extends HavenApiError {
|
|
360
|
-
merchantErrorCode = "merchant_timeout";
|
|
361
|
-
constructor(message) {
|
|
362
|
-
super(message, 504);
|
|
363
|
-
this.name = "MerchantTimeoutError";
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
var X402UnexpectedStatusError = class extends HavenApiError {
|
|
367
|
-
x402ErrorCode = "unexpected_non_402_status";
|
|
368
|
-
/**
|
|
369
|
-
* #2979: `body` is the merchant's own JSON, when the non-402 response
|
|
370
|
-
* carried one — e.g. the demo merchant's `/mcp` readiness gate answers
|
|
371
|
-
* `503 { error: 'merchant_not_ready', reason_code, ... }`. Optional and
|
|
372
|
-
* best-effort: a non-JSON or unreadable body leaves this `undefined`, same
|
|
373
|
-
* as before this field existed. Consumers key on it (not on the message
|
|
374
|
-
* string) to distinguish an honest, machine-readable merchant refusal from
|
|
375
|
-
* a genuine "this is not the x402 endpoint" miss, which otherwise look
|
|
376
|
-
* identical — both are just "some non-402 status".
|
|
377
|
-
*/
|
|
378
|
-
constructor(message, statusCode, body) {
|
|
379
|
-
super(message, statusCode, body);
|
|
380
|
-
this.name = "X402UnexpectedStatusError";
|
|
381
|
-
}
|
|
382
|
-
};
|
|
383
|
-
var X402AlreadySettledError = class extends HavenApiError {
|
|
384
|
-
constructor(message, receipt, basis) {
|
|
385
|
-
super(message, 409, void 0, receipt.paymentId);
|
|
386
|
-
this.receipt = receipt;
|
|
387
|
-
this.basis = basis;
|
|
388
|
-
this.name = "X402AlreadySettledError";
|
|
389
|
-
}
|
|
390
|
-
receipt;
|
|
391
|
-
basis;
|
|
392
|
-
x402ErrorCode = "already_settled";
|
|
393
|
-
};
|
|
394
|
-
var HavenPaymentStateError = class extends HavenApiError {
|
|
395
|
-
constructor(message, statusCode, state, body) {
|
|
396
|
-
super(message, statusCode, body, state.paymentId);
|
|
397
|
-
this.state = state;
|
|
398
|
-
this.name = "HavenPaymentStateError";
|
|
399
|
-
}
|
|
400
|
-
state;
|
|
401
|
-
resumeState;
|
|
402
|
-
get status() {
|
|
403
|
-
return this.state.status;
|
|
404
|
-
}
|
|
405
|
-
get phase() {
|
|
406
|
-
return this.state.phase;
|
|
407
|
-
}
|
|
408
|
-
get nextAction() {
|
|
409
|
-
return this.state.nextAction;
|
|
410
|
-
}
|
|
411
|
-
};
|
|
412
|
-
var HavenSigningError = class extends HavenError {
|
|
413
|
-
constructor(message) {
|
|
414
|
-
super(message, "SIGNING_ERROR");
|
|
415
|
-
this.name = "HavenSigningError";
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
var HavenZeroSettlementHashError = class extends HavenError {
|
|
419
|
-
constructor(paymentId) {
|
|
420
|
-
super(
|
|
421
|
-
"settlement_tx_hash is the zero hash (0x00\u202600), which is never a real settlement transaction \u2014 refused before any report was sent.",
|
|
422
|
-
"ZERO_SETTLEMENT_HASH",
|
|
423
|
-
400,
|
|
424
|
-
paymentId
|
|
425
|
-
);
|
|
426
|
-
this.name = "HavenZeroSettlementHashError";
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
var SignerRefusalCode = {
|
|
430
|
-
/** `SUPPORTED_X402_EXPECTED_VERSIONS` in `@haven_ai/signer` does not include the received version. */
|
|
431
|
-
UnsupportedExpectedContextVersion: "UNSUPPORTED_EXPECTED_CONTEXT_VERSION",
|
|
432
|
-
/** `SUPPORTED_SWEEP_BINDING_VERSIONS` in `@haven_ai/signer` does not include the received version. */
|
|
433
|
-
UnsupportedSweepBindingVersion: "UNSUPPORTED_SWEEP_BINDING_VERSION"
|
|
434
|
-
};
|
|
435
|
-
function signerUpdateFallback(channel = HAVEN_CONNECTOR_CHANNEL) {
|
|
436
|
-
return `Update @haven_ai/signer by rerunning \`${connectorRerunCommand(void 0, { channel })}\`, which reinstalls the pinned MCP runtime, then retry the same signing call. Nothing was signed or spent \u2014 the quote or payment this version came from is unaffected and does not need to be re-quoted.`;
|
|
437
|
-
}
|
|
438
|
-
var SIGNER_UPDATE_FALLBACK = signerUpdateFallback();
|
|
439
|
-
var HavenUnsupportedSignerVersionError = class extends HavenError {
|
|
440
|
-
constructor(message, code, supportedVersions, receivedVersion, fallback) {
|
|
441
|
-
super(message, code);
|
|
442
|
-
this.supportedVersions = supportedVersions;
|
|
443
|
-
this.receivedVersion = receivedVersion;
|
|
444
|
-
this.fallback = fallback;
|
|
445
|
-
this.name = "HavenUnsupportedSignerVersionError";
|
|
446
|
-
}
|
|
447
|
-
supportedVersions;
|
|
448
|
-
receivedVersion;
|
|
449
|
-
fallback;
|
|
450
|
-
};
|
|
451
|
-
var HavenTimeoutError = class extends HavenError {
|
|
452
|
-
constructor(paymentId) {
|
|
453
|
-
super(
|
|
454
|
-
`Timed out waiting for payment ${paymentId} to confirm`,
|
|
455
|
-
"TIMEOUT",
|
|
456
|
-
void 0,
|
|
457
|
-
paymentId
|
|
458
|
-
);
|
|
459
|
-
this.name = "HavenTimeoutError";
|
|
460
|
-
}
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
// src/signer.ts
|
|
464
11
|
function signHash(privateKey, hash) {
|
|
465
12
|
try {
|
|
466
13
|
const signingKey = new ethers.ethers.SigningKey(privateKey);
|
|
467
14
|
const sig = signingKey.sign(hash);
|
|
468
15
|
return sig.serialized;
|
|
469
16
|
} catch (err) {
|
|
470
|
-
throw new HavenSigningError(
|
|
17
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
471
18
|
`Failed to sign hash: ${err instanceof Error ? err.message : String(err)}`
|
|
472
19
|
);
|
|
473
20
|
}
|
|
@@ -483,7 +30,7 @@ async function signTypedDataVerbatim(privateKey, typedData, label) {
|
|
|
483
30
|
typedData.message
|
|
484
31
|
);
|
|
485
32
|
} catch (err) {
|
|
486
|
-
throw new HavenSigningError(
|
|
33
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
487
34
|
`Failed to sign ${label}: ${err instanceof Error ? err.message : String(err)}`
|
|
488
35
|
);
|
|
489
36
|
}
|
|
@@ -498,7 +45,7 @@ function addressFromKey(privateKey) {
|
|
|
498
45
|
try {
|
|
499
46
|
return new ethers.ethers.Wallet(privateKey).address;
|
|
500
47
|
} catch (err) {
|
|
501
|
-
throw new HavenSigningError(
|
|
48
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
502
49
|
`Invalid private key: ${err instanceof Error ? err.message : String(err)}`
|
|
503
50
|
);
|
|
504
51
|
}
|
|
@@ -511,615 +58,43 @@ function verifySignature(hash, signature, expectedAddress) {
|
|
|
511
58
|
return false;
|
|
512
59
|
}
|
|
513
60
|
}
|
|
514
|
-
|
|
515
|
-
// src/base64.ts
|
|
516
|
-
function normalizeBase64(value) {
|
|
517
|
-
const standard = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
518
|
-
const remainder = standard.length % 4;
|
|
519
|
-
return remainder === 0 ? standard : standard + "=".repeat(4 - remainder);
|
|
520
|
-
}
|
|
521
|
-
function encodeBase64Utf8(value) {
|
|
522
|
-
if (typeof Buffer !== "undefined") {
|
|
523
|
-
return Buffer.from(value, "utf8").toString("base64");
|
|
524
|
-
}
|
|
525
|
-
const bytes = new TextEncoder().encode(value);
|
|
526
|
-
let binary = "";
|
|
527
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
528
|
-
binary += String.fromCharCode(bytes[i]);
|
|
529
|
-
}
|
|
530
|
-
return btoa(binary);
|
|
531
|
-
}
|
|
532
|
-
function decodeBase64Utf8(value) {
|
|
533
|
-
const normalized = normalizeBase64(value);
|
|
534
|
-
if (typeof Buffer !== "undefined") {
|
|
535
|
-
return Buffer.from(normalized, "base64").toString("utf8");
|
|
536
|
-
}
|
|
537
|
-
const binary = atob(normalized);
|
|
538
|
-
const bytes = new Uint8Array(binary.length);
|
|
539
|
-
for (let i = 0; i < binary.length; i++) {
|
|
540
|
-
bytes[i] = binary.charCodeAt(i);
|
|
541
|
-
}
|
|
542
|
-
return new TextDecoder().decode(bytes);
|
|
543
|
-
}
|
|
544
|
-
function encodeBase64Json(value) {
|
|
545
|
-
return encodeBase64Utf8(JSON.stringify(value));
|
|
546
|
-
}
|
|
547
|
-
function decodeBase64Json(value, label) {
|
|
548
|
-
try {
|
|
549
|
-
return JSON.parse(decodeBase64Utf8(value));
|
|
550
|
-
} catch (err) {
|
|
551
|
-
if (label) throw new Error(`Failed to decode ${label}`);
|
|
552
|
-
throw err;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// src/sweep.ts
|
|
557
|
-
var SWEEP_BASE_CHAIN_ID = 8453;
|
|
558
|
-
var SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
|
|
559
|
-
var SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
560
|
-
var SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
561
|
-
var USDC_EIP712_DOMAIN_BY_CHAIN = {
|
|
562
|
-
[SWEEP_BASE_CHAIN_ID]: {
|
|
563
|
-
name: "USD Coin",
|
|
564
|
-
version: "2",
|
|
565
|
-
chainId: SWEEP_BASE_CHAIN_ID,
|
|
566
|
-
verifyingContract: SWEEP_BASE_USDC_ADDRESS
|
|
567
|
-
},
|
|
568
|
-
[SWEEP_BASE_SEPOLIA_CHAIN_ID]: {
|
|
569
|
-
name: "USDC",
|
|
570
|
-
version: "2",
|
|
571
|
-
chainId: SWEEP_BASE_SEPOLIA_CHAIN_ID,
|
|
572
|
-
verifyingContract: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
var USDC_ADDRESS_BY_CHAIN = {
|
|
576
|
-
[SWEEP_BASE_CHAIN_ID]: SWEEP_BASE_USDC_ADDRESS,
|
|
577
|
-
[SWEEP_BASE_SEPOLIA_CHAIN_ID]: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
|
|
578
|
-
};
|
|
579
|
-
var SWEEPABLE_CHAIN_IDS = Object.keys(USDC_ADDRESS_BY_CHAIN).map(Number);
|
|
580
|
-
function isSweepableChain(chainId) {
|
|
581
|
-
return chainId in USDC_ADDRESS_BY_CHAIN;
|
|
582
|
-
}
|
|
583
|
-
var TRANSFER_WITH_AUTHORIZATION_TYPES = {
|
|
584
|
-
TransferWithAuthorization: [
|
|
585
|
-
{ name: "from", type: "address" },
|
|
586
|
-
{ name: "to", type: "address" },
|
|
587
|
-
{ name: "value", type: "uint256" },
|
|
588
|
-
{ name: "validAfter", type: "uint256" },
|
|
589
|
-
{ name: "validBefore", type: "uint256" },
|
|
590
|
-
{ name: "nonce", type: "bytes32" }
|
|
591
|
-
]
|
|
592
|
-
};
|
|
593
|
-
function sweepUsdcAddress(chainId) {
|
|
594
|
-
const address = USDC_ADDRESS_BY_CHAIN[chainId];
|
|
595
|
-
if (!address) {
|
|
596
|
-
throw new HavenSigningError(
|
|
597
|
-
`Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
return address;
|
|
601
|
-
}
|
|
602
|
-
function sweepUsdcDomain(chainId) {
|
|
603
|
-
const domain = USDC_EIP712_DOMAIN_BY_CHAIN[chainId];
|
|
604
|
-
if (!domain) {
|
|
605
|
-
throw new HavenSigningError(
|
|
606
|
-
`Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
return domain;
|
|
610
|
-
}
|
|
611
|
-
function sameAddress(a, b) {
|
|
612
|
-
return a.toLowerCase() === b.toLowerCase();
|
|
613
|
-
}
|
|
614
|
-
function buildSweepTypedData(auth) {
|
|
615
|
-
const domain = sweepUsdcDomain(auth.chainId);
|
|
616
|
-
const expectedToken = sweepUsdcAddress(auth.chainId);
|
|
617
|
-
if (!sameAddress(auth.token, expectedToken)) {
|
|
618
|
-
throw new HavenSigningError(
|
|
619
|
-
`Sweep token ${auth.token} is not the canonical USDC contract for chain ${auth.chainId}.`
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
if (!/^0x[0-9a-fA-F]{64}$/.test(auth.nonce)) {
|
|
623
|
-
throw new HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
|
|
624
|
-
}
|
|
625
|
-
return {
|
|
626
|
-
domain,
|
|
627
|
-
types: TRANSFER_WITH_AUTHORIZATION_TYPES,
|
|
628
|
-
primaryType: "TransferWithAuthorization",
|
|
629
|
-
message: {
|
|
630
|
-
from: auth.from,
|
|
631
|
-
to: auth.to,
|
|
632
|
-
value: BigInt(auth.value),
|
|
633
|
-
validAfter: BigInt(auth.validAfter),
|
|
634
|
-
validBefore: BigInt(auth.validBefore),
|
|
635
|
-
nonce: auth.nonce
|
|
636
|
-
}
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
function buildSweepAuthorizationMessage(auth) {
|
|
640
|
-
return `Haven sweep authorization v1
|
|
641
|
-
${stableStringify({
|
|
642
|
-
version: 1,
|
|
643
|
-
kind: "haven.sweep.authorization",
|
|
644
|
-
from: auth.from.toLowerCase(),
|
|
645
|
-
to: auth.to.toLowerCase(),
|
|
646
|
-
value: auth.value,
|
|
647
|
-
validAfter: auth.validAfter,
|
|
648
|
-
validBefore: auth.validBefore,
|
|
649
|
-
nonce: auth.nonce.toLowerCase(),
|
|
650
|
-
token: auth.token.toLowerCase(),
|
|
651
|
-
chainId: auth.chainId
|
|
652
|
-
})}`;
|
|
653
|
-
}
|
|
654
|
-
function stableStringify(value) {
|
|
655
|
-
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
656
|
-
if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
|
|
657
|
-
const object = value;
|
|
658
|
-
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// src/x402.ts
|
|
662
|
-
var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
663
|
-
var BASE_SEPOLIA_USDC_ADDRESS = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
|
|
664
|
-
var STANDARD_X402_USDC_ADDRESSES = /* @__PURE__ */ new Set([BASE_USDC_ADDRESS, BASE_SEPOLIA_USDC_ADDRESS]);
|
|
665
|
-
var X402_IDEMPOTENCY_BUCKET_MS = 3e5;
|
|
666
|
-
var DECIMAL_ATOMIC_AMOUNT_RE = /^[0-9]+$/;
|
|
667
|
-
var X402_PAYMENT_HEADER_MAX_LENGTH = 65536;
|
|
668
|
-
var BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
669
|
-
var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
670
|
-
var SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;
|
|
671
|
-
var NONCE_RE = /^0x[0-9a-fA-F]{64}$/;
|
|
672
|
-
var X402PaymentHeaderValidationError = class extends Error {
|
|
673
|
-
constructor() {
|
|
674
|
-
super("Invalid X-PAYMENT header.");
|
|
675
|
-
this.name = "X402PaymentHeaderValidationError";
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
function isPositiveDecimalAtomicAmount(value) {
|
|
679
|
-
return DECIMAL_ATOMIC_AMOUNT_RE.test(value) && BigInt(value) > 0n;
|
|
680
|
-
}
|
|
681
|
-
function optionAuthorizationAmount(option) {
|
|
682
|
-
return option.maxAmountRequired ?? option.amount;
|
|
683
|
-
}
|
|
684
|
-
var X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
|
|
685
|
-
var X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
|
|
686
|
-
function clampAuthorizationWindow(seconds) {
|
|
687
|
-
const requested = typeof seconds === "number" && Number.isFinite(seconds) ? seconds : 30;
|
|
688
|
-
return Math.min(Math.max(Math.floor(requested), 1), X402_MAX_AUTHORIZATION_WINDOW_SECONDS);
|
|
689
|
-
}
|
|
690
|
-
function normalizePaymentOption(value) {
|
|
691
|
-
const candidate = value;
|
|
692
|
-
if (!candidate || typeof candidate !== "object" || typeof candidate.scheme !== "string" || typeof candidate.network !== "string" || typeof candidate.asset !== "string" || typeof candidate.payTo !== "string") {
|
|
693
|
-
return null;
|
|
694
|
-
}
|
|
695
|
-
const amount = typeof candidate.amount === "string" ? candidate.amount : typeof candidate.maxAmountRequired === "string" ? candidate.maxAmountRequired : null;
|
|
696
|
-
if (!amount) return null;
|
|
697
|
-
if (!isPositiveDecimalAtomicAmount(amount)) return null;
|
|
698
|
-
if (candidate.maxAmountRequired !== void 0 && (typeof candidate.maxAmountRequired !== "string" || !isPositiveDecimalAtomicAmount(candidate.maxAmountRequired))) {
|
|
699
|
-
return null;
|
|
700
|
-
}
|
|
701
|
-
return {
|
|
702
|
-
scheme: candidate.scheme,
|
|
703
|
-
network: candidate.network,
|
|
704
|
-
amount,
|
|
705
|
-
maxAmountRequired: candidate.maxAmountRequired,
|
|
706
|
-
resource: candidate.resource,
|
|
707
|
-
description: candidate.description,
|
|
708
|
-
mimeType: candidate.mimeType,
|
|
709
|
-
asset: candidate.asset,
|
|
710
|
-
payTo: candidate.payTo,
|
|
711
|
-
maxTimeoutSeconds: clampAuthorizationWindow(candidate.maxTimeoutSeconds),
|
|
712
|
-
extra: candidate.extra
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
function normalizePaymentRequired(value) {
|
|
716
|
-
const candidate = value;
|
|
717
|
-
if (!candidate || typeof candidate !== "object" || typeof candidate.x402Version !== "number" || !Array.isArray(candidate.accepts)) {
|
|
718
|
-
return null;
|
|
719
|
-
}
|
|
720
|
-
const accepts = candidate.accepts.map((option) => normalizePaymentOption(option)).filter((option) => !!option && typeof option === "object");
|
|
721
|
-
if (accepts.length === 0) return null;
|
|
722
|
-
const first = accepts[0];
|
|
723
|
-
const resourceUrl = candidate.resource?.url ?? first.resource;
|
|
724
|
-
if (!resourceUrl) return null;
|
|
725
|
-
const resource = {
|
|
726
|
-
...candidate.resource && typeof candidate.resource === "object" ? candidate.resource : {},
|
|
727
|
-
url: resourceUrl,
|
|
728
|
-
description: candidate.resource?.description ?? first.description,
|
|
729
|
-
mimeType: candidate.resource?.mimeType ?? first.mimeType
|
|
730
|
-
};
|
|
731
|
-
return {
|
|
732
|
-
x402Version: candidate.x402Version,
|
|
733
|
-
resource,
|
|
734
|
-
accepts,
|
|
735
|
-
error: candidate.error,
|
|
736
|
-
...candidate.extensions && typeof candidate.extensions === "object" ? { extensions: candidate.extensions } : {}
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
var SUPPORTED_X402_NETWORKS = {
|
|
740
|
-
"eip155:100": "Gnosis Chain",
|
|
741
|
-
"eip155:8453": "Base",
|
|
742
|
-
"base": "Base",
|
|
743
|
-
"eip155:84532": "Base Sepolia",
|
|
744
|
-
"base-sepolia": "Base Sepolia"
|
|
745
|
-
};
|
|
746
|
-
var STANDARD_X402_NETWORKS = {
|
|
747
|
-
"eip155:8453": "base",
|
|
748
|
-
"base": "base",
|
|
749
|
-
"eip155:84532": "base-sepolia",
|
|
750
|
-
"base-sepolia": "base-sepolia"
|
|
751
|
-
};
|
|
752
|
-
var GNOSIS_TOKENS = {
|
|
753
|
-
"0x0000000000000000000000000000000000000000": { symbol: "xDAI", decimals: 18 },
|
|
754
|
-
"0xcb444e90d8198415266c6a2724b7900fb12fc56e": { symbol: "EURe", decimals: 18 },
|
|
755
|
-
"0x2a22f9c3b484c3629090feed35f17ff8f88f76f0": { symbol: "USDC.e", decimals: 6 }
|
|
756
|
-
};
|
|
757
|
-
var BASE_TOKENS = {
|
|
758
|
-
"0x0000000000000000000000000000000000000000": { symbol: "ETH", decimals: 18 },
|
|
759
|
-
"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": { symbol: "USDC", decimals: 6 }
|
|
760
|
-
};
|
|
761
|
-
var BASE_SEPOLIA_TOKENS = {
|
|
762
|
-
"0x0000000000000000000000000000000000000000": { symbol: "ETH", decimals: 18 },
|
|
763
|
-
"0x036cbd53842c5426634e7929541ec2318f3dcf7e": { symbol: "USDC", decimals: 6 }
|
|
764
|
-
};
|
|
765
|
-
var ALL_TOKENS = {
|
|
766
|
-
...GNOSIS_TOKENS,
|
|
767
|
-
...BASE_TOKENS,
|
|
768
|
-
...BASE_SEPOLIA_TOKENS
|
|
769
|
-
};
|
|
770
|
-
var NETWORK_TOKENS = {
|
|
771
|
-
"eip155:100": GNOSIS_TOKENS,
|
|
772
|
-
"eip155:8453": BASE_TOKENS,
|
|
773
|
-
"base": BASE_TOKENS,
|
|
774
|
-
"eip155:84532": BASE_SEPOLIA_TOKENS,
|
|
775
|
-
"base-sepolia": BASE_SEPOLIA_TOKENS
|
|
776
|
-
};
|
|
777
|
-
var X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
|
|
778
|
-
var X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
|
|
779
|
-
var X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
|
|
780
|
-
var X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
|
|
781
|
-
var X402_PAYMENT_HEADER_NAMES_SENT = `${X402_PAYMENT_HEADER_NAME}, ${X402_LEGACY_PAYMENT_HEADER_NAME}`;
|
|
782
|
-
var X402_PAYMENT_HEADER_NAMES = [
|
|
783
|
-
X402_PAYMENT_HEADER_NAME,
|
|
784
|
-
X402_LEGACY_PAYMENT_HEADER_NAME
|
|
785
|
-
];
|
|
786
|
-
function x402PaymentHeaderNamesFor(paymentHeader) {
|
|
787
|
-
const both = [X402_PAYMENT_HEADER_NAME, X402_LEGACY_PAYMENT_HEADER_NAME];
|
|
788
|
-
let decoded;
|
|
789
|
-
try {
|
|
790
|
-
decoded = decodeBase64Json(paymentHeader);
|
|
791
|
-
} catch {
|
|
792
|
-
return both;
|
|
793
|
-
}
|
|
794
|
-
const accepted = decoded?.accepted;
|
|
795
|
-
if (!accepted || typeof accepted !== "object" || Array.isArray(accepted)) return both;
|
|
796
|
-
return isErc7710Option(accepted) ? [X402_PAYMENT_HEADER_NAME] : both;
|
|
797
|
-
}
|
|
798
|
-
function x402PaymentHeaderNamesSent(paymentHeader) {
|
|
799
|
-
return x402PaymentHeaderNamesFor(paymentHeader).join(", ");
|
|
800
|
-
}
|
|
801
|
-
function x402V2PaymentEnvelope(paymentRequired, accepted, payload) {
|
|
802
|
-
const resource = paymentRequired.resource;
|
|
803
|
-
const extensions = paymentRequired.extensions;
|
|
804
|
-
return {
|
|
805
|
-
x402Version: paymentRequired.x402Version,
|
|
806
|
-
...resource && typeof resource === "object" && !Array.isArray(resource) ? { resource } : {},
|
|
807
|
-
accepted,
|
|
808
|
-
payload,
|
|
809
|
-
...extensions && typeof extensions === "object" && !Array.isArray(extensions) ? { extensions } : {}
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function parsePaymentRequired(response) {
|
|
813
|
-
const v2Header = response.headers.get("PAYMENT-REQUIRED");
|
|
814
|
-
if (v2Header) {
|
|
815
|
-
const parsed = normalizePaymentRequired(
|
|
816
|
-
decodeBase64Json(v2Header, "PAYMENT-REQUIRED header")
|
|
817
|
-
);
|
|
818
|
-
if (parsed) return parsed;
|
|
819
|
-
}
|
|
820
|
-
const v1Header = response.headers.get("X-PAYMENT");
|
|
821
|
-
if (v1Header) {
|
|
822
|
-
const parsed = normalizePaymentRequired(
|
|
823
|
-
decodeBase64Json(v1Header, "X-PAYMENT header")
|
|
824
|
-
);
|
|
825
|
-
if (parsed) return parsed;
|
|
826
|
-
}
|
|
827
|
-
throw new Error(
|
|
828
|
-
"No x402 payment headers found in 402 response. Expected PAYMENT-REQUIRED (v2) or X-PAYMENT (v1) header."
|
|
829
|
-
);
|
|
830
|
-
}
|
|
831
|
-
async function parsePaymentRequiredResponse(response) {
|
|
832
|
-
try {
|
|
833
|
-
return parsePaymentRequired(response);
|
|
834
|
-
} catch (headerErr) {
|
|
835
|
-
try {
|
|
836
|
-
const body = await response.clone().json();
|
|
837
|
-
const parsed = normalizePaymentRequired(body);
|
|
838
|
-
if (parsed) return parsed;
|
|
839
|
-
} catch {
|
|
840
|
-
}
|
|
841
|
-
throw headerErr;
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
function selectPaymentOption(accepts) {
|
|
845
|
-
if (!accepts || accepts.length === 0) return null;
|
|
846
|
-
for (const opt of accepts) {
|
|
847
|
-
if (opt.network in SUPPORTED_X402_NETWORKS) {
|
|
848
|
-
const networkTokens = NETWORK_TOKENS[opt.network];
|
|
849
|
-
if (networkTokens?.[opt.asset.toLowerCase()] && isPositiveDecimalAtomicAmount(optionAuthorizationAmount(opt))) {
|
|
850
|
-
return opt;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
for (const opt of accepts) {
|
|
855
|
-
if (opt.network in SUPPORTED_X402_NETWORKS && isPositiveDecimalAtomicAmount(optionAuthorizationAmount(opt))) {
|
|
856
|
-
return opt;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
return null;
|
|
860
|
-
}
|
|
861
|
-
var ERC7710_ASSET_TRANSFER_METHOD = "erc7710";
|
|
862
|
-
function x402AssetTransferMethod(option) {
|
|
863
|
-
const raw = option.extra?.assetTransferMethod;
|
|
864
|
-
return typeof raw === "string" ? raw : null;
|
|
865
|
-
}
|
|
866
|
-
function isErc7710Option(option) {
|
|
867
|
-
return x402AssetTransferMethod(option) === ERC7710_ASSET_TRANSFER_METHOD;
|
|
868
|
-
}
|
|
869
|
-
function x402FacilitatorAddresses(option) {
|
|
870
|
-
const raw = option.extra?.facilitatorAddresses;
|
|
871
|
-
if (!Array.isArray(raw)) return null;
|
|
872
|
-
const addresses = raw.filter((a) => typeof a === "string" && ADDRESS_RE.test(a));
|
|
873
|
-
return addresses.length > 0 ? addresses : null;
|
|
874
|
-
}
|
|
875
|
-
function isPayableStandardOption(opt) {
|
|
876
|
-
return opt.scheme === "exact" && opt.network in STANDARD_X402_NETWORKS && STANDARD_X402_USDC_ADDRESSES.has(opt.asset.toLowerCase()) && isPositiveDecimalAtomicAmount(optionAuthorizationAmount(opt));
|
|
877
|
-
}
|
|
878
|
-
function selectStandardPaymentOption(accepts) {
|
|
879
|
-
if (!accepts || accepts.length === 0) return null;
|
|
880
|
-
for (const opt of accepts) {
|
|
881
|
-
if (opt === null || typeof opt !== "object") continue;
|
|
882
|
-
if (!isErc7710Option(opt) && isPayableStandardOption(opt)) return opt;
|
|
883
|
-
}
|
|
884
|
-
return null;
|
|
885
|
-
}
|
|
886
|
-
function selectErc7710PaymentOption(accepts) {
|
|
887
|
-
if (!accepts || accepts.length === 0) return null;
|
|
888
|
-
for (const opt of accepts) {
|
|
889
|
-
if (opt === null || typeof opt !== "object") continue;
|
|
890
|
-
if (isErc7710Option(opt) && isPayableStandardOption(opt)) return opt;
|
|
891
|
-
}
|
|
892
|
-
return null;
|
|
893
|
-
}
|
|
894
|
-
function selectX402SettlementScheme(accepts, opts) {
|
|
895
|
-
if (opts.delegationRail) {
|
|
896
|
-
const preferred = selectErc7710PaymentOption(accepts);
|
|
897
|
-
if (preferred) {
|
|
898
|
-
return {
|
|
899
|
-
scheme: "erc7710",
|
|
900
|
-
option: preferred,
|
|
901
|
-
facilitatorAddresses: x402FacilitatorAddresses(preferred)
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
const fallback = selectStandardPaymentOption(accepts);
|
|
906
|
-
if (fallback) return { scheme: "eip3009", option: fallback, facilitatorAddresses: null };
|
|
907
|
-
return null;
|
|
908
|
-
}
|
|
909
|
-
function x402AuthorizationAmount(option) {
|
|
910
|
-
const amount = optionAuthorizationAmount(option);
|
|
911
|
-
if (!isPositiveDecimalAtomicAmount(amount)) {
|
|
912
|
-
throw new Error("Invalid x402 amount: must be a positive decimal atomic amount");
|
|
913
|
-
}
|
|
914
|
-
return amount;
|
|
915
|
-
}
|
|
916
|
-
function buildX402ExpectedMessage(context) {
|
|
917
|
-
const version = context.payerDelegate ? 3 : context.typedDataHash ? 2 : 1;
|
|
918
|
-
const payload = {
|
|
919
|
-
version,
|
|
920
|
-
kind: "haven.x402.expected",
|
|
921
|
-
paymentId: context.paymentId,
|
|
922
|
-
payloadHash: context.payloadHash.toLowerCase(),
|
|
923
|
-
resourceUrl: context.resourceUrl,
|
|
924
|
-
merchantTo: context.merchantTo.toLowerCase(),
|
|
925
|
-
amount: context.amount,
|
|
926
|
-
asset: context.asset.toLowerCase(),
|
|
927
|
-
network: context.network
|
|
928
|
-
};
|
|
929
|
-
if (context.expiresAt) {
|
|
930
|
-
payload.expiresAt = context.expiresAt;
|
|
931
|
-
}
|
|
932
|
-
if (context.typedDataHash) {
|
|
933
|
-
payload.typedDataHash = context.typedDataHash.toLowerCase();
|
|
934
|
-
}
|
|
935
|
-
if (context.payerDelegate) {
|
|
936
|
-
payload.payerDelegate = context.payerDelegate.toLowerCase();
|
|
937
|
-
if (context.payerAgentId) {
|
|
938
|
-
payload.payerAgentId = context.payerAgentId;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
return `Haven x402 expected context v${version}
|
|
942
|
-
${stableStringify2(payload)}`;
|
|
943
|
-
}
|
|
944
|
-
function toStandardPaymentRequirements(paymentRequired, option) {
|
|
945
|
-
const network = STANDARD_X402_NETWORKS[option.network];
|
|
946
|
-
if (!network) {
|
|
947
|
-
throw new Error(`x402 exact payments are not supported on ${option.network}`);
|
|
948
|
-
}
|
|
949
|
-
if (option.scheme !== "exact") {
|
|
950
|
-
throw new Error(`Unsupported x402 scheme: ${option.scheme}`);
|
|
951
|
-
}
|
|
952
|
-
return {
|
|
953
|
-
scheme: "exact",
|
|
954
|
-
network,
|
|
955
|
-
maxAmountRequired: x402AuthorizationAmount(option),
|
|
956
|
-
resource: option.resource ?? paymentRequired.resource.url,
|
|
957
|
-
description: option.description ?? paymentRequired.resource.description ?? "Haven x402 payment",
|
|
958
|
-
mimeType: option.mimeType ?? paymentRequired.resource.mimeType ?? "application/octet-stream",
|
|
959
|
-
payTo: option.payTo,
|
|
960
|
-
asset: option.asset,
|
|
961
|
-
// Second enforcement point (#715): the parse path clamps too, but this is
|
|
962
|
-
// the last stop before the x402 library turns the timeout into
|
|
963
|
-
// `validBefore` — options constructed without parsing are bounded here.
|
|
964
|
-
// The forward margin (#1256) is added ONLY here, at signing: the parse
|
|
965
|
-
// path keeps recording the merchant's advertised timeout unchanged, and
|
|
966
|
-
// the library's `validBefore = now + this value` then carries enough
|
|
967
|
-
// slack to satisfy the facilitator's `validBefore ≥ now + maxTimeout`
|
|
968
|
-
// verify rule after our funding leg confirms.
|
|
969
|
-
maxTimeoutSeconds: clampAuthorizationWindow(option.maxTimeoutSeconds) + X402_SETTLEMENT_FORWARD_MARGIN_SECONDS,
|
|
970
|
-
extra: option.extra
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
async function validateStandardX402PaymentHeader(paymentHeader, context) {
|
|
974
|
-
try {
|
|
975
|
-
if (typeof paymentHeader !== "string" || paymentHeader.length === 0 || paymentHeader.length > X402_PAYMENT_HEADER_MAX_LENGTH || paymentHeader.length % 4 !== 0 || !BASE64_RE.test(paymentHeader)) {
|
|
976
|
-
throw new Error("wire");
|
|
977
|
-
}
|
|
978
|
-
const decoded = decodeBase64Json(paymentHeader);
|
|
979
|
-
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) throw new Error("shape");
|
|
980
|
-
const version = decoded.x402Version;
|
|
981
|
-
const payload = decoded.payload;
|
|
982
|
-
if (version !== 1 && version !== 2 || !payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
983
|
-
throw new Error("shape");
|
|
984
|
-
}
|
|
985
|
-
if (version === 1) {
|
|
986
|
-
if (!hasOnlyKeys(decoded, ["x402Version", "scheme", "network", "payload"])) throw new Error("shape");
|
|
987
|
-
if (decoded.scheme !== "exact" || decoded.network !== standardX402WireNetwork(context.network)) {
|
|
988
|
-
throw new Error("context");
|
|
989
|
-
}
|
|
990
|
-
} else {
|
|
991
|
-
if (!hasOnlyKeys(decoded, ["x402Version", "accepted", "payload"], ["resource", "extensions"])) {
|
|
992
|
-
throw new Error("shape");
|
|
993
|
-
}
|
|
994
|
-
if ("resource" in decoded && (!decoded.resource || typeof decoded.resource !== "object" || Array.isArray(decoded.resource))) {
|
|
995
|
-
throw new Error("shape");
|
|
996
|
-
}
|
|
997
|
-
if ("extensions" in decoded && (!decoded.extensions || typeof decoded.extensions !== "object" || Array.isArray(decoded.extensions))) {
|
|
998
|
-
throw new Error("shape");
|
|
999
|
-
}
|
|
1000
|
-
const accepted = selectStandardPaymentOption([decoded.accepted]);
|
|
1001
|
-
if (!accepted || !matchesHeaderContext(accepted, context)) throw new Error("context");
|
|
1002
|
-
}
|
|
1003
|
-
const record = payload;
|
|
1004
|
-
if (!hasOnlyKeys(record, ["signature", "authorization"])) throw new Error("shape");
|
|
1005
|
-
if (typeof record.signature !== "string" || !SIGNATURE_RE.test(record.signature)) throw new Error("shape");
|
|
1006
|
-
const authorization = record.authorization;
|
|
1007
|
-
if (!authorization || typeof authorization !== "object" || Array.isArray(authorization)) throw new Error("shape");
|
|
1008
|
-
const auth = authorization;
|
|
1009
|
-
if (!hasOnlyKeys(auth, ["from", "to", "value", "validAfter", "validBefore", "nonce"])) throw new Error("shape");
|
|
1010
|
-
if (typeof auth.from !== "string" || !ADDRESS_RE.test(auth.from) || typeof auth.to !== "string" || !ADDRESS_RE.test(auth.to) || typeof auth.value !== "string" || !isPositiveDecimalAtomicAmount(auth.value) || typeof auth.validAfter !== "string" || !DECIMAL_ATOMIC_AMOUNT_RE.test(auth.validAfter) || typeof auth.validBefore !== "string" || !DECIMAL_ATOMIC_AMOUNT_RE.test(auth.validBefore) || typeof auth.nonce !== "string" || !NONCE_RE.test(auth.nonce)) {
|
|
1011
|
-
throw new Error("shape");
|
|
1012
|
-
}
|
|
1013
|
-
if (!sameAddress2(auth.from, context.payer) || !sameAddress2(auth.to, context.merchantTo) || auth.value !== context.amountAtomic) {
|
|
1014
|
-
throw new Error("context");
|
|
1015
|
-
}
|
|
1016
|
-
const validAfter = BigInt(auth.validAfter);
|
|
1017
|
-
const validBefore = BigInt(auth.validBefore);
|
|
1018
|
-
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1019
|
-
if (validBefore <= now || validAfter > validBefore) throw new Error("expired");
|
|
1020
|
-
const typedData = buildSweepTypedData({
|
|
1021
|
-
from: auth.from,
|
|
1022
|
-
to: auth.to,
|
|
1023
|
-
value: auth.value,
|
|
1024
|
-
validAfter: auth.validAfter,
|
|
1025
|
-
validBefore: auth.validBefore,
|
|
1026
|
-
nonce: auth.nonce,
|
|
1027
|
-
token: context.asset,
|
|
1028
|
-
chainId: context.chainId
|
|
1029
|
-
});
|
|
1030
|
-
const recovered = await viem.recoverTypedDataAddress({
|
|
1031
|
-
...typedData,
|
|
1032
|
-
// `buildSweepTypedData` keeps the public domain framework-neutral;
|
|
1033
|
-
// viem brands contract addresses at this crypto call boundary only.
|
|
1034
|
-
domain: {
|
|
1035
|
-
...typedData.domain,
|
|
1036
|
-
verifyingContract: typedData.domain.verifyingContract
|
|
1037
|
-
},
|
|
1038
|
-
message: {
|
|
1039
|
-
...typedData.message,
|
|
1040
|
-
from: typedData.message.from,
|
|
1041
|
-
to: typedData.message.to,
|
|
1042
|
-
nonce: typedData.message.nonce
|
|
1043
|
-
},
|
|
1044
|
-
signature: record.signature
|
|
1045
|
-
});
|
|
1046
|
-
if (!sameAddress2(recovered, context.payer)) throw new Error("recovery");
|
|
1047
|
-
} catch {
|
|
1048
|
-
throw new X402PaymentHeaderValidationError();
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
function hasOnlyKeys(value, required, optional = []) {
|
|
1052
|
-
return Object.keys(value).every((key) => required.includes(key) || optional.includes(key)) && required.every((key) => key in value);
|
|
1053
|
-
}
|
|
1054
|
-
function sameAddress2(left, right) {
|
|
1055
|
-
return left.toLowerCase() === right.toLowerCase();
|
|
1056
|
-
}
|
|
1057
|
-
function standardX402WireNetwork(network) {
|
|
1058
|
-
return STANDARD_X402_NETWORKS[network] ?? null;
|
|
1059
|
-
}
|
|
1060
|
-
function matchesHeaderContext(option, context) {
|
|
1061
|
-
if (option.scheme !== "exact" || !sameAddress2(option.payTo, context.merchantTo) || !sameAddress2(option.asset, context.asset) || option.network !== context.network || x402AuthorizationAmount(option) !== context.amountAtomic) return false;
|
|
1062
|
-
return option.resource === void 0 || option.resource === context.resourceUrl;
|
|
1063
|
-
}
|
|
1064
|
-
function buildX402IdempotencyKey(paymentRequired, option, now = Date.now()) {
|
|
1065
|
-
const bucket = Math.floor(now / X402_IDEMPOTENCY_BUCKET_MS);
|
|
1066
|
-
const material = [
|
|
1067
|
-
paymentRequired.resource.url,
|
|
1068
|
-
paymentRequired.resource.description ?? "",
|
|
1069
|
-
option.payTo.toLowerCase(),
|
|
1070
|
-
option.asset.toLowerCase(),
|
|
1071
|
-
x402AuthorizationAmount(option),
|
|
1072
|
-
option.network,
|
|
1073
|
-
bucket
|
|
1074
|
-
].join("|");
|
|
1075
|
-
return `x402:${crypto.createHash("sha256").update(material).digest("hex").slice(0, 16)}`;
|
|
1076
|
-
}
|
|
1077
|
-
function encodePaymentProof(receipt) {
|
|
1078
|
-
const payload = {
|
|
1079
|
-
x402Version: 2,
|
|
1080
|
-
resource: receipt.resourceUrl ? { url: receipt.resourceUrl } : void 0,
|
|
1081
|
-
accepted: receipt.accepted,
|
|
1082
|
-
payload: {
|
|
1083
|
-
type: "haven_tx_hash",
|
|
1084
|
-
txHash: receipt.txHash,
|
|
1085
|
-
paymentId: receipt.paymentId,
|
|
1086
|
-
settledVia: "haven",
|
|
1087
|
-
payer: receipt.payer,
|
|
1088
|
-
chainId: receipt.chainId
|
|
1089
|
-
}
|
|
1090
|
-
};
|
|
1091
|
-
return encodeBase64Json(payload);
|
|
1092
|
-
}
|
|
1093
|
-
function resolveTokenFromAddress(address, network) {
|
|
1094
|
-
const lower = address.toLowerCase();
|
|
1095
|
-
if (network && network in NETWORK_TOKENS) {
|
|
1096
|
-
return NETWORK_TOKENS[network][lower] ?? null;
|
|
1097
|
-
}
|
|
1098
|
-
return ALL_TOKENS[lower] ?? null;
|
|
1099
|
-
}
|
|
1100
|
-
function stableStringify2(value) {
|
|
1101
|
-
if (value === null || typeof value !== "object") {
|
|
1102
|
-
const primitive = JSON.stringify(value);
|
|
1103
|
-
return primitive === void 0 ? "undefined" : primitive;
|
|
1104
|
-
}
|
|
1105
|
-
if (value instanceof Date) return JSON.stringify(value.toISOString());
|
|
1106
|
-
if (Array.isArray(value)) return `[${value.map((item) => stableStringify2(item)).join(",")}]`;
|
|
1107
|
-
const object = value;
|
|
1108
|
-
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify2(object[key])}`).join(",")}}`;
|
|
1109
|
-
}
|
|
1110
61
|
var DEFAULT_BASE_URL = "http://localhost:3001";
|
|
1111
62
|
var DEFAULT_REQUEST_TIMEOUT = 3e4;
|
|
63
|
+
function withoutClientHeader(headers) {
|
|
64
|
+
const target = chunkQSSVOPWA_cjs.HAVEN_CLIENT_HEADER.toLowerCase();
|
|
65
|
+
return Object.fromEntries(Object.entries(headers).filter(([name]) => name.toLowerCase() !== target));
|
|
66
|
+
}
|
|
1112
67
|
var HavenApiTransport = class {
|
|
1113
68
|
apiKey;
|
|
1114
69
|
baseUrl;
|
|
1115
70
|
requestTimeout;
|
|
1116
71
|
defaultHeaders;
|
|
72
|
+
clientIdentity;
|
|
1117
73
|
requestContext = new async_hooks.AsyncLocalStorage();
|
|
74
|
+
lastClientUpdate;
|
|
1118
75
|
constructor(config) {
|
|
1119
76
|
this.apiKey = config.apiKey;
|
|
1120
77
|
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
1121
78
|
this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
|
|
1122
79
|
this.defaultHeaders = { ...config.defaultHeaders ?? {} };
|
|
80
|
+
this.clientIdentity = config.clientIdentity ?? chunkQSSVOPWA_cjs.SDK_CLIENT_IDENTITY;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The newest `client_update` the backend sent (#3303): inside a
|
|
84
|
+
* `withRequestContext` dispatch, the one that dispatch's own requests
|
|
85
|
+
* received; outside one, the latest this transport has seen.
|
|
86
|
+
*/
|
|
87
|
+
clientUpdate() {
|
|
88
|
+
const store = this.requestContext.getStore();
|
|
89
|
+
return store ? store.clientUpdate : this.lastClientUpdate;
|
|
90
|
+
}
|
|
91
|
+
recordClientUpdate(data) {
|
|
92
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) return;
|
|
93
|
+
const hint = chunkQSSVOPWA_cjs.readClientUpdate(data.client_update);
|
|
94
|
+
if (!hint) return;
|
|
95
|
+
this.lastClientUpdate = hint;
|
|
96
|
+
const store = this.requestContext.getStore();
|
|
97
|
+
if (store) store.clientUpdate = hint;
|
|
1123
98
|
}
|
|
1124
99
|
/** Run `fn` with extra headers scoped to its asynchronous Haven API work. */
|
|
1125
100
|
withRequestContext(headers, fn) {
|
|
@@ -1142,28 +117,34 @@ var HavenApiTransport = class {
|
|
|
1142
117
|
headers: {
|
|
1143
118
|
"Content-Type": "application/json",
|
|
1144
119
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
1145
|
-
...this.defaultHeaders,
|
|
1146
|
-
...contextHeaders
|
|
120
|
+
...withoutClientHeader(this.defaultHeaders),
|
|
121
|
+
...withoutClientHeader(contextHeaders),
|
|
122
|
+
// Last, and any other spelling of it dropped above (fetch would
|
|
123
|
+
// JOIN `x-haven-client` and `X-Haven-Client` into one unparseable
|
|
124
|
+
// value), so neither `defaultHeaders` nor a dispatch context can
|
|
125
|
+
// misname the client; `clientIdentity` is the one way to set it.
|
|
126
|
+
[chunkQSSVOPWA_cjs.HAVEN_CLIENT_HEADER]: this.clientIdentity
|
|
1147
127
|
},
|
|
1148
128
|
body: body ? JSON.stringify(body) : void 0,
|
|
1149
129
|
signal: controller.signal
|
|
1150
130
|
});
|
|
1151
131
|
const data = await res.json();
|
|
132
|
+
this.recordClientUpdate(data);
|
|
1152
133
|
if (!res.ok) {
|
|
1153
134
|
const record = data;
|
|
1154
135
|
const errorText = typeof record.error === "string" ? record.error : void 0;
|
|
1155
136
|
const rawDetails = record.details ?? record.detail;
|
|
1156
137
|
const detailsText = typeof rawDetails === "string" ? rawDetails : rawDetails != null ? JSON.stringify(rawDetails) : void 0;
|
|
1157
138
|
const message = errorText && detailsText ? `${errorText}: ${detailsText}` : errorText ?? detailsText ?? "API request failed";
|
|
1158
|
-
throw new HavenApiError(message, res.status, data);
|
|
139
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(message, res.status, data);
|
|
1159
140
|
}
|
|
1160
141
|
return data;
|
|
1161
142
|
} catch (err) {
|
|
1162
|
-
if (err instanceof HavenApiError) throw err;
|
|
143
|
+
if (err instanceof chunkJKUIE45B_cjs.HavenApiError) throw err;
|
|
1163
144
|
if (err instanceof Error && err.name === "AbortError") {
|
|
1164
|
-
throw new HavenApiError(`Request to ${path} timed out`, 408);
|
|
145
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(`Request to ${path} timed out`, 408);
|
|
1165
146
|
}
|
|
1166
|
-
throw new HavenApiError(
|
|
147
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
1167
148
|
`Request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1168
149
|
0
|
|
1169
150
|
);
|
|
@@ -1250,13 +231,17 @@ function mapPaymentReceipt(raw) {
|
|
|
1250
231
|
const receipt = {
|
|
1251
232
|
id: raw.id,
|
|
1252
233
|
paymentId: raw.payment_id,
|
|
234
|
+
source: raw.rail,
|
|
1253
235
|
rail: raw.rail,
|
|
236
|
+
paymentProofStatus: raw.proof_status,
|
|
1254
237
|
proofStatus: raw.proof_status,
|
|
1255
238
|
txHash: raw.tx_hash,
|
|
1256
239
|
fundingTxHash: raw.funding_tx_hash ?? null,
|
|
1257
240
|
settlementTxHash: raw.settlement_tx_hash ?? null,
|
|
1258
241
|
chainId: raw.chain_id,
|
|
242
|
+
x402ResourceUrl: raw.resource_url,
|
|
1259
243
|
resourceUrl: raw.resource_url,
|
|
244
|
+
x402MerchantAddress: raw.merchant_address,
|
|
1260
245
|
merchantAddress: raw.merchant_address,
|
|
1261
246
|
payerAddress: raw.payer_address,
|
|
1262
247
|
parties: mapParties(raw.parties),
|
|
@@ -1280,6 +265,9 @@ function mapPaymentReceipt(raw) {
|
|
|
1280
265
|
if ("payment_intent_id" in raw) {
|
|
1281
266
|
receipt.paymentIntentId = raw.payment_intent_id ?? null;
|
|
1282
267
|
}
|
|
268
|
+
if (raw.scope) {
|
|
269
|
+
receipt.scope = { source: raw.scope.source, filter: raw.scope.filter };
|
|
270
|
+
}
|
|
1283
271
|
if ("approval_request_id" in raw) {
|
|
1284
272
|
receipt.approvalRequestId = raw.approval_request_id ?? null;
|
|
1285
273
|
}
|
|
@@ -1303,29 +291,29 @@ function paymentStateStatusCode(status, fallback = 502) {
|
|
|
1303
291
|
return PAYMENT_STATE_STATUS_CODES[status] ?? fallback;
|
|
1304
292
|
}
|
|
1305
293
|
function phaseForStatus(status) {
|
|
1306
|
-
if (status === "pending_signature") return AgentPaymentPhase.AgentSignatureRequired;
|
|
1307
|
-
if (status === "submitted") return AgentPaymentPhase.PaymentSubmitted;
|
|
1308
|
-
if (status === "confirmed") return AgentPaymentPhase.PaymentConfirmed;
|
|
1309
|
-
if (status === "pending" || status === "pending_approval") return AgentPaymentPhase.UserApprovalRequired;
|
|
1310
|
-
if (status === "approved") return AgentPaymentPhase.UserExecutionRequired;
|
|
1311
|
-
if (status === "proposed") return AgentPaymentPhase.WaitingForAdditionalApprovals;
|
|
1312
|
-
if (status === "executed") return AgentPaymentPhase.FundingSent;
|
|
1313
|
-
if (status === "rejected") return AgentPaymentPhase.Rejected;
|
|
1314
|
-
if (status === "expired") return AgentPaymentPhase.Expired;
|
|
1315
|
-
if (status === "failed") return AgentPaymentPhase.Failed;
|
|
294
|
+
if (status === "pending_signature") return chunkJKUIE45B_cjs.AgentPaymentPhase.AgentSignatureRequired;
|
|
295
|
+
if (status === "submitted") return chunkJKUIE45B_cjs.AgentPaymentPhase.PaymentSubmitted;
|
|
296
|
+
if (status === "confirmed") return chunkJKUIE45B_cjs.AgentPaymentPhase.PaymentConfirmed;
|
|
297
|
+
if (status === "pending" || status === "pending_approval") return chunkJKUIE45B_cjs.AgentPaymentPhase.UserApprovalRequired;
|
|
298
|
+
if (status === "approved") return chunkJKUIE45B_cjs.AgentPaymentPhase.UserExecutionRequired;
|
|
299
|
+
if (status === "proposed") return chunkJKUIE45B_cjs.AgentPaymentPhase.WaitingForAdditionalApprovals;
|
|
300
|
+
if (status === "executed") return chunkJKUIE45B_cjs.AgentPaymentPhase.FundingSent;
|
|
301
|
+
if (status === "rejected") return chunkJKUIE45B_cjs.AgentPaymentPhase.Rejected;
|
|
302
|
+
if (status === "expired") return chunkJKUIE45B_cjs.AgentPaymentPhase.Expired;
|
|
303
|
+
if (status === "failed") return chunkJKUIE45B_cjs.AgentPaymentPhase.Failed;
|
|
1316
304
|
return null;
|
|
1317
305
|
}
|
|
1318
306
|
function nextActionForStatus(status) {
|
|
1319
|
-
if (status === "pending_signature") return AgentPaymentNextAction.SignAndSubmitPayment;
|
|
1320
|
-
if (status === "submitted") return AgentPaymentNextAction.CheckStatusLater;
|
|
1321
|
-
if (status === "confirmed") return AgentPaymentNextAction.None;
|
|
1322
|
-
if (status === "pending" || status === "pending_approval") return AgentPaymentNextAction.StopAndTellUser;
|
|
1323
|
-
if (status === "approved") return AgentPaymentNextAction.StopAndTellUser;
|
|
1324
|
-
if (status === "proposed") return AgentPaymentNextAction.StopAndTellUser;
|
|
1325
|
-
if (status === "executed") return AgentPaymentNextAction.StopAndTellUser;
|
|
1326
|
-
if (status === "rejected") return AgentPaymentNextAction.StopAndTellUser;
|
|
1327
|
-
if (status === "expired") return AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
|
|
1328
|
-
if (status === "failed") return AgentPaymentNextAction.StopAndTellUser;
|
|
307
|
+
if (status === "pending_signature") return chunkJKUIE45B_cjs.AgentPaymentNextAction.SignAndSubmitPayment;
|
|
308
|
+
if (status === "submitted") return chunkJKUIE45B_cjs.AgentPaymentNextAction.CheckStatusLater;
|
|
309
|
+
if (status === "confirmed") return chunkJKUIE45B_cjs.AgentPaymentNextAction.None;
|
|
310
|
+
if (status === "pending" || status === "pending_approval") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
311
|
+
if (status === "approved") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
312
|
+
if (status === "proposed") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
313
|
+
if (status === "executed") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
314
|
+
if (status === "rejected") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
315
|
+
if (status === "expired") return chunkJKUIE45B_cjs.AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
|
|
316
|
+
if (status === "failed") return chunkJKUIE45B_cjs.AgentPaymentNextAction.StopAndTellUser;
|
|
1329
317
|
return null;
|
|
1330
318
|
}
|
|
1331
319
|
function messageForState(label, status, paymentId, nextAction) {
|
|
@@ -1399,17 +387,17 @@ function throwPaymentStateError(label, raw) {
|
|
|
1399
387
|
const statusCode = paymentStateStatusCode(raw.status);
|
|
1400
388
|
const state = paymentStateFromRaw(label, raw);
|
|
1401
389
|
if (state) {
|
|
1402
|
-
throw new HavenPaymentStateError(state.message, statusCode, state, raw);
|
|
390
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(state.message, statusCode, state, raw);
|
|
1403
391
|
}
|
|
1404
392
|
if (raw.status === "pending_approval") {
|
|
1405
|
-
throw new HavenApiError(
|
|
393
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
1406
394
|
`${label} exceeds the agent's on-chain budget and was declined; no approval is pending and none will arrive (payment_id: ${raw.payment_id}).`,
|
|
1407
395
|
statusCode,
|
|
1408
396
|
raw
|
|
1409
397
|
);
|
|
1410
398
|
}
|
|
1411
399
|
if (raw.status === "expired") {
|
|
1412
|
-
throw new HavenApiError(
|
|
400
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
1413
401
|
`${label} expired before it could be completed (payment_id: ${raw.payment_id}).`,
|
|
1414
402
|
statusCode,
|
|
1415
403
|
raw
|
|
@@ -1417,7 +405,52 @@ function throwPaymentStateError(label, raw) {
|
|
|
1417
405
|
}
|
|
1418
406
|
const paymentId = raw.payment_id ? ` (payment_id: ${raw.payment_id})` : "";
|
|
1419
407
|
const message = raw.error ?? `${label} ${raw.status}${paymentId}`;
|
|
1420
|
-
throw new HavenApiError(message, statusCode, raw);
|
|
408
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(message, statusCode, raw);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// src/x402-retry-target.ts
|
|
412
|
+
function resolveX402RetryTarget(input) {
|
|
413
|
+
const requestUrl = input.requestUrl?.trim() || void 0;
|
|
414
|
+
if (requestUrl) {
|
|
415
|
+
return {
|
|
416
|
+
url: requestUrl,
|
|
417
|
+
source: "request",
|
|
418
|
+
resourceUrlDiffersFromRequest: requestUrl !== input.resourceUrl
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
return { url: input.resourceUrl, source: "resource" };
|
|
422
|
+
}
|
|
423
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "::1", "[::1]"]);
|
|
424
|
+
var RESERVED_SUFFIXES = [".test", ".localhost", ".invalid", ".example"];
|
|
425
|
+
var IPV4_LOOPBACK = /^127(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/;
|
|
426
|
+
function isSecureX402RetryTarget(url) {
|
|
427
|
+
let parsed;
|
|
428
|
+
try {
|
|
429
|
+
parsed = new URL(url);
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
if (parsed.protocol === "https:") return true;
|
|
434
|
+
if (parsed.protocol !== "http:") return false;
|
|
435
|
+
const host = parsed.hostname.toLowerCase();
|
|
436
|
+
if (LOOPBACK_HOSTS.has(host) || IPV4_LOOPBACK.test(host)) return true;
|
|
437
|
+
return RESERVED_SUFFIXES.some((suffix) => host.endsWith(suffix));
|
|
438
|
+
}
|
|
439
|
+
var INSECURE_RETRY_TARGET_CODE = "INSECURE_RETRY_TARGET";
|
|
440
|
+
var HavenInsecureRetryTargetError = class extends chunkJKUIE45B_cjs.HavenError {
|
|
441
|
+
constructor(url) {
|
|
442
|
+
super(
|
|
443
|
+
`Refusing to send a payment header to ${url}: the paid x402 retry must go to an https URL (or a loopback / reserved test host). The merchant's challenge declared this resource URL; retry with the https URL you quoted (pass it as \`url\`), and report a merchant whose challenge downgrades the scheme.`,
|
|
444
|
+
INSECURE_RETRY_TARGET_CODE,
|
|
445
|
+
400
|
|
446
|
+
);
|
|
447
|
+
this.url = url;
|
|
448
|
+
this.name = "HavenInsecureRetryTargetError";
|
|
449
|
+
}
|
|
450
|
+
url;
|
|
451
|
+
};
|
|
452
|
+
function assertSecureX402RetryTarget(url) {
|
|
453
|
+
if (!isSecureX402RetryTarget(url)) throw new HavenInsecureRetryTargetError(url);
|
|
1421
454
|
}
|
|
1422
455
|
|
|
1423
456
|
// src/mcp-merchant-transport.ts
|
|
@@ -1426,6 +459,10 @@ var MCP_NOTIFICATION_TIMEOUT = 1e4;
|
|
|
1426
459
|
var MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
1427
460
|
var MCP_ACCEPT = "application/json, text/event-stream";
|
|
1428
461
|
var MCP_CLIENT_INFO = { name: "haven-sdk", version: "1" };
|
|
462
|
+
var MCP_X402_PAYMENT_META_KEY = "x402/payment";
|
|
463
|
+
var MCP_X402_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
|
|
464
|
+
var X402_RETRY_REJECTED_STATUS = 402;
|
|
465
|
+
var SESSION_NOT_FOUND_NEXT_ACTION = "reinitialize_then_retry_same_payment_header";
|
|
1429
466
|
var McpMerchantTransport = class {
|
|
1430
467
|
merchantTimeout;
|
|
1431
468
|
fetchImpl;
|
|
@@ -1442,7 +479,7 @@ var McpMerchantTransport = class {
|
|
|
1442
479
|
return await this.fetchImpl(url, { ...init, signal });
|
|
1443
480
|
} catch (err) {
|
|
1444
481
|
if (timeoutSignal.aborted) {
|
|
1445
|
-
throw new MerchantTimeoutError(`Merchant request timed out after ${timeoutMs}ms: ${url}`);
|
|
482
|
+
throw new chunkJKUIE45B_cjs.MerchantTimeoutError(`Merchant request timed out after ${timeoutMs}ms: ${url}`);
|
|
1446
483
|
}
|
|
1447
484
|
throw err;
|
|
1448
485
|
}
|
|
@@ -1521,7 +558,7 @@ var McpMerchantTransport = class {
|
|
|
1521
558
|
return response;
|
|
1522
559
|
}
|
|
1523
560
|
const message = selectJsonRpcResult(parseSseJsonRpcMessages(text));
|
|
1524
|
-
if (!message) return response;
|
|
561
|
+
if (!message || !("result" in message || "error" in message)) return response;
|
|
1525
562
|
const body = "result" in message ? message.result : message;
|
|
1526
563
|
const headers = new Headers(response.headers);
|
|
1527
564
|
headers.set("content-type", "application/json");
|
|
@@ -1577,13 +614,64 @@ var McpMerchantTransport = class {
|
|
|
1577
614
|
* overwrite, which is worse than the duplicate this change removes.
|
|
1578
615
|
*/
|
|
1579
616
|
async deliverPayment(url, init, paymentHeader) {
|
|
617
|
+
assertSecureX402RetryTarget(url);
|
|
1580
618
|
const headers = new Headers(init?.headers);
|
|
1581
|
-
const send = x402PaymentHeaderNamesFor(paymentHeader);
|
|
1582
|
-
for (const name of X402_PAYMENT_HEADER_NAMES) {
|
|
619
|
+
const send = chunkQSSVOPWA_cjs.x402PaymentHeaderNamesFor(paymentHeader);
|
|
620
|
+
for (const name of chunkQSSVOPWA_cjs.X402_PAYMENT_HEADER_NAMES) {
|
|
1583
621
|
if (send.includes(name)) headers.set(name, paymentHeader);
|
|
1584
622
|
else headers.delete(name);
|
|
1585
623
|
}
|
|
1586
|
-
return this.fetch(url, { ...init, headers });
|
|
624
|
+
return this.fetch(url, withMcpPaymentMeta({ ...init, headers }, paymentHeader));
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* #3171: deliver the payment; if the merchant answers its unknown-session
|
|
628
|
+
* 404 WITH the settled-nothing recovery data, re-initialize once and resend
|
|
629
|
+
* the SAME header on the new session. The merchant's own guarantee (#1578:
|
|
630
|
+
* the session guard runs before its payment gate) is what makes the resend
|
|
631
|
+
* safe — a bare -32001, or any other 404, is returned to the caller
|
|
632
|
+
* untouched (body re-wrapped, since reading it consumed the stream). One
|
|
633
|
+
* recovery only: a second 404 is the answer.
|
|
634
|
+
*/
|
|
635
|
+
async deliverPaymentRecoveringSession(url, init, paymentHeader, reinitialize) {
|
|
636
|
+
const first = await this.deliverPayment(url, init, paymentHeader);
|
|
637
|
+
if (first.status !== 404) return first;
|
|
638
|
+
let text;
|
|
639
|
+
try {
|
|
640
|
+
text = await first.clone().text();
|
|
641
|
+
} catch {
|
|
642
|
+
return first;
|
|
643
|
+
}
|
|
644
|
+
if (!sessionNotFoundRecovery(text)) return first;
|
|
645
|
+
const sessionId = await reinitialize();
|
|
646
|
+
if (!sessionId) return first;
|
|
647
|
+
return this.deliverPayment(url, this.withSessionHeaders(init, sessionId), paymentHeader);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* #3118: read a native MCP payment-required tool result from a response
|
|
651
|
+
* WITHOUT consuming it — JSON or SSE framed. `undefined` for anything that
|
|
652
|
+
* is not an `isError: true` tool result carrying a valid `PaymentRequired`
|
|
653
|
+
* (structured content first, text fallback second), so an ordinary tool
|
|
654
|
+
* error, a successful result that merely resembles a challenge, or an
|
|
655
|
+
* unparseable body is never mistaken for a payment demand.
|
|
656
|
+
*/
|
|
657
|
+
async extractToolResultChallenge(response, init) {
|
|
658
|
+
const toolResult = await this.readToolResult(response, init);
|
|
659
|
+
return toolResult ? extractMcpPaymentRequired(toolResult) : void 0;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* #3118: the tool RESULT a response carries, read WITHOUT consuming it, or
|
|
663
|
+
* `undefined`. Only a JSON or SSE body is read at all (#3155 review S2):
|
|
664
|
+
* a non-402 answer used to be returned untouched, and buffering an
|
|
665
|
+
* arbitrary body — a streaming or binary paid resource — to look for a
|
|
666
|
+
* challenge would block the caller until the stream ended or the merchant
|
|
667
|
+
* timeout fired. A merchant that speaks JSON-RPC declares one of those two
|
|
668
|
+
* content types.
|
|
669
|
+
*/
|
|
670
|
+
async readToolResult(response, init) {
|
|
671
|
+
if (init !== void 0 && !isJsonRpcToolsCallBody(init.body)) return void 0;
|
|
672
|
+
const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
|
|
673
|
+
if (!contentType.includes("application/json") && !contentType.includes("text/event-stream")) return void 0;
|
|
674
|
+
return mcpToolResultOf(await this.readMessage(response));
|
|
1587
675
|
}
|
|
1588
676
|
async notifyInitialized(url, init, sessionId, wallet) {
|
|
1589
677
|
try {
|
|
@@ -1605,6 +693,106 @@ var McpMerchantTransport = class {
|
|
|
1605
693
|
}
|
|
1606
694
|
}
|
|
1607
695
|
};
|
|
696
|
+
function mcpToolResultOf(value) {
|
|
697
|
+
if (!isRecord(value)) return void 0;
|
|
698
|
+
if ("jsonrpc" in value) {
|
|
699
|
+
return isRecord(value.result) ? value.result : void 0;
|
|
700
|
+
}
|
|
701
|
+
if ("isError" in value || Array.isArray(value.content) || isRecord(value._meta)) return value;
|
|
702
|
+
return void 0;
|
|
703
|
+
}
|
|
704
|
+
function extractMcpPaymentRequired(toolResult) {
|
|
705
|
+
if (toolResult.isError !== true) return void 0;
|
|
706
|
+
if (isRecord(toolResult.structuredContent)) {
|
|
707
|
+
const parsed = chunkQSSVOPWA_cjs.normalizePaymentRequired(toolResult.structuredContent);
|
|
708
|
+
if (parsed) return parsed;
|
|
709
|
+
}
|
|
710
|
+
if (Array.isArray(toolResult.content)) {
|
|
711
|
+
for (const item of toolResult.content) {
|
|
712
|
+
if (!isRecord(item) || item.type !== "text" || typeof item.text !== "string") continue;
|
|
713
|
+
let candidate;
|
|
714
|
+
try {
|
|
715
|
+
candidate = JSON.parse(item.text);
|
|
716
|
+
} catch {
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
const parsed = chunkQSSVOPWA_cjs.normalizePaymentRequired(candidate);
|
|
720
|
+
if (parsed) return parsed;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return void 0;
|
|
724
|
+
}
|
|
725
|
+
function mcpSettlementFromToolResult(toolResult) {
|
|
726
|
+
const meta = toolResult._meta;
|
|
727
|
+
if (!isRecord(meta)) return void 0;
|
|
728
|
+
const settlement = meta[MCP_X402_PAYMENT_RESPONSE_META_KEY];
|
|
729
|
+
if (!isRecord(settlement) || typeof settlement.success !== "boolean") return void 0;
|
|
730
|
+
return {
|
|
731
|
+
success: settlement.success,
|
|
732
|
+
...typeof settlement.transaction === "string" ? { transaction: settlement.transaction } : {},
|
|
733
|
+
...typeof settlement.network === "string" ? { network: settlement.network } : {},
|
|
734
|
+
...typeof settlement.payer === "string" ? { payer: settlement.payer } : {},
|
|
735
|
+
...typeof settlement.errorReason === "string" ? { errorReason: settlement.errorReason } : {}
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
function withMcpPaymentMeta(init, paymentHeader) {
|
|
739
|
+
const request = parseJsonRpcToolsCall(init.body);
|
|
740
|
+
if (!request) return init;
|
|
741
|
+
let envelope;
|
|
742
|
+
try {
|
|
743
|
+
envelope = chunkQSSVOPWA_cjs.decodeBase64Json(paymentHeader);
|
|
744
|
+
} catch {
|
|
745
|
+
return init;
|
|
746
|
+
}
|
|
747
|
+
if (!isRecord(envelope)) return init;
|
|
748
|
+
const params = request.params;
|
|
749
|
+
const existingMeta = isRecord(params._meta) ? params._meta : {};
|
|
750
|
+
return {
|
|
751
|
+
...init,
|
|
752
|
+
body: JSON.stringify({
|
|
753
|
+
...request,
|
|
754
|
+
params: { ...params, _meta: { ...existingMeta, [MCP_X402_PAYMENT_META_KEY]: envelope } }
|
|
755
|
+
})
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
function encodeMcpSettlementReceipt(settlement) {
|
|
759
|
+
return chunkQSSVOPWA_cjs.encodeBase64Json(settlement);
|
|
760
|
+
}
|
|
761
|
+
function parseJsonRpcToolsCall(body) {
|
|
762
|
+
if (typeof body !== "string") return void 0;
|
|
763
|
+
let request;
|
|
764
|
+
try {
|
|
765
|
+
request = JSON.parse(body);
|
|
766
|
+
} catch {
|
|
767
|
+
return void 0;
|
|
768
|
+
}
|
|
769
|
+
if (!isRecord(request) || request.method !== "tools/call" || !isRecord(request.params)) return void 0;
|
|
770
|
+
return request;
|
|
771
|
+
}
|
|
772
|
+
function isJsonRpcToolsCallBody(body) {
|
|
773
|
+
return parseJsonRpcToolsCall(body) !== void 0;
|
|
774
|
+
}
|
|
775
|
+
function sessionNotFoundRecovery(body) {
|
|
776
|
+
let parsed;
|
|
777
|
+
try {
|
|
778
|
+
parsed = JSON.parse(body);
|
|
779
|
+
} catch {
|
|
780
|
+
return void 0;
|
|
781
|
+
}
|
|
782
|
+
if (!isRecord(parsed) || !isRecord(parsed.error)) return void 0;
|
|
783
|
+
if (parsed.error.code !== -32001) return void 0;
|
|
784
|
+
const data = parsed.error.data;
|
|
785
|
+
if (!isRecord(data)) return void 0;
|
|
786
|
+
if (data.settled !== false || data.next_action !== SESSION_NOT_FOUND_NEXT_ACTION) return void 0;
|
|
787
|
+
return {
|
|
788
|
+
reason: typeof data.reason === "string" ? data.reason : "session_expired",
|
|
789
|
+
settled: false,
|
|
790
|
+
next_action: SESSION_NOT_FOUND_NEXT_ACTION
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function isRecord(value) {
|
|
794
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
795
|
+
}
|
|
1608
796
|
async function captureMerchantResponse(response) {
|
|
1609
797
|
const merchant_body = await response.text().catch(() => "");
|
|
1610
798
|
return {
|
|
@@ -1691,6 +879,10 @@ function deriveReadiness(status, allowances) {
|
|
|
1691
879
|
if (status !== "active") return "revoked";
|
|
1692
880
|
return allowances.some((allowance) => safeBigInt(allowance.remainingAtomic) > 0n) ? "ready" : "needs_approval";
|
|
1693
881
|
}
|
|
882
|
+
function formatRemainingDisplay(tokenAddress, tokenSymbol, remainingAtomic) {
|
|
883
|
+
const token = chunkQSSVOPWA_cjs.resolveTokenFromAddress(tokenAddress);
|
|
884
|
+
return token ? `${formatAtomicAmount(safeBigInt(remainingAtomic), token.decimals)} ${tokenSymbol}` : `${remainingAtomic} ${tokenSymbol} (atomic; unknown decimals)`;
|
|
885
|
+
}
|
|
1694
886
|
var AccountReads = class {
|
|
1695
887
|
transport;
|
|
1696
888
|
getPaymentStatus;
|
|
@@ -1712,12 +904,12 @@ var AccountReads = class {
|
|
|
1712
904
|
async getAgentSummary() {
|
|
1713
905
|
const [agent, allowanceSummary] = await Promise.all([this.getAgent(), this.getAllowances()]);
|
|
1714
906
|
const allowances = allowanceSummary.allowances.map((allowance) => {
|
|
1715
|
-
const token = resolveTokenFromAddress(allowance.tokenAddress);
|
|
1716
|
-
const remainingDisplay = token ? `${formatAtomicAmount(safeBigInt(allowance.onchain.remaining), token.decimals)} ${allowance.tokenSymbol}` : `${allowance.onchain.remaining} ${allowance.tokenSymbol} (atomic; unknown decimals)`;
|
|
1717
907
|
return {
|
|
908
|
+
id: allowance.id,
|
|
1718
909
|
tokenSymbol: allowance.tokenSymbol,
|
|
910
|
+
tokenAddress: allowance.tokenAddress,
|
|
1719
911
|
remainingAtomic: allowance.onchain.remaining,
|
|
1720
|
-
remainingDisplay,
|
|
912
|
+
remainingDisplay: allowance.remainingDisplay,
|
|
1721
913
|
configuredAmount: allowance.configuredAmount,
|
|
1722
914
|
resetPeriodMin: allowance.resetPeriodMin,
|
|
1723
915
|
isResetPending: allowance.onchain.isResetPending
|
|
@@ -1745,6 +937,7 @@ var AccountReads = class {
|
|
|
1745
937
|
tokenSymbol: allowance.token_symbol,
|
|
1746
938
|
configuredAmount: allowance.configured_amount,
|
|
1747
939
|
resetPeriodMin: allowance.reset_period_min,
|
|
940
|
+
remainingDisplay: formatRemainingDisplay(allowance.token_address, allowance.token_symbol, allowance.onchain.remaining),
|
|
1748
941
|
onchain: {
|
|
1749
942
|
amount: allowance.onchain.amount,
|
|
1750
943
|
spent: allowance.onchain.spent,
|
|
@@ -1759,12 +952,39 @@ var AccountReads = class {
|
|
|
1759
952
|
}))
|
|
1760
953
|
};
|
|
1761
954
|
}
|
|
955
|
+
/**
|
|
956
|
+
* #3126 — the sufficiency signal behind {@link HavenBalanceCoverage}.
|
|
957
|
+
*
|
|
958
|
+
* Deliberately NOT a balance read: the endpoint answers whether the
|
|
959
|
+
* account HOLDS at least the checked amount, as `covered
|
|
960
|
+
* true/false/null`, and never returns the balance itself. The camelCase
|
|
961
|
+
* mapping is permissive (raw fields flow through; the server owns the
|
|
962
|
+
* wire shape, pinned by the backend's `expectMatchesSpec` assertion), so
|
|
963
|
+
* an older server that has not deployed the endpoint surfaces its 404 as
|
|
964
|
+
* a thrown error rather than a fabricated answer.
|
|
965
|
+
*/
|
|
966
|
+
async checkFunds(input) {
|
|
967
|
+
const query = `token=${encodeURIComponent(input.token)}&amount_atomic=${encodeURIComponent(input.amountAtomic)}`;
|
|
968
|
+
const raw = await this.transport.get(
|
|
969
|
+
`/machine-payments/balance-coverage?${query}`
|
|
970
|
+
);
|
|
971
|
+
return {
|
|
972
|
+
covered: raw.covered,
|
|
973
|
+
...raw.coverage_error !== void 0 ? { coverageError: raw.coverage_error } : {},
|
|
974
|
+
chainId: raw.chain_id,
|
|
975
|
+
tokenAddress: raw.token_address,
|
|
976
|
+
tokenSymbol: raw.token_symbol,
|
|
977
|
+
checkedAmountAtomic: raw.checked_amount_atomic,
|
|
978
|
+
budgetRemainingAtomic: raw.budget_remaining_atomic,
|
|
979
|
+
...raw.budget_remaining_is_from_chain !== void 0 ? { budgetRemainingIsFromChain: raw.budget_remaining_is_from_chain } : {}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
1762
982
|
async getPostPurchaseAllowanceSummary(paymentId) {
|
|
1763
983
|
const unavailable = (detail, payment2 = null) => ({
|
|
1764
984
|
payment: payment2,
|
|
1765
985
|
allowance: null,
|
|
1766
986
|
warnings: [{
|
|
1767
|
-
code: AgentPaymentWarningCode.AllowanceCheckUnavailable,
|
|
987
|
+
code: chunkJKUIE45B_cjs.AgentPaymentWarningCode.AllowanceCheckUnavailable,
|
|
1768
988
|
message: `Could not read the post-purchase allowance/budget for payment ${paymentId} (${detail}). The payment itself succeeded \u2014 the on-chain policy remains the actual spend gate; this only affects the remaining-budget figure reported here.`
|
|
1769
989
|
}]
|
|
1770
990
|
});
|
|
@@ -1790,7 +1010,7 @@ var AccountReads = class {
|
|
|
1790
1010
|
(allowance) => allowance.tokenAddress.toLowerCase() === tokenAddress.toLowerCase()
|
|
1791
1011
|
);
|
|
1792
1012
|
if (!match) return unavailable("no allowance/budget row matches the settled token", payment);
|
|
1793
|
-
const token = resolveTokenFromAddress(match.tokenAddress);
|
|
1013
|
+
const token = chunkQSSVOPWA_cjs.resolveTokenFromAddress(match.tokenAddress);
|
|
1794
1014
|
const remainingDisplay = token ? `${formatAtomicAmount(safeBigInt(match.onchain.remaining), token.decimals)} ${match.tokenSymbol}` : void 0;
|
|
1795
1015
|
const rail = agentResult.value.executionRail;
|
|
1796
1016
|
return {
|
|
@@ -1810,10 +1030,23 @@ var AccountReads = class {
|
|
|
1810
1030
|
return unavailable(error instanceof Error ? error.message : String(error));
|
|
1811
1031
|
}
|
|
1812
1032
|
}
|
|
1033
|
+
/** The first page's receipts as a bare array — the pre-#3128 shape, kept for callers that never page. */
|
|
1813
1034
|
async listReceipts(options = {}) {
|
|
1814
|
-
|
|
1035
|
+
return (await this.listReceiptsPage(options)).receipts;
|
|
1036
|
+
}
|
|
1037
|
+
/** #3128: one page with `total`, `hasMore` and `nextCursor` — see {@link HavenPaymentReceiptsPage}. */
|
|
1038
|
+
async listReceiptsPage(options = {}) {
|
|
1039
|
+
const params = new URLSearchParams();
|
|
1040
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
1041
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
1042
|
+
const query = params.size > 0 ? `?${params.toString()}` : "";
|
|
1815
1043
|
const raw = await this.transport.get(`/machine-payments/receipts${query}`);
|
|
1816
|
-
return
|
|
1044
|
+
return {
|
|
1045
|
+
receipts: raw.receipts.map(mapPaymentReceipt),
|
|
1046
|
+
total: typeof raw.total === "number" ? raw.total : null,
|
|
1047
|
+
hasMore: typeof raw.has_more === "boolean" ? raw.has_more : null,
|
|
1048
|
+
nextCursor: typeof raw.next_cursor === "string" ? raw.next_cursor : null
|
|
1049
|
+
};
|
|
1817
1050
|
}
|
|
1818
1051
|
async getReceipt(paymentId) {
|
|
1819
1052
|
const { receipt } = await this.transport.get(`/payments/${paymentId}/receipt`);
|
|
@@ -1852,7 +1085,7 @@ function isWaitTimeout(err) {
|
|
|
1852
1085
|
async function waitForSweepTx(tx) {
|
|
1853
1086
|
let receipt;
|
|
1854
1087
|
try {
|
|
1855
|
-
receipt = await tx.wait(1, DEFAULT_CONFIRMATION_TIMEOUT_MS);
|
|
1088
|
+
receipt = await tx.wait(1, chunkJKUIE45B_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS);
|
|
1856
1089
|
} catch (err) {
|
|
1857
1090
|
if (!isWaitTimeout(err)) throw err;
|
|
1858
1091
|
return { txHash: tx.hash, confirmation: "unconfirmed" };
|
|
@@ -1866,16 +1099,16 @@ var DelegateSweepApi = class {
|
|
|
1866
1099
|
}
|
|
1867
1100
|
options;
|
|
1868
1101
|
async sweepDelegate() {
|
|
1869
|
-
if (!this.options.delegateKey) throw new HavenSigningError("delegateKey is required for sweepDelegate.");
|
|
1102
|
+
if (!this.options.delegateKey) throw new chunkJKUIE45B_cjs.HavenSigningError("delegateKey is required for sweepDelegate.");
|
|
1870
1103
|
const agent = await this.options.getAgent();
|
|
1871
|
-
if (!agent.delegateAddress) throw new HavenApiError("Agent has no delegate address.", 422);
|
|
1104
|
+
if (!agent.delegateAddress) throw new chunkJKUIE45B_cjs.HavenApiError("Agent has no delegate address.", 422);
|
|
1872
1105
|
const rpcUrl = this.options.chainRpcs[agent.chainId];
|
|
1873
|
-
if (!rpcUrl) throw new HavenApiError(`chainRpcs[${agent.chainId}] must be configured to sweep the delegate wallet.`, 422);
|
|
1106
|
+
if (!rpcUrl) throw new chunkJKUIE45B_cjs.HavenApiError(`chainRpcs[${agent.chainId}] must be configured to sweep the delegate wallet.`, 422);
|
|
1874
1107
|
const provider = createJsonRpcProvider(rpcUrl);
|
|
1875
1108
|
const wallet = createWallet(this.options.delegateKey, provider);
|
|
1876
1109
|
const transfers = [];
|
|
1877
|
-
if (isSweepableChain(agent.chainId)) {
|
|
1878
|
-
const contract = createErc20Contract(sweepUsdcAddress(agent.chainId), ["function balanceOf(address) view returns (uint256)", "function transfer(address to, uint256 amount) returns (bool)"], wallet);
|
|
1110
|
+
if (chunkQSSVOPWA_cjs.isSweepableChain(agent.chainId)) {
|
|
1111
|
+
const contract = createErc20Contract(chunkQSSVOPWA_cjs.sweepUsdcAddress(agent.chainId), ["function balanceOf(address) view returns (uint256)", "function transfer(address to, uint256 amount) returns (bool)"], wallet);
|
|
1879
1112
|
const balance2 = await contract.balanceOf(agent.delegateAddress);
|
|
1880
1113
|
if (balance2 > 0n) {
|
|
1881
1114
|
const tx = await contract.transfer(agent.accountAddress, balance2);
|
|
@@ -1929,7 +1162,7 @@ function chainIdFromNetwork(network) {
|
|
|
1929
1162
|
function chainIdOrNull(network) {
|
|
1930
1163
|
return chainIdFromNetwork(network) ?? null;
|
|
1931
1164
|
}
|
|
1932
|
-
function
|
|
1165
|
+
function sameAddress(a, b) {
|
|
1933
1166
|
return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
|
|
1934
1167
|
}
|
|
1935
1168
|
function decimalFromUsdcAtomic(value) {
|
|
@@ -1963,7 +1196,7 @@ function snapshotRequestBody(body) {
|
|
|
1963
1196
|
if (body == null) return void 0;
|
|
1964
1197
|
if (typeof body === "string") return body;
|
|
1965
1198
|
if (body instanceof URLSearchParams) return body.toString();
|
|
1966
|
-
throw new HavenApiError(
|
|
1199
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
1967
1200
|
"Quote helpers can only capture resumable request bodies that are strings or URLSearchParams. For streams, blobs, or binary bodies, preserve the original request yourself and call the matching resume method with fresh init.",
|
|
1968
1201
|
400
|
|
1969
1202
|
);
|
|
@@ -1984,32 +1217,40 @@ function requestInitFromSnapshot(request) {
|
|
|
1984
1217
|
};
|
|
1985
1218
|
}
|
|
1986
1219
|
function noCompatiblePaymentOptionError(accepts) {
|
|
1987
|
-
const erc7710Only = selectErc7710PaymentOption(accepts) !== null;
|
|
1988
|
-
|
|
1989
|
-
|
|
1220
|
+
const erc7710Only = chunkQSSVOPWA_cjs.selectErc7710PaymentOption(accepts) !== null;
|
|
1221
|
+
const unsupportedOnly = !erc7710Only && accepts.some(
|
|
1222
|
+
(opt) => opt !== null && typeof opt === "object" && !chunkQSSVOPWA_cjs.isErc7710Option(opt) && (chunkQSSVOPWA_cjs.x402AssetTransferMethod(opt) !== null || opt.extra?.paymentFlow !== void 0)
|
|
1223
|
+
);
|
|
1224
|
+
return new chunkJKUIE45B_cjs.HavenApiError(
|
|
1225
|
+
"No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC." + (erc7710Only ? " The only Haven-compatible option this merchant advertises is tagged extra.assetTransferMethod: 'erc7710' (direct settlement), which this EIP-3009 payment path cannot settle \u2014 the limitation is the settlement scheme, not the asset. Paying this merchant requires a delegation-rail erc7710 flow (settleX402Erc7710, or the hosted MCP purchase tools)." : unsupportedOnly ? " Every option this merchant advertises asks for a transfer method or payment flow Haven cannot construct (for example extra.assetTransferMethod: 'permit2', or an unrecognized extra.paymentFlow). No payment intent was created and no funds moved." : ""),
|
|
1990
1226
|
400
|
|
1991
1227
|
);
|
|
1992
1228
|
}
|
|
1993
1229
|
function buildX402Quote(paymentRequired, request, idempotencyKey, mcpTransport) {
|
|
1994
|
-
const standard = selectStandardPaymentOption(paymentRequired.accepts);
|
|
1995
|
-
const option = standard ?? selectErc7710PaymentOption(paymentRequired.accepts);
|
|
1230
|
+
const standard = chunkQSSVOPWA_cjs.selectStandardPaymentOption(paymentRequired.accepts);
|
|
1231
|
+
const option = standard ?? chunkQSSVOPWA_cjs.selectErc7710PaymentOption(paymentRequired.accepts);
|
|
1996
1232
|
if (!option) {
|
|
1997
1233
|
throw noCompatiblePaymentOptionError(paymentRequired.accepts);
|
|
1998
1234
|
}
|
|
1999
|
-
const token = resolveTokenFromAddress(option.asset, option.network);
|
|
1235
|
+
const token = chunkQSSVOPWA_cjs.resolveTokenFromAddress(option.asset, option.network);
|
|
2000
1236
|
return {
|
|
2001
1237
|
rail: "x402",
|
|
2002
|
-
idempotencyKey: idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option),
|
|
1238
|
+
idempotencyKey: idempotencyKey ?? chunkQSSVOPWA_cjs.buildX402IdempotencyKey(paymentRequired, option),
|
|
2003
1239
|
paymentRequired,
|
|
2004
1240
|
accepted: option,
|
|
2005
1241
|
acceptedScheme: standard ? "standard" : "erc7710",
|
|
2006
1242
|
request,
|
|
2007
1243
|
...mcpTransport ? { mcpTransport } : {},
|
|
2008
1244
|
resourceUrl: paymentRequired.resource.url,
|
|
1245
|
+
// #3097: the merchant's declaration vs the URL the caller quoted. The
|
|
1246
|
+
// paid retry goes to the caller's URL; a quote that says the two disagree
|
|
1247
|
+
// is how an agent sees a challenge that downgrades the scheme or moves
|
|
1248
|
+
// the host before it pays.
|
|
1249
|
+
resourceUrlDiffersFromRequest: paymentRequired.resource.url !== request.url,
|
|
2009
1250
|
description: paymentRequired.resource.description ?? option.description ?? null,
|
|
2010
1251
|
mimeType: paymentRequired.resource.mimeType ?? option.mimeType ?? null,
|
|
2011
|
-
amountAtomic: x402AuthorizationAmount(option),
|
|
2012
|
-
amount: decimalFromUsdcAtomic(x402AuthorizationAmount(option)),
|
|
1252
|
+
amountAtomic: chunkQSSVOPWA_cjs.x402AuthorizationAmount(option),
|
|
1253
|
+
amount: decimalFromUsdcAtomic(chunkQSSVOPWA_cjs.x402AuthorizationAmount(option)),
|
|
2013
1254
|
token: token?.symbol ?? "USDC",
|
|
2014
1255
|
// #1351: null when the asset is unrecognised on this network — the
|
|
2015
1256
|
// `token` fallback above is a LABEL, not evidence of 6 decimals, and a
|
|
@@ -2048,7 +1289,7 @@ function buildX402Receipt(input) {
|
|
|
2048
1289
|
payTo: input.merchantTo ?? input.accepted.payTo
|
|
2049
1290
|
},
|
|
2050
1291
|
x402: {
|
|
2051
|
-
amount: x402AuthorizationAmount(input.accepted),
|
|
1292
|
+
amount: chunkQSSVOPWA_cjs.x402AuthorizationAmount(input.accepted),
|
|
2052
1293
|
token: input.token,
|
|
2053
1294
|
network: input.accepted.network,
|
|
2054
1295
|
asset: input.accepted.asset,
|
|
@@ -2057,7 +1298,7 @@ function buildX402Receipt(input) {
|
|
|
2057
1298
|
};
|
|
2058
1299
|
}
|
|
2059
1300
|
function buildX402ResumeState(input) {
|
|
2060
|
-
const token = resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
|
|
1301
|
+
const token = chunkQSSVOPWA_cjs.resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
|
|
2061
1302
|
return {
|
|
2062
1303
|
rail: "x402",
|
|
2063
1304
|
paymentId: input.paymentId,
|
|
@@ -2068,8 +1309,8 @@ function buildX402ResumeState(input) {
|
|
|
2068
1309
|
request: input.request,
|
|
2069
1310
|
resourceUrl: input.paymentRequired.resource.url,
|
|
2070
1311
|
description: input.paymentRequired.resource.description ?? input.accepted.description ?? null,
|
|
2071
|
-
amountAtomic: x402AuthorizationAmount(input.accepted),
|
|
2072
|
-
amount: decimalFromUsdcAtomic(x402AuthorizationAmount(input.accepted)),
|
|
1312
|
+
amountAtomic: chunkQSSVOPWA_cjs.x402AuthorizationAmount(input.accepted),
|
|
1313
|
+
amount: decimalFromUsdcAtomic(chunkQSSVOPWA_cjs.x402AuthorizationAmount(input.accepted)),
|
|
2073
1314
|
token: token?.symbol ?? "USDC",
|
|
2074
1315
|
asset: input.accepted.asset,
|
|
2075
1316
|
network: input.accepted.network,
|
|
@@ -2078,7 +1319,7 @@ function buildX402ResumeState(input) {
|
|
|
2078
1319
|
};
|
|
2079
1320
|
}
|
|
2080
1321
|
function attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
|
|
2081
|
-
if (!(err instanceof HavenPaymentStateError)) return;
|
|
1322
|
+
if (!(err instanceof chunkJKUIE45B_cjs.HavenPaymentStateError)) return;
|
|
2082
1323
|
if (err.state.rail !== "x402") return;
|
|
2083
1324
|
err.resumeState = buildX402ResumeState({
|
|
2084
1325
|
paymentId: err.state.paymentId,
|
|
@@ -2099,17 +1340,17 @@ function attachResumeState(err, input) {
|
|
|
2099
1340
|
}
|
|
2100
1341
|
function assertCanResumeX402(status, paymentRequired, option) {
|
|
2101
1342
|
if (status.rail !== "x402") {
|
|
2102
|
-
throw new HavenPaymentStateError(
|
|
1343
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(
|
|
2103
1344
|
`Payment ${status.paymentId} is ${status.rail}, not x402.`,
|
|
2104
1345
|
409,
|
|
2105
1346
|
status
|
|
2106
1347
|
);
|
|
2107
1348
|
}
|
|
2108
|
-
if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
|
|
2109
|
-
throw new HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
|
|
1349
|
+
if (status.nextAction !== chunkJKUIE45B_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
|
|
1350
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
|
|
2110
1351
|
}
|
|
2111
1352
|
if (!status.txHash) {
|
|
2112
|
-
throw new HavenApiError(
|
|
1353
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2113
1354
|
`x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
|
|
2114
1355
|
502,
|
|
2115
1356
|
status,
|
|
@@ -2117,15 +1358,15 @@ function assertCanResumeX402(status, paymentRequired, option) {
|
|
|
2117
1358
|
);
|
|
2118
1359
|
}
|
|
2119
1360
|
if (status.resourceUrl && status.resourceUrl !== paymentRequired.resource.url) {
|
|
2120
|
-
throw new HavenApiError(
|
|
1361
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2121
1362
|
"x402 resume request does not match the approved resource URL.",
|
|
2122
1363
|
409,
|
|
2123
1364
|
{ status, paymentRequired },
|
|
2124
1365
|
status.paymentId
|
|
2125
1366
|
);
|
|
2126
1367
|
}
|
|
2127
|
-
if (status.merchantAddress && !
|
|
2128
|
-
throw new HavenApiError(
|
|
1368
|
+
if (status.merchantAddress && !sameAddress(status.merchantAddress, option.payTo)) {
|
|
1369
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2129
1370
|
"x402 resume request does not match the approved merchant.",
|
|
2130
1371
|
409,
|
|
2131
1372
|
{ status, selectedPayment: option },
|
|
@@ -2134,7 +1375,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
|
|
|
2134
1375
|
}
|
|
2135
1376
|
const optionChainId = chainIdFromNetwork(option.network);
|
|
2136
1377
|
if (status.chainId && optionChainId && status.chainId !== optionChainId) {
|
|
2137
|
-
throw new HavenApiError(
|
|
1378
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2138
1379
|
"x402 resume request does not match the approved network.",
|
|
2139
1380
|
409,
|
|
2140
1381
|
{ status, selectedPayment: option },
|
|
@@ -2142,7 +1383,7 @@ function assertCanResumeX402(status, paymentRequired, option) {
|
|
|
2142
1383
|
);
|
|
2143
1384
|
}
|
|
2144
1385
|
if (status.token && status.token !== "USDC") {
|
|
2145
|
-
throw new HavenApiError(
|
|
1386
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2146
1387
|
"x402 resume request does not match the approved token.",
|
|
2147
1388
|
409,
|
|
2148
1389
|
{ status, selectedPayment: option },
|
|
@@ -2150,9 +1391,9 @@ function assertCanResumeX402(status, paymentRequired, option) {
|
|
|
2150
1391
|
);
|
|
2151
1392
|
}
|
|
2152
1393
|
const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
|
|
2153
|
-
const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(x402AuthorizationAmount(option)));
|
|
1394
|
+
const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(chunkQSSVOPWA_cjs.x402AuthorizationAmount(option)));
|
|
2154
1395
|
if (approvedAmount && approvedAmount !== requestedAmount) {
|
|
2155
|
-
throw new HavenApiError(
|
|
1396
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2156
1397
|
"x402 resume request does not match the approved amount.",
|
|
2157
1398
|
409,
|
|
2158
1399
|
{ status, selectedPayment: option },
|
|
@@ -2210,7 +1451,7 @@ var X402FundingLeg = class {
|
|
|
2210
1451
|
url: paymentRequired.resource.url,
|
|
2211
1452
|
payTo: this.delegateAddress,
|
|
2212
1453
|
merchantPayTo: option.payTo,
|
|
2213
|
-
amount: x402AuthorizationAmount(option),
|
|
1454
|
+
amount: chunkQSSVOPWA_cjs.x402AuthorizationAmount(option),
|
|
2214
1455
|
asset: option.asset,
|
|
2215
1456
|
network: option.network,
|
|
2216
1457
|
description: paymentRequired.resource.description,
|
|
@@ -2221,17 +1462,17 @@ var X402FundingLeg = class {
|
|
|
2221
1462
|
settlementScheme: "eip3009"
|
|
2222
1463
|
});
|
|
2223
1464
|
const state = paymentStateFromRaw("x402 payment", raw);
|
|
2224
|
-
const executedReplay = raw.success && raw.tx_hash ? "idempotency-collision" : state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request ? "approval-resume" : null;
|
|
1465
|
+
const executedReplay = raw.success && raw.tx_hash ? "idempotency-collision" : state?.nextAction === chunkJKUIE45B_cjs.AgentPaymentNextAction.RetryOriginalX402Request ? "approval-resume" : null;
|
|
2225
1466
|
if (executedReplay) {
|
|
2226
1467
|
const canFund = await this.delegateCanFund(
|
|
2227
1468
|
raw.chain_id ?? state?.chainId ?? chainIdFromNetwork(option.network),
|
|
2228
1469
|
option.asset,
|
|
2229
|
-
x402AuthorizationAmount(option)
|
|
1470
|
+
chunkQSSVOPWA_cjs.x402AuthorizationAmount(option)
|
|
2230
1471
|
);
|
|
2231
1472
|
const refuse = executedReplay === "idempotency-collision" ? canFund !== true : canFund === false;
|
|
2232
1473
|
if (refuse) {
|
|
2233
1474
|
const settledReceipt = state && executedReplay === "approval-resume" ? this.receiptFromStatus(paymentRequired, option, void 0, state) : this.receiptFromAuthorization(paymentRequired, option, void 0, raw);
|
|
2234
|
-
throw new X402AlreadySettledError(
|
|
1475
|
+
throw new chunkJKUIE45B_cjs.X402AlreadySettledError(
|
|
2235
1476
|
canFund === false ? "This x402 payment already settled \u2014 the delegate no longer holds the funds to authorize it again. To buy the same item a second time, pass a distinct `idempotencyKey`; the synthesised key intentionally collapses repeat calls for the same product within a 5-minute window so a retried request cannot pay twice." : "This x402 payment already settled, and whether the delegate can still fund a new authorization could not be verified (no `chainRpcs` entry for this chain). Refusing rather than issue an authorization that may be unfundable. To buy the same item a second time, pass a distinct `idempotencyKey`; to finish an interrupted payment, resume it by `paymentId`.",
|
|
2236
1477
|
settledReceipt,
|
|
2237
1478
|
canFund === false ? "settled" : "unverifiable"
|
|
@@ -2244,14 +1485,14 @@ var X402FundingLeg = class {
|
|
|
2244
1485
|
this.cacheReceipt(idempotencyKey, paymentHeader, receipt2);
|
|
2245
1486
|
return receipt2;
|
|
2246
1487
|
}
|
|
2247
|
-
if (state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
|
|
1488
|
+
if (state?.nextAction === chunkJKUIE45B_cjs.AgentPaymentNextAction.RetryOriginalX402Request) {
|
|
2248
1489
|
const receipt2 = this.receiptFromStatus(paymentRequired, option, paymentHeader, state);
|
|
2249
1490
|
this.cacheReceipt(idempotencyKey, paymentHeader, receipt2);
|
|
2250
1491
|
return receipt2;
|
|
2251
1492
|
}
|
|
2252
1493
|
this.assertSignableAuthorizationState("x402 payment", raw);
|
|
2253
1494
|
if (!raw.sign_data?.hash) {
|
|
2254
|
-
throw new HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
|
|
1495
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
|
|
2255
1496
|
}
|
|
2256
1497
|
const sig = await this.signForData(raw.sign_data);
|
|
2257
1498
|
const execResult = await this.post(
|
|
@@ -2272,25 +1513,25 @@ var X402FundingLeg = class {
|
|
|
2272
1513
|
// ── Header minting ───────────────────────────────────────────────
|
|
2273
1514
|
async createPaymentHeader(paymentRequired, option) {
|
|
2274
1515
|
if (!this.delegateKey) {
|
|
2275
|
-
throw new HavenSigningError("delegateKey is required to sign x402 payment headers.");
|
|
1516
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError("delegateKey is required to sign x402 payment headers.");
|
|
2276
1517
|
}
|
|
2277
1518
|
const account = accounts.privateKeyToAccount(this.delegateKey);
|
|
2278
|
-
const requirements = toStandardPaymentRequirements(paymentRequired, option);
|
|
1519
|
+
const requirements = chunkQSSVOPWA_cjs.toStandardPaymentRequirements(paymentRequired, option);
|
|
2279
1520
|
const header = await schemes.exact.evm.createPaymentHeader(
|
|
2280
1521
|
account,
|
|
2281
1522
|
paymentRequired.x402Version,
|
|
2282
1523
|
requirements
|
|
2283
1524
|
);
|
|
2284
1525
|
if (paymentRequired.x402Version < 2) return header;
|
|
2285
|
-
const payment = decodeBase64Json(header);
|
|
2286
|
-
return encodeBase64Json(x402V2PaymentEnvelope(paymentRequired, option, payment.payload));
|
|
1526
|
+
const payment = chunkQSSVOPWA_cjs.decodeBase64Json(header);
|
|
1527
|
+
return chunkQSSVOPWA_cjs.encodeBase64Json(chunkQSSVOPWA_cjs.x402V2PaymentEnvelope(paymentRequired, option, payment.payload));
|
|
2287
1528
|
}
|
|
2288
1529
|
// ── Receipt mapping ──────────────────────────────────────────────
|
|
2289
1530
|
receiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
|
|
2290
1531
|
const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
|
|
2291
1532
|
const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
|
|
2292
1533
|
const token = execResult?.token ?? raw.token ?? "USDC";
|
|
2293
|
-
const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(x402AuthorizationAmount(option));
|
|
1534
|
+
const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(chunkQSSVOPWA_cjs.x402AuthorizationAmount(option));
|
|
2294
1535
|
const to = execResult?.to ?? raw.to ?? this.delegateAddress ?? "";
|
|
2295
1536
|
const explorerUrl = execResult?.explorer_url ?? raw.explorer_url ?? explorerUrlOrEmpty(chainId, txHash);
|
|
2296
1537
|
const merchantTo = execResult?.merchant_to ?? raw.merchant_to ?? option.payTo;
|
|
@@ -2312,7 +1553,7 @@ var X402FundingLeg = class {
|
|
|
2312
1553
|
}
|
|
2313
1554
|
receiptFromStatus(paymentRequired, option, paymentHeader, status) {
|
|
2314
1555
|
if (!status.txHash) {
|
|
2315
|
-
throw new HavenApiError(
|
|
1556
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2316
1557
|
`x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
|
|
2317
1558
|
502,
|
|
2318
1559
|
status,
|
|
@@ -2323,7 +1564,7 @@ var X402FundingLeg = class {
|
|
|
2323
1564
|
paymentId: status.paymentId,
|
|
2324
1565
|
txHash: status.txHash,
|
|
2325
1566
|
token: status.token || "USDC",
|
|
2326
|
-
amount: status.amount || decimalFromUsdcAtomic(x402AuthorizationAmount(option)),
|
|
1567
|
+
amount: status.amount || decimalFromUsdcAtomic(chunkQSSVOPWA_cjs.x402AuthorizationAmount(option)),
|
|
2327
1568
|
to: this.delegateAddress ?? "",
|
|
2328
1569
|
resourceUrl: paymentRequired.resource.url,
|
|
2329
1570
|
explorerUrl: explorerUrlOrEmpty(status.chainId, status.txHash),
|
|
@@ -2351,7 +1592,7 @@ var X402FundingLeg = class {
|
|
|
2351
1592
|
const provider = createJsonRpcProvider(rpcUrl);
|
|
2352
1593
|
const onChainReceipt = await provider.waitForTransaction(txHash, 1, timeoutMs);
|
|
2353
1594
|
if (!onChainReceipt || onChainReceipt.status !== 1) {
|
|
2354
|
-
throw new HavenApiError(
|
|
1595
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2355
1596
|
"Funding tx did not confirm on-chain within the timeout window.",
|
|
2356
1597
|
500,
|
|
2357
1598
|
{ txHash, chainId }
|
|
@@ -2400,7 +1641,7 @@ var X402FundingLeg = class {
|
|
|
2400
1641
|
};
|
|
2401
1642
|
function getPaymentHeaderValidBefore(paymentHeader) {
|
|
2402
1643
|
try {
|
|
2403
|
-
const payment = decodeBase64Json(
|
|
1644
|
+
const payment = chunkQSSVOPWA_cjs.decodeBase64Json(
|
|
2404
1645
|
paymentHeader
|
|
2405
1646
|
);
|
|
2406
1647
|
const payload = payment.payload;
|
|
@@ -2455,12 +1696,15 @@ var X402Erc7710 = class {
|
|
|
2455
1696
|
*/
|
|
2456
1697
|
async settle(paymentRequired, options = {}) {
|
|
2457
1698
|
if (!this.delegateKey) {
|
|
2458
|
-
throw new HavenSigningError(
|
|
1699
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
2459
1700
|
"delegateKey is required for x402 payments. Pass it in the HavenClient config."
|
|
2460
1701
|
);
|
|
2461
1702
|
}
|
|
2462
1703
|
const prepared = await this.prepare(paymentRequired, options);
|
|
2463
|
-
const signature = await this.signForData(
|
|
1704
|
+
const signature = await this.signForData(
|
|
1705
|
+
prepared.signData,
|
|
1706
|
+
settlementExpectationFromQuote(prepared.settlement)
|
|
1707
|
+
);
|
|
2464
1708
|
const paymentHeader = await this.submit(prepared.paymentId, signature);
|
|
2465
1709
|
return { ...prepared.settlement, paymentHeader };
|
|
2466
1710
|
}
|
|
@@ -2477,21 +1721,21 @@ var X402Erc7710 = class {
|
|
|
2477
1721
|
async prepare(paymentRequired, options = {}) {
|
|
2478
1722
|
const delegationRail = options.delegationRail ?? (await this.getAgent()).executionRail === "delegation";
|
|
2479
1723
|
if (!delegationRail) {
|
|
2480
|
-
throw new HavenApiError(
|
|
1724
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2481
1725
|
"erc7710 settlement requires a delegation-rail account; this one is not on it. Use authorizeX402() for the standard EIP-3009 path.",
|
|
2482
1726
|
400
|
|
2483
1727
|
);
|
|
2484
1728
|
}
|
|
2485
|
-
const selection = selectX402SettlementScheme(paymentRequired.accepts, { delegationRail });
|
|
1729
|
+
const selection = chunkQSSVOPWA_cjs.selectX402SettlementScheme(paymentRequired.accepts, { delegationRail });
|
|
2486
1730
|
if (!selection || selection.scheme !== "erc7710") {
|
|
2487
|
-
throw new HavenApiError(
|
|
1731
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2488
1732
|
"This merchant does not advertise an erc7710 settlement option (no accepts[] entry carries extra.assetTransferMethod: 'erc7710'). Use authorizeX402() for the standard EIP-3009 path.",
|
|
2489
1733
|
400
|
|
2490
1734
|
);
|
|
2491
1735
|
}
|
|
2492
1736
|
const option = selection.option;
|
|
2493
1737
|
const merchantPayTo = option.payTo;
|
|
2494
|
-
const amountAtomic = x402AuthorizationAmount(option);
|
|
1738
|
+
const amountAtomic = chunkQSSVOPWA_cjs.x402AuthorizationAmount(option);
|
|
2495
1739
|
const raw = await this.post("/x402", {
|
|
2496
1740
|
url: options.resourceUrl ?? paymentRequired.resource?.url,
|
|
2497
1741
|
// #2373: the full 402 challenge, persisted verbatim by the backend
|
|
@@ -2529,11 +1773,11 @@ var X402Erc7710 = class {
|
|
|
2529
1773
|
...options.mcpCallContext ? { mcpCallContext: options.mcpCallContext } : {}
|
|
2530
1774
|
});
|
|
2531
1775
|
if (!raw.payment_id) {
|
|
2532
|
-
throw new HavenApiError("No payment_id returned from x402/authorize", 500, raw);
|
|
1776
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No payment_id returned from x402/authorize", 500, raw);
|
|
2533
1777
|
}
|
|
2534
1778
|
const signData = raw.sign_data;
|
|
2535
1779
|
if (signData?.signature_scheme !== "eip712_delegation" || !signData.typed_data) {
|
|
2536
|
-
throw new HavenApiError(
|
|
1780
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2537
1781
|
`x402/authorize did not return an erc7710 settlement child (signature_scheme was ${JSON.stringify(signData?.signature_scheme)}). Refusing to sign a payload this path did not ask for.`,
|
|
2538
1782
|
500,
|
|
2539
1783
|
raw
|
|
@@ -2566,7 +1810,7 @@ var X402Erc7710 = class {
|
|
|
2566
1810
|
{ signature }
|
|
2567
1811
|
);
|
|
2568
1812
|
if (!settled.payment_header) {
|
|
2569
|
-
throw new HavenApiError(
|
|
1813
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2570
1814
|
"x402 settle returned no payment_header \u2014 the merchant cannot be retried.",
|
|
2571
1815
|
500,
|
|
2572
1816
|
settled
|
|
@@ -2575,6 +1819,21 @@ var X402Erc7710 = class {
|
|
|
2575
1819
|
return settled.payment_header;
|
|
2576
1820
|
}
|
|
2577
1821
|
};
|
|
1822
|
+
function settlementExpectationFromQuote(settlement) {
|
|
1823
|
+
const chainId = chunkJKUIE45B_cjs.chainIdForNetwork(settlement.network);
|
|
1824
|
+
if (chainId === void 0) {
|
|
1825
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
1826
|
+
`Refusing to sign the x402 settlement child: the merchant's network ${JSON.stringify(settlement.network)} is not one this SDK can verify a settlement child on.`
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
return {
|
|
1830
|
+
merchantTo: settlement.merchantPayTo,
|
|
1831
|
+
amount: settlement.amountAtomic,
|
|
1832
|
+
asset: settlement.asset,
|
|
1833
|
+
chainId,
|
|
1834
|
+
...settlement.facilitatorAddresses && settlement.facilitatorAddresses.length > 0 ? { redeemers: settlement.facilitatorAddresses } : {}
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
2578
1837
|
|
|
2579
1838
|
// src/tool-adapter.ts
|
|
2580
1839
|
function toolX402PaymentRequired(input) {
|
|
@@ -2613,7 +1872,7 @@ function x402ToolReceipt(receipt) {
|
|
|
2613
1872
|
};
|
|
2614
1873
|
}
|
|
2615
1874
|
function toolError(err) {
|
|
2616
|
-
if (err instanceof HavenPaymentStateError) {
|
|
1875
|
+
if (err instanceof chunkJKUIE45B_cjs.HavenPaymentStateError) {
|
|
2617
1876
|
return {
|
|
2618
1877
|
success: false,
|
|
2619
1878
|
payment_id: err.state.paymentId,
|
|
@@ -2658,7 +1917,7 @@ function toolError(err) {
|
|
|
2658
1917
|
error: err.message
|
|
2659
1918
|
};
|
|
2660
1919
|
}
|
|
2661
|
-
if (err instanceof HavenApiError) {
|
|
1920
|
+
if (err instanceof chunkJKUIE45B_cjs.HavenApiError) {
|
|
2662
1921
|
return {
|
|
2663
1922
|
success: false,
|
|
2664
1923
|
status_code: err.statusCode,
|
|
@@ -2695,17 +1954,22 @@ var MerchantCompletion = class {
|
|
|
2695
1954
|
}
|
|
2696
1955
|
async retryRequest(url, initialInit, paymentRequired, receipt) {
|
|
2697
1956
|
if (!receipt.accepted) {
|
|
2698
|
-
throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
|
|
1957
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No accepted x402 option was recorded for payment retry", 500);
|
|
2699
1958
|
}
|
|
2700
1959
|
if (!receipt.paymentHeader) {
|
|
2701
|
-
throw new HavenApiError("No x402 payment header was returned for payment retry", 500);
|
|
1960
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No x402 payment header was returned for payment retry", 500);
|
|
2702
1961
|
}
|
|
2703
|
-
const retryResponse = await this.merchantTransport.
|
|
1962
|
+
const retryResponse = await this.merchantTransport.deliverPaymentRecoveringSession(
|
|
2704
1963
|
url,
|
|
2705
1964
|
initialInit,
|
|
2706
|
-
receipt.paymentHeader
|
|
1965
|
+
receipt.paymentHeader,
|
|
1966
|
+
() => this.merchantTransport.initialize(url, initialInit)
|
|
2707
1967
|
);
|
|
2708
|
-
|
|
1968
|
+
const toolResult = retryResponse.ok ? await this.merchantTransport.readToolResult(retryResponse) : void 0;
|
|
1969
|
+
const inBandChallenge = toolResult ? extractMcpPaymentRequired(toolResult) : void 0;
|
|
1970
|
+
const metaSettlement = toolResult ? mcpSettlementFromToolResult(toolResult) : void 0;
|
|
1971
|
+
const inBandRejection = inBandChallenge !== void 0 || metaSettlement?.success === false;
|
|
1972
|
+
if (!retryResponse.ok || inBandRejection) {
|
|
2709
1973
|
const merchant = await captureMerchantResponse(retryResponse);
|
|
2710
1974
|
await this.recordRetryRejected({
|
|
2711
1975
|
rail: "x402",
|
|
@@ -2718,9 +1982,9 @@ var MerchantCompletion = class {
|
|
|
2718
1982
|
delegate_to: receipt.to
|
|
2719
1983
|
}
|
|
2720
1984
|
});
|
|
2721
|
-
throw new HavenApiError(
|
|
1985
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2722
1986
|
"x402 retry failed after Haven funded the delegate wallet; reconciliation may be required.",
|
|
2723
|
-
merchant.merchant_status,
|
|
1987
|
+
inBandRejection ? X402_RETRY_REJECTED_STATUS : merchant.merchant_status,
|
|
2724
1988
|
{
|
|
2725
1989
|
marker: "x402_retry_rejected_after_funding",
|
|
2726
1990
|
payment_id: receipt.paymentId,
|
|
@@ -2732,7 +1996,10 @@ var MerchantCompletion = class {
|
|
|
2732
1996
|
}
|
|
2733
1997
|
);
|
|
2734
1998
|
}
|
|
2735
|
-
const
|
|
1999
|
+
const headerReceipt = retryResponse.headers.get("PAYMENT-RESPONSE");
|
|
2000
|
+
const protocolReceiptHeader = headerReceipt ?? (metaSettlement ? encodeMcpSettlementReceipt(metaSettlement) : void 0);
|
|
2001
|
+
const protocolReceiptHeaderName = headerReceipt ? "PAYMENT-RESPONSE" : metaSettlement ? `_meta.${MCP_X402_PAYMENT_RESPONSE_META_KEY}` : void 0;
|
|
2002
|
+
const merchantSettlement = parseMerchantSettlement(protocolReceiptHeader ?? null);
|
|
2736
2003
|
if (receipt.merchant && merchantSettlement.settlementTxHash) {
|
|
2737
2004
|
receipt.merchant.settlementTxHash = merchantSettlement.settlementTxHash;
|
|
2738
2005
|
receipt.merchant.settlementExplorerUrl = buildExplorerUrl(
|
|
@@ -2748,10 +2015,10 @@ var MerchantCompletion = class {
|
|
|
2748
2015
|
merchantStatus: retryResponse.status,
|
|
2749
2016
|
challengePayload: paymentRequired,
|
|
2750
2017
|
selectedPayment: receipt.accepted,
|
|
2751
|
-
paymentProofHeaderName: x402PaymentHeaderNamesSent(receipt.paymentHeader),
|
|
2018
|
+
paymentProofHeaderName: chunkQSSVOPWA_cjs.x402PaymentHeaderNamesSent(receipt.paymentHeader),
|
|
2752
2019
|
paymentProofHeader: receipt.paymentHeader,
|
|
2753
|
-
protocolReceiptHeaderName
|
|
2754
|
-
protocolReceiptHeader
|
|
2020
|
+
protocolReceiptHeaderName,
|
|
2021
|
+
protocolReceiptHeader
|
|
2755
2022
|
});
|
|
2756
2023
|
await this.reportMerchantReceipt(receipt.paymentId, retryResponse);
|
|
2757
2024
|
return retryResponse;
|
|
@@ -2789,18 +2056,18 @@ var MerchantCompletion = class {
|
|
|
2789
2056
|
async resolveCompletionContext(input) {
|
|
2790
2057
|
const status = await this.getPaymentStatus(input.paymentId);
|
|
2791
2058
|
if (status.rail !== "x402") {
|
|
2792
|
-
throw new HavenPaymentStateError(
|
|
2059
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(
|
|
2793
2060
|
`Payment ${status.paymentId} is ${status.rail}, not x402.`,
|
|
2794
2061
|
409,
|
|
2795
2062
|
status
|
|
2796
2063
|
);
|
|
2797
2064
|
}
|
|
2798
|
-
const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
|
|
2065
|
+
const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === chunkJKUIE45B_cjs.AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === chunkJKUIE45B_cjs.AgentPaymentPhase.PaymentConfirmed && status.nextAction === chunkJKUIE45B_cjs.AgentPaymentNextAction.None;
|
|
2799
2066
|
if (!readyForMerchantCompletion) {
|
|
2800
|
-
throw new HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
|
|
2067
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(status.message, paymentStateStatusCode(status.status, 409), status);
|
|
2801
2068
|
}
|
|
2802
2069
|
if (!input.noFundingLeg && !status.txHash) {
|
|
2803
|
-
throw new HavenApiError(
|
|
2070
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2804
2071
|
`x402 payment ${status.paymentId} is ready for merchant completion but has no Haven transaction hash.`,
|
|
2805
2072
|
502,
|
|
2806
2073
|
status,
|
|
@@ -2809,7 +2076,7 @@ var MerchantCompletion = class {
|
|
|
2809
2076
|
}
|
|
2810
2077
|
const approvedResourceUrl = status.resourceUrl ?? status.x402?.resourceUrl ?? null;
|
|
2811
2078
|
if (approvedResourceUrl && approvedResourceUrl !== input.url) {
|
|
2812
|
-
throw new HavenApiError(
|
|
2079
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2813
2080
|
"x402 merchant completion does not match the approved resource URL.",
|
|
2814
2081
|
409,
|
|
2815
2082
|
{ status, url: input.url },
|
|
@@ -2895,7 +2162,7 @@ var MerchantCompletion = class {
|
|
|
2895
2162
|
*/
|
|
2896
2163
|
async reportMerchantOutcome(input) {
|
|
2897
2164
|
if (!Number.isInteger(input.merchantStatus) || input.merchantStatus < 100 || input.merchantStatus > 599) {
|
|
2898
|
-
throw new HavenApiError(
|
|
2165
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2899
2166
|
`merchant_status must be an integer HTTP status from 100 to 599 (received ${input.merchantStatus}).`,
|
|
2900
2167
|
400,
|
|
2901
2168
|
void 0,
|
|
@@ -2904,7 +2171,7 @@ var MerchantCompletion = class {
|
|
|
2904
2171
|
}
|
|
2905
2172
|
const looksAccepted = input.merchantStatus >= 200 && input.merchantStatus < 300;
|
|
2906
2173
|
if (looksAccepted !== (input.outcome === "accepted")) {
|
|
2907
|
-
throw new HavenApiError(
|
|
2174
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2908
2175
|
`outcome "${input.outcome}" contradicts merchant_status ${input.merchantStatus}: report "accepted" only for a 2xx and "rejected" only for a non-2xx.`,
|
|
2909
2176
|
400,
|
|
2910
2177
|
void 0,
|
|
@@ -2913,14 +2180,14 @@ var MerchantCompletion = class {
|
|
|
2913
2180
|
}
|
|
2914
2181
|
const status = await this.getPaymentStatus(input.paymentId);
|
|
2915
2182
|
if (status.rail !== "x402") {
|
|
2916
|
-
throw new HavenPaymentStateError(
|
|
2183
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(
|
|
2917
2184
|
`Payment ${status.paymentId} is ${status.rail}, not x402 \u2014 there is no merchant retry to report.`,
|
|
2918
2185
|
409,
|
|
2919
2186
|
status
|
|
2920
2187
|
);
|
|
2921
2188
|
}
|
|
2922
2189
|
if (status.status !== "confirmed" || !status.txHash) {
|
|
2923
|
-
throw new HavenPaymentStateError(
|
|
2190
|
+
throw new chunkJKUIE45B_cjs.HavenPaymentStateError(
|
|
2924
2191
|
`Payment ${status.paymentId} has no confirmed Haven funding transaction to anchor a merchant report to (status ${status.status}). ${status.message}`,
|
|
2925
2192
|
paymentStateStatusCode(status.status, 409),
|
|
2926
2193
|
status
|
|
@@ -2928,7 +2195,7 @@ var MerchantCompletion = class {
|
|
|
2928
2195
|
}
|
|
2929
2196
|
const resourceUrl = status.resourceUrl ?? status.x402?.resourceUrl ?? null;
|
|
2930
2197
|
if (!resourceUrl) {
|
|
2931
|
-
throw new HavenApiError(
|
|
2198
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
2932
2199
|
`Payment ${status.paymentId} has no recorded resource URL, so a merchant report cannot be stored.`,
|
|
2933
2200
|
409,
|
|
2934
2201
|
status,
|
|
@@ -2981,7 +2248,7 @@ var MerchantCompletion = class {
|
|
|
2981
2248
|
await this.post("/machine-payments/evidence", body);
|
|
2982
2249
|
return { outcome: "confirmed" };
|
|
2983
2250
|
} catch (err) {
|
|
2984
|
-
const statusCode = err instanceof HavenApiError ? err.statusCode : void 0;
|
|
2251
|
+
const statusCode = err instanceof chunkJKUIE45B_cjs.HavenApiError ? err.statusCode : void 0;
|
|
2985
2252
|
const retryable = statusCode === EVIDENCE_RETRYABLE_STATUS;
|
|
2986
2253
|
if (!retryable) {
|
|
2987
2254
|
return { outcome: "refused", statusCode: statusCode ?? 0 };
|
|
@@ -3018,7 +2285,7 @@ var MerchantCompletion = class {
|
|
|
3018
2285
|
*/
|
|
3019
2286
|
async reportSettlementEvidence(paymentId, settlementTxHash) {
|
|
3020
2287
|
if (isZeroSettlementTxHash(settlementTxHash)) {
|
|
3021
|
-
throw new HavenZeroSettlementHashError(paymentId);
|
|
2288
|
+
throw new chunkJKUIE45B_cjs.HavenZeroSettlementHashError(paymentId);
|
|
3022
2289
|
}
|
|
3023
2290
|
return this.reportEvidence({
|
|
3024
2291
|
paymentId,
|
|
@@ -3038,7 +2305,7 @@ function parseMerchantSettlement(header) {
|
|
|
3038
2305
|
}
|
|
3039
2306
|
function parseProtocolReceiptHeader(value) {
|
|
3040
2307
|
try {
|
|
3041
|
-
return decodeBase64Json(value);
|
|
2308
|
+
return chunkQSSVOPWA_cjs.decodeBase64Json(value);
|
|
3042
2309
|
} catch {
|
|
3043
2310
|
try {
|
|
3044
2311
|
return JSON.parse(value);
|
|
@@ -3055,7 +2322,7 @@ function x402TypedDataDigest(typedData) {
|
|
|
3055
2322
|
try {
|
|
3056
2323
|
return viem.hashTypedData(typedData);
|
|
3057
2324
|
} catch (err) {
|
|
3058
|
-
throw new HavenSigningError(
|
|
2325
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3059
2326
|
`The x402 funding intent carried a sign_data.typed_data that is not a valid EIP-712 payload (needs domain, types, primaryType, message), so its digest cannot be derived and no signer could accept it. Underlying error: ${err instanceof Error ? err.message : String(err)}`
|
|
3060
2327
|
);
|
|
3061
2328
|
}
|
|
@@ -3079,7 +2346,18 @@ function mapCatalogEntry(entry) {
|
|
|
3079
2346
|
verifiedAt: entry.verified_at,
|
|
3080
2347
|
source: entry.source,
|
|
3081
2348
|
domainVerified: entry.domain_verified,
|
|
3082
|
-
verifiedPayable: entry.verified_payable
|
|
2349
|
+
verifiedPayable: entry.verified_payable,
|
|
2350
|
+
// #3078: absent (older backend) or null (unresolved join) both mean "no
|
|
2351
|
+
// merchant known" — the public field is then absent, never null.
|
|
2352
|
+
...entry.merchant ? {
|
|
2353
|
+
merchant: {
|
|
2354
|
+
id: entry.merchant.id,
|
|
2355
|
+
slug: entry.merchant.slug,
|
|
2356
|
+
name: entry.merchant.name,
|
|
2357
|
+
listingStatus: entry.merchant.listing_status,
|
|
2358
|
+
isTestMerchant: entry.merchant.is_test_merchant
|
|
2359
|
+
}
|
|
2360
|
+
} : {}
|
|
3083
2361
|
};
|
|
3084
2362
|
}
|
|
3085
2363
|
var HavenClient = class {
|
|
@@ -3126,7 +2404,7 @@ var HavenClient = class {
|
|
|
3126
2404
|
});
|
|
3127
2405
|
this.x402Wallet = config.x402Wallet;
|
|
3128
2406
|
this.merchantTransport = new McpMerchantTransport({ merchantTimeout: config.merchantTimeout });
|
|
3129
|
-
this.confirmationTimeout = config.confirmationTimeout ?? DEFAULT_CONFIRMATION_TIMEOUT_MS;
|
|
2407
|
+
this.confirmationTimeout = config.confirmationTimeout ?? chunkJKUIE45B_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS;
|
|
3130
2408
|
this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
|
|
3131
2409
|
this.chainRpcs = config.chainRpcs ?? {};
|
|
3132
2410
|
if (this.delegateKey) {
|
|
@@ -3152,7 +2430,7 @@ var HavenClient = class {
|
|
|
3152
2430
|
this.erc7710 = new X402Erc7710({
|
|
3153
2431
|
delegateKey: this.delegateKey,
|
|
3154
2432
|
post: (path, body) => this.post(path, body),
|
|
3155
|
-
signForData: (signData) => this.signForData(signData),
|
|
2433
|
+
signForData: (signData, settlementExpectation) => this.signForData(signData, settlementExpectation),
|
|
3156
2434
|
getAgent: () => this.getAgent()
|
|
3157
2435
|
});
|
|
3158
2436
|
}
|
|
@@ -3174,23 +2452,33 @@ var HavenClient = class {
|
|
|
3174
2452
|
withRequestContext(headers, fn) {
|
|
3175
2453
|
return this.havenApi.withRequestContext(headers, fn);
|
|
3176
2454
|
}
|
|
2455
|
+
/**
|
|
2456
|
+
* The backend's newest `client_update` hint for this client (#3303): inside
|
|
2457
|
+
* a `withRequestContext` dispatch, the one that dispatch's own requests
|
|
2458
|
+
* received; outside one, the latest seen. Undefined when the client is
|
|
2459
|
+
* current or the backend predates #3303.
|
|
2460
|
+
*/
|
|
2461
|
+
clientUpdate() {
|
|
2462
|
+
return this.havenApi.clientUpdate();
|
|
2463
|
+
}
|
|
3177
2464
|
// ── High-Level API ───────────────────────────────────────────────
|
|
3178
2465
|
/**
|
|
3179
2466
|
* Send a payment in one call.
|
|
3180
2467
|
*
|
|
3181
|
-
* Creates the intent, signs
|
|
2468
|
+
* Creates the intent, signs its `sign_data` (a delegation-rail intent's
|
|
2469
|
+
* EIP-712 typed data, after the #3271 UserOp binding check), submits the signature,
|
|
3182
2470
|
* and polls until confirmed (or throws on failure/timeout).
|
|
3183
2471
|
*
|
|
3184
2472
|
* Requires `delegateKey` to be set in the client config.
|
|
3185
2473
|
*/
|
|
3186
2474
|
async pay(request) {
|
|
3187
2475
|
if (!this.delegateKey) {
|
|
3188
|
-
throw new HavenSigningError(
|
|
2476
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3189
2477
|
"Cannot use pay() without a delegateKey. Use createIntent() + submitSignature() for manual signing."
|
|
3190
2478
|
);
|
|
3191
2479
|
}
|
|
3192
2480
|
const intent = await this.createIntent(request);
|
|
3193
|
-
const signature = this.
|
|
2481
|
+
const signature = await this.signForData(intent.signData);
|
|
3194
2482
|
await this.submitSignature(intent.paymentId, signature);
|
|
3195
2483
|
return this.waitForConfirmation(intent.paymentId);
|
|
3196
2484
|
}
|
|
@@ -3234,15 +2522,15 @@ var HavenClient = class {
|
|
|
3234
2522
|
* on-chain allowance — there is nothing to sign until the user approves.
|
|
3235
2523
|
*/
|
|
3236
2524
|
async createX402Intent(paymentRequired, options = {}) {
|
|
3237
|
-
const option = selectStandardPaymentOption(paymentRequired.accepts);
|
|
2525
|
+
const option = chunkQSSVOPWA_cjs.selectStandardPaymentOption(paymentRequired.accepts);
|
|
3238
2526
|
if (!option) {
|
|
3239
2527
|
throw noCompatiblePaymentOptionError(paymentRequired.accepts);
|
|
3240
2528
|
}
|
|
3241
2529
|
const fundingTo = options.delegateAddress ?? (await this.getAgent()).delegateAddress;
|
|
3242
2530
|
if (!fundingTo) {
|
|
3243
|
-
throw new HavenApiError("Authenticated agent has no delegate address registered.", 502);
|
|
2531
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("Authenticated agent has no delegate address registered.", 502);
|
|
3244
2532
|
}
|
|
3245
|
-
const idempotencyKey = options.idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option);
|
|
2533
|
+
const idempotencyKey = options.idempotencyKey ?? chunkQSSVOPWA_cjs.buildX402IdempotencyKey(paymentRequired, option);
|
|
3246
2534
|
const raw = await this.post("/x402", {
|
|
3247
2535
|
url: paymentRequired.resource.url,
|
|
3248
2536
|
payTo: fundingTo,
|
|
@@ -3253,7 +2541,7 @@ var HavenClient = class {
|
|
|
3253
2541
|
// of a silent reroute to the erc7710 settlement branch (the #1358
|
|
3254
2542
|
// review's open-budget misroute). Legacy-rail backends ignore the field.
|
|
3255
2543
|
settlementScheme: "eip3009",
|
|
3256
|
-
amount: x402AuthorizationAmount(option),
|
|
2544
|
+
amount: chunkQSSVOPWA_cjs.x402AuthorizationAmount(option),
|
|
3257
2545
|
asset: option.asset,
|
|
3258
2546
|
network: option.network,
|
|
3259
2547
|
description: paymentRequired.resource.description,
|
|
@@ -3271,15 +2559,15 @@ var HavenClient = class {
|
|
|
3271
2559
|
throwPaymentStateError("x402 payment", raw);
|
|
3272
2560
|
}
|
|
3273
2561
|
if (!raw.sign_data?.hash) {
|
|
3274
|
-
throw new HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
|
|
2562
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
|
|
3275
2563
|
}
|
|
3276
2564
|
if (raw.sign_data.signature_scheme !== void 0 && !raw.sign_data.typed_data) {
|
|
3277
|
-
throw new HavenSigningError(
|
|
2565
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3278
2566
|
`This account's x402 funding intent declares signature scheme '${raw.sign_data.signature_scheme}' but carried no typed_data to sign. Refusing to fall back to the bare hash \u2014 the account would reject that signature on-chain. This is a backend contract violation; report it rather than working around it.`
|
|
3279
2567
|
);
|
|
3280
2568
|
}
|
|
3281
2569
|
if (!raw.x402_expected_auth) {
|
|
3282
|
-
throw new HavenApiError("No x402 expected-context binding returned from x402/authorize", 500, raw);
|
|
2570
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("No x402 expected-context binding returned from x402/authorize", 500, raw);
|
|
3283
2571
|
}
|
|
3284
2572
|
return {
|
|
3285
2573
|
paymentId: raw.payment_id,
|
|
@@ -3290,7 +2578,7 @@ var HavenClient = class {
|
|
|
3290
2578
|
accepted: option,
|
|
3291
2579
|
resourceUrl: paymentRequired.resource.url,
|
|
3292
2580
|
merchantTo: raw.merchant_to ?? option.payTo,
|
|
3293
|
-
amountAtomic: x402AuthorizationAmount(option),
|
|
2581
|
+
amountAtomic: chunkQSSVOPWA_cjs.x402AuthorizationAmount(option),
|
|
3294
2582
|
asset: option.asset,
|
|
3295
2583
|
network: option.network,
|
|
3296
2584
|
expectedAuth: raw.x402_expected_auth,
|
|
@@ -3315,13 +2603,13 @@ var HavenClient = class {
|
|
|
3315
2603
|
*/
|
|
3316
2604
|
sign(hash) {
|
|
3317
2605
|
if (!this.delegateKey) {
|
|
3318
|
-
throw new HavenSigningError(
|
|
2606
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3319
2607
|
"Cannot sign without a delegateKey. Pass the private key in HavenClient config, or sign externally."
|
|
3320
2608
|
);
|
|
3321
2609
|
}
|
|
3322
2610
|
const signature = signHash(this.delegateKey, hash);
|
|
3323
2611
|
if (!verifySignature(hash, signature, this.delegateAddress)) {
|
|
3324
|
-
throw new HavenSigningError(
|
|
2612
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3325
2613
|
"Local signature verification failed \u2014 recovered address does not match delegate key."
|
|
3326
2614
|
);
|
|
3327
2615
|
}
|
|
@@ -3337,40 +2625,51 @@ var HavenClient = class {
|
|
|
3337
2625
|
* (#834) — the backend refuses those intents with HTTP 410 before any
|
|
3338
2626
|
* sign_data reaches a client, so encountering it here is a hard error too.
|
|
3339
2627
|
*/
|
|
3340
|
-
async signForData(signData) {
|
|
2628
|
+
async signForData(signData, settlementExpectation) {
|
|
3341
2629
|
if (!this.delegateKey) {
|
|
3342
|
-
throw new HavenSigningError(
|
|
2630
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3343
2631
|
"Cannot sign without a delegateKey. Pass the private key in HavenClient config, or sign externally."
|
|
3344
2632
|
);
|
|
3345
2633
|
}
|
|
3346
2634
|
const scheme = signData.signature_scheme;
|
|
3347
2635
|
if (scheme === "eip191_userop") {
|
|
3348
|
-
throw new HavenSigningError(
|
|
2636
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3349
2637
|
"The session rail is retired \u2014 'eip191_userop' intents can no longer be signed. Re-onboard the account on the delegation rail."
|
|
3350
2638
|
);
|
|
3351
2639
|
}
|
|
3352
2640
|
if (scheme === "eip712_userop") {
|
|
3353
2641
|
if (!signData.typed_data) {
|
|
3354
|
-
throw new HavenSigningError(
|
|
2642
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3355
2643
|
"sign_data.signature_scheme is eip712_userop but typed_data is missing \u2014 refusing to sign the bare hash (the account would reject it)."
|
|
3356
2644
|
);
|
|
3357
2645
|
}
|
|
2646
|
+
chunkJKUIE45B_cjs.assertUserOpTypedDataBinding(signData.typed_data, signData.hash);
|
|
2647
|
+
chunkQSSVOPWA_cjs.assertBoundDirectPaymentUserOp(
|
|
2648
|
+
signData.typed_data,
|
|
2649
|
+
this.delegateAddress
|
|
2650
|
+
);
|
|
3358
2651
|
return signUserOpTypedDataForDelegation(this.delegateKey, signData.typed_data);
|
|
3359
2652
|
}
|
|
3360
2653
|
if (scheme === "eip712_delegation") {
|
|
3361
2654
|
if (!signData.typed_data) {
|
|
3362
|
-
throw new HavenSigningError(
|
|
2655
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3363
2656
|
"sign_data.signature_scheme is eip712_delegation but typed_data is missing \u2014 refusing to sign the bare hash (the settlement would be rejected on redemption)."
|
|
3364
2657
|
);
|
|
3365
2658
|
}
|
|
2659
|
+
if (!settlementExpectation) {
|
|
2660
|
+
throw new chunkQSSVOPWA_cjs.HavenTypedDataRefusedError(
|
|
2661
|
+
"Refusing to sign an x402 settlement child without an independent expectation of what it must pay (the merchant's 402). Pay erc7710 merchants through settleX402Erc7710(), which supplies it."
|
|
2662
|
+
);
|
|
2663
|
+
}
|
|
2664
|
+
chunkQSSVOPWA_cjs.assertOwnSettlementChild(signData.typed_data, settlementExpectation, this.delegateAddress);
|
|
3366
2665
|
return signSettlementDelegationTypedData(this.delegateKey, signData.typed_data);
|
|
3367
2666
|
}
|
|
3368
2667
|
if (scheme === void 0) {
|
|
3369
|
-
throw new HavenSigningError(
|
|
2668
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3370
2669
|
"sign_data.signature_scheme is required \u2014 the legacy AllowanceModule rail that signed the bare hash is retired (#2850). Refusing to guess a signing scheme."
|
|
3371
2670
|
);
|
|
3372
2671
|
}
|
|
3373
|
-
throw new HavenSigningError(
|
|
2672
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3374
2673
|
`Unknown sign_data.signature_scheme '${scheme}' \u2014 refusing to guess a signing scheme. Update @haven_ai/sdk.`
|
|
3375
2674
|
);
|
|
3376
2675
|
}
|
|
@@ -3423,11 +2722,12 @@ var HavenClient = class {
|
|
|
3423
2722
|
return this.accountReads.getAgentSummary();
|
|
3424
2723
|
}
|
|
3425
2724
|
/**
|
|
3426
|
-
* Sweep stranded USDC and ETH from the delegate EOA back to the
|
|
2725
|
+
* Sweep stranded USDC and ETH from the delegate EOA back to the agent's Haven account.
|
|
3427
2726
|
*
|
|
3428
2727
|
* The delegate key held by this client signs and submits the transfer transactions
|
|
3429
2728
|
* directly — Haven's backend never handles the key or constructs signed txs
|
|
3430
|
-
* (CASP/MiCA Red Line #2). Funds always go to the
|
|
2729
|
+
* (CASP/MiCA Red Line #2). Funds always go to the Haven account linked to this agent
|
|
2730
|
+
* (`accountAddress` from `getAgent()`).
|
|
3431
2731
|
*
|
|
3432
2732
|
* Requires `chainRpcs` to be set for the agent's chain in `HavenClientConfig`.
|
|
3433
2733
|
*/
|
|
@@ -3461,6 +2761,49 @@ var HavenClient = class {
|
|
|
3461
2761
|
async getAllowances() {
|
|
3462
2762
|
return this.accountReads.getAllowances();
|
|
3463
2763
|
}
|
|
2764
|
+
/**
|
|
2765
|
+
* #3126 — is the checked amount of the token actually HELD on the
|
|
2766
|
+
* agent's own account?
|
|
2767
|
+
*
|
|
2768
|
+
* This is the companion to {@link getAllowances}, not a variant of it:
|
|
2769
|
+
* allowances answer what the agent is PERMITTED to spend this period;
|
|
2770
|
+
* this answers whether the account HOLDS funds behind that permission,
|
|
2771
|
+
* as a sufficiency signal — `covered: true | false | null` — never as a
|
|
2772
|
+
* balance. `covered: null` means the chain read failed: treat it as
|
|
2773
|
+
* unverifiable, not as absence (`coverageError` says why). The account's
|
|
2774
|
+
* balance itself is deliberately not returned.
|
|
2775
|
+
*/
|
|
2776
|
+
async checkFunds(input) {
|
|
2777
|
+
return this.accountReads.checkFunds(input);
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* `POST /machine-payments/budget-precheck` (#3054): ask Haven to decide —
|
|
2781
|
+
* server-side — whether `amountAtomic` of `token` fits the agent's
|
|
2782
|
+
* remaining delegation budget, the same compare the guided prepare used to
|
|
2783
|
+
* run locally over its allowances read.
|
|
2784
|
+
*
|
|
2785
|
+
* On insufficiency Haven refuses (403, `delegation_budget_exceeded`) and
|
|
2786
|
+
* the refusal reaches the `payment_refusals` ledger with
|
|
2787
|
+
* `source: 'hosted_prepare'` — the point of the endpoint. This method
|
|
2788
|
+
* surfaces that decision as a thrown {@link HavenApiError}; it does NOT
|
|
2789
|
+
* swallow it, because swallowing would turn a decided refusal into the
|
|
2790
|
+
* degrade-to-warning path and the ledger row would still land while the
|
|
2791
|
+
* purchase proceeded.
|
|
2792
|
+
*
|
|
2793
|
+
* camelCase body like the route family; the response mirrors the wire
|
|
2794
|
+
* (`sufficient`, `remaining_atomic`). `resourceUrl` is the merchant
|
|
2795
|
+
* resource being bought — the ledger dedupe window's discriminating
|
|
2796
|
+
* column — never this request's own URL.
|
|
2797
|
+
*/
|
|
2798
|
+
async precheckBudget(input) {
|
|
2799
|
+
return this.post("/machine-payments/budget-precheck", {
|
|
2800
|
+
chainId: input.chainId,
|
|
2801
|
+
token: input.token,
|
|
2802
|
+
amountAtomic: input.amountAtomic,
|
|
2803
|
+
...input.merchantTo !== void 0 ? { merchantTo: input.merchantTo } : {},
|
|
2804
|
+
...input.resourceUrl !== void 0 ? { resourceUrl: input.resourceUrl } : {}
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
3464
2807
|
/**
|
|
3465
2808
|
* Post-purchase allowance/budget summary for a settled payment (#1310).
|
|
3466
2809
|
*
|
|
@@ -3510,7 +2853,7 @@ var HavenClient = class {
|
|
|
3510
2853
|
*/
|
|
3511
2854
|
async getPaymentStatusWithPostPurchaseAllowance(paymentId) {
|
|
3512
2855
|
const status = await this.getPaymentStatus(paymentId);
|
|
3513
|
-
if (status.rail === AgentPaymentRail.X402 && status.phase === AgentPaymentPhase.PaymentConfirmed) {
|
|
2856
|
+
if (status.rail === chunkJKUIE45B_cjs.AgentPaymentRail.X402 && status.phase === chunkJKUIE45B_cjs.AgentPaymentPhase.PaymentConfirmed) {
|
|
3514
2857
|
const { allowance, warnings } = await this.getPostPurchaseAllowanceSummary(paymentId);
|
|
3515
2858
|
return { ...status, allowance, ...warnings.length > 0 ? { warnings } : {} };
|
|
3516
2859
|
}
|
|
@@ -3583,6 +2926,10 @@ var HavenClient = class {
|
|
|
3583
2926
|
async listReceipts(options = {}) {
|
|
3584
2927
|
return this.accountReads.listReceipts(options);
|
|
3585
2928
|
}
|
|
2929
|
+
/** #3128: one page of receipts with `total`, `hasMore` and `nextCursor`. */
|
|
2930
|
+
async listReceiptsPage(options = {}) {
|
|
2931
|
+
return this.accountReads.listReceiptsPage(options);
|
|
2932
|
+
}
|
|
3586
2933
|
/**
|
|
3587
2934
|
* Fetch the verifiable receipt bundle for a settled payment and verify it
|
|
3588
2935
|
* locally. The server's own verification is ignored — the receipt is verified
|
|
@@ -3614,7 +2961,7 @@ var HavenClient = class {
|
|
|
3614
2961
|
}
|
|
3615
2962
|
await sleep(this.pollingInterval);
|
|
3616
2963
|
}
|
|
3617
|
-
throw new HavenTimeoutError(paymentId);
|
|
2964
|
+
throw new chunkJKUIE45B_cjs.HavenTimeoutError(paymentId);
|
|
3618
2965
|
}
|
|
3619
2966
|
// ── x402 Protocol Support ────────────────────────────────────────
|
|
3620
2967
|
/**
|
|
@@ -3628,18 +2975,18 @@ var HavenClient = class {
|
|
|
3628
2975
|
*/
|
|
3629
2976
|
async authorizeX402(paymentRequired, options = {}) {
|
|
3630
2977
|
if (!this.delegateKey) {
|
|
3631
|
-
throw new HavenSigningError(
|
|
2978
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3632
2979
|
"delegateKey is required for x402 payments. Pass it in the HavenClient config."
|
|
3633
2980
|
);
|
|
3634
2981
|
}
|
|
3635
2982
|
if (!this.delegateAddress) {
|
|
3636
|
-
throw new HavenSigningError("delegateAddress could not be derived from delegateKey.");
|
|
2983
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
|
|
3637
2984
|
}
|
|
3638
|
-
const option = selectStandardPaymentOption(paymentRequired.accepts);
|
|
2985
|
+
const option = chunkQSSVOPWA_cjs.selectStandardPaymentOption(paymentRequired.accepts);
|
|
3639
2986
|
if (!option) {
|
|
3640
2987
|
throw noCompatiblePaymentOptionError(paymentRequired.accepts);
|
|
3641
2988
|
}
|
|
3642
|
-
const idempotencyKey = options.idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option);
|
|
2989
|
+
const idempotencyKey = options.idempotencyKey ?? chunkQSSVOPWA_cjs.buildX402IdempotencyKey(paymentRequired, option);
|
|
3643
2990
|
const cached = this.fundingLeg.cachedReceipt(idempotencyKey);
|
|
3644
2991
|
if (cached) return cached;
|
|
3645
2992
|
const inFlight = this.inFlightX402.get(idempotencyKey);
|
|
@@ -3668,22 +3015,27 @@ var HavenClient = class {
|
|
|
3668
3015
|
const request = snapshotX402Request(url, initialInit);
|
|
3669
3016
|
const response = await this.merchantTransport.fetch(url, initialInit);
|
|
3670
3017
|
if (response.status !== 402) {
|
|
3018
|
+
const toolResultChallenge = await this.merchantTransport.extractToolResultChallenge(response, initialInit);
|
|
3019
|
+
if (toolResultChallenge) {
|
|
3020
|
+
const mcpTransport2 = await this.merchantTransport.detect(url, toolResultChallenge, response);
|
|
3021
|
+
return buildX402Quote(toolResultChallenge, request, options.idempotencyKey, mcpTransport2);
|
|
3022
|
+
}
|
|
3671
3023
|
let body;
|
|
3672
3024
|
try {
|
|
3673
3025
|
body = await response.clone().json();
|
|
3674
3026
|
} catch {
|
|
3675
3027
|
body = void 0;
|
|
3676
3028
|
}
|
|
3677
|
-
throw new X402UnexpectedStatusError(
|
|
3029
|
+
throw new chunkJKUIE45B_cjs.X402UnexpectedStatusError(
|
|
3678
3030
|
`Expected an x402 quote response with HTTP 402, got HTTP ${response.status}.`,
|
|
3679
3031
|
response.status || 400,
|
|
3680
3032
|
body
|
|
3681
3033
|
);
|
|
3682
3034
|
}
|
|
3683
3035
|
if (response.headers.get("MACHINE-PAYMENT-CHALLENGE")) {
|
|
3684
|
-
throw new HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
|
|
3036
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
|
|
3685
3037
|
}
|
|
3686
|
-
const paymentRequired = await parsePaymentRequiredResponse(response);
|
|
3038
|
+
const paymentRequired = await chunkQSSVOPWA_cjs.parsePaymentRequiredResponse(response);
|
|
3687
3039
|
const mcpTransport = await this.merchantTransport.detect(url, paymentRequired, response);
|
|
3688
3040
|
return buildX402Quote(paymentRequired, request, options.idempotencyKey, mcpTransport);
|
|
3689
3041
|
}
|
|
@@ -3701,7 +3053,7 @@ var HavenClient = class {
|
|
|
3701
3053
|
const wallet = await this.merchantCompletion.resolveWalletForMerchantCall();
|
|
3702
3054
|
const sessionId = await this.merchantTransport.initialize(url, init, wallet);
|
|
3703
3055
|
if (!sessionId) {
|
|
3704
|
-
throw new HavenApiError(
|
|
3056
|
+
throw new chunkJKUIE45B_cjs.HavenApiError(
|
|
3705
3057
|
"The merchant did not establish an MCP session before the x402 quote. No payment was created.",
|
|
3706
3058
|
502,
|
|
3707
3059
|
{ mcpSessionNotEstablished: true }
|
|
@@ -3775,18 +3127,18 @@ var HavenClient = class {
|
|
|
3775
3127
|
}
|
|
3776
3128
|
async resumeAuthorizedX402(input) {
|
|
3777
3129
|
if (!this.delegateKey) {
|
|
3778
|
-
throw new HavenSigningError(
|
|
3130
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError(
|
|
3779
3131
|
"delegateKey is required for x402 payments. Pass it in the HavenClient config."
|
|
3780
3132
|
);
|
|
3781
3133
|
}
|
|
3782
3134
|
if (!this.delegateAddress) {
|
|
3783
|
-
throw new HavenSigningError("delegateAddress could not be derived from delegateKey.");
|
|
3135
|
+
throw new chunkJKUIE45B_cjs.HavenSigningError("delegateAddress could not be derived from delegateKey.");
|
|
3784
3136
|
}
|
|
3785
|
-
const option = selectStandardPaymentOption(input.paymentRequired.accepts);
|
|
3137
|
+
const option = chunkQSSVOPWA_cjs.selectStandardPaymentOption(input.paymentRequired.accepts);
|
|
3786
3138
|
if (!option) {
|
|
3787
3139
|
throw noCompatiblePaymentOptionError(input.paymentRequired.accepts);
|
|
3788
3140
|
}
|
|
3789
|
-
const idempotencyKey = input.idempotencyKey ?? buildX402IdempotencyKey(input.paymentRequired, option);
|
|
3141
|
+
const idempotencyKey = input.idempotencyKey ?? chunkQSSVOPWA_cjs.buildX402IdempotencyKey(input.paymentRequired, option);
|
|
3790
3142
|
const cached = this.fundingLeg.cachedReceipt(idempotencyKey);
|
|
3791
3143
|
if (cached) return cached;
|
|
3792
3144
|
const status = await this.getPaymentStatus(input.paymentId);
|
|
@@ -3794,10 +3146,10 @@ var HavenClient = class {
|
|
|
3794
3146
|
const canFund = await this.fundingLeg.delegateCanFund(
|
|
3795
3147
|
status.chainId ?? chainIdFromNetwork(option.network),
|
|
3796
3148
|
option.asset,
|
|
3797
|
-
x402AuthorizationAmount(option)
|
|
3149
|
+
chunkQSSVOPWA_cjs.x402AuthorizationAmount(option)
|
|
3798
3150
|
);
|
|
3799
3151
|
if (canFund === false) {
|
|
3800
|
-
throw new X402AlreadySettledError(
|
|
3152
|
+
throw new chunkJKUIE45B_cjs.X402AlreadySettledError(
|
|
3801
3153
|
`x402 payment ${status.paymentId} has already settled \u2014 the delegate no longer holds the funds to authorize it again, so there is nothing left to resume.`,
|
|
3802
3154
|
this.fundingLeg.receiptFromStatus(input.paymentRequired, option, void 0, status),
|
|
3803
3155
|
"settled"
|
|
@@ -3818,13 +3170,13 @@ var HavenClient = class {
|
|
|
3818
3170
|
const url = input.url ?? input.request?.url;
|
|
3819
3171
|
if (!paymentRequired) {
|
|
3820
3172
|
if (!url) {
|
|
3821
|
-
throw new HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
|
|
3173
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
|
|
3822
3174
|
}
|
|
3823
3175
|
const response = await this.merchantTransport.fetch(url, initialInit);
|
|
3824
3176
|
if (response.status !== 402) {
|
|
3825
|
-
throw new HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
|
|
3177
|
+
throw new chunkJKUIE45B_cjs.HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
|
|
3826
3178
|
}
|
|
3827
|
-
paymentRequired = await parsePaymentRequiredResponse(response);
|
|
3179
|
+
paymentRequired = await chunkQSSVOPWA_cjs.parsePaymentRequiredResponse(response);
|
|
3828
3180
|
}
|
|
3829
3181
|
const receipt = await this.resumeAuthorizedX402({
|
|
3830
3182
|
paymentId: input.paymentId,
|
|
@@ -3834,10 +3186,11 @@ var HavenClient = class {
|
|
|
3834
3186
|
return this.merchantCompletion.retryRequest(url ?? paymentRequired.resource.url, initialInit, paymentRequired, receipt);
|
|
3835
3187
|
}
|
|
3836
3188
|
/**
|
|
3837
|
-
* Fetch wrapper that automatically handles HTTP 402 responses
|
|
3189
|
+
* Fetch wrapper that automatically handles HTTP 402 responses — and, since
|
|
3190
|
+
* #3118, a native-MCP payment-required tool result answered under HTTP 200.
|
|
3838
3191
|
*
|
|
3839
|
-
* Works like the standard `fetch()` but intercepts 402 responses
|
|
3840
|
-
* pays via x402 through Haven, and retries the request.
|
|
3192
|
+
* Works like the standard `fetch()` but intercepts 402 responses (or that
|
|
3193
|
+
* tool-result challenge), pays via x402 through Haven, and retries the request.
|
|
3841
3194
|
*
|
|
3842
3195
|
* ```ts
|
|
3843
3196
|
* const response = await haven.fetch('https://paid-api.com/data')
|
|
@@ -3845,8 +3198,9 @@ var HavenClient = class {
|
|
|
3845
3198
|
* ```
|
|
3846
3199
|
*
|
|
3847
3200
|
* **MCP-over-x402 auto-handshake (issue #315):** when the endpoint is
|
|
3848
|
-
* MCP-shaped — the URL path ends in `/mcp`, or the 402 body
|
|
3849
|
-
*
|
|
3201
|
+
* MCP-shaped — the URL path ends in `/mcp`, or the 402 body (or, since
|
|
3202
|
+
* #3118, the tool-result challenge) carries a Coinbase Bazaar
|
|
3203
|
+
* `extensions.bazaar` block — the SDK runs the MCP
|
|
3850
3204
|
* `initialize` handshake, threads the resulting `mcp-session-id`,
|
|
3851
3205
|
* `Accept: application/json, text/event-stream`, and `x402-wallet` headers
|
|
3852
3206
|
* through every request, and collapses SSE responses to the JSON-RPC
|
|
@@ -3864,22 +3218,29 @@ var HavenClient = class {
|
|
|
3864
3218
|
let requestInit = withX402Wallet(init, x402PayerAddress(this.delegateAddress, this.x402Wallet));
|
|
3865
3219
|
if (mcpSessionId) requestInit = this.merchantTransport.withSessionHeaders(requestInit, mcpSessionId);
|
|
3866
3220
|
const response = await this.merchantTransport.fetch(url, requestInit);
|
|
3867
|
-
if (response.status !== 402) {
|
|
3868
|
-
return mcpSessionId ? this.merchantTransport.surfaceResult(response) : response;
|
|
3869
|
-
}
|
|
3870
3221
|
let paymentRequired;
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3222
|
+
let nativeChallenge = false;
|
|
3223
|
+
if (response.status !== 402) {
|
|
3224
|
+
const toolResultChallenge = await this.merchantTransport.extractToolResultChallenge(response, requestInit);
|
|
3225
|
+
if (!toolResultChallenge) {
|
|
3226
|
+
return mcpSessionId ? this.merchantTransport.surfaceResult(response) : response;
|
|
3227
|
+
}
|
|
3228
|
+
paymentRequired = toolResultChallenge;
|
|
3229
|
+
nativeChallenge = true;
|
|
3230
|
+
} else {
|
|
3231
|
+
try {
|
|
3232
|
+
paymentRequired = await chunkQSSVOPWA_cjs.parsePaymentRequiredResponse(response);
|
|
3233
|
+
} catch {
|
|
3234
|
+
return response;
|
|
3235
|
+
}
|
|
3875
3236
|
}
|
|
3876
|
-
if (!mcpSessionId && await this.merchantTransport.hasBazaarExtension(response)) {
|
|
3237
|
+
if (!mcpSessionId && (paymentRequired.extensions?.bazaar != null || await this.merchantTransport.hasBazaarExtension(response))) {
|
|
3877
3238
|
mcpSessionId = await this.merchantTransport.initialize(url, init);
|
|
3878
3239
|
if (mcpSessionId) requestInit = this.merchantTransport.withSessionHeaders(requestInit, mcpSessionId);
|
|
3879
3240
|
}
|
|
3880
3241
|
const request = snapshotX402Request(url, requestInit);
|
|
3881
|
-
const option = selectStandardPaymentOption(paymentRequired.accepts);
|
|
3882
|
-
const idempotencyKey = options.idempotencyKey ?? (option ? buildX402IdempotencyKey(paymentRequired, option) : void 0);
|
|
3242
|
+
const option = chunkQSSVOPWA_cjs.selectStandardPaymentOption(paymentRequired.accepts);
|
|
3243
|
+
const idempotencyKey = options.idempotencyKey ?? (option ? chunkQSSVOPWA_cjs.buildX402IdempotencyKey(paymentRequired, option) : void 0);
|
|
3883
3244
|
let receipt;
|
|
3884
3245
|
try {
|
|
3885
3246
|
receipt = await this.authorizeX402(paymentRequired, options);
|
|
@@ -3895,7 +3256,7 @@ var HavenClient = class {
|
|
|
3895
3256
|
throw err;
|
|
3896
3257
|
}
|
|
3897
3258
|
const retryResponse = await this.merchantCompletion.retryRequest(url, requestInit, paymentRequired, receipt);
|
|
3898
|
-
return mcpSessionId ? this.merchantTransport.surfaceResult(retryResponse) : retryResponse;
|
|
3259
|
+
return mcpSessionId || nativeChallenge ? this.merchantTransport.surfaceResult(retryResponse) : retryResponse;
|
|
3899
3260
|
}
|
|
3900
3261
|
/**
|
|
3901
3262
|
* Deliver an already-signed x402 payment header to the merchant and return
|
|
@@ -3916,7 +3277,7 @@ var HavenClient = class {
|
|
|
3916
3277
|
* collapses an SSE JSON-RPC response to its `result`.
|
|
3917
3278
|
*/
|
|
3918
3279
|
/**
|
|
3919
|
-
* Wait for a payment's
|
|
3280
|
+
* Wait for a payment's account→delegate funding tx to reach ≥1 on-chain
|
|
3920
3281
|
* confirmation. The hosted x402 completion path MUST call this after funding
|
|
3921
3282
|
* and before delivering the merchant payment header, so the merchant's
|
|
3922
3283
|
* balanceOf(delegate) / transferWithAuthorization verification sees the funded
|
|
@@ -3955,10 +3316,13 @@ var HavenClient = class {
|
|
|
3955
3316
|
}
|
|
3956
3317
|
let requestInit = withX402Wallet(input.init, x402Wallet) ?? {};
|
|
3957
3318
|
if (mcpSessionId) requestInit = this.merchantTransport.withSessionHeaders(requestInit, mcpSessionId);
|
|
3958
|
-
const response = await this.merchantTransport.
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3319
|
+
const response = await this.merchantTransport.deliverPaymentRecoveringSession(
|
|
3320
|
+
input.url,
|
|
3321
|
+
requestInit,
|
|
3322
|
+
input.paymentHeader,
|
|
3323
|
+
() => this.merchantTransport.initialize(input.url, input.init, x402Wallet)
|
|
3324
|
+
);
|
|
3325
|
+
const surfaced = await this.merchantTransport.surfaceResult(response);
|
|
3962
3326
|
const text = await surfaced.text();
|
|
3963
3327
|
let body;
|
|
3964
3328
|
try {
|
|
@@ -3966,8 +3330,16 @@ var HavenClient = class {
|
|
|
3966
3330
|
} catch {
|
|
3967
3331
|
body = text;
|
|
3968
3332
|
}
|
|
3333
|
+
const toolResult = mcpToolResultOf(body);
|
|
3334
|
+
const inBandChallenge = toolResult ? extractMcpPaymentRequired(toolResult) : void 0;
|
|
3335
|
+
const metaSettlement = toolResult ? mcpSettlementFromToolResult(toolResult) : void 0;
|
|
3336
|
+
const headerReceipt = surfaced.headers.get("PAYMENT-RESPONSE") ?? void 0;
|
|
3337
|
+
const protocolReceiptHeaderName = headerReceipt ? "PAYMENT-RESPONSE" : metaSettlement ? `_meta.${MCP_X402_PAYMENT_RESPONSE_META_KEY}` : void 0;
|
|
3338
|
+
const protocolReceiptHeader = headerReceipt ?? (metaSettlement ? encodeMcpSettlementReceipt(metaSettlement) : void 0);
|
|
3339
|
+
const settlement = parseMerchantSettlement(protocolReceiptHeader ?? null);
|
|
3340
|
+
const merchantAccepted = surfaced.ok && inBandChallenge === void 0 && metaSettlement?.success !== false;
|
|
3969
3341
|
let evidenceOutcome;
|
|
3970
|
-
if (!
|
|
3342
|
+
if (!merchantAccepted) {
|
|
3971
3343
|
if (!input.noFundingLeg && fundingTxHash) {
|
|
3972
3344
|
await this.merchantCompletion.recordRetryRejected({
|
|
3973
3345
|
rail: "x402",
|
|
@@ -3995,9 +3367,9 @@ var HavenClient = class {
|
|
|
3995
3367
|
txHash: evidenceTxHash,
|
|
3996
3368
|
resourceUrl: evidenceContext.resourceUrl,
|
|
3997
3369
|
merchantStatus: surfaced.status,
|
|
3998
|
-
paymentProofHeaderName: x402PaymentHeaderNamesSent(input.paymentHeader),
|
|
3370
|
+
paymentProofHeaderName: chunkQSSVOPWA_cjs.x402PaymentHeaderNamesSent(input.paymentHeader),
|
|
3999
3371
|
paymentProofHeader: input.paymentHeader,
|
|
4000
|
-
protocolReceiptHeaderName
|
|
3372
|
+
protocolReceiptHeaderName,
|
|
4001
3373
|
protocolReceiptHeader
|
|
4002
3374
|
});
|
|
4003
3375
|
}
|
|
@@ -4005,9 +3377,10 @@ var HavenClient = class {
|
|
|
4005
3377
|
}
|
|
4006
3378
|
return {
|
|
4007
3379
|
status: surfaced.status,
|
|
4008
|
-
ok:
|
|
3380
|
+
ok: merchantAccepted,
|
|
4009
3381
|
body,
|
|
4010
|
-
|
|
3382
|
+
// #3155 review S3: a transaction beside a rejection is not a settlement.
|
|
3383
|
+
settlementTxHash: merchantAccepted ? settlement.settlementTxHash ?? void 0 : void 0,
|
|
4011
3384
|
evidenceOutcome
|
|
4012
3385
|
};
|
|
4013
3386
|
}
|
|
@@ -4197,12 +3570,12 @@ var toolDescriptions = {
|
|
|
4197
3570
|
payX402OneShot: {
|
|
4198
3571
|
summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.",
|
|
4199
3572
|
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.",
|
|
4200
|
-
behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only) and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.",
|
|
3573
|
+
behavior: "Calls the URL, parses any HTTP 402 x402 challenge (or, since #3118, a native-MCP payment-required tool result under HTTP 200), signs the payment locally, then retries the original request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only) and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status with no payment-required tool result, returns it unchanged without contacting Haven.",
|
|
4201
3574
|
nextActionGuidance: "Preserve the returned resume_state or paymentId \u2014 either identifies this payment if you need to ask about it later. This tool performs the merchant retry itself, so do not wait on a signal while the call is in flight. If the process crashes after this call and a later haven_get_payment_status reports nextAction=retry_original_x402_request, Haven's funding leg confirmed but no merchant response was ever recorded \u2014 call the resume tool with the preserved resume_state or payment_id instead of paying again. If the response carries phase=insufficient_funds and nextAction=fund_account_or_raise_allowance, the payment cannot be retried until the account is funded or the agent budget raised \u2014 stop and tell the user the shortfall reported on the response."
|
|
4202
3575
|
},
|
|
4203
3576
|
resumeX402: {
|
|
4204
3577
|
summary: "Resume an x402 payment whose Haven-side authorization already succeeded but whose merchant retry did not complete.",
|
|
4205
|
-
behavior: "Accepts either resume_state or payment_id, validates the
|
|
3578
|
+
behavior: "Accepts either resume_state or payment_id, validates the x402 details against the authorized funding, and retries the merchant request with the signed payment header (PAYMENT-SIGNATURE, plus legacy X-PAYMENT on EIP-3009 only; also params._meta on an MCP tools/call body). No new Haven payment is created.",
|
|
4206
3579
|
nextActionGuidance: "Only call this after haven_get_payment_status reports nextAction=retry_original_x402_request \u2014 that means Haven's funding leg confirmed but no merchant response was ever recorded, most often because the process crashed between funding and the merchant retry. Any other nextAction reports a conflict instead of retrying, so do not call this speculatively. Do not start a new merchant session and do not pay again \u2014 that would pay twice for one resource."
|
|
4207
3580
|
},
|
|
4208
3581
|
// #1328: quoteMpp / payMpp / resumeMpp (the mpp_demo challenge/quote/resume
|
|
@@ -4220,21 +3593,29 @@ var toolDescriptions = {
|
|
|
4220
3593
|
nextActionGuidance: ""
|
|
4221
3594
|
},
|
|
4222
3595
|
getAgent: {
|
|
4223
|
-
summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness,
|
|
4224
|
-
selectionGuidance: "Use this as the
|
|
4225
|
-
behavior:
|
|
3596
|
+
summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness, per-token remaining allowance (atomic + human-readable). The recommended first call in a new session.",
|
|
3597
|
+
selectionGuidance: "Use this as the session bootstrap, or to confirm identity together with whether the agent can spend right now. For per-token detail (configured vs spent vs reset window) use haven_get_allowances.",
|
|
3598
|
+
behavior: 'Reads identity plus the live spend-authority snapshot \u2014 the active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is "ready" when at least one token has remaining spend authority, "needs_approval" when the agent is active but has none, and "revoked" when the credential is not active. It covers hosted identity + on-chain spend authority ONLY \u2014 the hosted server cannot see the LOCAL signer, so "ready" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves; there is no approval queue \u2014 ask the owner to grant or raise the budget in Haven. allowances[] carries id, tokenAddress, remainingAtomic, remainingDisplay per token. Identity fields: id, name, status, accountAddress, delegateAddress, chainId.',
|
|
4226
3599
|
nextActionGuidance: ""
|
|
4227
3600
|
},
|
|
4228
3601
|
getAllowances: {
|
|
4229
3602
|
summary: "Return configured and on-chain allowance state for the authenticated agent. On-chain allowance is the real spend gate.",
|
|
4230
|
-
selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend.",
|
|
4231
|
-
behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary). An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside.",
|
|
3603
|
+
selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend. For whether the account actually HOLDS funds behind the budget use haven_check_funds.",
|
|
3604
|
+
behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary), each with id, onchain.remaining, remainingDisplay. An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside.",
|
|
4232
3605
|
nextActionGuidance: ""
|
|
4233
3606
|
},
|
|
3607
|
+
// #3126 — the sufficiency signal, deliberately NOT a balance tool. The
|
|
3608
|
+
// constrained actor reads a boolean, never the treasury total.
|
|
3609
|
+
checkFunds: {
|
|
3610
|
+
summary: "Check whether the agent's account actually holds at least the given amount of a token \u2014 funds held, not spend permitted.",
|
|
3611
|
+
selectionGuidance: "Use this before attempting a payment when it matters whether the money is really there: allowance answers say what you are PERMITTED to spend, never whether the account HOLDS it. For allowance, budget, spend-limit, remaining-budget, reset-period, or what-can-I-spend questions use the allowance lookup tool instead.",
|
|
3612
|
+
behavior: "Returns covered: true (the account holds at least the checked amount), false (a live chain read reports less \u2014 the budget is backed by an empty account; stop and tell the user funds are missing), or null (the chain read failed \u2014 unverifiable, never treat it as absence; coverageError says why). The account balance itself is deliberately not returned: this is a sufficiency signal, not a balance read. budget_remaining_atomic is the permitted figure from the allowance lookup (the SDK spells it budgetRemainingAtomic), named so it can never be confused with holdings.",
|
|
3613
|
+
nextActionGuidance: "On covered=false, do not attempt the payment \u2014 tell the user the account is short and let them fund it; on covered=null, retry the check shortly or proceed knowing the payment may fail on-chain."
|
|
3614
|
+
},
|
|
4234
3615
|
listReceipts: {
|
|
4235
|
-
summary: "List
|
|
4236
|
-
selectionGuidance: "
|
|
4237
|
-
behavior: "
|
|
3616
|
+
summary: "List machine-payment receipts, newest first, by page.",
|
|
3617
|
+
selectionGuidance: "This agent's payment evidence, not the wallet's transaction history (sweeps, funding legs, other agents); use the allowance tool instead for remaining allowance or what-can-I-spend questions.",
|
|
3618
|
+
behavior: "Page { receipts, total, hasMore, nextCursor }; hasMore: pass nextCursor as cursor. parties.treasuryAccount is Haven's authoritative payer. protocolReceiptPayload is the merchant's PAYMENT-RESPONSE relayed verbatim: merchant-controlled, unverified, not Haven's record; payer may differ from payerAddress. Proof header values omitted.",
|
|
4238
3619
|
nextActionGuidance: ""
|
|
4239
3620
|
},
|
|
4240
3621
|
verifyReceipt: {
|
|
@@ -4250,10 +3631,10 @@ var toolDescriptions = {
|
|
|
4250
3631
|
nextActionGuidance: "On a decline, report the reason to the user and ask them to raise the budget in Haven \u2014 there is no approval queue to wait on. This tool retries the merchant itself while it runs, so do not wait on a signal mid-call. If the process crashes after payment, a later haven_get_payment_status call may report nextAction=retry_original_x402_request \u2014 resume via haven_resume_x402_payment instead of paying again."
|
|
4251
3632
|
},
|
|
4252
3633
|
discoverTools: {
|
|
4253
|
-
summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices,
|
|
4254
|
-
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. Use verified=verified for entries Haven watched pass a live quote probe (operator-curated or self-submitted) \u2014 domain_verified is the only ownership claim; never treat these badges as proof of merchant honesty, quality, or reliability. 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
|
|
4255
|
-
behavior: "Use each entry's suggested_tool
|
|
4256
|
-
nextActionGuidance: `
|
|
3634
|
+
summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog \u2014 names, prices, the next call.",
|
|
3635
|
+
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. Use verified=verified for entries Haven watched pass a live quote probe (operator-curated or self-submitted) \u2014 domain_verified is the only ownership claim; never treat these badges as proof of merchant honesty, quality, or reliability. 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 next tool to call.",
|
|
3636
|
+
behavior: "Use each entry's suggested_tool + suggested_arguments first; an entry without them says why. 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, the hint, and the provenance badges source/domain_verified/verified_payable. 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.",
|
|
3637
|
+
nextActionGuidance: `Call suggested_tool with suggested_arguments VERBATIM (no hint: read suggested_tool_omitted_reason). Confirm the price from the live quote or pay result, not the catalog; if the next tool takes a cap, pass the user's cap as max_amount_human in whole tokens ("no more than 1 USDC" \u2192 max_amount_human: "1"), never atomic units by hand.`
|
|
4257
3638
|
},
|
|
4258
3639
|
submitCatalogEntry: {
|
|
4259
3640
|
summary: "Submit a merchant's payable (x402/MCP) endpoint to Haven's Verified Payable Directory for verification and listing.",
|
|
@@ -4263,14 +3644,14 @@ var toolDescriptions = {
|
|
|
4263
3644
|
},
|
|
4264
3645
|
sweep_delegate: {
|
|
4265
3646
|
summary: "Sweep stranded USDC and/or ETH from the delegate wallet back to the originating account.",
|
|
4266
|
-
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.",
|
|
3647
|
+
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, or haven_check_funds for whether the account holds funds.",
|
|
4267
3648
|
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 account (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. Each transfer carries confirmation: "confirmed" (a receipt was seen \u2014 the funds are in the account) or "unconfirmed" (broadcast but not confirmed within 90 seconds \u2014 still in the mempool, may still land). The top-level unconfirmed flag is true when any transfer is unconfirmed.`,
|
|
4268
3649
|
nextActionGuidance: 'If transfers is non-empty, confirm the amounts with the user. Report a transfer as recovered ONLY when its confirmation is "confirmed". For an "unconfirmed" transfer, tell the user it was submitted but not yet confirmed, give them its txHash and explorerUrl to check, and do not re-run the sweep immediately \u2014 a re-run after it lands will simply find nothing stranded.'
|
|
4269
3650
|
},
|
|
4270
3651
|
send: {
|
|
4271
3652
|
summary: "Send ETH or USDC directly from the agent's Haven wallet to a recipient address.",
|
|
4272
|
-
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.",
|
|
4273
|
-
behavior: "Sends the
|
|
3653
|
+
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. Do NOT use to check whether funds are held before sending \u2014 use haven_check_funds.",
|
|
3654
|
+
behavior: "Sends the amount by redeeming the agent's on-chain budget delegation, account to recipient with no funding leg. Budget, recipient and expiry are enforced on-chain while the transfer is prepared, so a request outside them is declined before any money moves or any signing \u2014 never queued for a human to approve. The agent's signing key signs the account's typed data, refusing any that mismatches the payment's hash; Haven never receives the key.",
|
|
4274
3655
|
nextActionGuidance: "On a decline, report the reason to the user and ask them to grant or raise the budget in Haven \u2014 there is nothing to poll and no approval will arrive. After a successful send, poll haven_get_payment_status until nextAction=none."
|
|
4275
3656
|
},
|
|
4276
3657
|
reportSettlementEvidence: {
|
|
@@ -4648,8 +4029,10 @@ the \`mcp__haven-signer__\` namespace and keep the delegate key on this machine.
|
|
|
4648
4029
|
That namespacing is Claude-family; other runtimes name the servers by their
|
|
4649
4030
|
own config keys (Codex: \`haven\`, \`haven_signer\`). Tool results carry the
|
|
4650
4031
|
exact next step (\`next_action\`, \`next_tool\`, \`next_arguments\`, plus the
|
|
4651
|
-
runtime-neutral \`next_tool_server\` + \`next_tool_name\`
|
|
4652
|
-
on that logical server, whatever your runtime calls it).
|
|
4032
|
+
runtime-neutral \`next_tool_server\` + \`next_tool_name\` + \`next_tool_server_role\`
|
|
4033
|
+
\u2014 the bare tool name on that logical server, whatever your runtime calls it).
|
|
4034
|
+
When no tool follows, \`next_tool\` is absent and \`next_tool_omitted_reason\`
|
|
4035
|
+
says why; that is a complete answer.
|
|
4653
4036
|
Follow those fields first; the prose below is fallback and orientation, not
|
|
4654
4037
|
the source of truth.
|
|
4655
4038
|
|
|
@@ -4736,6 +4119,13 @@ spending:
|
|
|
4736
4119
|
local signer; the signer is verified by calling any signer tool.
|
|
4737
4120
|
- \`mcp__haven__haven_get_allowances\` \u2014 detailed per-token breakdown
|
|
4738
4121
|
(configured, spent, reset window) when you need more than the summary.
|
|
4122
|
+
- \`mcp__haven__haven_check_funds\` \u2014 whether the account actually HOLDS at
|
|
4123
|
+
least a given amount of a token. Allowance answers above say what you are
|
|
4124
|
+
permitted to spend; this one says whether the money is really there,
|
|
4125
|
+
answered as \`covered\` true/false/null \u2014 never as a balance. On
|
|
4126
|
+
\`covered: false\`, stop and tell the user the account is short; on
|
|
4127
|
+
\`covered: null\` (the chain read failed), treat it as unverifiable rather
|
|
4128
|
+
than as absence.
|
|
4739
4129
|
|
|
4740
4130
|
Budgets reset on a period the user chose. If a payment exceeds the remaining
|
|
4741
4131
|
budget it is declined before any money moves \u2014 tell the user; they can raise
|
|
@@ -4864,8 +4254,10 @@ check on in-flight payments. Do not poll in a tight loop.
|
|
|
4864
4254
|
## Failure handling
|
|
4865
4255
|
|
|
4866
4256
|
Haven tool failures are shaped like \`{ success: false, code, message, ... }\`
|
|
4867
|
-
or older \`{ error, status, details? }\` responses.
|
|
4868
|
-
|
|
4257
|
+
or older \`{ error, status, details? }\` responses. A failure carries the same
|
|
4258
|
+
\`next_action\` / \`next_tool\` / \`next_arguments\` / \`next_tool_omitted_reason\`
|
|
4259
|
+
fields a success does; follow them first, then branch on \`code\` and surface
|
|
4260
|
+
\`message\` or \`error\` verbatim. Common cases:
|
|
4869
4261
|
|
|
4870
4262
|
- \`insufficient_funds\`: the Haven wallet doesn't hold enough of that token.
|
|
4871
4263
|
Suggest the user add funds in the Haven dashboard.
|
|
@@ -4926,45 +4318,6 @@ for that credential.
|
|
|
4926
4318
|
var SKILL_FOLDER_NAME = "haven-pay";
|
|
4927
4319
|
var HAVEN_SKILL_BODY_MD = HAVEN_SKILL_MD.replace(/^---\n[\s\S]*?\n---\n+/, "");
|
|
4928
4320
|
|
|
4929
|
-
// src/node-version.ts
|
|
4930
|
-
var HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
|
|
4931
|
-
function parseNodeVersion(value) {
|
|
4932
|
-
const match = value.trim().match(/^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
4933
|
-
if (!match) return [0, 0, 0];
|
|
4934
|
-
return [Number(match[1] ?? 0), Number(match[2] ?? 0), Number(match[3] ?? 0)];
|
|
4935
|
-
}
|
|
4936
|
-
function compareNodeVersions(left, right) {
|
|
4937
|
-
const leftParts = parseNodeVersion(left);
|
|
4938
|
-
const rightParts = parseNodeVersion(right);
|
|
4939
|
-
for (let i = 0; i < 3; i += 1) {
|
|
4940
|
-
if (leftParts[i] !== rightParts[i]) return leftParts[i] > rightParts[i] ? 1 : -1;
|
|
4941
|
-
}
|
|
4942
|
-
return 0;
|
|
4943
|
-
}
|
|
4944
|
-
function isSupportedNodeVersion(nodeVersion = process.versions.node, minimumNodeVersion = HAVEN_MINIMUM_NODE_VERSION) {
|
|
4945
|
-
return compareNodeVersions(nodeVersion, minimumNodeVersion) >= 0;
|
|
4946
|
-
}
|
|
4947
|
-
function unsupportedNodeVersionMessage(options) {
|
|
4948
|
-
const nodeVersion = options.nodeVersion ?? process.versions.node;
|
|
4949
|
-
const minimum = options.minimumNodeVersion ?? HAVEN_MINIMUM_NODE_VERSION;
|
|
4950
|
-
const lines = [
|
|
4951
|
-
`${options.subject} requires Node.js >=${minimum}, but this is Node.js ${nodeVersion}.`,
|
|
4952
|
-
"",
|
|
4953
|
-
"Upgrade Node, then try again:",
|
|
4954
|
-
` nvm install ${major(minimum)} && nvm use ${major(minimum)} (nvm)`,
|
|
4955
|
-
` fnm install ${major(minimum)} && fnm use ${major(minimum)} (fnm)`,
|
|
4956
|
-
` volta install node@${major(minimum)} (volta)`,
|
|
4957
|
-
` or download Node ${major(minimum)} from https://nodejs.org`,
|
|
4958
|
-
"",
|
|
4959
|
-
"If you use a version manager, check that the agent runtime launching Haven picks up the same version \u2014 upgrading your shell does not always change what a desktop app spawns."
|
|
4960
|
-
];
|
|
4961
|
-
if (options.retryHint) lines.push("", options.retryHint);
|
|
4962
|
-
return lines.join("\n");
|
|
4963
|
-
}
|
|
4964
|
-
function major(version) {
|
|
4965
|
-
return String(parseNodeVersion(version)[0]);
|
|
4966
|
-
}
|
|
4967
|
-
|
|
4968
4321
|
// src/merchant-discovery.ts
|
|
4969
4322
|
var MERCHANT_DISCOVERY_PATHS = ["/.well-known/haven-demo-merchant", "/"];
|
|
4970
4323
|
var DISCOVERY_MAX_BYTES = 64 * 1024;
|
|
@@ -5009,6 +4362,438 @@ function sameUrl(a, b) {
|
|
|
5009
4362
|
}
|
|
5010
4363
|
}
|
|
5011
4364
|
|
|
4365
|
+
Object.defineProperty(exports, "DEFAULT_NEXT_TOOL_BY_ACTION", {
|
|
4366
|
+
enumerable: true,
|
|
4367
|
+
get: function () { return chunkQSSVOPWA_cjs.DEFAULT_NEXT_TOOL_BY_ACTION; }
|
|
4368
|
+
});
|
|
4369
|
+
Object.defineProperty(exports, "ERC7710_ASSET_TRANSFER_METHOD", {
|
|
4370
|
+
enumerable: true,
|
|
4371
|
+
get: function () { return chunkQSSVOPWA_cjs.ERC7710_ASSET_TRANSFER_METHOD; }
|
|
4372
|
+
});
|
|
4373
|
+
Object.defineProperty(exports, "HAVEN_CLIENT_HEADER", {
|
|
4374
|
+
enumerable: true,
|
|
4375
|
+
get: function () { return chunkQSSVOPWA_cjs.HAVEN_CLIENT_HEADER; }
|
|
4376
|
+
});
|
|
4377
|
+
Object.defineProperty(exports, "HAVEN_MINIMUM_NODE_VERSION", {
|
|
4378
|
+
enumerable: true,
|
|
4379
|
+
get: function () { return chunkQSSVOPWA_cjs.HAVEN_MINIMUM_NODE_VERSION; }
|
|
4380
|
+
});
|
|
4381
|
+
Object.defineProperty(exports, "HavenTypedDataRefusedError", {
|
|
4382
|
+
enumerable: true,
|
|
4383
|
+
get: function () { return chunkQSSVOPWA_cjs.HavenTypedDataRefusedError; }
|
|
4384
|
+
});
|
|
4385
|
+
Object.defineProperty(exports, "NEXT_TOOL_SERVER_NAMES", {
|
|
4386
|
+
enumerable: true,
|
|
4387
|
+
get: function () { return chunkQSSVOPWA_cjs.NEXT_TOOL_SERVER_NAMES; }
|
|
4388
|
+
});
|
|
4389
|
+
Object.defineProperty(exports, "NEXT_TOOL_SERVER_ROLES", {
|
|
4390
|
+
enumerable: true,
|
|
4391
|
+
get: function () { return chunkQSSVOPWA_cjs.NEXT_TOOL_SERVER_ROLES; }
|
|
4392
|
+
});
|
|
4393
|
+
Object.defineProperty(exports, "SDK_CLIENT_IDENTITY", {
|
|
4394
|
+
enumerable: true,
|
|
4395
|
+
get: function () { return chunkQSSVOPWA_cjs.SDK_CLIENT_IDENTITY; }
|
|
4396
|
+
});
|
|
4397
|
+
Object.defineProperty(exports, "SDK_VERSION", {
|
|
4398
|
+
enumerable: true,
|
|
4399
|
+
get: function () { return chunkQSSVOPWA_cjs.SDK_VERSION; }
|
|
4400
|
+
});
|
|
4401
|
+
Object.defineProperty(exports, "SWEEP_BASE_CHAIN_ID", {
|
|
4402
|
+
enumerable: true,
|
|
4403
|
+
get: function () { return chunkQSSVOPWA_cjs.SWEEP_BASE_CHAIN_ID; }
|
|
4404
|
+
});
|
|
4405
|
+
Object.defineProperty(exports, "SWEEP_BASE_SEPOLIA_CHAIN_ID", {
|
|
4406
|
+
enumerable: true,
|
|
4407
|
+
get: function () { return chunkQSSVOPWA_cjs.SWEEP_BASE_SEPOLIA_CHAIN_ID; }
|
|
4408
|
+
});
|
|
4409
|
+
Object.defineProperty(exports, "SWEEP_BASE_SEPOLIA_USDC_ADDRESS", {
|
|
4410
|
+
enumerable: true,
|
|
4411
|
+
get: function () { return chunkQSSVOPWA_cjs.SWEEP_BASE_SEPOLIA_USDC_ADDRESS; }
|
|
4412
|
+
});
|
|
4413
|
+
Object.defineProperty(exports, "SWEEP_BASE_USDC_ADDRESS", {
|
|
4414
|
+
enumerable: true,
|
|
4415
|
+
get: function () { return chunkQSSVOPWA_cjs.SWEEP_BASE_USDC_ADDRESS; }
|
|
4416
|
+
});
|
|
4417
|
+
Object.defineProperty(exports, "TRANSFER_WITH_AUTHORIZATION_TYPES", {
|
|
4418
|
+
enumerable: true,
|
|
4419
|
+
get: function () { return chunkQSSVOPWA_cjs.TRANSFER_WITH_AUTHORIZATION_TYPES; }
|
|
4420
|
+
});
|
|
4421
|
+
Object.defineProperty(exports, "TYPED_DATA_NOT_ALLOWED", {
|
|
4422
|
+
enumerable: true,
|
|
4423
|
+
get: function () { return chunkQSSVOPWA_cjs.TYPED_DATA_NOT_ALLOWED; }
|
|
4424
|
+
});
|
|
4425
|
+
Object.defineProperty(exports, "X402PaymentHeaderValidationError", {
|
|
4426
|
+
enumerable: true,
|
|
4427
|
+
get: function () { return chunkQSSVOPWA_cjs.X402PaymentHeaderValidationError; }
|
|
4428
|
+
});
|
|
4429
|
+
Object.defineProperty(exports, "X402_LEGACY_PAYMENT_HEADER_NAME", {
|
|
4430
|
+
enumerable: true,
|
|
4431
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_LEGACY_PAYMENT_HEADER_NAME; }
|
|
4432
|
+
});
|
|
4433
|
+
Object.defineProperty(exports, "X402_MAX_AUTHORIZATION_WINDOW_SECONDS", {
|
|
4434
|
+
enumerable: true,
|
|
4435
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_MAX_AUTHORIZATION_WINDOW_SECONDS; }
|
|
4436
|
+
});
|
|
4437
|
+
Object.defineProperty(exports, "X402_PAYMENT_HEADER_NAME", {
|
|
4438
|
+
enumerable: true,
|
|
4439
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_PAYMENT_HEADER_NAME; }
|
|
4440
|
+
});
|
|
4441
|
+
Object.defineProperty(exports, "X402_PAYMENT_HEADER_NAMES_SENT", {
|
|
4442
|
+
enumerable: true,
|
|
4443
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_PAYMENT_HEADER_NAMES_SENT; }
|
|
4444
|
+
});
|
|
4445
|
+
Object.defineProperty(exports, "X402_PAYMENT_REQUIRED_HEADER_NAME", {
|
|
4446
|
+
enumerable: true,
|
|
4447
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_PAYMENT_REQUIRED_HEADER_NAME; }
|
|
4448
|
+
});
|
|
4449
|
+
Object.defineProperty(exports, "X402_PAYMENT_RESPONSE_HEADER_NAME", {
|
|
4450
|
+
enumerable: true,
|
|
4451
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_PAYMENT_RESPONSE_HEADER_NAME; }
|
|
4452
|
+
});
|
|
4453
|
+
Object.defineProperty(exports, "X402_SETTLEMENT_FORWARD_MARGIN_SECONDS", {
|
|
4454
|
+
enumerable: true,
|
|
4455
|
+
get: function () { return chunkQSSVOPWA_cjs.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS; }
|
|
4456
|
+
});
|
|
4457
|
+
Object.defineProperty(exports, "assertBoundDirectPaymentUserOp", {
|
|
4458
|
+
enumerable: true,
|
|
4459
|
+
get: function () { return chunkQSSVOPWA_cjs.assertBoundDirectPaymentUserOp; }
|
|
4460
|
+
});
|
|
4461
|
+
Object.defineProperty(exports, "buildSweepAuthorizationMessage", {
|
|
4462
|
+
enumerable: true,
|
|
4463
|
+
get: function () { return chunkQSSVOPWA_cjs.buildSweepAuthorizationMessage; }
|
|
4464
|
+
});
|
|
4465
|
+
Object.defineProperty(exports, "buildSweepTypedData", {
|
|
4466
|
+
enumerable: true,
|
|
4467
|
+
get: function () { return chunkQSSVOPWA_cjs.buildSweepTypedData; }
|
|
4468
|
+
});
|
|
4469
|
+
Object.defineProperty(exports, "buildX402ExpectedMessage", {
|
|
4470
|
+
enumerable: true,
|
|
4471
|
+
get: function () { return chunkQSSVOPWA_cjs.buildX402ExpectedMessage; }
|
|
4472
|
+
});
|
|
4473
|
+
Object.defineProperty(exports, "compareNodeVersions", {
|
|
4474
|
+
enumerable: true,
|
|
4475
|
+
get: function () { return chunkQSSVOPWA_cjs.compareNodeVersions; }
|
|
4476
|
+
});
|
|
4477
|
+
Object.defineProperty(exports, "createNextStepBuilder", {
|
|
4478
|
+
enumerable: true,
|
|
4479
|
+
get: function () { return chunkQSSVOPWA_cjs.createNextStepBuilder; }
|
|
4480
|
+
});
|
|
4481
|
+
Object.defineProperty(exports, "decodeBase64Json", {
|
|
4482
|
+
enumerable: true,
|
|
4483
|
+
get: function () { return chunkQSSVOPWA_cjs.decodeBase64Json; }
|
|
4484
|
+
});
|
|
4485
|
+
Object.defineProperty(exports, "decodeBase64Utf8", {
|
|
4486
|
+
enumerable: true,
|
|
4487
|
+
get: function () { return chunkQSSVOPWA_cjs.decodeBase64Utf8; }
|
|
4488
|
+
});
|
|
4489
|
+
Object.defineProperty(exports, "defaultNextToolFor", {
|
|
4490
|
+
enumerable: true,
|
|
4491
|
+
get: function () { return chunkQSSVOPWA_cjs.defaultNextToolFor; }
|
|
4492
|
+
});
|
|
4493
|
+
Object.defineProperty(exports, "encodeBase64Json", {
|
|
4494
|
+
enumerable: true,
|
|
4495
|
+
get: function () { return chunkQSSVOPWA_cjs.encodeBase64Json; }
|
|
4496
|
+
});
|
|
4497
|
+
Object.defineProperty(exports, "encodeBase64Utf8", {
|
|
4498
|
+
enumerable: true,
|
|
4499
|
+
get: function () { return chunkQSSVOPWA_cjs.encodeBase64Utf8; }
|
|
4500
|
+
});
|
|
4501
|
+
Object.defineProperty(exports, "encodePaymentProof", {
|
|
4502
|
+
enumerable: true,
|
|
4503
|
+
get: function () { return chunkQSSVOPWA_cjs.encodePaymentProof; }
|
|
4504
|
+
});
|
|
4505
|
+
Object.defineProperty(exports, "havenClientIdentity", {
|
|
4506
|
+
enumerable: true,
|
|
4507
|
+
get: function () { return chunkQSSVOPWA_cjs.havenClientIdentity; }
|
|
4508
|
+
});
|
|
4509
|
+
Object.defineProperty(exports, "isErc7710Option", {
|
|
4510
|
+
enumerable: true,
|
|
4511
|
+
get: function () { return chunkQSSVOPWA_cjs.isErc7710Option; }
|
|
4512
|
+
});
|
|
4513
|
+
Object.defineProperty(exports, "isSupportedNodeVersion", {
|
|
4514
|
+
enumerable: true,
|
|
4515
|
+
get: function () { return chunkQSSVOPWA_cjs.isSupportedNodeVersion; }
|
|
4516
|
+
});
|
|
4517
|
+
Object.defineProperty(exports, "isSweepableChain", {
|
|
4518
|
+
enumerable: true,
|
|
4519
|
+
get: function () { return chunkQSSVOPWA_cjs.isSweepableChain; }
|
|
4520
|
+
});
|
|
4521
|
+
Object.defineProperty(exports, "normalizePaymentRequired", {
|
|
4522
|
+
enumerable: true,
|
|
4523
|
+
get: function () { return chunkQSSVOPWA_cjs.normalizePaymentRequired; }
|
|
4524
|
+
});
|
|
4525
|
+
Object.defineProperty(exports, "parseNextTool", {
|
|
4526
|
+
enumerable: true,
|
|
4527
|
+
get: function () { return chunkQSSVOPWA_cjs.parseNextTool; }
|
|
4528
|
+
});
|
|
4529
|
+
Object.defineProperty(exports, "parsePaymentRequired", {
|
|
4530
|
+
enumerable: true,
|
|
4531
|
+
get: function () { return chunkQSSVOPWA_cjs.parsePaymentRequired; }
|
|
4532
|
+
});
|
|
4533
|
+
Object.defineProperty(exports, "parsePaymentRequiredResponse", {
|
|
4534
|
+
enumerable: true,
|
|
4535
|
+
get: function () { return chunkQSSVOPWA_cjs.parsePaymentRequiredResponse; }
|
|
4536
|
+
});
|
|
4537
|
+
Object.defineProperty(exports, "readClientUpdate", {
|
|
4538
|
+
enumerable: true,
|
|
4539
|
+
get: function () { return chunkQSSVOPWA_cjs.readClientUpdate; }
|
|
4540
|
+
});
|
|
4541
|
+
Object.defineProperty(exports, "renderNextTool", {
|
|
4542
|
+
enumerable: true,
|
|
4543
|
+
get: function () { return chunkQSSVOPWA_cjs.renderNextTool; }
|
|
4544
|
+
});
|
|
4545
|
+
Object.defineProperty(exports, "resolveTokenFromAddress", {
|
|
4546
|
+
enumerable: true,
|
|
4547
|
+
get: function () { return chunkQSSVOPWA_cjs.resolveTokenFromAddress; }
|
|
4548
|
+
});
|
|
4549
|
+
Object.defineProperty(exports, "selectErc7710PaymentOption", {
|
|
4550
|
+
enumerable: true,
|
|
4551
|
+
get: function () { return chunkQSSVOPWA_cjs.selectErc7710PaymentOption; }
|
|
4552
|
+
});
|
|
4553
|
+
Object.defineProperty(exports, "selectPaymentOption", {
|
|
4554
|
+
enumerable: true,
|
|
4555
|
+
get: function () { return chunkQSSVOPWA_cjs.selectPaymentOption; }
|
|
4556
|
+
});
|
|
4557
|
+
Object.defineProperty(exports, "selectStandardPaymentOption", {
|
|
4558
|
+
enumerable: true,
|
|
4559
|
+
get: function () { return chunkQSSVOPWA_cjs.selectStandardPaymentOption; }
|
|
4560
|
+
});
|
|
4561
|
+
Object.defineProperty(exports, "selectX402SettlementScheme", {
|
|
4562
|
+
enumerable: true,
|
|
4563
|
+
get: function () { return chunkQSSVOPWA_cjs.selectX402SettlementScheme; }
|
|
4564
|
+
});
|
|
4565
|
+
Object.defineProperty(exports, "sweepUsdcAddress", {
|
|
4566
|
+
enumerable: true,
|
|
4567
|
+
get: function () { return chunkQSSVOPWA_cjs.sweepUsdcAddress; }
|
|
4568
|
+
});
|
|
4569
|
+
Object.defineProperty(exports, "sweepUsdcDomain", {
|
|
4570
|
+
enumerable: true,
|
|
4571
|
+
get: function () { return chunkQSSVOPWA_cjs.sweepUsdcDomain; }
|
|
4572
|
+
});
|
|
4573
|
+
Object.defineProperty(exports, "toStandardPaymentRequirements", {
|
|
4574
|
+
enumerable: true,
|
|
4575
|
+
get: function () { return chunkQSSVOPWA_cjs.toStandardPaymentRequirements; }
|
|
4576
|
+
});
|
|
4577
|
+
Object.defineProperty(exports, "unsupportedNodeVersionMessage", {
|
|
4578
|
+
enumerable: true,
|
|
4579
|
+
get: function () { return chunkQSSVOPWA_cjs.unsupportedNodeVersionMessage; }
|
|
4580
|
+
});
|
|
4581
|
+
Object.defineProperty(exports, "validateStandardX402PaymentHeader", {
|
|
4582
|
+
enumerable: true,
|
|
4583
|
+
get: function () { return chunkQSSVOPWA_cjs.validateStandardX402PaymentHeader; }
|
|
4584
|
+
});
|
|
4585
|
+
Object.defineProperty(exports, "x402AssetTransferMethod", {
|
|
4586
|
+
enumerable: true,
|
|
4587
|
+
get: function () { return chunkQSSVOPWA_cjs.x402AssetTransferMethod; }
|
|
4588
|
+
});
|
|
4589
|
+
Object.defineProperty(exports, "x402AuthorizationAmount", {
|
|
4590
|
+
enumerable: true,
|
|
4591
|
+
get: function () { return chunkQSSVOPWA_cjs.x402AuthorizationAmount; }
|
|
4592
|
+
});
|
|
4593
|
+
Object.defineProperty(exports, "x402FacilitatorAddresses", {
|
|
4594
|
+
enumerable: true,
|
|
4595
|
+
get: function () { return chunkQSSVOPWA_cjs.x402FacilitatorAddresses; }
|
|
4596
|
+
});
|
|
4597
|
+
Object.defineProperty(exports, "x402V2PaymentEnvelope", {
|
|
4598
|
+
enumerable: true,
|
|
4599
|
+
get: function () { return chunkQSSVOPWA_cjs.x402V2PaymentEnvelope; }
|
|
4600
|
+
});
|
|
4601
|
+
Object.defineProperty(exports, "AGENT_PAYMENT_FAILURE_CODE_VALUES", {
|
|
4602
|
+
enumerable: true,
|
|
4603
|
+
get: function () { return chunkJKUIE45B_cjs.AGENT_PAYMENT_FAILURE_CODE_VALUES; }
|
|
4604
|
+
});
|
|
4605
|
+
Object.defineProperty(exports, "AGENT_PAYMENT_NEXT_ACTION_VALUES", {
|
|
4606
|
+
enumerable: true,
|
|
4607
|
+
get: function () { return chunkJKUIE45B_cjs.AGENT_PAYMENT_NEXT_ACTION_VALUES; }
|
|
4608
|
+
});
|
|
4609
|
+
Object.defineProperty(exports, "AGENT_PAYMENT_PHASE_VALUES", {
|
|
4610
|
+
enumerable: true,
|
|
4611
|
+
get: function () { return chunkJKUIE45B_cjs.AGENT_PAYMENT_PHASE_VALUES; }
|
|
4612
|
+
});
|
|
4613
|
+
Object.defineProperty(exports, "AGENT_PAYMENT_RAIL_VALUES", {
|
|
4614
|
+
enumerable: true,
|
|
4615
|
+
get: function () { return chunkJKUIE45B_cjs.AGENT_PAYMENT_RAIL_VALUES; }
|
|
4616
|
+
});
|
|
4617
|
+
Object.defineProperty(exports, "AgentPaymentFailureCode", {
|
|
4618
|
+
enumerable: true,
|
|
4619
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentFailureCode; }
|
|
4620
|
+
});
|
|
4621
|
+
Object.defineProperty(exports, "AgentPaymentFailureCodeDescriptions", {
|
|
4622
|
+
enumerable: true,
|
|
4623
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentFailureCodeDescriptions; }
|
|
4624
|
+
});
|
|
4625
|
+
Object.defineProperty(exports, "AgentPaymentFailureCodeSchema", {
|
|
4626
|
+
enumerable: true,
|
|
4627
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentFailureCodeSchema; }
|
|
4628
|
+
});
|
|
4629
|
+
Object.defineProperty(exports, "AgentPaymentNextAction", {
|
|
4630
|
+
enumerable: true,
|
|
4631
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentNextAction; }
|
|
4632
|
+
});
|
|
4633
|
+
Object.defineProperty(exports, "AgentPaymentNextActionDescriptions", {
|
|
4634
|
+
enumerable: true,
|
|
4635
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentNextActionDescriptions; }
|
|
4636
|
+
});
|
|
4637
|
+
Object.defineProperty(exports, "AgentPaymentNextActionSchema", {
|
|
4638
|
+
enumerable: true,
|
|
4639
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentNextActionSchema; }
|
|
4640
|
+
});
|
|
4641
|
+
Object.defineProperty(exports, "AgentPaymentPhase", {
|
|
4642
|
+
enumerable: true,
|
|
4643
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentPhase; }
|
|
4644
|
+
});
|
|
4645
|
+
Object.defineProperty(exports, "AgentPaymentPhaseDescriptions", {
|
|
4646
|
+
enumerable: true,
|
|
4647
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentPhaseDescriptions; }
|
|
4648
|
+
});
|
|
4649
|
+
Object.defineProperty(exports, "AgentPaymentPhaseSchema", {
|
|
4650
|
+
enumerable: true,
|
|
4651
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentPhaseSchema; }
|
|
4652
|
+
});
|
|
4653
|
+
Object.defineProperty(exports, "AgentPaymentRail", {
|
|
4654
|
+
enumerable: true,
|
|
4655
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentRail; }
|
|
4656
|
+
});
|
|
4657
|
+
Object.defineProperty(exports, "AgentPaymentRailDescriptions", {
|
|
4658
|
+
enumerable: true,
|
|
4659
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentRailDescriptions; }
|
|
4660
|
+
});
|
|
4661
|
+
Object.defineProperty(exports, "AgentPaymentRailSchema", {
|
|
4662
|
+
enumerable: true,
|
|
4663
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentRailSchema; }
|
|
4664
|
+
});
|
|
4665
|
+
Object.defineProperty(exports, "AgentPaymentWarningCode", {
|
|
4666
|
+
enumerable: true,
|
|
4667
|
+
get: function () { return chunkJKUIE45B_cjs.AgentPaymentWarningCode; }
|
|
4668
|
+
});
|
|
4669
|
+
Object.defineProperty(exports, "CONNECTOR_PACKAGE_NAME", {
|
|
4670
|
+
enumerable: true,
|
|
4671
|
+
get: function () { return chunkJKUIE45B_cjs.CONNECTOR_PACKAGE_NAME; }
|
|
4672
|
+
});
|
|
4673
|
+
Object.defineProperty(exports, "DEFAULT_CONFIRMATION_TIMEOUT_MS", {
|
|
4674
|
+
enumerable: true,
|
|
4675
|
+
get: function () { return chunkJKUIE45B_cjs.DEFAULT_CONFIRMATION_TIMEOUT_MS; }
|
|
4676
|
+
});
|
|
4677
|
+
Object.defineProperty(exports, "DIRECT_SIGN_CONTEXT_VERSION", {
|
|
4678
|
+
enumerable: true,
|
|
4679
|
+
get: function () { return chunkJKUIE45B_cjs.DIRECT_SIGN_CONTEXT_VERSION; }
|
|
4680
|
+
});
|
|
4681
|
+
Object.defineProperty(exports, "ENTRY_POINT_V07", {
|
|
4682
|
+
enumerable: true,
|
|
4683
|
+
get: function () { return chunkJKUIE45B_cjs.ENTRY_POINT_V07; }
|
|
4684
|
+
});
|
|
4685
|
+
Object.defineProperty(exports, "HAVEN_CONNECTOR_CHANNEL", {
|
|
4686
|
+
enumerable: true,
|
|
4687
|
+
get: function () { return chunkJKUIE45B_cjs.HAVEN_CONNECTOR_CHANNEL; }
|
|
4688
|
+
});
|
|
4689
|
+
Object.defineProperty(exports, "HYBRID_DELEGATOR_DOMAIN_NAME", {
|
|
4690
|
+
enumerable: true,
|
|
4691
|
+
get: function () { return chunkJKUIE45B_cjs.HYBRID_DELEGATOR_DOMAIN_NAME; }
|
|
4692
|
+
});
|
|
4693
|
+
Object.defineProperty(exports, "HYBRID_DELEGATOR_DOMAIN_VERSION", {
|
|
4694
|
+
enumerable: true,
|
|
4695
|
+
get: function () { return chunkJKUIE45B_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION; }
|
|
4696
|
+
});
|
|
4697
|
+
Object.defineProperty(exports, "HavenApiError", {
|
|
4698
|
+
enumerable: true,
|
|
4699
|
+
get: function () { return chunkJKUIE45B_cjs.HavenApiError; }
|
|
4700
|
+
});
|
|
4701
|
+
Object.defineProperty(exports, "HavenError", {
|
|
4702
|
+
enumerable: true,
|
|
4703
|
+
get: function () { return chunkJKUIE45B_cjs.HavenError; }
|
|
4704
|
+
});
|
|
4705
|
+
Object.defineProperty(exports, "HavenPaymentStateError", {
|
|
4706
|
+
enumerable: true,
|
|
4707
|
+
get: function () { return chunkJKUIE45B_cjs.HavenPaymentStateError; }
|
|
4708
|
+
});
|
|
4709
|
+
Object.defineProperty(exports, "HavenSigningError", {
|
|
4710
|
+
enumerable: true,
|
|
4711
|
+
get: function () { return chunkJKUIE45B_cjs.HavenSigningError; }
|
|
4712
|
+
});
|
|
4713
|
+
Object.defineProperty(exports, "HavenTimeoutError", {
|
|
4714
|
+
enumerable: true,
|
|
4715
|
+
get: function () { return chunkJKUIE45B_cjs.HavenTimeoutError; }
|
|
4716
|
+
});
|
|
4717
|
+
Object.defineProperty(exports, "HavenUnsupportedSignerVersionError", {
|
|
4718
|
+
enumerable: true,
|
|
4719
|
+
get: function () { return chunkJKUIE45B_cjs.HavenUnsupportedSignerVersionError; }
|
|
4720
|
+
});
|
|
4721
|
+
Object.defineProperty(exports, "HavenUserOpBindingError", {
|
|
4722
|
+
enumerable: true,
|
|
4723
|
+
get: function () { return chunkJKUIE45B_cjs.HavenUserOpBindingError; }
|
|
4724
|
+
});
|
|
4725
|
+
Object.defineProperty(exports, "HavenZeroSettlementHashError", {
|
|
4726
|
+
enumerable: true,
|
|
4727
|
+
get: function () { return chunkJKUIE45B_cjs.HavenZeroSettlementHashError; }
|
|
4728
|
+
});
|
|
4729
|
+
Object.defineProperty(exports, "MerchantTimeoutError", {
|
|
4730
|
+
enumerable: true,
|
|
4731
|
+
get: function () { return chunkJKUIE45B_cjs.MerchantTimeoutError; }
|
|
4732
|
+
});
|
|
4733
|
+
Object.defineProperty(exports, "PACKED_USER_OPERATION_FIELDS", {
|
|
4734
|
+
enumerable: true,
|
|
4735
|
+
get: function () { return chunkJKUIE45B_cjs.PACKED_USER_OPERATION_FIELDS; }
|
|
4736
|
+
});
|
|
4737
|
+
Object.defineProperty(exports, "ROOT_AUTHORITY", {
|
|
4738
|
+
enumerable: true,
|
|
4739
|
+
get: function () { return chunkJKUIE45B_cjs.ROOT_AUTHORITY; }
|
|
4740
|
+
});
|
|
4741
|
+
Object.defineProperty(exports, "SIGNER_UPDATE_FALLBACK", {
|
|
4742
|
+
enumerable: true,
|
|
4743
|
+
get: function () { return chunkJKUIE45B_cjs.SIGNER_UPDATE_FALLBACK; }
|
|
4744
|
+
});
|
|
4745
|
+
Object.defineProperty(exports, "SignerRefusalCode", {
|
|
4746
|
+
enumerable: true,
|
|
4747
|
+
get: function () { return chunkJKUIE45B_cjs.SignerRefusalCode; }
|
|
4748
|
+
});
|
|
4749
|
+
Object.defineProperty(exports, "X402AlreadySettledError", {
|
|
4750
|
+
enumerable: true,
|
|
4751
|
+
get: function () { return chunkJKUIE45B_cjs.X402AlreadySettledError; }
|
|
4752
|
+
});
|
|
4753
|
+
Object.defineProperty(exports, "X402UnexpectedStatusError", {
|
|
4754
|
+
enumerable: true,
|
|
4755
|
+
get: function () { return chunkJKUIE45B_cjs.X402UnexpectedStatusError; }
|
|
4756
|
+
});
|
|
4757
|
+
Object.defineProperty(exports, "assertUserOpTypedDataBinding", {
|
|
4758
|
+
enumerable: true,
|
|
4759
|
+
get: function () { return chunkJKUIE45B_cjs.assertUserOpTypedDataBinding; }
|
|
4760
|
+
});
|
|
4761
|
+
Object.defineProperty(exports, "connectorRerunCommand", {
|
|
4762
|
+
enumerable: true,
|
|
4763
|
+
get: function () { return chunkJKUIE45B_cjs.connectorRerunCommand; }
|
|
4764
|
+
});
|
|
4765
|
+
Object.defineProperty(exports, "connectorSpec", {
|
|
4766
|
+
enumerable: true,
|
|
4767
|
+
get: function () { return chunkJKUIE45B_cjs.connectorSpec; }
|
|
4768
|
+
});
|
|
4769
|
+
Object.defineProperty(exports, "deriveDelegateAccountAddress", {
|
|
4770
|
+
enumerable: true,
|
|
4771
|
+
get: function () { return chunkJKUIE45B_cjs.deriveDelegateAccountAddress; }
|
|
4772
|
+
});
|
|
4773
|
+
Object.defineProperty(exports, "isConnectorChannel", {
|
|
4774
|
+
enumerable: true,
|
|
4775
|
+
get: function () { return chunkJKUIE45B_cjs.isConnectorChannel; }
|
|
4776
|
+
});
|
|
4777
|
+
Object.defineProperty(exports, "isPackedUserOperationTypedData", {
|
|
4778
|
+
enumerable: true,
|
|
4779
|
+
get: function () { return chunkJKUIE45B_cjs.isPackedUserOperationTypedData; }
|
|
4780
|
+
});
|
|
4781
|
+
Object.defineProperty(exports, "packedUserOperationHash", {
|
|
4782
|
+
enumerable: true,
|
|
4783
|
+
get: function () { return chunkJKUIE45B_cjs.packedUserOperationHash; }
|
|
4784
|
+
});
|
|
4785
|
+
Object.defineProperty(exports, "resolveConnectorChannel", {
|
|
4786
|
+
enumerable: true,
|
|
4787
|
+
get: function () { return chunkJKUIE45B_cjs.resolveConnectorChannel; }
|
|
4788
|
+
});
|
|
4789
|
+
Object.defineProperty(exports, "signerUpdateFallback", {
|
|
4790
|
+
enumerable: true,
|
|
4791
|
+
get: function () { return chunkJKUIE45B_cjs.signerUpdateFallback; }
|
|
4792
|
+
});
|
|
4793
|
+
Object.defineProperty(exports, "verifySettlementChild", {
|
|
4794
|
+
enumerable: true,
|
|
4795
|
+
get: function () { return chunkJKUIE45B_cjs.verifySettlementChild; }
|
|
4796
|
+
});
|
|
5012
4797
|
exports.AGENT_APPROVAL_RELAY_JSON_SENTENCE = AGENT_APPROVAL_RELAY_JSON_SENTENCE;
|
|
5013
4798
|
exports.AGENT_APPROVAL_RELAY_PROSE_SENTENCE = AGENT_APPROVAL_RELAY_PROSE_SENTENCE;
|
|
5014
4799
|
exports.AGENT_COMMAND_MODIFICATION_SENTENCE = AGENT_COMMAND_MODIFICATION_SENTENCE;
|
|
@@ -5016,109 +4801,33 @@ exports.AGENT_JSON_MODE_SENTENCE = AGENT_JSON_MODE_SENTENCE;
|
|
|
5016
4801
|
exports.AGENT_LOCAL_KEY_SENTENCE = AGENT_LOCAL_KEY_SENTENCE;
|
|
5017
4802
|
exports.AGENT_NETWORK_ACCESS_SENTENCE = AGENT_NETWORK_ACCESS_SENTENCE;
|
|
5018
4803
|
exports.AGENT_ONBOARDING_PROMPT = AGENT_ONBOARDING_PROMPT;
|
|
5019
|
-
exports.AGENT_PAYMENT_FAILURE_CODE_VALUES = AGENT_PAYMENT_FAILURE_CODE_VALUES;
|
|
5020
|
-
exports.AGENT_PAYMENT_NEXT_ACTION_VALUES = AGENT_PAYMENT_NEXT_ACTION_VALUES;
|
|
5021
|
-
exports.AGENT_PAYMENT_PHASE_VALUES = AGENT_PAYMENT_PHASE_VALUES;
|
|
5022
|
-
exports.AGENT_PAYMENT_RAIL_VALUES = AGENT_PAYMENT_RAIL_VALUES;
|
|
5023
4804
|
exports.AGENT_README_SECTION_MD = AGENT_README_SECTION_MD;
|
|
5024
4805
|
exports.AGENT_SECRET_HYGIENE_SENTENCE = AGENT_SECRET_HYGIENE_SENTENCE;
|
|
5025
4806
|
exports.AGENT_WIRING_COLLISION_RELAY_SENTENCE = AGENT_WIRING_COLLISION_RELAY_SENTENCE;
|
|
5026
|
-
exports.AgentPaymentFailureCode = AgentPaymentFailureCode;
|
|
5027
|
-
exports.AgentPaymentFailureCodeDescriptions = AgentPaymentFailureCodeDescriptions;
|
|
5028
|
-
exports.AgentPaymentFailureCodeSchema = AgentPaymentFailureCodeSchema;
|
|
5029
|
-
exports.AgentPaymentNextAction = AgentPaymentNextAction;
|
|
5030
|
-
exports.AgentPaymentNextActionDescriptions = AgentPaymentNextActionDescriptions;
|
|
5031
|
-
exports.AgentPaymentNextActionSchema = AgentPaymentNextActionSchema;
|
|
5032
|
-
exports.AgentPaymentPhase = AgentPaymentPhase;
|
|
5033
|
-
exports.AgentPaymentPhaseDescriptions = AgentPaymentPhaseDescriptions;
|
|
5034
|
-
exports.AgentPaymentPhaseSchema = AgentPaymentPhaseSchema;
|
|
5035
|
-
exports.AgentPaymentRail = AgentPaymentRail;
|
|
5036
|
-
exports.AgentPaymentRailDescriptions = AgentPaymentRailDescriptions;
|
|
5037
|
-
exports.AgentPaymentRailSchema = AgentPaymentRailSchema;
|
|
5038
|
-
exports.AgentPaymentWarningCode = AgentPaymentWarningCode;
|
|
5039
|
-
exports.CONNECTOR_PACKAGE_NAME = CONNECTOR_PACKAGE_NAME;
|
|
5040
|
-
exports.DEFAULT_CONFIRMATION_TIMEOUT_MS = DEFAULT_CONFIRMATION_TIMEOUT_MS;
|
|
5041
4807
|
exports.DISCOVERY_MAX_BYTES = DISCOVERY_MAX_BYTES;
|
|
5042
|
-
exports.ERC7710_ASSET_TRANSFER_METHOD = ERC7710_ASSET_TRANSFER_METHOD;
|
|
5043
4808
|
exports.HAVEN_AGENT_RUNBOOK_MD = HAVEN_AGENT_RUNBOOK_MD;
|
|
5044
|
-
exports.HAVEN_CONNECTOR_CHANNEL = HAVEN_CONNECTOR_CHANNEL;
|
|
5045
|
-
exports.HAVEN_MINIMUM_NODE_VERSION = HAVEN_MINIMUM_NODE_VERSION;
|
|
5046
4809
|
exports.HAVEN_SKILL_BODY_MD = HAVEN_SKILL_BODY_MD;
|
|
5047
4810
|
exports.HAVEN_SKILL_MD = HAVEN_SKILL_MD;
|
|
5048
|
-
exports.HavenApiError = HavenApiError;
|
|
5049
4811
|
exports.HavenClient = HavenClient;
|
|
5050
|
-
exports.
|
|
5051
|
-
exports.
|
|
5052
|
-
exports.HavenSigningError = HavenSigningError;
|
|
5053
|
-
exports.HavenTimeoutError = HavenTimeoutError;
|
|
5054
|
-
exports.HavenUnsupportedSignerVersionError = HavenUnsupportedSignerVersionError;
|
|
5055
|
-
exports.HavenZeroSettlementHashError = HavenZeroSettlementHashError;
|
|
4812
|
+
exports.HavenInsecureRetryTargetError = HavenInsecureRetryTargetError;
|
|
4813
|
+
exports.INSECURE_RETRY_TARGET_CODE = INSECURE_RETRY_TARGET_CODE;
|
|
5056
4814
|
exports.MERCHANT_DISCOVERY_PATHS = MERCHANT_DISCOVERY_PATHS;
|
|
5057
|
-
exports.MerchantTimeoutError = MerchantTimeoutError;
|
|
5058
4815
|
exports.RECEIPT_VERSION = RECEIPT_VERSION;
|
|
5059
|
-
exports.SIGNER_UPDATE_FALLBACK = SIGNER_UPDATE_FALLBACK;
|
|
5060
4816
|
exports.SKILL_FOLDER_NAME = SKILL_FOLDER_NAME;
|
|
5061
|
-
exports.SWEEP_BASE_CHAIN_ID = SWEEP_BASE_CHAIN_ID;
|
|
5062
|
-
exports.SWEEP_BASE_SEPOLIA_CHAIN_ID = SWEEP_BASE_SEPOLIA_CHAIN_ID;
|
|
5063
|
-
exports.SWEEP_BASE_SEPOLIA_USDC_ADDRESS = SWEEP_BASE_SEPOLIA_USDC_ADDRESS;
|
|
5064
|
-
exports.SWEEP_BASE_USDC_ADDRESS = SWEEP_BASE_USDC_ADDRESS;
|
|
5065
|
-
exports.SignerRefusalCode = SignerRefusalCode;
|
|
5066
|
-
exports.TRANSFER_WITH_AUTHORIZATION_TYPES = TRANSFER_WITH_AUTHORIZATION_TYPES;
|
|
5067
|
-
exports.X402AlreadySettledError = X402AlreadySettledError;
|
|
5068
|
-
exports.X402PaymentHeaderValidationError = X402PaymentHeaderValidationError;
|
|
5069
|
-
exports.X402UnexpectedStatusError = X402UnexpectedStatusError;
|
|
5070
|
-
exports.X402_LEGACY_PAYMENT_HEADER_NAME = X402_LEGACY_PAYMENT_HEADER_NAME;
|
|
5071
|
-
exports.X402_MAX_AUTHORIZATION_WINDOW_SECONDS = X402_MAX_AUTHORIZATION_WINDOW_SECONDS;
|
|
5072
|
-
exports.X402_PAYMENT_HEADER_NAME = X402_PAYMENT_HEADER_NAME;
|
|
5073
|
-
exports.X402_PAYMENT_HEADER_NAMES_SENT = X402_PAYMENT_HEADER_NAMES_SENT;
|
|
5074
|
-
exports.X402_PAYMENT_REQUIRED_HEADER_NAME = X402_PAYMENT_REQUIRED_HEADER_NAME;
|
|
5075
|
-
exports.X402_PAYMENT_RESPONSE_HEADER_NAME = X402_PAYMENT_RESPONSE_HEADER_NAME;
|
|
5076
|
-
exports.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = X402_SETTLEMENT_FORWARD_MARGIN_SECONDS;
|
|
5077
4817
|
exports.addressFromKey = addressFromKey;
|
|
5078
|
-
exports.
|
|
5079
|
-
exports.buildSweepTypedData = buildSweepTypedData;
|
|
5080
|
-
exports.buildX402ExpectedMessage = buildX402ExpectedMessage;
|
|
5081
|
-
exports.compareNodeVersions = compareNodeVersions;
|
|
4818
|
+
exports.assertSecureX402RetryTarget = assertSecureX402RetryTarget;
|
|
5082
4819
|
exports.composeDescription = composeDescription;
|
|
5083
|
-
exports.connectorRerunCommand = connectorRerunCommand;
|
|
5084
|
-
exports.connectorSpec = connectorSpec;
|
|
5085
|
-
exports.decodeBase64Json = decodeBase64Json;
|
|
5086
|
-
exports.decodeBase64Utf8 = decodeBase64Utf8;
|
|
5087
4820
|
exports.discoverMerchantMcpUrl = discoverMerchantMcpUrl;
|
|
5088
|
-
exports.encodeBase64Json = encodeBase64Json;
|
|
5089
|
-
exports.encodeBase64Utf8 = encodeBase64Utf8;
|
|
5090
|
-
exports.encodePaymentProof = encodePaymentProof;
|
|
5091
4821
|
exports.havenTools = havenTools;
|
|
5092
|
-
exports.
|
|
5093
|
-
exports.isErc7710Option = isErc7710Option;
|
|
5094
|
-
exports.isSupportedNodeVersion = isSupportedNodeVersion;
|
|
5095
|
-
exports.isSweepableChain = isSweepableChain;
|
|
4822
|
+
exports.isSecureX402RetryTarget = isSecureX402RetryTarget;
|
|
5096
4823
|
exports.isZeroSettlementTxHash = isZeroSettlementTxHash;
|
|
5097
|
-
exports.normalizePaymentRequired = normalizePaymentRequired;
|
|
5098
|
-
exports.parsePaymentRequired = parsePaymentRequired;
|
|
5099
|
-
exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
|
|
5100
4824
|
exports.readX402ReceiptPayer = readX402ReceiptPayer;
|
|
5101
|
-
exports.
|
|
5102
|
-
exports.resolveTokenFromAddress = resolveTokenFromAddress;
|
|
4825
|
+
exports.resolveX402RetryTarget = resolveX402RetryTarget;
|
|
5103
4826
|
exports.sameUrl = sameUrl;
|
|
5104
|
-
exports.selectErc7710PaymentOption = selectErc7710PaymentOption;
|
|
5105
|
-
exports.selectPaymentOption = selectPaymentOption;
|
|
5106
|
-
exports.selectStandardPaymentOption = selectStandardPaymentOption;
|
|
5107
|
-
exports.selectX402SettlementScheme = selectX402SettlementScheme;
|
|
5108
4827
|
exports.signHash = signHash;
|
|
5109
4828
|
exports.signUserOpTypedDataForDelegation = signUserOpTypedDataForDelegation;
|
|
5110
|
-
exports.signerUpdateFallback = signerUpdateFallback;
|
|
5111
|
-
exports.sweepUsdcAddress = sweepUsdcAddress;
|
|
5112
|
-
exports.sweepUsdcDomain = sweepUsdcDomain;
|
|
5113
|
-
exports.toStandardPaymentRequirements = toStandardPaymentRequirements;
|
|
5114
4829
|
exports.toolDescriptions = toolDescriptions;
|
|
5115
|
-
exports.unsupportedNodeVersionMessage = unsupportedNodeVersionMessage;
|
|
5116
|
-
exports.validateStandardX402PaymentHeader = validateStandardX402PaymentHeader;
|
|
5117
4830
|
exports.verifyPaymentReceipt = verifyPaymentReceipt;
|
|
5118
4831
|
exports.verifySignature = verifySignature;
|
|
5119
|
-
exports.x402AssetTransferMethod = x402AssetTransferMethod;
|
|
5120
|
-
exports.x402AuthorizationAmount = x402AuthorizationAmount;
|
|
5121
|
-
exports.x402FacilitatorAddresses = x402FacilitatorAddresses;
|
|
5122
|
-
exports.x402V2PaymentEnvelope = x402V2PaymentEnvelope;
|
|
5123
4832
|
//# sourceMappingURL=index.cjs.map
|
|
5124
4833
|
//# sourceMappingURL=index.cjs.map
|