@bosonprotocol/x402-server 0.1.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 (53) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +65 -0
  3. package/dist/cjs/challenge/index.d.ts +64 -0
  4. package/dist/cjs/challenge/index.js +96 -0
  5. package/dist/cjs/challenge/index.js.map +1 -0
  6. package/dist/cjs/client-tnrpqVMW.d.ts +36 -0
  7. package/dist/cjs/config-CBr9qMps.d.ts +419 -0
  8. package/dist/cjs/facilitator/index.d.ts +26 -0
  9. package/dist/cjs/facilitator/index.js +136 -0
  10. package/dist/cjs/facilitator/index.js.map +1 -0
  11. package/dist/cjs/handlers/index.d.ts +267 -0
  12. package/dist/cjs/handlers/index.js +1182 -0
  13. package/dist/cjs/handlers/index.js.map +1 -0
  14. package/dist/cjs/index.d.ts +72 -0
  15. package/dist/cjs/index.js +1643 -0
  16. package/dist/cjs/index.js.map +1 -0
  17. package/dist/cjs/onchain/index.d.ts +73 -0
  18. package/dist/cjs/onchain/index.js +87 -0
  19. package/dist/cjs/onchain/index.js.map +1 -0
  20. package/dist/cjs/package.json +3 -0
  21. package/dist/cjs/validate/index.d.ts +67 -0
  22. package/dist/cjs/validate/index.js +429 -0
  23. package/dist/cjs/validate/index.js.map +1 -0
  24. package/dist/esm/challenge/index.js +3 -0
  25. package/dist/esm/challenge/index.js.map +1 -0
  26. package/dist/esm/chunk-4NQ3VKC3.js +84 -0
  27. package/dist/esm/chunk-4NQ3VKC3.js.map +1 -0
  28. package/dist/esm/chunk-CGVXQX5V.js +426 -0
  29. package/dist/esm/chunk-CGVXQX5V.js.map +1 -0
  30. package/dist/esm/chunk-DJMCSCBE.js +3 -0
  31. package/dist/esm/chunk-DJMCSCBE.js.map +1 -0
  32. package/dist/esm/chunk-EAKQ4EFZ.js +124 -0
  33. package/dist/esm/chunk-EAKQ4EFZ.js.map +1 -0
  34. package/dist/esm/chunk-GBPU373M.js +93 -0
  35. package/dist/esm/chunk-GBPU373M.js.map +1 -0
  36. package/dist/esm/chunk-PU5Y7FZG.js +14 -0
  37. package/dist/esm/chunk-PU5Y7FZG.js.map +1 -0
  38. package/dist/esm/chunk-WU7QJ7YP.js +3 -0
  39. package/dist/esm/chunk-WU7QJ7YP.js.map +1 -0
  40. package/dist/esm/chunk-Y5HFLCAT.js +657 -0
  41. package/dist/esm/chunk-Y5HFLCAT.js.map +1 -0
  42. package/dist/esm/facilitator/index.js +4 -0
  43. package/dist/esm/facilitator/index.js.map +1 -0
  44. package/dist/esm/handlers/index.js +6 -0
  45. package/dist/esm/handlers/index.js.map +1 -0
  46. package/dist/esm/index.js +261 -0
  47. package/dist/esm/index.js.map +1 -0
  48. package/dist/esm/onchain/index.js +4 -0
  49. package/dist/esm/onchain/index.js.map +1 -0
  50. package/dist/esm/package.json +3 -0
  51. package/dist/esm/validate/index.js +4 -0
  52. package/dist/esm/validate/index.js.map +1 -0
  53. package/package.json +88 -0
