@haven_ai/sdk 0.4.0-alpha.0 → 0.6.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2958 @@
1
+ import { PaymentRequirements } from 'x402/types';
2
+ import { Hex, Address } from 'viem';
3
+
4
+ interface HavenClientConfig {
5
+ /** Haven API key (sk_agent_xxx) */
6
+ apiKey: string;
7
+ /** Agent's delegate EOA private key. If provided, the SDK handles signing automatically. */
8
+ delegateKey?: string;
9
+ /** Haven API base URL (default: http://localhost:3001) */
10
+ baseUrl?: string;
11
+ /** Optional wallet identity to send as the x402-wallet header. */
12
+ x402Wallet?: string;
13
+ /** Timeout in ms for individual HTTP requests (default: 30000) */
14
+ requestTimeout?: number;
15
+ /** Timeout (ms) for MERCHANT-facing requests — x402/MPP probes, MCP
16
+ * handshakes, paid retries. Separate from requestTimeout (Haven API):
17
+ * merchants may settle on-chain synchronously, so the default is
18
+ * deliberately generous. #1300. */
19
+ merchantTimeout?: number;
20
+ /** Timeout in ms when polling for tx confirmation (default: 90000) */
21
+ confirmationTimeout?: number;
22
+ /** Polling interval in ms when waiting for confirmation (default: 3000) */
23
+ pollingInterval?: number;
24
+ /**
25
+ * Extra headers to attach to every request to the Haven API.
26
+ *
27
+ * Used by the MCP server to tag requests with `X-Haven-MCP-Tool: <name>`
28
+ * so the backend can record an audit-log entry per tool invocation. Has
29
+ * no effect on outbound merchant requests (x402 / MPP) — those are
30
+ * standard HTTP and never carry Haven-internal headers.
31
+ */
32
+ defaultHeaders?: Record<string, string>;
33
+ /**
34
+ * `<package>/<version>` naming the published package that embeds this
35
+ * client, sent on every Haven API request as `X-Haven-Client` (#3303) so the
36
+ * backend can tell an outdated client what to run. Defaults to
37
+ * `@haven_ai/sdk/<this SDK's version>`. It cannot be set through
38
+ * `defaultHeaders` — the transport writes it last.
39
+ */
40
+ clientIdentity?: string;
41
+ /**
42
+ * JSON-RPC RPC URLs keyed by EIP-155 chain ID.
43
+ *
44
+ * When provided for a chain, the SDK waits for ≥1 on-chain confirmation of
45
+ * the funding tx (account → delegate EOA) before retrying the merchant. This prevents
46
+ * the race where the merchant's `balanceOf(delegate)` call runs before the
47
+ * funding block has propagated to the merchant's RPC node.
48
+ *
49
+ * Without this option the SDK proceeds as soon as Haven's backend confirms
50
+ * submission (backward-compatible default). Set it to a reliable RPC
51
+ * endpoint (e.g. Alchemy / Infura) for production usage.
52
+ *
53
+ * @example { 8453: 'https://mainnet.base.org' }
54
+ */
55
+ chainRpcs?: Record<number, string>;
56
+ }
57
+ interface PaymentRequest {
58
+ /** Token symbol: "EURe", "USDC.e", or "xDAI" */
59
+ token: string;
60
+ /** Amount as a decimal string, e.g. "5.00" */
61
+ amount: string;
62
+ /** Recipient Ethereum address (0x...) */
63
+ to: string;
64
+ /**
65
+ * Optional dedupe key (#1207): a retried request with the same key returns
66
+ * the FIRST request's result instead of minting a second transfer or a
67
+ * second approval. Same contract as /machine-payments/send. Max 128 chars.
68
+ */
69
+ idempotencyKey?: string;
70
+ /**
71
+ * #3329: redeem against this open task budget's child delegation instead
72
+ * of the agent's budget delegation directly — `[task child, budget]`. The
73
+ * backend refuses (404/409) when the id is unknown, not open, or its
74
+ * token/recipient/parent disagree with this request.
75
+ */
76
+ taskBudgetId?: string;
77
+ }
78
+ interface SignData {
79
+ /** The hash to sign (keccak256, 0x-prefixed) */
80
+ hash: string;
81
+ /**
82
+ * Delegation rail: 'eip712_userop' (funding redemption) or
83
+ * 'eip712_delegation' (erc7710 settlement child). The backend spec makes it
84
+ * required; the legacy AllowanceModule reading — absent = raw ECDSA over
85
+ * `hash` — is retired (#2850), and the SDK client refuses an absent scheme.
86
+ * The session rail's 'eip191_userop' is retired (#834).
87
+ *
88
+ * When present, `hash` is NOT what gets signed — `typed_data` is (#1138).
89
+ */
90
+ signature_scheme?: 'eip712_userop' | 'eip712_delegation';
91
+ /**
92
+ * EIP-712 payload the account validates, signed VERBATIM (#829). Present
93
+ * whenever `signature_scheme` is — never reconstruct it from `components`.
94
+ */
95
+ typed_data?: {
96
+ domain: Record<string, unknown>;
97
+ types: Record<string, unknown>;
98
+ primaryType: string;
99
+ message: Record<string, unknown>;
100
+ };
101
+ /** Breakdown of values that were hashed — useful for debugging */
102
+ components: {
103
+ /**
104
+ * The PAYER account (the user's smart account). Not to be confused with
105
+ * `account`, which on the funding shapes holds the DELEGATE account
106
+ * address.
107
+ */
108
+ payer_account?: string;
109
+ token: string;
110
+ to: string;
111
+ amount: string;
112
+ payment_token: string;
113
+ payment: string;
114
+ nonce: number;
115
+ };
116
+ /** Human-readable signing instructions */
117
+ instructions: string;
118
+ }
119
+ interface PaymentIntent {
120
+ /** Unique payment ID */
121
+ paymentId: string;
122
+ /** Current status */
123
+ status: 'pending_signature';
124
+ /** ISO 8601 expiry timestamp */
125
+ expiresAt: string;
126
+ /** Data needed to sign the payment */
127
+ signData: SignData;
128
+ }
129
+ type PaymentStatus = 'pending_signature' | 'submitted' | 'confirmed' | 'pending_approval' | 'approved' | 'proposed' | 'executed' | 'rejected' | 'expired' | 'failed';
130
+ interface PaymentResult {
131
+ /** Unique payment ID */
132
+ paymentId: string;
133
+ /** Final status */
134
+ status: PaymentStatus;
135
+ /** Token that was sent */
136
+ token: string;
137
+ /** Amount that was sent (human-readable) */
138
+ amount: string;
139
+ /** Recipient address */
140
+ to: string;
141
+ /** On-chain transaction hash (present when confirmed) */
142
+ txHash: string | null;
143
+ /** Error message (present when failed) */
144
+ errorMessage: string | null;
145
+ /** Block explorer URL for the transaction (chain-dependent) */
146
+ explorerUrl: string | null;
147
+ /** ISO 8601 timestamps */
148
+ createdAt: string;
149
+ signedAt: string | null;
150
+ submittedAt: string | null;
151
+ confirmedAt: string | null;
152
+ expiresAt: string;
153
+ /**
154
+ * Platform fee surfaced on the result so it's never silently collected. Dark
155
+ * today (`amount` "0", `applied` false); always present so it's visible the
156
+ * moment fees go live.
157
+ */
158
+ fee?: PaymentFee | null;
159
+ }
160
+ /** The Haven platform fee applied to a payment (#386). */
161
+ interface PaymentFee {
162
+ /** Human-readable fee amount ("0" while the fee module is dark). */
163
+ amount: string;
164
+ /** Token the fee is denominated in. */
165
+ token: string;
166
+ /** Fee as basis points of gross (0 while dark). */
167
+ basisPoints: number;
168
+ /** True when a non-zero fee was actually applied. */
169
+ applied: boolean;
170
+ }
171
+ /** Payment requirements from an HTTP 402 response (x402 protocol). */
172
+ interface X402PaymentRequired {
173
+ x402Version: number;
174
+ resource: {
175
+ url: string;
176
+ description?: string;
177
+ mimeType?: string;
178
+ [key: string]: unknown;
179
+ };
180
+ accepts: X402PaymentOption[];
181
+ error?: string;
182
+ extensions?: Record<string, unknown>;
183
+ }
184
+ /** A single payment option from x402 PaymentRequired. */
185
+ interface X402PaymentOption {
186
+ scheme: string;
187
+ network: string;
188
+ amount: string;
189
+ maxAmountRequired?: string;
190
+ resource?: string;
191
+ description?: string;
192
+ mimeType?: string;
193
+ asset: string;
194
+ payTo: string;
195
+ maxTimeoutSeconds: number;
196
+ /**
197
+ * Merchant-supplied scheme metadata. Two keys are load-bearing for Haven
198
+ * (#1453), both from MetaMask's erc7710 x402 shape:
199
+ *
200
+ * assetTransferMethod — 'erc7710' marks this entry as settleable by
201
+ * redeeming a delegation chain. Absent/other means
202
+ * the standard EIP-3009 authorization.
203
+ * facilitatorAddresses — who may redeem it, pinned into the settlement
204
+ * child's redeemer caveat (#1058).
205
+ *
206
+ * Left as an open record on purpose: the field is the merchant's, and
207
+ * narrowing it to Haven's two keys would silently drop everything else a
208
+ * merchant sends. Read it through `x402AssetTransferMethod` /
209
+ * `x402FacilitatorAddresses` rather than indexing it raw.
210
+ */
211
+ extra?: Record<string, unknown>;
212
+ }
213
+ /** Receipt returned after a successful x402 payment. */
214
+ interface X402Receipt {
215
+ success: boolean;
216
+ paymentId: string;
217
+ txHash: string;
218
+ token: string;
219
+ amount: string;
220
+ to: string;
221
+ resourceUrl: string;
222
+ explorerUrl: string;
223
+ accepted?: X402PaymentOption;
224
+ paymentHeader?: string;
225
+ merchantTo?: string | null;
226
+ payer?: string;
227
+ chainId?: number;
228
+ haven?: {
229
+ paymentId: string;
230
+ fundingTxHash: string;
231
+ fundingExplorerUrl: string;
232
+ };
233
+ merchant?: {
234
+ payTo: string | null;
235
+ settlementTxHash?: string | null;
236
+ settlementExplorerUrl?: string | null;
237
+ };
238
+ x402?: {
239
+ amount: string;
240
+ token: string;
241
+ network: string;
242
+ asset: string;
243
+ resource: string;
244
+ };
245
+ }
246
+ interface X402AuthorizationOptions {
247
+ /** Stable caller-supplied key for this user intent. Prevents duplicate approvals across fresh 402 quotes. */
248
+ idempotencyKey?: string;
249
+ /**
250
+ * #1307: the merchant MCP-tool call context this quote was made against
251
+ * (merchant_url, tool_name, arguments, mcp_transport). Persisted on the
252
+ * intent so `getX402MerchantCallContext` can rehydrate it by payment_id at
253
+ * settle/complete time instead of the caller re-threading it. Optional —
254
+ * omit for a non-MCP-tool x402 merchant (plain HTTP resource).
255
+ */
256
+ mcpCallContext?: X402McpCallContext;
257
+ /**
258
+ * #1348: the agent's delegate address, when the caller already resolved it
259
+ * from `getAgent()` in this same flow — skips `createX402Intent`'s internal
260
+ * agent fetch (one full round trip on every guided purchase). Staleness
261
+ * caveat (#1358 review): the backend derives the funding shape by comparing
262
+ * `payTo` to the CURRENT delegate address, so a value made stale by a
263
+ * delegate rotation mid-flow is not always a clean failure — a pinned-budget
264
+ * agent gets a 403, but an open-budget delegation agent would route to the
265
+ * settlement shape with the stale address. The window is one tool call
266
+ * (previously sub-millisecond, now the merchant-quote duration), never
267
+ * externally suppliable; server-truth hardening is tracked in #1360. Only
268
+ * pass an address fetched in THIS flow; omit to keep the self-contained
269
+ * fetch.
270
+ */
271
+ delegateAddress?: string;
272
+ /**
273
+ * #3329: redeem against this open task budget's child delegation for the
274
+ * funding leg / erc7710 settlement child instead of the agent's budget
275
+ * delegation directly. Same refusal contract as `PaymentRequest.taskBudgetId`.
276
+ * On the EIP-3009 funding leg (`authorizeX402`, `fetch()`, `payX402Quote()`)
277
+ * a task budget's recipient pin is compared with the agent's own delegate
278
+ * wallet, so a merchant-pinned task budget is refused there
279
+ * (`task_budget_recipient_mismatch`); it pays through erc7710 only (#3378).
280
+ */
281
+ taskBudgetId?: string;
282
+ }
283
+ /**
284
+ * Keyless x402 construct result.
285
+ *
286
+ * Returned by `createX402Intent` — the non-custodial half of an x402 payment.
287
+ * It carries the unsigned funding payload (`signData`, account → delegate EOA)
288
+ * plus everything the *edge* needs to build and sign the EIP-3009 merchant
289
+ * header itself. The construct path never signs; both delegate signatures
290
+ * (funding payload + merchant header) happen on the machine that holds the key.
291
+ */
292
+ interface X402Intent {
293
+ /** Haven payment id for the funding transfer. */
294
+ paymentId: string;
295
+ /** Stable key used to create or refresh this x402 funding intent. */
296
+ idempotencyKey: string;
297
+ status: 'pending_signature';
298
+ /** ISO 8601 expiry of the funding intent, if returned. */
299
+ expiresAt?: string;
300
+ /** The unsigned funding payload to sign with the delegate key (account → delegate EOA). */
301
+ signData: SignData;
302
+ /** The selected x402 option — the edge needs this to build the EIP-3009 header. */
303
+ accepted: X402PaymentOption;
304
+ /** Resource URL the 402 came from. */
305
+ resourceUrl: string;
306
+ /** Merchant payTo address (the final recipient of the EIP-3009 transfer). */
307
+ merchantTo: string;
308
+ /** Atomic amount the edge signer must authorize in the merchant header. */
309
+ amountAtomic: string;
310
+ /** Token contract the merchant header must pay. */
311
+ asset: string;
312
+ /** x402 network the merchant header must use. */
313
+ network: string;
314
+ /** Haven-authenticated binding over the x402 expected context. */
315
+ expectedAuth: X402ExpectedAuth;
316
+ /**
317
+ * #1690: the payer identity Haven bound into the expected context (v3),
318
+ * relayed VERBATIM to the signer's wire shape. Absent until the backend
319
+ * flips X402_EMIT_PAYER_CONTEXT.
320
+ */
321
+ payerDelegate?: string;
322
+ payerAgentId?: string;
323
+ /**
324
+ * EIP-712 digest of `signData.typed_data`, present on the delegation rail
325
+ * (#1138). The edge signer needs it to reconstruct the v2 expected-context
326
+ * message that Haven signed.
327
+ */
328
+ expectedTypedDataHash?: string;
329
+ /** Delegate EOA the funding transfer tops up (the x402 payer). */
330
+ fundingTo: string;
331
+ }
332
+ interface X402ExpectedContext {
333
+ paymentId: string;
334
+ payloadHash: string;
335
+ resourceUrl: string;
336
+ merchantTo: string;
337
+ amount: string;
338
+ asset: string;
339
+ network: string;
340
+ /** Optional ISO expiry for the funding/quote window. When present, it is bound into the Haven-authenticated context. */
341
+ expiresAt?: string;
342
+ /**
343
+ * EIP-712 digest of the typed data the account actually validates
344
+ * (delegation rail, #1138). Present ⇒ the context is **version 2** and the
345
+ * signer must sign that typed data, never `payloadHash`.
346
+ *
347
+ * On the delegation rail `payloadHash` is the bare ERC-4337 UserOp hash,
348
+ * which is NOT what the account validates — binding it alone would leave the
349
+ * edge signer unable to verify the payload it is being asked to sign. Binding
350
+ * this digest makes Haven's declaration cover the real payload.
351
+ *
352
+ * Absent ⇒ the retired version-1 bare-hash context. Since #3272 the backend
353
+ * never emits one (`signX402ExpectedContext` requires this field) and
354
+ * `@haven_ai/signer` refuses it with its version-mismatch refusal; the field
355
+ * stays optional here only because the type also describes older payloads.
356
+ */
357
+ typedDataHash?: string;
358
+ /**
359
+ * The DELEGATE ADDRESS this quote was created for (#1690). Present ⇒ the
360
+ * context is **version 3** and the signer refuses to sign when this is not
361
+ * its own delegate — the guard that turns "quote as agent A, sign as agent
362
+ * B" from an on-chain revert three layers later into a named refusal.
363
+ * Inside the Haven-signed message on purpose: outside it, it is forgeable.
364
+ */
365
+ payerDelegate?: string;
366
+ /** The paying agent's id, for the refusal message's diagnosis (#1690). */
367
+ payerAgentId?: string;
368
+ }
369
+ interface X402ExpectedAuth {
370
+ /**
371
+ * 2 = carries `typedDataHash` (delegation rail, #1138). 3 = additionally binds
372
+ * the payer identity (#1690). 1 (hash-only, retired Safe rail) is never
373
+ * emitted since #3272 and the signer refuses it.
374
+ *
375
+ * Deliberately `number`, not a literal union (#1143). This is an **inbound**
376
+ * value: a signer parses a context Haven produced, and a signer older than the
377
+ * backend will legitimately receive a version it does not know. A closed union
378
+ * makes that state unrepresentable, which pushed the rejection down to the
379
+ * schema boundary and produced a raw validation error naming neither the cause
380
+ * nor the fix. The supported set lives in the signer
381
+ * (`SUPPORTED_X402_EXPECTED_VERSIONS`), which fails closed on anything outside
382
+ * it with an actionable message.
383
+ */
384
+ version: number;
385
+ message: string;
386
+ signature: string;
387
+ signer: string;
388
+ }
389
+ /** Serializable HTTP request state for retrying the same x402 merchant request. */
390
+ interface X402RequestSnapshot {
391
+ url: string;
392
+ method: string;
393
+ headers: [string, string][];
394
+ body?: string;
395
+ }
396
+ interface X402McpTransport {
397
+ handshakeRequired: boolean;
398
+ source: 'path' | 'bazaar';
399
+ }
400
+ /**
401
+ * #1307: the merchant MCP-tool call an x402 quote was made against — carried
402
+ * through `createX402Intent`'s options so Haven can persist it for the
403
+ * settle-leg rehydration handoff (`getX402MerchantCallContext`). Convenience
404
+ * metadata for retrying the merchant's OWN JSON-RPC call, never payment
405
+ * authority.
406
+ */
407
+ interface X402McpCallContext {
408
+ merchantUrl: string;
409
+ toolName: string;
410
+ arguments?: Record<string, unknown>;
411
+ mcpTransport?: X402McpTransport;
412
+ }
413
+ /**
414
+ * Response shape of `getX402MerchantCallContext` — the stored merchant call
415
+ * context for a payment_id, rehydrated instead of re-threaded (#1307).
416
+ */
417
+ interface X402MerchantCallContext {
418
+ paymentId: string;
419
+ merchantUrl: string;
420
+ toolName: string;
421
+ arguments: Record<string, unknown>;
422
+ mcpTransport?: X402McpTransport;
423
+ }
424
+ /** Quote parsed from an HTTP 402 response without creating a Haven payment. */
425
+ interface X402Quote {
426
+ rail: 'x402';
427
+ idempotencyKey: string;
428
+ paymentRequired: X402PaymentRequired;
429
+ accepted: X402PaymentOption;
430
+ /**
431
+ * #2054: which selector produced `accepted`, and therefore which entry every
432
+ * amount on this quote describes. `'standard'` is the untagged,
433
+ * EIP-3009-settleable entry; `'erc7710'` means the merchant advertises NO
434
+ * standard entry, so the quote describes its erc7710 one — settleable only
435
+ * from a delegation-rail account, a fact the quote layer cannot see (the
436
+ * rail is a property of the ACCOUNT, not of the 402). This field is
437
+ * descriptive: the actual settlement scheme is still chosen later, with the
438
+ * rail in hand, by `selectX402SettlementScheme`.
439
+ */
440
+ acceptedScheme: 'standard' | 'erc7710';
441
+ request: X402RequestSnapshot;
442
+ mcpTransport?: X402McpTransport;
443
+ resourceUrl: string;
444
+ /** #3097: `resourceUrl` (the merchant's declaration) is not `request.url` (what was quoted). */
445
+ resourceUrlDiffersFromRequest: boolean;
446
+ description: string | null;
447
+ mimeType: string | null;
448
+ amountAtomic: string;
449
+ amount: string;
450
+ token: string;
451
+ /**
452
+ * #1351: decimals for `asset` on `network`, resolved from the SAME
453
+ * address→token binding that produced `token` — the quote's own authority on
454
+ * how many atomic units one human unit is. `null` when the merchant's asset
455
+ * is not a token Haven recognises on that network, in which case `token` is
456
+ * an unverified fallback label and NO human→atomic conversion is safe.
457
+ * Consumers converting a human-denominated figure (a user-intent spending
458
+ * cap) MUST fail closed on `null` rather than assume 6.
459
+ */
460
+ decimals: number | null;
461
+ asset: string;
462
+ network: string;
463
+ chainId: number | null;
464
+ merchantAddress: string;
465
+ maxTimeoutSeconds: number;
466
+ }
467
+ /** State bundle an agent can persist while waiting for manual x402 approval. */
468
+ interface X402ResumeState {
469
+ rail: 'x402';
470
+ paymentId: string;
471
+ idempotencyKey: string;
472
+ paymentRequired: X402PaymentRequired;
473
+ accepted: X402PaymentOption;
474
+ url: string;
475
+ request?: X402RequestSnapshot;
476
+ resourceUrl: string;
477
+ description: string | null;
478
+ amountAtomic: string;
479
+ amount: string;
480
+ token: string;
481
+ asset: string;
482
+ network: string;
483
+ chainId: number | null;
484
+ merchantAddress: string;
485
+ }
486
+ type PaymentResumeState = X402ResumeState;
487
+ interface ResumeAuthorizedX402Input extends X402AuthorizationOptions {
488
+ /** Payment or approval request ID returned by authorizeX402 / haven.fetch. */
489
+ paymentId: string;
490
+ /** Original or freshly parsed x402 requirements for the merchant retry. */
491
+ paymentRequired: X402PaymentRequired;
492
+ }
493
+ interface ResumeX402PaymentInput extends X402AuthorizationOptions {
494
+ /** Payment or approval request ID returned by authorizeX402 / haven.fetch. */
495
+ paymentId: string;
496
+ /** Original paid URL. If paymentRequired is omitted, Haven will call it once to re-read the 402 challenge. */
497
+ url: string;
498
+ /** Original fetch options. Reused for the 402 probe and final merchant retry. */
499
+ init?: RequestInit;
500
+ /** Serializable original request captured by quoteX402() / pending approval errors. */
501
+ request?: X402RequestSnapshot;
502
+ /** Original or freshly parsed x402 requirements. Supplying this avoids an extra merchant 402 probe. */
503
+ paymentRequired?: X402PaymentRequired;
504
+ }
505
+ type MachinePaymentRail = 'x402' | 'mpp_demo' | 'mpp_crypto' | 'stripe_deposit' | 'spt';
506
+ interface HavenAgent {
507
+ id: string;
508
+ name: string;
509
+ status: string;
510
+ /** The agent's Haven account (smart account) address. */
511
+ accountAddress: string;
512
+ delegateAddress: string;
513
+ chainId: number;
514
+ /**
515
+ * Which on-chain policy primitive gates this agent's spend (#1306): the
516
+ * legacy Safe AllowanceModule (retired — no account can enter it since
517
+ * #1984, and it cannot spend since #1986) or the delegation
518
+ * rail's active budget delegations (#1090). Read-only reporting — the
519
+ * on-chain state is the actual gate either way, this only says which
520
+ * mechanism a caller should read/derive from.
521
+ */
522
+ executionRail: 'legacy' | 'delegation';
523
+ }
524
+ interface HavenAllowance {
525
+ id: string;
526
+ tokenAddress: string;
527
+ tokenSymbol: string;
528
+ configuredAmount: string;
529
+ resetPeriodMin: number;
530
+ /**
531
+ * #3128: human-readable `onchain.remaining`, e.g. "4.96 USDC" — the SAME
532
+ * string {@link HavenAgentAllowanceSummary.remainingDisplay} carries for
533
+ * this allowance, computed by one function from `onchain.remaining` and
534
+ * the token's decimals, so the two reads cannot disagree. Additive; the
535
+ * wire carries no display form (it is derived client-side).
536
+ */
537
+ remainingDisplay: string;
538
+ onchain: {
539
+ amount: string;
540
+ spent: string;
541
+ remaining: string;
542
+ effectiveSpent: string;
543
+ resetTimeMin: number;
544
+ lastResetMin: number;
545
+ nonce: number;
546
+ isResetPending: boolean;
547
+ /**
548
+ * Delegation rail only (#1319, provenance for #1145's fallback): true
549
+ * when `remaining` came from a live on-chain enforcer read, false when
550
+ * the read failed and `remaining` is the fallback full configured
551
+ * budget. Undefined on the legacy AllowanceModule rail, which has no
552
+ * fallback concept. Reporting only — the on-chain policy remains the
553
+ * actual spend gate either way.
554
+ */
555
+ remainingIsFromChain?: boolean;
556
+ };
557
+ }
558
+ interface HavenAllowanceSummary {
559
+ agentId: string;
560
+ accountAddress: string;
561
+ delegateAddress: string;
562
+ chainId: number;
563
+ allowances: HavenAllowance[];
564
+ }
565
+ /**
566
+ * Post-purchase allowance/budget summary attached to a settled x402 payment
567
+ * (#1310). Read-only reporting — the on-chain policy remains the actual
568
+ * spend gate either way, this only says what is left after the purchase.
569
+ *
570
+ * Deliberately the SAME rail-labeled field spelling as #1306's
571
+ * catalog-purchase preflight `allowance` block (never a new spelling),
572
+ * minus the preflight-only `sufficient` field: post-purchase reporting
573
+ * answers "what is left", not "was this purchase covered". Read through the
574
+ * exact same source as {@link HavenAllowanceSummary} / `haven_get_allowances`
575
+ * (`GET /machine-payments/allowances`; delegation-rail values are the #1090
576
+ * `deriveDelegationBudgets`-backed enforcer read, never `agent_allowances`),
577
+ * so this can never disagree with `haven_get_allowances` for the same
578
+ * fixture.
579
+ */
580
+ interface PostPurchaseAllowanceSummary {
581
+ /** Which on-chain policy primitive gates this agent's spend (#1306 labeling). */
582
+ rail: 'legacy' | 'delegation';
583
+ /** Remaining atomic units, read through the same source as {@link HavenAllowance.onchain.remaining}. */
584
+ remaining_atomic: string;
585
+ /** Human-readable remaining, e.g. "4.96 USDC". Omitted when the token's decimals are unknown. */
586
+ remaining_display?: string;
587
+ token_symbol?: string;
588
+ token_address?: string;
589
+ /** Minutes — mirrors {@link HavenAllowance.resetPeriodMin} / the delegation's period. */
590
+ reset_period?: number;
591
+ source: 'allowance_module' | 'active_delegations';
592
+ }
593
+ /**
594
+ * #3126 — the answer to "is there money actually HELD behind my budget?",
595
+ * asked as a sufficiency signal rather than a balance.
596
+ *
597
+ * Every other agent-readable figure in this package describes SPEND
598
+ * AUTHORITY — what the agent is PERMITTED to move this period
599
+ * ({@link HavenAllowanceSummary}). This shape answers the different question
600
+ * of whether the account HOLDS funds behind that authority, and deliberately
601
+ * answers it as `covered: boolean | null`, never as a figure: a constrained
602
+ * actor has no business reading the treasury total, and the boolean answers
603
+ * the only decision an agent has (attempt the payment, or tell the user
604
+ * funds are missing).
605
+ *
606
+ * The naming keeps the two concepts apart (the #3126 binding constraint):
607
+ * `budgetRemainingAtomic` is AUTHORITY — the same value
608
+ * {@link HavenAllowanceSummary} reports per token as `onchain.remaining` —
609
+ * while `covered` speaks only of HELD funds. Nothing here is named like the
610
+ * authority fields (`remaining`, `available`); nothing here returns a
611
+ * balance.
612
+ *
613
+ * `covered: null` means the chain read FAILED — unverifiable, never a
614
+ * guess. The same honesty rule `x402-funding-leg.ts`'s `delegateCanFund`
615
+ * established (#1521): treat null as "we do not know", not as "funded" or
616
+ * as absence; `coverageError` carries why.
617
+ */
618
+ interface HavenBalanceCoverage {
619
+ /**
620
+ * true: the chain reports the agent's account holds at least
621
+ * `checkedAmountAtomic` of the token. false: the chain read succeeded and
622
+ * reports LESS — tell the user funds are missing rather than retrying.
623
+ * null: the chain read failed — unverifiable, never treated as absence.
624
+ */
625
+ covered: boolean | null;
626
+ /** Present only when `covered` is null: why the chain read could not answer. */
627
+ coverageError?: string;
628
+ chainId: number;
629
+ tokenAddress: string;
630
+ tokenSymbol: string;
631
+ /** The amount the coverage question was asked about, in atomic units. */
632
+ checkedAmountAtomic: string;
633
+ /**
634
+ * Context, AUTHORITY not holdings: the agent's remaining spend authority
635
+ * for the requested token, in atomic units — the same derivation
636
+ * {@link HavenAllowanceSummary} reports (`onchain.remaining`; the #1090
637
+ * derivation, the #1145 enforcer read). Zero when no active budget row
638
+ * names the token. Compare it with `covered`, never instead of it.
639
+ */
640
+ budgetRemainingAtomic: string;
641
+ /**
642
+ * Provenance of `budgetRemainingAtomic` (#1319, same semantics as
643
+ * {@link HavenAllowance.onchain.remainingIsFromChain}): true when the
644
+ * budget figure came from a live enforcer read, false when it fell back
645
+ * to the configured budget. Absent when no budget row existed for the
646
+ * token (nothing was read).
647
+ */
648
+ budgetRemainingIsFromChain?: boolean;
649
+ }
650
+ /**
651
+ * Affirmative spend-readiness for the authenticated agent, derived from the raw
652
+ * agent status plus the remaining spend authority the backend reports per rail
653
+ * (the active budget delegation on the delegation rail — #1135; the retired
654
+ * AllowanceModule rail used an on-chain allowance instead):
655
+ * - `ready` — active and at least one token has remaining spend authority.
656
+ * - `needs_approval`— active but no remaining spend authority to auto-spend.
657
+ * The over-budget outcome differs by rail: on the retired
658
+ * AllowanceModule rail the payment was queued for the wallet
659
+ * owner to approve in Haven; on the delegation rail there is
660
+ * NO approval queue — an over-budget redemption reverts
661
+ * on-chain, so the owner must grant or raise the budget in
662
+ * Haven before the agent can pay.
663
+ * - `revoked` — the agent's status is not `active`; nothing auto-executes.
664
+ *
665
+ * Note: a hard-paused/disabled credential is rejected by the API before this
666
+ * call returns, so it surfaces as an API error rather than `revoked`. `revoked`
667
+ * is reached when the request authenticates but the agent status is non-active.
668
+ *
669
+ * Wallet token balance is intentionally NOT folded in here: the on-chain
670
+ * remaining allowance is the gate Haven enforces, and insufficient wallet
671
+ * funding surfaces at pay time as INSUFFICIENT_FUNDS.
672
+ */
673
+ type HavenAgentReadiness = 'ready' | 'needs_approval' | 'revoked';
674
+ /**
675
+ * Compact, agent-facing per-token spend authority for the bootstrap summary.
676
+ *
677
+ * #3128: a deliberately DIFFERENT view of the same allowance as
678
+ * {@link HavenAllowance} — flat, no `onchain` block, no spent/nonce/reset-time
679
+ * detail — but never a disjoint one: every field here is present on or
680
+ * derived from the {@link HavenAllowance} with the same `id`, and
681
+ * `remainingAtomic` / `remainingDisplay` equal that allowance's
682
+ * `onchain.remaining` / `remainingDisplay` byte for byte (pinned by test). A
683
+ * client that wants the id AND a display amount can therefore use either
684
+ * read alone.
685
+ */
686
+ interface HavenAgentAllowanceSummary {
687
+ /** #3128: the {@link HavenAllowance.id} this row summarises. */
688
+ id: string;
689
+ tokenSymbol: string;
690
+ /** #3128: the {@link HavenAllowance.tokenAddress}. */
691
+ tokenAddress: string;
692
+ /** Live on-chain remaining allowance in atomic units. */
693
+ remainingAtomic: string;
694
+ /** Human-readable remaining, e.g. "4.96 USDC". */
695
+ remainingDisplay: string;
696
+ /** Configured allowance amount (atomic) the owner granted. */
697
+ configuredAmount: string;
698
+ resetPeriodMin: number;
699
+ isResetPending: boolean;
700
+ }
701
+ /**
702
+ * One-shot "am I ready?" bootstrap: identity + live spend authority + a
703
+ * readiness signal, so an agent can answer "who am I and can I pay right now"
704
+ * from a single call at session start. Superset of {@link HavenAgent}.
705
+ */
706
+ interface HavenAgentSummary extends HavenAgent {
707
+ /**
708
+ * @deprecated Use {@link HavenAgentSummary.spend_authority_readiness} —
709
+ * same value, honest name. This signal covers hosted identity + on-chain
710
+ * spend authority ONLY; it says nothing about the LOCAL signer, which the
711
+ * hosted side cannot see (verify via a signer tool or connect --doctor).
712
+ * Kept as an alias; removal earliest after the next release train (#1590).
713
+ */
714
+ readiness: HavenAgentReadiness;
715
+ /**
716
+ * Spend-authority readiness: hosted identity + on-chain remaining spend
717
+ * authority. Deliberately named for what it covers — the LOCAL signer's
718
+ * availability is NOT included and must be verified separately (a signer
719
+ * tool call, or the connector's `--doctor`, whose exact command this build
720
+ * renders from `HAVEN_CONNECTOR_CHANNEL` — see `connector-channel.ts`).
721
+ */
722
+ spend_authority_readiness: HavenAgentReadiness;
723
+ allowances: HavenAgentAllowanceSummary[];
724
+ /**
725
+ * #3329: open, unexpired task budgets — a derived VIEW, same discipline as
726
+ * {@link HavenAgentSummary.allowances}. Populated from
727
+ * `GET /task-budgets?status=open`; empty (never throws) against a backend
728
+ * that predates #3329's route (a 404 there is treated as "no task
729
+ * budgets", not a fetch failure).
730
+ */
731
+ taskBudgets: HavenTaskBudgetSummary[];
732
+ }
733
+ /** #3329: task-budget lifecycle status, as the wire names it. */
734
+ type HavenTaskBudgetStatus = 'pending' | 'open' | 'closing' | 'closed';
735
+ /** #3329: `RawTaskBudget`, camelCased — what every SDK task-budget method returns. */
736
+ interface HavenTaskBudget {
737
+ id: string;
738
+ agentId: string;
739
+ chainId: number;
740
+ tokenAddress: string;
741
+ recipientAddress: string | null;
742
+ parentDelegationHash: string;
743
+ delegationHash: string;
744
+ label: string | null;
745
+ maxAtomic: string;
746
+ status: HavenTaskBudgetStatus;
747
+ expiresAt: number;
748
+ isExpired: boolean;
749
+ createdAt: string;
750
+ openedAt: string | null;
751
+ closedAt: string | null;
752
+ closeTxHash: string | null;
753
+ }
754
+ /**
755
+ * #3329: the condensed row `getAgentSummary()` carries per open, unexpired
756
+ * task budget — enough to render a "reserved by open task budgets" line and
757
+ * a task-budget list without a second read.
758
+ */
759
+ interface HavenTaskBudgetSummary {
760
+ id: string;
761
+ label: string | null;
762
+ tokenAddress: string;
763
+ maxAtomic: string;
764
+ maxDisplay: string;
765
+ recipientAddress: string | null;
766
+ expiresAt: number;
767
+ }
768
+ /** #3329: `POST /task-budgets` and `POST /task-budgets/:id/close` — the sign-then-submit envelope. */
769
+ interface HavenTaskBudgetSignData {
770
+ signature_scheme: 'eip712_delegation' | 'eip712_userop';
771
+ typed_data: Record<string, unknown>;
772
+ }
773
+ interface OpenTaskBudgetResult {
774
+ taskBudget: HavenTaskBudget;
775
+ signData: HavenTaskBudgetSignData;
776
+ nextAction: string;
777
+ instructions: string;
778
+ }
779
+ interface CloseTaskBudgetResult {
780
+ taskBudget: HavenTaskBudget;
781
+ status: HavenTaskBudgetStatus;
782
+ /** Present only when the close needed a signature (an OPEN, unexpired budget). */
783
+ signData?: HavenTaskBudgetSignData;
784
+ nextAction?: string;
785
+ }
786
+ interface SubmitTaskBudgetResult {
787
+ taskBudget: HavenTaskBudget;
788
+ status: HavenTaskBudgetStatus;
789
+ /** Present only once the close UserOp lands (`status === 'closed'` from `closing`). */
790
+ closeTxHash?: string;
791
+ }
792
+ /** #3329: `GET /task-budgets/:id/sign-context` — `purpose: 'open'` shape. */
793
+ interface TaskBudgetOpenSignContext {
794
+ taskBudgetId: string;
795
+ purpose: 'open';
796
+ taskSignContextVersion: number;
797
+ typedData: Record<string, unknown>;
798
+ expected: {
799
+ delegateAccount: string;
800
+ chainId: number;
801
+ tokenAddress: string;
802
+ maxAmountAtomic: string;
803
+ recipientAddress: string | null;
804
+ expiresAt: number;
805
+ parentDelegationHash: string;
806
+ };
807
+ }
808
+ /** #3329: `GET /task-budgets/:id/sign-context` — `purpose: 'close'` shape. */
809
+ interface TaskBudgetCloseSignContext {
810
+ taskBudgetId: string;
811
+ purpose: 'close';
812
+ taskSignContextVersion: number;
813
+ typedData: Record<string, unknown>;
814
+ userOperation: Record<string, unknown>;
815
+ userOpHash: string;
816
+ expected: {
817
+ delegateAccount: string;
818
+ chainId: number;
819
+ delegationHash: string;
820
+ };
821
+ }
822
+ type TaskBudgetSignContext = TaskBudgetOpenSignContext | TaskBudgetCloseSignContext;
823
+ /**
824
+ * #2960 — one party vocabulary for "who paid" a Haven payment, additive
825
+ * alongside every existing lone `payer*`/`*Address` field (same discipline
826
+ * as the #2907 `safe`/`account` dual-emit, except these four are DISTINCT
827
+ * addresses, not same-value twins of one old field).
828
+ */
829
+ interface PaymentParties {
830
+ treasuryAccount: string | null;
831
+ delegate: string | null;
832
+ delegateAccount: string | null;
833
+ merchant: string | null;
834
+ }
835
+ /** @internal wire shape of {@link PaymentParties}. */
836
+ interface RawPaymentParties {
837
+ treasury_account: string | null;
838
+ delegate: string | null;
839
+ delegate_account: string | null;
840
+ merchant: string | null;
841
+ }
842
+ /**
843
+ * #3132 (owner decision 3 on #3130): what population a list row came from and
844
+ * what narrowed it, as two values. Receipts are `{ source: 'agent', filter:
845
+ * null }` — this agent's evidence rows only, no query-time narrowing. The
846
+ * wallet feed (`GET /transactions`, the CLI's `activity list`) is
847
+ * `source: 'wallet'` with `filter: 'agent'` when `agentId` narrows it, and it
848
+ * is a DIFFERENT population (explorer window plus synthesized intents; sweeps
849
+ * and funding legs included), never this view. A receipt read is not a
850
+ * transaction-history read.
851
+ */
852
+ interface HavenListScope {
853
+ source: 'wallet' | 'agent';
854
+ filter: 'agent' | 'account' | 'account+agent' | null;
855
+ }
856
+ interface HavenPaymentReceipt {
857
+ id: string;
858
+ /** #3132: present when the backend states it (absent on an older backend). */
859
+ scope?: HavenListScope;
860
+ paymentId: string;
861
+ paymentIntentId?: string | null;
862
+ approvalRequestId?: string | null;
863
+ /**
864
+ * #3134: the payment protocol this receipt settled on — one of the
865
+ * evidence-eligible rails (`x402`, `mpp_demo`, `mpp_crypto`, `spt`) — under the
866
+ * name the transactions feed uses for the same concept. Distinct from
867
+ * `scope.source`, which names the LIST population (#3132) — the transaction
868
+ * row carries the same two. Same name, narrower domain: never `'direct'`
869
+ * here — the feed's SQL default for an intent that names no protocol has no
870
+ * receipt analogue, because no protocol means no evidence row.
871
+ */
872
+ source: string;
873
+ /**
874
+ * #3134: the evidence row's recorded proof status, under the transactions
875
+ * feed's name. Same name, different nullability: `string` here because a
876
+ * receipt IS the evidence row, `string | null` on the feed, where a row may
877
+ * LEFT JOIN to none (#3132) — do not share a non-null-asserting helper.
878
+ */
879
+ paymentProofStatus: string;
880
+ /**
881
+ * @deprecated (#2998) meaning depends on the settlement scheme — the
882
+ * account → delegate funding transaction on eip3009, the (only) settlement
883
+ * transaction on erc7710. Prefer {@link fundingTxHash} / {@link settlementTxHash}, which
884
+ * name which is which.
885
+ */
886
+ txHash: string;
887
+ /** The account → delegate funding transaction, relayed by Haven (#2998); null on erc7710 (no funding leg) and on retired mpp-rail rows. */
888
+ fundingTxHash: string | null;
889
+ /**
890
+ * The delegate → merchant settlement transaction (#2998). Trust level differs
891
+ * by scheme: on erc7710 it is `txHash` itself and Haven VERIFIED it on-chain
892
+ * before the receipt existed; on eip3009 it is the merchant's claim as relayed
893
+ * (PAYMENT-RESPONSE), NOT verified on-chain by Haven — cite it as such.
894
+ */
895
+ settlementTxHash: string | null;
896
+ chainId: number;
897
+ /** #3134: the paid resource, under the transactions feed's protocol-prefixed name (`string | null` there; a receipt always has one). */
898
+ x402ResourceUrl: string;
899
+ /** #3134: the merchant paid, under the transactions feed's protocol-prefixed name. */
900
+ x402MerchantAddress: string | null;
901
+ payerAddress: string;
902
+ /** #2960: additive alongside `payerAddress` above (`parties.treasury_account` only). */
903
+ parties?: PaymentParties;
904
+ settlementAddress: string;
905
+ tokenSymbol: string;
906
+ tokenAddress: string;
907
+ amountRaw: string;
908
+ amount: string;
909
+ challengeId: string | null;
910
+ idempotencyKey: string | null;
911
+ challengePayload?: Record<string, unknown> | null;
912
+ selectedPayment?: Record<string, unknown> | null;
913
+ paymentProofHeaderName: string | null;
914
+ protocolReceiptHeaderName: string | null;
915
+ /**
916
+ * #3125 — the merchant's `PAYMENT-RESPONSE` object relayed VERBATIM:
917
+ * opaque, unvalidated, unverified, MERCHANT-CONTROLLED third-party data.
918
+ * Haven neither authors nor verifies anything inside it, including
919
+ * `protocolReceiptPayload.payer` —
920
+ * that `payer` is the merchant's claim, NOT Haven's record, and is not
921
+ * {@link payerAddress} (Haven's own, authoritative; field observation
922
+ * 2026-09-18: the two held different addresses on every row read). For who
923
+ * paid, read `parties` ({@link PaymentParties}) — `treasuryAccount`,
924
+ * `delegate`, `delegateAccount`, `merchant` are Haven-derived and
925
+ * authoritative; anything inside this object is not.
926
+ *
927
+ * Deliberately NOT namespaced or key-prefixed on the wire (#3125): the
928
+ * relay must stay the merchant's object verbatim (its `transaction` key
929
+ * feeds `settlementTxHash`), and prefixing the envelope could not prefix
930
+ * the merchant-controlled keys inside it — the `payer` collision lives
931
+ * there, so provenance is made legible at the read surfaces instead (this
932
+ * comment and the tool descriptions).
933
+ */
934
+ protocolReceiptPayload?: Record<string, unknown> | null;
935
+ merchantStatus: number | null;
936
+ confirmedAt: string | null;
937
+ createdAt: string;
938
+ updatedAt: string;
939
+ }
940
+ /**
941
+ * How long this SDK waits for an on-chain confirmation before it stops
942
+ * waiting (#1756).
943
+ *
944
+ * Lives here rather than in `client.ts` so the payment-confirmation poller
945
+ * and the delegate sweep share ONE number instead of forking it. The SDK's
946
+ * other chain waits are already bounded (`waitForFundingTx` at 30 s), so a
947
+ * fourth independently chosen literal is exactly the drift this constant
948
+ * exists to prevent.
949
+ */
950
+ declare const DEFAULT_CONFIRMATION_TIMEOUT_MS = 90000;
951
+ /**
952
+ * Whether a sweep transfer was observed to confirm (#1756).
953
+ *
954
+ * The distinction is the point: `unconfirmed` means the transfer was
955
+ * BROADCAST and may still land, which is neither success nor failure. It must
956
+ * never be collapsed into either — reporting a still-pending transaction as
957
+ * done, or as failed, are the same defect in opposite directions.
958
+ */
959
+ type SweepConfirmation =
960
+ /** A receipt was observed. The funds are in the agent's Haven account. */
961
+ 'confirmed'
962
+ /**
963
+ * Broadcast, but no receipt within `DEFAULT_CONFIRMATION_TIMEOUT_MS` (or the
964
+ * node returned no receipt). The transaction is still in the mempool and may
965
+ * mine at any time. `txHash` is the broadcast hash — check it on the
966
+ * explorer before re-running the sweep, and expect a re-run to find nothing
967
+ * stranded if it has since landed.
968
+ */
969
+ | 'unconfirmed';
970
+ /** One transferred asset in a delegate sweep. */
971
+ interface SweepEntry {
972
+ /** 'USDC' or 'ETH' */
973
+ asset: string;
974
+ /** Human-readable amount swept (e.g. "0.12") */
975
+ amount: string;
976
+ /** Atomic amount swept */
977
+ amountAtomic: string;
978
+ /**
979
+ * Transaction hash of the sweep transfer.
980
+ *
981
+ * The RECEIPT hash when `confirmation` is `confirmed`; the BROADCAST hash
982
+ * when it is `unconfirmed` — which is the whole reason the sweep returns
983
+ * instead of throwing on a deadline, since this hash is the only thing that
984
+ * lets a user recover the transfer by hand (#1756).
985
+ */
986
+ txHash: string;
987
+ /** Block explorer URL for the tx */
988
+ explorerUrl: string;
989
+ /**
990
+ * Did this transfer confirm on-chain within the deadline? (#1756)
991
+ *
992
+ * `unconfirmed` entries have MOVED NOTHING YET and may still move. Do not
993
+ * report a sweep as complete without checking this on every entry.
994
+ */
995
+ confirmation: SweepConfirmation;
996
+ }
997
+ /** Result of a `sweepDelegate()` call. */
998
+ interface SweepResult {
999
+ /** Address funds were swept FROM */
1000
+ fromAddress: string;
1001
+ /** Address funds were swept TO (always the agent's Haven account) */
1002
+ toAddress: string;
1003
+ /** Chain the sweep occurred on */
1004
+ chainId: number;
1005
+ /** One entry per transferred asset. Empty when nothing was stranded. */
1006
+ transfers: SweepEntry[];
1007
+ /**
1008
+ * True when ANY entry is `unconfirmed` — i.e. the sweep broadcast something
1009
+ * it could not confirm within the deadline (#1756).
1010
+ *
1011
+ * Derived from `transfers`, and present anyway because the consumer most
1012
+ * likely to misread this result is an LLM reading the JSON of the
1013
+ * `haven_sweep_delegate` tool, which will otherwise see a populated
1014
+ * `transfers` array and report the money as recovered.
1015
+ */
1016
+ unconfirmed: boolean;
1017
+ }
1018
+ type PaymentStateKind = 'payment_intent' | 'approval_request';
1019
+ interface AgentPaymentEnumSchema {
1020
+ type: 'string';
1021
+ enum: readonly string[];
1022
+ description: string;
1023
+ 'x-enumDescriptions': Record<string, string>;
1024
+ }
1025
+ declare const AgentPaymentPhase: {
1026
+ /** The agent must sign and submit the prepared payment before Haven can relay it. */
1027
+ readonly AgentSignatureRequired: "agent_signature_required";
1028
+ /** Haven has received the signed payment and the agent should poll for confirmation. */
1029
+ readonly PaymentSubmitted: "payment_submitted";
1030
+ /** The direct payment is confirmed; the agent does not need to do more for this payment id. */
1031
+ readonly PaymentConfirmed: "payment_confirmed";
1032
+ /**
1033
+ * #2115: RETIRED wire value — no live rail produces it. It described the
1034
+ * Safe rail's approval queue, which no longer exists. Kept so a stored value
1035
+ * still typechecks; see `AgentPaymentPhaseDescriptions` below for the
1036
+ * agent-visible wording, which this comment used to contradict.
1037
+ */
1038
+ readonly UserApprovalRequired: "user_approval_required";
1039
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
1040
+ readonly UserExecutionRequired: "user_execution_required";
1041
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
1042
+ readonly WaitingForAdditionalApprovals: "waiting_for_additional_approvals";
1043
+ /** The Haven funding leg was sent; the agent can continue the merchant/protocol leg. */
1044
+ readonly FundingSent: "funding_sent";
1045
+ /** The payment was rejected and cannot proceed; the agent should stop and tell the user. */
1046
+ readonly Rejected: "rejected";
1047
+ /** The payment expired before completion. */
1048
+ readonly Expired: "expired";
1049
+ /** Haven could not complete the payment; the agent should stop and surface the failure. */
1050
+ readonly Failed: "failed";
1051
+ /**
1052
+ * Pre-flight check determined the delegate's existing balance plus the
1053
+ * remaining on-chain budget cannot cover the requested amount, so no
1054
+ * payment intent was created. The account must be funded or the agent's
1055
+ * budget raised before retrying — #2115: the old wording contrasted this
1056
+ * with `UserApprovalRequired` as if that were a live alternative, and named
1057
+ * the retired rail's Safe and per-token allowance as the fix.
1058
+ */
1059
+ readonly InsufficientFunds: "insufficient_funds";
1060
+ /**
1061
+ * Haven's funding leg (account → delegate, the #946 EIP-3009 bridge)
1062
+ * confirmed on-chain, but the merchant rejected the x402 retry. The delegate
1063
+ * wallet may hold stranded USDC that was never settled to the merchant. The
1064
+ * agent should stop, tell the user, and wait for the sweep flow to reclaim
1065
+ * the funds.
1066
+ */
1067
+ readonly FundedButUnsettled: "funded_but_unsettled";
1068
+ };
1069
+ type AgentPaymentPhase = (typeof AgentPaymentPhase)[keyof typeof AgentPaymentPhase];
1070
+ declare const AgentPaymentNextAction: {
1071
+ /** Sign with the delegate key and submit the payment to Haven. */
1072
+ readonly SignAndSubmitPayment: "sign_and_submit_payment";
1073
+ /** Poll getPaymentStatus later using this payment id. */
1074
+ readonly CheckStatusLater: "check_status_later";
1075
+ /** No further agent action is required for this payment id. */
1076
+ readonly None: "none";
1077
+ /**
1078
+ * #2115: RETIRED wire value — no live rail produces it and nothing maps to
1079
+ * it. Stop and tell the user rather than polling; no approval will arrive.
1080
+ */
1081
+ readonly WaitForUserApproval: "wait_for_user_approval";
1082
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user rather than polling. */
1083
+ readonly WaitForUserToCompletePayment: "wait_for_user_to_complete_payment";
1084
+ /** Resume this payment id and retry the original x402 request with the merchant payment header. */
1085
+ readonly RetryOriginalX402Request: "retry_original_x402_request";
1086
+ /** Stop retrying this payment and tell the user what happened. */
1087
+ readonly StopAndTellUser: "stop_and_tell_user";
1088
+ /** Ask again only if the user still wants the payment after expiry. */
1089
+ readonly RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it";
1090
+ /** #1307: retry the SAME tool call, supplying the explicit context fields the server could not rehydrate. */
1091
+ readonly RetryWithExplicitContext: "retry_with_explicit_context";
1092
+ /**
1093
+ * The x402 funding/quote window expired. Re-quote the same logical merchant
1094
+ * operation with the same idempotency key to stay double-charge-safe.
1095
+ */
1096
+ readonly PaymentWindowExpired: "payment_window_expired";
1097
+ /**
1098
+ * Stop and tell the user that the originating account needs to be funded or
1099
+ * the agent's per-token allowance needs to be raised before the payment
1100
+ * can succeed. A user approval will not fix this state on its own.
1101
+ *
1102
+ * #2914: the account-vocabulary spelling, and the only one — the
1103
+ * pre-#2907 `fund_safe_or_raise_allowance` wire value (and the
1104
+ * `AgentPaymentNextActionAccountAlias` seam #2908 added to bridge it) are
1105
+ * retired along with the rest of the #2908 compatibility window.
1106
+ */
1107
+ readonly FundAccountOrRaiseAllowance: "fund_account_or_raise_allowance";
1108
+ /**
1109
+ * The delegate wallet may hold funds that were sent from the agent's Haven
1110
+ * account but never settled to the merchant. The wallet owner should initiate
1111
+ * a sweep to return those funds to that account.
1112
+ */
1113
+ readonly SweepStrandedFunds: "sweep_stranded_funds";
1114
+ /**
1115
+ * #2970: a `submitted` erc7710 x402 intent whose settlement window has
1116
+ * passed with no on-chain settlement evidence Haven could verify. Distinct
1117
+ * from {@link CheckStatusLater}, which this REPLACES once the window is
1118
+ * past — but it is not futile: Haven's settlement sweep (120s tick) scans
1119
+ * each candidate over its own window plus a 120s clock-skew allowance, so
1120
+ * it can still attribute the settlement for a short while after this value
1121
+ * first appears. Poll {@link CheckStatusLater}'s tool
1122
+ * (`haven_get_payment_status`) once more, roughly two minutes later; if it
1123
+ * still shows no evidence, tell the user the goods were delivered but
1124
+ * Haven holds no verified settlement evidence for this payment. If the
1125
+ * agent holds the merchant's real settlement transaction hash (from
1126
+ * `PAYMENT-RESPONSE`'s `transaction` field, or a prior settle/complete
1127
+ * result's `settlement_tx_hash`), report it with the hosted
1128
+ * `haven_report_settlement_evidence` tool instead of waiting —
1129
+ * `haven_report_x402_outcome` takes no hash and refuses a non-`confirmed`
1130
+ * intent.
1131
+ */
1132
+ readonly AwaitingSettlementEvidence: "awaiting_settlement_evidence";
1133
+ };
1134
+ type AgentPaymentNextAction = (typeof AgentPaymentNextAction)[keyof typeof AgentPaymentNextAction];
1135
+ declare const AgentPaymentFailureCode: {
1136
+ /** A merchant-authoritative x402 price exceeds the caller's pre-funding max_amount cap. */
1137
+ readonly PriceExceedsMax: "PRICE_EXCEEDS_MAX";
1138
+ /** The x402 funding/quote window expired before the signer or hosted settle step could finish. */
1139
+ readonly PaymentWindowExpired: "PAYMENT_WINDOW_EXPIRED";
1140
+ /** The merchant rejected the paid retry. On eip3009 the funding leg had succeeded (sweep);
1141
+ * on erc7710 there is no funding leg — nothing to sweep, follow the message (#2983). */
1142
+ readonly MerchantRejectedAfterFunding: "MERCHANT_REJECTED_AFTER_FUNDING";
1143
+ /** #1300 review: funding is on-chain but the merchant never ANSWERED the
1144
+ * paid retry within the timeout. NOT proof of rejection — the merchant
1145
+ * may still settle late, so the guidance is verify-then-act. On eip3009
1146
+ * the funding leg had succeeded (verify-then-sweep); on erc7710 there is
1147
+ * no funding leg — nothing to sweep, follow the message (#3000). */
1148
+ readonly MerchantUnresponsiveAfterFunding: "MERCHANT_UNRESPONSIVE_AFTER_FUNDING";
1149
+ /**
1150
+ * #1307: the caller omitted merchant_url/tool_name (asking Haven to
1151
+ * rehydrate the stored MCP merchant-call context by payment_id), but no
1152
+ * usable context was stored for this intent — either it was never an
1153
+ * MCP-tool quote, or the stored context is incomplete. The fallback is
1154
+ * mechanical: re-send merchant_url, tool_name, arguments, and
1155
+ * mcp_transport explicitly (the version-skew path).
1156
+ */
1157
+ readonly MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE";
1158
+ /**
1159
+ * #1351: the caller supplied BOTH the atomic `max_amount` and the
1160
+ * human-denominated `max_amount_human` cap for one purchase. Haven refuses
1161
+ * to guess which the user meant — the two differ by a factor of 10^decimals,
1162
+ * so picking wrong is exactly the silent-overspend this cap exists to
1163
+ * prevent. Rejected before any merchant probe, funding intent, or signature.
1164
+ */
1165
+ readonly AmbiguousMaxAmount: "AMBIGUOUS_MAX_AMOUNT";
1166
+ /**
1167
+ * #1351: a human-denominated cap was supplied, but it cannot be converted to
1168
+ * atomic units against THIS quote — either the quote's asset has no known
1169
+ * decimals on its network, or the cap carries more fraction digits than the
1170
+ * asset can represent (truncating it would silently change the user's cap).
1171
+ * The fallback is the exact atomic `max_amount`.
1172
+ */
1173
+ readonly MaxAmountUnconvertible: "MAX_AMOUNT_UNCONVERTIBLE";
1174
+ /**
1175
+ * #2979: the merchant answered a `tools/call` probe with its own
1176
+ * machine-readable "cannot settle right now" refusal (HTTP 503,
1177
+ * `{ error: 'merchant_not_ready', reason_code, ... }`) instead of a 402
1178
+ * challenge — e.g. its settlement wallet is out of gas. No 402 was ever
1179
+ * issued and no payment was created; this is honest and (per
1180
+ * `retry_after_s`, when present) usually transient, unlike a permanent
1181
+ * endpoint miss.
1182
+ */
1183
+ readonly MerchantNotReady: "MERCHANT_NOT_READY";
1184
+ };
1185
+ type AgentPaymentFailureCode = (typeof AgentPaymentFailureCode)[keyof typeof AgentPaymentFailureCode];
1186
+ /**
1187
+ * Stable rail identifier carried on Haven agent payment responses and resume
1188
+ * state.
1189
+ *
1190
+ * Two layers of vocabulary share this enum because both reach the wire:
1191
+ *
1192
+ * - **Categorical rails** identify the rail family and are used as the
1193
+ * `PaymentResumeState` discriminator: `direct`, `x402` (`mpp` remains a
1194
+ * valid categorical VALUE on historical status reads, but #1328 retired
1195
+ * the `MppResumeState` variant that used to carry it — the mpp_demo
1196
+ * client resume flow no longer exists).
1197
+ * - **Granular rails** identify the specific protocol the backend persists
1198
+ * and returns on response bodies: `mpp_demo`, `mpp_crypto`,
1199
+ * `stripe_deposit`, `spt`. `x402` doubles as both categorical and
1200
+ * granular.
1201
+ *
1202
+ * Consumers reading the top-level `rail` field on a payment status response
1203
+ * should treat any `mpp*` value as the MPP family — this still applies to
1204
+ * historical `mpp_demo` rows, which remain readable.
1205
+ */
1206
+ declare const AgentPaymentRail: {
1207
+ /** Standard Haven payment from the user's account, redeemed through the agent's budget delegation. */
1208
+ readonly Direct: "direct";
1209
+ /** x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg. */
1210
+ readonly X402: "x402";
1211
+ /** Machine Payment Protocol family — categorical value used as a resume-state discriminator. */
1212
+ readonly Mpp: "mpp";
1213
+ /** Haven internal MPP demo rail. Not for production traffic. */
1214
+ readonly MppDemo: "mpp_demo";
1215
+ /** Crypto-settled MPP rail. */
1216
+ readonly MppCrypto: "mpp_crypto";
1217
+ /** Stripe-deposit-backed MPP rail. */
1218
+ readonly StripeDeposit: "stripe_deposit";
1219
+ /** Stripe Payment Token MPP rail. */
1220
+ readonly Spt: "spt";
1221
+ };
1222
+ type AgentPaymentRail = (typeof AgentPaymentRail)[keyof typeof AgentPaymentRail];
1223
+ type PaymentPhase = AgentPaymentPhase;
1224
+ type PaymentNextAction = AgentPaymentNextAction;
1225
+ declare const AGENT_PAYMENT_PHASE_VALUES: ("rejected" | "expired" | "failed" | "agent_signature_required" | "payment_submitted" | "payment_confirmed" | "user_approval_required" | "user_execution_required" | "waiting_for_additional_approvals" | "funding_sent" | "insufficient_funds" | "funded_but_unsettled")[];
1226
+ declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "retry_with_explicit_context" | "payment_window_expired" | "fund_account_or_raise_allowance" | "sweep_stranded_funds" | "awaiting_settlement_evidence")[];
1227
+ declare const AGENT_PAYMENT_FAILURE_CODE_VALUES: ("PRICE_EXCEEDS_MAX" | "PAYMENT_WINDOW_EXPIRED" | "MERCHANT_REJECTED_AFTER_FUNDING" | "MERCHANT_UNRESPONSIVE_AFTER_FUNDING" | "MERCHANT_CALL_CONTEXT_UNAVAILABLE" | "AMBIGUOUS_MAX_AMOUNT" | "MAX_AMOUNT_UNCONVERTIBLE" | "MERCHANT_NOT_READY")[];
1228
+ declare const AGENT_PAYMENT_RAIL_VALUES: ("x402" | "mpp_demo" | "mpp_crypto" | "stripe_deposit" | "spt" | "direct" | "mpp")[];
1229
+ declare const AgentPaymentPhaseDescriptions: Record<AgentPaymentPhase, string>;
1230
+ declare const AgentPaymentNextActionDescriptions: Record<AgentPaymentNextAction, string>;
1231
+ declare const AgentPaymentFailureCodeDescriptions: Record<AgentPaymentFailureCode, string>;
1232
+ /**
1233
+ * #1308: machine-readable warning codes carried in the `warnings` array on
1234
+ * x402 MCP tool responses. Warnings are ADVISORY — they never replace a
1235
+ * refusal, and existing failure codes stay authoritative for errors. The
1236
+ * legacy `cap_warning` string field is kept for compatibility; the structured
1237
+ * entry carries the same message under MISSING_MAX_AMOUNT.
1238
+ */
1239
+ declare const AgentPaymentWarningCode: {
1240
+ /** No max_amount cap was supplied — the live quoted price was accepted as-is. */
1241
+ readonly MissingMaxAmount: "MISSING_MAX_AMOUNT";
1242
+ /** The signing window closes soon; sign promptly or re-quote with the same idempotency key. */
1243
+ readonly QuoteExpiresSoon: "QUOTE_EXPIRES_SOON";
1244
+ /** The merchant URL was resolved via discovery — pass the RESOLVED url forward. */
1245
+ readonly MerchantUrlDiscovered: "MERCHANT_URL_DISCOVERED";
1246
+ /**
1247
+ * #1306: the catalog's last-verified price_atomic differs from the LIVE
1248
+ * merchant quote for a guided catalog purchase. The catalog price is only
1249
+ * ever indicative; the live quote in the same response is authoritative.
1250
+ */
1251
+ readonly CatalogPriceDiffers: "CATALOG_PRICE_DIFFERS";
1252
+ /**
1253
+ * #1306: the rail-aware allowance/budget pre-check could not be read (RPC
1254
+ * failure, etc). `sufficient` is reported as null rather than a fabricated
1255
+ * true/false — the on-chain policy remains the actual gate either way.
1256
+ */
1257
+ readonly AllowanceCheckUnavailable: "ALLOWANCE_CHECK_UNAVAILABLE";
1258
+ /**
1259
+ * #1319: the delegation-rail read itself SUCCEEDED, but the remaining
1260
+ * figure it returned is the #1145 fallback (the full configured budget)
1261
+ * rather than a live ERC20PeriodTransferEnforcer read — `sufficient` is a
1262
+ * real true/false, just computed from an optimistic number. Distinct from
1263
+ * {@link AgentPaymentWarningCode.AllowanceCheckUnavailable}, which fires
1264
+ * when the read failed outright and `sufficient` degrades to null. The
1265
+ * on-chain policy re-checks at redemption either way; this only says the
1266
+ * guidance shown here may be optimistic.
1267
+ */
1268
+ readonly AllowanceReadOptimistic: "ALLOWANCE_READ_OPTIMISTIC";
1269
+ /**
1270
+ * #2991: the quote tools' `expected_settlement_scheme` prediction of what
1271
+ * `haven_prepare_catalog_purchase` / `haven_pay_mcp_tool` will actually
1272
+ * select could not be computed — the agent's execution rail could not be
1273
+ * read from Haven, so `expected_settlement_scheme` is `null` rather than a
1274
+ * guess. `accepted_scheme` (the merchant's offer) is unaffected.
1275
+ */
1276
+ readonly X402SchemeUnknown: "X402_SCHEME_UNKNOWN";
1277
+ /**
1278
+ * #2968: the merchant answered 200 and handed over goods, but Haven holds NO
1279
+ * on-chain evidence that the payment moved. `settled: false` beside this code
1280
+ * is not a failure — it is the absence of proof, and the two must travel
1281
+ * together so an agent can tell "the user has the goods" apart from "the
1282
+ * money moved". Carries the intent's `expires_at`: after that instant the
1283
+ * settlement can no longer land at all.
1284
+ */
1285
+ readonly SettlementUnconfirmed: "SETTLEMENT_UNCONFIRMED";
1286
+ };
1287
+ type AgentPaymentWarningCode = (typeof AgentPaymentWarningCode)[keyof typeof AgentPaymentWarningCode];
1288
+ interface AgentPaymentWarning {
1289
+ code: AgentPaymentWarningCode;
1290
+ message: string;
1291
+ }
1292
+ /**
1293
+ * #1308: the structured next-step contract on x402 MCP tool responses. It
1294
+ * EXTENDS the existing taxonomy — `next_action` values come from
1295
+ * AgentPaymentNextAction, never a parallel vocabulary. `next_arguments`
1296
+ * carries the small, literally-usable arguments; bulky pass-through fields
1297
+ * (payment_required) are named in `reason` and taken from the SAME response.
1298
+ */
1299
+ interface AgentNextStep {
1300
+ /** From `AgentPaymentNextAction`. */
1301
+ next_action: AgentPaymentNextAction;
1302
+ /**
1303
+ * Claude-family namespaced tool name for the next call
1304
+ * (`mcp__<server>__<tool>`), when one exists.
1305
+ *
1306
+ * **Namespaced with the DEFAULT server names**, which is the most the hosted
1307
+ * server can know: local server names are the client's own config and never
1308
+ * reach Haven. Two runtimes are already not the default — Codex names servers
1309
+ * by config key (`haven`, `haven_signer`), and a connector run with
1310
+ * `--name <slug>` wires `haven-<slug>` / `haven-signer-<slug>` (#1694). On
1311
+ * either, this field and `next_tool_server` name a server the client does not
1312
+ * have. Prefer {@link AgentNextStep.next_tool_server_role} plus
1313
+ * {@link AgentNextStep.next_tool_name} whenever your servers are not the
1314
+ * default pair; see #2550.
1315
+ */
1316
+ next_tool?: string;
1317
+ /**
1318
+ * The server half of `next_tool`, unprefixed — `haven` or `haven-signer`.
1319
+ * Carries the same default-name caveat as `next_tool` (#1588, #2550).
1320
+ */
1321
+ next_tool_server?: string;
1322
+ /** The bare tool name, callable on whichever server plays the role below. */
1323
+ next_tool_name?: string;
1324
+ /**
1325
+ * Which of the CLIENT'S OWN servers to call (#2550). Runtime-neutral, and
1326
+ * the field to resolve against when your server names are not the defaults —
1327
+ * it names a role rather than a name the hosted server had to guess.
1328
+ */
1329
+ next_tool_server_role?: 'hosted' | 'signer';
1330
+ /** Small literal arguments for next_tool. Bulky fields are referenced by reason. */
1331
+ next_arguments?: Record<string, unknown>;
1332
+ /**
1333
+ * #3101 (epic #3105, decision 3): present exactly when `next_tool` is
1334
+ * absent — why no tool is named (the payment id is unknown, nothing is left
1335
+ * to do, the arguments could not be built). `next_tool` is never null.
1336
+ */
1337
+ next_tool_omitted_reason?: string;
1338
+ /** False when the agent should stop and involve the user before continuing. */
1339
+ safe_to_continue: boolean;
1340
+ reason: string;
1341
+ }
1342
+ /**
1343
+ * #1349: compact, Haven-generated reporting evidence for a completed x402
1344
+ * merchant purchase. `status`, money fields, merchant endpoint/address, and
1345
+ * funding transaction come from Haven payment state; `product` and
1346
+ * `invoice_id` are optional merchant-supplied display metadata. The raw
1347
+ * merchant result remains separate evidence and MUST NOT be used to infer
1348
+ * settlement status.
1349
+ */
1350
+ interface AgentPurchaseSummary {
1351
+ /** Set only after Haven has completed the funding and merchant-settlement flow. */
1352
+ status: 'settled';
1353
+ product: string | null;
1354
+ amount: string | null;
1355
+ amount_atomic: string | null;
1356
+ asset: string | null;
1357
+ network: string | null;
1358
+ merchant: {
1359
+ address: string | null;
1360
+ resource_url: string | null;
1361
+ };
1362
+ /** Merchant-supplied identifier, or null when the merchant did not supply one. */
1363
+ invoice_id: string | null;
1364
+ funding_tx_hash: string | null;
1365
+ /** Optional merchant receipt reference parsed from PAYMENT-RESPONSE; not Haven settlement proof. */
1366
+ settlement_tx_hash: string | null;
1367
+ /** Same read-only allowance block returned at the top level, or null when unavailable. */
1368
+ allowance: PostPurchaseAllowanceSummary | null;
1369
+ }
1370
+ /** #1308: compact reporting summary — what the agent tells the user. */
1371
+ interface AgentPaymentSummary {
1372
+ payment_id: string;
1373
+ status: string;
1374
+ amount?: string;
1375
+ amount_atomic?: string;
1376
+ token?: string;
1377
+ network?: string;
1378
+ expires_at?: string;
1379
+ product?: string;
1380
+ /**
1381
+ * Default reporting contract for a successful `haven_settle_mcp_tool` call.
1382
+ * The merchant's raw `result` remains available separately as advanced
1383
+ * evidence; do not parse it to determine whether a payment settled.
1384
+ */
1385
+ purchase_summary?: AgentPurchaseSummary;
1386
+ }
1387
+ declare const AgentPaymentRailDescriptions: Record<AgentPaymentRail, string>;
1388
+ declare const AgentPaymentPhaseSchema: AgentPaymentEnumSchema;
1389
+ declare const AgentPaymentNextActionSchema: AgentPaymentEnumSchema;
1390
+ declare const AgentPaymentFailureCodeSchema: AgentPaymentEnumSchema;
1391
+ declare const AgentPaymentRailSchema: AgentPaymentEnumSchema;
1392
+ interface PaymentStatusResult {
1393
+ paymentId: string;
1394
+ kind: PaymentStateKind;
1395
+ rail: string;
1396
+ status: PaymentStatus | string;
1397
+ phase: PaymentPhase;
1398
+ nextAction: PaymentNextAction;
1399
+ amount: string;
1400
+ token: string;
1401
+ resourceUrl: string | null;
1402
+ merchantAddress: string | null;
1403
+ /** Delegate EOA captured on the payment intent when it was created. */
1404
+ payerAddress?: string | null;
1405
+ /** #2960: additive alongside `payerAddress` above (`parties.delegate` only). */
1406
+ parties?: PaymentParties;
1407
+ txHash: string | null;
1408
+ expiresAt: string;
1409
+ chainId: number;
1410
+ message: string;
1411
+ /** Platform fee surfaced so it's never silently collected (#386). */
1412
+ fee?: PaymentFee | null;
1413
+ amountAtomic?: string | null;
1414
+ asset?: string | null;
1415
+ network?: string | null;
1416
+ description?: string | null;
1417
+ idempotencyKey?: string | null;
1418
+ x402?: {
1419
+ amountAtomic: string | null;
1420
+ asset: string | null;
1421
+ network: string | null;
1422
+ resourceUrl: string | null;
1423
+ merchantAddress: string | null;
1424
+ description: string | null;
1425
+ idempotencyKey: string | null;
1426
+ };
1427
+ mpp?: {
1428
+ amountAtomic: string | null;
1429
+ asset: string | null;
1430
+ network: string | null;
1431
+ resourceUrl: string | null;
1432
+ merchantAddress: string | null;
1433
+ description: string | null;
1434
+ idempotencyKey: string | null;
1435
+ challengeId: string | null;
1436
+ };
1437
+ }
1438
+ /**
1439
+ * Result of an erc7710 direct settlement (#1454).
1440
+ *
1441
+ * Deliberately NOT an `X402Receipt`. A 3009 receipt describes a completed
1442
+ * two-leg payment — funding tx included — whereas here nothing has settled yet
1443
+ * when this returns: the merchant redeems the delegation chain when the caller
1444
+ * retries with the header. Reusing the receipt type would let a caller read
1445
+ * `txHash` as "paid" on a payment that has not moved a cent.
1446
+ */
1447
+ interface X402Erc7710Settlement {
1448
+ paymentId: string;
1449
+ /**
1450
+ * Pass verbatim as the `PAYMENT-SIGNATURE` header on the merchant retry —
1451
+ * that name ALONE. erc7710 is always x402 v2, and this header carries the
1452
+ * delegation chain, so also sending the legacy `X-PAYMENT` overflows the
1453
+ * merchant's header limit (HTTP 431, #2341).
1454
+ */
1455
+ paymentHeader: string;
1456
+ /** The merchant address the child delegation is pinned to. */
1457
+ merchantPayTo: string;
1458
+ amountAtomic: string;
1459
+ asset: string;
1460
+ network: string;
1461
+ /** Facilitators the child is redeemable by, when the merchant advertised any. */
1462
+ facilitatorAddresses: string[] | null;
1463
+ }
1464
+ /** @internal */
1465
+ /** One payable service in Haven's merchant catalog (epic #1717). */
1466
+ interface HavenCatalogEntry {
1467
+ id: string;
1468
+ name: string;
1469
+ description: string;
1470
+ category: string;
1471
+ resourceUrl: string;
1472
+ rail: 'x402' | 'mpp';
1473
+ protocol: 'http' | 'mcp';
1474
+ toolName: string | null;
1475
+ toolArguments: Record<string, unknown> | null;
1476
+ priceDisplay: string | null;
1477
+ priceAtomic: string | null;
1478
+ asset: string | null;
1479
+ network: string | null;
1480
+ status: 'active' | 'degraded' | 'delisted';
1481
+ verifiedAt: string | null;
1482
+ /**
1483
+ * Where the entry came from. `operator` = curated in migrations/scripts
1484
+ * (the operator vouches for the listing; the catalog refresh probe still
1485
+ * checks the endpoint, see `verifiedPayable`). `ingestion` = submitted
1486
+ * through the Verified Payable Directory and passed domain-ownership proof
1487
+ * plus the read-only quote probe.
1488
+ */
1489
+ source: 'operator' | 'ingestion';
1490
+ /** True only for `ingestion` entries — the one ownership claim. See the epic's trust claim (never merchant honesty or quality). */
1491
+ domainVerified: boolean;
1492
+ /**
1493
+ * True when Haven watched this endpoint answer a live quote (#2978): the
1494
+ * directory probe for `ingestion` rows, the periodic catalog refresh probe
1495
+ * for `operator` rows (`status === 'active'` with `verifiedAt` set). False
1496
+ * for a degraded row of either source. `discoverTools({ verified:
1497
+ * 'verified' })` filters on this field, not on `source`.
1498
+ */
1499
+ verifiedPayable: boolean;
1500
+ /**
1501
+ * The merchant this entry belongs to (#3078). OPTIONAL on purpose: an
1502
+ * installed SDK may face a backend that predates the merchant layer, and
1503
+ * `discoverTools` must keep working against it — the field is absent, not
1504
+ * null, in that case.
1505
+ */
1506
+ merchant?: HavenCatalogMerchant;
1507
+ }
1508
+ /** A catalog entry's merchant as the wire carries it (#3078). */
1509
+ interface HavenCatalogMerchant {
1510
+ id: string;
1511
+ slug: string;
1512
+ name: string;
1513
+ /** `coming_soon` never reaches an entry in practice (a prospect has no offers). */
1514
+ listingStatus: 'live' | 'coming_soon';
1515
+ /** Haven-run test content: the demo store and the stranded-funds fixture. */
1516
+ isTestMerchant: boolean;
1517
+ }
1518
+ /**
1519
+ * #3128: one page of receipts. `total` is the count Haven holds for the
1520
+ * agent (an empty page with `total: 0` means no receipt exists — there is no
1521
+ * indexing delay behind this list); `hasMore` says the page was cut at the
1522
+ * limit; `nextCursor` is fed back as `cursor` for the next page. Against a
1523
+ * backend older than #3128 the three are `null` — "unknown", never a
1524
+ * fabricated 0 / false.
1525
+ */
1526
+ interface HavenPaymentReceiptsPage {
1527
+ receipts: HavenPaymentReceipt[];
1528
+ total: number | null;
1529
+ hasMore: boolean | null;
1530
+ nextCursor: string | null;
1531
+ }
1532
+ /** @internal */
1533
+ /** Wire shape of POST /catalog/submit (#1717, #1716). */
1534
+ interface CatalogSubmissionAccepted {
1535
+ id: string;
1536
+ verify_token: string;
1537
+ status: 'submitted' | 'ownership_verified' | 'verified_payable';
1538
+ }
1539
+ /** @internal Client-facing submission handle. */
1540
+ interface HavenCatalogSubmission {
1541
+ id: string;
1542
+ verifyToken: string;
1543
+ status: 'submitted' | 'ownership_verified' | 'verified_payable';
1544
+ }
1545
+ declare class HavenError extends Error {
1546
+ readonly code: string;
1547
+ readonly statusCode?: number | undefined;
1548
+ readonly paymentId?: string | undefined;
1549
+ constructor(message: string, code: string, statusCode?: number | undefined, paymentId?: string | undefined);
1550
+ }
1551
+ declare class HavenApiError extends HavenError {
1552
+ readonly body?: unknown | undefined;
1553
+ constructor(message: string, statusCode: number, body?: unknown | undefined, paymentId?: string);
1554
+ }
1555
+ /**
1556
+ * #1300: quoteX402 hit a URL that answered something other than 402 — the
1557
+ * typed form of "this is not the x402 endpoint". Exists so consumers (the
1558
+ * hosted MCP's #1271 discovery trigger) can key on a class instead of
1559
+ * message text.
1560
+ */
1561
+ /**
1562
+ * #1300: a merchant-facing fetch hit the client-side merchantTimeout. Typed
1563
+ * so consumers can distinguish "merchant never answered" from a real HTTP
1564
+ * error response — the funded-retry path routes this to verify-then-sweep
1565
+ * guidance instead of a bare 504.
1566
+ */
1567
+ declare class MerchantTimeoutError extends HavenApiError {
1568
+ readonly merchantErrorCode: "merchant_timeout";
1569
+ constructor(message: string);
1570
+ }
1571
+ declare class X402UnexpectedStatusError extends HavenApiError {
1572
+ readonly x402ErrorCode: "unexpected_non_402_status";
1573
+ /**
1574
+ * #2979: `body` is the merchant's own JSON, when the non-402 response
1575
+ * carried one — e.g. the demo merchant's `/mcp` readiness gate answers
1576
+ * `503 { error: 'merchant_not_ready', reason_code, ... }`. Optional and
1577
+ * best-effort: a non-JSON or unreadable body leaves this `undefined`, same
1578
+ * as before this field existed. Consumers key on it (not on the message
1579
+ * string) to distinguish an honest, machine-readable merchant refusal from
1580
+ * a genuine "this is not the x402 endpoint" miss, which otherwise look
1581
+ * identical — both are just "some non-402 status".
1582
+ */
1583
+ constructor(message: string, statusCode: number, body?: unknown);
1584
+ }
1585
+ /**
1586
+ * #1521: the idempotency key resolved to a payment that has already settled,
1587
+ * and the delegate can no longer fund a fresh authorization for it.
1588
+ *
1589
+ * This is the typed form of "you already bought this". It exists because the
1590
+ * alternative was indefensible: the SDK used to mint a new EIP-3009
1591
+ * authorization against the spent delegate and hand it back paired with the
1592
+ * ORIGINAL payment's `txHash`, so the caller learned what had happened only
1593
+ * from a merchant-side balance error that reads identically to a broken
1594
+ * payment rail.
1595
+ *
1596
+ * `receipt` is the ORIGINAL payment — a real receipt for real settled funds,
1597
+ * deliberately carrying no `paymentHeader`, because any header minted here
1598
+ * would be exactly the unfundable artifact this error replaces.
1599
+ */
1600
+ declare class X402AlreadySettledError extends HavenApiError {
1601
+ readonly receipt: X402Receipt;
1602
+ /**
1603
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1604
+ * authorization, so this payment demonstrably completed.
1605
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1606
+ * could not be established either way. Same refusal, weaker claim; say
1607
+ * which, rather than assert what was not checked.
1608
+ */
1609
+ readonly basis: 'settled' | 'unverifiable';
1610
+ readonly x402ErrorCode: "already_settled";
1611
+ constructor(message: string, receipt: X402Receipt,
1612
+ /**
1613
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1614
+ * authorization, so this payment demonstrably completed.
1615
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1616
+ * could not be established either way. Same refusal, weaker claim; say
1617
+ * which, rather than assert what was not checked.
1618
+ */
1619
+ basis: 'settled' | 'unverifiable');
1620
+ }
1621
+ declare class HavenPaymentStateError extends HavenApiError {
1622
+ readonly state: PaymentStatusResult;
1623
+ resumeState?: X402ResumeState;
1624
+ constructor(message: string, statusCode: number, state: PaymentStatusResult, body?: unknown);
1625
+ get status(): string;
1626
+ get phase(): PaymentPhase;
1627
+ get nextAction(): PaymentNextAction;
1628
+ }
1629
+ declare class HavenSigningError extends HavenError {
1630
+ constructor(message: string);
1631
+ }
1632
+ /**
1633
+ * #2972: `MerchantCompletion.reportSettlementEvidence` /
1634
+ * `HavenClient.reportSettlementEvidence` refuse a `0x00…00` settlement hash
1635
+ * BEFORE any network call — see `isZeroSettlementTxHash`. That marker is
1636
+ * never a real transaction (the demo merchant's own "delivered, not settled"
1637
+ * value), so posting it to `POST /machine-payments/evidence` could only ever
1638
+ * come back refused, at the cost of a real round trip. A typed error rather
1639
+ * than a `HavenApiError`-shaped 400: no request was ever attempted, so there
1640
+ * is no HTTP status or response body to carry.
1641
+ */
1642
+ declare class HavenZeroSettlementHashError extends HavenError {
1643
+ constructor(paymentId: string);
1644
+ }
1645
+ /**
1646
+ * Refusal codes the local signer returns when it does not recognise the
1647
+ * VERSION of a Haven-signed binding it was asked to sign (#1309). Distinct
1648
+ * from `AgentPaymentFailureCode`: these describe a **signer capability**
1649
+ * problem (this install cannot evaluate what Haven sent), not a payment-domain
1650
+ * outcome, and they never reach the backend's REST/OpenAPI surface — only the
1651
+ * local signer's own MCP tool responses (`haven_sign` / `haven_sign_x402` /
1652
+ * `haven_sign_sweep_delegate`). That is also why this pair does not go through
1653
+ * the `AgentPaymentFailureCode` four-gate (sdk → backend mirror → spec →
1654
+ * api-types): there is no backend mirror to keep in sync with.
1655
+ */
1656
+ declare const SignerRefusalCode: {
1657
+ /** `SUPPORTED_X402_EXPECTED_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1658
+ readonly UnsupportedExpectedContextVersion: "UNSUPPORTED_EXPECTED_CONTEXT_VERSION";
1659
+ /** `SUPPORTED_SWEEP_BINDING_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1660
+ readonly UnsupportedSweepBindingVersion: "UNSUPPORTED_SWEEP_BINDING_VERSION";
1661
+ };
1662
+ type SignerRefusalCode = (typeof SignerRefusalCode)[keyof typeof SignerRefusalCode];
1663
+ /**
1664
+ * Canonical recovery guidance for a stale local signer (#1309) — the ONE
1665
+ * string both the signer's structured refusal (`fallback` field, carried by
1666
+ * `HavenUnsupportedSignerVersionError`) and the hosted quote's advisory
1667
+ * `signer_compatibility.fallback` (#1155) render, so an agent that meets
1668
+ * either surface is told the identical fix. A second hand-maintained copy of
1669
+ * this sentence is exactly how the two surfaces could start disagreeing about
1670
+ * what to do.
1671
+ */
1672
+ declare function signerUpdateFallback(channel?: string): string;
1673
+ /**
1674
+ * The same sentence rendered for THIS build's channel (#2423). Every existing
1675
+ * consumer keeps importing this constant and keeps getting a string; the only
1676
+ * thing that moved is that `alpha` is no longer typed into it.
1677
+ *
1678
+ * The hosted MCP server is the one caller that does NOT use this constant: it
1679
+ * is deployed rather than published, so it renders `signerUpdateFallback()`
1680
+ * with the channel its own environment names.
1681
+ */
1682
+ declare const SIGNER_UPDATE_FALLBACK: string;
1683
+ /**
1684
+ * Thrown by the local signer when a Haven-signed binding (x402 expected
1685
+ * context or sweep authorization) carries a version outside what this signer
1686
+ * install enforces (#1143, structured as #1309). Machine-readable: `code`,
1687
+ * `supportedVersions`, and `receivedVersion` are DERIVED from the signer's own
1688
+ * `SUPPORTED_X402_EXPECTED_VERSIONS` / `SUPPORTED_SWEEP_BINDING_VERSIONS`
1689
+ * constants at the throw site, never a second literal — see
1690
+ * `assertSupportedBindingVersion` in `@haven_ai/signer`.
1691
+ *
1692
+ * This narrows HOW the refusal is reported. It does not weaken it: nothing is
1693
+ * signed either way, and the version stays inside the Haven-signed binding
1694
+ * message (callers must not "fix" a mismatch by rewriting it).
1695
+ */
1696
+ declare class HavenUnsupportedSignerVersionError extends HavenError {
1697
+ readonly supportedVersions: readonly number[];
1698
+ readonly receivedVersion: number;
1699
+ readonly fallback: string;
1700
+ constructor(message: string, code: SignerRefusalCode, supportedVersions: readonly number[], receivedVersion: number, fallback: string);
1701
+ }
1702
+ declare class HavenTimeoutError extends HavenError {
1703
+ constructor(paymentId: string);
1704
+ }
1705
+
1706
+ /**
1707
+ * Gasless delegate-sweep primitives — the single source of truth shared by the
1708
+ * edge signer (which signs) and the Haven backend (which relays).
1709
+ *
1710
+ * A stranded delegate EOA holds USDC but no ETH, so a raw ERC-20 transfer can't
1711
+ * pay for its own gas. Instead the delegate signs an *off-chain* EIP-3009
1712
+ * `TransferWithAuthorization` and the Haven relayer submits it on-chain and pays
1713
+ * gas. The relayer is only a gas payer: it holds no allowance and is never a
1714
+ * spender, so a relayer compromise cannot move user funds.
1715
+ *
1716
+ * Framework-neutral on purpose: `buildSweepTypedData` returns a plain
1717
+ * `{ domain, types, primaryType, message }` that both viem
1718
+ * (`signTypedData`/`recoverTypedDataAddress`) and ethers v6
1719
+ * (`signTypedData`/`verifyTypedData`) accept, so the signer (viem) and backend
1720
+ * (ethers) stay in lockstep without sharing a crypto library.
1721
+ */
1722
+ /** Base mainnet. The only chain Haven sweeps today. */
1723
+ declare const SWEEP_BASE_CHAIN_ID = 8453;
1724
+ /** Base Sepolia testnet — used by the dev environment / QA harness. */
1725
+ declare const SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
1726
+ /** Canonical Circle USDC on Base (FiatTokenV2_2). */
1727
+ declare const SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
1728
+ /** Circle's canonical Base Sepolia testnet USDC. */
1729
+ declare const SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
1730
+ /** True when the gasless sweep supports a chain (its USDC domain + address are known). */
1731
+ declare function isSweepableChain(chainId: number): boolean;
1732
+ /** EIP-712 `TransferWithAuthorization` struct, per EIP-3009. */
1733
+ declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
1734
+ readonly TransferWithAuthorization: readonly [{
1735
+ readonly name: "from";
1736
+ readonly type: "address";
1737
+ }, {
1738
+ readonly name: "to";
1739
+ readonly type: "address";
1740
+ }, {
1741
+ readonly name: "value";
1742
+ readonly type: "uint256";
1743
+ }, {
1744
+ readonly name: "validAfter";
1745
+ readonly type: "uint256";
1746
+ }, {
1747
+ readonly name: "validBefore";
1748
+ readonly type: "uint256";
1749
+ }, {
1750
+ readonly name: "nonce";
1751
+ readonly type: "bytes32";
1752
+ }];
1753
+ };
1754
+ interface SweepEip712Domain {
1755
+ name: string;
1756
+ version: string;
1757
+ chainId: number;
1758
+ verifyingContract: string;
1759
+ }
1760
+ /**
1761
+ * A fully-specified EIP-3009 authorization. All amounts/times are decimal
1762
+ * strings (JSON-safe) and `nonce` is a 0x-prefixed 32-byte hex value. `token`
1763
+ * and `chainId` are carried explicitly so the signer can assert they are
1764
+ * canonical before signing.
1765
+ */
1766
+ interface SweepAuthorization {
1767
+ /** Delegate EOA the funds are swept FROM. */
1768
+ from: string;
1769
+ /** The agent's Haven account the funds are swept TO. */
1770
+ to: string;
1771
+ /** Atomic USDC amount (decimal string). */
1772
+ value: string;
1773
+ /** Unix seconds the authorization becomes valid (decimal string, usually "0"). */
1774
+ validAfter: string;
1775
+ /** Unix seconds the authorization expires (decimal string). */
1776
+ validBefore: string;
1777
+ /** Random 0x-prefixed 32-byte hex nonce. */
1778
+ nonce: string;
1779
+ /** USDC contract address. */
1780
+ token: string;
1781
+ /** Chain id (8453 today). */
1782
+ chainId: number;
1783
+ }
1784
+ /**
1785
+ * Haven's signature over the sweep authorization context, signed with the same
1786
+ * binding key the x402 expected-context uses. Lets the edge signer verify the
1787
+ * authorization actually came from Haven (and wasn't crafted by a compromised
1788
+ * hosted server pointing `to` at an attacker) before it signs.
1789
+ */
1790
+ interface SweepExpectedAuth {
1791
+ /**
1792
+ * Currently always 1. Typed as `number` for the same reason as
1793
+ * `X402ExpectedAuth.version` (#1143): it is inbound, so a stale signer must be
1794
+ * able to *receive* an unknown version in order to report it. The signer's
1795
+ * `SUPPORTED_SWEEP_BINDING_VERSIONS` is the authority on what it will sign.
1796
+ */
1797
+ version: number;
1798
+ message: string;
1799
+ signature: string;
1800
+ signer: string;
1801
+ }
1802
+ /** What `POST /machine-payments/sweep/prepare` returns when funds are stranded. */
1803
+ interface SweepPreparation {
1804
+ authorization: SweepAuthorization;
1805
+ expectedAuth: SweepExpectedAuth;
1806
+ }
1807
+ /** Wire response from `POST /machine-payments/sweep/prepare` (snake_case). */
1808
+ interface SweepPrepareResponse {
1809
+ /** Present and true when the delegate holds nothing to recover. */
1810
+ nothing_stranded?: boolean;
1811
+ /**
1812
+ * Present and true when the stranded balance is below the sweep floor (#700):
1813
+ * it is left on the delegate as dust rather than recovered, because the gas to
1814
+ * sweep it would exceed its value. `min_usdc` carries the configured floor. No
1815
+ * `authorization` is built.
1816
+ */
1817
+ below_min?: boolean;
1818
+ min_usdc?: string;
1819
+ /** The authorization to sign — absent when nothing is stranded or below the floor. */
1820
+ authorization?: SweepAuthorization;
1821
+ /** Haven's binding over the authorization — absent when nothing is stranded. */
1822
+ expected_auth?: SweepExpectedAuth;
1823
+ asset?: string;
1824
+ amount?: string;
1825
+ amount_atomic?: string;
1826
+ chain_id: number;
1827
+ sign_instructions?: string;
1828
+ message?: string;
1829
+ }
1830
+ /** Wire response from `POST /machine-payments/sweep/submit` (snake_case). */
1831
+ interface SweepSubmitResponse {
1832
+ tx_hash: string;
1833
+ asset: string;
1834
+ amount: string;
1835
+ amount_atomic: string;
1836
+ from_address: string;
1837
+ to_address: string;
1838
+ chain_id: number;
1839
+ explorer_url: string;
1840
+ idempotent_replay?: boolean;
1841
+ }
1842
+ /** Result of a submitted gasless sweep. */
1843
+ interface SweepSubmitResult {
1844
+ txHash: string;
1845
+ amount: string;
1846
+ amountAtomic: string;
1847
+ asset: string;
1848
+ fromAddress: string;
1849
+ toAddress: string;
1850
+ chainId: number;
1851
+ explorerUrl: string;
1852
+ }
1853
+ interface SweepTypedData {
1854
+ domain: SweepEip712Domain;
1855
+ types: typeof TRANSFER_WITH_AUTHORIZATION_TYPES;
1856
+ primaryType: 'TransferWithAuthorization';
1857
+ message: {
1858
+ from: string;
1859
+ to: string;
1860
+ value: bigint;
1861
+ validAfter: bigint;
1862
+ validBefore: bigint;
1863
+ nonce: string;
1864
+ };
1865
+ }
1866
+ /** Resolve the canonical USDC contract for a sweepable chain, or throw. */
1867
+ declare function sweepUsdcAddress(chainId: number): string;
1868
+ /** Resolve the USDC EIP-712 domain for a sweepable chain, or throw. */
1869
+ declare function sweepUsdcDomain(chainId: number): SweepEip712Domain;
1870
+ /**
1871
+ * Build the EIP-712 typed data for an authorization, validating that the token
1872
+ * and chain are canonical (the domain's `verifyingContract` must match the
1873
+ * authorization's `token`). Returns bigint-valued fields so both viem and
1874
+ * ethers v6 sign/recover identically.
1875
+ */
1876
+ declare function buildSweepTypedData(auth: SweepAuthorization): SweepTypedData;
1877
+ /**
1878
+ * Canonical, deterministic string the backend signs and the signer re-derives
1879
+ * for the authorization binding. The `Haven sweep authorization v1` namespace
1880
+ * (and `kind`) is distinct from the x402 expected-context namespace so an x402
1881
+ * binding can never be replayed as a sweep authorization even though they share
1882
+ * a signing key.
1883
+ */
1884
+ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): string;
1885
+
1886
+ /**
1887
+ * Client identity on Haven API requests (#3303, epic #3302).
1888
+ *
1889
+ * Every published Haven client names itself with one header,
1890
+ * `X-Haven-Client: <package>/<version>`, so the backend can tell an outdated
1891
+ * client what to run — a `client_update` hint on its responses, or, only below
1892
+ * a minimum the deployment has explicitly set, a 426 `client_outdated` refusal
1893
+ * at the payment-initiating routes (the signer: at sign-context). The backend's
1894
+ * table and decision live in `@haven_ai/core`'s `client-compat.ts`; this module
1895
+ * is the client half and deliberately holds no thresholds.
1896
+ *
1897
+ * Deliberately free of any other SDK import so `@haven_ai/sdk/edge` (the
1898
+ * signer's ethers-free entry) can re-export it.
1899
+ */
1900
+ /**
1901
+ * This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
1902
+ * it with the package version on every release — never hand-edit it.
1903
+ */
1904
+ declare const SDK_VERSION = "0.6.0-alpha.0";
1905
+ /** The request header every published Haven client sends. */
1906
+ declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
1907
+ /** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
1908
+ declare function havenClientIdentity(pkg: string, version: string): string;
1909
+ /** What a bare SDK embedder sends when it names no package of its own. */
1910
+ declare const SDK_CLIENT_IDENTITY: string;
1911
+ /**
1912
+ * The `client_update` object the backend attaches to a response when this
1913
+ * client is behind (`required: false`) or below a set minimum
1914
+ * (`required: true`). Every field is the backend's; the SDK never computes one.
1915
+ */
1916
+ interface HavenClientUpdate {
1917
+ package: string;
1918
+ current: string;
1919
+ recommended: string | null;
1920
+ min_version: string | null;
1921
+ required: boolean;
1922
+ upgrade_command: string;
1923
+ notes_url: string | null;
1924
+ }
1925
+ /** Narrow an unknown response field to a {@link HavenClientUpdate}, or undefined. */
1926
+ declare function readClientUpdate(value: unknown): HavenClientUpdate | undefined;
1927
+
1928
+ /**
1929
+ * #3101 (epic #3105, slice 2/5): the typed next-step builder.
1930
+ *
1931
+ * Every hosted payment tool ends by naming the agent's next tool and its
1932
+ * arguments (#1308). Until this module, the tool was a free string and the
1933
+ * arguments a `Record<string, unknown>`, so nothing tied the keys to the tool
1934
+ * named beside them — three sites handed `{ payment_id: null }` to a tool
1935
+ * whose `payment_id` is a required string, and the compiler could not see it.
1936
+ *
1937
+ * The builder is generic over a TARGET MAP the caller supplies: bare tool
1938
+ * name → { role, validate }. It is deliberately schema-library-agnostic (the
1939
+ * SDK carries no zod): the hosted server derives each target's argument type
1940
+ * from its own zod shape and passes a `validate` closure; this module only
1941
+ * needs to know the role (to render `mcp__<server>__<tool>`) and how to say
1942
+ * whether arguments parse. Keyed on the bare name + role (decision 1) so the
1943
+ * namespaced string is rendered in exactly one place and the runtime-neutral
1944
+ * `next_tool_server` / `next_tool_name` / `next_tool_server_role` fields are
1945
+ * derived from the same input rather than parsed back out of a literal.
1946
+ *
1947
+ * Decisions 3 and 8: `nextTool` is REQUIRED on the input and may be `null` —
1948
+ * a site that forgets it is a compile error; a site with no next tool says
1949
+ * why, and the wire omits `next_tool` and carries `next_tool_omitted_reason`.
1950
+ * `next_tool` is never null on the wire.
1951
+ */
1952
+ type NextToolServerRole = 'hosted' | 'signer';
1953
+ /** The DEFAULT server name each role is wired under (#1588, #2550). */
1954
+ declare const NEXT_TOOL_SERVER_NAMES: Record<NextToolServerRole, string>;
1955
+ /** Default server name → role. An unknown server yields no role rather than a guess (#2550). */
1956
+ declare const NEXT_TOOL_SERVER_ROLES: Record<string, NextToolServerRole>;
1957
+ /** Renders the Claude-family namespaced tool name — the one string clients have followed since #1308. */
1958
+ declare function renderNextTool(role: NextToolServerRole, name: string): string;
1959
+ /** Parses a namespaced literal back into its parts; `role` is absent for an unknown server. */
1960
+ declare function parseNextTool(literal: string): {
1961
+ server: string;
1962
+ name: string;
1963
+ role?: NextToolServerRole;
1964
+ } | null;
1965
+ /**
1966
+ * One target the builder may hand off to. `TArgs` is the argument type the
1967
+ * caller derived from the tool's declared schema; `validate` is the runtime
1968
+ * twin of that type and returns `null` when the arguments parse, else why not.
1969
+ */
1970
+ interface NextStepTarget<TArgs> {
1971
+ role: NextToolServerRole;
1972
+ validate: (input: unknown) => string | null;
1973
+ /** Phantom carrier for the argument type; never read at runtime. */
1974
+ readonly _args?: TArgs;
1975
+ }
1976
+ type NextStepTargets = Record<string, NextStepTarget<unknown>>;
1977
+ /** The argument type a target carries. */
1978
+ type NextStepArguments<Targets extends NextStepTargets, T extends keyof Targets> = Targets[T] extends NextStepTarget<infer A> ? A : never;
1979
+ /**
1980
+ * The handoff half of a next step: a registered tool with arguments that
1981
+ * tool accepts, or no tool with the reason. A discriminated union over the
1982
+ * target map's keys, so a wrong key, a missing required key, an unregistered
1983
+ * tool name and an omitted `nextTool` are each a compile error at the site.
1984
+ */
1985
+ type NextStepHandoff<Targets extends NextStepTargets> = {
1986
+ [T in keyof Targets & string]: {
1987
+ nextTool: T;
1988
+ nextArguments: NextStepArguments<Targets, T>;
1989
+ };
1990
+ }[keyof Targets & string] | {
1991
+ nextTool: null;
1992
+ nextToolOmittedReason: string;
1993
+ };
1994
+ type NextStepInput<Targets extends NextStepTargets> = NextStepHandoff<Targets> & {
1995
+ nextAction: AgentPaymentNextAction;
1996
+ safeToContinue: boolean;
1997
+ reason: string;
1998
+ };
1999
+ /** The wire shape: `AgentNextStep` (its `next_tool` family) — never a null `next_tool`. */
2000
+ type NextStep = AgentNextStep;
2001
+ /**
2002
+ * Per-`next_action` default tool (decision 9): the tool a site names unless it
2003
+ * has a reason to override. Only actions with ONE sensible target are listed;
2004
+ * `retry_original_x402_request` is absent because its only live emitter names
2005
+ * no tool on purpose (the agent's own HTTP retry); `sign_and_submit_payment`
2006
+ * is absent because the signer tool
2007
+ * depends on the settlement scheme (`haven_sign` for erc7710 delegations,
2008
+ * `haven_sign_x402` for the EIP-3009 bridge) and a wrong default there would be
2009
+ * worse than none.
2010
+ */
2011
+ declare const DEFAULT_NEXT_TOOL_BY_ACTION: {
2012
+ readonly check_status_later: "haven_get_payment_status";
2013
+ readonly sweep_stranded_funds: "haven_sweep_delegate";
2014
+ };
2015
+ declare function defaultNextToolFor(action: AgentPaymentNextAction): string | undefined;
2016
+ /**
2017
+ * Builds a `nextStep` function bound to a target map. The returned function
2018
+ * renders the wire fields from the bare name + role, and re-validates the
2019
+ * arguments at runtime: on a mismatch it FAILS SAFE — omits the tool and says
2020
+ * why in `next_tool_omitted_reason` — rather than throwing out of a handler
2021
+ * that has already moved money. The compile-time twin makes that branch
2022
+ * unreachable from typed sites; it exists for callers that bypass the types.
2023
+ */
2024
+ declare function createNextStepBuilder<Targets extends NextStepTargets>(targets: Targets): (input: NextStepInput<Targets>) => NextStep;
2025
+
2026
+ /**
2027
+ * The npm dist-tag the published Haven packages tell a user to re-run (#2423,
2028
+ * slice 3 of epic #2420).
2029
+ *
2030
+ * ## Why a constant and not a literal
2031
+ *
2032
+ * Roughly a dozen user- and agent-facing strings across `@haven_ai/sdk`,
2033
+ * `@haven_ai/signer`, `@haven_ai/connect` and the hosted MCP server say some
2034
+ * form of "re-run `npx @haven_ai/connect@alpha`". Every one of them was a
2035
+ * hard-coded literal, which is correct only for a build published under the
2036
+ * `alpha` dist-tag. Once `dev`-branch snapshots publish under a `dev` tag
2037
+ * (#2421), a snapshot build telling its tester to re-run `@alpha` would hand
2038
+ * them the production connector — silently replacing the very build they are
2039
+ * testing. So the tag becomes one build-time constant and every hint derives
2040
+ * from it.
2041
+ *
2042
+ * ## Who writes it
2043
+ *
2044
+ * `scripts/release-bump.mjs` rewrites {@link HAVEN_CONNECTOR_CHANNEL} from the
2045
+ * version it is bumping to, using exactly the rule `.github/workflows/publish.yml`
2046
+ * uses to pick the `--tag` for that same version:
2047
+ *
2048
+ * | version | dist-tag / channel |
2049
+ * |---|---|
2050
+ * | `0.1.34-alpha.0` | `alpha` |
2051
+ * | `0.0.0-dev.202609021200.abc1234` | `dev` |
2052
+ * | `0.2.0` | `latest` |
2053
+ *
2054
+ * One rule, two consumers. `scripts/ci/connector-channel-agreement.test.mjs`
2055
+ * executes the workflow's own shell and the bump script's own function over the
2056
+ * same version table and fails if they ever disagree.
2057
+ *
2058
+ * ## Build-time here, run-time there
2059
+ *
2060
+ * A published tarball cannot read a deployment's environment, so for the
2061
+ * published packages the channel is baked in at release time. A surface that is
2062
+ * *deployed* rather than published has no release at which to bake anything in,
2063
+ * so it reads the `HAVEN_CONNECTOR_CHANNEL` environment variable and falls back
2064
+ * to this constant. Two surfaces do that: the hosted MCP server
2065
+ * (`packages/mcp-server/src/connector-channel.ts`) and, since slice 2 (#2422),
2066
+ * the backend's connector handout (`parseConnectorChannel` in
2067
+ * `packages/backend/src/config.ts`). All three readers share one variable name,
2068
+ * one default and one validation pattern, and that agreement is EXECUTED rather
2069
+ * than asserted: `packages/backend/src/__tests__/connector-channel.test.ts`
2070
+ * runs this module's `resolveConnectorChannel` and the backend's
2071
+ * `parseConnectorChannel` over the same input table and fails if they ever
2072
+ * diverge.
2073
+ *
2074
+ * **This says nothing about how any environment is configured.** Setting the
2075
+ * variable anywhere is an operator action (epic #2420, operator step 3); no
2076
+ * code here can observe it and none of this comment asserts it has happened.
2077
+ */
2078
+ /** The published connector package. Never varies; only its tag does. */
2079
+ declare const CONNECTOR_PACKAGE_NAME = "@haven_ai/connect";
2080
+ /**
2081
+ * The npm dist-tag this build's re-run hints name.
2082
+ *
2083
+ * **Do not hand-edit.** `scripts/release-bump.mjs` owns this literal the same
2084
+ * way it owns `CONNECTOR_VERSION` and its siblings, and
2085
+ * `scripts/release-bump.test.mjs` fails if the two drift.
2086
+ */
2087
+ declare const HAVEN_CONNECTOR_CHANNEL = "alpha";
2088
+ /** True when `value` is a well-formed dist-tag. */
2089
+ declare function isConnectorChannel(value: string): boolean;
2090
+ /**
2091
+ * Resolve a channel from a deployment's `HAVEN_CONNECTOR_CHANNEL`.
2092
+ *
2093
+ * - unset, empty or whitespace ⇒ `fallback` (dashboards store a cleared
2094
+ * variable as `""`, and that must land on the production-safe value);
2095
+ * - well-formed ⇒ itself;
2096
+ * - anything else ⇒ **throws**. It does not quietly fall back: a typo such as
2097
+ * `dve` would then land on the production channel, and the environment would
2098
+ * look fixed while reproducing the exact defect this slice removes.
2099
+ *
2100
+ * Well-formed-but-wrong (`dve` again) is *not* caught here and cannot be — it
2101
+ * fails later at `npx`, where the error names the package. Stated rather than
2102
+ * implied.
2103
+ */
2104
+ declare function resolveConnectorChannel(raw: string | undefined | null, fallback?: string): string;
2105
+ /** `@haven_ai/connect@<channel>` — the spec an `npx` invocation names. */
2106
+ declare function connectorSpec(channel?: string): string;
2107
+ /**
2108
+ * The re-run command every hint embeds.
2109
+ *
2110
+ * `connectorRerunCommand()` → `npx @haven_ai/connect@alpha`
2111
+ * `connectorRerunCommand('--doctor')` → `npx @haven_ai/connect@alpha --doctor`
2112
+ *
2113
+ * `args` is appended verbatim so each call site keeps its own flags and its own
2114
+ * surrounding sentence. The wording of those sentences is deliberately NOT
2115
+ * moved here: several are inside signer refusal messages that users and agents
2116
+ * pattern-match on, and this change is meant to move the channel token and
2117
+ * nothing else.
2118
+ */
2119
+ declare function connectorRerunCommand(args?: string, options?: {
2120
+ channel?: string;
2121
+ npxFlags?: string;
2122
+ }): string;
2123
+
2124
+ /**
2125
+ * The Node.js floor Haven's published packages support (#1161).
2126
+ *
2127
+ * ## Why this lives in the SDK
2128
+ *
2129
+ * Three packages need to enforce the same floor — `connect` (at setup),
2130
+ * `signer` and `mcp` (at startup) — and `@haven_ai/sdk` is the only dependency
2131
+ * all three already share. A copy per package is how the floor drifted in the
2132
+ * first place: `engines` said `>=24` everywhere while connect's runtime manifest
2133
+ * enforced `20.0.0`, so a connect run on Node v23 passed the guard, installed
2134
+ * the signer, and signed a real payment. Two numbers for one fact is one number
2135
+ * too many.
2136
+ *
2137
+ * Each consumer still owns its own refusal — the error type, the exit code, the
2138
+ * wording of "what to do next" — because a library must never terminate its
2139
+ * host process. This module only answers *is this version supported* and *what
2140
+ * should we tell the user*.
2141
+ *
2142
+ * ## Why a floor is enforced at all
2143
+ *
2144
+ * `engines` is advisory: npm emits `EBADENGINE` and installs anyway unless the
2145
+ * user happens to have `engine-strict` set. For a normal library that is a
2146
+ * reasonable default. For the **signer** it is not — it holds the delegate key
2147
+ * and produces every payment signature, so a subtle runtime incompatibility
2148
+ * shows up as a wrong or missing signature on a money path. "It seemed to work"
2149
+ * is precisely the evidence that cannot be relied on there.
2150
+ */
2151
+ /**
2152
+ * The minimum supported Node.js version, as `major.minor.patch`.
2153
+ *
2154
+ * MUST equal the `engines.node` floor declared by every published Haven
2155
+ * package. A guard test in each package asserts exactly that against its own
2156
+ * `package.json`, so the two cannot drift again silently.
2157
+ */
2158
+ declare const HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
2159
+ /**
2160
+ * Compare two Node versions. Negative when `left` is older.
2161
+ *
2162
+ * An unparseable version parses to `0.0.0` and therefore compares as older than
2163
+ * any real floor — fail-closed. A version string Haven cannot read is not
2164
+ * evidence of a supported runtime, and treating it as one would reopen exactly
2165
+ * the hole this module closes.
2166
+ */
2167
+ declare function compareNodeVersions(left: string, right: string): number;
2168
+ declare function isSupportedNodeVersion(nodeVersion?: string, minimumNodeVersion?: string): boolean;
2169
+ interface UnsupportedNodeVersionMessageOptions {
2170
+ /**
2171
+ * What is being refused, in the user's terms — "Haven setup", "The Haven
2172
+ * signer". Leads the message so the reader knows what just stopped.
2173
+ */
2174
+ subject: string;
2175
+ nodeVersion?: string;
2176
+ minimumNodeVersion?: string;
2177
+ /** Appended verbatim as the closing line. Used for the re-run instruction. */
2178
+ retryHint?: string;
2179
+ }
2180
+ /**
2181
+ * The refusal text.
2182
+ *
2183
+ * Names the detected version, the required version, and **how to fix it** — the
2184
+ * previous message stopped after the two version numbers, which tells a user
2185
+ * they are stuck without telling them how to get unstuck. The version-manager
2186
+ * lines are the fix for nearly everyone; the closing caveat is there because the
2187
+ * runtime that *spawns* the signer is frequently not the shell that was
2188
+ * upgraded, and a desktop app can keep launching the old Node long after
2189
+ * `node -v` in a terminal says otherwise.
2190
+ */
2191
+ declare function unsupportedNodeVersionMessage(options: UnsupportedNodeVersionMessageOptions): string;
2192
+
2193
+ /**
2194
+ * x402 protocol support for the Haven SDK.
2195
+ *
2196
+ * Provides:
2197
+ * - parsePaymentRequired() — extract payment requirements from a 402 response
2198
+ * - parsePaymentRequiredResponse() — async parser with JSON body fallback
2199
+ * - encodePaymentProof() — encode a receipt as a PAYMENT-SIGNATURE header
2200
+ *
2201
+ * The main authorizeX402() and fetchWithPayment() are methods on HavenClient
2202
+ * (see client.ts) since they need API access and signing.
2203
+ */
2204
+
2205
+ /**
2206
+ * Persisted, agent-scoped facts used to preflight a signed standard x402
2207
+ * payment header. This is an integrity comparison only: it never rebuilds,
2208
+ * modifies, persists, or submits the supplied authorization.
2209
+ */
2210
+ interface X402PaymentHeaderContext {
2211
+ merchantTo: string;
2212
+ amountAtomic: string;
2213
+ asset: string;
2214
+ network: string;
2215
+ resourceUrl: string;
2216
+ payer: string;
2217
+ chainId: number;
2218
+ }
2219
+ /** A deliberately value-free refusal for untrusted payment-header input. */
2220
+ declare class X402PaymentHeaderValidationError extends Error {
2221
+ constructor();
2222
+ }
2223
+ /**
2224
+ * Upper bound on the MERCHANT-requested part of the EIP-3009 authorization
2225
+ * window (#715, epic #713). The x402 library sets
2226
+ * `validBefore = now + maxTimeoutSeconds` straight from the MERCHANT's 402
2227
+ * challenge — without a cap, a malicious or sloppy merchant can request a
2228
+ * year-long window and a leaked signed authorization stays spendable that
2229
+ * whole time. 600 s is generous for any facilitator settle (typical is
2230
+ * 30–60 s). This cap applies only to the signed authorization, never to the
2231
+ * advertised requirements echoed in `accepted`. A merchant requiring more
2232
+ * than the bounded lifetime can still reject at verification; preserving its
2233
+ * offer does not widen Haven's signing policy.
2234
+ */
2235
+ declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
2236
+ /**
2237
+ * Forward margin ADDED on top of the (clamped) merchant timeout when the
2238
+ * authorization is actually signed (#1256). The x402 verify rule requires
2239
+ * `validBefore ≥ now + maxTimeoutSeconds` AT THE FACILITATOR — but the
2240
+ * upstream library computes `validBefore = now + maxTimeoutSeconds` at
2241
+ * SIGNING time, leaving zero forward margin. Haven's flow guarantees elapsed
2242
+ * time between the two (the funding UserOp confirms before the merchant
2243
+ * retry, ~1 min plus latency), so every purchase against a merchant whose
2244
+ * `maxTimeoutSeconds` exceeded that latency failed structurally — measured
2245
+ * live on Base mainnet: Anchor requires 300 s, and 226 s remained at verify.
2246
+ *
2247
+ * 300 s covers funding + retry latency with room to spare. The #715 exposure
2248
+ * ceiling becomes clamped-timeout + margin ≤ 900 s total forward — a
2249
+ * deliberate widening from 600 s, recorded on #1256: an authorization that
2250
+ * cannot pass verify protects no one, and 900 s is still bounded by the same
2251
+ * clamp discipline.
2252
+ */
2253
+ declare const X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
2254
+ declare function normalizePaymentRequired(value: unknown): X402PaymentRequired | null;
2255
+ /**
2256
+ * The x402 wire header names, in one place (#2289).
2257
+ *
2258
+ * v2 renamed all three; v1's only name was `X-PAYMENT`, used in BOTH
2259
+ * directions. Haven had adopted the v2 names for everything it *reads* and
2260
+ * kept the v1 name for the one thing it *writes*, which is how a strict v2
2261
+ * merchant came to never see a payment header at all.
2262
+ *
2263
+ * The 2026-08-31 owner decision was to send both outbound names on every
2264
+ * retry rather than switch on `x402Version`: a v1 merchant ignores the name it
2265
+ * does not know, a v2 merchant ignores the legacy one, and no version
2266
+ * heuristic has to be right for a payment to land.
2267
+ *
2268
+ * **That is no longer unconditional (#2341).** It held while the cost of a
2269
+ * spare header was zero, and on the EIP-3009 bridge it still is. On erc7710 it
2270
+ * is not: that header carries a whole delegation chain, and duplicating it
2271
+ * overflowed the merchant's header limit — HTTP 431, every erc7710 settlement
2272
+ * refused. `x402PaymentHeaderNamesFor` below is the live rule; read it rather
2273
+ * than this paragraph, which records why the simpler rule was right first.
2274
+ */
2275
+ /** v2 client→server payment payload. The name a strict v2 merchant reads. */
2276
+ declare const X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
2277
+ /** v1 client→server payment payload; still accepted by most v2 merchants. */
2278
+ declare const X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
2279
+ /** v2 server→client payment requirements. */
2280
+ declare const X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
2281
+ /** v2 server→client settlement receipt. */
2282
+ declare const X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
2283
+ /**
2284
+ * Both wire names, v2 first — the value an EIP-3009 retry actually sends.
2285
+ *
2286
+ * **Not the general answer any more (#2341), and not what a recorder should
2287
+ * reach for.** This was the evidence record's `paymentProofHeaderName` while
2288
+ * both names always went on the wire; erc7710 now sends one, so a recorder
2289
+ * still reading this constant would log a legacy header that was never sent —
2290
+ * exactly the drift the previous wording promised it prevented. Use
2291
+ * `x402PaymentHeaderNamesSent(paymentHeader)`. Kept exported because it is a
2292
+ * published surface and removing it would break consumers.
2293
+ */
2294
+ declare const X402_PAYMENT_HEADER_NAMES_SENT = "PAYMENT-SIGNATURE, X-PAYMENT";
2295
+ /**
2296
+ * The x402 v2 payment envelope: `{x402Version, resource?, accepted, payload,
2297
+ * extensions?}` per the spec's PaymentPayload (§5.2.2).
2298
+ *
2299
+ * The `resource` and `extensions` echoes are the #2361 fix, and they are not
2300
+ * optional politeness: the spec makes the extensions echo a MUST ("the client
2301
+ * must include at least the info received"), and CoinGecko's facilitator was
2302
+ * live-bisected rejecting the echo-less envelope with a bare 400 while
2303
+ * accepting the identical signature and `accepted`/`payload` bytes with the
2304
+ * echoes added (#2360, Base mainnet, 2026-09-01). Both objects are echoed
2305
+ * VERBATIM from the merchant's 402 — never reconstructed — and omitted when
2306
+ * the challenge carries none, which keeps the envelope byte-identical to the
2307
+ * pre-#2361 shape for echo-less merchants (Ampersend and Soundside settled
2308
+ * that shape live, so omission is the proven-compatible default).
2309
+ *
2310
+ * The `accepted` wrap itself is #303's shape and predates this helper — see
2311
+ * the #300/#303 history before "fixing" it: scheme/network live INSIDE
2312
+ * `accepted` in v2, never at the top level.
2313
+ */
2314
+ declare function x402V2PaymentEnvelope(paymentRequired: Pick<X402PaymentRequired, 'x402Version' | 'resource' | 'extensions'>, accepted: X402PaymentOption, payload: unknown): Record<string, unknown>;
2315
+ /**
2316
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
2317
+ *
2318
+ * Supports:
2319
+ * - v2: PAYMENT-REQUIRED header (base64 JSON)
2320
+ * - v1 fallback: X-PAYMENT header or response body
2321
+ */
2322
+ declare function parsePaymentRequired(response: Response): X402PaymentRequired;
2323
+ /**
2324
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
2325
+ *
2326
+ * Soundside and other Bazaar-style MCP endpoints return the PaymentRequired
2327
+ * object in the JSON body, while older Haven demos and many x402 examples use
2328
+ * base64 headers. This keeps the synchronous header parser intact and adds the
2329
+ * body fallback needed for those endpoints.
2330
+ */
2331
+ declare function parsePaymentRequiredResponse(response: Response): Promise<X402PaymentRequired>;
2332
+ /**
2333
+ * Select the best payment option from the x402 accepts array.
2334
+ *
2335
+ * Preference order:
2336
+ * 1. Option on a Haven-supported network with a known token
2337
+ * 2. Any option on a Haven-supported network
2338
+ * 3. null — no compatible option
2339
+ */
2340
+ declare function selectPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2341
+ /** The `extra.assetTransferMethod` value that marks an erc7710-settleable entry. */
2342
+ declare const ERC7710_ASSET_TRANSFER_METHOD = "erc7710";
2343
+ /**
2344
+ * Read `extra.assetTransferMethod` defensively. `extra` is the merchant's own
2345
+ * object, so it is untrusted shape: anything that is not the exact string is
2346
+ * treated as "not erc7710" rather than coerced.
2347
+ */
2348
+ declare function x402AssetTransferMethod(option: X402PaymentOption): string | null;
2349
+ /** True when the merchant advertises this entry as erc7710-settleable. */
2350
+ declare function isErc7710Option(option: X402PaymentOption): boolean;
2351
+ /**
2352
+ * The facilitator addresses a merchant advertises for an erc7710 entry, for
2353
+ * the #1058 redeemer pin — or `null` when it pins nothing.
2354
+ *
2355
+ * **An EMPTY array is `null`, not `[]`.** The backend rejects an empty
2356
+ * `redeemers` list with a 400 (`routes/x402.ts`), and the QA scenario already
2357
+ * treats empty as absent. Returning `[]` here would hand callers a value that
2358
+ * means "pin to nobody" — which is not a narrower pin, it is an unbuildable
2359
+ * delegation.
2360
+ *
2361
+ * Malformed entries are DROPPED rather than failing the whole option, and that
2362
+ * asymmetry is deliberate. A pin narrowed by a merchant's typo means the
2363
+ * facilitator that actually tries to redeem is not on the list, so redemption
2364
+ * reverts — and erc7710 has no funding leg, so nothing moved and nothing is
2365
+ * stranded. Refusing the option outright would instead deny a payment the
2366
+ * remaining valid facilitators could have settled. Losing the payment is the
2367
+ * worse outcome, precisely because the failure this issue closes (#1453) is the
2368
+ * one where funds move BEFORE the rejection.
2369
+ */
2370
+ declare function x402FacilitatorAddresses(option: X402PaymentOption): string[] | null;
2371
+ /**
2372
+ * Select an option that can be paid with the official x402 EIP-3009 exact
2373
+ * scheme. Haven's older tx-hash proof path can describe more networks; the
2374
+ * merchant-verified path currently needs Base USDC.
2375
+ *
2376
+ * **Skips erc7710-tagged entries (#1453).** It used to return the first
2377
+ * positional match and never look at `extra.assetTransferMethod`, so a merchant
2378
+ * that listed its erc7710 entry first made a Haven client echo that option
2379
+ * while signing a standard EIP-3009 authorization. The merchant rejects the
2380
+ * mismatch cleanly — but on the two-leg bridge the account→delegate funding
2381
+ * transfer has already executed, so the visible result is a stranded delegate
2382
+ * balance for the sweep to reclaim. Only our own demo merchant's ordering was
2383
+ * holding that shut, and that pin binds our merchant, not the ones we do not
2384
+ * control.
2385
+ */
2386
+ declare function selectStandardPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2387
+ /**
2388
+ * Select the erc7710-settleable option, if the merchant advertises one.
2389
+ */
2390
+ declare function selectErc7710PaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2391
+ /** What a settlement-scheme decision resolved to. */
2392
+ interface X402SchemeSelection {
2393
+ scheme: 'erc7710' | 'eip3009';
2394
+ option: X402PaymentOption;
2395
+ /** Redeemer pin for the settlement child; only ever set on erc7710. */
2396
+ facilitatorAddresses: string[] | null;
2397
+ }
2398
+ /**
2399
+ * THE preference rule, in one place (#1450 owner decision, #1453).
2400
+ *
2401
+ * Prefer erc7710 whenever the account is on the delegation rail and the
2402
+ * merchant advertises `extra.assetTransferMethod: "erc7710"`; fall back to
2403
+ * the EIP-3009 bridge otherwise.
2404
+ *
2405
+ * Both halves of that condition are required, and the rail half is the
2406
+ * caller's to supply — the SDK cannot see which rail an account is on from a
2407
+ * 402 response alone. A legacy AllowanceModule account passing
2408
+ * `delegationRail: true` would select a scheme its account cannot settle; the
2409
+ * backend refuses that at authorize with the #1986 retired-rail 410 (#2245 —
2410
+ * previously a scheme-specific 400 that wrongly implied the legacy rail could
2411
+ * still settle via EIP-3009), which is where a rail mismatch SHOULD fail,
2412
+ * on-chain-adjacent rather than in a client that could be lying to itself.
2413
+ *
2414
+ * Returns `null` when neither scheme has a payable entry — the caller decides
2415
+ * whether that is an error or a reason to look elsewhere.
2416
+ */
2417
+ declare function selectX402SettlementScheme(accepts: X402PaymentOption[], opts: {
2418
+ delegationRail: boolean;
2419
+ }): X402SchemeSelection | null;
2420
+ declare function x402AuthorizationAmount(option: X402PaymentOption): string;
2421
+ /**
2422
+ * Canonical Haven-authenticated x402 expected context, recomputed byte-for-byte
2423
+ * by the edge signer before it signs anything.
2424
+ *
2425
+ * **Two versions, and the version is derived — never passed in (#1138).**
2426
+ * `typedDataHash` present ⇒ v2, absent ⇒ v1. A v1 message is byte-identical to
2427
+ * what shipped before, so existing signers keep verifying legacy-rail bindings
2428
+ * unchanged.
2429
+ *
2430
+ * The version lives in both the header line and the payload so neither can be
2431
+ * reinterpreted as the other: a v2 context cannot be replayed as a v1 one that
2432
+ * drops the typed-data commitment, and a v1 context cannot be presented as v2.
2433
+ * That downgrade is exactly the attack the digest exists to stop — see
2434
+ * `assertExpectedBinding` in `@haven_ai/signer`, which refuses to raw-sign a
2435
+ * hash under a v2 binding and refuses to sign typed data without one.
2436
+ */
2437
+ declare function buildX402ExpectedMessage(context: X402ExpectedContext): string;
2438
+ declare function toStandardPaymentRequirements(paymentRequired: X402PaymentRequired, option: X402PaymentOption): PaymentRequirements;
2439
+ /**
2440
+ * Strictly validate an edge-signed EIP-3009 X-PAYMENT header against the
2441
+ * persisted x402 intent context before a hosted relay can submit funding.
2442
+ *
2443
+ * The merchant/facilitator remains the final protocol verifier. This closes a
2444
+ * separate hosted-relay integrity gap: malformed or context-mismatched input
2445
+ * must never cause Haven to relay the funding signature first.
2446
+ */
2447
+ declare function validateStandardX402PaymentHeader(paymentHeader: string, context: X402PaymentHeaderContext): Promise<void>;
2448
+ /**
2449
+ * Encode a payment receipt as a base64 PAYMENT-SIGNATURE header value.
2450
+ *
2451
+ * This follows the x402 v2 protocol — the server's facilitator will
2452
+ * verify the on-chain transaction referenced by tx_hash.
2453
+ */
2454
+ declare function encodePaymentProof(receipt: {
2455
+ txHash: string;
2456
+ paymentId: string;
2457
+ token: string;
2458
+ amount: string;
2459
+ to: string;
2460
+ resourceUrl?: string;
2461
+ accepted?: X402PaymentOption;
2462
+ payer?: string;
2463
+ chainId?: number;
2464
+ }): string;
2465
+ /**
2466
+ * Resolve a token symbol from a contract address.
2467
+ *
2468
+ * Checks all supported chains. For chain-specific resolution,
2469
+ * pass the optional `network` CAIP-2 string (e.g. "eip155:100").
2470
+ */
2471
+ declare function resolveTokenFromAddress(address: string, network?: string): {
2472
+ symbol: string;
2473
+ decimals: number;
2474
+ } | null;
2475
+
2476
+ /**
2477
+ * #3271: the integrity check every client runs before signing a direct
2478
+ * delegation-rail payment's typed data.
2479
+ *
2480
+ * A direct payment (`POST /payments`, surfaced as `haven_send` / `haven_pay`)
2481
+ * is signed as the HybridDeleGator's EIP-712 `PackedUserOperation`, and Haven
2482
+ * returns two things for it: that typed data, and `payload_hash` — the
2483
+ * ERC-4337 v0.7 UserOperation hash of the same operation. Nothing used to tie
2484
+ * the two together at signing time. The typed data is multi-KB and reaches the
2485
+ * signer through a language model when it is relayed by hand, so one corrupted
2486
+ * character produced a valid-looking signature over the wrong digest, and the
2487
+ * first sign of it was `AA24 signature error` from the bundler (#3271,
2488
+ * reproduced on dev 2026-09-24).
2489
+ *
2490
+ * This recomputes the v0.7 hash from the typed data's own message and domain
2491
+ * and refuses unless it equals `payload_hash`, and it pins the parts of the
2492
+ * typed data the hash does NOT cover (domain name/version/verifyingContract,
2493
+ * the field list, the EntryPoint). It is a CORRUPTION check: the caller supplies
2494
+ * both values, so it proves they describe the same operation, never that Haven
2495
+ * prepared it. Provenance is the byte-free sign context (`payment_id`); what a
2496
+ * delegate key will sign at all is `assertBoundDirectPaymentUserOp`
2497
+ * (`direct-payment-guard.ts`, #3272 / #3283), which every caller of this check
2498
+ * — `HavenClient.signForData` and the signer's `haven_sign` — runs next.
2499
+ *
2500
+ * Pure viem, no ethers: `@haven_ai/sdk/edge` re-exports it for the edge signer,
2501
+ * and `edge-imports.test.ts` pins that graph.
2502
+ */
2503
+ /** Version of the direct-payment sign context (`GET /payments/:id/sign-context`). */
2504
+ declare const DIRECT_SIGN_CONTEXT_VERSION = 1;
2505
+ /** The ERC-4337 v0.7 EntryPoint — the only one the delegation rail submits to. */
2506
+ declare const ENTRY_POINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
2507
+ /**
2508
+ * The HybridDeleGator EIP-712 domain constants and the `PackedUserOperation`
2509
+ * field list, vendored from `@metamask/smart-accounts-kit`
2510
+ * (`contracts.HybridDeleGator.constants`, `SIGNABLE_USER_OP_TYPED_DATA`) so the
2511
+ * published packages need no runtime dependency on the kit. Pinned equal to the
2512
+ * kit's values by `userop-binding.test.ts`.
2513
+ */
2514
+ declare const HYBRID_DELEGATOR_DOMAIN_NAME = "HybridDeleGator";
2515
+ declare const HYBRID_DELEGATOR_DOMAIN_VERSION = "1";
2516
+ declare const PACKED_USER_OPERATION_FIELDS: ReadonlyArray<{
2517
+ name: string;
2518
+ type: string;
2519
+ }>;
2520
+ /** Refusal raised when UserOperation typed data (a direct payment, or the SDK's x402 funding leg) does not match its `payload_hash`. */
2521
+ declare class HavenUserOpBindingError extends HavenError {
2522
+ constructor(message: string);
2523
+ }
2524
+ /** True when the typed data is a `PackedUserOperation` (the direct-payment shape). */
2525
+ declare function isPackedUserOperationTypedData(value: unknown): boolean;
2526
+ /**
2527
+ * Compute the ERC-4337 v0.7 UserOperation hash from a HybridDeleGator
2528
+ * `PackedUserOperation` typed-data object — the value Haven returns as
2529
+ * `payload_hash` for a direct payment (`getUserOperationHash`, entryPoint 0.7).
2530
+ */
2531
+ declare function packedUserOperationHash(typedData: unknown): Hex;
2532
+ /**
2533
+ * Refuse (throw `HavenUserOpBindingError`) unless this `PackedUserOperation`
2534
+ * typed data is the operation `payloadHash` names, in the HybridDeleGator
2535
+ * domain of its own sender, against the v0.7 EntryPoint. Returns the
2536
+ * recomputed hash.
2537
+ */
2538
+ declare function assertUserOpTypedDataBinding(typedData: unknown, payloadHash: string): Hex;
2539
+
2540
+ /**
2541
+ * The counterfactual HybridDeleGator account address for an owner EOA (#3272).
2542
+ *
2543
+ * `haven_sign`'s unbound branch (`@haven_ai/signer`'s `tools.ts`) and, since
2544
+ * #3283, `HavenClient.signForData` (`direct-payment-guard.ts`) sign a
2545
+ * `PackedUserOperation`
2546
+ * only when its `sender` (== `domain.verifyingContract`) is THIS SIGNER'S OWN
2547
+ * delegate account — never any other HybridDeleGator, and never a third
2548
+ * party's. Haven provisions that account counterfactually at signup (#970):
2549
+ * it may have zero on-chain transactions, so the signer must be able to
2550
+ * compute its address OFFLINE, from nothing but the delegate key's own
2551
+ * address.
2552
+ *
2553
+ * This is exactly what `@metamask/smart-accounts-kit`'s
2554
+ * `getCounterfactualAccountData` computes for
2555
+ * `implementation: 'Hybrid'`, `deployParams: [owner, [], [], []]` (no passkey
2556
+ * co-owners — the only shape Haven's signup flow provisions), `deploySalt:
2557
+ * '0x'`: CREATE2 of an `ERC1967Proxy(HybridDeleGatorImpl, initialize(owner,
2558
+ * [], [], []))` behind the `SimpleFactory`.
2559
+ *
2560
+ * VENDORED, NOT IMPORTED. `@metamask/smart-accounts-kit` is a devDependency
2561
+ * only (see `package.json`) — this package installs on users' machines and
2562
+ * must not carry it at runtime. The constants below (the factory and
2563
+ * implementation addresses, the `ERC1967Proxy` bytecode) are copied from the
2564
+ * kit's pinned environment / `@metamask/delegation-abis`' bytecode export,
2565
+ * exactly like `settlement-child.ts` vendors the DelegationManager and caveat
2566
+ * enforcer addresses for the same reason. Cross-checked against the kit by
2567
+ * `packages/signer/src/delegate-account.pins.test.ts`, including against the real, on-chain
2568
+ * `direct-payment-userop.json` fixture.
2569
+ */
2570
+
2571
+ /**
2572
+ * SimpleFactory — deterministically deployed, so Base and Base Sepolia share
2573
+ * the address (matches `packages/backend/src/rails/delegation-contracts.ts`'s
2574
+ * `simpleFactory` pin for both chains).
2575
+ */
2576
+ declare const SIMPLE_FACTORY_ADDRESS: Address;
2577
+ /**
2578
+ * HybridDeleGator implementation — matches `delegation-contracts.ts`'s
2579
+ * `hybridDeleGatorImpl` pin for both chains.
2580
+ */
2581
+ declare const HYBRID_DELEGATOR_IMPLEMENTATION: Address;
2582
+ /**
2583
+ * Derive the counterfactual HybridDeleGator account address for `owner`, with
2584
+ * no passkey co-owners — the only shape Haven's signup flow provisions
2585
+ * (#970). Pure and offline: no RPC call, no dependency on the account having
2586
+ * been deployed. Verified byte-for-byte against
2587
+ * `@metamask/smart-accounts-kit`'s `getCounterfactualAccountData` by
2588
+ * `packages/signer/src/delegate-account.pins.test.ts`, including against a real Base Sepolia payload served by the dev backend
2589
+ * (`direct-payment-userop.json`).
2590
+ */
2591
+ declare function deriveDelegateAccountAddress(owner: Address): Address;
2592
+
2593
+ /**
2594
+ * Independent verification of an erc7710 x402 settlement child (#1455).
2595
+ *
2596
+ * Moved from `@haven_ai/signer` into the SDK by #3283 (epic #3284) so the
2597
+ * signer and `HavenClient.signForData` run ONE verifier. The signer checks the
2598
+ * child against the Haven-signed expected context; the SDK checks it against
2599
+ * the merchant's own 402, which Haven does not produce.
2600
+ *
2601
+ * WHY THIS EXISTS. `assertExpectedBinding` proves Haven *declared* a payload:
2602
+ * the expected context is signed by `HAVEN_X402_BINDING_SIGNER` and commits to
2603
+ * the digest of the exact bytes being signed. That is a real property, and it
2604
+ * is not this one. It says nothing about what the payload MEANS.
2605
+ *
2606
+ * A backend that declared `merchantTo = the real merchant` while pinning a
2607
+ * different payee in the child's `AllowedCalldata` caveat would produce a
2608
+ * perfectly consistent pair: the declaration binds the digest, the digest is
2609
+ * the child's, and the child pays someone else. The signature is the authority
2610
+ * here — the merchant's facilitator redeems it and pulls from the treasury — so
2611
+ * the signer has to re-derive the meaning locally or it is a pass-through with
2612
+ * extra steps.
2613
+ *
2614
+ * ADDRESSES ARE PINNED HERE ON PURPOSE. Reading the enforcer map from Haven
2615
+ * would make the check circular: an attacker who can pick which contract counts
2616
+ * as "the payee enforcer" can satisfy any comparison. Taking
2617
+ * `@metamask/smart-accounts-kit` as a runtime dependency was the other option
2618
+ * and was rejected — this package installs on users' machines. The constants
2619
+ * below are snapshot-pinned and cross-checked against the kit by a test
2620
+ * (`packages/signer/src/settlement-child.pins.test.ts`), the same pattern
2621
+ * `packages/core/src/chains.ts` uses against its registry.
2622
+ *
2623
+ * EXTRA CAVEATS ARE ALLOWED, and that is deliberate — verified, not assumed
2624
+ * (#1455 review challenged it directly).
2625
+ *
2626
+ * `DelegationManager.redeemDelegations` loops every caveat of every delegation
2627
+ * and calls `beforeHook` on each, with no break and no try/catch: a single
2628
+ * revert aborts the whole redemption, and nothing lets one caveat cause another
2629
+ * to be skipped. Top-level caveats are therefore strictly AND-ed, so one this
2630
+ * file does not recognise can only add a constraint, never remove one.
2631
+ *
2632
+ * The specific challenge was `LogicalOrWrapperEnforcer`, whose terms encode
2633
+ * several caveat GROUPS and whose own security notice warns that "the redeemer
2634
+ * can select the least restrictive group, bypassing stricter requirements in
2635
+ * other groups". That warning is about groups INSIDE the wrapper — it binds
2636
+ * whoever authors wrapper terms. The wrapper is itself one caveat among the
2637
+ * delegation's, so it is AND-ed with the four required below and cannot unlock
2638
+ * them.
2639
+ *
2640
+ * The shape that WOULD be dangerous is the inverse: a required caveat hidden
2641
+ * inside a wrapper group instead of sitting at top level, where the redeemer
2642
+ * could select a group that omits it. This file scans top-level caveats and
2643
+ * refuses on absence, so that child is refused for lacking the caveat — which
2644
+ * is the correct outcome and is pinned by a test.
2645
+ */
2646
+ /** DelegationManager, the EIP-712 `verifyingContract` for a delegation. */
2647
+ declare const DELEGATION_MANAGER = "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3";
2648
+ /**
2649
+ * Caveat enforcers, by role. Deterministically deployed, so Base and Base
2650
+ * Sepolia share addresses — verified for both chains by the pin test.
2651
+ */
2652
+ declare const CAVEAT_ENFORCERS: {
2653
+ readonly erc20TransferAmount: "0xf100b0819427117EcF76Ed94B358B1A5b5C6D2Fc";
2654
+ readonly allowedCalldata: "0xc2b0d624c1c4319760C96503BA27C347F3260f55";
2655
+ readonly timestamp: "0x1046bb45C8d673d4ea75321280DB34899413c069";
2656
+ readonly redeemer: "0xE144b0b2618071B4E56f746313528a669c7E65c5";
2657
+ };
2658
+ /** The backend's own ceiling (`MAX_SETTLEMENT_WINDOW_SECONDS`), enforced again here. */
2659
+ declare const MAX_SETTLEMENT_WINDOW_SECONDS = 600;
2660
+ interface SettlementChildTypedData {
2661
+ domain: {
2662
+ name?: string;
2663
+ version?: string;
2664
+ chainId?: number | string;
2665
+ verifyingContract?: string;
2666
+ };
2667
+ types: Record<string, unknown>;
2668
+ primaryType: string;
2669
+ message: Record<string, unknown>;
2670
+ }
2671
+ /**
2672
+ * True when this typed data is a delegation — the shape that must never be
2673
+ * signed unbound. Excludes a SELF-delegation (`delegate === delegator`,
2674
+ * #3329): that is the shape of a task-budget child
2675
+ * (`task-budget-guards.ts`'s `isTaskChildTypedData`), a DIFFERENT typed-data
2676
+ * class verified by a different function against a different expectation. A
2677
+ * real settlement child's `delegate` is always a facilitator or
2678
+ * `ANY_BENEFICIARY` — never this account's own address — so narrowing here
2679
+ * costs this verifier nothing and keeps the two classes from ever
2680
+ * overlapping.
2681
+ */
2682
+ declare function isSettlementChildTypedData(value: unknown): value is SettlementChildTypedData;
2683
+ /**
2684
+ * Map an x402 network string to a chain id. Local on purpose (#1455 review):
2685
+ * the chain must come from Haven's SIGNED `network` field, never from the
2686
+ * payload under verification — see `verifySettlementChild`.
2687
+ */
2688
+ declare function chainIdForNetwork(network: string | undefined): number | undefined;
2689
+ interface SettlementChildExpectation {
2690
+ merchantTo: string;
2691
+ amount: string;
2692
+ asset: string;
2693
+ /**
2694
+ * Derived from the expected context's SIGNED `network`, never from
2695
+ * `typedData.domain.chainId`. Comparing the payload's own claim against
2696
+ * itself is a check that cannot fail — which is exactly what shipped in the
2697
+ * first draft of this file's call site, and what the review caught.
2698
+ */
2699
+ chainId: number;
2700
+ /** ISO timestamp; the child must not outlive it. */
2701
+ expiresAt?: string;
2702
+ /**
2703
+ * #3283 / #3281 criterion 8: the signer's OWN derived delegate account.
2704
+ * When set, the child's `delegator` must be exactly this account — the
2705
+ * child is a re-delegation of this agent's budget, never a grant from some
2706
+ * other account the key happens to control.
2707
+ */
2708
+ delegatorAccount?: string;
2709
+ /**
2710
+ * #3283: the facilitator addresses the merchant's 402 advertised
2711
+ * (`extra.facilitatorAddresses`). When non-empty, the child must carry a
2712
+ * `RedeemerEnforcer` caveat pinning exactly this set — otherwise the child
2713
+ * is a bearer instrument any party could redeem within its bounds.
2714
+ */
2715
+ redeemers?: readonly string[];
2716
+ }
2717
+ /** `@metamask/delegation-core`'s `ROOT_AUTHORITY` — a delegation chained to nothing. */
2718
+ declare const ROOT_AUTHORITY: string;
2719
+ /**
2720
+ * Verify a settlement child implements what the expected context declares.
2721
+ * Throws `HavenSigningError` on any disagreement; returns nothing on success.
2722
+ *
2723
+ * `now` is injectable so the expiry checks are testable without faking clocks.
2724
+ */
2725
+ declare function verifySettlementChild(typedData: SettlementChildTypedData, expected: SettlementChildExpectation, now?: number): void;
2726
+
2727
+ /** Wire code for a typed-data payload outside the signable allowlist. */
2728
+ declare const TYPED_DATA_NOT_ALLOWED: "TYPED_DATA_NOT_ALLOWED";
2729
+ /**
2730
+ * A typed-data payload was refused before signing because it is not a shape
2731
+ * a delegate key may sign. Nothing was signed. `@haven_ai/signer` subclasses
2732
+ * this to attach its MCP next step; the `code` is the same on both.
2733
+ */
2734
+ declare class HavenTypedDataRefusedError extends HavenSigningError {
2735
+ readonly code: typeof TYPED_DATA_NOT_ALLOWED;
2736
+ constructor(message: string);
2737
+ }
2738
+ /**
2739
+ * Chains the delegation rail has PINNED delegation contracts for
2740
+ * (`packages/backend/src/rails/delegation-contracts.ts`) — the only chains a
2741
+ * direct-payment UserOp may be scoped to. Gnosis (100) has no pinned
2742
+ * DelegationManager/enforcer set, so it is deliberately excluded even though
2743
+ * the delegate account itself could exist there.
2744
+ */
2745
+ declare const DIRECT_PAYMENT_CHAIN_IDS: ReadonlySet<number>;
2746
+ /** The DeleGator's single-execution `execute((address,uint256,bytes))` — selector `0x5c1c6dcd`. */
2747
+ declare const EXECUTE_ABI: readonly [{
2748
+ readonly type: "function";
2749
+ readonly name: "execute";
2750
+ readonly inputs: readonly [{
2751
+ readonly name: "_execution";
2752
+ readonly type: "tuple";
2753
+ readonly components: readonly [{
2754
+ readonly name: "target";
2755
+ readonly type: "address";
2756
+ }, {
2757
+ readonly name: "value";
2758
+ readonly type: "uint256";
2759
+ }, {
2760
+ readonly name: "callData";
2761
+ readonly type: "bytes";
2762
+ }];
2763
+ }];
2764
+ readonly outputs: readonly [];
2765
+ readonly stateMutability: "payable";
2766
+ }];
2767
+ /**
2768
+ * The content + provenance allowlist (#3272 criteria 1–2). Call ONLY after
2769
+ * `assertUserOpTypedDataBinding` has already proven `typedData` is a
2770
+ * well-formed `PackedUserOperation` matching its own hash — this function
2771
+ * trusts `typedData.domain`/`message` are shaped correctly and checks only
2772
+ * what they SAY. Throws `HavenTypedDataRefusedError` (never returns) on any
2773
+ * disagreement.
2774
+ */
2775
+ declare function assertBoundDirectPaymentUserOp(typedData: Record<string, unknown>, delegateAddress: string): void;
2776
+
2777
+ /**
2778
+ * The settlement-child half of the same surface (#3283): verify an erc7710
2779
+ * child against `expectation` (from somewhere Haven did not write — the
2780
+ * merchant's 402 in the SDK, the Haven-signed expected context in the
2781
+ * signer), AND that it is re-delegated from this key's OWN account. Throws
2782
+ * `HavenTypedDataRefusedError` (code `TYPED_DATA_NOT_ALLOWED`) on any
2783
+ * disagreement.
2784
+ */
2785
+ declare function assertOwnSettlementChild(typedData: unknown, expectation: SettlementChildExpectation, delegateAddress: string): void;
2786
+ /**
2787
+ * #3281 (epic #3284, criterion 5): pin WHERE an x402 EIP-3009 funding leg's
2788
+ * redemption sends the money. The funding leg is always
2789
+ * `transfer(<delegate EOA>, <amount>)` of the quoted token
2790
+ * (`delegation-authorize.ts` → `prepareDelegationPayment(agent, token,
2791
+ * payTo = the delegate EOA, amountRaw)`), so the single execution must be
2792
+ * exactly `encodePacked(asset, 0, transfer(delegateAddress, amount))`.
2793
+ *
2794
+ * `delegateAddress` is the signing key's OWN address — local, not from Haven —
2795
+ * so even a compromised Haven can at most move budget into the agent's own
2796
+ * EOA (the hot-delegate residual the sweep returns), never to an attacker.
2797
+ * `asset` and `amount` keep the leg consistent with what is being paid. Two
2798
+ * callers, two sources: the signer's x402 arm (#3281) passes the Haven-signed
2799
+ * expected context's; `HavenClient.signForData` (#3375) passes the 402 option
2800
+ * the SDK is paying, never the `/x402` response.
2801
+ *
2802
+ * Call ONLY after `assertBoundDirectPaymentUserOp` has passed on the same
2803
+ * typed data (it proves the `execute` → `redeemDelegations` shape this reads).
2804
+ * Throws `HavenTypedDataRefusedError` on any disagreement.
2805
+ */
2806
+ declare function assertFundingLegPaysDelegate(typedData: Record<string, unknown>, expected: {
2807
+ delegateAddress: string;
2808
+ asset: string;
2809
+ amount: string;
2810
+ }): void;
2811
+
2812
+ /**
2813
+ * Task budgets (#3329): independent verification of a task child delegation
2814
+ * and its close UserOp, mirroring `settlement-child.ts` / `direct-payment-
2815
+ * guard.ts` for a DIFFERENT typed-data class.
2816
+ *
2817
+ * A task budget's child is a SELF-delegation: the agent's own delegate
2818
+ * account grants itself a narrower, time-boxed slice of its budget
2819
+ * delegation (`delegate === delegator === the agent's own account`), chained
2820
+ * under the budget via `authority`. That is what separates it from an x402
2821
+ * settlement child, whose `delegate` is a facilitator/ANY_BENEFICIARY — never
2822
+ * the agent's own account. `isSettlementChildTypedData` (`settlement-
2823
+ * child.ts`) was narrowed to return `false` for a self-delegated payload so
2824
+ * the two classes cannot be confused by either verifier; this file is the
2825
+ * task-child counterpart, verified against a different expectation
2826
+ * (`GET /task-budgets/:id/sign-context`, never a merchant's 402).
2827
+ *
2828
+ * Two shapes, two functions:
2829
+ * - `assertOwnTaskChild` verifies the `Delegation` typed data signed to OPEN
2830
+ * a task budget.
2831
+ * - `assertOwnTaskBudgetCloseUserOp` verifies the `PackedUserOperation`
2832
+ * typed data signed to CLOSE one early (an on-chain
2833
+ * `disableDelegation(child)` call from the agent's own account) — an
2834
+ * authority-REDUCING action only, never a grant.
2835
+ *
2836
+ * `hashDelegation` below reproduces `@metamask/smart-accounts-kit/utils`'s
2837
+ * struct hash (via `@metamask/delegation-core`) byte-for-byte, WITHOUT taking
2838
+ * the kit as a runtime dependency (this package installs on users' machines —
2839
+ * same reasoning `delegate-account.ts` and `settlement-child.ts` give for
2840
+ * their own vendored constants). `DELEGATION_TYPEHASH` / `CAVEAT_TYPEHASH`
2841
+ * are pinned literals, cross-checked against the kit's own `hashDelegation`
2842
+ * by a test vector in `task-budget-guards.test.ts` (which imports the kit
2843
+ * ONLY in that test file).
2844
+ */
2845
+
2846
+ /** The backend's own ceiling (`MAX_TASK_BUDGET_TTL_SECONDS`), enforced again here. */
2847
+ declare const MAX_TASK_BUDGET_TTL_SECONDS = 86400;
2848
+ interface TaskChildTypedData {
2849
+ domain: {
2850
+ name?: string;
2851
+ version?: string;
2852
+ chainId?: number | string;
2853
+ verifyingContract?: string;
2854
+ };
2855
+ types: Record<string, unknown>;
2856
+ primaryType: string;
2857
+ message: Record<string, unknown>;
2858
+ }
2859
+ /**
2860
+ * True when this typed data is a task-budget child: a `Delegation` whose
2861
+ * `delegate` equals its own `delegator` (self-delegation). This is the ONLY
2862
+ * shape distinguishing it from an x402 settlement child (whose `delegate` is
2863
+ * a facilitator or `ANY_BENEFICIARY`) — `isSettlementChildTypedData` is
2864
+ * narrowed to return `false` for this same shape so the two verifiers never
2865
+ * overlap.
2866
+ */
2867
+ declare function isTaskChildTypedData(value: unknown): value is TaskChildTypedData;
2868
+ interface TaskChildExpectation {
2869
+ chainId: number;
2870
+ tokenAddress: string;
2871
+ maxAmountAtomic: string;
2872
+ recipientAddress: string | null;
2873
+ /** unix seconds — the `TimestampEnforcer`'s `beforeThreshold`. */
2874
+ expiresAt: number;
2875
+ parentDelegationHash: string;
2876
+ }
2877
+ /**
2878
+ * Verify a task-budget child delegation is EXACTLY what
2879
+ * `GET /task-budgets/:id/sign-context` (purpose `open`) declared, AND that
2880
+ * both `delegate` and `delegator` are this signer's OWN account. Throws
2881
+ * `HavenTypedDataRefusedError` (never returns) on any disagreement.
2882
+ */
2883
+ declare function assertOwnTaskChild(typedData: unknown, expected: TaskChildExpectation, delegateAddress: string, now?: number): void;
2884
+ interface TaskBudgetCloseExpectation {
2885
+ /** The child delegation's own struct hash (`agent_task_budgets.delegation_hash`). */
2886
+ delegationHash: string;
2887
+ }
2888
+ /**
2889
+ * Verify a task-budget close UserOp is EXACTLY an on-chain
2890
+ * `disableDelegation(child)` call from the agent's own delegate account —
2891
+ * authority-REDUCING only, never a grant. Throws `HavenTypedDataRefusedError`
2892
+ * (never returns) on any disagreement.
2893
+ */
2894
+ declare function assertOwnTaskBudgetCloseUserOp(typedData: Record<string, unknown>, expected: TaskBudgetCloseExpectation, delegateAddress: string): void;
2895
+ /**
2896
+ * `@metamask/delegation-core`'s `DELEGATION_TYPEHASH` — pinned, cross-checked
2897
+ * against the kit by a test vector in `task-budget-guards.test.ts`.
2898
+ */
2899
+ declare const DELEGATION_TYPEHASH: Hex;
2900
+ /** `@metamask/delegation-core`'s `CAVEAT_TYPEHASH` — pinned, same cross-check. */
2901
+ declare const CAVEAT_TYPEHASH: Hex;
2902
+ interface DelegationForHashing {
2903
+ delegate: Address;
2904
+ delegator: Address;
2905
+ authority: Hex;
2906
+ caveats: readonly {
2907
+ enforcer: Address;
2908
+ terms: Hex;
2909
+ }[];
2910
+ salt: bigint;
2911
+ }
2912
+ /**
2913
+ * Reproduces `@metamask/smart-accounts-kit/utils`'s `hashDelegation`
2914
+ * byte-for-byte, WITHOUT the kit at runtime (see the file header). Ignores
2915
+ * `signature` — the kit's own `hashDelegation` does the same (it hashes with
2916
+ * `signature: '0x'` regardless of what the caller passes).
2917
+ */
2918
+ declare function hashDelegation(delegation: DelegationForHashing): Hex;
2919
+
2920
+ /**
2921
+ * Runtime-agnostic base64 helpers — the single source of truth for the wire
2922
+ * encoding shared by the SDK and the edge signer (#325).
2923
+ *
2924
+ * Why this module exists: the SDK used `atob`/`btoa` (Web globals) while the
2925
+ * signer used `Buffer` (Node-only). Both worked because both currently run in
2926
+ * Node ≥ 16, but the duplication was a latent wire-incompatibility — and the
2927
+ * signer is headed for non-Node runtimes (browsers, Cloudflare Workers) where
2928
+ * `Buffer` does not exist (#314).
2929
+ *
2930
+ * Encoding contract:
2931
+ * - Output is ALWAYS standard base64 (`+`, `/`, padded). The x402 protocol's
2932
+ * reference implementation validates headers against
2933
+ * `/^[A-Za-z0-9+/]*={0,2}$/` — URL-safe output would be rejected.
2934
+ * - Decoding is tolerant: URL-safe input (`-`, `_`, unpadded) is normalized
2935
+ * before decoding, since third-party merchants are not guaranteed to be as
2936
+ * strict as the reference implementation.
2937
+ * - UTF-8 throughout. Naive `btoa(JSON.stringify(...))` throws on any
2938
+ * non-Latin-1 character (e.g. a merchant description with an emoji or
2939
+ * non-ASCII name); these helpers route through TextEncoder/TextDecoder on
2940
+ * the Web path so multibyte characters round-trip identically on both
2941
+ * runtimes.
2942
+ */
2943
+ /** Encode a UTF-8 string as standard base64. */
2944
+ declare function encodeBase64Utf8(value: string): string;
2945
+ /** Decode standard or URL-safe base64 to a UTF-8 string. */
2946
+ declare function decodeBase64Utf8(value: string): string;
2947
+ /** Encode a JSON-serializable value as a standard-base64 string. */
2948
+ declare function encodeBase64Json(value: unknown): string;
2949
+ /**
2950
+ * Decode a base64 JSON payload.
2951
+ *
2952
+ * Pass a `label` to get a wrapped error message instead of the raw
2953
+ * JSON/base64 error — call sites parsing untrusted merchant headers use this
2954
+ * to produce actionable failures.
2955
+ */
2956
+ declare function decodeBase64Json<T>(value: string, label?: string): T;
2957
+
2958
+ export { AgentPaymentPhase as $, type AgentPaymentWarning as A, type ResumeAuthorizedX402Input as B, type CloseTaskBudgetResult as C, type ResumeX402PaymentInput as D, type X402ResumeState as E, type X402McpTransport as F, type X402MerchantCallContext as G, type HavenClientConfig as H, HavenError as I, AGENT_PAYMENT_FAILURE_CODE_VALUES as J, AGENT_PAYMENT_NEXT_ACTION_VALUES as K, AGENT_PAYMENT_PHASE_VALUES as L, AGENT_PAYMENT_RAIL_VALUES as M, type AgentNextStep as N, type OpenTaskBudgetResult as O, type PaymentRequest as P, type AgentPaymentEnumSchema as Q, type RawPaymentParties as R, type SweepResult as S, type TaskBudgetSignContext as T, AgentPaymentFailureCode as U, AgentPaymentFailureCodeDescriptions as V, AgentPaymentFailureCodeSchema as W, type X402PaymentRequired as X, AgentPaymentNextAction as Y, AgentPaymentNextActionDescriptions as Z, AgentPaymentNextActionSchema as _, type HavenClientUpdate as a, type SweepExpectedAuth as a$, AgentPaymentPhaseDescriptions as a0, AgentPaymentPhaseSchema as a1, AgentPaymentRail as a2, AgentPaymentRailDescriptions as a3, AgentPaymentRailSchema as a4, type AgentPaymentSummary as a5, AgentPaymentWarningCode as a6, type AgentPurchaseSummary as a7, CONNECTOR_PACKAGE_NAME as a8, type CatalogSubmissionAccepted as a9, NEXT_TOOL_SERVER_NAMES as aA, NEXT_TOOL_SERVER_ROLES as aB, type NextStep as aC, type NextStepArguments as aD, type NextStepHandoff as aE, type NextStepInput as aF, type NextStepTarget as aG, type NextStepTargets as aH, type NextToolServerRole as aI, PACKED_USER_OPERATION_FIELDS as aJ, type PaymentFee as aK, type PaymentNextAction as aL, type PaymentPhase as aM, type PaymentStatus as aN, ROOT_AUTHORITY as aO, SDK_CLIENT_IDENTITY as aP, SDK_VERSION as aQ, SIGNER_UPDATE_FALLBACK as aR, SWEEP_BASE_CHAIN_ID as aS, SWEEP_BASE_SEPOLIA_CHAIN_ID as aT, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as aU, SWEEP_BASE_USDC_ADDRESS as aV, type SettlementChildExpectation as aW, SignerRefusalCode as aX, type SweepConfirmation as aY, type SweepEip712Domain as aZ, type SweepEntry as a_, DEFAULT_CONFIRMATION_TIMEOUT_MS as aa, DEFAULT_NEXT_TOOL_BY_ACTION as ab, DIRECT_SIGN_CONTEXT_VERSION as ac, ENTRY_POINT_V07 as ad, ERC7710_ASSET_TRANSFER_METHOD as ae, HAVEN_CLIENT_HEADER as af, HAVEN_CONNECTOR_CHANNEL as ag, HAVEN_MINIMUM_NODE_VERSION as ah, HYBRID_DELEGATOR_DOMAIN_NAME as ai, HYBRID_DELEGATOR_DOMAIN_VERSION as aj, type HavenAgentAllowanceSummary as ak, type HavenAgentReadiness as al, type HavenAllowance as am, HavenApiError as an, type HavenCatalogMerchant as ao, type HavenListScope as ap, HavenPaymentStateError as aq, HavenSigningError as ar, HavenTimeoutError as as, HavenTypedDataRefusedError as at, HavenUnsupportedSignerVersionError as au, HavenUserOpBindingError as av, HavenZeroSettlementHashError as aw, MAX_TASK_BUDGET_TTL_SECONDS as ax, type MachinePaymentRail as ay, MerchantTimeoutError as az, type PaymentResult as b, selectX402SettlementScheme as b$, type SweepPreparation as b0, type SweepSubmitResult as b1, type SweepTypedData as b2, TRANSFER_WITH_AUTHORIZATION_TYPES as b3, TYPED_DATA_NOT_ALLOWED as b4, type TaskBudgetCloseExpectation as b5, type TaskChildExpectation as b6, type TaskChildTypedData as b7, type UnsupportedNodeVersionMessageOptions as b8, X402AlreadySettledError as b9, decodeBase64Json as bA, decodeBase64Utf8 as bB, defaultNextToolFor as bC, deriveDelegateAccountAddress as bD, encodeBase64Json as bE, encodeBase64Utf8 as bF, encodePaymentProof as bG, hashDelegation as bH, havenClientIdentity as bI, isConnectorChannel as bJ, isErc7710Option as bK, isPackedUserOperationTypedData as bL, isSupportedNodeVersion as bM, isSweepableChain as bN, isTaskChildTypedData as bO, normalizePaymentRequired as bP, packedUserOperationHash as bQ, parseNextTool as bR, parsePaymentRequired as bS, parsePaymentRequiredResponse as bT, readClientUpdate as bU, renderNextTool as bV, resolveConnectorChannel as bW, resolveTokenFromAddress as bX, selectErc7710PaymentOption as bY, selectPaymentOption as bZ, selectStandardPaymentOption as b_, type X402ExpectedAuth as ba, type X402ExpectedContext as bb, type X402PaymentHeaderContext as bc, X402PaymentHeaderValidationError as bd, type X402PaymentOption as be, type X402RequestSnapshot as bf, type X402SchemeSelection as bg, X402UnexpectedStatusError as bh, X402_LEGACY_PAYMENT_HEADER_NAME as bi, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as bj, X402_PAYMENT_HEADER_NAME as bk, X402_PAYMENT_HEADER_NAMES_SENT as bl, X402_PAYMENT_REQUIRED_HEADER_NAME as bm, X402_PAYMENT_RESPONSE_HEADER_NAME as bn, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as bo, assertBoundDirectPaymentUserOp as bp, assertOwnTaskBudgetCloseUserOp as bq, assertOwnTaskChild as br, assertUserOpTypedDataBinding as bs, buildSweepAuthorizationMessage as bt, buildSweepTypedData as bu, buildX402ExpectedMessage as bv, compareNodeVersions as bw, connectorRerunCommand as bx, connectorSpec as by, createNextStepBuilder as bz, type PaymentIntent as c, signerUpdateFallback as c0, sweepUsdcAddress as c1, sweepUsdcDomain as c2, toStandardPaymentRequirements as c3, unsupportedNodeVersionMessage as c4, validateStandardX402PaymentHeader as c5, verifySettlementChild as c6, x402AssetTransferMethod as c7, x402AuthorizationAmount as c8, x402FacilitatorAddresses as c9, x402V2PaymentEnvelope as ca, CAVEAT_ENFORCERS as cb, CAVEAT_TYPEHASH as cc, DELEGATION_MANAGER as cd, DELEGATION_TYPEHASH as ce, DIRECT_PAYMENT_CHAIN_IDS as cf, type DelegationForHashing as cg, EXECUTE_ABI as ch, HYBRID_DELEGATOR_IMPLEMENTATION as ci, MAX_SETTLEMENT_WINDOW_SECONDS as cj, SIMPLE_FACTORY_ADDRESS as ck, type SettlementChildTypedData as cl, assertFundingLegPaysDelegate as cm, assertOwnSettlementChild as cn, chainIdForNetwork as co, isSettlementChildTypedData as cp, type X402AuthorizationOptions as d, type X402Intent as e, type PaymentStatusResult as f, type HavenAgent as g, type HavenAgentSummary as h, type SweepPrepareResponse as i, type SweepAuthorization as j, type SweepSubmitResponse as k, type HavenAllowanceSummary as l, type HavenBalanceCoverage as m, type PostPurchaseAllowanceSummary as n, type HavenCatalogEntry as o, type HavenCatalogSubmission as p, type HavenPaymentReceipt as q, type HavenPaymentReceiptsPage as r, type HavenTaskBudget as s, type SubmitTaskBudgetResult as t, type PaymentResumeState as u, type X402Receipt as v, type X402Quote as w, type X402Erc7710Settlement as x, type X402McpCallContext as y, type SignData as z };