@haven_ai/sdk 0.8.1-alpha.0 → 0.9.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.
Files changed (39) hide show
  1. package/dist/base64-BZDPJ8M1.d.ts +1344 -0
  2. package/dist/base64-Cyxhsvqd.d.cts +1344 -0
  3. package/dist/{chunk-WDA3IGJP.js → chunk-424S4QMG.js} +10 -5
  4. package/dist/chunk-424S4QMG.js.map +1 -0
  5. package/dist/{chunk-HX34HOW4.cjs → chunk-4Z6ATE44.cjs} +2 -2
  6. package/dist/chunk-4Z6ATE44.cjs.map +1 -0
  7. package/dist/chunk-7UTWSJC5.cjs +106 -0
  8. package/dist/chunk-7UTWSJC5.cjs.map +1 -0
  9. package/dist/{chunk-H4APV67M.js → chunk-J7N4LUZZ.js} +2 -2
  10. package/dist/chunk-J7N4LUZZ.js.map +1 -0
  11. package/dist/chunk-VRKWNJ7H.js +103 -0
  12. package/dist/chunk-VRKWNJ7H.js.map +1 -0
  13. package/dist/{chunk-HFOAYTD4.cjs → chunk-ZDKNPNI3.cjs} +41 -35
  14. package/dist/chunk-ZDKNPNI3.cjs.map +1 -0
  15. package/dist/edge.cjs +97 -89
  16. package/dist/edge.d.cts +4 -2
  17. package/dist/edge.d.ts +4 -2
  18. package/dist/edge.js +4 -4
  19. package/dist/index.cjs +1028 -487
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +96 -144
  22. package/dist/index.d.ts +96 -144
  23. package/dist/index.js +700 -186
  24. package/dist/index.js.map +1 -1
  25. package/dist/receipt-D4Roey3D.d.cts +130 -0
  26. package/dist/receipt-WkXHZGbu.d.ts +130 -0
  27. package/dist/test-support.cjs +71 -18
  28. package/dist/test-support.cjs.map +1 -1
  29. package/dist/test-support.d.cts +21 -1
  30. package/dist/test-support.d.ts +21 -1
  31. package/dist/test-support.js +53 -3
  32. package/dist/test-support.js.map +1 -1
  33. package/dist/{base64-BjxHPgtC.d.cts → types-CrszUJ7Z.d.cts} +208 -1306
  34. package/dist/{base64-BjxHPgtC.d.ts → types-CrszUJ7Z.d.ts} +208 -1306
  35. package/package.json +1 -1
  36. package/dist/chunk-H4APV67M.js.map +0 -1
  37. package/dist/chunk-HFOAYTD4.cjs.map +0 -1
  38. package/dist/chunk-HX34HOW4.cjs.map +0 -1
  39. package/dist/chunk-WDA3IGJP.js.map +0 -1
