@haven_ai/sdk 0.8.0-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.
- package/dist/base64-BZDPJ8M1.d.ts +1344 -0
- package/dist/base64-Cyxhsvqd.d.cts +1344 -0
- package/dist/{chunk-UXULZ3ZY.js → chunk-424S4QMG.js} +10 -5
- package/dist/chunk-424S4QMG.js.map +1 -0
- package/dist/{chunk-HX34HOW4.cjs → chunk-4Z6ATE44.cjs} +2 -2
- package/dist/chunk-4Z6ATE44.cjs.map +1 -0
- package/dist/chunk-7UTWSJC5.cjs +106 -0
- package/dist/chunk-7UTWSJC5.cjs.map +1 -0
- package/dist/{chunk-H4APV67M.js → chunk-J7N4LUZZ.js} +2 -2
- package/dist/chunk-J7N4LUZZ.js.map +1 -0
- package/dist/chunk-VRKWNJ7H.js +103 -0
- package/dist/chunk-VRKWNJ7H.js.map +1 -0
- package/dist/{chunk-WJFDXCYP.cjs → chunk-ZDKNPNI3.cjs} +41 -35
- package/dist/chunk-ZDKNPNI3.cjs.map +1 -0
- package/dist/edge.cjs +97 -89
- package/dist/edge.d.cts +4 -2
- package/dist/edge.d.ts +4 -2
- package/dist/edge.js +4 -4
- package/dist/index.cjs +1033 -490
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -147
- package/dist/index.d.ts +103 -147
- package/dist/index.js +705 -189
- package/dist/index.js.map +1 -1
- package/dist/receipt-D4Roey3D.d.cts +130 -0
- package/dist/receipt-WkXHZGbu.d.ts +130 -0
- package/dist/test-support.cjs +71 -18
- package/dist/test-support.cjs.map +1 -1
- package/dist/test-support.d.cts +21 -1
- package/dist/test-support.d.ts +21 -1
- package/dist/test-support.js +53 -3
- package/dist/test-support.js.map +1 -1
- package/dist/{base64-znjJJQqu.d.cts → types-CrszUJ7Z.d.cts} +208 -1306
- package/dist/{base64-znjJJQqu.d.ts → types-CrszUJ7Z.d.ts} +208 -1306
- package/package.json +1 -1
- package/dist/chunk-H4APV67M.js.map +0 -1
- package/dist/chunk-HX34HOW4.cjs.map +0 -1
- package/dist/chunk-UXULZ3ZY.js.map +0 -1
- package/dist/chunk-WJFDXCYP.cjs.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.js';
|
|
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 };
|