@circle-fin/x402-batching 2.0.3

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,697 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/server/index.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ BatchFacilitatorClient: () => BatchFacilitatorClient,
34
+ GatewayEvmScheme: () => GatewayEvmScheme,
35
+ createGatewayMiddleware: () => createGatewayMiddleware,
36
+ isBatchPayment: () => isBatchPayment
37
+ });
38
+ module.exports = __toCommonJS(server_exports);
39
+
40
+ // src/server/BatchFacilitatorClient.ts
41
+ var BatchFacilitatorClient = class {
42
+ url;
43
+ _createAuthHeaders;
44
+ /**
45
+ * Creates a new BatchFacilitatorClient.
46
+ *
47
+ * @param config - Configuration including Gateway URL and optional auth headers
48
+ */
49
+ constructor(config = {}) {
50
+ this.url = (config.url ?? "https://gateway-api-testnet.circle.com").replace(
51
+ /\/$/,
52
+ ""
53
+ );
54
+ this._createAuthHeaders = config.createAuthHeaders;
55
+ }
56
+ /**
57
+ * Verify a payment with Circle Gateway.
58
+ *
59
+ * @param paymentPayload - The payment payload to verify
60
+ * @param paymentRequirements - The payment requirements
61
+ * @returns Verification response
62
+ */
63
+ async verify(paymentPayload, paymentRequirements) {
64
+ let headers = {
65
+ "Content-Type": "application/json"
66
+ };
67
+ if (this._createAuthHeaders) {
68
+ const authHeaders = await this._createAuthHeaders();
69
+ headers = { ...headers, ...authHeaders.verify };
70
+ }
71
+ const response = await fetch(`${this.url}/v1/x402/verify`, {
72
+ method: "POST",
73
+ headers,
74
+ body: JSON.stringify({
75
+ paymentPayload: this.toJsonSafe(paymentPayload),
76
+ paymentRequirements: this.toJsonSafe(paymentRequirements)
77
+ })
78
+ });
79
+ const data = await response.json();
80
+ if (typeof data === "object" && data !== null && "isValid" in data) {
81
+ return data;
82
+ }
83
+ throw new Error(
84
+ `Circle Gateway verify failed (${response.status}): ${JSON.stringify(data)}`
85
+ );
86
+ }
87
+ /**
88
+ * Settle a payment with Circle Gateway.
89
+ *
90
+ * @param paymentPayload - The payment payload to settle
91
+ * @param paymentRequirements - The payment requirements
92
+ * @returns Settlement response
93
+ */
94
+ async settle(paymentPayload, paymentRequirements) {
95
+ let headers = {
96
+ "Content-Type": "application/json"
97
+ };
98
+ if (this._createAuthHeaders) {
99
+ const authHeaders = await this._createAuthHeaders();
100
+ headers = { ...headers, ...authHeaders.settle };
101
+ }
102
+ const response = await fetch(`${this.url}/v1/x402/settle`, {
103
+ method: "POST",
104
+ headers,
105
+ body: JSON.stringify({
106
+ paymentPayload: this.toJsonSafe(paymentPayload),
107
+ paymentRequirements: this.toJsonSafe(paymentRequirements)
108
+ })
109
+ });
110
+ const text = await response.text();
111
+ if (!text) {
112
+ throw new Error(
113
+ `Circle Gateway settle returned empty response (${response.status})`
114
+ );
115
+ }
116
+ const data = JSON.parse(text);
117
+ if (typeof data === "object" && data !== null && "success" in data) {
118
+ return data;
119
+ }
120
+ throw new Error(`Circle Gateway settle failed (${response.status}): ${text}`);
121
+ }
122
+ /**
123
+ * Get supported payment kinds from Circle Gateway.
124
+ *
125
+ * This fetches the supported networks and their GatewayWallet contract addresses.
126
+ * The response includes `extra.verifyingContract` for each supported network.
127
+ *
128
+ * @returns Supported payment kinds and extensions
129
+ */
130
+ async getSupported() {
131
+ let headers = {
132
+ "Content-Type": "application/json"
133
+ };
134
+ if (this._createAuthHeaders) {
135
+ const authHeaders = await this._createAuthHeaders();
136
+ headers = { ...headers, ...authHeaders.supported };
137
+ }
138
+ const response = await fetch(`${this.url}/v1/x402/supported`, {
139
+ method: "GET",
140
+ headers
141
+ });
142
+ if (!response.ok) {
143
+ const errorText = await response.text().catch(() => response.statusText);
144
+ throw new Error(
145
+ `Circle Gateway getSupported failed (${response.status}): ${errorText}`
146
+ );
147
+ }
148
+ return await response.json();
149
+ }
150
+ /**
151
+ * Helper to convert objects to JSON-safe format.
152
+ * Handles BigInt and other non-JSON types.
153
+ */
154
+ toJsonSafe(obj) {
155
+ return JSON.parse(
156
+ JSON.stringify(
157
+ obj,
158
+ (_, value) => typeof value === "bigint" ? value.toString() : value
159
+ )
160
+ );
161
+ }
162
+ };
163
+
164
+ // src/server/GatewayEvmScheme.ts
165
+ var import_server = require("@x402/evm/exact/server");
166
+
167
+ // src/client/GatewayClient.ts
168
+ var import_viem = require("viem");
169
+ var import_accounts = require("viem/accounts");
170
+ var chains = __toESM(require("viem/chains"));
171
+ var sonicTestnet = (0, import_viem.defineChain)({
172
+ id: 14601,
173
+ name: "Sonic Testnet",
174
+ nativeCurrency: { decimals: 18, name: "Sonic", symbol: "S" },
175
+ rpcUrls: {
176
+ default: { http: ["https://rpc.testnet.soniclabs.com"] }
177
+ },
178
+ blockExplorers: {
179
+ default: { name: "Sonic Testnet Explorer", url: "https://testnet.soniclabs.com/" }
180
+ },
181
+ testnet: true
182
+ });
183
+ var GATEWAY_DOMAINS = {
184
+ // Testnet
185
+ arbitrumSepolia: 3,
186
+ arcTestnet: 26,
187
+ avalancheFuji: 1,
188
+ baseSepolia: 6,
189
+ sepolia: 0,
190
+ hyperEvmTestnet: 19,
191
+ optimismSepolia: 2,
192
+ polygonAmoy: 7,
193
+ seiAtlantic: 16,
194
+ sonicTestnet: 13,
195
+ unichainSepolia: 10,
196
+ worldChainSepolia: 14,
197
+ // Mainnet
198
+ arbitrum: 3,
199
+ avalanche: 1,
200
+ base: 6,
201
+ mainnet: 0,
202
+ hyperEvm: 19,
203
+ optimism: 2,
204
+ polygon: 7,
205
+ sei: 16,
206
+ sonic: 13,
207
+ unichain: 10,
208
+ worldChain: 14
209
+ };
210
+ var TESTNET_GATEWAY_WALLET = "0x0077777d7EBA4688BDeF3E311b846F25870A19B9";
211
+ var TESTNET_GATEWAY_MINTER = "0x0022222ABE238Cc2C7Bb1f21003F0a260052475B";
212
+ var MAINNET_GATEWAY_WALLET = "0x77777777Dcc4d5A8B6E418Fd04D8997ef11000eE";
213
+ var MAINNET_GATEWAY_MINTER = "0x2222222d7164433c4C09B0b0D809a9b52C04C205";
214
+ var CHAIN_CONFIGS = {
215
+ // Testnet chains
216
+ arbitrumSepolia: {
217
+ chain: chains.arbitrumSepolia,
218
+ domain: GATEWAY_DOMAINS.arbitrumSepolia,
219
+ usdc: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
220
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
221
+ gatewayMinter: TESTNET_GATEWAY_MINTER
222
+ },
223
+ arcTestnet: {
224
+ chain: chains.arcTestnet,
225
+ domain: GATEWAY_DOMAINS.arcTestnet,
226
+ usdc: "0x3600000000000000000000000000000000000000",
227
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
228
+ gatewayMinter: TESTNET_GATEWAY_MINTER,
229
+ rpcUrl: "https://rpc.testnet.arc.network"
230
+ },
231
+ avalancheFuji: {
232
+ chain: chains.avalancheFuji,
233
+ domain: GATEWAY_DOMAINS.avalancheFuji,
234
+ usdc: "0x5425890298aed601595a70AB815c96711a31Bc65",
235
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
236
+ gatewayMinter: TESTNET_GATEWAY_MINTER
237
+ },
238
+ baseSepolia: {
239
+ chain: chains.baseSepolia,
240
+ domain: GATEWAY_DOMAINS.baseSepolia,
241
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
242
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
243
+ gatewayMinter: TESTNET_GATEWAY_MINTER,
244
+ rpcUrl: "https://sepolia-preconf.base.org"
245
+ },
246
+ sepolia: {
247
+ chain: chains.sepolia,
248
+ domain: GATEWAY_DOMAINS.sepolia,
249
+ usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
250
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
251
+ gatewayMinter: TESTNET_GATEWAY_MINTER
252
+ },
253
+ hyperEvmTestnet: {
254
+ chain: chains.hyperliquidEvmTestnet,
255
+ domain: GATEWAY_DOMAINS.hyperEvmTestnet,
256
+ usdc: "0x2B3370eE501B4a559b57D449569354196457D8Ab",
257
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
258
+ gatewayMinter: TESTNET_GATEWAY_MINTER
259
+ },
260
+ optimismSepolia: {
261
+ chain: chains.optimismSepolia,
262
+ domain: GATEWAY_DOMAINS.optimismSepolia,
263
+ usdc: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7",
264
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
265
+ gatewayMinter: TESTNET_GATEWAY_MINTER
266
+ },
267
+ polygonAmoy: {
268
+ chain: chains.polygonAmoy,
269
+ domain: GATEWAY_DOMAINS.polygonAmoy,
270
+ usdc: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
271
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
272
+ gatewayMinter: TESTNET_GATEWAY_MINTER
273
+ },
274
+ seiAtlantic: {
275
+ chain: chains.seiTestnet,
276
+ domain: GATEWAY_DOMAINS.seiAtlantic,
277
+ usdc: "0x4fCF1784B31630811181f670Aea7A7bEF803eaED",
278
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
279
+ gatewayMinter: TESTNET_GATEWAY_MINTER
280
+ },
281
+ sonicTestnet: {
282
+ chain: sonicTestnet,
283
+ domain: GATEWAY_DOMAINS.sonicTestnet,
284
+ usdc: "0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51",
285
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
286
+ gatewayMinter: TESTNET_GATEWAY_MINTER
287
+ },
288
+ unichainSepolia: {
289
+ chain: chains.unichainSepolia,
290
+ domain: GATEWAY_DOMAINS.unichainSepolia,
291
+ usdc: "0x31d0220469e10c4E71834a79b1f276d740d3768F",
292
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
293
+ gatewayMinter: TESTNET_GATEWAY_MINTER
294
+ },
295
+ worldChainSepolia: {
296
+ chain: chains.worldchainSepolia,
297
+ domain: GATEWAY_DOMAINS.worldChainSepolia,
298
+ usdc: "0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88",
299
+ gatewayWallet: TESTNET_GATEWAY_WALLET,
300
+ gatewayMinter: TESTNET_GATEWAY_MINTER
301
+ },
302
+ // Mainnet chains
303
+ arbitrum: {
304
+ chain: chains.arbitrum,
305
+ domain: GATEWAY_DOMAINS.arbitrum,
306
+ usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
307
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
308
+ gatewayMinter: MAINNET_GATEWAY_MINTER
309
+ },
310
+ avalanche: {
311
+ chain: chains.avalanche,
312
+ domain: GATEWAY_DOMAINS.avalanche,
313
+ usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
314
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
315
+ gatewayMinter: MAINNET_GATEWAY_MINTER
316
+ },
317
+ base: {
318
+ chain: chains.base,
319
+ domain: GATEWAY_DOMAINS.base,
320
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
321
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
322
+ gatewayMinter: MAINNET_GATEWAY_MINTER
323
+ },
324
+ mainnet: {
325
+ chain: chains.mainnet,
326
+ domain: GATEWAY_DOMAINS.mainnet,
327
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
328
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
329
+ gatewayMinter: MAINNET_GATEWAY_MINTER
330
+ },
331
+ hyperEvm: {
332
+ chain: chains.hyperEvm,
333
+ domain: GATEWAY_DOMAINS.hyperEvm,
334
+ usdc: "0xb88339CB7199b77E23DB6E890353E22632Ba630f",
335
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
336
+ gatewayMinter: MAINNET_GATEWAY_MINTER
337
+ },
338
+ optimism: {
339
+ chain: chains.optimism,
340
+ domain: GATEWAY_DOMAINS.optimism,
341
+ usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
342
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
343
+ gatewayMinter: MAINNET_GATEWAY_MINTER
344
+ },
345
+ polygon: {
346
+ chain: chains.polygon,
347
+ domain: GATEWAY_DOMAINS.polygon,
348
+ usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
349
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
350
+ gatewayMinter: MAINNET_GATEWAY_MINTER
351
+ },
352
+ sei: {
353
+ chain: chains.sei,
354
+ domain: GATEWAY_DOMAINS.sei,
355
+ usdc: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392",
356
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
357
+ gatewayMinter: MAINNET_GATEWAY_MINTER
358
+ },
359
+ sonic: {
360
+ chain: chains.sonic,
361
+ domain: GATEWAY_DOMAINS.sonic,
362
+ usdc: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894",
363
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
364
+ gatewayMinter: MAINNET_GATEWAY_MINTER
365
+ },
366
+ unichain: {
367
+ chain: chains.unichain,
368
+ domain: GATEWAY_DOMAINS.unichain,
369
+ usdc: "0x078D782b760474a361dDA0AF3839290b0EF57AD6",
370
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
371
+ gatewayMinter: MAINNET_GATEWAY_MINTER
372
+ },
373
+ worldChain: {
374
+ chain: chains.worldchain,
375
+ domain: GATEWAY_DOMAINS.worldChain,
376
+ usdc: "0x79A02482A880bCe3F13E09da970dC34dB4cD24D1",
377
+ gatewayWallet: MAINNET_GATEWAY_WALLET,
378
+ gatewayMinter: MAINNET_GATEWAY_MINTER
379
+ }
380
+ };
381
+
382
+ // src/server/GatewayEvmScheme.ts
383
+ var GatewayEvmScheme = class extends import_server.ExactEvmScheme {
384
+ constructor() {
385
+ super();
386
+ this.registerGatewayMoneyParsers();
387
+ }
388
+ /**
389
+ * Enhances payment requirements by merging the facilitator's extra data.
390
+ *
391
+ * The base `ExactEvmScheme.enhancePaymentRequirements` returns requirements
392
+ * unchanged, dropping `supportedKind.extra`. Gateway payments require
393
+ * `extra.verifyingContract` (and other fields like `name`, `version`) to
394
+ * be present for clients to construct the correct signing domain.
395
+ */
396
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
397
+ void extensionKeys;
398
+ return {
399
+ ...paymentRequirements,
400
+ maxTimeoutSeconds: 345600,
401
+ // 4 days — Gateway batches settlements asynchronously
402
+ extra: {
403
+ ...paymentRequirements.extra,
404
+ ...supportedKind.extra
405
+ }
406
+ };
407
+ }
408
+ /**
409
+ * Registers money parsers for all Gateway-supported networks.
410
+ *
411
+ * Builds a `network → USDC address` lookup from `CHAIN_CONFIGS` and
412
+ * registers a single parser that converts dollar amounts to USDC atomic
413
+ * units (6 decimals) for any Gateway-supported chain.
414
+ *
415
+ * Returns `null` for unknown networks so `ExactEvmScheme`'s built-in
416
+ * parser handles them.
417
+ */
418
+ registerGatewayMoneyParsers() {
419
+ const networkUsdcMap = /* @__PURE__ */ new Map();
420
+ for (const config of Object.values(CHAIN_CONFIGS)) {
421
+ const network = `eip155:${config.chain.id}`;
422
+ networkUsdcMap.set(network, config.usdc);
423
+ }
424
+ this.registerMoneyParser(async (amount, network) => {
425
+ const usdcAddress = networkUsdcMap.get(network);
426
+ if (!usdcAddress) {
427
+ return null;
428
+ }
429
+ return {
430
+ amount: Math.round(amount * 1e6).toString(),
431
+ asset: usdcAddress
432
+ };
433
+ });
434
+ }
435
+ };
436
+
437
+ // src/constants.ts
438
+ var CIRCLE_BATCHING_NAME = "GatewayWalletBatched";
439
+ var CIRCLE_BATCHING_VERSION = "1";
440
+ var CIRCLE_BATCHING_SCHEME = "exact";
441
+
442
+ // src/detection.ts
443
+ function supportsBatching(requirements) {
444
+ const extra = requirements.extra;
445
+ if (!extra) {
446
+ return false;
447
+ }
448
+ return extra.name === CIRCLE_BATCHING_NAME && extra.version === CIRCLE_BATCHING_VERSION;
449
+ }
450
+ var isBatchPayment = supportsBatching;
451
+
452
+ // src/server/middleware.ts
453
+ function getUsdcAddress(kind) {
454
+ const assets = kind.extra?.assets;
455
+ if (!assets || assets.length === 0) return null;
456
+ const usdc = assets.find((a) => a.symbol === "USDC");
457
+ return usdc?.address ?? null;
458
+ }
459
+ function parsePrice(price) {
460
+ const numericPrice = price.replace(/[$]/g, "");
461
+ const amount = parseFloat(numericPrice);
462
+ if (isNaN(amount) || amount <= 0) {
463
+ throw new Error(`Invalid price: ${price}`);
464
+ }
465
+ return Math.round(amount * 1e6).toString();
466
+ }
467
+ function createGatewayMiddleware(config) {
468
+ const facilitator = new BatchFacilitatorClient({
469
+ url: config.facilitatorUrl
470
+ });
471
+ const configuredNetworks = config.networks ? Array.isArray(config.networks) ? config.networks : [config.networks] : null;
472
+ let cachedSupportedKinds = null;
473
+ async function getSupportedKinds() {
474
+ if (cachedSupportedKinds) {
475
+ return cachedSupportedKinds;
476
+ }
477
+ const supported = await facilitator.getSupported();
478
+ cachedSupportedKinds = supported.kinds;
479
+ return cachedSupportedKinds;
480
+ }
481
+ async function getAcceptedNetworks() {
482
+ const allKinds = await getSupportedKinds();
483
+ if (configuredNetworks) {
484
+ return allKinds.filter(
485
+ (k) => configuredNetworks.includes(k.network) && k.extra?.verifyingContract
486
+ );
487
+ }
488
+ return allKinds.filter((k) => k.extra?.verifyingContract);
489
+ }
490
+ async function createAllPaymentRequirements(price) {
491
+ const networks = await getAcceptedNetworks();
492
+ const amount = parsePrice(price);
493
+ return networks.filter((kind) => getUsdcAddress(kind)).map((kind) => ({
494
+ scheme: CIRCLE_BATCHING_SCHEME,
495
+ // Must be 'exact' for Gateway API
496
+ network: kind.network,
497
+ asset: getUsdcAddress(kind),
498
+ // Use actual USDC address
499
+ amount,
500
+ payTo: config.sellerAddress,
501
+ maxTimeoutSeconds: 345600,
502
+ // 4 days (same as digital-dungeon)
503
+ extra: {
504
+ name: CIRCLE_BATCHING_NAME,
505
+ version: CIRCLE_BATCHING_VERSION,
506
+ verifyingContract: kind.extra.verifyingContract
507
+ }
508
+ }));
509
+ }
510
+ async function createPaymentRequirements(price, network) {
511
+ const networks = await getAcceptedNetworks();
512
+ const kind = networks.find((k) => k.network === network);
513
+ if (!kind || !kind.extra?.verifyingContract) {
514
+ return null;
515
+ }
516
+ const usdcAddress = getUsdcAddress(kind);
517
+ if (!usdcAddress) {
518
+ return null;
519
+ }
520
+ return {
521
+ scheme: CIRCLE_BATCHING_SCHEME,
522
+ // Must be 'exact' for Gateway API
523
+ network: kind.network,
524
+ asset: usdcAddress,
525
+ // Use actual USDC address
526
+ amount: parsePrice(price),
527
+ payTo: config.sellerAddress,
528
+ maxTimeoutSeconds: 345600,
529
+ // 4 days
530
+ extra: {
531
+ name: CIRCLE_BATCHING_NAME,
532
+ version: CIRCLE_BATCHING_VERSION,
533
+ verifyingContract: kind.extra.verifyingContract
534
+ }
535
+ };
536
+ }
537
+ return {
538
+ require: (price) => {
539
+ return async (req, res, next) => {
540
+ try {
541
+ const paymentHeader = req.headers["payment-signature"];
542
+ if (!paymentHeader) {
543
+ const allRequirements = await createAllPaymentRequirements(price);
544
+ const url = req.url ?? "/";
545
+ const description = config.description ?? "Paid resource";
546
+ if (allRequirements.length === 0) {
547
+ res.statusCode = 503;
548
+ res.setHeader("Content-Type", "application/json");
549
+ res.end(JSON.stringify({ error: "No payment networks available" }));
550
+ return;
551
+ }
552
+ const paymentRequired = {
553
+ x402Version: 2,
554
+ // Version 2 required by Gateway API
555
+ resource: {
556
+ url,
557
+ description,
558
+ mimeType: "application/json"
559
+ },
560
+ accepts: allRequirements
561
+ };
562
+ const paymentRequiredHeader = Buffer.from(
563
+ JSON.stringify(paymentRequired)
564
+ ).toString("base64");
565
+ res.statusCode = 402;
566
+ res.setHeader("PAYMENT-REQUIRED", paymentRequiredHeader);
567
+ res.setHeader("Content-Type", "application/json");
568
+ res.end(JSON.stringify({}));
569
+ return;
570
+ }
571
+ const paymentPayload = JSON.parse(
572
+ Buffer.from(paymentHeader, "base64").toString("utf-8")
573
+ );
574
+ const acceptedRequirements = paymentPayload.accepted;
575
+ if (!acceptedRequirements?.network) {
576
+ res.statusCode = 400;
577
+ res.setHeader("Content-Type", "application/json");
578
+ res.end(
579
+ JSON.stringify({ error: "Missing accepted requirements in payment" })
580
+ );
581
+ return;
582
+ }
583
+ const requirements = await createPaymentRequirements(
584
+ price,
585
+ acceptedRequirements.network
586
+ );
587
+ if (!requirements) {
588
+ res.statusCode = 400;
589
+ res.setHeader("Content-Type", "application/json");
590
+ res.end(
591
+ JSON.stringify({
592
+ error: `Network ${acceptedRequirements.network} not accepted`
593
+ })
594
+ );
595
+ return;
596
+ }
597
+ const verifyResult = await facilitator.verify(paymentPayload, requirements);
598
+ if (!verifyResult.isValid) {
599
+ res.statusCode = 402;
600
+ res.setHeader("Content-Type", "application/json");
601
+ res.end(
602
+ JSON.stringify({
603
+ error: "Payment verification failed",
604
+ reason: verifyResult.invalidReason
605
+ })
606
+ );
607
+ return;
608
+ }
609
+ const settleResult = await facilitator.settle(paymentPayload, requirements);
610
+ if (!settleResult.success) {
611
+ res.statusCode = 402;
612
+ res.setHeader("Content-Type", "application/json");
613
+ res.end(
614
+ JSON.stringify({
615
+ error: "Payment settlement failed",
616
+ reason: settleResult.errorReason
617
+ })
618
+ );
619
+ return;
620
+ }
621
+ req.payment = {
622
+ verified: true,
623
+ payer: settleResult.payer ?? verifyResult.payer ?? "",
624
+ amount: parsePrice(price),
625
+ network: requirements.network,
626
+ transaction: settleResult.transaction
627
+ };
628
+ const settleResponseHeader = Buffer.from(
629
+ JSON.stringify({
630
+ success: true,
631
+ transaction: settleResult.transaction,
632
+ network: requirements.network,
633
+ payer: settleResult.payer ?? verifyResult.payer ?? ""
634
+ })
635
+ ).toString("base64");
636
+ res.setHeader("PAYMENT-RESPONSE", settleResponseHeader);
637
+ next();
638
+ } catch (error) {
639
+ res.statusCode = 500;
640
+ res.setHeader("Content-Type", "application/json");
641
+ res.end(
642
+ JSON.stringify({
643
+ error: "Payment processing error",
644
+ message: error.message
645
+ })
646
+ );
647
+ }
648
+ };
649
+ },
650
+ verify: async (payment) => {
651
+ try {
652
+ const paymentPayload = payment;
653
+ const result = await facilitator.verify(
654
+ paymentPayload.paymentPayload,
655
+ paymentPayload.paymentRequirements
656
+ );
657
+ return {
658
+ valid: result.isValid,
659
+ payer: result.payer,
660
+ error: result.invalidReason
661
+ };
662
+ } catch (error) {
663
+ return {
664
+ valid: false,
665
+ error: error.message
666
+ };
667
+ }
668
+ },
669
+ settle: async (payment) => {
670
+ try {
671
+ const paymentPayload = payment;
672
+ const result = await facilitator.settle(
673
+ paymentPayload.paymentPayload,
674
+ paymentPayload.paymentRequirements
675
+ );
676
+ return {
677
+ success: result.success,
678
+ transaction: result.transaction,
679
+ error: result.errorReason
680
+ };
681
+ } catch (error) {
682
+ return {
683
+ success: false,
684
+ error: error.message
685
+ };
686
+ }
687
+ }
688
+ };
689
+ }
690
+ // Annotate the CommonJS export names for ESM import in node:
691
+ 0 && (module.exports = {
692
+ BatchFacilitatorClient,
693
+ GatewayEvmScheme,
694
+ createGatewayMiddleware,
695
+ isBatchPayment
696
+ });
697
+ //# sourceMappingURL=index.js.map