x402z-facilitator 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,633 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/service/bootstrap.ts
9
+ import { x402Facilitator } from "@x402/core/facilitator";
10
+ import { toFacilitatorEvmSigner } from "@x402/evm";
11
+ import { createWalletClient, http, publicActions } from "viem";
12
+ import { privateKeyToAccount } from "viem/accounts";
13
+
14
+ // src/service/service.ts
15
+ import { createServer } from "http";
16
+ async function readJson(req) {
17
+ const chunks = [];
18
+ for await (const chunk of req) {
19
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
20
+ }
21
+ const body = Buffer.concat(chunks).toString("utf8");
22
+ return JSON.parse(body);
23
+ }
24
+ function sendJson(res, status, payload) {
25
+ res.writeHead(status, { "content-type": "application/json" });
26
+ res.end(JSON.stringify(payload));
27
+ }
28
+ function createFacilitatorService(config) {
29
+ const server = createServer(async (req, res) => {
30
+ try {
31
+ const method = req.method ?? "GET";
32
+ const url = req.url ?? "/";
33
+ if (process.env.X402Z_DEBUG === "1") {
34
+ console.debug(`[x402z-facilitator] ${method} ${url}`);
35
+ }
36
+ if (!req.url) {
37
+ sendJson(res, 404, { error: "not_found" });
38
+ return;
39
+ }
40
+ if (req.method === "GET" && req.url === "/supported") {
41
+ sendJson(res, 200, config.facilitator.getSupported());
42
+ return;
43
+ }
44
+ if (req.method === "POST" && req.url === "/verify") {
45
+ const body = await readJson(req);
46
+ const result = await config.facilitator.verify(body.paymentPayload, body.paymentRequirements);
47
+ sendJson(res, 200, result);
48
+ return;
49
+ }
50
+ if (req.method === "POST" && req.url === "/settle") {
51
+ const body = await readJson(req);
52
+ const result = await config.facilitator.settle(body.paymentPayload, body.paymentRequirements);
53
+ sendJson(res, 200, result);
54
+ return;
55
+ }
56
+ sendJson(res, 404, { error: "not_found" });
57
+ } catch (error) {
58
+ const message = error instanceof Error ? error.message : "internal_error";
59
+ sendJson(res, 500, { error: message });
60
+ }
61
+ });
62
+ return server;
63
+ }
64
+ function startFacilitatorService(config) {
65
+ const port = config.port ?? 8040;
66
+ const server = createFacilitatorService(config);
67
+ server.listen(port);
68
+ return { port };
69
+ }
70
+
71
+ // src/scheme/scheme.ts
72
+ import { decodeEventLog, getAddress, isAddressEqual } from "viem";
73
+ import {
74
+ confidentialPaymentTypes,
75
+ confidentialTokenAbi,
76
+ hashEncryptedAmountInput
77
+ } from "x402z-shared";
78
+ var batcherAbi = [
79
+ {
80
+ inputs: [
81
+ { internalType: "address", name: "token", type: "address" },
82
+ {
83
+ components: [
84
+ {
85
+ components: [
86
+ { internalType: "address", name: "holder", type: "address" },
87
+ { internalType: "address", name: "payee", type: "address" },
88
+ { internalType: "uint256", name: "maxClearAmount", type: "uint256" },
89
+ { internalType: "bytes32", name: "resourceHash", type: "bytes32" },
90
+ { internalType: "uint48", name: "validAfter", type: "uint48" },
91
+ { internalType: "uint48", name: "validBefore", type: "uint48" },
92
+ { internalType: "bytes32", name: "nonce", type: "bytes32" },
93
+ { internalType: "bytes32", name: "encryptedAmountHash", type: "bytes32" }
94
+ ],
95
+ internalType: "struct IFHEToken.ConfidentialPayment",
96
+ name: "p",
97
+ type: "tuple"
98
+ },
99
+ { internalType: "externalEuint64", name: "encryptedAmountInput", type: "bytes32" },
100
+ { internalType: "bytes", name: "inputProof", type: "bytes" },
101
+ { internalType: "bytes", name: "sig", type: "bytes" }
102
+ ],
103
+ internalType: "struct FHETokenBatcher.Request[]",
104
+ name: "requests",
105
+ type: "tuple[]"
106
+ }
107
+ ],
108
+ name: "batchConfidentialTransferWithAuthorization",
109
+ outputs: [
110
+ { internalType: "bool[]", name: "successes", type: "bool[]" },
111
+ { internalType: "bytes32[]", name: "transferredHandles", type: "bytes32[]" }
112
+ ],
113
+ stateMutability: "nonpayable",
114
+ type: "function"
115
+ },
116
+ {
117
+ anonymous: false,
118
+ inputs: [
119
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
120
+ { indexed: false, internalType: "bytes32", name: "transferredHandle", type: "bytes32" }
121
+ ],
122
+ name: "BatchItemSuccess",
123
+ type: "event"
124
+ },
125
+ {
126
+ anonymous: false,
127
+ inputs: [
128
+ { indexed: true, internalType: "uint256", name: "index", type: "uint256" },
129
+ { indexed: false, internalType: "bytes", name: "reason", type: "bytes" }
130
+ ],
131
+ name: "BatchItemFailure",
132
+ type: "event"
133
+ }
134
+ ];
135
+ var X402zEvmFacilitator = class {
136
+ constructor(config) {
137
+ this.config = config;
138
+ this.scheme = "erc7984-mind-v1";
139
+ this.caipFamily = "eip155:*";
140
+ this.queue = [];
141
+ this.hashFn = config.hashEncryptedAmountInput ?? hashEncryptedAmountInput;
142
+ this.clock = config.clock ?? (() => Math.floor(Date.now() / 1e3));
143
+ this.checkUsedNonces = config.checkUsedNonces ?? true;
144
+ this.waitForReceipt = config.waitForReceipt ?? true;
145
+ this.batchIntervalMs = Math.max(0, config.batchIntervalMs ?? 15e3);
146
+ this.receiptOptions = config.receipt;
147
+ this.batcherAddress = getAddress(config.batcherAddress);
148
+ }
149
+ getExtra(_) {
150
+ return void 0;
151
+ }
152
+ getSigners(_) {
153
+ return [...this.config.signer.getAddresses()];
154
+ }
155
+ async verify(payload, requirements) {
156
+ const confidentialPayload = payload.payload;
157
+ if (payload.accepted.scheme !== this.scheme || requirements.scheme !== this.scheme) {
158
+ return {
159
+ isValid: false,
160
+ invalidReason: "unsupported_scheme",
161
+ payer: confidentialPayload?.authorization?.holder
162
+ };
163
+ }
164
+ if (payload.accepted.network !== requirements.network) {
165
+ return {
166
+ isValid: false,
167
+ invalidReason: "network_mismatch",
168
+ payer: confidentialPayload.authorization.holder
169
+ };
170
+ }
171
+ const extra = requirements.extra;
172
+ const eip712 = extra?.eip712;
173
+ if (!eip712?.name || !eip712?.version) {
174
+ return {
175
+ isValid: false,
176
+ invalidReason: "missing_eip712_domain",
177
+ payer: confidentialPayload.authorization.holder
178
+ };
179
+ }
180
+ const now = this.clock();
181
+ const validAfter = Number(confidentialPayload.authorization.validAfter);
182
+ const validBefore = Number(confidentialPayload.authorization.validBefore);
183
+ if (Number.isNaN(validAfter) || Number.isNaN(validBefore)) {
184
+ return {
185
+ isValid: false,
186
+ invalidReason: "invalid_validity_window",
187
+ payer: confidentialPayload.authorization.holder
188
+ };
189
+ }
190
+ if (now < validAfter || now > validBefore) {
191
+ return {
192
+ isValid: false,
193
+ invalidReason: "authorization_expired",
194
+ payer: confidentialPayload.authorization.holder
195
+ };
196
+ }
197
+ if (!isAddressEqual(getAddress(confidentialPayload.authorization.payee), getAddress(requirements.payTo))) {
198
+ return {
199
+ isValid: false,
200
+ invalidReason: "recipient_mismatch",
201
+ payer: confidentialPayload.authorization.holder
202
+ };
203
+ }
204
+ const computedHash = this.hashFn(confidentialPayload.encryptedAmountInput);
205
+ if (computedHash !== confidentialPayload.authorization.encryptedAmountHash) {
206
+ return {
207
+ isValid: false,
208
+ invalidReason: "encrypted_amount_mismatch",
209
+ payer: confidentialPayload.authorization.holder
210
+ };
211
+ }
212
+ const chainId = parseInt(requirements.network.split(":")[1]);
213
+ const isValidSignature = await this.config.signer.verifyTypedData({
214
+ address: confidentialPayload.authorization.holder,
215
+ domain: {
216
+ name: eip712.name,
217
+ version: eip712.version,
218
+ chainId,
219
+ verifyingContract: getAddress(requirements.asset)
220
+ },
221
+ types: confidentialPaymentTypes,
222
+ primaryType: "ConfidentialPayment",
223
+ message: {
224
+ holder: getAddress(confidentialPayload.authorization.holder),
225
+ payee: getAddress(confidentialPayload.authorization.payee),
226
+ maxClearAmount: BigInt(confidentialPayload.authorization.maxClearAmount),
227
+ resourceHash: confidentialPayload.authorization.resourceHash,
228
+ validAfter: BigInt(confidentialPayload.authorization.validAfter),
229
+ validBefore: BigInt(confidentialPayload.authorization.validBefore),
230
+ nonce: confidentialPayload.authorization.nonce,
231
+ encryptedAmountHash: confidentialPayload.authorization.encryptedAmountHash
232
+ },
233
+ signature: confidentialPayload.signature
234
+ });
235
+ if (!isValidSignature) {
236
+ return {
237
+ isValid: false,
238
+ invalidReason: "invalid_signature",
239
+ payer: confidentialPayload.authorization.holder
240
+ };
241
+ }
242
+ if (this.checkUsedNonces) {
243
+ const used = await this.config.signer.readContract({
244
+ address: getAddress(requirements.asset),
245
+ abi: confidentialTokenAbi,
246
+ functionName: "usedNonces",
247
+ args: [confidentialPayload.authorization.holder, confidentialPayload.authorization.nonce]
248
+ });
249
+ if (used) {
250
+ return {
251
+ isValid: false,
252
+ invalidReason: "nonce_already_used",
253
+ payer: confidentialPayload.authorization.holder
254
+ };
255
+ }
256
+ }
257
+ return {
258
+ isValid: true,
259
+ payer: confidentialPayload.authorization.holder
260
+ };
261
+ }
262
+ async settle(payload, requirements) {
263
+ const valid = await this.verify(payload, requirements);
264
+ const confidentialPayload = payload.payload;
265
+ if (!valid.isValid) {
266
+ return {
267
+ success: false,
268
+ errorReason: valid.invalidReason ?? "invalid_payment",
269
+ payer: confidentialPayload.authorization.holder,
270
+ transaction: "",
271
+ network: requirements.network
272
+ };
273
+ }
274
+ return new Promise((resolve) => {
275
+ this.queue.push({ payload, requirements, resolve });
276
+ this.scheduleFlush();
277
+ });
278
+ }
279
+ scheduleFlush() {
280
+ if (this.flushTimer) {
281
+ return;
282
+ }
283
+ const delay = this.batchIntervalMs;
284
+ this.flushTimer = setTimeout(() => {
285
+ this.flushTimer = void 0;
286
+ void this.flushQueue();
287
+ }, delay);
288
+ }
289
+ async flushQueue() {
290
+ if (this.queue.length === 0) {
291
+ return;
292
+ }
293
+ const queued = this.queue;
294
+ this.queue = [];
295
+ const byToken = /* @__PURE__ */ new Map();
296
+ for (const entry of queued) {
297
+ const tokenKey = getAddress(entry.requirements.asset);
298
+ const group = byToken.get(tokenKey) ?? [];
299
+ group.push(entry);
300
+ byToken.set(tokenKey, group);
301
+ }
302
+ for (const [tokenAddress, entries] of byToken.entries()) {
303
+ await this.flushBatch(tokenAddress, entries);
304
+ }
305
+ if (this.queue.length > 0) {
306
+ this.scheduleFlush();
307
+ }
308
+ }
309
+ async flushBatch(tokenAddress, entries) {
310
+ const buildRequests = (batchEntries2) => batchEntries2.map(({ entry }) => {
311
+ const confidentialPayload = entry.payload.payload;
312
+ return {
313
+ p: confidentialPayload.authorization,
314
+ encryptedAmountInput: confidentialPayload.encryptedAmountInput,
315
+ inputProof: confidentialPayload.inputProof,
316
+ sig: confidentialPayload.signature
317
+ };
318
+ });
319
+ const originalEntries = entries.map((entry, index) => ({ entry, index }));
320
+ let batchEntries = originalEntries;
321
+ let requests = buildRequests(batchEntries);
322
+ let txRequest = {
323
+ address: this.batcherAddress,
324
+ abi: batcherAbi,
325
+ functionName: "batchConfidentialTransferWithAuthorization",
326
+ args: [tokenAddress, requests]
327
+ };
328
+ if (process.env.X402Z_DEBUG === "1") {
329
+ console.debug("[x402z-facilitator] settle tx", {
330
+ batcherAddress: this.batcherAddress,
331
+ tokenAddress,
332
+ functionName: txRequest.functionName,
333
+ to: txRequest.address,
334
+ size: requests.length
335
+ });
336
+ }
337
+ try {
338
+ const [successes, transferredHandles] = await this.config.signer.simulateContract(txRequest);
339
+ if (successes.length === batchEntries.length && transferredHandles.length === batchEntries.length) {
340
+ const filtered = [];
341
+ batchEntries.forEach((item, index) => {
342
+ if (successes[index]) {
343
+ filtered.push(item);
344
+ return;
345
+ }
346
+ const confidentialPayload = item.entry.payload.payload;
347
+ item.entry.resolve({
348
+ success: false,
349
+ errorReason: "preflight_failed",
350
+ payer: confidentialPayload.authorization.holder,
351
+ transaction: "",
352
+ network: item.entry.requirements.network,
353
+ batch: { index: item.index, success: false, transferredHandle: transferredHandles[index] }
354
+ });
355
+ });
356
+ if (filtered.length === 0) {
357
+ return;
358
+ }
359
+ batchEntries = filtered;
360
+ requests = buildRequests(batchEntries);
361
+ txRequest = {
362
+ ...txRequest,
363
+ args: [tokenAddress, requests]
364
+ };
365
+ }
366
+ } catch (error) {
367
+ if (process.env.X402Z_DEBUG === "1") {
368
+ console.error("[x402z-facilitator] settle tx error", error);
369
+ }
370
+ for (const entry of entries) {
371
+ const confidentialPayload = entry.payload.payload;
372
+ entry.resolve({
373
+ success: false,
374
+ errorReason: "preflight_failed",
375
+ payer: confidentialPayload.authorization.holder,
376
+ transaction: "",
377
+ network: entry.requirements.network
378
+ });
379
+ }
380
+ return;
381
+ }
382
+ const settleEntries = batchEntries.map((item) => item.entry);
383
+ let txHash;
384
+ try {
385
+ txHash = await this.config.signer.writeContract(txRequest);
386
+ } catch (error) {
387
+ for (const entry of settleEntries) {
388
+ const confidentialPayload = entry.payload.payload;
389
+ entry.resolve({
390
+ success: false,
391
+ errorReason: "settlement_failed",
392
+ payer: confidentialPayload.authorization.holder,
393
+ transaction: "",
394
+ network: entry.requirements.network
395
+ });
396
+ }
397
+ return;
398
+ }
399
+ if (process.env.X402Z_DEBUG === "1") {
400
+ console.debug("[x402z-facilitator] tx submitted", txHash);
401
+ }
402
+ let receipt;
403
+ if (this.waitForReceipt) {
404
+ receipt = await this.config.signer.waitForTransactionReceipt({ hash: txHash });
405
+ if (process.env.X402Z_DEBUG === "1") {
406
+ console.debug("[x402z-facilitator] tx receipt", receipt);
407
+ }
408
+ if (receipt.status !== "success") {
409
+ for (const entry of settleEntries) {
410
+ const confidentialPayload = entry.payload.payload;
411
+ entry.resolve({
412
+ success: false,
413
+ errorReason: "settlement_failed",
414
+ payer: confidentialPayload.authorization.holder,
415
+ transaction: txHash,
416
+ network: entry.requirements.network
417
+ });
418
+ }
419
+ return;
420
+ }
421
+ }
422
+ if (!this.waitForReceipt) {
423
+ settleEntries.forEach((entry) => {
424
+ const confidentialPayload = entry.payload.payload;
425
+ entry.resolve({
426
+ success: true,
427
+ payer: confidentialPayload.authorization.holder,
428
+ transaction: txHash,
429
+ network: entry.requirements.network
430
+ });
431
+ });
432
+ return;
433
+ }
434
+ const batchResults = /* @__PURE__ */ new Map();
435
+ if (receipt?.logs) {
436
+ for (const log of receipt.logs) {
437
+ if (!log?.address) {
438
+ continue;
439
+ }
440
+ if (!isAddressEqual(getAddress(log.address), this.batcherAddress)) {
441
+ continue;
442
+ }
443
+ const decoded = decodeEventLog({
444
+ abi: batcherAbi,
445
+ data: log.data,
446
+ topics: log.topics
447
+ });
448
+ if (process.env.X402Z_DEBUG === "1") {
449
+ console.debug("[x402z-facilitator] batch log", decoded);
450
+ }
451
+ if (decoded.eventName === "BatchItemSuccess") {
452
+ const args = decoded.args;
453
+ batchResults.set(Number(args.index), {
454
+ success: true,
455
+ transferredHandle: args.transferredHandle
456
+ });
457
+ } else if (decoded.eventName === "BatchItemFailure") {
458
+ const args = decoded.args;
459
+ batchResults.set(Number(args.index), {
460
+ success: false,
461
+ failureReason: args.reason
462
+ });
463
+ }
464
+ }
465
+ }
466
+ settleEntries.forEach((entry, index) => {
467
+ const confidentialPayload = entry.payload.payload;
468
+ const batchResult = batchResults.get(index);
469
+ if (!batchResult || !batchResult.success) {
470
+ entry.resolve({
471
+ success: false,
472
+ errorReason: "settlement_failed",
473
+ payer: confidentialPayload.authorization.holder,
474
+ transaction: txHash,
475
+ network: entry.requirements.network,
476
+ ...batchResult ? { batch: { index, ...batchResult } } : {}
477
+ });
478
+ return;
479
+ }
480
+ entry.resolve({
481
+ success: true,
482
+ payer: confidentialPayload.authorization.holder,
483
+ transaction: txHash,
484
+ network: entry.requirements.network,
485
+ batch: { index, ...batchResult }
486
+ });
487
+ });
488
+ }
489
+ };
490
+
491
+ // src/service/bootstrap.ts
492
+ function requireEnv(key) {
493
+ const value = process.env[key];
494
+ if (!value) {
495
+ throw new Error(`Missing required env var: ${key}`);
496
+ }
497
+ return value;
498
+ }
499
+ function createFacilitatorFromEnv() {
500
+ const privateKey = requireEnv("FACILITATOR_EVM_PRIVATE_KEY");
501
+ const chainId = Number(process.env.FACILITATOR_EVM_CHAIN_ID ?? "11155111");
502
+ const rpcUrl = requireEnv("FACILITATOR_EVM_RPC_URL");
503
+ const networks = (process.env.FACILITATOR_NETWORKS ?? "eip155:11155111").split(",").map((network) => network.trim()).filter(Boolean);
504
+ const waitForReceipt = (process.env.FACILITATOR_WAIT_FOR_RECEIPT ?? "true") === "true";
505
+ const batcherAddress = process.env.FACILITATOR_BATCHER_ADDRESS;
506
+ if (!batcherAddress) {
507
+ throw new Error("FACILITATOR_BATCHER_ADDRESS is required");
508
+ }
509
+ const batchIntervalMs = process.env.FACILITATOR_BATCH_INTERVAL_MS ? Number(process.env.FACILITATOR_BATCH_INTERVAL_MS) : void 0;
510
+ const receiptTimeoutMs = process.env.FACILITATOR_RECEIPT_TIMEOUT_MS ? Number(process.env.FACILITATOR_RECEIPT_TIMEOUT_MS) : void 0;
511
+ const receiptConfirmations = process.env.FACILITATOR_RECEIPT_CONFIRMATIONS ? Number(process.env.FACILITATOR_RECEIPT_CONFIRMATIONS) : void 0;
512
+ const receiptPollingIntervalMs = process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS ? Number(process.env.FACILITATOR_RECEIPT_POLLING_INTERVAL_MS) : void 0;
513
+ const gasMultiplier = process.env.FACILITATOR_GAS_MULTIPLIER ? Number(process.env.FACILITATOR_GAS_MULTIPLIER) : void 0;
514
+ const debugEnabled = process.env.X402Z_DEBUG === "1";
515
+ const account = privateKeyToAccount(privateKey);
516
+ if (debugEnabled) {
517
+ console.debug("[x402z-facilitator] config", {
518
+ chainId,
519
+ networks,
520
+ rpcUrl,
521
+ waitForReceipt,
522
+ batcherAddress,
523
+ gasMultiplier,
524
+ batchIntervalMs,
525
+ receipt: {
526
+ confirmations: receiptConfirmations,
527
+ timeoutMs: receiptTimeoutMs,
528
+ pollingIntervalMs: receiptPollingIntervalMs
529
+ },
530
+ address: account.address
531
+ });
532
+ }
533
+ const client = createWalletClient({
534
+ account,
535
+ chain: {
536
+ id: chainId,
537
+ name: "custom",
538
+ nativeCurrency: { name: "native", symbol: "NATIVE", decimals: 18 },
539
+ rpcUrls: { default: { http: [rpcUrl] } }
540
+ },
541
+ transport: http(rpcUrl)
542
+ }).extend(publicActions);
543
+ const baseSigner = toFacilitatorEvmSigner({
544
+ address: account.address,
545
+ readContract: (args) => client.readContract({
546
+ ...args,
547
+ args: args.args || []
548
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
549
+ }),
550
+ verifyTypedData: (args) => client.verifyTypedData(args),
551
+ writeContract: async (args) => {
552
+ let gas;
553
+ if (gasMultiplier && gasMultiplier > 0) {
554
+ try {
555
+ const estimated = await client.estimateContractGas({
556
+ ...args,
557
+ args: args.args || [],
558
+ account
559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
560
+ });
561
+ const scale = BigInt(Math.round(gasMultiplier * 1e3));
562
+ const scaled = estimated * scale / 1000n;
563
+ gas = scaled > estimated ? scaled : estimated;
564
+ } catch (error) {
565
+ if (debugEnabled) {
566
+ console.debug("[x402z-facilitator] gas estimate failed", error);
567
+ }
568
+ }
569
+ }
570
+ return client.writeContract({
571
+ ...args,
572
+ args: args.args || [],
573
+ ...gas ? { gas } : {}
574
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
575
+ });
576
+ },
577
+ sendTransaction: (args) => (
578
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
579
+ client.sendTransaction({ to: args.to, data: args.data })
580
+ ),
581
+ waitForTransactionReceipt: (args) => client.waitForTransactionReceipt(args),
582
+ getCode: (args) => client.getCode(args)
583
+ });
584
+ const signer = {
585
+ ...baseSigner,
586
+ simulateContract: async (args) => {
587
+ const result = await client.simulateContract({
588
+ ...args,
589
+ args: args.args || [],
590
+ account
591
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
592
+ });
593
+ return result.result;
594
+ }
595
+ };
596
+ const facilitator = new x402Facilitator();
597
+ for (const network of networks) {
598
+ facilitator.register(
599
+ network,
600
+ new X402zEvmFacilitator({
601
+ signer,
602
+ waitForReceipt,
603
+ batcherAddress,
604
+ batchIntervalMs,
605
+ receipt: {
606
+ confirmations: receiptConfirmations,
607
+ timeoutMs: receiptTimeoutMs,
608
+ pollingIntervalMs: receiptPollingIntervalMs
609
+ }
610
+ })
611
+ );
612
+ }
613
+ return facilitator;
614
+ }
615
+ function startFacilitator() {
616
+ const facilitator = createFacilitatorFromEnv();
617
+ const port = Number(process.env.FACILITATOR_PORT ?? "8040");
618
+ const server = createFacilitatorService({ facilitator, port });
619
+ server.listen(port);
620
+ return { port };
621
+ }
622
+ if (__require.main === module) {
623
+ const { port } = startFacilitator();
624
+ console.log(`Confidential facilitator listening on :${port}`);
625
+ }
626
+
627
+ export {
628
+ X402zEvmFacilitator,
629
+ createFacilitatorService,
630
+ startFacilitatorService,
631
+ createFacilitatorFromEnv,
632
+ startFacilitator
633
+ };