@@ -0,0 +1,1643 @@
1
+ 'use strict';
2
+
3
+ var coreSdk = require('@bosonprotocol/core-sdk');
4
+ var x402Actions = require('@bosonprotocol/x402-actions');
5
+ var escrow = require('@bosonprotocol/x402-core/schemes/escrow');
6
+ var zod = require('zod');
7
+ var eip712 = require('@bosonprotocol/x402-core/eip712');
8
+ var x402Evm = require('@bosonprotocol/x402-evm');
9
+ var stateMachine = require('@bosonprotocol/x402-core/state-machine');
10
+
11
+ // src/server.ts
12
+
13
+ // src/onchain/web3lib-read-stub.ts
14
+ var TAG = "x402-server:read";
15
+ function unreachable(method) {
16
+ return new Error(
17
+ `${TAG}: stub Web3LibAdapter.${method}() should never be called from the read-only CoreSDK instance. If you see this, a non-subgraph code path leaked through.`
18
+ );
19
+ }
20
+ function createReadOnlyWeb3LibStub() {
21
+ return {
22
+ uuid: `${TAG}:stub`,
23
+ getSignerAddress: () => Promise.reject(unreachable("getSignerAddress")),
24
+ isSignerContract: () => Promise.reject(unreachable("isSignerContract")),
25
+ getChainId: () => Promise.reject(unreachable("getChainId")),
26
+ getBalance: () => Promise.reject(unreachable("getBalance")),
27
+ estimateGas: () => Promise.reject(unreachable("estimateGas")),
28
+ sendTransaction: () => Promise.reject(unreachable("sendTransaction")),
29
+ call: () => Promise.reject(unreachable("call")),
30
+ send: () => Promise.reject(unreachable("send")),
31
+ getTransactionReceipt: () => Promise.reject(unreachable("getTransactionReceipt")),
32
+ getCurrentTimeMs: () => Promise.reject(unreachable("getCurrentTimeMs"))
33
+ };
34
+ }
35
+ function buildPaymentRequirements(args) {
36
+ const {
37
+ offer,
38
+ asset,
39
+ amount,
40
+ tokenAuthStrategies,
41
+ recipientId,
42
+ maxTimeoutSeconds,
43
+ fulfillment,
44
+ network,
45
+ escrow: escrow$1,
46
+ channelRegistry
47
+ } = args;
48
+ const actions = x402Actions.deriveInitialNextActions(channelRegistry);
49
+ const requirements = {
50
+ scheme: "escrow",
51
+ network,
52
+ asset,
53
+ amount,
54
+ escrowAddress: escrow$1,
55
+ recipientId,
56
+ maxTimeoutSeconds,
57
+ offer,
58
+ tokenAuthStrategies: [...tokenAuthStrategies],
59
+ ...fulfillment !== void 0 ? { fulfillment } : {},
60
+ actions
61
+ };
62
+ return escrow.escrowPaymentRequirementsSchema.parse(requirements);
63
+ }
64
+ var STUB_CALLER_TAG = "@bosonprotocol/x402-server:sign-full-offer";
65
+ async function signFullOffer({
66
+ fullOffer,
67
+ signer,
68
+ escrow,
69
+ chainId
70
+ }) {
71
+ const web3Lib = buildForwardingAdapter(signer, chainId);
72
+ const result = await coreSdk.exchanges.handler.signFullOffer({
73
+ fullOfferArgsUnsigned: fullOffer,
74
+ contractAddress: escrow,
75
+ chainId,
76
+ web3Lib
77
+ });
78
+ return {
79
+ fullOffer,
80
+ sellerSig: result.signature,
81
+ creator: signer.address
82
+ };
83
+ }
84
+ function buildForwardingAdapter(signer, chainId) {
85
+ const unreachable2 = (method) => Promise.reject(
86
+ new Error(
87
+ `${STUB_CALLER_TAG}: Web3LibAdapter.${method}() called unexpectedly \u2014 sign-full-offer is a signing-only path.`
88
+ )
89
+ );
90
+ return {
91
+ uuid: `${STUB_CALLER_TAG}:forward`,
92
+ getSignerAddress: () => Promise.resolve(signer.address),
93
+ isSignerContract: () => Promise.resolve(false),
94
+ getChainId: () => Promise.resolve(chainId),
95
+ send: async (method, params) => {
96
+ if (method !== "eth_signTypedData_v4") {
97
+ throw new Error(`${STUB_CALLER_TAG}: unexpected RPC method: ${method}`);
98
+ }
99
+ const [, json] = params;
100
+ if (typeof json !== "string") {
101
+ throw new Error(`${STUB_CALLER_TAG}: eth_signTypedData_v4 payload is not a JSON string`);
102
+ }
103
+ const td = JSON.parse(json);
104
+ return signer.signTypedData({
105
+ domain: td.domain,
106
+ types: td.types,
107
+ primaryType: td.primaryType,
108
+ message: td.message
109
+ });
110
+ },
111
+ getBalance: () => unreachable2("getBalance"),
112
+ estimateGas: () => unreachable2("estimateGas"),
113
+ sendTransaction: () => unreachable2("sendTransaction"),
114
+ call: () => unreachable2("call"),
115
+ getTransactionReceipt: () => unreachable2("getTransactionReceipt"),
116
+ getCurrentTimeMs: () => unreachable2("getCurrentTimeMs")
117
+ };
118
+ }
119
+ var httpUrlSchema = zod.z.string().url().refine((url) => url.startsWith("http://") || url.startsWith("https://"), {
120
+ message: "must be an http(s) URL"
121
+ });
122
+ var sellerSignerSchema = zod.z.object({
123
+ address: escrow.addressSchema,
124
+ // `SellerSigner.signTypedData` is typed `Promise<Hex>` in the TS
125
+ // interface — tighten the zod return wrapper to match so a signer
126
+ // that resolves to a non-hex string fails loudly at call time
127
+ // rather than silently producing a bad `BosonOfferRef.sellerSig`.
128
+ signTypedData: zod.z.function().args(zod.z.unknown()).returns(zod.z.promise(escrow.hexSchema))
129
+ }).passthrough();
130
+ var exchangeReaderShallowSchema = zod.z.object({
131
+ read: zod.z.function().args(zod.z.string()).returns(zod.z.unknown())
132
+ }).passthrough();
133
+ var coreSdkReadShallowSchema = zod.z.object({
134
+ getFunds: zod.z.function().args(zod.z.unknown()).returns(zod.z.unknown()),
135
+ getSellersByAddress: zod.z.function().args(zod.z.unknown()).returns(zod.z.unknown()),
136
+ getBuyers: zod.z.function().args(zod.z.unknown()).returns(zod.z.unknown())
137
+ }).passthrough();
138
+ var fulfillmentChannelShallowSchema = zod.z.object({
139
+ id: zod.z.string().min(1),
140
+ validate: zod.z.function(),
141
+ onCommit: zod.z.function()
142
+ }).passthrough();
143
+ var x402bServerConfigSchema = zod.z.object({
144
+ network: escrow.evmNetworkSchema,
145
+ chainId: zod.z.number().int().positive(),
146
+ escrow: escrow.addressSchema,
147
+ signer: sellerSignerSchema,
148
+ facilitator: zod.z.object({
149
+ url: httpUrlSchema
150
+ }).strict(),
151
+ channelRegistry: x402Actions.channelRegistryZodSchema,
152
+ exchangeReader: exchangeReaderShallowSchema.optional(),
153
+ subgraphUrl: httpUrlSchema.optional(),
154
+ coreSdkRead: coreSdkReadShallowSchema.optional(),
155
+ exchangeFulfillmentOptionStore: zod.z.instanceof(Map).optional(),
156
+ fulfillmentRecoveryStore: zod.z.instanceof(Map).optional(),
157
+ fulfillmentChannels: zod.z.array(fulfillmentChannelShallowSchema).superRefine((channels, ctx) => {
158
+ const seen = /* @__PURE__ */ new Set();
159
+ const duplicates = /* @__PURE__ */ new Set();
160
+ for (const c of channels) {
161
+ if (seen.has(c.id)) duplicates.add(c.id);
162
+ seen.add(c.id);
163
+ }
164
+ if (duplicates.size > 0) {
165
+ ctx.addIssue({
166
+ code: zod.z.ZodIssueCode.custom,
167
+ message: `fulfillmentChannels has duplicate id(s): ${[...duplicates].join(", ")}`
168
+ });
169
+ }
170
+ }).optional()
171
+ }).strict().superRefine((cfg, ctx) => {
172
+ const networkChainId = Number(cfg.network.split(":")[1]);
173
+ if (networkChainId !== cfg.chainId) {
174
+ ctx.addIssue({
175
+ code: zod.z.ZodIssueCode.custom,
176
+ path: ["chainId"],
177
+ message: `chainId (${cfg.chainId}) must match network (${cfg.network})`
178
+ });
179
+ }
180
+ });
181
+ function assertChannelRegistryEscrowMatch(config) {
182
+ if (config.escrow.toLowerCase() !== config.channelRegistry.escrow.toLowerCase()) {
183
+ throw new Error(
184
+ `x402-server config: escrow (${config.escrow}) does not match channelRegistry.escrow (${config.channelRegistry.escrow})`
185
+ );
186
+ }
187
+ }
188
+
189
+ // src/facilitator/errors.ts
190
+ var FacilitatorHttpError = class extends Error {
191
+ constructor(message, init) {
192
+ super(message, init.cause !== void 0 ? { cause: init.cause } : void 0);
193
+ this.name = "FacilitatorHttpError";
194
+ this.code = init.code;
195
+ if (init.status !== void 0) this.status = init.status;
196
+ if (init.facilitatorCode !== void 0) this.facilitatorCode = init.facilitatorCode;
197
+ }
198
+ };
199
+
200
+ // src/facilitator/client.ts
201
+ function createFacilitatorClient(opts) {
202
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
203
+ if (fetchImpl === void 0) {
204
+ throw new Error(
205
+ "createFacilitatorClient: no `fetch` implementation available. Pass `opts.fetch` explicitly."
206
+ );
207
+ }
208
+ const baseUrl = opts.url.replace(/\/+$/, "");
209
+ const baseHeaders = { "content-type": "application/json", ...opts.headers ?? {} };
210
+ const post = async (path, body, validate) => {
211
+ let res;
212
+ try {
213
+ res = await fetchImpl(`${baseUrl}${path}`, {
214
+ method: "POST",
215
+ headers: baseHeaders,
216
+ body: JSON.stringify(body)
217
+ });
218
+ } catch (cause) {
219
+ throw new FacilitatorHttpError(`facilitator network error (${path})`, {
220
+ code: "NETWORK_ERROR",
221
+ cause
222
+ });
223
+ }
224
+ let text;
225
+ try {
226
+ text = await res.text();
227
+ } catch (cause) {
228
+ throw new FacilitatorHttpError(`facilitator response body could not be read (${path})`, {
229
+ code: "BAD_RESPONSE_BODY",
230
+ status: res.status,
231
+ cause
232
+ });
233
+ }
234
+ let parsed;
235
+ try {
236
+ parsed = text.length === 0 ? null : JSON.parse(text);
237
+ } catch (cause) {
238
+ throw new FacilitatorHttpError(`facilitator returned non-JSON body (${path})`, {
239
+ code: "BAD_RESPONSE_BODY",
240
+ status: res.status,
241
+ cause
242
+ });
243
+ }
244
+ if (!res.ok) {
245
+ if (res.status === 400 && isFailureBranch(parsed) && validate(parsed)) {
246
+ return parsed;
247
+ }
248
+ const facilitatorCode = extractFacilitatorCode(parsed);
249
+ throw new FacilitatorHttpError(
250
+ `facilitator HTTP ${res.status} (${path}): ${reasonString(parsed) ?? text}`,
251
+ {
252
+ code: "BAD_HTTP_STATUS",
253
+ status: res.status,
254
+ ...facilitatorCode !== void 0 ? { facilitatorCode } : {}
255
+ }
256
+ );
257
+ }
258
+ if (!validate(parsed)) {
259
+ throw new FacilitatorHttpError(`facilitator returned unexpected body shape (${path})`, {
260
+ code: "BAD_RESPONSE_BODY",
261
+ status: res.status
262
+ });
263
+ }
264
+ return parsed;
265
+ };
266
+ return {
267
+ verify: (input) => post("/verify", input, isVerifyResult),
268
+ settle: (input) => post("/settle", input, isSettleResult),
269
+ performAction: (input) => post(
270
+ `/perform-action?action=${encodeURIComponent(input.action)}`,
271
+ input,
272
+ isPerformActionResult
273
+ )
274
+ };
275
+ }
276
+ function isObject(v) {
277
+ return v !== null && typeof v === "object";
278
+ }
279
+ function isFailureBranch(v) {
280
+ return isObject(v) && v.ok === false && typeof v.code === "string" && typeof v.reason === "string";
281
+ }
282
+ function isVerifyResult(parsed) {
283
+ if (!isObject(parsed)) return false;
284
+ if (parsed.ok === true) return true;
285
+ return isFailureBranch(parsed);
286
+ }
287
+ function isSettleResult(parsed) {
288
+ if (!isObject(parsed)) return false;
289
+ if (parsed.ok === true) {
290
+ return typeof parsed.exchangeId === "string" && typeof parsed.txHash === "string";
291
+ }
292
+ return isFailureBranch(parsed);
293
+ }
294
+ function isPerformActionResult(parsed) {
295
+ if (!isObject(parsed)) return false;
296
+ if (parsed.ok === true) {
297
+ if (typeof parsed.txHash !== "string") return false;
298
+ if (parsed.newExchangeState !== void 0 && typeof parsed.newExchangeState !== "string") {
299
+ return false;
300
+ }
301
+ if (parsed.newDisputeState !== void 0 && typeof parsed.newDisputeState !== "string") {
302
+ return false;
303
+ }
304
+ return true;
305
+ }
306
+ return isFailureBranch(parsed);
307
+ }
308
+ function extractFacilitatorCode(body) {
309
+ if (body === null || typeof body !== "object") return void 0;
310
+ const code = body.code;
311
+ return typeof code === "string" ? code : void 0;
312
+ }
313
+ function reasonString(body) {
314
+ if (body === null || typeof body !== "object") return void 0;
315
+ const reason = body.reason;
316
+ return typeof reason === "string" ? reason : void 0;
317
+ }
318
+
319
+ // src/internal/facilitator-endpoints.ts
320
+ var COMMIT_ACTION_IDS = /* @__PURE__ */ new Set([
321
+ "boson-createOfferAndCommit",
322
+ "boson-createOfferCommitAndRedeem"
323
+ ]);
324
+ function facilitatorEndpointFor(actionId, facilitatorUrl) {
325
+ const base = facilitatorUrl.replace(/\/+$/, "");
326
+ if (COMMIT_ACTION_IDS.has(actionId)) {
327
+ return `${base}/settle`;
328
+ }
329
+ return `${base}/perform-action?action=${encodeURIComponent(actionId)}`;
330
+ }
331
+ function stampFacilitatorEndpoints(next, facilitatorUrl) {
332
+ return next.map((entry) => {
333
+ if (!entry.channels.includes("facilitator")) {
334
+ return entry;
335
+ }
336
+ if (entry.endpoints?.facilitator !== void 0) {
337
+ return entry;
338
+ }
339
+ return {
340
+ ...entry,
341
+ endpoints: {
342
+ ...entry.endpoints,
343
+ facilitator: facilitatorEndpointFor(entry.id, facilitatorUrl)
344
+ }
345
+ };
346
+ });
347
+ }
348
+
349
+ // src/handlers/next-actions.ts
350
+ function emitNextActions(input, registry, facilitatorUrl) {
351
+ const derived = input.exchangeState === x402Actions.ExchangeState.DISPUTED ? x402Actions.deriveNextActions(
352
+ {
353
+ exchangeId: input.exchangeId,
354
+ exchangeState: x402Actions.ExchangeState.DISPUTED,
355
+ disputeState: input.disputeState
356
+ },
357
+ registry
358
+ ) : x402Actions.deriveNextActions(
359
+ { exchangeId: input.exchangeId, exchangeState: input.exchangeState },
360
+ registry
361
+ );
362
+ if (facilitatorUrl === void 0) {
363
+ return derived;
364
+ }
365
+ return {
366
+ ...derived,
367
+ next: stampFacilitatorEndpoints(derived.next, facilitatorUrl)
368
+ };
369
+ }
370
+
371
+ // src/handlers/types.ts
372
+ function handlerOk(body) {
373
+ return { ok: true, status: 200, body };
374
+ }
375
+ function plainHandlerOk(body) {
376
+ return { ok: true, status: 200, body };
377
+ }
378
+ function handlerErr(status, code, reason, details) {
379
+ const body = { code, reason };
380
+ if (details !== void 0) body.details = details;
381
+ return { ok: false, status, body };
382
+ }
383
+ function decodeXPaymentHeader(header) {
384
+ if (header === void 0 || header === null || header.length === 0) {
385
+ return { ok: false, code: "MISSING_HEADER", reason: "X-PAYMENT header is missing" };
386
+ }
387
+ const padded = base64UrlToBase64(header);
388
+ let decoded;
389
+ try {
390
+ if (typeof atob === "function") {
391
+ const binary = atob(padded);
392
+ const bytes = new Uint8Array(binary.length);
393
+ for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
394
+ decoded = new TextDecoder().decode(bytes);
395
+ } else {
396
+ decoded = Buffer.from(padded, "base64").toString("utf8");
397
+ }
398
+ } catch (e) {
399
+ return { ok: false, code: "INVALID_BASE64", reason: e.message };
400
+ }
401
+ let parsed;
402
+ try {
403
+ parsed = JSON.parse(decoded);
404
+ } catch (e) {
405
+ return { ok: false, code: "INVALID_JSON", reason: e.message };
406
+ }
407
+ try {
408
+ const payload = escrow.parseEscrowPaymentPayload(parsed);
409
+ return { ok: true, payload };
410
+ } catch (e) {
411
+ return { ok: false, code: "INVALID_PAYLOAD", reason: e.message };
412
+ }
413
+ }
414
+ function base64UrlToBase64(input) {
415
+ const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
416
+ const padding = normalized.length % 4 === 0 ? "" : "=".repeat(4 - normalized.length % 4);
417
+ return normalized + padding;
418
+ }
419
+ async function validatePaymentPayload(args) {
420
+ const { payload, requirements } = args;
421
+ if (payload.scheme !== "escrow" || requirements.scheme !== "escrow") {
422
+ return failure(1, "SCHEME_MISMATCH", "scheme", "escrow", payload.scheme);
423
+ }
424
+ if (payload.network !== requirements.network) {
425
+ return failure(2, "NETWORK_MISMATCH", "network", requirements.network, payload.network);
426
+ }
427
+ if (!deepEqual(payload.payload.offerRef.fullOffer, requirements.offer.fullOffer)) {
428
+ return failure(
429
+ 3,
430
+ "FULL_OFFER_MISMATCH",
431
+ "payload.offerRef.fullOffer",
432
+ "<requirements.offer.fullOffer>",
433
+ "<payload.offerRef.fullOffer>"
434
+ );
435
+ }
436
+ if (payload.payload.offerRef.sellerSig !== requirements.offer.sellerSig) {
437
+ return failure(
438
+ 4,
439
+ "SELLER_SIG_MISMATCH",
440
+ "payload.offerRef.sellerSig",
441
+ requirements.offer.sellerSig,
442
+ payload.payload.offerRef.sellerSig
443
+ );
444
+ }
445
+ const advertisedActions = requirements.actions.next.map((entry) => entry.id);
446
+ if (!advertisedActions.includes(payload.payload.action)) {
447
+ return failure(
448
+ 5,
449
+ "ACTION_NOT_IN_REQUIREMENTS",
450
+ "payload.action",
451
+ advertisedActions,
452
+ payload.payload.action
453
+ );
454
+ }
455
+ if (!requirements.tokenAuthStrategies.includes(payload.payload.tokenAuthStrategy)) {
456
+ return failure(
457
+ 6,
458
+ "TOKEN_AUTH_NOT_IN_REQUIREMENTS",
459
+ "payload.tokenAuthStrategy",
460
+ requirements.tokenAuthStrategies,
461
+ payload.payload.tokenAuthStrategy
462
+ );
463
+ }
464
+ const calldataResult = await checkFunctionSignatureAndCalldataEquality(payload);
465
+ if (calldataResult !== null) return calldataResult;
466
+ if (payload.payload.buyer.toLowerCase() !== payload.payload.metaTx.from.toLowerCase()) {
467
+ return failure(
468
+ 8,
469
+ "BAD_META_TX_SIGNATURE",
470
+ "payload.metaTx.from",
471
+ payload.payload.buyer,
472
+ payload.payload.metaTx.from
473
+ );
474
+ }
475
+ let recovered;
476
+ try {
477
+ recovered = await eip712.recoverMetaTransactionSigner({
478
+ chainId: args.chainId,
479
+ verifyingContract: requirements.escrowAddress,
480
+ message: {
481
+ nonce: BigInt(payload.payload.metaTx.nonce),
482
+ from: payload.payload.metaTx.from,
483
+ contractAddress: requirements.escrowAddress,
484
+ functionName: payload.payload.metaTx.functionName,
485
+ functionSignature: payload.payload.metaTx.functionSignature
486
+ },
487
+ signature: encodeRsv(payload.payload.metaTx.sig)
488
+ });
489
+ } catch (e) {
490
+ return failure(
491
+ 8,
492
+ "BAD_META_TX_SIGNATURE",
493
+ "payload.metaTx.sig",
494
+ "recoverable ECDSA signature",
495
+ payload.payload.metaTx.sig,
496
+ e.message
497
+ );
498
+ }
499
+ if (recovered.toLowerCase() !== payload.payload.buyer.toLowerCase()) {
500
+ return failure(
501
+ 8,
502
+ "BAD_META_TX_SIGNATURE",
503
+ "payload.metaTx.sig",
504
+ payload.payload.buyer,
505
+ recovered
506
+ );
507
+ }
508
+ const strategyResult = checkTokenAuthRules(payload, requirements, args.now);
509
+ if (strategyResult !== null) return strategyResult;
510
+ const fulfillmentResult = checkFulfillment(payload, requirements, args.validateFulfillmentData);
511
+ if (fulfillmentResult !== null) return fulfillmentResult;
512
+ return { ok: true };
513
+ }
514
+ async function checkFunctionSignatureAndCalldataEquality(payload) {
515
+ const action = payload.payload.action;
516
+ const buildCalldata = action === "boson-createOfferAndCommit" ? x402Evm.buildCreateOfferAndCommitCalldata : action === "boson-createOfferCommitAndRedeem" ? x402Evm.buildCreateOfferCommitAndRedeemCalldata : void 0;
517
+ if (!buildCalldata) {
518
+ return failure(
519
+ 7,
520
+ "CALLDATA_MISMATCH",
521
+ "payload.action",
522
+ "boson-createOfferAndCommit | boson-createOfferCommitAndRedeem",
523
+ action,
524
+ "rule-7 calldata reconstruction is only defined for commit-time actions"
525
+ );
526
+ }
527
+ const fullOfferWithSig = {
528
+ ...payload.payload.offerRef.fullOffer,
529
+ committer: payload.payload.buyer,
530
+ signature: payload.payload.offerRef.sellerSig
531
+ };
532
+ let expected;
533
+ try {
534
+ expected = await buildCalldata({ fullOffer: fullOfferWithSig });
535
+ } catch (e) {
536
+ return failure(
537
+ 7,
538
+ "CALLDATA_MISMATCH",
539
+ "payload.metaTx.functionSignature",
540
+ void 0,
541
+ void 0,
542
+ e.message
543
+ );
544
+ }
545
+ if (expected.functionName !== payload.payload.metaTx.functionName) {
546
+ return failure(
547
+ 7,
548
+ "CALLDATA_MISMATCH",
549
+ "payload.metaTx.functionName",
550
+ expected.functionName,
551
+ payload.payload.metaTx.functionName
552
+ );
553
+ }
554
+ if (expected.functionSignature.toLowerCase() !== payload.payload.metaTx.functionSignature.toLowerCase()) {
555
+ return failure(
556
+ 7,
557
+ "CALLDATA_MISMATCH",
558
+ "payload.metaTx.functionSignature",
559
+ expected.functionSignature,
560
+ payload.payload.metaTx.functionSignature
561
+ );
562
+ }
563
+ return null;
564
+ }
565
+ function checkTokenAuthRules(payload, requirements, nowSec) {
566
+ const strategy = payload.payload.tokenAuthStrategy;
567
+ const tokenAuth = payload.payload.tokenAuth;
568
+ const now = nowSec ?? Math.floor(Date.now() / 1e3);
569
+ const horizon = now + requirements.maxTimeoutSeconds;
570
+ if (strategy === "none") {
571
+ if (tokenAuth !== void 0) {
572
+ return failure(
573
+ 9,
574
+ "TOKEN_AUTH_UNEXPECTED",
575
+ "payload.tokenAuth",
576
+ "undefined (strategy=none)",
577
+ tokenAuth.kind
578
+ );
579
+ }
580
+ return null;
581
+ }
582
+ if (tokenAuth === void 0) {
583
+ return failure(
584
+ 9,
585
+ "TOKEN_AUTH_MISSING",
586
+ "payload.tokenAuth",
587
+ `<${strategy} authorization>`,
588
+ "undefined"
589
+ );
590
+ }
591
+ if (tokenAuth.kind !== strategy) {
592
+ return failure(9, "TOKEN_AUTH_MISSING", "payload.tokenAuth.kind", strategy, tokenAuth.kind);
593
+ }
594
+ switch (tokenAuth.kind) {
595
+ case "erc3009": {
596
+ if (tokenAuth.data.value !== requirements.amount) {
597
+ return failure(
598
+ 9,
599
+ "TOKEN_AUTH_AMOUNT_MISMATCH",
600
+ "payload.tokenAuth.data.value",
601
+ requirements.amount,
602
+ tokenAuth.data.value
603
+ );
604
+ }
605
+ if (tokenAuth.data.to.toLowerCase() !== requirements.escrowAddress.toLowerCase()) {
606
+ return failure(
607
+ 9,
608
+ "TOKEN_AUTH_RECIPIENT_MISMATCH",
609
+ "payload.tokenAuth.data.to",
610
+ requirements.escrowAddress,
611
+ tokenAuth.data.to
612
+ );
613
+ }
614
+ if (tokenAuth.data.validBefore > horizon) {
615
+ return failure(
616
+ 9,
617
+ "TOKEN_AUTH_DEADLINE_EXCEEDED",
618
+ "payload.tokenAuth.data.validBefore",
619
+ `<= ${horizon}`,
620
+ tokenAuth.data.validBefore
621
+ );
622
+ }
623
+ return null;
624
+ }
625
+ case "permit": {
626
+ if (tokenAuth.data.value !== requirements.amount) {
627
+ return failure(
628
+ 10,
629
+ "TOKEN_AUTH_AMOUNT_MISMATCH",
630
+ "payload.tokenAuth.data.value",
631
+ requirements.amount,
632
+ tokenAuth.data.value
633
+ );
634
+ }
635
+ if (tokenAuth.data.spender.toLowerCase() !== requirements.escrowAddress.toLowerCase()) {
636
+ return failure(
637
+ 10,
638
+ "TOKEN_AUTH_SPENDER_MISMATCH",
639
+ "payload.tokenAuth.data.spender",
640
+ requirements.escrowAddress,
641
+ tokenAuth.data.spender
642
+ );
643
+ }
644
+ if (tokenAuth.data.deadline > horizon) {
645
+ return failure(
646
+ 10,
647
+ "TOKEN_AUTH_DEADLINE_EXCEEDED",
648
+ "payload.tokenAuth.data.deadline",
649
+ `<= ${horizon}`,
650
+ tokenAuth.data.deadline
651
+ );
652
+ }
653
+ return null;
654
+ }
655
+ case "permit2": {
656
+ if (tokenAuth.data.permitted.amount !== requirements.amount) {
657
+ return failure(
658
+ 11,
659
+ "TOKEN_AUTH_AMOUNT_MISMATCH",
660
+ "payload.tokenAuth.data.permitted.amount",
661
+ requirements.amount,
662
+ tokenAuth.data.permitted.amount
663
+ );
664
+ }
665
+ if (tokenAuth.data.permitted.token.toLowerCase() !== requirements.asset.toLowerCase()) {
666
+ return failure(
667
+ 11,
668
+ "TOKEN_AUTH_TOKEN_MISMATCH",
669
+ "payload.tokenAuth.data.permitted.token",
670
+ requirements.asset,
671
+ tokenAuth.data.permitted.token
672
+ );
673
+ }
674
+ if (tokenAuth.data.spender.toLowerCase() !== requirements.escrowAddress.toLowerCase()) {
675
+ return failure(
676
+ 11,
677
+ "TOKEN_AUTH_SPENDER_MISMATCH",
678
+ "payload.tokenAuth.data.spender",
679
+ requirements.escrowAddress,
680
+ tokenAuth.data.spender
681
+ );
682
+ }
683
+ if (tokenAuth.data.deadline > horizon) {
684
+ return failure(
685
+ 11,
686
+ "TOKEN_AUTH_DEADLINE_EXCEEDED",
687
+ "payload.tokenAuth.data.deadline",
688
+ `<= ${horizon}`,
689
+ tokenAuth.data.deadline
690
+ );
691
+ }
692
+ return null;
693
+ }
694
+ default:
695
+ return failure(
696
+ 9,
697
+ "TOKEN_AUTH_UNKNOWN_STRATEGY",
698
+ "payload.tokenAuth.kind",
699
+ "erc3009 | permit | permit2",
700
+ tokenAuth.kind
701
+ );
702
+ }
703
+ }
704
+ function checkFulfillment(payload, requirements, validator) {
705
+ const required = requirements.fulfillment?.required === true;
706
+ const carried = payload.fulfillment;
707
+ if (carried === void 0) {
708
+ return required ? failure(13, "FULFILLMENT_REQUIRED", "payload.fulfillment", "<option>", "undefined") : null;
709
+ }
710
+ const advertised = requirements.fulfillment?.options ?? [];
711
+ const matched = advertised.find((option) => option.id === carried.option);
712
+ if (!matched) {
713
+ return failure(
714
+ 13,
715
+ "FULFILLMENT_OPTION_NOT_ADVERTISED",
716
+ "payload.fulfillment.option",
717
+ advertised.map((o) => o.id),
718
+ carried.option
719
+ );
720
+ }
721
+ const action = payload.payload.action;
722
+ if (action === "boson-createOfferCommitAndRedeem") {
723
+ if (carried.data === void 0) {
724
+ return failure(
725
+ 13,
726
+ "FULFILLMENT_DATA_REQUIRED",
727
+ "payload.fulfillment.data",
728
+ matched.schema ?? "null",
729
+ "undefined",
730
+ "atomic createOfferCommitAndRedeem requires fulfillment.data at commit time"
731
+ );
732
+ }
733
+ if (validator !== void 0) {
734
+ const result = validator(matched.id, carried.data);
735
+ if (!result.ok) {
736
+ return failure(
737
+ 13,
738
+ "FULFILLMENT_DATA_INVALID",
739
+ "payload.fulfillment.data",
740
+ matched.schema,
741
+ carried.data,
742
+ result.reason
743
+ );
744
+ }
745
+ }
746
+ return null;
747
+ }
748
+ if (carried.data !== void 0) {
749
+ return failure(
750
+ 13,
751
+ "FULFILLMENT_DATA_UNEXPECTED",
752
+ "payload.fulfillment.data",
753
+ "undefined",
754
+ carried.data,
755
+ "two-step boson-createOfferAndCommit defers fulfillment.data to the redeem POST body"
756
+ );
757
+ }
758
+ return null;
759
+ }
760
+ function deepEqual(a, b) {
761
+ if (a === b) return true;
762
+ if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
763
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
764
+ if (Array.isArray(a) && Array.isArray(b)) {
765
+ if (a.length !== b.length) return false;
766
+ for (let i = 0; i < a.length; i += 1) {
767
+ if (!deepEqual(a[i], b[i])) return false;
768
+ }
769
+ return true;
770
+ }
771
+ const ao = a;
772
+ const bo = b;
773
+ const aKeys = Object.keys(ao);
774
+ const bKeys = Object.keys(bo);
775
+ if (aKeys.length !== bKeys.length) return false;
776
+ for (const k of aKeys) {
777
+ if (!Object.prototype.hasOwnProperty.call(bo, k)) return false;
778
+ if (!deepEqual(ao[k], bo[k])) return false;
779
+ }
780
+ return true;
781
+ }
782
+ function encodeRsv(sig) {
783
+ if (sig.v !== 0 && sig.v !== 1 && sig.v !== 27 && sig.v !== 28) {
784
+ throw new Error("signature v must be 0, 1, 27, or 28");
785
+ }
786
+ const r = sig.r.replace(/^0x/, "").padStart(64, "0");
787
+ const s = sig.s.replace(/^0x/, "").padStart(64, "0");
788
+ const normalizedV = sig.v === 0 || sig.v === 1 ? sig.v + 27 : sig.v;
789
+ const v = normalizedV.toString(16).padStart(2, "0");
790
+ return `0x${r}${s}${v}`;
791
+ }
792
+ function failure(rule, code, field, expected, got, reason) {
793
+ const out = { ok: false, rule, code };
794
+ if (field !== void 0) out.field = field;
795
+ if (expected !== void 0) out.expected = expected;
796
+ if (got !== void 0) out.got = got;
797
+ if (reason !== void 0) out.reason = reason;
798
+ return out;
799
+ }
800
+ function verifyExchangeSnapshot(snapshot, expected) {
801
+ if (snapshot === null) {
802
+ return { ok: false, code: "EXCHANGE_NOT_FOUND" };
803
+ }
804
+ if (snapshot.state !== expected.state) {
805
+ return {
806
+ ok: false,
807
+ code: "STATE_MISMATCH",
808
+ field: "state",
809
+ expected: expected.state,
810
+ got: snapshot.state
811
+ };
812
+ }
813
+ if (expected.state === x402Actions.ExchangeState.DISPUTED) {
814
+ if (snapshot.disputeState !== expected.disputeState) {
815
+ return {
816
+ ok: false,
817
+ code: "DISPUTE_STATE_MISMATCH",
818
+ field: "disputeState",
819
+ expected: expected.disputeState,
820
+ got: snapshot.disputeState
821
+ };
822
+ }
823
+ }
824
+ if (snapshot.seller.toLowerCase() !== expected.seller.toLowerCase()) {
825
+ return {
826
+ ok: false,
827
+ code: "SELLER_MISMATCH",
828
+ field: "seller",
829
+ expected: expected.seller,
830
+ got: snapshot.seller
831
+ };
832
+ }
833
+ if (snapshot.exchangeToken.toLowerCase() !== expected.exchangeToken.toLowerCase()) {
834
+ return {
835
+ ok: false,
836
+ code: "TOKEN_MISMATCH",
837
+ field: "exchangeToken",
838
+ expected: expected.exchangeToken,
839
+ got: snapshot.exchangeToken
840
+ };
841
+ }
842
+ if (snapshot.price !== expected.price) {
843
+ return {
844
+ ok: false,
845
+ code: "PRICE_MISMATCH",
846
+ field: "price",
847
+ expected: expected.price,
848
+ got: snapshot.price
849
+ };
850
+ }
851
+ return { ok: true };
852
+ }
853
+ async function verifyExchange(reader, exchangeId, expected, options = {}) {
854
+ const attempts = Math.max(1, Math.floor(options.attempts ?? 3));
855
+ const delayMs = Math.max(0, Math.floor(options.delayMs ?? 50));
856
+ let result = { ok: false, code: "EXCHANGE_NOT_FOUND" };
857
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
858
+ const snapshot = await reader.read(exchangeId);
859
+ result = verifyExchangeSnapshot(snapshot, expected);
860
+ if (result.ok || !isRetryableVerifyResult(result) || attempt === attempts) {
861
+ return result;
862
+ }
863
+ if (delayMs > 0) {
864
+ await delay(delayMs);
865
+ }
866
+ }
867
+ return result;
868
+ }
869
+ function isRetryableVerifyResult(result) {
870
+ return !result.ok && (result.code === "EXCHANGE_NOT_FOUND" || result.code === "STATE_MISMATCH" || result.code === "DISPUTE_STATE_MISMATCH");
871
+ }
872
+ async function delay(ms) {
873
+ await new Promise((resolve) => {
874
+ setTimeout(resolve, ms);
875
+ });
876
+ }
877
+
878
+ // src/handlers/commit-and-redeem.ts
879
+ async function handleCommit(input, ctx) {
880
+ return await handleCommitImpl(input, ctx, {
881
+ expectedAction: "boson-createOfferAndCommit",
882
+ expectedState: x402Actions.ExchangeState.COMMITTED
883
+ });
884
+ }
885
+ async function handleCommitAndRedeem(input, ctx) {
886
+ return await handleCommitImpl(input, ctx, {
887
+ expectedAction: "boson-createOfferCommitAndRedeem",
888
+ expectedState: x402Actions.ExchangeState.REDEEMED
889
+ });
890
+ }
891
+ async function handleCommitImpl(input, ctx, expected) {
892
+ const decoded = decodeXPaymentHeader(input.paymentHeader);
893
+ if (!decoded.ok) {
894
+ const status = decoded.code === "MISSING_HEADER" ? 402 : 400;
895
+ return handlerErr(status, decoded.code, decoded.reason);
896
+ }
897
+ if (decoded.payload.payload.action !== expected.expectedAction) {
898
+ return handlerErr(
899
+ 400,
900
+ "ACTION_ROUTE_MISMATCH",
901
+ `handler expected action ${expected.expectedAction}, got ${decoded.payload.payload.action}`,
902
+ {
903
+ expected: expected.expectedAction,
904
+ got: decoded.payload.payload.action
905
+ }
906
+ );
907
+ }
908
+ const channels = ctx.config.fulfillmentChannels ?? [];
909
+ const channelById = new Map(channels.map((c) => [c.id, c]));
910
+ const validation = await validatePaymentPayload({
911
+ payload: decoded.payload,
912
+ requirements: input.requirements,
913
+ chainId: ctx.config.chainId,
914
+ validateFulfillmentData: (option, data) => {
915
+ const channel = channelById.get(option);
916
+ if (channel === void 0) {
917
+ return {
918
+ ok: false,
919
+ reason: `fulfillment.option '${option}' has no registered channel adapter on this server`
920
+ };
921
+ }
922
+ try {
923
+ return channel.validate(data);
924
+ } catch (e) {
925
+ return { ok: false, reason: e instanceof Error ? e.message : String(e) };
926
+ }
927
+ }
928
+ });
929
+ if (!validation.ok) {
930
+ return handlerErr(400, validation.code, validation.reason ?? `rule ${validation.rule} failed`, {
931
+ rule: validation.rule,
932
+ field: validation.field,
933
+ expected: validation.expected,
934
+ got: validation.got
935
+ });
936
+ }
937
+ let settleResult;
938
+ try {
939
+ settleResult = await ctx.facilitator.settle({
940
+ scheme: "escrow",
941
+ network: input.requirements.network,
942
+ payload: decoded.payload,
943
+ requirements: input.requirements
944
+ });
945
+ } catch (e) {
946
+ if (e instanceof FacilitatorHttpError) {
947
+ return handlerErr(502, "FACILITATOR_UNREACHABLE", e.message, {
948
+ code: e.code,
949
+ status: e.status,
950
+ facilitatorCode: e.facilitatorCode
951
+ });
952
+ }
953
+ throw e;
954
+ }
955
+ if (!settleResult.ok) {
956
+ return handlerErr(502, "FACILITATOR_REJECTED", settleResult.reason, {
957
+ facilitatorCode: settleResult.code
958
+ });
959
+ }
960
+ const verifyResult = await verifyExchange(
961
+ ctx.exchangeReader,
962
+ settleResult.exchangeId,
963
+ buildExpectedFromRequirements(input.requirements, expected.expectedState)
964
+ );
965
+ if (!verifyResult.ok) {
966
+ return handlerErr(
967
+ 502,
968
+ `STATE_VERIFY_${verifyResult.code}`,
969
+ "post-settle state verification failed",
970
+ {
971
+ exchangeId: settleResult.exchangeId,
972
+ txHash: settleResult.txHash,
973
+ field: verifyResult.field,
974
+ expected: verifyResult.expected,
975
+ got: verifyResult.got
976
+ }
977
+ );
978
+ }
979
+ if (expected.expectedState === x402Actions.ExchangeState.COMMITTED) {
980
+ ctx.exchangeFulfillmentOptionStore.set(
981
+ settleResult.exchangeId,
982
+ input.requirements.fulfillment?.options.map((option) => option.id) ?? []
983
+ );
984
+ }
985
+ const warnings = [];
986
+ if (expected.expectedState === x402Actions.ExchangeState.REDEEMED && decoded.payload.fulfillment !== void 0 && decoded.payload.fulfillment.data !== void 0) {
987
+ const pending = {
988
+ exchangeId: settleResult.exchangeId,
989
+ option: decoded.payload.fulfillment.option,
990
+ data: decoded.payload.fulfillment.data,
991
+ redeemer: decoded.payload.payload.buyer,
992
+ recordedAt: Date.now()
993
+ };
994
+ ctx.fulfillmentRecoveryStore.set(settleResult.exchangeId, pending);
995
+ const channel = channelById.get(decoded.payload.fulfillment.option);
996
+ if (channel === void 0) {
997
+ const reason = "no channel adapter is registered";
998
+ ctx.fulfillmentRecoveryStore.set(settleResult.exchangeId, {
999
+ ...pending,
1000
+ error: reason
1001
+ });
1002
+ warnings.push({
1003
+ code: "FULFILLMENT_COMMIT_DEFERRED",
1004
+ reason: "atomic redeem succeeded on-chain, but no channel adapter is registered",
1005
+ details: {
1006
+ exchangeId: settleResult.exchangeId,
1007
+ option: decoded.payload.fulfillment.option,
1008
+ error: reason
1009
+ }
1010
+ });
1011
+ } else {
1012
+ try {
1013
+ await channel.onCommit(settleResult.exchangeId, decoded.payload.fulfillment.data);
1014
+ ctx.fulfillmentRecoveryStore.delete(settleResult.exchangeId);
1015
+ } catch (e) {
1016
+ const reason = e instanceof Error ? e.message : String(e);
1017
+ ctx.fulfillmentRecoveryStore.set(settleResult.exchangeId, {
1018
+ ...pending,
1019
+ error: reason
1020
+ });
1021
+ warnings.push({
1022
+ code: "FULFILLMENT_COMMIT_DEFERRED",
1023
+ reason: "atomic redeem succeeded on-chain, but the channel adapter rejected the data",
1024
+ details: {
1025
+ exchangeId: settleResult.exchangeId,
1026
+ option: decoded.payload.fulfillment.option,
1027
+ error: reason
1028
+ }
1029
+ });
1030
+ }
1031
+ }
1032
+ }
1033
+ const nextActions = emitNextActions(
1034
+ {
1035
+ exchangeId: settleResult.exchangeId,
1036
+ exchangeState: expected.expectedState
1037
+ },
1038
+ ctx.config.channelRegistry,
1039
+ ctx.config.facilitator.url
1040
+ );
1041
+ return handlerOk({
1042
+ exchangeId: settleResult.exchangeId,
1043
+ txHash: settleResult.txHash,
1044
+ nextActions,
1045
+ ...warnings.length > 0 ? { warnings } : {}
1046
+ });
1047
+ }
1048
+ function buildExpectedFromRequirements(requirements, state) {
1049
+ return {
1050
+ state,
1051
+ seller: requirements.offer.creator,
1052
+ exchangeToken: requirements.asset,
1053
+ price: requirements.amount
1054
+ };
1055
+ }
1056
+ async function handlePerformAction(action, input, ctx) {
1057
+ const reference = await ctx.exchangeReader.read(input.exchangeId);
1058
+ if (reference === null) {
1059
+ return handlerErr(
1060
+ 502,
1061
+ "STATE_VERIFY_EXCHANGE_NOT_FOUND",
1062
+ "pre-action exchange reference could not be read",
1063
+ { action, exchangeId: input.exchangeId }
1064
+ );
1065
+ }
1066
+ let result;
1067
+ try {
1068
+ result = await ctx.facilitator.performAction({
1069
+ network: ctx.config.network,
1070
+ escrowAddress: ctx.config.escrow,
1071
+ exchangeId: input.exchangeId,
1072
+ action,
1073
+ signedPayload: input.signedPayload
1074
+ });
1075
+ } catch (e) {
1076
+ if (e instanceof FacilitatorHttpError) {
1077
+ return handlerErr(502, "FACILITATOR_UNREACHABLE", e.message, {
1078
+ code: e.code,
1079
+ status: e.status,
1080
+ facilitatorCode: e.facilitatorCode
1081
+ });
1082
+ }
1083
+ throw e;
1084
+ }
1085
+ if (!result.ok) {
1086
+ return handlerErr(502, "FACILITATOR_REJECTED", result.reason, {
1087
+ facilitatorCode: result.code
1088
+ });
1089
+ }
1090
+ const postState = stateMachine.ACTION_POST_STATE[action];
1091
+ const expected = {
1092
+ state: postState.exchange,
1093
+ ...postState.dispute !== void 0 ? { disputeState: postState.dispute } : {},
1094
+ seller: reference.seller,
1095
+ exchangeToken: reference.exchangeToken,
1096
+ price: reference.price
1097
+ };
1098
+ const verifyResult = await verifyExchange(ctx.exchangeReader, input.exchangeId, expected);
1099
+ if (!verifyResult.ok) {
1100
+ return handlerErr(
1101
+ 502,
1102
+ `STATE_VERIFY_${verifyResult.code}`,
1103
+ "post-action state verification failed",
1104
+ {
1105
+ action,
1106
+ exchangeId: input.exchangeId,
1107
+ txHash: result.txHash,
1108
+ field: verifyResult.field,
1109
+ expected: verifyResult.expected,
1110
+ got: verifyResult.got
1111
+ }
1112
+ );
1113
+ }
1114
+ const nextActions = postState.exchange === x402Actions.ExchangeState.DISPUTED && postState.dispute !== void 0 ? emitNextActions(
1115
+ {
1116
+ exchangeId: input.exchangeId,
1117
+ exchangeState: x402Actions.ExchangeState.DISPUTED,
1118
+ disputeState: postState.dispute
1119
+ },
1120
+ ctx.config.channelRegistry,
1121
+ ctx.config.facilitator.url
1122
+ ) : emitNextActions(
1123
+ {
1124
+ exchangeId: input.exchangeId,
1125
+ exchangeState: postState.exchange
1126
+ },
1127
+ ctx.config.channelRegistry,
1128
+ ctx.config.facilitator.url
1129
+ );
1130
+ return handlerOk({ txHash: result.txHash, nextActions });
1131
+ }
1132
+ async function handleRedeem(input, ctx) {
1133
+ let redeemer;
1134
+ try {
1135
+ redeemer = x402Evm.decodeSignedPayload(input.signedPayload).from;
1136
+ } catch (e) {
1137
+ return handlerErr(
1138
+ 400,
1139
+ "SIGNED_PAYLOAD_DECODE_FAILED",
1140
+ e instanceof Error ? e.message : "signedPayload could not be decoded"
1141
+ );
1142
+ }
1143
+ let resolvedChannel;
1144
+ if (input.fulfillment !== void 0) {
1145
+ const advertisedOptions = ctx.exchangeFulfillmentOptionStore.get(input.exchangeId);
1146
+ if (advertisedOptions !== void 0 && !advertisedOptions.includes(input.fulfillment.option)) {
1147
+ return handlerErr(
1148
+ 400,
1149
+ "FULFILLMENT_OPTION_NOT_ADVERTISED",
1150
+ `fulfillment.option '${input.fulfillment.option}' was not advertised for this exchange`,
1151
+ { option: input.fulfillment.option, advertised: advertisedOptions }
1152
+ );
1153
+ }
1154
+ const channels = ctx.config.fulfillmentChannels;
1155
+ if (channels === void 0) {
1156
+ return handlerErr(
1157
+ 400,
1158
+ "FULFILLMENT_CHANNELS_NOT_CONFIGURED",
1159
+ "server received redeem-time fulfillment data but has no fulfillmentChannels registered"
1160
+ );
1161
+ }
1162
+ const channel = channels.find((c) => c.id === input.fulfillment.option);
1163
+ if (channel === void 0) {
1164
+ return handlerErr(
1165
+ 400,
1166
+ "FULFILLMENT_OPTION_UNKNOWN",
1167
+ `fulfillment.option '${input.fulfillment.option}' is not registered with the server`,
1168
+ { option: input.fulfillment.option, registered: channels.map((c) => c.id) }
1169
+ );
1170
+ }
1171
+ let validation;
1172
+ try {
1173
+ validation = channel.validate(input.fulfillment.data);
1174
+ } catch (e) {
1175
+ return handlerErr(400, "FULFILLMENT_DATA_INVALID", errorMessage(e), {
1176
+ option: input.fulfillment.option
1177
+ });
1178
+ }
1179
+ if (!validation.ok) {
1180
+ return handlerErr(400, "FULFILLMENT_DATA_INVALID", validation.reason, {
1181
+ option: input.fulfillment.option
1182
+ });
1183
+ }
1184
+ resolvedChannel = channel;
1185
+ }
1186
+ const result = await handlePerformAction("boson-redeem", input, ctx);
1187
+ if (!result.ok) return result;
1188
+ let warning;
1189
+ if (resolvedChannel !== void 0 && input.fulfillment !== void 0) {
1190
+ const pending = {
1191
+ exchangeId: input.exchangeId,
1192
+ option: input.fulfillment.option,
1193
+ data: input.fulfillment.data,
1194
+ redeemer,
1195
+ recordedAt: Date.now()
1196
+ };
1197
+ ctx.fulfillmentRecoveryStore.set(input.exchangeId, pending);
1198
+ try {
1199
+ await resolvedChannel.onCommit(input.exchangeId, input.fulfillment.data);
1200
+ ctx.fulfillmentRecoveryStore.delete(input.exchangeId);
1201
+ } catch (e) {
1202
+ const reason = errorMessage(e);
1203
+ ctx.fulfillmentRecoveryStore.set(input.exchangeId, { ...pending, error: reason });
1204
+ warning = {
1205
+ code: "FULFILLMENT_UPDATE_DEFERRED",
1206
+ reason: "redeem succeeded on-chain, but the server could not persist the fulfillment update",
1207
+ details: {
1208
+ exchangeId: input.exchangeId,
1209
+ option: input.fulfillment.option,
1210
+ error: reason
1211
+ }
1212
+ };
1213
+ }
1214
+ }
1215
+ ctx.exchangeFulfillmentOptionStore.delete(input.exchangeId);
1216
+ if (warning !== void 0) {
1217
+ return {
1218
+ ...result,
1219
+ body: {
1220
+ ...result.body,
1221
+ warnings: [...result.body.warnings ?? [], warning]
1222
+ }
1223
+ };
1224
+ }
1225
+ return result;
1226
+ }
1227
+ function errorMessage(e) {
1228
+ return e instanceof Error ? e.message : String(e);
1229
+ }
1230
+ var handleComplete = (input, ctx) => handlePerformAction("boson-completeExchange", input, ctx);
1231
+ var handleDisputeRaise = (input, ctx) => handlePerformAction("boson-raiseDispute", input, ctx);
1232
+ var handleDisputeResolve = (input, ctx) => handlePerformAction("boson-resolveDispute", input, ctx);
1233
+ var handleDisputeRetract = (input, ctx) => handlePerformAction("boson-retractDispute", input, ctx);
1234
+ var handleDisputeEscalate = (input, ctx) => handlePerformAction("boson-escalateDispute", input, ctx);
1235
+ var DECIMAL_UINT_RE = escrow.DECIMAL_UINT;
1236
+ var ADDRESS_RE = escrow.ADDRESS;
1237
+ var HEX_BYTES_RE = /^0x([0-9a-fA-F]{2})*$/;
1238
+
1239
+ // src/handlers/resolve-entity.ts
1240
+ async function resolveEntityId(coreSdk, input) {
1241
+ const address = input.address.toLowerCase();
1242
+ let sellers = [];
1243
+ let buyers = [];
1244
+ try {
1245
+ [sellers, buyers] = await Promise.all([
1246
+ input.role === "buyer" ? Promise.resolve([]) : coreSdk.getSellersByAddress(address),
1247
+ input.role === "seller" ? Promise.resolve([]) : coreSdk.getBuyers({ buyersFilter: { wallet: address } })
1248
+ ]);
1249
+ } catch (e) {
1250
+ return {
1251
+ ok: false,
1252
+ code: "SUBGRAPH_FAILURE",
1253
+ reason: e instanceof Error ? e.message : "subgraph lookup failed"
1254
+ };
1255
+ }
1256
+ const sellerIds = sellers.map((s) => s.id);
1257
+ const buyerIds = buyers.map((b) => b.id);
1258
+ if (input.role === "seller") {
1259
+ if (sellerIds.length === 0) {
1260
+ return {
1261
+ ok: false,
1262
+ code: "NOT_FOUND",
1263
+ reason: `no seller entity found for address ${address}`
1264
+ };
1265
+ }
1266
+ if (sellerIds.length > 1) {
1267
+ return {
1268
+ ok: false,
1269
+ code: "AMBIGUOUS",
1270
+ reason: `address ${address} resolves to multiple seller entities (ids ${sellerIds.join(", ")}); pass entityId to disambiguate`,
1271
+ sellerIds
1272
+ };
1273
+ }
1274
+ return { ok: true, entityId: sellerIds[0], role: "seller" };
1275
+ }
1276
+ if (input.role === "buyer") {
1277
+ if (buyerIds.length === 0) {
1278
+ return {
1279
+ ok: false,
1280
+ code: "NOT_FOUND",
1281
+ reason: `no buyer entity found for address ${address}`
1282
+ };
1283
+ }
1284
+ if (buyerIds.length > 1) {
1285
+ return {
1286
+ ok: false,
1287
+ code: "AMBIGUOUS",
1288
+ reason: `address ${address} resolves to multiple buyer entities (ids ${buyerIds.join(", ")}); pass entityId to disambiguate`,
1289
+ buyerIds
1290
+ };
1291
+ }
1292
+ return { ok: true, entityId: buyerIds[0], role: "buyer" };
1293
+ }
1294
+ const totalMatches = sellerIds.length + buyerIds.length;
1295
+ if (totalMatches === 0) {
1296
+ return {
1297
+ ok: false,
1298
+ code: "NOT_FOUND",
1299
+ reason: `no seller or buyer entity found for address ${address}`
1300
+ };
1301
+ }
1302
+ if (totalMatches > 1) {
1303
+ return {
1304
+ ok: false,
1305
+ code: "AMBIGUOUS",
1306
+ reason: `address ${address} resolves to ${describeMatches(sellerIds, buyerIds)}; pass role and/or entityId to disambiguate`,
1307
+ ...sellerIds.length > 0 ? { sellerIds } : {},
1308
+ ...buyerIds.length > 0 ? { buyerIds } : {}
1309
+ };
1310
+ }
1311
+ if (sellerIds.length === 1) return { ok: true, entityId: sellerIds[0], role: "seller" };
1312
+ return { ok: true, entityId: buyerIds[0], role: "buyer" };
1313
+ }
1314
+ function describeMatches(sellerIds, buyerIds) {
1315
+ const parts = [];
1316
+ if (sellerIds.length > 0) {
1317
+ parts.push(
1318
+ sellerIds.length === 1 ? `seller (id ${sellerIds[0]})` : `${sellerIds.length} sellers (ids ${sellerIds.join(", ")})`
1319
+ );
1320
+ }
1321
+ if (buyerIds.length > 0) {
1322
+ parts.push(
1323
+ buyerIds.length === 1 ? `buyer (id ${buyerIds[0]})` : `${buyerIds.length} buyers (ids ${buyerIds.join(", ")})`
1324
+ );
1325
+ }
1326
+ return parts.join(" and ");
1327
+ }
1328
+
1329
+ // src/handlers/withdraw-funds.ts
1330
+ async function handleWithdrawFunds(input, ctx) {
1331
+ let entityId;
1332
+ let role;
1333
+ if ("entityId" in input) {
1334
+ if (!DECIMAL_UINT_RE.test(input.entityId)) {
1335
+ return handlerErr(
1336
+ 400,
1337
+ "INVALID_ENTITY_ID",
1338
+ `entityId must be a decimal uint256 string, got "${input.entityId}"`
1339
+ );
1340
+ }
1341
+ entityId = input.entityId;
1342
+ } else {
1343
+ if (!ADDRESS_RE.test(input.address)) {
1344
+ return handlerErr(
1345
+ 400,
1346
+ "INVALID_ADDRESS",
1347
+ `address must be a 20-byte 0x-prefixed hex string, got "${input.address}"`
1348
+ );
1349
+ }
1350
+ const resolved = await resolveEntityId(ctx.coreSdkRead, {
1351
+ address: input.address,
1352
+ ...input.role !== void 0 ? { role: input.role } : {}
1353
+ });
1354
+ if (!resolved.ok) {
1355
+ const status = resolved.code === "NOT_FOUND" ? 404 : resolved.code === "AMBIGUOUS" ? 409 : 502;
1356
+ const details = resolved.code === "AMBIGUOUS" ? {
1357
+ ...resolved.sellerIds !== void 0 ? { sellerIds: resolved.sellerIds } : {},
1358
+ ...resolved.buyerIds !== void 0 ? { buyerIds: resolved.buyerIds } : {}
1359
+ } : void 0;
1360
+ return handlerErr(status, resolved.code, resolved.reason, details);
1361
+ }
1362
+ entityId = resolved.entityId;
1363
+ role = resolved.role;
1364
+ }
1365
+ let result;
1366
+ try {
1367
+ result = await ctx.facilitator.performAction({
1368
+ network: ctx.config.network,
1369
+ escrowAddress: ctx.config.escrow,
1370
+ entityId,
1371
+ action: "boson-withdrawFunds",
1372
+ signedPayload: input.signedPayload
1373
+ });
1374
+ } catch (e) {
1375
+ if (e instanceof FacilitatorHttpError) {
1376
+ return handlerErr(502, "FACILITATOR_UNREACHABLE", e.message, {
1377
+ code: e.code,
1378
+ status: e.status,
1379
+ facilitatorCode: e.facilitatorCode
1380
+ });
1381
+ }
1382
+ throw e;
1383
+ }
1384
+ if (!result.ok) {
1385
+ return handlerErr(502, "FACILITATOR_REJECTED", result.reason, {
1386
+ facilitatorCode: result.code
1387
+ });
1388
+ }
1389
+ return plainHandlerOk({
1390
+ txHash: result.txHash,
1391
+ entityId,
1392
+ ...role !== void 0 ? { role } : {}
1393
+ });
1394
+ }
1395
+
1396
+ // src/handlers/available-funds.ts
1397
+ async function handleGetAvailableFunds(query, ctx) {
1398
+ let entityId;
1399
+ let role;
1400
+ if ("entityId" in query) {
1401
+ if (!DECIMAL_UINT_RE.test(query.entityId)) {
1402
+ return handlerErr(
1403
+ 400,
1404
+ "INVALID_ENTITY_ID",
1405
+ `entityId must be a decimal uint256 string, got "${query.entityId}"`
1406
+ );
1407
+ }
1408
+ entityId = query.entityId;
1409
+ } else {
1410
+ if (!ADDRESS_RE.test(query.address)) {
1411
+ return handlerErr(
1412
+ 400,
1413
+ "INVALID_ADDRESS",
1414
+ `address must be a 20-byte 0x-prefixed hex string, got "${query.address}"`
1415
+ );
1416
+ }
1417
+ const resolved = await resolveEntityId(ctx.coreSdkRead, {
1418
+ address: query.address,
1419
+ ...query.role !== void 0 ? { role: query.role } : {}
1420
+ });
1421
+ if (!resolved.ok) {
1422
+ const status = resolved.code === "NOT_FOUND" ? 404 : resolved.code === "AMBIGUOUS" ? 409 : 502;
1423
+ return handlerErr(status, resolved.code, resolved.reason, omitErrorMetadata(resolved));
1424
+ }
1425
+ entityId = resolved.entityId;
1426
+ role = resolved.role;
1427
+ }
1428
+ let raw;
1429
+ try {
1430
+ raw = await ctx.coreSdkRead.getFunds({ fundsFilter: { accountId: entityId } });
1431
+ } catch (e) {
1432
+ return handlerErr(
1433
+ 502,
1434
+ "SUBGRAPH_FAILURE",
1435
+ e instanceof Error ? e.message : "subgraph getFunds lookup failed"
1436
+ );
1437
+ }
1438
+ const funds = raw.map((entry) => ({
1439
+ tokenAddress: entry.token.address,
1440
+ tokenSymbol: entry.token.symbol,
1441
+ tokenName: entry.token.name,
1442
+ decimals: Number(entry.token.decimals),
1443
+ availableAmount: entry.availableAmount
1444
+ }));
1445
+ return plainHandlerOk({
1446
+ entityId,
1447
+ ...role !== void 0 ? { role } : {},
1448
+ funds
1449
+ });
1450
+ }
1451
+ function omitErrorMetadata(resolved) {
1452
+ if (resolved.code !== "AMBIGUOUS") return void 0;
1453
+ const details = {};
1454
+ if (resolved.sellerIds !== void 0) details.sellerIds = resolved.sellerIds;
1455
+ if (resolved.buyerIds !== void 0) details.buyerIds = resolved.buyerIds;
1456
+ return Object.keys(details).length > 0 ? details : void 0;
1457
+ }
1458
+
1459
+ // src/onchain/core-sdk-read.ts
1460
+ function asCoreSdkReadAdapter(coreSdk) {
1461
+ return coreSdk;
1462
+ }
1463
+
1464
+ // src/server.ts
1465
+ function withFacilitatorEndpoints(requirements, facilitatorUrl) {
1466
+ return {
1467
+ ...requirements,
1468
+ actions: {
1469
+ ...requirements.actions,
1470
+ next: stampFacilitatorEndpoints(requirements.actions.next, facilitatorUrl)
1471
+ }
1472
+ };
1473
+ }
1474
+ function createX402bServer(config) {
1475
+ const validated = x402bServerConfigSchema.parse(config);
1476
+ assertChannelRegistryEscrowMatch(validated);
1477
+ const facilitator = createFacilitatorClient({ url: validated.facilitator.url });
1478
+ const exchangeFulfillmentOptionStore = validated.exchangeFulfillmentOptionStore ?? /* @__PURE__ */ new Map();
1479
+ const fulfillmentRecoveryStore = validated.fulfillmentRecoveryStore ?? /* @__PURE__ */ new Map();
1480
+ validated.exchangeFulfillmentOptionStore = exchangeFulfillmentOptionStore;
1481
+ validated.fulfillmentRecoveryStore = fulfillmentRecoveryStore;
1482
+ const signOffer = (unsigned) => signFullOffer({
1483
+ fullOffer: unsigned,
1484
+ signer: validated.signer,
1485
+ escrow: validated.escrow,
1486
+ chainId: validated.chainId
1487
+ });
1488
+ const requireReader = async (action) => {
1489
+ if (validated.exchangeReader === void 0) {
1490
+ throw new Error(
1491
+ `x402-server: handlers.${action}() requires \`exchangeReader\` in config (post-settle state verification step).`
1492
+ );
1493
+ }
1494
+ return validated.exchangeReader;
1495
+ };
1496
+ let cachedCoreSdkRead;
1497
+ const requireCoreSdkRead = (action) => {
1498
+ if (validated.coreSdkRead !== void 0) return validated.coreSdkRead;
1499
+ if (cachedCoreSdkRead !== void 0) return cachedCoreSdkRead;
1500
+ if (validated.subgraphUrl === void 0) {
1501
+ throw new Error(
1502
+ `x402-server: handlers.${action}() requires either \`coreSdkRead\` or \`subgraphUrl\` in config (subgraph read step).`
1503
+ );
1504
+ }
1505
+ cachedCoreSdkRead = asCoreSdkReadAdapter(
1506
+ new coreSdk.CoreSDK({
1507
+ web3Lib: createReadOnlyWeb3LibStub(),
1508
+ subgraphUrl: validated.subgraphUrl,
1509
+ protocolDiamond: validated.escrow,
1510
+ chainId: validated.chainId
1511
+ })
1512
+ );
1513
+ return cachedCoreSdkRead;
1514
+ };
1515
+ return {
1516
+ config: validated,
1517
+ facilitator,
1518
+ signOffer,
1519
+ async buildPaymentRequirements(input) {
1520
+ const offer = "unsigned" in input.offer ? await signOffer(input.offer.unsigned) : input.offer;
1521
+ const requirements = buildPaymentRequirements({
1522
+ offer,
1523
+ asset: input.offer && "unsigned" in input.offer ? input.asset : input.asset,
1524
+ amount: input.amount,
1525
+ tokenAuthStrategies: input.tokenAuthStrategies,
1526
+ recipientId: input.recipientId,
1527
+ maxTimeoutSeconds: input.maxTimeoutSeconds,
1528
+ ...input.fulfillment !== void 0 ? { fulfillment: input.fulfillment } : {},
1529
+ network: validated.network,
1530
+ escrow: validated.escrow,
1531
+ channelRegistry: validated.channelRegistry
1532
+ });
1533
+ return withFacilitatorEndpoints(requirements, validated.facilitator.url);
1534
+ },
1535
+ handlers: {
1536
+ commit: async (input) => handleCommit(input, {
1537
+ config: validated,
1538
+ facilitator,
1539
+ exchangeReader: await requireReader("commit"),
1540
+ fulfillmentRecoveryStore,
1541
+ exchangeFulfillmentOptionStore
1542
+ }),
1543
+ commitAndRedeem: async (input) => handleCommitAndRedeem(input, {
1544
+ config: validated,
1545
+ facilitator,
1546
+ exchangeReader: await requireReader("commitAndRedeem"),
1547
+ fulfillmentRecoveryStore,
1548
+ exchangeFulfillmentOptionStore
1549
+ }),
1550
+ redeem: async (input) => handleRedeem(input, {
1551
+ config: validated,
1552
+ facilitator,
1553
+ exchangeReader: await requireReader("redeem"),
1554
+ exchangeFulfillmentOptionStore,
1555
+ fulfillmentRecoveryStore
1556
+ }),
1557
+ complete: async (input) => handleComplete(input, {
1558
+ config: validated,
1559
+ facilitator,
1560
+ exchangeReader: await requireReader("complete")
1561
+ }),
1562
+ disputeRaise: async (input) => handleDisputeRaise(input, {
1563
+ config: validated,
1564
+ facilitator,
1565
+ exchangeReader: await requireReader("disputeRaise")
1566
+ }),
1567
+ disputeResolve: async (input) => handleDisputeResolve(input, {
1568
+ config: validated,
1569
+ facilitator,
1570
+ exchangeReader: await requireReader("disputeResolve")
1571
+ }),
1572
+ disputeRetract: async (input) => handleDisputeRetract(input, {
1573
+ config: validated,
1574
+ facilitator,
1575
+ exchangeReader: await requireReader("disputeRetract")
1576
+ }),
1577
+ disputeEscalate: async (input) => handleDisputeEscalate(input, {
1578
+ config: validated,
1579
+ facilitator,
1580
+ exchangeReader: await requireReader("disputeEscalate")
1581
+ }),
1582
+ withdrawFunds: async (input) => handleWithdrawFunds(input, {
1583
+ config: validated,
1584
+ facilitator,
1585
+ coreSdkRead: requireCoreSdkRead("withdrawFunds")
1586
+ }),
1587
+ getAvailableFunds: async (query) => handleGetAvailableFunds(query, {
1588
+ coreSdkRead: requireCoreSdkRead("getAvailableFunds")
1589
+ })
1590
+ }
1591
+ };
1592
+ }
1593
+
1594
+ // src/internal/x-payment-response.ts
1595
+ function encodeXPaymentResponse(body) {
1596
+ const json = JSON.stringify(body);
1597
+ if (typeof Buffer !== "undefined") {
1598
+ return Buffer.from(json, "utf8").toString("base64");
1599
+ }
1600
+ const bytes = new TextEncoder().encode(json);
1601
+ let binary = "";
1602
+ for (let i = 0; i < bytes.length; i++) {
1603
+ binary += String.fromCharCode(bytes[i]);
1604
+ }
1605
+ return btoa(binary);
1606
+ }
1607
+ var X_PAYMENT_RESPONSE_HEADER = "X-PAYMENT-RESPONSE";
1608
+
1609
+ exports.ADDRESS_RE = ADDRESS_RE;
1610
+ exports.DECIMAL_UINT_RE = DECIMAL_UINT_RE;
1611
+ exports.FacilitatorHttpError = FacilitatorHttpError;
1612
+ exports.HEX_BYTES_RE = HEX_BYTES_RE;
1613
+ exports.X_PAYMENT_RESPONSE_HEADER = X_PAYMENT_RESPONSE_HEADER;
1614
+ exports.asCoreSdkReadAdapter = asCoreSdkReadAdapter;
1615
+ exports.assertChannelRegistryEscrowMatch = assertChannelRegistryEscrowMatch;
1616
+ exports.buildPaymentRequirements = buildPaymentRequirements;
1617
+ exports.createFacilitatorClient = createFacilitatorClient;
1618
+ exports.createX402bServer = createX402bServer;
1619
+ exports.decodeXPaymentHeader = decodeXPaymentHeader;
1620
+ exports.emitNextActions = emitNextActions;
1621
+ exports.encodeXPaymentResponse = encodeXPaymentResponse;
1622
+ exports.handleCommit = handleCommit;
1623
+ exports.handleCommitAndRedeem = handleCommitAndRedeem;
1624
+ exports.handleComplete = handleComplete;
1625
+ exports.handleDisputeEscalate = handleDisputeEscalate;
1626
+ exports.handleDisputeRaise = handleDisputeRaise;
1627
+ exports.handleDisputeResolve = handleDisputeResolve;
1628
+ exports.handleDisputeRetract = handleDisputeRetract;
1629
+ exports.handleGetAvailableFunds = handleGetAvailableFunds;
1630
+ exports.handlePerformAction = handlePerformAction;
1631
+ exports.handleRedeem = handleRedeem;
1632
+ exports.handleWithdrawFunds = handleWithdrawFunds;
1633
+ exports.handlerErr = handlerErr;
1634
+ exports.handlerOk = handlerOk;
1635
+ exports.plainHandlerOk = plainHandlerOk;
1636
+ exports.resolveEntityId = resolveEntityId;
1637
+ exports.signFullOffer = signFullOffer;
1638
+ exports.validatePaymentPayload = validatePaymentPayload;
1639
+ exports.verifyExchange = verifyExchange;
1640
+ exports.verifyExchangeSnapshot = verifyExchangeSnapshot;
1641
+ exports.x402bServerConfigSchema = x402bServerConfigSchema;
1642
+ //# sourceMappingURL=index.js.map
1643
+ //# sourceMappingURL=index.js.map