@@ -0,0 +1,1344 @@
1
+ import { Q as AgentNextStep, Z as AgentPaymentNextAction, aL as X402PaymentOption, aK as X402ExpectedContext, X as X402PaymentRequired, I as HavenError, am as HavenSigningError } from './types-CrszUJ7Z.cjs';
2
+ import { PaymentRequirements } from 'x402/types';
3
+ import { Hex, Address } from 'viem';
4
+
5
+ /**
6
+ * Gasless delegate-sweep primitives — the single source of truth shared by the
7
+ * edge signer (which signs) and the Haven backend (which relays).
8
+ *
9
+ * A stranded delegate EOA holds USDC but no ETH, so a raw ERC-20 transfer can't
10
+ * pay for its own gas. Instead the delegate signs an *off-chain* EIP-3009
11
+ * `TransferWithAuthorization` and the Haven relayer submits it on-chain and pays
12
+ * gas. The relayer is only a gas payer: it holds no allowance and is never a
13
+ * spender, so a relayer compromise cannot move user funds.
14
+ *
15
+ * Framework-neutral on purpose: `buildSweepTypedData` returns a plain
16
+ * `{ domain, types, primaryType, message }` that both viem
17
+ * (`signTypedData`/`recoverTypedDataAddress`) and ethers v6
18
+ * (`signTypedData`/`verifyTypedData`) accept, so the signer (viem) and backend
19
+ * (ethers) stay in lockstep without sharing a crypto library.
20
+ */
21
+ /** Base mainnet. The only chain Haven sweeps today. */
22
+ declare const SWEEP_BASE_CHAIN_ID = 8453;
23
+ /** Base Sepolia testnet — used by the dev environment / QA harness. */
24
+ declare const SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
25
+ /** Canonical Circle USDC on Base (FiatTokenV2_2). */
26
+ declare const SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
27
+ /** Circle's canonical Base Sepolia testnet USDC. */
28
+ declare const SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
29
+ /** True when the gasless sweep supports a chain (its USDC domain + address are known). */
30
+ declare function isSweepableChain(chainId: number): boolean;
31
+ /** EIP-712 `TransferWithAuthorization` struct, per EIP-3009. */
32
+ declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
33
+ readonly TransferWithAuthorization: readonly [{
34
+ readonly name: "from";
35
+ readonly type: "address";
36
+ }, {
37
+ readonly name: "to";
38
+ readonly type: "address";
39
+ }, {
40
+ readonly name: "value";
41
+ readonly type: "uint256";
42
+ }, {
43
+ readonly name: "validAfter";
44
+ readonly type: "uint256";
45
+ }, {
46
+ readonly name: "validBefore";
47
+ readonly type: "uint256";
48
+ }, {
49
+ readonly name: "nonce";
50
+ readonly type: "bytes32";
51
+ }];
52
+ };
53
+ interface SweepEip712Domain {
54
+ name: string;
55
+ version: string;
56
+ chainId: number;
57
+ verifyingContract: string;
58
+ }
59
+ /**
60
+ * A fully-specified EIP-3009 authorization. All amounts/times are decimal
61
+ * strings (JSON-safe) and `nonce` is a 0x-prefixed 32-byte hex value. `token`
62
+ * and `chainId` are carried explicitly so the signer can assert they are
63
+ * canonical before signing.
64
+ */
65
+ interface SweepAuthorization {
66
+ /** Delegate EOA the funds are swept FROM. */
67
+ from: string;
68
+ /** The agent's Haven account the funds are swept TO. */
69
+ to: string;
70
+ /** Atomic USDC amount (decimal string). */
71
+ value: string;
72
+ /** Unix seconds the authorization becomes valid (decimal string, usually "0"). */
73
+ validAfter: string;
74
+ /** Unix seconds the authorization expires (decimal string). */
75
+ validBefore: string;
76
+ /** Random 0x-prefixed 32-byte hex nonce. */
77
+ nonce: string;
78
+ /** USDC contract address. */
79
+ token: string;
80
+ /** Chain id (8453 today). */
81
+ chainId: number;
82
+ }
83
+ /**
84
+ * Haven's signature over the sweep authorization context, signed with the same
85
+ * binding key the x402 expected-context uses. Lets the edge signer verify the
86
+ * authorization actually came from Haven (and wasn't crafted by a compromised
87
+ * hosted server pointing `to` at an attacker) before it signs.
88
+ */
89
+ interface SweepExpectedAuth {
90
+ /**
91
+ * Currently always 1. Typed as `number` for the same reason as
92
+ * `X402ExpectedAuth.version` (#1143): it is inbound, so a stale signer must be
93
+ * able to *receive* an unknown version in order to report it. The signer's
94
+ * `SUPPORTED_SWEEP_BINDING_VERSIONS` is the authority on what it will sign.
95
+ */
96
+ version: number;
97
+ message: string;
98
+ signature: string;
99
+ signer: string;
100
+ }
101
+ /** What `POST /machine-payments/sweep/prepare` returns when funds are stranded. */
102
+ interface SweepPreparation {
103
+ authorization: SweepAuthorization;
104
+ expectedAuth: SweepExpectedAuth;
105
+ }
106
+ /** Wire response from `POST /machine-payments/sweep/prepare` (snake_case). */
107
+ interface SweepPrepareResponse {
108
+ /** Present and true when the delegate holds nothing to recover. */
109
+ nothing_stranded?: boolean;
110
+ /**
111
+ * Present and true when the stranded balance is below the sweep floor (#700):
112
+ * it is left on the delegate as dust rather than recovered, because the gas to
113
+ * sweep it would exceed its value. `min_usdc` carries the configured floor. No
114
+ * `authorization` is built.
115
+ */
116
+ below_min?: boolean;
117
+ min_usdc?: string;
118
+ /** The authorization to sign — absent when nothing is stranded or below the floor. */
119
+ authorization?: SweepAuthorization;
120
+ /** Haven's binding over the authorization — absent when nothing is stranded. */
121
+ expected_auth?: SweepExpectedAuth;
122
+ asset?: string;
123
+ amount?: string;
124
+ amount_atomic?: string;
125
+ chain_id: number;
126
+ sign_instructions?: string;
127
+ message?: string;
128
+ }
129
+ /** Wire response from `POST /machine-payments/sweep/submit` (snake_case). */
130
+ interface SweepSubmitResponse {
131
+ tx_hash: string;
132
+ asset: string;
133
+ amount: string;
134
+ amount_atomic: string;
135
+ from_address: string;
136
+ to_address: string;
137
+ chain_id: number;
138
+ explorer_url: string;
139
+ idempotent_replay?: boolean;
140
+ }
141
+ /** Result of a submitted gasless sweep. */
142
+ interface SweepSubmitResult {
143
+ txHash: string;
144
+ amount: string;
145
+ amountAtomic: string;
146
+ asset: string;
147
+ fromAddress: string;
148
+ toAddress: string;
149
+ chainId: number;
150
+ explorerUrl: string;
151
+ }
152
+ interface SweepTypedData {
153
+ domain: SweepEip712Domain;
154
+ types: typeof TRANSFER_WITH_AUTHORIZATION_TYPES;
155
+ primaryType: 'TransferWithAuthorization';
156
+ message: {
157
+ from: string;
158
+ to: string;
159
+ value: bigint;
160
+ validAfter: bigint;
161
+ validBefore: bigint;
162
+ nonce: string;
163
+ };
164
+ }
165
+ /** Resolve the canonical USDC contract for a sweepable chain, or throw. */
166
+ declare function sweepUsdcAddress(chainId: number): string;
167
+ /** Resolve the USDC EIP-712 domain for a sweepable chain, or throw. */
168
+ declare function sweepUsdcDomain(chainId: number): SweepEip712Domain;
169
+ /**
170
+ * Build the EIP-712 typed data for an authorization, validating that the token
171
+ * and chain are canonical (the domain's `verifyingContract` must match the
172
+ * authorization's `token`). Returns bigint-valued fields so both viem and
173
+ * ethers v6 sign/recover identically.
174
+ */
175
+ declare function buildSweepTypedData(auth: SweepAuthorization): SweepTypedData;
176
+ /**
177
+ * Canonical, deterministic string the backend signs and the signer re-derives
178
+ * for the authorization binding. The `Haven sweep authorization v1` namespace
179
+ * (and `kind`) is distinct from the x402 expected-context namespace so an x402
180
+ * binding can never be replayed as a sweep authorization even though they share
181
+ * a signing key.
182
+ */
183
+ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): string;
184
+
185
+ /**
186
+ * Client identity on Haven API requests (#3303, epic #3302).
187
+ *
188
+ * Every published Haven client names itself with one header,
189
+ * `X-Haven-Client: <package>/<version>`, so the backend can tell an outdated
190
+ * client what to run — a `client_update` hint on its responses, or, only below
191
+ * a minimum the deployment has explicitly set, a 426 `client_outdated` refusal
192
+ * at the payment-initiating routes (the signer: at sign-context). The backend's
193
+ * table and decision live in `@haven_ai/core`'s `client-compat.ts`; this module
194
+ * is the client half and deliberately holds no thresholds.
195
+ *
196
+ * Deliberately free of any other SDK import so `@haven_ai/sdk/edge` (the
197
+ * signer's ethers-free entry) can re-export it.
198
+ */
199
+ /**
200
+ * This SDK's own version. Owned by `scripts/release-bump.mjs`, which rewrites
201
+ * it with the package version on every release — never hand-edit it.
202
+ */
203
+ declare const SDK_VERSION = "0.9.0-alpha.0";
204
+ /** The request header every published Haven client sends. */
205
+ declare const HAVEN_CLIENT_HEADER = "X-Haven-Client";
206
+ /** `<package>/<version>` — the value of {@link HAVEN_CLIENT_HEADER}. */
207
+ declare function havenClientIdentity(pkg: string, version: string): string;
208
+ /** What a bare SDK embedder sends when it names no package of its own. */
209
+ declare const SDK_CLIENT_IDENTITY: string;
210
+ /**
211
+ * The `client_update` object the backend attaches to a response when this
212
+ * client is behind (`required: false`) or below a set minimum
213
+ * (`required: true`). Every field is the backend's; the SDK never computes one.
214
+ */
215
+ interface HavenClientUpdate {
216
+ package: string;
217
+ current: string;
218
+ recommended: string | null;
219
+ min_version: string | null;
220
+ required: boolean;
221
+ upgrade_command: string;
222
+ notes_url: string | null;
223
+ }
224
+ /** Narrow an unknown response field to a {@link HavenClientUpdate}, or undefined. */
225
+ declare function readClientUpdate(value: unknown): HavenClientUpdate | undefined;
226
+
227
+ /**
228
+ * #3101 (epic #3105, slice 2/5): the typed next-step builder.
229
+ *
230
+ * Every hosted payment tool ends by naming the agent's next tool and its
231
+ * arguments (#1308). Until this module, the tool was a free string and the
232
+ * arguments a `Record<string, unknown>`, so nothing tied the keys to the tool
233
+ * named beside them — three sites handed `{ payment_id: null }` to a tool
234
+ * whose `payment_id` is a required string, and the compiler could not see it.
235
+ *
236
+ * The builder is generic over a TARGET MAP the caller supplies: bare tool
237
+ * name → { role, validate }. It is deliberately schema-library-agnostic (the
238
+ * SDK carries no zod): the hosted server derives each target's argument type
239
+ * from its own zod shape and passes a `validate` closure; this module only
240
+ * needs to know the role (to render `mcp__<server>__<tool>`) and how to say
241
+ * whether arguments parse. Keyed on the bare name + role (decision 1) so the
242
+ * namespaced string is rendered in exactly one place and the runtime-neutral
243
+ * `next_tool_server` / `next_tool_name` / `next_tool_server_role` fields are
244
+ * derived from the same input rather than parsed back out of a literal.
245
+ *
246
+ * Decisions 3 and 8: `nextTool` is REQUIRED on the input and may be `null` —
247
+ * a site that forgets it is a compile error; a site with no next tool says
248
+ * why, and the wire omits `next_tool` and carries `next_tool_omitted_reason`.
249
+ * `next_tool` is never null on the wire.
250
+ */
251
+ type NextToolServerRole = 'hosted' | 'signer';
252
+ /** The DEFAULT server name each role is wired under (#1588, #2550). */
253
+ declare const NEXT_TOOL_SERVER_NAMES: Record<NextToolServerRole, string>;
254
+ /** Default server name → role. An unknown server yields no role rather than a guess (#2550). */
255
+ declare const NEXT_TOOL_SERVER_ROLES: Record<string, NextToolServerRole>;
256
+ /** Renders the Claude-family namespaced tool name — the one string clients have followed since #1308. */
257
+ declare function renderNextTool(role: NextToolServerRole, name: string): string;
258
+ /** Parses a namespaced literal back into its parts; `role` is absent for an unknown server. */
259
+ declare function parseNextTool(literal: string): {
260
+ server: string;
261
+ name: string;
262
+ role?: NextToolServerRole;
263
+ } | null;
264
+ /**
265
+ * One target the builder may hand off to. `TArgs` is the argument type the
266
+ * caller derived from the tool's declared schema; `validate` is the runtime
267
+ * twin of that type and returns `null` when the arguments parse, else why not.
268
+ */
269
+ interface NextStepTarget<TArgs> {
270
+ role: NextToolServerRole;
271
+ validate: (input: unknown) => string | null;
272
+ /** Phantom carrier for the argument type; never read at runtime. */
273
+ readonly _args?: TArgs;
274
+ }
275
+ type NextStepTargets = Record<string, NextStepTarget<unknown>>;
276
+ /** The argument type a target carries. */
277
+ type NextStepArguments<Targets extends NextStepTargets, T extends keyof Targets> = Targets[T] extends NextStepTarget<infer A> ? A : never;
278
+ /**
279
+ * The handoff half of a next step: a registered tool with arguments that
280
+ * tool accepts, or no tool with the reason. A discriminated union over the
281
+ * target map's keys, so a wrong key, a missing required key, an unregistered
282
+ * tool name and an omitted `nextTool` are each a compile error at the site.
283
+ */
284
+ type NextStepHandoff<Targets extends NextStepTargets> = {
285
+ [T in keyof Targets & string]: {
286
+ nextTool: T;
287
+ nextArguments: NextStepArguments<Targets, T>;
288
+ };
289
+ }[keyof Targets & string] | {
290
+ nextTool: null;
291
+ nextToolOmittedReason: string;
292
+ };
293
+ type NextStepInput<Targets extends NextStepTargets> = NextStepHandoff<Targets> & {
294
+ nextAction: AgentPaymentNextAction;
295
+ safeToContinue: boolean;
296
+ reason: string;
297
+ };
298
+ /** The wire shape: `AgentNextStep` (its `next_tool` family) — never a null `next_tool`. */
299
+ type NextStep = AgentNextStep;
300
+ /**
301
+ * Per-`next_action` default tool (decision 9): the tool a site names unless it
302
+ * has a reason to override. Only actions with ONE sensible target are listed;
303
+ * `retry_original_x402_request` is absent because its only live emitter names
304
+ * no tool on purpose (the agent's own HTTP retry); `sign_and_submit_payment`
305
+ * is absent because the signer tool
306
+ * depends on the settlement scheme (`haven_sign` for erc7710 delegations,
307
+ * `haven_sign_x402` for the EIP-3009 bridge) and a wrong default there would be
308
+ * worse than none.
309
+ */
310
+ declare const DEFAULT_NEXT_TOOL_BY_ACTION: {
311
+ readonly check_status_later: "haven_get_payment_status";
312
+ readonly sweep_stranded_funds: "haven_sweep_delegate";
313
+ };
314
+ declare function defaultNextToolFor(action: AgentPaymentNextAction): string | undefined;
315
+ /**
316
+ * Builds a `nextStep` function bound to a target map. The returned function
317
+ * renders the wire fields from the bare name + role, and re-validates the
318
+ * arguments at runtime: on a mismatch it FAILS SAFE — omits the tool and says
319
+ * why in `next_tool_omitted_reason` — rather than throwing out of a handler
320
+ * that has already moved money. The compile-time twin makes that branch
321
+ * unreachable from typed sites; it exists for callers that bypass the types.
322
+ */
323
+ declare function createNextStepBuilder<Targets extends NextStepTargets>(targets: Targets): (input: NextStepInput<Targets>) => NextStep;
324
+
325
+ /**
326
+ * The npm dist-tag the published Haven packages tell a user to re-run (#2423,
327
+ * slice 3 of epic #2420).
328
+ *
329
+ * ## Why a constant and not a literal
330
+ *
331
+ * Roughly a dozen user- and agent-facing strings across `@haven_ai/sdk`,
332
+ * `@haven_ai/signer`, `@haven_ai/connect` and the hosted MCP server say some
333
+ * form of "re-run `npx @haven_ai/connect@alpha`". Every one of them was a
334
+ * hard-coded literal, which is correct only for a build published under the
335
+ * `alpha` dist-tag. Once `dev`-branch snapshots publish under a `dev` tag
336
+ * (#2421), a snapshot build telling its tester to re-run `@alpha` would hand
337
+ * them the production connector — silently replacing the very build they are
338
+ * testing. So the tag becomes one build-time constant and every hint derives
339
+ * from it.
340
+ *
341
+ * ## Who writes it
342
+ *
343
+ * `scripts/release-bump.mjs` rewrites {@link HAVEN_CONNECTOR_CHANNEL} from the
344
+ * version it is bumping to, using exactly the rule `.github/workflows/publish.yml`
345
+ * uses to pick the `--tag` for that same version:
346
+ *
347
+ * | version | dist-tag / channel |
348
+ * |---|---|
349
+ * | `0.1.34-alpha.0` | `alpha` |
350
+ * | `0.0.0-dev.202609021200.abc1234` | `dev` |
351
+ * | `0.2.0` | `latest` |
352
+ *
353
+ * One rule, two consumers. `scripts/ci/connector-channel-agreement.test.mjs`
354
+ * executes the workflow's own shell and the bump script's own function over the
355
+ * same version table and fails if they ever disagree.
356
+ *
357
+ * ## Build-time here, run-time there
358
+ *
359
+ * A published tarball cannot read a deployment's environment, so for the
360
+ * published packages the channel is baked in at release time. A surface that is
361
+ * *deployed* rather than published has no release at which to bake anything in,
362
+ * so it reads the `HAVEN_CONNECTOR_CHANNEL` environment variable and falls back
363
+ * to this constant. Two surfaces do that: the hosted MCP server
364
+ * (`packages/mcp-server/src/connector-channel.ts`) and, since slice 2 (#2422),
365
+ * the backend's connector handout (`parseConnectorChannel` in
366
+ * `packages/backend/src/config.ts`). All three readers share one variable name,
367
+ * one default and one validation pattern, and that agreement is EXECUTED rather
368
+ * than asserted: `packages/backend/src/__tests__/connector-channel.test.ts`
369
+ * runs this module's `resolveConnectorChannel` and the backend's
370
+ * `parseConnectorChannel` over the same input table and fails if they ever
371
+ * diverge.
372
+ *
373
+ * **This says nothing about how any environment is configured.** Setting the
374
+ * variable anywhere is an operator action (epic #2420, operator step 3); no
375
+ * code here can observe it and none of this comment asserts it has happened.
376
+ */
377
+ /** The published connector package. Never varies; only its tag does. */
378
+ declare const CONNECTOR_PACKAGE_NAME = "@haven_ai/connect";
379
+ /**
380
+ * The npm dist-tag this build's re-run hints name.
381
+ *
382
+ * **Do not hand-edit.** `scripts/release-bump.mjs` owns this literal the same
383
+ * way it owns `CONNECTOR_VERSION` and its siblings, and
384
+ * `scripts/release-bump.test.mjs` fails if the two drift.
385
+ */
386
+ declare const HAVEN_CONNECTOR_CHANNEL = "alpha";
387
+ /** True when `value` is a well-formed dist-tag. */
388
+ declare function isConnectorChannel(value: string): boolean;
389
+ /**
390
+ * Resolve a channel from a deployment's `HAVEN_CONNECTOR_CHANNEL`.
391
+ *
392
+ * - unset, empty or whitespace ⇒ `fallback` (dashboards store a cleared
393
+ * variable as `""`, and that must land on the production-safe value);
394
+ * - well-formed ⇒ itself;
395
+ * - anything else ⇒ **throws**. It does not quietly fall back: a typo such as
396
+ * `dve` would then land on the production channel, and the environment would
397
+ * look fixed while reproducing the exact defect this slice removes.
398
+ *
399
+ * Well-formed-but-wrong (`dve` again) is *not* caught here and cannot be — it
400
+ * fails later at `npx`, where the error names the package. Stated rather than
401
+ * implied.
402
+ */
403
+ declare function resolveConnectorChannel(raw: string | undefined | null, fallback?: string): string;
404
+ /** `@haven_ai/connect@<channel>` — the spec an `npx` invocation names. */
405
+ declare function connectorSpec(channel?: string): string;
406
+ /**
407
+ * The re-run command every hint embeds.
408
+ *
409
+ * `connectorRerunCommand()` → `npx @haven_ai/connect@alpha`
410
+ * `connectorRerunCommand('--doctor')` → `npx @haven_ai/connect@alpha --doctor`
411
+ *
412
+ * `args` is appended verbatim so each call site keeps its own flags and its own
413
+ * surrounding sentence. The wording of those sentences is deliberately NOT
414
+ * moved here: several are inside signer refusal messages that users and agents
415
+ * pattern-match on, and this change is meant to move the channel token and
416
+ * nothing else.
417
+ */
418
+ declare function connectorRerunCommand(args?: string, options?: {
419
+ channel?: string;
420
+ npxFlags?: string;
421
+ }): string;
422
+ /**
423
+ * The command every UPGRADE hint names (#3412): `npx -y @haven_ai/connect@<channel> --doctor`.
424
+ *
425
+ * A bare connector re-run is a SETUP command — on a machine that is already
426
+ * set up it stops at "Missing --setup <hv_setup_...> setup token", so an
427
+ * outdated signer, local MCP or connector told to "re-run the connector" was
428
+ * handed a dead end. The flagless doctor works as pasted on an existing
429
+ * install (#3210: it resolves the runtime from the setup record), diagnoses an
430
+ * outdated signer, and prints the exact `--doctor --repair` line for the agent
431
+ * it describes — with `--credentials-dir` whenever more than one agent lives on
432
+ * the machine, so the repair cannot land on a different agent.
433
+ *
434
+ * `-y` because an upgrade hint is often run by an agent in a non-interactive
435
+ * shell. `@haven_ai/core`'s `upgradeCommandFor` (the backend's
436
+ * `client_update.upgrade_command`) cannot import this package, so it carries a
437
+ * copy; `packages/backend/src/__tests__/connector-upgrade-command-parity.test.ts`
438
+ * fails if the two ever disagree. Setup-time hints (identity restore,
439
+ * mid-setup retry) legitimately stay on {@link connectorRerunCommand}.
440
+ */
441
+ declare function connectorUpgradeCommand(options?: {
442
+ channel?: string;
443
+ }): string;
444
+
445
+ /**
446
+ * The Node.js floor Haven's published packages support (#1161).
447
+ *
448
+ * ## Why this lives in the SDK
449
+ *
450
+ * Three packages need to enforce the same floor — `connect` (at setup),
451
+ * `signer` and `mcp` (at startup) — and `@haven_ai/sdk` is the only dependency
452
+ * all three already share. A copy per package is how the floor drifted in the
453
+ * first place: `engines` said `>=24` everywhere while connect's runtime manifest
454
+ * enforced `20.0.0`, so a connect run on Node v23 passed the guard, installed
455
+ * the signer, and signed a real payment. Two numbers for one fact is one number
456
+ * too many.
457
+ *
458
+ * Each consumer still owns its own refusal — the error type, the exit code, the
459
+ * wording of "what to do next" — because a library must never terminate its
460
+ * host process. This module only answers *is this version supported* and *what
461
+ * should we tell the user*.
462
+ *
463
+ * ## Why a floor is enforced at all
464
+ *
465
+ * `engines` is advisory: npm emits `EBADENGINE` and installs anyway unless the
466
+ * user happens to have `engine-strict` set. For a normal library that is a
467
+ * reasonable default. For the **signer** it is not — it holds the delegate key
468
+ * and produces every payment signature, so a subtle runtime incompatibility
469
+ * shows up as a wrong or missing signature on a money path. "It seemed to work"
470
+ * is precisely the evidence that cannot be relied on there.
471
+ */
472
+ /**
473
+ * The minimum supported Node.js version, as `major.minor.patch`.
474
+ *
475
+ * MUST equal the `engines.node` floor declared by every published Haven
476
+ * package. A guard test in each package asserts exactly that against its own
477
+ * `package.json`, so the two cannot drift again silently.
478
+ */
479
+ declare const HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
480
+ /**
481
+ * Compare two Node versions. Negative when `left` is older.
482
+ *
483
+ * An unparseable version parses to `0.0.0` and therefore compares as older than
484
+ * any real floor — fail-closed. A version string Haven cannot read is not
485
+ * evidence of a supported runtime, and treating it as one would reopen exactly
486
+ * the hole this module closes.
487
+ */
488
+ declare function compareNodeVersions(left: string, right: string): number;
489
+ declare function isSupportedNodeVersion(nodeVersion?: string, minimumNodeVersion?: string): boolean;
490
+ interface UnsupportedNodeVersionMessageOptions {
491
+ /**
492
+ * What is being refused, in the user's terms — "Haven setup", "The Haven
493
+ * signer". Leads the message so the reader knows what just stopped.
494
+ */
495
+ subject: string;
496
+ nodeVersion?: string;
497
+ minimumNodeVersion?: string;
498
+ /** Appended verbatim as the closing line. Used for the re-run instruction. */
499
+ retryHint?: string;
500
+ }
501
+ /**
502
+ * The refusal text.
503
+ *
504
+ * Names the detected version, the required version, and **how to fix it** — the
505
+ * previous message stopped after the two version numbers, which tells a user
506
+ * they are stuck without telling them how to get unstuck. The version-manager
507
+ * lines are the fix for nearly everyone; the closing caveat is there because the
508
+ * runtime that *spawns* the signer is frequently not the shell that was
509
+ * upgraded, and a desktop app can keep launching the old Node long after
510
+ * `node -v` in a terminal says otherwise.
511
+ */
512
+ declare function unsupportedNodeVersionMessage(options: UnsupportedNodeVersionMessageOptions): string;
513
+
514
+ /**
515
+ * x402 protocol support for the Haven SDK.
516
+ *
517
+ * Provides:
518
+ * - parsePaymentRequired() — extract payment requirements from a 402 response
519
+ * - parsePaymentRequiredResponse() — async parser with JSON body fallback
520
+ * - encodePaymentProof() — encode a receipt as a PAYMENT-SIGNATURE header
521
+ *
522
+ * The main authorizeX402() and fetchWithPayment() are methods on HavenClient
523
+ * (see client.ts) since they need API access and signing.
524
+ */
525
+
526
+ /**
527
+ * Persisted, agent-scoped facts used to preflight a signed standard x402
528
+ * payment header. This is an integrity comparison only: it never rebuilds,
529
+ * modifies, persists, or submits the supplied authorization.
530
+ */
531
+ interface X402PaymentHeaderContext {
532
+ merchantTo: string;
533
+ amountAtomic: string;
534
+ asset: string;
535
+ network: string;
536
+ resourceUrl: string;
537
+ payer: string;
538
+ chainId: number;
539
+ }
540
+ /** A deliberately value-free refusal for untrusted payment-header input. */
541
+ declare class X402PaymentHeaderValidationError extends Error {
542
+ constructor();
543
+ }
544
+ /**
545
+ * Upper bound on the MERCHANT-requested part of the EIP-3009 authorization
546
+ * window (#715, epic #713). The x402 library sets
547
+ * `validBefore = now + maxTimeoutSeconds` straight from the MERCHANT's 402
548
+ * challenge — without a cap, a malicious or sloppy merchant can request a
549
+ * year-long window and a leaked signed authorization stays spendable that
550
+ * whole time. 600 s is generous for any facilitator settle (typical is
551
+ * 30–60 s). This cap applies only to the signed authorization, never to the
552
+ * advertised requirements echoed in `accepted`. A merchant requiring more
553
+ * than the bounded lifetime can still reject at verification; preserving its
554
+ * offer does not widen Haven's signing policy.
555
+ */
556
+ declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
557
+ /**
558
+ * Forward margin ADDED on top of the (clamped) merchant timeout when the
559
+ * authorization is actually signed (#1256). The x402 verify rule requires
560
+ * `validBefore ≥ now + maxTimeoutSeconds` AT THE FACILITATOR — but the
561
+ * upstream library computes `validBefore = now + maxTimeoutSeconds` at
562
+ * SIGNING time, leaving zero forward margin. Haven's flow guarantees elapsed
563
+ * time between the two (the funding UserOp confirms before the merchant
564
+ * retry, ~1 min plus latency), so every purchase against a merchant whose
565
+ * `maxTimeoutSeconds` exceeded that latency failed structurally — measured
566
+ * live on Base mainnet: Anchor requires 300 s, and 226 s remained at verify.
567
+ *
568
+ * 300 s covers funding + retry latency with room to spare. The #715 exposure
569
+ * ceiling becomes clamped-timeout + margin ≤ 900 s total forward — a
570
+ * deliberate widening from 600 s, recorded on #1256: an authorization that
571
+ * cannot pass verify protects no one, and 900 s is still bounded by the same
572
+ * clamp discipline.
573
+ */
574
+ declare const X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
575
+ declare function normalizePaymentRequired(value: unknown): X402PaymentRequired | null;
576
+ /**
577
+ * The x402 wire header names, in one place (#2289).
578
+ *
579
+ * v2 renamed all three; v1's only name was `X-PAYMENT`, used in BOTH
580
+ * directions. Haven had adopted the v2 names for everything it *reads* and
581
+ * kept the v1 name for the one thing it *writes*, which is how a strict v2
582
+ * merchant came to never see a payment header at all.
583
+ *
584
+ * The 2026-08-31 owner decision was to send both outbound names on every
585
+ * retry rather than switch on `x402Version`: a v1 merchant ignores the name it
586
+ * does not know, a v2 merchant ignores the legacy one, and no version
587
+ * heuristic has to be right for a payment to land.
588
+ *
589
+ * **That is no longer unconditional (#2341).** It held while the cost of a
590
+ * spare header was zero, and on the EIP-3009 bridge it still is. On erc7710 it
591
+ * is not: that header carries a whole delegation chain, and duplicating it
592
+ * overflowed the merchant's header limit — HTTP 431, every erc7710 settlement
593
+ * refused. `x402PaymentHeaderNamesFor` below is the live rule; read it rather
594
+ * than this paragraph, which records why the simpler rule was right first.
595
+ */
596
+ /** v2 client→server payment payload. The name a strict v2 merchant reads. */
597
+ declare const X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
598
+ /** v1 client→server payment payload; still accepted by most v2 merchants. */
599
+ declare const X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
600
+ /** v2 server→client payment requirements. */
601
+ declare const X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
602
+ /** v2 server→client settlement receipt. */
603
+ declare const X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
604
+ /**
605
+ * Both wire names, v2 first — the value an EIP-3009 retry actually sends.
606
+ *
607
+ * **Not the general answer any more (#2341), and not what a recorder should
608
+ * reach for.** This was the evidence record's `paymentProofHeaderName` while
609
+ * both names always went on the wire; erc7710 now sends one, so a recorder
610
+ * still reading this constant would log a legacy header that was never sent —
611
+ * exactly the drift the previous wording promised it prevented. Use
612
+ * `x402PaymentHeaderNamesSent(paymentHeader)`. Kept exported because it is a
613
+ * published surface and removing it would break consumers.
614
+ */
615
+ declare const X402_PAYMENT_HEADER_NAMES_SENT = "PAYMENT-SIGNATURE, X-PAYMENT";
616
+ /**
617
+ * Which payment header names to put on the wire for THIS payload (#2341).
618
+ *
619
+ * #2289 set both names unconditionally, and on the EIP-3009 bridge that is
620
+ * right: the header is a signature plus a six-field authorization, doubling it
621
+ * costs nothing, and lenient v1-only merchants are real. On **erc7710** it is
622
+ * not right, and it is not merely wasteful — the header carries the whole
623
+ * `[child, budget]` delegation chain plus the UserOperation, so sending it
624
+ * twice pushed the request past the server header-size limit and merchants
625
+ * answered **HTTP 431 Request Header Fields Too Large**. Every erc7710
626
+ * settlement failed, with the funding leg already spent on the hosted path.
627
+ *
628
+ * The rule is by SCHEME, not by byte count, because the scheme is what makes
629
+ * the alias pointless rather than merely large: an erc7710 payload is always
630
+ * `x402Version: 2` (the backend's `encodeXPaymentHeader` hardcodes it), and a
631
+ * merchant that can redeem a delegation chain is by construction running x402
632
+ * v2 plus the MetaMask erc7710 extension — it reads `PAYMENT-SIGNATURE`. The
633
+ * legacy name cannot help it and can only cost the request. A size threshold
634
+ * would be an arbitrary number that changes behaviour silently near its edge.
635
+ *
636
+ * An unreadable header falls back to BOTH names — the #2289 behaviour. Haven
637
+ * builds this value itself, so a parse failure means something is already
638
+ * wrong; the conservative answer there is the one that keeps v1 merchants
639
+ * working rather than the one that happens to fix a size problem we cannot
640
+ * confirm this payload has.
641
+ */
642
+ declare function x402PaymentHeaderNamesFor(paymentHeader: string): readonly string[];
643
+ /**
644
+ * The retry headers an agent sets on its own merchant retry, ready-made:
645
+ * `{ <name>: <paymentHeader> }` for every name `x402PaymentHeaderNamesFor`
646
+ * puts on the wire for this payload (#3727).
647
+ *
648
+ * Exists so no caller re-derives the names from prose: the rule is the SDK's
649
+ * live one (both `PAYMENT-SIGNATURE` and `X-PAYMENT` on eip3009,
650
+ * `PAYMENT-SIGNATURE` only on erc7710 — the #2341 rule), and a change to it
651
+ * flows here through the same function the request path uses. Every value is
652
+ * the header verbatim; only the NAMES vary.
653
+ */
654
+ declare function x402RetryHeadersFor(paymentHeader: string): Record<string, string>;
655
+ /**
656
+ * The x402 v2 payment envelope: `{x402Version, resource?, accepted, payload,
657
+ * extensions?}` per the spec's PaymentPayload (§5.2.2).
658
+ *
659
+ * The `resource` and `extensions` echoes are the #2361 fix, and they are not
660
+ * optional politeness: the spec makes the extensions echo a MUST ("the client
661
+ * must include at least the info received"), and CoinGecko's facilitator was
662
+ * live-bisected rejecting the echo-less envelope with a bare 400 while
663
+ * accepting the identical signature and `accepted`/`payload` bytes with the
664
+ * echoes added (#2360, Base mainnet, 2026-09-01). Both objects are echoed
665
+ * VERBATIM from the merchant's 402 — never reconstructed — and omitted when
666
+ * the challenge carries none, which keeps the envelope byte-identical to the
667
+ * pre-#2361 shape for echo-less merchants (Ampersend and Soundside settled
668
+ * that shape live, so omission is the proven-compatible default).
669
+ *
670
+ * The `accepted` wrap itself is #303's shape and predates this helper — see
671
+ * the #300/#303 history before "fixing" it: scheme/network live INSIDE
672
+ * `accepted` in v2, never at the top level.
673
+ */
674
+ declare function x402V2PaymentEnvelope(paymentRequired: Pick<X402PaymentRequired, 'x402Version' | 'resource' | 'extensions'>, accepted: X402PaymentOption, payload: unknown): Record<string, unknown>;
675
+ /**
676
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
677
+ *
678
+ * Supports:
679
+ * - v2: PAYMENT-REQUIRED header (base64 JSON)
680
+ * - v1 fallback: X-PAYMENT header or response body
681
+ */
682
+ declare function parsePaymentRequired(response: Response): X402PaymentRequired;
683
+ /**
684
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
685
+ *
686
+ * Soundside and other Bazaar-style MCP endpoints return the PaymentRequired
687
+ * object in the JSON body, while older Haven demos and many x402 examples use
688
+ * base64 headers. This keeps the synchronous header parser intact and adds the
689
+ * body fallback needed for those endpoints.
690
+ */
691
+ declare function parsePaymentRequiredResponse(response: Response): Promise<X402PaymentRequired>;
692
+ /**
693
+ * Select the best payment option from the x402 accepts array.
694
+ *
695
+ * Preference order:
696
+ * 1. Option on a Haven-supported network with a known token
697
+ * 2. Any option on a Haven-supported network
698
+ * 3. null — no compatible option
699
+ */
700
+ declare function selectPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
701
+ /** The `extra.assetTransferMethod` value that marks an erc7710-settleable entry. */
702
+ declare const ERC7710_ASSET_TRANSFER_METHOD = "erc7710";
703
+ /**
704
+ * Read `extra.assetTransferMethod` defensively. `extra` is the merchant's own
705
+ * object, so it is untrusted shape: anything that is not the exact string is
706
+ * treated as "not erc7710" rather than coerced.
707
+ */
708
+ declare function x402AssetTransferMethod(option: X402PaymentOption): string | null;
709
+ /** True when the merchant advertises this entry as erc7710-settleable. */
710
+ declare function isErc7710Option(option: X402PaymentOption): boolean;
711
+ /**
712
+ * The facilitator addresses a merchant advertises for an erc7710 entry, for
713
+ * the #1058 redeemer pin — or `null` when it pins nothing.
714
+ *
715
+ * **An EMPTY array is `null`, not `[]`.** The backend rejects an empty
716
+ * `redeemers` list with a 400 (`routes/x402.ts`), and the QA scenario already
717
+ * treats empty as absent. Returning `[]` here would hand callers a value that
718
+ * means "pin to nobody" — which is not a narrower pin, it is an unbuildable
719
+ * delegation.
720
+ *
721
+ * Malformed entries are DROPPED rather than failing the whole option, and that
722
+ * asymmetry is deliberate. A pin narrowed by a merchant's typo means the
723
+ * facilitator that actually tries to redeem is not on the list, so redemption
724
+ * reverts — and erc7710 has no funding leg, so nothing moved and nothing is
725
+ * stranded. Refusing the option outright would instead deny a payment the
726
+ * remaining valid facilitators could have settled. Losing the payment is the
727
+ * worse outcome, precisely because the failure this issue closes (#1453) is the
728
+ * one where funds move BEFORE the rejection.
729
+ */
730
+ declare function x402FacilitatorAddresses(option: X402PaymentOption): string[] | null;
731
+ /**
732
+ * Select an option that can be paid with the official x402 EIP-3009 exact
733
+ * scheme. Haven's older tx-hash proof path can describe more networks; the
734
+ * merchant-verified path currently needs Base USDC.
735
+ *
736
+ * **Skips erc7710-tagged entries (#1453).** It used to return the first
737
+ * positional match and never look at `extra.assetTransferMethod`, so a merchant
738
+ * that listed its erc7710 entry first made a Haven client echo that option
739
+ * while signing a standard EIP-3009 authorization. The merchant rejects the
740
+ * mismatch cleanly — but on the two-leg bridge the account→delegate funding
741
+ * transfer has already executed, so the visible result is a stranded delegate
742
+ * balance for the sweep to reclaim. Only our own demo merchant's ordering was
743
+ * holding that shut, and that pin binds our merchant, not the ones we do not
744
+ * control.
745
+ */
746
+ declare function selectStandardPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
747
+ /**
748
+ * Select the erc7710-settleable option, if the merchant advertises one.
749
+ */
750
+ declare function selectErc7710PaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
751
+ /** What a settlement-scheme decision resolved to. */
752
+ interface X402SchemeSelection {
753
+ scheme: 'erc7710' | 'eip3009';
754
+ option: X402PaymentOption;
755
+ /** Redeemer pin for the settlement child; only ever set on erc7710. */
756
+ facilitatorAddresses: string[] | null;
757
+ }
758
+ /**
759
+ * THE preference rule, in one place (#1450 owner decision, #1453).
760
+ *
761
+ * Prefer erc7710 whenever the account is on the delegation rail and the
762
+ * merchant advertises `extra.assetTransferMethod: "erc7710"`; fall back to
763
+ * the EIP-3009 bridge otherwise.
764
+ *
765
+ * Both halves of that condition are required, and the rail half is the
766
+ * caller's to supply — the SDK cannot see which rail an account is on from a
767
+ * 402 response alone. A legacy AllowanceModule account passing
768
+ * `delegationRail: true` would select a scheme its account cannot settle; the
769
+ * backend refuses that at authorize with the #1986 retired-rail 410 (#2245 —
770
+ * previously a scheme-specific 400 that wrongly implied the legacy rail could
771
+ * still settle via EIP-3009), which is where a rail mismatch SHOULD fail,
772
+ * on-chain-adjacent rather than in a client that could be lying to itself.
773
+ *
774
+ * Returns `null` when neither scheme has a payable entry — the caller decides
775
+ * whether that is an error or a reason to look elsewhere.
776
+ */
777
+ declare function selectX402SettlementScheme(accepts: X402PaymentOption[], opts: {
778
+ delegationRail: boolean;
779
+ }): X402SchemeSelection | null;
780
+ declare function x402AuthorizationAmount(option: X402PaymentOption): string;
781
+ /**
782
+ * Canonical Haven-authenticated x402 expected context, recomputed byte-for-byte
783
+ * by the edge signer before it signs anything.
784
+ *
785
+ * **Two versions, and the version is derived — never passed in (#1138).**
786
+ * `typedDataHash` present ⇒ v2, absent ⇒ v1. A v1 message is byte-identical to
787
+ * what shipped before, so existing signers keep verifying legacy-rail bindings
788
+ * unchanged.
789
+ *
790
+ * The version lives in both the header line and the payload so neither can be
791
+ * reinterpreted as the other: a v2 context cannot be replayed as a v1 one that
792
+ * drops the typed-data commitment, and a v1 context cannot be presented as v2.
793
+ * That downgrade is exactly the attack the digest exists to stop — see
794
+ * `assertExpectedBinding` in `@haven_ai/signer`, which refuses to raw-sign a
795
+ * hash under a v2 binding and refuses to sign typed data without one.
796
+ */
797
+ declare function buildX402ExpectedMessage(context: X402ExpectedContext): string;
798
+ declare function toStandardPaymentRequirements(paymentRequired: X402PaymentRequired, option: X402PaymentOption): PaymentRequirements;
799
+ /**
800
+ * Strictly validate an edge-signed EIP-3009 X-PAYMENT header against the
801
+ * persisted x402 intent context before a hosted relay can submit funding.
802
+ *
803
+ * The merchant/facilitator remains the final protocol verifier. This closes a
804
+ * separate hosted-relay integrity gap: malformed or context-mismatched input
805
+ * must never cause Haven to relay the funding signature first.
806
+ */
807
+ declare function validateStandardX402PaymentHeader(paymentHeader: string, context: X402PaymentHeaderContext): Promise<void>;
808
+ /**
809
+ * Encode a payment receipt as a base64 PAYMENT-SIGNATURE header value.
810
+ *
811
+ * This follows the x402 v2 protocol — the server's facilitator will
812
+ * verify the on-chain transaction referenced by tx_hash.
813
+ */
814
+ declare function encodePaymentProof(receipt: {
815
+ txHash: string;
816
+ paymentId: string;
817
+ token: string;
818
+ amount: string;
819
+ to: string;
820
+ resourceUrl?: string;
821
+ accepted?: X402PaymentOption;
822
+ payer?: string;
823
+ chainId?: number;
824
+ }): string;
825
+ /**
826
+ * Resolve a token symbol from a contract address.
827
+ *
828
+ * Checks all supported chains. For chain-specific resolution,
829
+ * pass the optional `network` CAIP-2 string (e.g. "eip155:8453").
830
+ */
831
+ declare function resolveTokenFromAddress(address: string, network?: string): {
832
+ symbol: string;
833
+ decimals: number;
834
+ } | null;
835
+ /**
836
+ * #3410: token decimals from a SYMBOL + CHAIN — the same registry
837
+ * `resolveTokenFromAddress` reads, keyed the other way. The address-based
838
+ * resolver needs the token's contract address, which the consent seed path
839
+ * (setup-time credential files) does not carry; the symbol and chain it does
840
+ * carry. Null when the symbol is not registered on that chain (unknown or
841
+ * custom tokens) — callers must fall back to an explicit atomic label rather
842
+ * than reading an atomic amount as whole tokens.
843
+ */
844
+ declare function resolveTokenBySymbol(chainId: number, symbol: string): {
845
+ symbol: string;
846
+ decimals: number;
847
+ } | null;
848
+
849
+ /**
850
+ * #3271: the integrity check every client runs before signing a direct
851
+ * delegation-rail payment's typed data.
852
+ *
853
+ * A direct payment (`POST /payments`, surfaced as `haven_send` / `haven_pay`)
854
+ * is signed as the HybridDeleGator's EIP-712 `PackedUserOperation`, and Haven
855
+ * returns two things for it: that typed data, and `payload_hash` — the
856
+ * ERC-4337 v0.7 UserOperation hash of the same operation. Nothing used to tie
857
+ * the two together at signing time. The typed data is multi-KB and reaches the
858
+ * signer through a language model when it is relayed by hand, so one corrupted
859
+ * character produced a valid-looking signature over the wrong digest, and the
860
+ * first sign of it was `AA24 signature error` from the bundler (#3271,
861
+ * reproduced on dev 2026-09-24).
862
+ *
863
+ * This recomputes the v0.7 hash from the typed data's own message and domain
864
+ * and refuses unless it equals `payload_hash`, and it pins the parts of the
865
+ * typed data the hash does NOT cover (domain name/version/verifyingContract,
866
+ * the field list, the EntryPoint). It is a CORRUPTION check: the caller supplies
867
+ * both values, so it proves they describe the same operation, never that Haven
868
+ * prepared it. Provenance is the byte-free sign context (`payment_id`); what a
869
+ * delegate key will sign at all is `assertBoundDirectPaymentUserOp`
870
+ * (`direct-payment-guard.ts`, #3272 / #3283), which every caller of this check
871
+ * — `HavenClient.signForData` and the signer's `haven_sign` — runs next.
872
+ *
873
+ * Pure viem, no ethers: `@haven_ai/sdk/edge` re-exports it for the edge signer,
874
+ * and `edge-imports.test.ts` pins that graph.
875
+ */
876
+ /** Version of the direct-payment sign context (`GET /payments/:id/sign-context`). */
877
+ declare const DIRECT_SIGN_CONTEXT_VERSION = 1;
878
+ /**
879
+ * #3419: version of the task-budget sign context (`GET
880
+ * /task-budgets/:id/sign-context`), the sign-then-submit envelope every
881
+ * `haven_sign { task_budget_id }` call fetches. The backend emits it
882
+ * (`task-budget-service.ts`, `task_sign_context_version: 1`); the signer
883
+ * derives its enforced set `SUPPORTED_TASK_SIGN_CONTEXT_VERSIONS` from this
884
+ * constant — never a second literal — and the hosted/local task-budget
885
+ * handoffs report it in `signer_compatibility.task_sign_context_version`.
886
+ * The signer could not carry the single source itself (a published package
887
+ * cannot host a constant the backend also serves), so it lives beside the
888
+ * other binding constants here, exactly as `DIRECT_SIGN_CONTEXT_VERSION` does.
889
+ */
890
+ declare const TASK_SIGN_CONTEXT_VERSION = 1;
891
+ /** The ERC-4337 v0.7 EntryPoint — the only one the delegation rail submits to. */
892
+ declare const ENTRY_POINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
893
+ /**
894
+ * The HybridDeleGator EIP-712 domain constants and the `PackedUserOperation`
895
+ * field list, vendored from `@metamask/smart-accounts-kit`
896
+ * (`contracts.HybridDeleGator.constants`, `SIGNABLE_USER_OP_TYPED_DATA`) so the
897
+ * published packages need no runtime dependency on the kit. Pinned equal to the
898
+ * kit's values by `userop-binding.test.ts`.
899
+ */
900
+ declare const HYBRID_DELEGATOR_DOMAIN_NAME = "HybridDeleGator";
901
+ declare const HYBRID_DELEGATOR_DOMAIN_VERSION = "1";
902
+ declare const PACKED_USER_OPERATION_FIELDS: ReadonlyArray<{
903
+ name: string;
904
+ type: string;
905
+ }>;
906
+ /** Refusal raised when UserOperation typed data (a direct payment, or the SDK's x402 funding leg) does not match its `payload_hash`. */
907
+ declare class HavenUserOpBindingError extends HavenError {
908
+ constructor(message: string);
909
+ }
910
+ /** True when the typed data is a `PackedUserOperation` (the direct-payment shape). */
911
+ declare function isPackedUserOperationTypedData(value: unknown): boolean;
912
+ /**
913
+ * Compute the ERC-4337 v0.7 UserOperation hash from a HybridDeleGator
914
+ * `PackedUserOperation` typed-data object — the value Haven returns as
915
+ * `payload_hash` for a direct payment (`getUserOperationHash`, entryPoint 0.7).
916
+ */
917
+ declare function packedUserOperationHash(typedData: unknown): Hex;
918
+ /**
919
+ * Refuse (throw `HavenUserOpBindingError`) unless this `PackedUserOperation`
920
+ * typed data is the operation `payloadHash` names, in the HybridDeleGator
921
+ * domain of its own sender, against the v0.7 EntryPoint. Returns the
922
+ * recomputed hash.
923
+ */
924
+ declare function assertUserOpTypedDataBinding(typedData: unknown, payloadHash: string): Hex;
925
+
926
+ /**
927
+ * The counterfactual HybridDeleGator account address for an owner EOA (#3272).
928
+ *
929
+ * `haven_sign`'s unbound branch (`@haven_ai/signer`'s `tools.ts`) and, since
930
+ * #3283, `HavenClient.signForData` (`direct-payment-guard.ts`) sign a
931
+ * `PackedUserOperation`
932
+ * only when its `sender` (== `domain.verifyingContract`) is THIS SIGNER'S OWN
933
+ * delegate account — never any other HybridDeleGator, and never a third
934
+ * party's. Haven provisions that account counterfactually at signup (#970):
935
+ * it may have zero on-chain transactions, so the signer must be able to
936
+ * compute its address OFFLINE, from nothing but the delegate key's own
937
+ * address.
938
+ *
939
+ * This is exactly what `@metamask/smart-accounts-kit`'s
940
+ * `getCounterfactualAccountData` computes for
941
+ * `implementation: 'Hybrid'`, `deployParams: [owner, [], [], []]` (no passkey
942
+ * co-owners — the only shape Haven's signup flow provisions), `deploySalt:
943
+ * '0x'`: CREATE2 of an `ERC1967Proxy(HybridDeleGatorImpl, initialize(owner,
944
+ * [], [], []))` behind the `SimpleFactory`.
945
+ *
946
+ * VENDORED, NOT IMPORTED. `@metamask/smart-accounts-kit` is a devDependency
947
+ * only (see `package.json`) — this package installs on users' machines and
948
+ * must not carry it at runtime. The constants below (the factory and
949
+ * implementation addresses, the `ERC1967Proxy` bytecode) are copied from the
950
+ * kit's pinned environment / `@metamask/delegation-abis`' bytecode export,
951
+ * exactly like `settlement-child.ts` vendors the DelegationManager and caveat
952
+ * enforcer addresses for the same reason. Cross-checked against the kit by
953
+ * `packages/signer/src/delegate-account.pins.test.ts`, including against the real, on-chain
954
+ * `direct-payment-userop.json` fixture.
955
+ */
956
+
957
+ /**
958
+ * SimpleFactory — deterministically deployed, so Base and Base Sepolia share
959
+ * the address (matches `packages/backend/src/rails/delegation-contracts.ts`'s
960
+ * `simpleFactory` pin for both chains).
961
+ */
962
+ declare const SIMPLE_FACTORY_ADDRESS: Address;
963
+ /**
964
+ * HybridDeleGator implementation — matches `delegation-contracts.ts`'s
965
+ * `hybridDeleGatorImpl` pin for both chains.
966
+ */
967
+ declare const HYBRID_DELEGATOR_IMPLEMENTATION: Address;
968
+ /**
969
+ * Derive the counterfactual HybridDeleGator account address for `owner`, with
970
+ * no passkey co-owners — the only shape Haven's signup flow provisions
971
+ * (#970). Pure and offline: no RPC call, no dependency on the account having
972
+ * been deployed. Verified byte-for-byte against
973
+ * `@metamask/smart-accounts-kit`'s `getCounterfactualAccountData` by
974
+ * `packages/signer/src/delegate-account.pins.test.ts`, including against a real Base Sepolia payload served by the dev backend
975
+ * (`direct-payment-userop.json`).
976
+ */
977
+ declare function deriveDelegateAccountAddress(owner: Address): Address;
978
+
979
+ /**
980
+ * Independent verification of an erc7710 x402 settlement child (#1455).
981
+ *
982
+ * Moved from `@haven_ai/signer` into the SDK by #3283 (epic #3284) so the
983
+ * signer and `HavenClient.signForData` run ONE verifier. The signer checks the
984
+ * child against the Haven-signed expected context; the SDK checks it against
985
+ * the merchant's own 402, which Haven does not produce.
986
+ *
987
+ * WHY THIS EXISTS. `assertExpectedBinding` proves Haven *declared* a payload:
988
+ * the expected context is signed by `HAVEN_X402_BINDING_SIGNER` and commits to
989
+ * the digest of the exact bytes being signed. That is a real property, and it
990
+ * is not this one. It says nothing about what the payload MEANS.
991
+ *
992
+ * A backend that declared `merchantTo = the real merchant` while pinning a
993
+ * different payee in the child's `AllowedCalldata` caveat would produce a
994
+ * perfectly consistent pair: the declaration binds the digest, the digest is
995
+ * the child's, and the child pays someone else. The signature is the authority
996
+ * here — the merchant's facilitator redeems it and pulls from the treasury — so
997
+ * the signer has to re-derive the meaning locally or it is a pass-through with
998
+ * extra steps.
999
+ *
1000
+ * ADDRESSES ARE PINNED HERE ON PURPOSE. Reading the enforcer map from Haven
1001
+ * would make the check circular: an attacker who can pick which contract counts
1002
+ * as "the payee enforcer" can satisfy any comparison. Taking
1003
+ * `@metamask/smart-accounts-kit` as a runtime dependency was the other option
1004
+ * and was rejected — this package installs on users' machines. The constants
1005
+ * below are snapshot-pinned and cross-checked against the kit by a test
1006
+ * (`packages/signer/src/settlement-child.pins.test.ts`), the same pattern
1007
+ * `packages/core/src/chains.ts` uses against its registry.
1008
+ *
1009
+ * EXTRA CAVEATS ARE ALLOWED, and that is deliberate — verified, not assumed
1010
+ * (#1455 review challenged it directly).
1011
+ *
1012
+ * `DelegationManager.redeemDelegations` loops every caveat of every delegation
1013
+ * and calls `beforeHook` on each, with no break and no try/catch: a single
1014
+ * revert aborts the whole redemption, and nothing lets one caveat cause another
1015
+ * to be skipped. Top-level caveats are therefore strictly AND-ed, so one this
1016
+ * file does not recognise can only add a constraint, never remove one.
1017
+ *
1018
+ * The specific challenge was `LogicalOrWrapperEnforcer`, whose terms encode
1019
+ * several caveat GROUPS and whose own security notice warns that "the redeemer
1020
+ * can select the least restrictive group, bypassing stricter requirements in
1021
+ * other groups". That warning is about groups INSIDE the wrapper — it binds
1022
+ * whoever authors wrapper terms. The wrapper is itself one caveat among the
1023
+ * delegation's, so it is AND-ed with the four required below and cannot unlock
1024
+ * them.
1025
+ *
1026
+ * The shape that WOULD be dangerous is the inverse: a required caveat hidden
1027
+ * inside a wrapper group instead of sitting at top level, where the redeemer
1028
+ * could select a group that omits it. This file scans top-level caveats and
1029
+ * refuses on absence, so that child is refused for lacking the caveat — which
1030
+ * is the correct outcome and is pinned by a test.
1031
+ */
1032
+ /** DelegationManager, the EIP-712 `verifyingContract` for a delegation. */
1033
+ declare const DELEGATION_MANAGER = "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3";
1034
+ /**
1035
+ * Caveat enforcers, by role. Deterministically deployed, so Base and Base
1036
+ * Sepolia share addresses — verified for both chains by the pin test.
1037
+ */
1038
+ declare const CAVEAT_ENFORCERS: {
1039
+ readonly erc20TransferAmount: "0xf100b0819427117EcF76Ed94B358B1A5b5C6D2Fc";
1040
+ readonly allowedCalldata: "0xc2b0d624c1c4319760C96503BA27C347F3260f55";
1041
+ readonly timestamp: "0x1046bb45C8d673d4ea75321280DB34899413c069";
1042
+ readonly redeemer: "0xE144b0b2618071B4E56f746313528a669c7E65c5";
1043
+ };
1044
+ /** The backend's own ceiling (`MAX_SETTLEMENT_WINDOW_SECONDS`), enforced again here. */
1045
+ declare const MAX_SETTLEMENT_WINDOW_SECONDS = 600;
1046
+ interface SettlementChildTypedData {
1047
+ domain: {
1048
+ name?: string;
1049
+ version?: string;
1050
+ chainId?: number | string;
1051
+ verifyingContract?: string;
1052
+ };
1053
+ types: Record<string, unknown>;
1054
+ primaryType: string;
1055
+ message: Record<string, unknown>;
1056
+ }
1057
+ /**
1058
+ * True when this typed data is a delegation — the shape that must never be
1059
+ * signed unbound. Excludes a SELF-delegation (`delegate === delegator`,
1060
+ * #3329): that is the shape of a task-budget child
1061
+ * (`task-budget-guards.ts`'s `isTaskChildTypedData`), a DIFFERENT typed-data
1062
+ * class verified by a different function against a different expectation. A
1063
+ * real settlement child's `delegate` is always a facilitator or
1064
+ * `ANY_BENEFICIARY` — never this account's own address — so narrowing here
1065
+ * costs this verifier nothing and keeps the two classes from ever
1066
+ * overlapping.
1067
+ */
1068
+ declare function isSettlementChildTypedData(value: unknown): value is SettlementChildTypedData;
1069
+ /**
1070
+ * Map an x402 network string to a chain id. Local on purpose (#1455 review):
1071
+ * the chain must come from Haven's SIGNED `network` field, never from the
1072
+ * payload under verification — see `verifySettlementChild`.
1073
+ */
1074
+ declare function chainIdForNetwork(network: string | undefined): number | undefined;
1075
+ interface SettlementChildExpectation {
1076
+ merchantTo: string;
1077
+ amount: string;
1078
+ asset: string;
1079
+ /**
1080
+ * Derived from the expected context's SIGNED `network`, never from
1081
+ * `typedData.domain.chainId`. Comparing the payload's own claim against
1082
+ * itself is a check that cannot fail — which is exactly what shipped in the
1083
+ * first draft of this file's call site, and what the review caught.
1084
+ */
1085
+ chainId: number;
1086
+ /** ISO timestamp; the child must not outlive it. */
1087
+ expiresAt?: string;
1088
+ /**
1089
+ * #3283 / #3281 criterion 8: the signer's OWN derived delegate account.
1090
+ * When set, the child's `delegator` must be exactly this account — the
1091
+ * child is a re-delegation of this agent's budget, never a grant from some
1092
+ * other account the key happens to control.
1093
+ */
1094
+ delegatorAccount?: string;
1095
+ /**
1096
+ * #3283: the facilitator addresses the merchant's 402 advertised
1097
+ * (`extra.facilitatorAddresses`). When non-empty, the child must carry a
1098
+ * `RedeemerEnforcer` caveat pinning exactly this set — otherwise the child
1099
+ * is a bearer instrument any party could redeem within its bounds.
1100
+ */
1101
+ redeemers?: readonly string[];
1102
+ }
1103
+ /** `@metamask/delegation-core`'s `ROOT_AUTHORITY` — a delegation chained to nothing. */
1104
+ declare const ROOT_AUTHORITY: string;
1105
+ /**
1106
+ * Verify a settlement child implements what the expected context declares.
1107
+ * Throws `HavenSigningError` on any disagreement; returns nothing on success.
1108
+ *
1109
+ * `now` is injectable so the expiry checks are testable without faking clocks.
1110
+ */
1111
+ declare function verifySettlementChild(typedData: SettlementChildTypedData, expected: SettlementChildExpectation, now?: number): void;
1112
+
1113
+ /** Wire code for a typed-data payload outside the signable allowlist. */
1114
+ declare const TYPED_DATA_NOT_ALLOWED: "TYPED_DATA_NOT_ALLOWED";
1115
+ /**
1116
+ * A typed-data payload was refused before signing because it is not a shape
1117
+ * a delegate key may sign. Nothing was signed. `@haven_ai/signer` subclasses
1118
+ * this to attach its MCP next step; the `code` is the same on both.
1119
+ */
1120
+ declare class HavenTypedDataRefusedError extends HavenSigningError {
1121
+ readonly code: typeof TYPED_DATA_NOT_ALLOWED;
1122
+ constructor(message: string);
1123
+ }
1124
+ /**
1125
+ * Chains the delegation rail has PINNED delegation contracts for
1126
+ * (`packages/backend/src/rails/delegation-contracts.ts`) — the only chains a
1127
+ * direct-payment UserOp may be scoped to. No other chain has a pinned
1128
+ * DelegationManager/enforcer set, so every other chain is deliberately
1129
+ * excluded even where the delegate account itself could exist.
1130
+ */
1131
+ declare const DIRECT_PAYMENT_CHAIN_IDS: ReadonlySet<number>;
1132
+ /** The DeleGator's single-execution `execute((address,uint256,bytes))` — selector `0x5c1c6dcd`. */
1133
+ declare const EXECUTE_ABI: readonly [{
1134
+ readonly type: "function";
1135
+ readonly name: "execute";
1136
+ readonly inputs: readonly [{
1137
+ readonly name: "_execution";
1138
+ readonly type: "tuple";
1139
+ readonly components: readonly [{
1140
+ readonly name: "target";
1141
+ readonly type: "address";
1142
+ }, {
1143
+ readonly name: "value";
1144
+ readonly type: "uint256";
1145
+ }, {
1146
+ readonly name: "callData";
1147
+ readonly type: "bytes";
1148
+ }];
1149
+ }];
1150
+ readonly outputs: readonly [];
1151
+ readonly stateMutability: "payable";
1152
+ }];
1153
+ /**
1154
+ * The content + provenance allowlist (#3272 criteria 1–2). Call ONLY after
1155
+ * `assertUserOpTypedDataBinding` has already proven `typedData` is a
1156
+ * well-formed `PackedUserOperation` matching its own hash — this function
1157
+ * trusts `typedData.domain`/`message` are shaped correctly and checks only
1158
+ * what they SAY. Throws `HavenTypedDataRefusedError` (never returns) on any
1159
+ * disagreement.
1160
+ */
1161
+ declare function assertBoundDirectPaymentUserOp(typedData: Record<string, unknown>, delegateAddress: string): void;
1162
+
1163
+ /**
1164
+ * The settlement-child half of the same surface (#3283): verify an erc7710
1165
+ * child against `expectation` (from somewhere Haven did not write — the
1166
+ * merchant's 402 in the SDK, the Haven-signed expected context in the
1167
+ * signer), AND that it is re-delegated from this key's OWN account. Throws
1168
+ * `HavenTypedDataRefusedError` (code `TYPED_DATA_NOT_ALLOWED`) on any
1169
+ * disagreement.
1170
+ */
1171
+ declare function assertOwnSettlementChild(typedData: unknown, expectation: SettlementChildExpectation, delegateAddress: string): void;
1172
+ /**
1173
+ * #3281 (epic #3284, criterion 5): pin WHERE an x402 EIP-3009 funding leg's
1174
+ * redemption sends the money. The funding leg is always
1175
+ * `transfer(<delegate EOA>, <amount>)` of the quoted token
1176
+ * (`delegation-authorize.ts` → `prepareDelegationPayment(agent, token,
1177
+ * payTo = the delegate EOA, amountRaw)`), so the single execution must be
1178
+ * exactly `encodePacked(asset, 0, transfer(delegateAddress, amount))`.
1179
+ *
1180
+ * `delegateAddress` is the signing key's OWN address — local, not from Haven —
1181
+ * so even a compromised Haven can at most move budget into the agent's own
1182
+ * EOA (the hot-delegate residual the sweep returns), never to an attacker.
1183
+ * `asset` and `amount` keep the leg consistent with what is being paid. Two
1184
+ * callers, two sources: the signer's x402 arm (#3281) passes the Haven-signed
1185
+ * expected context's; `HavenClient.signForData` (#3375) passes the 402 option
1186
+ * the SDK is paying, never the `/x402` response.
1187
+ *
1188
+ * Call ONLY after `assertBoundDirectPaymentUserOp` has passed on the same
1189
+ * typed data (it proves the `execute` → `redeemDelegations` shape this reads).
1190
+ * Throws `HavenTypedDataRefusedError` on any disagreement.
1191
+ */
1192
+ declare function assertFundingLegPaysDelegate(typedData: Record<string, unknown>, expected: {
1193
+ delegateAddress: string;
1194
+ asset: string;
1195
+ amount: string;
1196
+ }): void;
1197
+
1198
+ /**
1199
+ * Task budgets (#3329): independent verification of a task child delegation
1200
+ * and its close UserOp, mirroring `settlement-child.ts` / `direct-payment-
1201
+ * guard.ts` for a DIFFERENT typed-data class.
1202
+ *
1203
+ * A task budget's child is a SELF-delegation: the agent's own delegate
1204
+ * account grants itself a narrower, time-boxed slice of its budget
1205
+ * delegation (`delegate === delegator === the agent's own account`), chained
1206
+ * under the budget via `authority`. That is what separates it from an x402
1207
+ * settlement child, whose `delegate` is a facilitator/ANY_BENEFICIARY — never
1208
+ * the agent's own account. `isSettlementChildTypedData` (`settlement-
1209
+ * child.ts`) was narrowed to return `false` for a self-delegated payload so
1210
+ * the two classes cannot be confused by either verifier; this file is the
1211
+ * task-child counterpart, verified against a different expectation
1212
+ * (`GET /task-budgets/:id/sign-context`, never a merchant's 402).
1213
+ *
1214
+ * Two shapes, two functions:
1215
+ * - `assertOwnTaskChild` verifies the `Delegation` typed data signed to OPEN
1216
+ * a task budget.
1217
+ * - `assertOwnTaskBudgetCloseUserOp` verifies the `PackedUserOperation`
1218
+ * typed data signed to CLOSE one early (an on-chain
1219
+ * `disableDelegation(child)` call from the agent's own account) — an
1220
+ * authority-REDUCING action only, never a grant.
1221
+ *
1222
+ * `hashDelegation` below reproduces `@metamask/smart-accounts-kit/utils`'s
1223
+ * struct hash (via `@metamask/delegation-core`) byte-for-byte, WITHOUT taking
1224
+ * the kit as a runtime dependency (this package installs on users' machines —
1225
+ * same reasoning `delegate-account.ts` and `settlement-child.ts` give for
1226
+ * their own vendored constants). `DELEGATION_TYPEHASH` / `CAVEAT_TYPEHASH`
1227
+ * are pinned literals, cross-checked against the kit's own `hashDelegation`
1228
+ * by a test vector in `task-budget-guards.test.ts` (which imports the kit
1229
+ * ONLY in that test file).
1230
+ */
1231
+
1232
+ /** The backend's own ceiling (`MAX_TASK_BUDGET_TTL_SECONDS`), enforced again here. */
1233
+ declare const MAX_TASK_BUDGET_TTL_SECONDS = 86400;
1234
+ interface TaskChildTypedData {
1235
+ domain: {
1236
+ name?: string;
1237
+ version?: string;
1238
+ chainId?: number | string;
1239
+ verifyingContract?: string;
1240
+ };
1241
+ types: Record<string, unknown>;
1242
+ primaryType: string;
1243
+ message: Record<string, unknown>;
1244
+ }
1245
+ /**
1246
+ * True when this typed data is a task-budget child: a `Delegation` whose
1247
+ * `delegate` equals its own `delegator` (self-delegation). This is the ONLY
1248
+ * shape distinguishing it from an x402 settlement child (whose `delegate` is
1249
+ * a facilitator or `ANY_BENEFICIARY`) — `isSettlementChildTypedData` is
1250
+ * narrowed to return `false` for this same shape so the two verifiers never
1251
+ * overlap.
1252
+ */
1253
+ declare function isTaskChildTypedData(value: unknown): value is TaskChildTypedData;
1254
+ interface TaskChildExpectation {
1255
+ chainId: number;
1256
+ tokenAddress: string;
1257
+ maxAmountAtomic: string;
1258
+ recipientAddress: string | null;
1259
+ /** unix seconds — the `TimestampEnforcer`'s `beforeThreshold`. */
1260
+ expiresAt: number;
1261
+ parentDelegationHash: string;
1262
+ }
1263
+ /**
1264
+ * Verify a task-budget child delegation is EXACTLY what
1265
+ * `GET /task-budgets/:id/sign-context` (purpose `open`) declared, AND that
1266
+ * both `delegate` and `delegator` are this signer's OWN account. Throws
1267
+ * `HavenTypedDataRefusedError` (never returns) on any disagreement.
1268
+ */
1269
+ declare function assertOwnTaskChild(typedData: unknown, expected: TaskChildExpectation, delegateAddress: string, now?: number): void;
1270
+ interface TaskBudgetCloseExpectation {
1271
+ /** The child delegation's own struct hash (`agent_task_budgets.delegation_hash`). */
1272
+ delegationHash: string;
1273
+ }
1274
+ /**
1275
+ * Verify a task-budget close UserOp is EXACTLY an on-chain
1276
+ * `disableDelegation(child)` call from the agent's own delegate account —
1277
+ * authority-REDUCING only, never a grant. Throws `HavenTypedDataRefusedError`
1278
+ * (never returns) on any disagreement.
1279
+ */
1280
+ declare function assertOwnTaskBudgetCloseUserOp(typedData: Record<string, unknown>, expected: TaskBudgetCloseExpectation, delegateAddress: string): void;
1281
+ /**
1282
+ * `@metamask/delegation-core`'s `DELEGATION_TYPEHASH` — pinned, cross-checked
1283
+ * against the kit by a test vector in `task-budget-guards.test.ts`.
1284
+ */
1285
+ declare const DELEGATION_TYPEHASH: Hex;
1286
+ /** `@metamask/delegation-core`'s `CAVEAT_TYPEHASH` — pinned, same cross-check. */
1287
+ declare const CAVEAT_TYPEHASH: Hex;
1288
+ interface DelegationForHashing {
1289
+ delegate: Address;
1290
+ delegator: Address;
1291
+ authority: Hex;
1292
+ caveats: readonly {
1293
+ enforcer: Address;
1294
+ terms: Hex;
1295
+ }[];
1296
+ salt: bigint;
1297
+ }
1298
+ /**
1299
+ * Reproduces `@metamask/smart-accounts-kit/utils`'s `hashDelegation`
1300
+ * byte-for-byte, WITHOUT the kit at runtime (see the file header). Ignores
1301
+ * `signature` — the kit's own `hashDelegation` does the same (it hashes with
1302
+ * `signature: '0x'` regardless of what the caller passes).
1303
+ */
1304
+ declare function hashDelegation(delegation: DelegationForHashing): Hex;
1305
+
1306
+ /**
1307
+ * Runtime-agnostic base64 helpers — the single source of truth for the wire
1308
+ * encoding shared by the SDK and the edge signer (#325).
1309
+ *
1310
+ * Why this module exists: the SDK used `atob`/`btoa` (Web globals) while the
1311
+ * signer used `Buffer` (Node-only). Both worked because both currently run in
1312
+ * Node ≥ 16, but the duplication was a latent wire-incompatibility — and the
1313
+ * signer is headed for non-Node runtimes (browsers, Cloudflare Workers) where
1314
+ * `Buffer` does not exist (#314).
1315
+ *
1316
+ * Encoding contract:
1317
+ * - Output is ALWAYS standard base64 (`+`, `/`, padded). The x402 protocol's
1318
+ * reference implementation validates headers against
1319
+ * `/^[A-Za-z0-9+/]*={0,2}$/` — URL-safe output would be rejected.
1320
+ * - Decoding is tolerant: URL-safe input (`-`, `_`, unpadded) is normalized
1321
+ * before decoding, since third-party merchants are not guaranteed to be as
1322
+ * strict as the reference implementation.
1323
+ * - UTF-8 throughout. Naive `btoa(JSON.stringify(...))` throws on any
1324
+ * non-Latin-1 character (e.g. a merchant description with an emoji or
1325
+ * non-ASCII name); these helpers route through TextEncoder/TextDecoder on
1326
+ * the Web path so multibyte characters round-trip identically on both
1327
+ * runtimes.
1328
+ */
1329
+ /** Encode a UTF-8 string as standard base64. */
1330
+ declare function encodeBase64Utf8(value: string): string;
1331
+ /** Decode standard or URL-safe base64 to a UTF-8 string. */
1332
+ declare function decodeBase64Utf8(value: string): string;
1333
+ /** Encode a JSON-serializable value as a standard-base64 string. */
1334
+ declare function encodeBase64Json(value: unknown): string;
1335
+ /**
1336
+ * Decode a base64 JSON payload.
1337
+ *
1338
+ * Pass a `label` to get a wrapped error message instead of the raw
1339
+ * JSON/base64 error — call sites parsing untrusted merchant headers use this
1340
+ * to produce actionable failures.
1341
+ */
1342
+ declare function decodeBase64Json<T>(value: string, label?: string): T;
1343
+
1344
+ export { X402_PAYMENT_HEADER_NAMES_SENT as $, type SweepEip712Domain as A, type SweepExpectedAuth as B, CONNECTOR_PACKAGE_NAME as C, DEFAULT_NEXT_TOOL_BY_ACTION as D, ENTRY_POINT_V07 as E, type SweepPreparation as F, type SweepSubmitResult as G, type HavenClientUpdate as H, type SweepTypedData as I, TRANSFER_WITH_AUTHORIZATION_TYPES as J, TYPED_DATA_NOT_ALLOWED as K, type TaskBudgetCloseExpectation as L, MAX_TASK_BUDGET_TTL_SECONDS as M, NEXT_TOOL_SERVER_NAMES as N, type TaskChildExpectation as O, PACKED_USER_OPERATION_FIELDS as P, type TaskChildTypedData as Q, ROOT_AUTHORITY as R, type SweepPrepareResponse as S, TASK_SIGN_CONTEXT_VERSION as T, type UnsupportedNodeVersionMessageOptions as U, X402PaymentHeaderValidationError as V, type X402SchemeSelection as W, type X402PaymentHeaderContext as X, X402_LEGACY_PAYMENT_HEADER_NAME as Y, X402_MAX_AUTHORIZATION_WINDOW_SECONDS as Z, X402_PAYMENT_HEADER_NAME as _, type SweepAuthorization as a, HYBRID_DELEGATOR_IMPLEMENTATION as a$, X402_PAYMENT_REQUIRED_HEADER_NAME as a0, X402_PAYMENT_RESPONSE_HEADER_NAME as a1, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS as a2, assertBoundDirectPaymentUserOp as a3, assertOwnTaskBudgetCloseUserOp as a4, assertOwnTaskChild as a5, assertUserOpTypedDataBinding as a6, buildSweepAuthorizationMessage as a7, buildSweepTypedData as a8, buildX402ExpectedMessage as a9, renderNextTool as aA, resolveConnectorChannel as aB, resolveTokenBySymbol as aC, resolveTokenFromAddress as aD, selectErc7710PaymentOption as aE, selectPaymentOption as aF, selectStandardPaymentOption as aG, selectX402SettlementScheme as aH, sweepUsdcAddress as aI, sweepUsdcDomain as aJ, toStandardPaymentRequirements as aK, unsupportedNodeVersionMessage as aL, validateStandardX402PaymentHeader as aM, verifySettlementChild as aN, x402AssetTransferMethod as aO, x402AuthorizationAmount as aP, x402FacilitatorAddresses as aQ, x402PaymentHeaderNamesFor as aR, x402RetryHeadersFor as aS, x402V2PaymentEnvelope as aT, type DelegationForHashing as aU, CAVEAT_ENFORCERS as aV, CAVEAT_TYPEHASH as aW, DELEGATION_MANAGER as aX, DELEGATION_TYPEHASH as aY, DIRECT_PAYMENT_CHAIN_IDS as aZ, EXECUTE_ABI as a_, compareNodeVersions as aa, connectorRerunCommand as ab, connectorSpec as ac, connectorUpgradeCommand as ad, createNextStepBuilder as ae, decodeBase64Json as af, decodeBase64Utf8 as ag, defaultNextToolFor as ah, deriveDelegateAccountAddress as ai, encodeBase64Json as aj, encodeBase64Utf8 as ak, encodePaymentProof as al, hashDelegation as am, havenClientIdentity as an, isConnectorChannel as ao, isErc7710Option as ap, isPackedUserOperationTypedData as aq, isSupportedNodeVersion as ar, isSweepableChain as as, isTaskChildTypedData as at, normalizePaymentRequired as au, packedUserOperationHash as av, parseNextTool as aw, parsePaymentRequired as ax, parsePaymentRequiredResponse as ay, readClientUpdate as az, type SweepSubmitResponse as b, MAX_SETTLEMENT_WINDOW_SECONDS as b0, SIMPLE_FACTORY_ADDRESS as b1, type SettlementChildTypedData as b2, assertFundingLegPaysDelegate as b3, assertOwnSettlementChild as b4, chainIdForNetwork as b5, isSettlementChildTypedData as b6, DIRECT_SIGN_CONTEXT_VERSION as c, ERC7710_ASSET_TRANSFER_METHOD as d, HAVEN_CLIENT_HEADER as e, HAVEN_CONNECTOR_CHANNEL as f, HAVEN_MINIMUM_NODE_VERSION as g, HYBRID_DELEGATOR_DOMAIN_NAME as h, HYBRID_DELEGATOR_DOMAIN_VERSION as i, HavenTypedDataRefusedError as j, HavenUserOpBindingError as k, NEXT_TOOL_SERVER_ROLES as l, type NextStep as m, type NextStepArguments as n, type NextStepHandoff as o, type NextStepInput as p, type NextStepTarget as q, type NextStepTargets as r, type NextToolServerRole as s, SDK_CLIENT_IDENTITY as t, SDK_VERSION as u, SWEEP_BASE_CHAIN_ID as v, SWEEP_BASE_SEPOLIA_CHAIN_ID as w, SWEEP_BASE_SEPOLIA_USDC_ADDRESS as x, SWEEP_BASE_USDC_ADDRESS as y, type SettlementChildExpectation as z };